Remove the coefficients from a SymPy expression - python

I have a symbolic expression in SymPy that I need to remove all the coefficients from after I take the 2nd derivative of the expression. Here is the code
import sympy as sym
x, y = sym.symbols('x y')
# define the shape function
S_function = 0 +\
x + y +\
x**2 + x*y + y**2 +\
x**3 + x**2*y + x*y**2 + y**3
# take the 2nd derivative of the shape function for the x components
S_function_xx = sym.expand(sym.diff(S_function,x,2))
print(S_function_xx)
And I get an output of 6*x + 2*y + 2, I need to convert this to x + y. Any suggestions are welcome.

If the expression is in fact a polynomial (as here), the following can be used: convert it to a Poly object, get its list of monomials with monoms, then recombine, deleting the constant term.
monom_list = sym.Poly(S_function_xx, x, y).monoms()
new_function = sum([x**a*y**b for a, b in monom_list if a + b > 0])
If S_function_xx is not a polynomial, it's not so clear what is a "coefficient".

Related

Find u as function of x and y using Python Sympy module when u is given in 2 equations

My goal is to find u as function of x and y using Sympy module.
the equations are:
The answer should be:
from sympy import cosh, sinh, symbols, sin, cos, Eq
u, v, x, y = symbols('u, v, x, y')
eqq1 = Eq(x, sin(u)*cosh(v))
eqq2 = Eq(y, cos(u)*sinh(v))
What's next?
I tried
result = solve((Eqq1, Eqq2), u, v)
Obviously it's not the right way.
Probably not the answer that you expect, but you can rework the problem by eliminating v, as follows:
(x cos u)² - (y sin u)² = cos²u sin²u
Then with t = sin²u, the equation is quadratic in t:
x² (1 - t) - y² t = (1 - t) t
Divide each side of x equation by cosh(v) and each side of y equation by sinh(v). Square all sides. Replace sinh(v)**2 with z and cosh(v)**2 with 1 + z. The sum of the lhs of the equations is 1. The difference is cos(2u). You can solve for cos(2u) and z and work out something close to what you are looking for.
>>> from sympy import x, y, z, v, u
>>> from sympy import cosh,sinh,cos,Tuple,solve
>>> e1 = x**2/cosh(v)**2 + y**2/sinh(v)**2-1
>>> e2 = y**2/sinh(v)**2-x**2/cosh(v)**2-cos(2*u)
>>> solve(Tuple(e1,e2).subs(cosh(v)**2,1+z).subs(sinh(v)**2,z), z, cos(2*u), dict=True)
[
{z: x**2/2 + y**2/2 - sqrt((x**2 - 2*x + y**2 + 1)*(x**2 + 2*x + y**2 + 1))/2 - 1/2,
cos(2*u): -x**2 - y**2 - sqrt((x**2 - 2*x + y**2 + 1)*(x**2 + 2*x + y**2 + 1))},
{z: x**2/2 + y**2/2 + sqrt((x**2 - 2*x + y**2 + 1)*(x**2 + 2*x + y**2 + 1))/2 - 1/2,
cos(2*u): -x**2 - y**2 + sqrt((x**2 - 2*x + y**2 + 1)*(x**2 + 2*x + y**2 + 1))}]

How to differentiate a expression with respect to a symbol that is not a free symbol of the expression in SymPy?

I have the following equation, like this:
y = 3x2 + x
Then, I want to differentiate the both side w.r.t the variable t with sympy. I try to implement it in the following code in JupyterNotebook:
>>> import sympy as sp
>>> x, y, t = sp.symbols('x y t', real=True)
>>> eq = sp.Eq(y, 3 * x **2 + x)
>>>
>>> expr1 = eq.lhs
>>> expr1
𝑦
>>> expr1.diff(t)
0
>>>
>>> expr2 = eq.rhs
>>> expr2
3𝑥^2+𝑥
>>> expr2.diff(t)
0
As the result, sympy will treat the symbol x and y as a constant. However, the ideal result I want should be the same as the result derived manually like this:
y = 3x2 + x
d/dt (y) = d/dt (3x2 + x)
dy/dt = 6 • x • dx/dt + 1 • dx/dt
dy/dt = (6x + 1) • dx/dt
How can I do the derivative operation on a expression with a specific symbol which is not a free symbol in the expression?
You should declare x and y as functions rather than symbols e.g.:
In [8]: x, y = symbols('x, y', cls=Function)
In [9]: t = symbols('t')
In [10]: eq = Eq(y(t), 3*x(t)**2 + x(t))
In [11]: eq
Out[11]:
2
y(t) = 3⋅x (t) + x(t)
In [12]: Eq(eq.lhs.diff(t), eq.rhs.diff(t))
Out[12]:
d d d
──(y(t)) = 6⋅x(t)⋅──(x(t)) + ──(x(t))
dt dt dt
https://docs.sympy.org/latest/modules/core.html#sympy.core.function.Function
Alternatively, the idiff function was made for this purpose but it works with expressions like f(x, y) and can return the value of dy/dx. So first make your Eq and expression and then calculate the desired derivative:
>>> from sympy import idiff
>>> e = eq.rewrite(Add)
>>> dydx = idiff(e, y, x); dydx
6*x + 1
Note, too, that even in your equation (if you write it explicitly in terms of functions of t) you do not need to isolate y(t) -- you can differentiate and solve for it:
>>> from sympy.abc import t
>>> x,y=map(Function,'xy')
>>> eq = x(t)*(y(t)**2 - y(t) + 1)
>>> yp=y(t).diff(t); Eq(yp, solve(eq.diff(t),yp)[0])
Eq(Derivative(y(t), t), (-y(t)**2 + y(t) - 1)*Derivative(x(t), t)/((2*y(t) - 1)*x(t)))

