Symbolic Taylor expansion - sage

I would like to expand the symbol function $f(x)$ as a Taylor series in SageMath
$$\delta f(x)=\delta x\frac{d}{dx}f+\frac12(\delta x)^2\frac{d^2}
{dx^2}f+O((\delta x)^3)$$
with
$$\delta x = a_1(\delta t)^{\frac12}+a_2(\delta t)+a_3(\delta t)^{\frac32}+O((\delta t)^2)$$
And expand and collect the same power terms of $\delta t$ up to a designated power, say, $\frac32$. $f$ is just a symbol, I just need Mathsage to produce the symbols of derivatives $\frac{d}{dx}$.
How should one set this up in SageMath?

Is this what you want to do?
sage: f = function('f', nargs=1)(x)
sage: f
f(x)
sage: f.taylor(x, 0, 2)
1/2*x^2*D[0, 0](f)(0) + x*D[0](f)(0) + f(0)

With sympy, you would do something like this to get the Taylor series.
import sympy
dt = sympy.Symbol('dt')
a1 = sympy.Symbol('a1')
a2 = sympy.Symbol('a2')
a3 = sympy.Symbol('a3')
dx = a1*dt**(1/2) + a2*dt + a3*dt**(3/2)
from sympy.abc import x
f = sympy.Function('f')(x)
df = dx*sympy.diff(f,x) + 1/2*dx**2*sympy.diff(f,x,2)
df.series(x)
This is assuming x and δx are independent.

Related

Ways of using(assigning) variables in Sage

