Defining new operators with specific rules

I would like to define new derivative operators dd1 and dd2. They should follow the following rules (dd being either dd1 or dd2 - They follow the same rules.):

dd(a+b)=dd(a)+dd(b);
dd(a*b)=b*dd(a)+a*dd(b);
dd(-a)=-dd(a);
dd(1/a)=-1/a^2*dd(a);
dd(c)=0;
dd(c*a)=c*dd(a);
dd(a**c)=c*a**(c-1)*dd(a);


where c is a symbolic variable or a number of any kind and, a and b are scalar field functions on a manifold.

If the code is something like the following:

# First operator
def dd1(x):
...

# Second operator
def dd2(x):
...

Man = Manifold(4, 'Man', r'\mathcal{Man}')
CO.<t,r,th,ph> = Man.chart(r't r:(0,+oo) th:(0,pi):\theta ph:(0,2*pi):\phi')
a=Man.scalar_field(function('a')(*CO))
b=Man.scalar_field(function('b')(*CO))
c=var('c')


Then, it should produce these sample outputs for the following inputs:

Input> dd1(a)
Outpt> dd1(a)

Input> dd1(dd2(a))
Outpt> dd1(dd2(a))

Input> dd2(a*b)
Outpt> b*dd2(a)+a*dd2(b)

Input> dd1(c*a)
Outpt> c*dd1(a)

Input> dd2(dd1(c*a))
Outpt> c*dd2(dd1(a))

Input> dd1(-a)
Outpt> -dd1(a)

Input> dd2(c)
Outpt> 0

Input> dd1(7)
Outpt> 0

edit retag close merge delete

3
( 2024-02-11 12:51:05 +0100 )edit

Sort by ยป oldest newest most voted

The following code seems to do the job. However, it looks very clumsy and I would be very happy to receive comments.

##################################################################
##################################################################
def efdd(self, x):
# x is a number:
if x in RR or (I*x) in RR:
return 0

# Exponential exp(a)
elif x.operator()==exp:
return dd((log(x)).simplify())*x

# Logarithm log(a)
elif x.operator()==ln:
return (1/exp(x))*dd(exp(x))

# Single symbolic input
elif x.is_symbol():
if x.is_integer() or (I*x).is_integer() or x in RR or (I*x) in RR:
return 0
else:
pass
elif (-1*(x)).is_symbol():
if x.is_integer() or (I*x).is_integer() or x in RR or (I*x) in RR:
return 0
else:
return -dd(-x)

# Power in input with plus (a1^c1)
elif x.operator() == operator.pow:
try:
a, b = x.operands()
if a.is_integer() or a in RR or (I*a) in RR:
return a*(b^(a-1))*dd(b)
else:
return b*(a^(b-1))*dd(a)
except:
a, b, c = x.operands()
if a.is_integer() or (I*a).is_integer() or a in RR or (I*a) in RR:
return a*(b^(a-1))*dd(b)
else:
return b*(a^(b-1))*dd(a)

# Power in input with minus (-a1^c1)
elif (-1*x).operator() == operator.pow:
try:
a, b = (-1*x).operands()
if a.is_integer() or (I*a).is_integer() or a in RR or (I*a) in RR:
return -a*(b^(a-1))*dd(b)
else:
return -b*(a^(b-1))*dd(a)
except:
a, b, c = (-1*x).operands()
if a.is_integer() or (I*a).is_integer() or a in RR or (I*a) in RR:
return -a*(b^(a-1))*dd(b)
else:
return -b*(a^(b-1))*dd(a)

# Summation in input
oplist = x.operands()
return sum(dd(op) for op in oplist)

# Multiplication in input
elif x.operator() == mul_vararg:
ops=x.operands()
result=0
for i in range(len(ops)):
prod=1
for j in range(len(ops)):
if i!=j:
prod=prod*ops[j]
result=result+dd(ops[i])*prod
return result

##################################################################
dd = function("dd",latex_name=r"\Delta",eval_func=efdd)
##################################################################

var('a1,a2,a3,a4')
var('c1,c2,c3')
assume(c1,'integer')
assume(c2,'integer')
assume(c3,'integer')

show("dd(a1+a2+a3)=",dd(a1+a2+a3))
show("dd(-a1+a2-a3)=",dd(-a1+a2-a3))
show("dd(a1*a2)=",dd(a1*a2))
show("dd(a1*a2-a3*a4)=",dd(a1*a2-a3*a4))
show("dd(c1*a1)=",dd(c1*a1))
show("dd(-c1*a2)=",dd(-c1*a2))
show("dd(a1^c1)=",dd(a1^c1))
show("dd(-a1^c1)=",dd(-a1^c1))
show("dd(1/a1)=",dd(1/a1))
show("dd(-1/a1)=",dd(-1/a1))
show("dd(1/(a1^2))=",dd(1/(a1^2)))
show("dd(c1*a1*a2)=",dd(c1*a1*a2))
show("dd(a1*a2*a3*a4)=",dd(a1*a2*a3*a4))
show("dd(c1*a2*a3*a4)=",dd(c1*a2*a3*a4))

more

If you are happy with this solution, you can accept your own answer.

( 2024-02-26 16:21:53 +0100 )edit