Eliminate a variable to relate two functions in Python using SymPy - python

I have two equations that are parametrized by a variable "t". These look like:
X = p(t)
Y = q(t)
where p and q are polynomials in t. I want to use Python's SymPy library to eliminate the t variable and express Y = F(X) for some function X. I have tried using solve() in SymPy but this is not working too well. I know that Maple and Mathematica both have eliminate() functions that can accomplish this, but I wanted to know if Python might have a general function that does this.

Here is a lightly tested simple routine
def eliminate(eqs, z):
"""return eqs with parameter z eliminated from each equation; the first
element in the returned list will be the definition of z that was used
to eliminate z from the other equations.
Examples
========
>>> eqs = [Eq(2*x + 3*y + 4*z, 1),
... Eq(9*x + 8*y + 7*z, 2)]
>>> eliminate(eqs, z)
[Eq(z, -x/2 - 3*y/4 + 1/4), Eq(11*x/2 + 11*y/4 + 7/4, 2)]
>>> Eq(y,solve(_[1], y)[0])
Eq(y, -2*x + 1/11)
"""
from sympy.solvers.solveset import linsolve
Z = Dummy()
rv = []
for i, e in enumerate(eqs):
if z not in e.free_symbols:
continue
e = e.subs(z, Z)
if z in e.free_symbols:
break
try:
s = linsolve([e], Z)
if s:
zi = list(s)[0][0]
rv.append(Eq(z, zi))
rv.extend([eqs[j].subs(z, zi)
for j in range(len(eqs)) if j != i])
return rv
except ValueError:
continue
raise ValueError('only a linear parameter can be eliminated')
There is a more complex routine at this issue.

I refer to this example from the 'Scope' section of https://reference.wolfram.com/language/ref/Eliminate.html.
Eliminate[2 x + 3 y + 4 z == 1 && 9 x + 8 y + 7 z == 2, z]
>>> from sympy import *
>>> var('x y z')
(x, y, z)
>>> solve(2*x+3*y+4*z-1, z)
[-x/2 - 3*y/4 + 1/4]
>>> solve(9*x+8*y+7*z-2, z)
[-9*x/7 - 8*y/7 + 2/7]
>>> (-9*x/7 - 8*y/7 + Rational(2,7))-(-x/2 - 3*y/4 + Rational(1,4)).simplify()
-11*x/14 - 11*y/28 + 1/28
>>> 28*((-9*x/7 - 8*y/7 + Rational(2,7))-(-x/2 - 3*y/4 + Rational(1,4)).simplify())
-22*x - 11*y + 1
Solve each equation for z.
Subtract one expression for z from the other.
Note only that numeric fractions need to be coded — I've used Rational because I forget other methods — so that fractional arithmetic is used.
I multiply through to get rid of the denominators.
This approach will work only for the elimination of a single variable. I haven't considered the second and subsequent examples.
I hope this is useful.

Suppose you wanted to solve the equations for as a function of . This can be done by solving for both and :
solve(
[
Eq(z, sin(theta)),
Eq(z_o, cos(theta))
],
[z_o, theta],
dict=True
)
which yields
You can then throw away the result for and use the rest. This doesn't work for all situations - it requires that the intermediate variable be something that sympy could solve for directly.

Related

How to integrate expressions with sympy?

I have a problem integrating an expression:
I need to integrate all terms regardless of the variable,
the expression: -x + 2 * (x - 1)
Expected result: -x**2/2 + 2 * ((x - 1)**2) / 2
the code I'm using:
from sympy import *
x = symbols('x')
expr = - x + factor(2 * (x - 1))
int_1 = integrate(expr)
print(int_1)
generated result: x**2/2 - 2*x
I'm a python beginner...
Thank you!
If you check your result you will find it is the same as the original equation, so the answer is right:
>>> eq = -x + factor(2 * (x - 1))
>>> integrate(eq).diff()
x - 2
>>> eq.expand()
x - 2
This means that the result you got differed from the expected results by a constant and such cases are considered correct in terms of indefinite integration.
It looks like you already learned about autoexpansion (thus the use of factor to keep the 2 from distributing). What you may not realize, however, is that once you pass an expression to a routine it is not required to keep your expression in factored form. It looks like you were expecting that the x - 1 would be treated like x. We can simulate that as
>>> integrate(-x)+integrate(2*y).subs(y,x-1)
-x**2/2 + (x - 1)**2
Using y to represent x - 1 is ok in this case since the results only differ by a constant:
>>> (integrate(x-1) - integrate(y).subs(y ,x-1)).is_constant()
True
It will not, however, be true for all functions of x.
The problem is that you didn't pass any integration limits (from and to), so the only possible answer was the integrated formula.
If for example you want to integrate from 0 to inf, you need to pass this instead
from sympy import *
x = symbols('x')
expr = - x + factor(2 * (x - 1))
int_1 = integrate(expr, (x,0, float('inf')))
print(int_1)
replace 0 and/or float('inf') by any numbers you want to evaluate.

