# Legendre_P in symbolic function - recursion error

Hello,
Undergraduate Physics mathemtica->sage convert here trying to use sage for both symbolic substitution to print equations and to plot.

I have the equation M_y^2 * cos(x)^4 -2*My(x)*sin(x)*cos(x)^3 and would like to see how this behaves when substituting different associated legendre polynomials for My^2. Code for this:

Y_fnc(x,y_max,l,m)=y_max*gen_legendre_P(l,m,cos(x))
f(x,y_max,l,m)=Y_fnc(x,y_max,l,m) * cos(x)^4 -2*sqrt(Y_fnc(x,y_max,l,m))*sin(x)*cos(x)^3

Which results in:  [...] File "/home/ian/sage-6.8-x86_64-Linux/local/lib/python2.7/site-packages/sage/symbolic/expression_conversions.py", line 319, in symbol raise NotImplementedError("symbol") RuntimeError: maximum recursion depth exceeded while calling a Python object  With example line of the truncated output being:
File "/home/ian/sage-6.8-x86_64-Linux/local/lib/python2.7/site-packages/sage/functions/orthogonal_polys.py", line 1239, in gen_legendre_P
return sqrt(1-x**2)*(((n-m+1)*x*gen_legendre_P(n,m-1,x)-(n+m-1)*gen_legendre_P(n-1,m-1,x))/(1-x**2))

I have also tried to use maxima.assoc_legendre_P but this doesn't work when I try to plot:
Y_fnc(x,y_max,l,m)=y_max*maxima.assoc_legendre_P(l,m,cos(x))
f(x,y_max,l,m)=Y_fnc(x,y_max,l,m) * cos(x)^4 -2*sqrt(Y_fnc(x,y_max,l,m))*sin(x)*cos(x)^3
plot(f(x,1,2,0),0,2*pi)


 verbose 0 (2716: plot.py, generate_plot_points) WARNING: When plotting, failed to evaluate function at 200 points. verbose 0 (2716: plot.py, generate_plot_points) Last error message: 'unable to simplify to float approximation' .

I can accomplish plotting by defining Python Functions:
edit:

    def Y_fnc_py(x,l,m,y_max):
return y_max*gen_legendre_P(l,m,cos(x))
def f(x,y_max,l,m):
return Y_fnc_py(x,y_max,l,m) * cos(x)^4 -2*sqrt(Y_fnc_py(x,y_max,l,m))*sin(x)*cos(x)^3
plot(f(x,y_max=2,l=1,m=1),0,2*pi)


Works however this will not allow me print f(x,y_max,l=3,m=2) so I can easily write down the equation. So this allows me to plot easily but doesn't display the equation well Help much appreciated thank you

edit retag close merge delete

At the end of your question you say "I can accomplish plotting by defining Python Functions ". Could you explain how you did this so that we can understand the problem ?

( 2015-10-26 18:17:18 -0500 )edit

Sort by » oldest newest most voted

I am not sure to understand your question, but you can define your own symbolic function, and how it can be numerically evaluated (which is required by the plot function), see the documentation of function factory.

So, you can define how your legendre function evaluates numerically:

sage: def evalf_my_legendre(self, a,b,c, parent=None, algorithm=None):
....:     return gen_legendre_P(ZZ(a),ZZ(b),RDF(c))


Note that i had to convert the input because the gen_legendre_P uses the mod function, see gen_legendre_P??.

Then, you can define your own symbolic my_legendre function, that can be numerically evaluated as before:

sage: my_legendre = function("my_legendre", nargs=3, evalf_func=evalf_my_legendre)


Then you can do:

sage: Y_fnc(x,y_max,l,m)=y_max*my_legendre(l,m,cos(x))
sage: Y_fnc
(x, y_max, l, m) |--> y_max*my_legendre(l, m, cos(x))

sage: f(x,y_max,l,m)=Y_fnc(x,y_max,l,m) * cos(x)^4 -2*sqrt(Y_fnc(x,y_max,l,m))*sin(x)*cos(x)^3
sage: f
(x, y_max, l, m) |--> y_max*cos(x)^4*my_legendre(l, m, cos(x)) - 2*sqrt(y_max*my_legendre(l, m, cos(x)))*cos(x)^3*sin(x)

