0

How can I define an operator (eg integrator) in Python operating on a multi-variable function? My problem is that when I define an integrator function numint to numerically integrate a multivariable function along one of its variables that variable should be introduced at the first place, while I need it to be introduced by the user when the operator is called as it can change from one line of the code to another. One way is to not use an operator and implant the integration formula whenever it is needed with the variable over which integration should be computed, but that way the code would get quite cumbersome, so better to avoid it as much as is possible. The code that works wrongly for me is the following. Any idea to make it work properly?

var('x,y,z,t,x1,y1,z1,t1')
U=function('U0',x,y,z,t,x1,y1,z1,t1)
U=sin(x*y*z*t - x1*y1*z1*t1)^5

num=2
def numint(f, u, h):
    integ = 0.5*h*(f(u=0) + f(u=1))
    for i in range(1,num):
        integ = integ + h * f(u=i*h)
    return integ

print numint(U,t1,1/num)+numint(U,t,1/num)

Now the variable over which integration is taken is 'u', not found in thefunction 'U' at all, so that the result would be:

2*sin(t*x*y*z - t1*x1*y1*z1)^5

while I was expecting it to once integrate U WRT t and once WRT t1 then adding them together.

As much as I read the problem is that of the local and global variables. Maybe using closure and nested function is a suitable way to define an operator as is done in the example provided here, but the example is useful for single variable functions and I couldn't use it for multivariable functions.


Update. The following code does what I want (see the last print command, the previous prints are for experiment) but I should use a free argument of the function (like y) and tries with a dummy variable (like u in the example code above) fails:

var('x,y,z,t,x1,y1,z1,t1')
R=[x,y,z,t]
R1=[x1,y1,z1,t1]
U=function('U0',*(R+R1))
U0(x,y,z,t,x1,y1,z1,t1)=sin(x-x1)*sin(y-y1)*sin(z-z1)*sin(t-t1)
         # if write U0=... instead of U0(...)=... the order of arguments of U0 is not
         # specified and e.g. sin(x-x1) might become sin(x-y) from the system's viewpoint

num=2
def numint(func, h):

    #integ = 0.5*h*(func(x=x,y=0,z=z,t=t,x1=x1,y1=y1,z1=z1,t1=t1) + func(x=x,y=1,z=z,t=t,x1=x1,y1=y1,z1=z1,t1=t1))
    #for i in range(1,num):
    #    integ = integ + h * func(x=x,y=i*h,z=z,t=t,x1=x1,y1=y1,z1=z1,t1=t1)

    #integ = 0.5*h*(func(x,0,z,t,x1,y1,z1,t1) + func(x,1,z,t,x1,y1,z1,t1))
    #for i in range(1,num):
    #    integ = integ + h * func(x,i*h,z,t,x1,y1,z1,t1)

    integ = 0.5*h*(func(y=0) + func(y=1))
    for i in range(1,num):
        integ = integ + h * func(y=i*h)

    return integ

print numint(U,h=1/num),'\n'
print numint(U0,h=1/num),'\n\n'

print U0(y=z,z=y),'\n'
print numint(U(y=z,z=y),h=1/num),'\n'
print numint(U0(y=z,z=y),h=1/num),'\n\n'

print numint(U0(y=t,t=y),h=1/num).substitute(t=y)+numint(U0(y=t1,t1=y),h=1/num).substitute(t1=y)

the result is:

0.250000000000000*U0(x, 0, z, t, x1, y1, z1, t1) + 1/2*U0(x, 1/2, z, t,
x1, y1, z1, t1) + 0.250000000000000*U0(x, 1, z, t, x1, y1, z1, t1) 

1/2*sin(-y1 + 1/2)*sin(z - z1)*sin(x - x1)*sin(t - t1) +
0.250000000000000*sin(-y1 + 1)*sin(z - z1)*sin(x - x1)*sin(t - t1) +
0.250000000000000*sin(z - z1)*sin(x - x1)*sin(t - t1)*sin(-y1) 


sin(-y1 + z)*sin(y - z1)*sin(x - x1)*sin(t - t1) 

0.250000000000000*U0(x, z, 0, t, x1, y1, z1, t1) + 1/2*U0(x, z, 1/2, t,
x1, y1, z1, t1) + 0.250000000000000*U0(x, z, 1, t, x1, y1, z1, t1) 

