Solve algebraic equation in SymPy - python

I am trying to solve simple algebraic parametrized equation sqrt(x)=sqrt(a)+1 with SymPy command solveset:
x, a = symbols("x a")
solveset(Eq(sqrt(x), sqrt(a)+1), x)
It returns as part of answer (conditional set) two solutions: 2*sqrt(a)+a+1 and -2*sqrt(a)+a+1. I can't understand how we can obtain the second one with minus sign from our equation!
Command solve in the same time gives us only solution (sqrt(a) + 1)**2, which is correct in my opinion.
What happens with solveset, any ideas?

The issue is to do with the sets you are solving over. Specifically, solveset defaults to a complex domain, resulting in extraneous solutions due to the complex square root. But by explicitly specifying a real domain and defining a and x to both be positive (as we're just dealing with reals, so can't have a or x negative), the desired solution can be extracted:
x, a = symbols('x a', positive=True)
solveset(Eq(sqrt(x), sqrt(a) + 1), x, domain=S.Reals).as_relational(x).expand()
# x = 2⋅√a + a + 1

The method that solveset uses gives two roots to consider but checksol is not able to show that the 2nd solution is not generally valid so to be safe, it returns both and shows you the condition which must be checked. If you substitute a value in for a you will obtain a set with the single concrete answer.

Related

How do I set 2 expressions equal to eachother and solve for x [duplicate]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
Let's say I have an equation:
2x + 6 = 12
With algebra we can see that x = 3. How can I make a program in Python that can solve for x? I'm new to programming, and I looked at eval() and exec() but I can't figure out how to make them do what I want. I do not want to use external libraries (e.g. SAGE), I want to do this in just plain Python.
How about SymPy? Their solver looks like what you need. Have a look at their source code if you want to build the library yourself…
There are two ways to approach this problem: numerically and symbolically.
To solve it numerically, you have to first encode it as a "runnable" function - stick a value in, get a value out. For example,
def my_function(x):
return 2*x + 6
It is quite possible to parse a string to automatically create such a function; say you parse 2x + 6 into a list, [6, 2] (where the list index corresponds to the power of x - so 6*x^0 + 2*x^1). Then:
def makePoly(arr):
def fn(x):
return sum(c*x**p for p,c in enumerate(arr))
return fn
my_func = makePoly([6, 2])
my_func(3) # returns 12
You then need another function which repeatedly plugs an x-value into your function, looks at the difference between the result and what it wants to find, and tweaks its x-value to (hopefully) minimize the difference.
def dx(fn, x, delta=0.001):
return (fn(x+delta) - fn(x))/delta
def solve(fn, value, x=0.5, maxtries=1000, maxerr=0.00001):
for tries in xrange(maxtries):
err = fn(x) - value
if abs(err) < maxerr:
return x
slope = dx(fn, x)
x -= err/slope
raise ValueError('no solution found')
There are lots of potential problems here - finding a good starting x-value, assuming that the function actually has a solution (ie there are no real-valued answers to x^2 + 2 = 0), hitting the limits of computational accuracy, etc. But in this case, the error minimization function is suitable and we get a good result:
solve(my_func, 16) # returns (x =) 5.000000000000496
Note that this solution is not absolutely, exactly correct. If you need it to be perfect, or if you want to try solving families of equations analytically, you have to turn to a more complicated beast: a symbolic solver.
A symbolic solver, like Mathematica or Maple, is an expert system with a lot of built-in rules ("knowledge") about algebra, calculus, etc; it "knows" that the derivative of sin is cos, that the derivative of kx^p is kpx^(p-1), and so on. When you give it an equation, it tries to find a path, a set of rule-applications, from where it is (the equation) to where you want to be (the simplest possible form of the equation, which is hopefully the solution).
Your example equation is quite simple; a symbolic solution might look like:
=> LHS([6, 2]) RHS([16])
# rule: pull all coefficients into LHS
LHS, RHS = [lh-rh for lh,rh in izip_longest(LHS, RHS, 0)], [0]
=> LHS([-10,2]) RHS([0])
# rule: solve first-degree poly
if RHS==[0] and len(LHS)==2:
LHS, RHS = [0,1], [-LHS[0]/LHS[1]]
=> LHS([0,1]) RHS([5])
and there is your solution: x = 5.
I hope this gives the flavor of the idea; the details of implementation (finding a good, complete set of rules and deciding when each rule should be applied) can easily consume many man-years of effort.
Python may be good, but it isn't God...
There are a few different ways to solve equations. SymPy has already been mentioned, if you're looking for analytic solutions.
If you're happy to just have a numerical solution, Numpy has a few routines that can help. If you're just interested in solutions to polynomials, numpy.roots will work. Specifically for the case you mentioned:
>>> import numpy
>>> numpy.roots([2,-6])
array([3.0])
For more complicated expressions, have a look at scipy.fsolve.
Either way, you can't escape using a library.
If you only want to solve the extremely limited set of equations mx + c = y for positive integer m, c, y, then this will do:
import re
def solve_linear_equation ( equ ):
"""
Given an input string of the format "3x+2=6", solves for x.
The format must be as shown - no whitespace, no decimal numbers,
no negative numbers.
"""
match = re.match(r"(\d+)x\+(\d+)=(\d+)", equ)
m, c, y = match.groups()
m, c, y = float(m), float(c), float(y) # Convert from strings to numbers
x = (y-c)/m
print ("x = %f" % x)
Some tests:
>>> solve_linear_equation("2x+4=12")
x = 4.000000
>>> solve_linear_equation("123x+456=789")
x = 2.707317
>>>
If you want to recognise and solve arbitrary equations, like sin(x) + e^(i*pi*x) = 1, then you will need to implement some kind of symbolic maths engine, similar to maxima, Mathematica, MATLAB's solve() or Symbolic Toolbox, etc. As a novice, this is beyond your ken.
Use a different tool. Something like Wolfram Alpha, Maple, R, Octave, Matlab or any other algebra software package.
As a beginner you should probably not attempt to solve such a non-trivial problem.