Substitute one equation into another in SymPy

Suppose I have equations x = z + 2 and y = x + 1 and I wish to substitute the first one into the second one, to eliminate x and get y = z + 3. In SymPy, I can create the first two equations as:
x = sympy.symbols('x')
y = sympy.symbols('y')
z = sympy.symbols('z')
equation_one = sympy.Eq(x, z + 2)
equation_two = sympy.Eq(y, x + 1)
What is the correct way to now substitute equation_one into equation_two? The output should be a new equation.
An approach that works in this case is to use the attributes lhs/rhs ("left hand side" and "right hand side").
import sympy as sp
x = sp.symbols('x')
y = sp.symbols('y')
z = sp.symbols('z')
equation_one = sp.Eq(x, z + 2)
equation_two = sp.Eq(y, x + 1)
print(equation_two.subs(equation_one.lhs,equation_one.rhs))
Result:
Eq(y, z + 3)

Parabolic fit with fixed peak

I have a set of data and want to put a parabolic fit over it. This already works with the polyfit function from numpy like this:
fit = np.polyfit(X, y, 2)
formula = np.poly1d(fit)
Now I want the parabula to have its peak value at a fixed x value and that the fit is still carried out as best as possible with this fixed peak. Is there a way to accomplish that?
From my data I know that the parabola will always be open downwards.
I think this is quite a difficult problem since the x coordinate of the peak of a second-order polynomial (ax^2 + bx + c) always lies in x = -b/2a.
A thing you could do is to drop the b term and offset it by the desired peak x value in fitting the polynomial like the code below. Note that I used scipy.optimize.curve_fit to fit for the custom function func.
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
# generating a parabola with noise
np.random.seed(42)
x = np.linspace(-10, 10, 100)
y = 10 -(x-2)**2 + np.random.normal(0, 5, x.shape)
# function to fit
def func(x, a, c):
return a*x**2 + c
# desired x peak value
x_peak = 2
popt, pcov = curve_fit(func, x - x_peak, y)
y_fit = func(x - x_peak, *popt)
# plotting
plt.plot(x, y, 'k.')
plt.plot(x, y_fit)
plt.axvline(x_peak)
plt.show()
Outputs the image:
Fixing a point on your parabola simplifies the problem, since you can rewrite your equation slightly in terms of a constant now:
y = A(x - B)**2 + C
Given the coefficients a, b, c in your original unconstrained fit, you have the relationships
a = A
b = -2AB
c = AB**2 + C
The only difference is that since B is a constant and you don't have an x - B term in the equation, you need to set up the least-squares problem yourself. Given arrays x, y and constant B, the problem looks like this:
m = np.stack((x - B, np.ones_like(x)), axis=-1)
(A, C), *_ = np.linalg.lstsq(m, y, rcond=None)
You can then extract the normal coefficient from the formulas for a, b, c above.
Here is a complete example, just like the one in the other answer:
B = 2
np.random.seed(42)
x = np.linspace(-10, 10, 100)
y = 10 -(x - B)**2 + np.random.normal(0, 5, x.shape)
m = np.stack(((x - B)**2, np.ones_like(x)), axis=-1)
(A, C), *_ = np.linalg.lstsq(m, y, rcond=None)
a = A
b = -2 * A * B
c = A * B**2 + C
y_fit = a * x**2 + b * x + c
You can drop a, b, c entirely and do
y_fit = A * (x - B)**2 + C
The result will be identical.
plt.plot(x, y, 'k.')
plt.plot(x, y_fit)
Without the condition of location of the peak the function to be fitted would be :
y = a x^2 + b x + c
With condition of location of the peak at x=p , given p :
-b/(2a)=p
b=-2 a p
y = a x^2 -2 a p x + c
y = a (x^2 - 2 p x) +c
Knowing p , one change of variable :
X = x^2 -2 p x
So, from the data (x,y) one first compute the new data (X,y)
Then a and c are computed thanks to linear regression
y = a X + c