Why doesn't SymPy simplify the expression?

I am just looking at the Python module SymPy and try, as a simple (useless) example the fit of a function f(x) by a function set g_i(x) in a given interval.
import sympy as sym
def functionFit(f, funcset, interval):
N = len(funcset) - 1
A = sym.zeros(N+1, N+1)
b = sym.zeros(N+1, 1)
x = sym.Symbol('x')
for i in range(N+1):
for j in range(i, N+1):
A[i,j] = sym.integrate(funcset[i]*funcset[j],
(x, interval[0], interval[1]))
A[j,i] = A[i,j]
b[i,0] = sym.integrate(funcset[i]*f, (x, interval[0], interval[1]))
c = A.LUsolve(b)
u = 0
for i in range(len(funcset)):
u += c[i,0]*funcset[i]
return u, c
x = sym.Symbol('x')
f = 10*sym.cos(x)+3*sym.sin(x)
fooset=(sym.sin(x), sym.cos(x))
interval = (1,2)
print("function to approximate:", f)
print("Basic functions:")
for foo in fooset:
print(" - ", foo)
u,c = functionFit(f, fooset, interval)
print()
print("simplified u:")
print(sym.simplify(u))
print()
print("simplified c:")
print(sym.simplify(c))
The result is the fit function u(x), to be returned, together with the coefficients by functionFit.
In my case
f(x) = 10 * sym.cos(x) + 3 * sym.sin(x)
and I want to fit it according to a linear combination of sin(x), cos(x).
So the coefficients should be 3 and 10.
The result is OK, but for u(x) I get
u(x) = (12*sin(2)**2*sin(4)*sin(x) + 3*sin(8)*sin(x) + 12*sin(2)*sin(x) + 40*sin(2)**2*sin(4)*cos(x) + 10*sin(8)*cos(x) + 40*sin(2)*cos(x))/(2*(sin(4) + 2*sin(2))) :
Function to approximate: 3*sin(x) + 10*cos(x)
Basic functions:
- sin(x)
- cos(x)
Simplified u: (12*sin(2)**2*sin(4)*sin(x) + 3*sin(8)*sin(x) + 12*sin(2)*sin(x) + 40*sin(2)**2*sin(4)*cos(x) + 10*sin(8)*cos(x) + 40*sin(2)*cos(x))/(2*(sin(4) + 2*sin(2)))
Simplified c: Matrix([[3], [10]])
which is indeed the same as 10 * cos(x) + 3 * sin(x).
However I wonder why it is not simplified to that expression. I tried several simplifying function available, but none of it gives the expected result.
Is there something wrong in my code or are my expectations to high?
Don't know if this is a solution for you, but I'd simply use the .evalf method of every Sympy expression
In [26]: u.simplify()
Out[26]: (12*sin(2)**2*sin(4)*sin(x) + 3*sin(8)*sin(x) + 12*sin(2)*sin(x) + 40*sin(2)**2*sin(4)*cos(x) + 10*sin(8)*cos(x) + 40*sin(2)*cos(x))/(2*(sin(4) + 2*sin(2)))
In [27]: u.evalf()
Out[27]: 3.0*sin(x) + 10.0*cos(x)
In [28]:

Map linsolve solutions to indexed symbols in Sympy