I have a long expression which I want to simplify but assuming that an equation holds

In Mathematica, you can use the function FullSimplify[expression,assumptions] to simplify expressions using assumptions. For instance, if I do this:
FullSimplify[x^2-y^2,x^2-y^2==1],
then the result will be 1 because that's the 'simplest expression that is equivalent to the function I gave the software.
Now I need to do the same with Python, but I don't know how to do that. I have seen the documentation about the command sympy.refine on this page:
https://docs.sympy.org/latest/modules/assumptions/refine.html
However, I haven't been able to use equalities as assumptions. It doesn't seem possible to assume things like that with the Q function.
I have tried to do something like this:
import sympy as sp
x,y=sp.symbols('x y')
sp.refine(x**2-y**2,x==y)
However, this gives me the following error: ValueError: Inconsistent assumptions
Does someone have any ideas about this? Thank you.
Without some scope for what kind of expressions and assumptions you want to work with this is probably an unsolvable problem so I'll make some assumptions.
If you want to simplify a polynomial expression based on some other polynomial expression(s) being zero then you can do this in sympy using ratsimpmodprime:
In [1]: x, y = symbols('x, y')
In [2]: assumptions = [x**2 + y**2 - 1]
In [3]: expression = x**2 + y**2
In [4]: ratsimpmodprime(expression, assumptions)
Out[4]: 1
https://docs.sympy.org/latest/modules/simplify/simplify.html#ratsimpmodprime
I tried two approaches to the problem.
Assume that x - y = 0. This was the only way I could find to express the assumption that you want to make. Unfortunately, it doesn't seem to be smart enough to notice that this assumption allows it to substitute x for y.
print("refine:", sp.refine(x**2-y**2,Q.zero(x-y)))
This just returns the original expression.
Ask sympy to substitute the expression. This isn't as automatic - you're asking it to do the substitution instead of giving it the option of doing the substitution, but it does work for this toy example.
expr = (x**2-y**2)
print("substitution:", expr.subs(x**2-y**2, 1))
prints 1.

Replacing numbers with parameters in sympy