sage: plot(f(x,1,2,0),0,2*pi)


You can see that the plot is not complete. This is due to the fact that taking the square root of a negative number does not makes sense:

sage: f(0.2,1,2,0).n()
0.505189228949794
sage: f(1.2,1,2,0).n()
NaN
sage: my_legendre(2,0,cos(1.2))
my_legendre(2, 0, 0.362357754476674)
sage: my_legendre(2,0,cos(1.2)).n()
-0.3030452866559341


EDIT

Reading your edits and comments, it seems that l and m are integer parameters that could be fixed in advance, while x and y_max are symbolic variables. So, you can express this as follows:

sage: var('x,y_max')
(x, y_max)
sage: Y_fnc = lambda l,m : y_max*gen_legendre_P(l,m,cos(x))
sage: f = lambda l,m : Y_fnc(l,m) * cos(x)^4 -2*sqrt(Y_fnc(l,m))*sin(x)*cos(x)^3


So, when you give values to integer parameters, you get the corresponding symbolic expression:

sage: f(1,1)
-sqrt(-cos(x)^2 + 1)*y_max*cos(x)^4 - 2*sqrt(-sqrt(-cos(x)^2 + 1)*y_max)*cos(x)^3*sin(x)
sage: f(2,0)
1/2*(3*(cos(x) - 1)^2 + 6*cos(x) - 4)*y_max*cos(x)^4 - 2*sqrt(1/2)*sqrt((3*(cos(x) - 1)^2 + 6*cos(x) - 4)*y_max)*cos(x)^3*sin(x)


You can also evaluate:

sage: f(2,0)(0.3,4.5)
-1.44117873676596*sqrt(1/2) + 3.25730637499042
sage: f(2,0)(1.2,4.5)
-(8.96876567884269e-18 + 0.146471059003904*I)*sqrt(1/2) - 0.0235109558634682


You can also plot, which will work only where the function takes real values:

sage: var('t')
t
sage: plot(f(2,0)(x=t,y_max=2),t,0,2*pi)

more

Thank you so much for your answer and time it's introduced me to some aspect of sage I was unaware of. Sorry for poorly phrasing the question however I think I can clarify. I would like print(f) to give me an answer fully expanded, not in terms of my_legendre(). A simpler example would be:

sage: var('y_max')
sage: Y_fnc(x,y_max,l,m)=y_max*cos(x)^3
sage: f(x,y_max,l,m)=Y_fnc(x,y_max,l,m) * cos(x)^4 -2*sqrt(Y_fnc(x,y_max,l,m))*sin(x)*cos(x)^3
sage: print(f)
(x, y_max, l, m) |--> y_max*cos(x)^7 -2*sqrt(y_max*cos(x)^3)*cos(x)^3*sin(x)
sage: plot(f(x,y_max))


Which will print the expanded output as above an plot with the only errors being imaginary parts. This is for Neutron scattering analysis btw.

( 2015-10-26 20:49:06 -0500 )edit

( 2015-10-26 21:26:27 -0500 )edit

This works thanks! I wonder if you have any insights into what went wrong with my initial method and how it is that your edit fixes this? Thank you again for your time and effort very much appreciated.

( 2015-10-26 21:41:01 -0500 )edit

I think there is a general issue about confusing between Python variables (a.k.a. "names") and symbolic variables (a.k.a. "symbol"). In this precise case, when we look at the source code of gen_legendre_P you can see that the first two inputs are integer parameters, that create a polynomial on the undeterminate that is the third input. For example, we can create real polynomials (not symbolic expressions), by using a polynomial undeterminate as the third input:

sage: x = polygen(QQ)
sage: gen_legendre_P(3,2,x)
-15*x^3 + 15*x
sage: gen_legendre_P(3,2,x).parent()
Univariate Polynomial Ring in x over Rational Field

( 2015-10-28 08:21:50 -0500 )edit

Now, looking at the documentation of the gen_legendre_P function, it seems that there is not enough information to understand that. I will open a ticket for that.

( 2015-10-28 08:23:29 -0500 )edit