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
Related
I am currently working on a project for calculating polynomial shifts via python of nth degree.
The user can input n amount of inputs which get stored in an array that then get converted via the shift and turned back into a new polynomial. The problem is, the higher the degree of n, the more calculations necessary to turn the shifted value to it's polynomial coefficient:
What the program should do is add and multiply all the values uniquely and save the result in a new array:
e.g. for a polynomial of degree 4, it will have inputs [a,b,c,d]
shiftedPCL[0] = a + b + c + d
shiftedPCL[1] = a*b + b*c + c*d + a*c + b*d + a*d
shiftedPCL[2] = a*b*c + b*c*d + a*b*d + a*c*d
shiftedPCL[3] = a*b*c*d
The first and last lines of the equations can be solved simply by summing and multiplying all the values in a list respectively, and I have created a simple recursive code to calculate the second to last line of equations using recursion, but for n greater than 3 it is useless, as it cannot calculate any lines that aren't the first, last or second to last.
This is why I would like to know if there's a way to add and multiply all elements in a list as shown above (for lists of any length).
What you are trying to do is the expansion of a product of monic binomials like
(x+a)(x+b)(x+c)(x+d) = x^4 + Ax^3 + Bx^2 + Cx + D.
Don't do that by means of the (modified) Vieta's formulas. Instead, apply one binomial at a time.
E.g. after three factors already expanded,
(x^3 + Px^2 + Qx + R)(x + d) = x^4 + (P + d) x^3 + (Q + Pd) x^2 + (R + Qd) x + Rd.
The element at index i in your resulting array is the sum of all products of combinations of i elements.
In python, the sum of all products of combinations of i elements from a list l can be written as:
sum(map(prod, combinations(l,i)))
Where sum and map are builtin functions, and prod and combinations are imported from standard library modules math and itertools, respectively.
from itertools import combinations
from math import prod
def sums_of_products(l):
return [sum(map(prod, combinations(l,i))) for i in range(1, len(l)+1)]
We can test this function with numbers, or with symbols using sympy:
from sympy import symbols
a,b,c,d = symbols('a b c d')
print( sums_of_products([a,b,c,d]) )
# [a + b + c + d,
# a*b + a*c + a*d + b*c + b*d + c*d,
# a*b*c + a*b*d + a*c*d + b*c*d,
# a*b*c*d]
print( sums_of_products([2,3,5,7]) )
# [17, 101, 247, 210]
The easiest way to do this in my opinion would be using python itertool. Python itertool is a module that provides various functions that work on iterators to produce complex iterators. The function is itertools permutations. This might be the easiest though slowest program:
from itertools import permutations
list1 = [1,2,3,4] #replace with a, b, c and d
shiftedPCL = []
for i in range(1,len(list1)+1):
comb = permutations(list1, i)
sum1 = 0
for j in comb:
print(j)
result = 1
for x in j:
result = result * x
sum1 += result
shiftedPCL.append(sum1)
print(shiftedPCL)
Variable Names changed as recommended by #Stef
The sequence is:
an = an-1 + (2 * an-2)
a0 = 1, a1= 1. Find a100
The way I did it is making a list.
#List 'a' with a0 = 1 , a1 = 1.
a = [1,1]
#To get the a100, implement 'i' as the index value of the list.
for i in range (2,101):
x = a[i-1] + (2 * a[i-2])
print( str(len(a)) + (": ") + str(x))
#Save new value to list
a.append(x)
Is there another way to do this where you can just directly get the value of a100? Or the value of a10000.. it will take up so much memory.
For this specific case, the sequence appears to be known as the Jacobsthal sequence. Wikipedia gives a closed form expression for a_n that can be expressed as follows:
def J(n):
return (2**(n+1) - (1 if n % 2 else -1))//3
Slightly more generally, you can use fast matrix exponentiation to find a specific value of a_n in O(log n) matrix operations. The approach here is a slight modification of this.
import numpy as np
def a(n):
mat = np.array([[1, 2], [1, 0]], dtype=object) # object for large integers
return np.linalg.matrix_power(mat, n)[0,0]
Here is the value for a_1000:
7143390714575115472989500327066678737076032078036890716291669255802340340832907483287989192104639054183964486117020978834580968571282093623989718383132383202623045183216153990280716403374914094585302788102030983322387960844932511706110362630718041943047464318457694778440286554435082924558137112046251
This recurrence relation has a closed form solution:
a = lambda n: (2**(n+1) + (-1)**n)//3
Then
a(0) == 1
a(1) == 1
a(2) == 3
...
Use Wolfram Alpha solve for the closed form solution.
For a more general solution, sympy's rsolve can generate a formula for linear recurrences. And then use substitution to find particular values.
from sympy import rsolve, Function, symbols
f = Function('f')
n = symbols('n', integer=True)
T = f(n) - f(n - 1) - 2 * f(n - 2)
sol = rsolve(T, f(n), {f(0): 1, f(1): 1})
print(sol.factor())
for k in range(6):
print(f'a[{10**k}] = {sol.subs({n:10**k})}')
This finds the formula: ((-1)**n + 2*2**n)/3 and substituting various values gives:
a[1] = 1
a[10] = 683
a[100] = 845100400152152934331135470251
a[1000] = 7143390714575115472989500327066678737076032078036890716291669255802340340832907483287989192104639054183964486117020978834580968571282093623989718383132383202623045183216153990280716403374914094585302788102030983322387960844932511706110362630718041943047464318457694778440286554435082924558137112046251
a[10000] = 13300420779205055899224947751223900558823312212574616365680059665686292553481297754613307789357463065266220752948806082847704327566275854078395857288064215971903820031195863017843497700844039930347033391278795541028339072307078736457006049910726416592060326596558672835961088838567081045539649268371274925376816731095916294031173247751323635481912358774462877183753093841891253840488152356727760984122637587639312975932940560640357511880709747618222262691017043766353735428453489979600223956211100972865182186443850404115054687605329465453071585497122508186691535256991501267222976387636433705286400943222614410489725426171396919846079518533884638490449629415374679171890883668485549192847140249201910928687618755494267749463781127049374279769561549759200832570764870138287994839741197500087328573494472227205070621546774178994858997503894208562707691159300991409504210074059830342802209213468621093971730976504006937230561044048029975244677676707947087336124281517272447267049737611904634607637370045500833604005013228174598706158078702963192048604263495032226147988471602982108251173897742022519137359868942131422329103081800375446624970338827853981873988860876269047918349845673238184625284288814399599917924440538912558558685095521850114849105048496522741529593155873907738282168861316542080131736118854643798317265443020838956090639908522753418790270855651099392460347365053921743882641323846748271362887055383912692879736402269982104388805781403942200602501882277026496929598476838303527006808207298214407168983217160516849324232198998893837958637097759081249712999519344381402467576288757211476207860932148655897231556293513976121900670048618498909700385756334067235325208259649285799693889564105871362639412657210097186118095746465818754306322522134720983321447905340926047485500603884544957480384983947611769143791817076603055269994974019086721023722205420067991783904156229025970272783748933896591684108429045765889012975813584862160062970831282169566933785351515891836917604484599090827358327607311145704700506065400164526586785514617302254188281302685535172938965970009784445593131997924161090875584262602248970534271757827918474036922817159666073457645479797721100990086996148246631809842046103645478455250800241851505149187576887740797874187195112987924800865762440512367759907023068198581038345298256830912964615391929510632144672034080214910330858779357159414245558929061170945822567007313514409276959727327732103102944890874437957354081499958646666151187821572015407908429716866090505450005466559490856410166587392640154829574782514412057571343645656039081553195235917082324370960357975081345975714019208241045008362225535513352731779100379038105003677818345932796086474225126766610787543447696005152433715459704967280220123536564742545543604882702212692308056024281175802607700426526000495235781464187268985316355546978912530579053491968145752746720495213034211965438416298865678974339803258684849814383125421063166939821410053665460303868944551299858094210708807124261007787849536528397806251
I have a math function whose output is defined by two variables, x and y.
The function is e^(x^3 + y^2).
I want to calculate every possible integer combination between 1 and some defined integer for x and y, and place them in an array so that each output is aligned with the cooresponding x value and y value index. So something like:
given:
x = 3
y = 5
output would be an array like this:
f(1,1) f(1,2) f(1,3)
f(2,1) f(2,2) f(2,3)
f(3,1) f(3,2) f(3,3)
f(4,1) f(4,2) f(4,3)
f(5,1) f(5,2) f(5,3)
I feel like this is an easy problem to tackle but I have limited knowledge. The code that follows is the best description.
import math
import numpy as np
equation = math.exp(x**3 + y**2)
#start at 1, not zero
i = 1
j = 1
#i want an array output
output = []
#function
def shape_f (i,j):
shape = []
output.append(shape)
while i < x + 1:
while j < y +1:
return math.exp(i**3 + j**2)
#increase counter
i = i +1
j = j +1
print output
I've gotten a blank array recently but I have also gotten one value (int instead of an array)
I am not sure if you have an indentation error, but it looks like you never do anything with the output of the function shape_f. You should define your equation as a function, rather than expression assignment. Then you can make a function that populates a list of lists as you describes.
import math
def equation(x, y):
return math.exp(x**3 + y**2)
def make_matrix(x_max, y_max, x_min=1, y_min=1):
out = []
for i in range(x_min, x_max+1):
row = []
for j in range(y_min, y_max+1):
row.append(equation(i, j))
out.append(row)
return out
matrix = make_matrix(3, 3)
matrix
# returns:
[[7.38905609893065, 148.4131591025766, 22026.465794806718],
[8103.083927575384, 162754.79141900392, 24154952.7535753],
[1446257064291.475, 29048849665247.426, 4311231547115195.0]]
We can do this very simply with numpy.
First, we use np.arange to generate a range of values from 0 (to simplify indexing) to a maximum value for both x and y. We can perform exponentiation, in a vectorised manner, to get the values of x^3 and y^2.
Next, we can apply np.add on the outer product of x^3 and y^3 to get every possible combination thereof. The final step is taking the natural exponential of the result:
x_max = 3
y_max = 5
x = np.arange(x_max + 1) ** 3
y = np.arange(y_max + 1) ** 2
result = np.e ** np.add.outer(x, y)
print(result[2, 3]) # e^(2 ** 3 + 3 ** 2)
Output:
24154952.753575277
A trivial solution would be to use the broadcasting feature of numpy with the exp function:
x = 3
y = 5
i = np.arange(y).reshape(-1, 1) + 1
j = np.arange(x).reshape(1, -1) + 1
result = np.exp(j**3 + y**2)
The reshape operations make i into a column with y elements and j into a row with x elements. Exponentiation does not change those shapes. Broadcasting happens when you add the two arrays together. The unit dimensions in one array get expanded to the corresponding dimension in the other. The result is a y-by-x matrix.
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.
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.