Changing coefficients modulo p in a SymPy polynomial

I took a cryptography course this semester in graduate school, and once of the topics we covered was NTRU. I am trying to code this in pure Python, purely as a hobby. When I attempt to find a polynomial's inverse modulo p (in this example p = 3), SymPy always returns negative coefficients, when I want strictly positive coefficients. Here is the code I have. I'll explain what I mean.
import sympy as sym
from sympy import GF
def make_poly(N,coeffs):
"""Create a polynomial in x."""
x = sym.Symbol('x')
coeffs = list(reversed(coeffs))
y = 0
for i in range(N):
y += (x**i)*coeffs[i]
y = sym.poly(y)
return y
N = 7
p = 3
q = 41
f = [1,0,-1,1,1,0,-1]
f_poly = make_poly(N,f)
x = sym.Symbol('x')
Fp = sym.polys.polytools.invert(f_poly,x**N-1,domain=GF(p))
Fq = sym.polys.polytools.invert(f_poly,x**N-1,domain=GF(q))
print('\nf =',f_poly)
print('\nFp =',Fp)
print('\nFq =',Fq)
In this code, f_poly is a polynomial with degree at most 6 (its degree is at most N-1), whose coefficients come from the list f (the first entry in f is the coefficient on the highest power of x, continuing in descending order).
Now, I want to find the inverse polynomial of f_poly in the convolution polynomial ring Rp = (Z/pZ)[x]/(x^N - 1)(Z/pZ)[x] (similarly for q). The output of the print statements at the bottom are:
f = Poly(x**6 - x**4 + x**3 + x**2 - 1, x, domain='ZZ')
Fp = Poly(x**6 - x**5 + x**3 + x**2 + x + 1, x, modulus=3)
Fq = Poly(8*x**6 - 15*x**5 - 10*x**4 - 20*x**3 - x**2 + 2*x - 4, x, modulus=41)
These polynomials are correct in modulus, but I would like to have positive coefficients everywhere, as later on in the algorithm there is some centerlifting involved, so I need to have positive coefficients. The results should be
Fp = x^6 + 2x^5 + x^3 + x^2 + x + 1
Fq = 8x^6 + 26x^5 + 31x^4 + 21x^3 + 40x^2 + 2x + 37
The answers I'm getting are correct in modulus, but I think that SymPy's invert is changing some of the coefficients to negative variants, instead of staying inside the mod.
Is there any way I can update the coefficients of this polynomial to have only positive coefficients in modulus, or is this just an artifact of SymPy's function? I want to keep the SymPy Poly format so I can use some of its embedded functions later on down the line. Any insight would be much appreciated!
This seems to be down to how the finite field object implemented in GF "wraps" integers around the given modulus. The default behavior is symmetric, which means that any integer x for which x % modulo <= modulo//2 maps to x % modulo, and otherwise maps to (x % modulo) - modulo. So GF(10)(5) == 5, whereas GF(10)(6) == -4. You can make GF always map to positive numbers instead by passing the symmetric=False argument:
import sympy as sym
from sympy import GF
def make_poly(N, coeffs):
"""Create a polynomial in x."""
x = sym.Symbol('x')
coeffs = list(reversed(coeffs))
y = 0
for i in range(N):
y += (x**i)*coeffs[i]
y = sym.poly(y)
return y
N = 7
p = 3
q = 41
f = [1,0,-1,1,1,0,-1]
f_poly = make_poly(N,f)
x = sym.Symbol('x')
Fp = sym.polys.polytools.invert(f_poly,x**N-1,domain=GF(p, symmetric=False))
Fq = sym.polys.polytools.invert(f_poly,x**N-1,domain=GF(q, symmetric=False))
print('\nf =',f_poly)
print('\nFp =',Fp)
print('\nFq =',Fq)
Now you'll get the polynomials you wanted. The output from the print(...) statements at the end of the example should look like:
f = Poly(x**6 - x**4 + x**3 + x**2 - 1, x, domain='ZZ')
Fp = Poly(x**6 + 2*x**5 + x**3 + x**2 + x + 1, x, modulus=3)
Fq = Poly(8*x**6 + 26*x**5 + 31*x**4 + 21*x**3 + 40*x**2 + 2*x + 37, x, modulus=41)
Mostly as a note for my own reference, here's how you would get Fp using Mathematica:
Fp = PolynomialMod[Algebra`PolynomialPowerMod`PolynomialPowerMod[x^6 - x^4 + x^3 + x^2 - 1, -1, x, x^7 - 1], 3]
output:
1 + x + x^2 + x^3 + 2 x^5 + x^6

Categories

Resources