I'm trying to code various optimisation methods, as a way of revising. I want to be able to use SymPy to evaluate a function with an arbitrary number of variables at a given point, where the co-ordinates of the point are stored in an array.
For example, I'd like to evaluate f(x,y) = 3*x**2 - 2*x*y + y**2 + 4*x + 3*y at the point b = [1,2]. But I'd really like a general way of doing it, that can handle a function with any number of variables and an appropriate length array as the point to be evaluated as, so sympy.evalf(f, subs = {foo}) isn't really very useful.
You are working with SymPy expression trees, not functions. On any expression you can do:
>>> vars = sorted(expression.free_symbols)
>>> evaluated = expression.subs(*zip(vars, your_values))
I would also expect this to be easier to do, but here's a good workaround:
If you know the symbol names ('x','y', e.g.), you can create a dict on the fly using zip:
fvars = sympy.symbols('x, y') #these probably already exist, use: fvars = [x,y]
b = [1,2]
sympy.evalf(f, subs = dict(zip(fvars,b)))
lambdify is a good option to generate a Python-callable function.
An example, assuming you have a function f and the symbols x and y:
from sympy import lambdify
import numpy as np
callable_fct = lambdify((x, y), f)
xn = np.arange(0, 2, 0.1)
yn = 3
print(callable_fct(xn, yn))
Related
I'm making a solver of cubic equations in Python that includes division of polynomials.
from sympy import symbols
# Coefficients
a = int(input("1st coef: "))
b = int(input("2nd coef: "))
c = int(input("3rd coef: "))
d = int(input("Const: "))
# Polynomial of x
def P(x):
return a*x**3 + b*x**2 + c*x + d
x = symbols('x')
# Find 1 root by Cardano
R = (3*a*c - b**2) / (9*a**2)
Q = (3*b**3 - 9*a*b*c + 27*a**2*d) / (54*a**3)
Delta = R**3 + Q**2
y = (-Q + sqrt(Delta))**(1/3) + (-Q - sqrt(Delta))**(1/3)
x_1 = y - b/(3*a)
# Division
P(x) / (x - x_1) = p(x)
print(p(x)) # Just a placeholder
The program returns an error: "cannot assign to operator" and highlights the P(x) after the # Division comment (worded poorly, yes, but I'm from Russia so idc).
What I tried doing was to assign a variable to a polynomial and then dividing:
z = P(x)
w = x - x_1
p = z / w
print(p)
But alas: it just returns a plain old quotient (a = 1, b = 4, c = -9, d = -36):
(x**3 + 4*x**2 - 9*x - 36)/(x - 2.94254537742264)
Does anyone out here knows what to do in this situation (not to mention the non-exact value of x_1: the roots of x^3+4x^2-9x-36=0 are 3, -4, and -3, no floaty-irrational-messy-ugly things in sight)?
tl;dr: Polynomial division confusion and non-exact roots
I am not sure what exactly your question is but here is an attempt at an answer
The line
P(x) / (x - x_1) = p(x)
is problematic for multiple reasons. First of all it's important to know that the = operator in python (and a lot of other modern programming languages) is an assignment operator. You seem to come from more of a math background, so consider it to be something like the := operator. The direction of this is always fixed, i.e. with a = b you are always assigning the value of b to the variable a. In your case you are basically assigning an expression the value of p which does not make much sense:
Python can't assign anything to an expression (At least not as far as I know)
p(x) is not yet defined
The second problem is that you are mixing python functions with math functions.
A python function looks something like this:
def some_function(some_parameter)
print("Some important Thing!: ", some_parameter)
some_return_value = 42
return some_return_value
It (can) take some variable(s) as input, do a bunch of things with them, and then (can) return something else. They are generally called with the bracket operator (). I.e. some_function(42) translates to execute some_function and substitute the first parameter with the value 42. An expression in sympy however is as far as python is concerned just an object/variable.
So basically you could have just written P = a*x**3 + b*x**2 + c*x + d. What your P(x) function is doing is basically taking the expression a*x**3 + b*x**2 + c*x + d, substituting x for whatever you have put in the brackets, and then giving it back in as a sympy expression. (It's important to understand, that the x in your P python function has nothing to do with the x you define later! Because of that, one usually tries to avoid such "false friends" in coding)
Also, a math function in sympy is really just an expression formed from sympy symbols. As far as sympy is concerned, the return value of the P function is a (mathematical) function of the symbols a,b,c,d and the symbol you put into the brackets. This is why, whenever you want to integrate or differentiate, you will need to specify by which symbol to do that.
So the line should have looked something like this.
p = P(x) / (x - x_1)
Or you leave replace the P(x) function with P = a*x**3 + b*x**2 + c*x + d and end up with
p = P / (x - x_1)
Thirdly if you would like to have the expression simplified you should take a look here (https://docs.sympy.org/latest/tutorial/simplification.html). There are multiple ways here of simplifying expressions, depending on what sort of expression you want as a result. To make for faster code sympy will only simplify your expression if you specifically ask for it.
You might however be disappointed with the results, as the line
y = (-Q + sqrt(Delta))**(1/3) + (-Q - sqrt(Delta))**(1/3)
will do an implicit conversion to floating point numbers, and you are going to end up with rounding problems. To blame is the (1/3) part which will evaluate to 0.33333333 before ever seeing sympy. One possible fix for this would be
y = (-Q + sqrt(Delta))**(sympy.Rational(1,3)) + (-Q - sqrt(Delta))**(sympy.Rational(1,3))
(You might need to add import sympy at the top)
Generally, it might be worth learning a bit more about python. It's a language that mostly tries to get out of your way with annoying technical details. This unfortunately however also means that things can get very confusing when using libraries like sympy, that heavily rely on stuff like classes and operator overloading. Learning a bit more python might give you a better idea about what's going on under the hood, and might make the distinction between python stuff and sympy specific stuff easier. Basically, you want to make sure to read and understand this (https://docs.sympy.org/latest/gotchas.html).
Let me know if you have any questions, or need some resources :)
according to this graph: desmos
print(solve('x**2 + x - 1/x'))
# [-1/3 + (-1/2 - sqrt(3)*I/2)*(sqrt(69)/18 + 25/54)**(1/3) + 1/(9*(-1/2 - sqrt(3)*I/2)*(sqrt(69)/18 + 25/54)**(1/3)), -1/3 + 1/(9*(-1/2 + sqrt(3)*I/2)*(sqrt(69)/18 + 25/54)**(1/3)) + (-1/2 + sqrt(3)*I/2)*(sqrt(69)/18 + 25/54)**(1/3), -1/3 + 1/(9*(sqrt(69)/18 + 25/54)**(1/3)) + (sqrt(69)/18 + 25/54)**(1/3)]
I was expecting [0.755, 0.57], but, I got something I cannot use in my future program. I desire to get a list of floats as result, so refer to this post, I did following, but I got some even more weird:
def solver(solved, rit=3):
res = []
for val in solved:
if isinstance(val, core.numbers.Add):
flt = val.as_two_terms()[0]
flt = round(flt, rit)
else:
flt = round(val, rit)
if not isinstance(flt, core.numbers.Add):
res.append(flt)
return res
print(solver(solve('x**2 + x - 1/x')))
# [-0.333, -0.333, -0.333]
Now I am really disappointed with sympy, I wonder if there is an accurate way to get a list of floats as result, or I will code my own gradient descent algorithm to find the roots and intersection.
sym.solve solves an equation for the independent variable. If you provide an expression, it'll assume the equation sym.Eq(expr, 0). But this only gives you the x values. You have to substitute said solutions to find the y value.
Your equation has 3 solutions. A conjugate pair of complex solutions and a real one. The latter is where your two graphs meet.
import sympy as sym
x = sym.Symbol('x')
# better to represent it like the equation it is
eq = sym.Eq(x**2, 1/x - x)
sol = sym.solve(eq)
for s in sol:
if s.is_real:
s = s.evalf()
print(s, eq.lhs.subs({x: s})) # eq.rhs works too
There are a variety of things you can do to get the solution. If you know the approximate root location and you want a numerical answer, nsolve is simplest since it has no requirements on the type of expression:
>>> from sympy import nsolve, symbols
>>> x = symbols('x')
>>> eq = x**2 + x - 1/x
>>> nsolve(eq, 1)
0.754877666246693
You can try a guess near 0.57 but it will go to the same solution. So is there really a second real roots? You can't use real_roots on this expression because it isn't in polynomial form. But if you split it into numerator and denominator you can check for the roots of the numerator:
>>> n, d = eq.as_numer_denom()
>>> from sympy import real_roots
>>> real_roots(n)
[CRootOf(x**3 + x**2 - 1, 0)]
So there is only one real root for that expression, the one that nroots gave you.
Note: the answer that solve gives is an exact solution to the cubic equation and it can't figure out definitively which ones are a solution to the equation so it returns all three. If you evaluate them you will find that only one of them is real. But since you don't need the symbolic solution, just stick to nroots.
Not sure why I can't find something on this but here's my question:
How do I initiate an integer without giving it a value so I can use it to solve equations.
E.g., if I specified that I had some integer x then I could write something that allows me to solve functions with respect to x.
E.g., an output might be: 2x+5
EX:
# Eisenstein Prime?
# 1J is complex number i
def eisenstein(a,b):
w = e**((2*math.pi*1J)/3)
z=a+b*w
a = a+b*(w**2)
print("Eisenstein Integer as z:")
print(z)
print("Omega as w:")
print(w)
This outputs:
Eisenstein Integer as z:
(-0.9999999999999987+5.196152422706632j)
Omega as w:
(-0.4999999999999998+0.8660254037844387j)
I'd like to have the variable similar to how j appears above.
You can't do that with plain ints. You'll need to install a package for symbolic mathematics.
python -m pip install sympy
Then to use it,
import sympy as sp
x = sp.var('x')
equation = 2*x + 5
print(sp.solve([equation], [x]))
Output:
{x: -5/2}
The solver takes lists because it can do systems of equations. You can also just
sp.solve(equation, x)
And get
[-5/2]
Another example.
import sympy as sp
x, y = sp.var('x y')
equation = 2*x + 5*y # Equations made this way are implicitly "= 0".
print(sp.solveset(equation, y, sp.S.Complexes))
Solved for y, note the output is in terms of x:
{-2*x/5}
I am trying to solve simultaneous equations for x and y, I am not getting any result (code just keeps on running). I feel the error is related to using sqrt in the equations but not sure. Can someone help me figure this out?
from __future__ import division
from sympy import Symbol,sqrt,solve
x = Symbol('x')
y = Symbol('y')
z = Symbol('z')
a = Symbol('a')
b = Symbol('b')
c = Symbol('c')
d = Symbol('d')
e = Symbol('e')
f = Symbol('f')
g = Symbol('g')
h = Symbol('h')
print (solve((sqrt((c-a)**2+(d-b)**2)+sqrt((x-c)**2+(y-d)**2)-2*sqrt((x-a)**2+(y-b)**2),(y-b)*(e-a)-(x-a)*(f-b)) ,x,y))
This is a(nother) problem were you have to rely on the A of CAS and let SymPy assist you instead of relying on SymPy (in it's current state) to do all the work. The following assumes that eqs is a list of the two equations you want to solve as you gave in the OP.
Notice that the 2nd equation is linear in both symbols. Solve for y and substitute into the first equation.
>>> yis = solve(eqs[1], y)[0]
>>> eq0 = eqs[0].subs(y,yis)
This gives an expression that has a lot of symbols in it and that slows things down. It also has two terms with sqrt that depend on x. Replace those arguments of the sqrt with Dummy symbols and then unrad the expression to get it in polynomial form, restore replacements and factor:
>>> from sympy.solvers.solvers import unrad, S
>>> reps = {i.base:Dummy() for i in eq0.atoms(Pow) if i.has(x) and i.exp==S.Half}
>>> ireps = {v:k for k,v in reps.items()}
>>> poly = unrad(eq0.xreplace(reps), *reps.values())[0].xreplace(ireps).factor()
Using factor is an expensive process to always use, but if you know the problem is going to take a long time without it, it is worth a try. In this case a quartic reduces to a product of quadratics which are easy to solve and don't require checking or simplification:
>>> xis = solve(poly, x)
There are three solutions for x and each of these can be substituted into the expression for y to get the three solutions. The solutions are large enough so they are not shown here.
>>> count_ops(xis)
386
SymPy does a wonderful work keeping track of all the operations I do to my symbolic expressions. But a the moment of printing the result for latex output I would like to enforce a certain ordering of the term. This is just for convention, and unfortunately that convention is not alphabetical on the symbol name(as reasonably sympy does)
import sympy as sp
sp.init_printing()
U,tp, z, d = sp.symbols('U t_\perp z d')
# do many operations with those symbols
# the final expression is:
z+tp**2+U+U/(z-3*tp)+d
My problem is that SymPy presents the expression ordered as
U + U/(-3*t_\perp + z) + d + t_\perp**2 + z
But this ordering is not the convention in my field. For us z has to be the leftmost expression, then tp, then U even if it is capitalized, d is the most irrelevant and is put at the right. All this variables hold a particular meaning and that is the reason we write them in such order, and the reason in the code variables are named in such way.
I don't want to rename z to a and as suggested in Prevent Sympy from rearranging the equation and then at the moment of printing transform that a into z. In Force SymPy to keep the order of terms there is a hint I can write a sorting function but I could not find documentation about it.
If you can put the terms in the order you want then setting the order flag for the Latex printer to 'none' will print them in that order.
>>> import sympy as sp
>>> sp.init_printing()
>>> U,tp, z, d = sp.symbols('U t_\perp z d')
>>> eq=z+tp**2+U+U/(z-3*tp)+d
Here we put them in order (knowing the power of tp is 2) and rebuild as an Add with evaluate=False to keep the order unchanged
>>> p = Add(*[eq.coeff(i)*i for i in (z, U, tp**2, d)],evaluate=False)
And now we print that expression with a printer instance with order='none':
>>> from sympy.printing.latex import LatexPrinter
>>> s=LatexPrinter(dict(order='none'))
>>> s._print_Add(p)
z + U \left(1 + \frac{1}{z - 3 t_\perp}\right) + t_\perp^{2} + d