I am trying to solve a set of linear simultaneous equations using linsolve in Sympy over a range of values. For simplicity I am showing below what I have been trying to do using simple equations.
from sympy import symbols, linsolve, IndexedBase
m = 2
n = symbols('n', integer=True)
x, y = symbols('x, y', cls=IndexedBase)
for n in range (0, m+1):
E1 = 2*x[n] + 5*y[n] - 33 + 2*n
E2 = x[n] + 3*y[n] - 19 + 4*n
sol = linsolve([E1, E2], [x[n], y[n]])
(x[n], y[n]) = tuple(*sol)
This returns an error "'IndexedBase' object does not support item assignment". How can I map the solution values to the indexed symbols so that I will be able to use them later in the code (e.g., take the sum of all x values (x[0] + x[1] + x[2])? I am looking for a robust solution as for the real equations the value of m can be around 500.
SymPy objects are immutable; one cannot attach numeric data to them. "x" is always just that, a symbol "x"; and "x[2]" is an indexed symbol "x[2]". They do not get associated with any numeric values. To store solutions, use a list of tuples or a dictionary (or list of dictionaries), whichever is more convenient.
solutions = {}
for n in range(0, m+1):
E1 = 2*x[n] + 5*y[n] - 33 + 2*n
E2 = x[n] + 3*y[n] - 19 + 4*n
sol = linsolve([E1, E2], [x[n], y[n]])
solutions.update(dict(zip([x[n], y[n]], *sol)))
print(solutions)
This prints {x[0]: 4, y[0]: 5, x[1]: 18, y[1]: -1, x[2]: 32, y[2]: -7}. You can then use this dictionary in subs:
expr = x[0] + 3*y[2]
print(expr.subs(solutions)) # -17

Use index of summation as the order of derivation

Given some function f, I want to compute the following sum using sympy:
In general I want to use the index of summation as the order of differentiation of the function but I could not find out how to do it with sympy.
Given n is an int you know in advance, you can construct a function:
from sympy import diff
def sum_diff_order(f,x,n):
g = 0
for i in range(n+1):
g += diff(f,x,i)
return g
So if you take f to be x**10 and n=5, we get:
>>> x = symbols('x')
>>> f = x**10
>>> sum_diff_order(f,x,5)
x**10 + 10*x**9 + 90*x**8 + 720*x**7 + 5040*x**6 + 30240*x**5
import sympy as sp
x = sp.symbols('x')
f = sp.Function('f')
n = 2
sum([f(x).diff(x,i) for i in range(n+1)])
f(x) + Derivative(f(x), x) + Derivative(f(x), x, x)
If n is an known integer, you can use something like Add(*[diff(f(x), x, i) for i in range(n+1)]). For symbolic n or infinity, it isn't possible yet, as there is no way yet to represent derivatives of symbolic order.

Linear Regression in Python

I am a brand new to programming and am taking a course in Python. I was asked to do linear regression on a data set that my professor gave out. Below is the program I have written (it doesn't work).
from math import *
f=open("data_setshort.csv", "r")
data = f.readlines()
f.close()
xvalues=[]; yvalues=[]
for line in data:
x,y=line.strip().split(",")
x=float(x.strip())
y=float(y.strip())
xvalues.append(x)
yvalues.append(y)
def regression(x,y):
n = len(x)
X = sum(x)
Y = sum(y)
for i in x:
A = sum(i**2)
return A
for i in x:
for j in y:
C = sum(x*y)
return C
return C
D = (X**2)-nA
m = (XY - nC)/D
b = (CX - AY)/D
return m,b
print "xvalues:", xvalues
print "yvalues:", yvalues
regression(xvalues,yvalues)
I am getting an error that says: line 23, in regression, A = sum (I**2). TypeError: 'float' object is not iterable.
I need to eventually create a plot for this data set (which I know how to do) and for the line defined by the regression. But for now I am trying to do linear regression in Python.
You can't sum over a single float, but you can sum over lists. E. g. you probably mean A = sum([xi**2 for xi in x]) to calculate Sum of each element in x to the power of 2. You also have various return statements in your code that don't really make any sense and can probably be removed completely, e. g. return C after the loop. Additionally, multiplication of two variables a and b can only be done by using a*b in python. Simply writing ab is not possible and will instead be regarded as a single variable with name "ab".
The corrected code could look like this:
def regression(x,y):
n = len(x)
X = sum(x)
Y = sum(y)
A = sum([xi**2 for xi in x])
C = sum([xi*yi for xi, yi in zip(x,y)])
D = X**2 - n*A
m = (X*Y - n*C) / float(D)
b = (C*X - A*Y) / float(D)
return (m, b)
You should probably put in something like A += i**2
As you must understand from the error message that you cannot iterate over a float, which means if i=2 you can't iterate over it as it is not a list, but if as you need to sum all the squares of x, you are iterating over x in for i in x and then you add the squares of i i**2 to A A+=i**2 adn then you return A.
Hope this helps!

Categories