1/2*sin(-z1 + 1/2)*sin(-y1 + z)*sin(x - x1)*sin(t - t1) +
0.250000000000000*sin(-z1 + 1)*sin(-y1 + z)*sin(x - x1)*sin(t - t1) +
0.250000000000000*sin(-y1 + z)*sin(x - x1)*sin(t - t1)*sin(-z1) 


1/2*sin(-t1 + 1/2)*sin(z - z1)*sin(y - y1)*sin(x - x1) +
0.250000000000000*sin(-t1 + 1)*sin(z - z1)*sin(y - y1)*sin(x - x1) +
0.250000000000000*sin(t - 1)*sin(z - z1)*sin(y - y1)*sin(x - x1) +
1/2*sin(t - 1/2)*sin(z - z1)*sin(y - y1)*sin(x - x1) +
0.250000000000000*sin(z - z1)*sin(y - y1)*sin(x - x1)*sin(t) +
0.250000000000000*sin(z - z1)*sin(y - y1)*sin(x - x1)*sin(-t1)

Note how I was forced to use .substitute(). Here integration was uni-variable but when the dimension of integration increases this way of coding can become confusing. Any idea to do this cleaner and more directly?

owari
  • 369
  • 3
  • 14

2 Answers2

1

You can use functools.partial() to convert a function with multiple variables to a function with one free variable.

Edit: Your function is

def numint(func, h):
    ...

So you should use e.g.

p = partial(numint, h=1/2.0)

Then you can call the new function:

p(func)

You should use keyword arguments to indicate which of the arguments you are giving to partial! And a non-keywoard ardument cannot follow a keyword argument.

Edit2: Note that Python itself does not have the ability to do symbolic manipulation of equations, which seems to be what you're looking for. You should probably re-label this as a SageMath question.

Roland Smith
  • 42,427
  • 3
  • 64
  • 94
  • Can you provide an example how to use it for this integration routine? My attempt to use it (eg by writing `from functools import partial; var1=x; numx=partial(numint,var1)`) failed :( – owari Apr 09 '13 at 08:01
  • also using `partial(numint(U0,var1,1/num),var1=t)` seems not to work although it doesn't give error. Please bare with me if I am miusing the commands a lot, I am a newbie. – owari Apr 09 '13 at 08:10
  • Thanks for the example, I tried with it and wrote [this minimal code](http://codeviewer.org/view/code:31c8) but it doesn't work. Can you explain me why it doesn't work? – owari Apr 09 '13 at 23:52
  • The first part of your code from `var` to `U0` in your minimal example isn't valid python; it gives a syntax error. You should fix that first. `U0` isn't a valid function definition... – Roland Smith Apr 10 '13 at 06:32
  • ah you are right, I just made a python file and ran into the same syntax error that you pointed out, but I couldn't resolve it. Mostly people were advising to use lists instead of arguments to avoid such errors and I cannot do that here, I really need to work with functions. Indeed, I am using SageMath which is based on Python, the code runs there with no error, but the output still is `sin(x-x1)*sin(y-y1)*sin(z-z1)*sin(t-t1)`. That is, integration has not been taken as was expected. – owari Apr 10 '13 at 10:50
  • Thank you, indeed as SymPy can do a lot using pure Python I guess operators would be able to be defined in Python as well. By the way, I was actually trying to ask you about the application of `partial()` in that code. Do you think the way it has been used (_i.e. calling the function with var1=..._) is correct? If yes and still I have problem then the problem would be due to SageMath and the way I have already used in my Updated Question is a better solution for me, I guess. – owari Apr 10 '13 at 20:35
  • The problems with your `partial()` call are that `U0` is not a Python function, and even if it were a proper function it would have a lot more arguments then you are giving it when you call `numericint()` – Roland Smith Apr 10 '13 at 21:25
0
var('x,y,z,t,x1,y1,z1,t1,var1')
U=function('U0',x,y,z,t,x1,y1,z1,t1)
U0(x,y,z,t,x1,y1,z1,t1)=sin(x-x1)*sin(y-y1)*sin(z-z1)*sin(t-t1)
    # if write U0=... instead of U0(...)=... the order of arguments of U0 is not
    # specified and e.g. sin(x-x1) might become sin(x-y) from the system's viewpoint

num=2.0
def numint(func, h):
    #global var1
    integ = 0.5*h*(func(var1=0) + func(var1=1))
    for i in range(1,num):
        integ = integ + h * func(var1=i*h)
    return integ


print numint(U0(x=var1),1/num)+numint(U0(y1=var1),1/num)
owari
  • 369
  • 3
  • 14