I have some SymPy expressions of the form: 2*x1**2+7*cos(8*x2)+2*Pi (mine are longer and more complicated, but this should be enough for my question). How can I turn all the numbers appearing in this expression into parameters, something like this: a*x1**2+b*cos(c*x2)+d. Basically, I have a program which is able to give me an approximate function able to fit some data, but the parameters are integers or some well known numbers, such as pi or e (this is the first expression I provided). Then, I want to take that expression and fine tune these numbers (using gradient descent), such that to obtain the actual parameters (one can assume that the functional form is right, just the parameters need to be adjusted). For example, in the end, the right equation could be: 2.87*x1**2+6.95*cos(8.05*x2)+6.27. Is there a way to do this? Thank you!
It's a little tricky because you say "all numbers" but you are ignoring exponents. In your example you are only replacing numerical factors in a term with new symbols. To do that (and to get you on your way with a possible solution) try using replace, telling it you are looking for a Mul and then telling it what you want to do with the Mul when you have it:
from sympy import *
from sympy.abc import x,y
eq=2*x**2+7*cos(8*y)+2*pi
def nfact2dum(m):
assert m.is_Mul
nonnum = sift(m.args, lambda i:i.is_number, binary=True)[1]
return Mul(*([Dummy()] + nonnum))
deq = eq.replace(
lambda x:x.is_Mul,
lambda x: nfact2dum(x))
print(
deq.subs(list(zip(deq.atoms(Dummy),numbered_symbols('c')))))
output: c0*x**2 + c2*cos(c1*y) + c3

Sympy: solve for fraction

I have an equation and I need to solve it for a fraction.
I have more complex fomulas to solve but here is a minimal example: take the following simple function Y = X*a.
I want to solve for Y/X, so I expect Y/X =a.
Here is the code, it produces an empty set of answers
from sympy import *
X,Y,a = symbols('X Y a')
testEq = Eq(Y,X*a)
solve(testEq,Y/X)
I guess I'm misunderstanding something, any help appreciated!
The solve function can solve for sub-expressions provided they appear "as is" in the equation being solved. For example, in the following code, solve returns an empty solution for testEq but it returns the correct solution for testEq2 which is the same equation rearranged in terms of Y/X.
from sympy import *
X,Y,a = symbols('X Y a')
testEq = Eq(Y,X*a)
solve(testEq,Y/X)
testEq2 = Eq( Y/X, a )
sol = solve(testEq2,Y/X)
This is not weird or unreasonable at all. If you look at the source code of the solve function it uses code like
>>> testEq.has( Y/X ) # returns False
>>> testEq2.has( Y/X ) # returns True
to check if the symbol ( or sympy object ) that we are solving is present in the equation. If SymPy had to check for all possible ways in which the symbols of an expression can be combined into sub-expressions, the code would become extremely complicated for something which can be easily achieved in other ways ( like solving for Y and dividing by X, in this example ).
Packages for symbolic computations are there to help us handle complicated mathematical equations. But they are not a substitute for human intelligence. More often than not, we need to guide these packages to help them give the answer in a form we want while working around their limitations.
In this issue, a focus routine handles such a request once an auxiliary expression is added to the one of interest:
>>> eq = Eq(y, x*a)
>>> aux = Eq(b, y/x)
>>> focus((aux, eq), b)
{b: a}
Such a routine does not eliminate the need for human intervention, it just assists by allowing the user to state the relationship of interest and add that to the current equation(s) from which the implications are then deduced/solved.

compute x-component of vector in sympy

I'm sure this is a really basic question, but I've googled and haven't found it. Supposed I have a vector in sympy
z = 3*x + 4*y
How do I compute the x-component of the vector (i.e. the 3)? z/x doesn't give it (there's still the y-part), nor does z[x] or z.x. Surely there's a way to do this, right?
Is it as simple as:
>>> from sympy.abc import x, y
>>> z = 3*x + 4*y
>>> z.coeff(x)
3
I think that calling this expression a vector is somewhat incorrect. Indeed, if you keep in your mind the assumption that x and y are some base vectors, it will work in your mind. However the library will not provide any vector-like functionality because it does not know that you want to treat this as vectors.
For vector with all the nice helper methods you can use the diffgeom submodule of sympy which provides predefined R^2 and R^3 spaces with numerous coordinate systems.
However, for your case pattern matching seems a much more natural choice. After all pattern matching is one of the basic building blocks of CASes like Mathematica and others.
In SymPy as in all other CASes you work with symbolic expressions which are basically big trees with operators at each node and some symbols at the leafs. You can match trees against some predefined patterns much in the same way in which you can use regex on strings. In sympy you use Wild to do that:
x, y = Symbols("x y")
a, b = Wild('a', exclude=[x, y]), Wild('b', exclude=[x, y])
(2*x + 3*y).match(a*x + b*y)
For the special case of linear combinations check coeff which is described in the other answer.
See: https://github.com/sympy/sympy/wiki/Idioms-and-Antipatterns#wild-and-match

Categories

Resources