I need to test an n-variable Boolean Function f = f(x0,...,xn-1). I need to fix x0, then run some tests for the g1 = f(x1,...,xn-1), then fix x1 and so on.
The problem is that I don't really understand how to do it with Sage.
At first, I tried to create a vector of values, that controls "fixing" of the variables
R.<x0,x1,x2,x3> = BooleanPolynomialRing()
v = [None,1,None, 0]
if v[0] != None:
x0=v[0]
if v[1] != None:
x1=v[1]
if v[2] != None:
x2=v[2]
if v[3] != None:
x3=v[3]
f = BooleanFunction(x0+x3+x0*x1+x0*x1*x2)
print(f.algebraic_normal_form())
output:x0*x2
This works fine, but it doesn't fit my task because I want to be able to automate the fixing process.
I want to replace the "if"s with a loop, but in this case, I don't know how to address variables inside the loop using indexes.
I'm new to Sage so I would appreciate any advice!
I'm not sure what BooleanFunction is, but:
sage: R.<x0, x1, x2, x3> = BooleanPolynomialRing()
If at this point you do something like x1 = 1, then x1 is no longer a generator of this ring, so let's try to avoid that.
sage: f = x0 + x3 + x0*x1 + x0*x1*x2 # f is in R
sage: f.substitute({x1: 1})
x0*x2 + x3
I think what you want is a good way to carry out the substitute part of this.
A helpful observation: you can convert strings to variable names:
sage: R('x0')
x0
So:
sage: d = {}
sage: for i in range(len(v)):
....: if v[i] is not None:
....: d[R('x' + str(i))] = v[i]
....:
sage: d
{x1: 1, x3: 0}
sage: f.substitute(d)
x0*x2
The code can now be made more compact in two ways.
Call x the list of generators and use x[i] rather than R('x' + str(i)'):
sage: R.<x0, x1, x2, x3> = BooleanPolynomialRing()
sage: x = R.gens()
sage: x[0]*x[3] + x[1]*x[2]*x[3]
x0*x3 + x1*x2*x3
Use comprehension syntax rather than empty dictionary and for loop:
sage: f = x0 + x3 + x0*x1 + x0*x1*x2
sage: v = [None, 1, None, 0]
sage: f.subs({x[i]: vi for i, vi in enumerate(v) if vi is not None})
x0*x2

How to work with the result of the wild sympy

I have the following code:
f=tan(x)*x**2
q=Wild('q')
s=f.match(tan(q))
s={q_ : x}
How to work with the result of the "wild"? How to not address the array, for example, s[0], s{0}?
Wild can be used when you have an expression which is the result of some complicated calculation, but you know it has to be of the form sin(something) times something else. Then s[q] will be the sympy expression for the "something". And s[p] for the "something else". This could be used to investigate both p and q. Or to further work with a simplified version of f, substituting p and q with new variables, especially if p and q would be complex expressions involving multiple variables.
Many more use cases are possible.
Here is an example:
from sympy import *
from sympy.abc import x, y, z
p = Wild('p')
q = Wild('q')
f = tan(x) * x**2
s = f.match(p*tan(q))
print(f'f is the tangent of "{s[q]}" multiplied by "{s[p]}"')
g = f.xreplace({s[q]: y, s[p]:z})
print(f'f rewritten in simplified form as a function of y and z: "{g}"')
h = s[p] * s[q]
print(f'a new function h, combining parts of f: "{h}"')
Output:
f is the tangent of "x" multiplied by "x**2"
f rewritten in simplified form as a function of y and z: "z*tan(y)"
a new function h, combining parts of f: "x**3"
If you're interested in all arguments from tan that appear in f written as a product, you might try:
from sympy import *
from sympy.abc import x
f = tan(x+2)*tan(x*x+1)*7*(x+1)*tan(1/x)
if f.func == Mul:
all_tan_args = [a.args[0] for a in f.args if a.func == tan]
# note: the [0] is needed because args give a tupple of arguments and
# in the case of tan you'ld want the first (there is only one)
elif f.func == tan:
all_tan_args = [f.args[0]]
else:
all_tan_args = []
prod = 1
for a in all_tan_args:
prod *= a
print(f'All the tangent arguments are: {all_tan_args}')
print(f'Their product is: {prod}')
Output:
All the tangent arguments are: [1/x, x**2 + 1, x + 2]
Their product is: (x + 2)*(x**2 + 1)/x
Note that neither method would work for f = tan(x)**2. For that, you'ld need to write another match and decide whether you'ld want to take the same power of the arguments.

How I display a math function in Julia?

I'm new in Julia and I'm trying to learn to manipulate calculus on it. How do I do if I calculate the gradient of a function with "ForwardDiff" like in the code below and see the function next?
I know if I input some values it gives me the gradient value in that point but I just want to see the function (the gradient of f1).
julia> gradf1(x1, x2) = ForwardDiff.gradient(z -> f1(z[1], z[2]), [x1, x2])
gradf1 (generic function with 1 method)
To elaborate on Felipe Lema's comment, here are some examples using SymPy.jl for various tasks:
#vars x y z
f(x,y,z) = x^2 * y * z
VF(x,y,z) = [x*y, y*z, z*x]
diff(f(x,y,z), x) # ∂f/∂x
diff.(f(x,y,z), [x,y,z]) # ∇f, gradiant
diff.(VF(x,y,z), [x,y,z]) |> sum # ∇⋅VF, divergence
J = VF(x,y,z).jacobian([x,y,z])
sum(diag(J)) # ∇⋅VF, divergence
Mx,Nx, Px, My,Ny,Py, Mz, Nz, Pz = J
[Py-Nz, Mz-Px, Nx-My] # ∇×VF
The divergence and gradient are also part of SymPy, but not exposed. Their use is more general, but cumbersome for this task. For example, this finds the curl:
import PyCall
PyCall.pyimport_conda("sympy.physics.vector", "sympy")
RF = sympy.physics.vector.ReferenceFrame("R")
v1 = get(RF,0)*get(RF,1)*RF.x + get(RF,1)*get(RF,2)*RF.y + get(RF,2)*get(RF,0)*RF.z
sympy.physics.vector.curl(v1, RF)

Unclassified statement at (1) in a mathematical expression

My first Fortran lesson is to plot the probability density function of the radial Sturmian functions. In case you are interested, the radial Sturmian functions are used to graph the momentum space eigenfunctions for the hydrogen atom.
In order to produce these radial functions, one needs to first produce some polynomials called the Gegenbauer polynomials, denoted
Cba(x),
where a and b should be stacked atop each other. One needs these polynomials because the Sturmians (let's call them R_n,l) are defined like so,
R_n,l(p) = N pl⁄(p2 + k2)l+2 Cn - l - 1l + 1(p2 - k2⁄p2 + k2),
where N is a normalisation constant, p is the momentum, n is the principle quantum number, l is the angular momentum and k is a constant. The normalisation constant is there so that when I come to square this function, it will produce a probability distribution for the momentum of the electron in a hydrogen atom.
Gegenbauer polynomials are generated using the following recurrence relation:
Cnl(x) = 1⁄n[2(l + n - 1) x Cn - 1l(x) - (2l + n - 2)Cn - 2l(x)],
with C0l(x) = 1 and C1l(x) = 2lx, as you may have noticed, l is fixed but n is not. At the start of my program, I will specify both l and n and work out the Gegenbauer polynomial I need for the radial function I wish to plot.
The problems I am having with my code at the moment are all in my subroutine for working out the value of the Gegenbauer polynomial Cn-l-1l+1(p2 - k2⁄p2 + k2) for incremental values of p between 0 and 3. I keep getting the error
Unclassified statement at (1)
but I cannot see what the issue is.
program Radial_Plot
implicit none
real, parameter :: pi = 4*atan(1.0)
integer, parameter :: top = 1000, l = 50, n = 100
real, dimension(1:top) :: x, y
real increment
real :: a=0.0, b = 2.5, k = 0.3
integer :: i
real, dimension(1:top) :: C
increment = (b-a)/(real(top)-1)
x(1) = 0.0
do i = 2, top
x(i) = x(i-1) + increment
end do
Call Gegenbauer(top, n, l, k, C)
y = x*C
! y is the function that I shall be plotting between values a and b.
end program Radial_Plot
Subroutine Gegenbauer(top1, n1, l1, k1, CSub)
! This subroutine is my attempt to calculate the Gegenbauer polynomials evaluated at a certain number of values between c and d.
implicit none
integer :: top1, i, j, n1, l1
real :: k1, increment1, c, d
real, dimension(1:top1) :: x1
real, dimension(1:n1 - l1, 1:top1) :: C1
real, dimension(1:n1 - l1) :: CSub
c = 0.0
d = 3.0
k1 = 0.3
n1 = 50
l1 = 25
top1 = 1000
increment1 = (d - c)/(real(top1) - 1)
x1(1) = 0.0
do i = 2, top1
x1(i) = x1(i-1) + increment1
end do
do j = 1, top1
C1(1,j) = 1
C1(2,j) = 2(l1 + 1)(x1(i)^2 - k1^2)/(x1(i)^2 + k1^2)
! All the errors occurring here are all due to, and I quote, 'Unclassifiable statement at (1)', I can't see what the heck I have done wrong.
do i = 3, n1 - l1
C1(i,j) = 2(((l1 + 1)/n1) + 1)(x1(i)^2 - k1^2)/(x1(i)^2 + k1^2)C1(i,j-1) - ((2(l1+1)/n1) + 1)C1(i,j-2)
end do
CSub(j) = Cn(n1 - l1,j)^2
end do
return
end Subroutine Gegenbauer
As francesalus correctly pointed out, the problem is because you use ^ instead of ** for exponentiation. Additionally, you do not put * between the terms you are multiplying.
C1(1,j) = 1
C1(2,j) = 2*(l1 + 1)*(x1(i)**2 - k1**2)/(x1(i)**2 + k1**2)
do i = 3, n1 - l1
C1(i,j) = 2 * (((l1 + 1)/n1) + 1) * (x1(i)**2 - k1**2) / &
(x1(i)**2 + k1**2)*C1(i,j-1) - ((2(l1+1)/n1) + 1) * &
C1(i,j-2)
end do
CSub(j) = Cn(n1 - l1,j)**2
Since you are beginning I have some advice. Learn to put all subroutines and functions to modules (unless they are internal). There is no reason for the return statement at the and of the subroutine, similarly as a stop statement isn't necessary at the and of the program.

how can i calculate the polynomial that has the following asymptotes

how can i calculate the polynomial that has the tangent lines (1) y = x where x = 1, and (2) y = 1 where x = 365
I realize this may not be the proper forum but I figured somebody here could answer this in jiffy.
Also, I am not looking for an algorithm to answer this. I'd just like like to see the process.
Thanks.
I guess I should have mentioned that i'm writing an algorithm for scaling the y-axis of flotr graph
The specification of the curve can be expressed as four constraints:
y(1) = 1, y'(1) = 1 => tangent is (y=x) when x=1
y(365) = 1, y'(365) = 0 => tangent is (y=1) when x=365
We therefore need a family of curves with at least four degrees of freedom to match these constraints; the simplest type of polynomial is a cubic,
y = a*x^3 + b*x^2 + c*x + d
y' = 3*a*x^2 + 2*b*x + c
and the constraints give the following equations for the parameters:
a + b + c + d = 1
3*a + 2*b + c = 1
48627125*a + 133225*b + 365*c + d = 1
399675*a + 730*b + c = 0
I'm too old and too lazy to solve these myself, so I googled a linear equation solver to give the answer:
a = 1/132496, b = -731/132496, c = 133955/132496, d = -729/132496
I will post this type of question in mathoverflow.net next time. thanks
my solution in javascript was to adapt the equation of a circle:
var radius = Math.pow((2*Math.pow(365, 2)), 1/2);
var t = 365; //offset
this.tMax = (Math.pow(Math.pow(r, 2) - Math.pow(x, 2), 1/2) - t) * (t / (r - t)) + 1;
the above equation has the above specified asymptotes. it is part of a step polynomial for scaling an axis for a flotr graph.
well, you are missing data (you need another point to determine the polynomial)
a*(x-1)^2+b*(x-1)+c=y-1
a*(x-365)^2+b*(x-365)+c=y-1
you can solve the exact answer for b
but A depends on C (or vv)
and your question is off topic anyways, and you need to revise your algebra

Resources