How to find out how SymPy solved an equation? - python

When I solve an equation using SymPy, it would be nice to learn what it actually did to find the solutions.
The following is a simple test case for answers. We know it should be using the quadratic equation, or some equivalent approach.
from sympy import *
>>> x = Symbol('x', real=True)
>>> solve(2*x**2 + 12*x + 12)
[-3 - sqrt(3), -3 + sqrt(3)]
Is some way of filtering through a record of the execution stack, or something else to extract what steps were useful to SymPy in solving a problem? I imagine some sort of tree-like search of steps is taken by SymPy, and a record of the stack calls would have to be pruned/simplified somehow.

Related

Solving a System of Inequalities with an Orthogonality Constraint in Python

I need to solve a system of inequalities for n variables where one of the inequalities has an orthogonality constraint. The inequalities are as follows.
In my particular problem, it has been proven that solving the system always results in one exact solution. Because of the orthogonality, I don't think I can use linear programming. Anyone have recommendations for efficient methods to solve in Python? Wolfram alpha is able to do it! (You can see an example here and here) I know sympy can't solve because it only can solve for univariate case. Please include runtime with whatever answer you give!
Edit: Just after posting this, I found z3. And it can somewhat do what I want. But I think it might be overkill and might not be as efficient as possible (hoping for linear in n:= the number of variables to solve for).
from z3 import Solver, Real
def solve_inequalities(z):
n = len(z)
s = Solver()
ys = [Real(f'y{i}') for i in range(n)]
s.add(sum(ys) == 0)
for i in range(1, n):
s.add(sum(ys[:i]) >= 0)
s.add(sum([(z[i]-ys[i])*ys[i] for i in range(n)]) == 0)
for i in range(n-1):
s.add(z[i]-ys[i] <= z[i+1]-ys[i+1])
s.check()
return s.model()

RuntimeError in solving equation using SymPy

I have a equation to solve. The equation can be described as the formula above. N and S are constants, for example N = 201 and S = 0.5. I use sympy in python to solve it. The python script is given as following:
from sympy import *
x=Symbol('x')
print solve( (((1-x)/200) **(1-x))* x**x - 2**(-0.5), x)
However, there is a RuntimeError: maximum recursion depth exceeded in __instancecheck__
I have also tried to use Mathematica, and it can output a result of 0.963
http://www.wolframalpha.com/input/?i=(((1-x)%2F200)+(1-x))*+xx+-+2**(-0.5)+%3D+0
Any suggestion is welcome. Thanks.
Assuming that you don't want a symbolic solution, just a value you can work with (like WA's 0.964), you can use mpmath for this. I'm not sure if it's actually possible to express the solution in radicals - WA certainly didn't even try. You should already have it installed as SymPy
Requires: mpmath
Specifically, mpmath.findroot seems to do what you want. It takes an actual callable Python object which is the function to find a root of, and a starting value for x. It also accepts some more parameters such as the minimum error tol and the solver to use which you could play around with, although they don't really seem necessary. You could quite simply use it like this:
import mpmath
f = lambda x: (((1-x)/200) **(1-x))* x**x - 2**(-0.5)
print mpmath.findroot(f, 1)
I just used 1 as a starting value - you could probably think of a better one. Judging by the shape of your graph, there's only one root to be found and it can be approached quite easily, without much need for fancy solvers, so this should suffice. Also, considering that "mpmath is a Python library for arbitrary-precision floating-point arithmetic", you should be able to get a very high precision answer from this if you wished. It has the output of
(0.963904761592753 + 0.0j)
This is actually an mpmath complex or mpc object,
mpc(real='0.96390476159275343', imag='0.0')
If you know it will have an imaginary value of 0, you can just use either of the following methods:
In [6]: abs(mpmath.mpc(23, 0))
Out[6]: mpf('23.0')
In [7]: mpmath.mpc(23, 0).real
Out[7]: mpf('23.0')
to "extract" a single float in the format of an mpf.

Python symbolic integration

I am using symbolic integration to integrate a combined function of circular function and power function.
from sympy import *
import math
import numpy as np
t = Symbol('t')
integrate(0.000671813*(7/2*(1.22222222+sin(2*math.pi*t-math.pi/2))-6)**0.33516,t)
However, when I finished input, it gives me an odd result:
0.000671813*Integral((3.0*sin(6.28318530717959*t - 1.5707963267949) - 2.33333334)**0.33516, t)
Why does this result contain Integral()? I checked online other functions and there is no Integral() in them.
An unevaluated Integral answer means that SymPy was unable to compute the integral.
Essentially you are trying to integrate a function that looks like
(sin(t) + a)**0.33516
where a is a constant number.
In general such an integration is not possible to express in elementary functions; see, for example, http://www.sosmath.com/calculus/integration/fant/fant.html,
especially the sentence on Chebyshev's theorem.

fsolve problems with the starting point

I'm using fsolve in order to solve a non linear equation. My problem is that, depending on the starting point the solutions change and I am not sure that the ones that I found are the most reasonable.
This is the code
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import fsolve, brentq,newton
A = np.arange(0.05,0.95,0.01)
PHI = np.deg2rad(np.arange(0,90,1))
def f(b):
return np.angle((1+3*a**4-3*a**2)+(a**4-a**6)*(np.exp(2j*b)+2*np.exp(-1j*b))+(a**2-2*a**4+a**6)*(np.exp(-2j*b)+2*np.exp(1j*b)))-Phi
B = np.zeros((len(A),len(PHI)))
for i in range(len(A)):
for j in range(len(PHI)):
a = A[i]
Phi = PHI[j]
b = fsolve(f, 1)
B[i,j]= b
I fixed x0 = 1 because it seems to give the more reasonable values. But sometimes, I think the method doesn't converge and the resulting values are too big.
What can I do to find the best solution?
Many thanks!
The eternal issue with turning non-linear solvers loose is having a really good understanding of your function, your initial guess, the solver itself, and the problem you are trying to address.
I note that there are many (a,Phi) combinations where your function does not have real roots. You should do some math, directed by the actual problem you are trying to solve, and determine where the function should have roots. Not knowing the actual problem, I can't do that for you.
Also, as noted on a (since deleted) answer, this is cyclical on b, so using a bounded solver (such as scipy.optimize.minimize using method='L-BFGS-B' might help to keep things under control. Note that to find roots with a minimizer you use the square of your function. If the found minimum is not close to zero (for you to define based on the problem), the real minima might be a complex conjugate pair.
Good luck.

Python - solve polynomial for y

I'm taking in a function (e.g. y = x**2) and need to solve for x. I know I can painstakingly solve this manually, but I'm trying to find instead a method to use. I've browsed numpy, scipy and sympy, but can't seem to find what I'm looking for. Currently I'm making a lambda out of the function so it'd be nice if i'm able to keep that format for the the method, but not necessary.
Thanks!
If you are looking for numerical solutions (i.e. just interested in the numbers, not the symbolic closed form solutions), then there are a few options for you in the SciPy.optimize module. For something simple, the newton is a pretty good start for simple polynomials, but you can take it from there.
For symbolic solutions (which is to say to get y = x**2 -> x = +/- sqrt(y)) SymPy solver gives you roughly what you need. The whole SymPy package is directed at doing symbolic manipulation.
Here is an example using the Python interpreter to solve the equation that is mentioned in the question. You will need to make sure that SymPy package is installed, then:
>>>> from sympy import * # we are importing everything for ease of use
>>>> x = Symbol("x")
>>>> y = Symbol("y") # create the two variables
>>>> equation = Eq(x ** 2, y) # create the equation
>>>> solve(equation, x)
[y**(1/2), -y**(1/2)]
As you see the basics are fairly workable, even as an interactive algebra system. Not nearly as nice as Mathematica, but then again, it is free and you can incorporate it into your own programs. Make sure to read the Gotchas and Pitfalls section of the SymPy documentation on how to encode the appropriate equations.
If all this was to get a quick and dirty solutions to equations then there is always Wolfram Alpha.
Use Newton-Raphson via scipy.optimize.newton. It finds roots of an equation, i.e., values of x for which f(x) = 0. In the example, you can cast the problem as looking for a root of the function f(x) = x² - y. If you supply a lambda that computes y, you can provide a general solution thus:
def inverse(f, f_prime=None):
def solve(y):
return newton(lambda x: f(x) - y, 1, f_prime, (), 1E-10, 1E6)
return solve
Using this function is quite simple:
>>> sqrt = inverse(lambda x: x**2)
>>> sqrt(2)
1.4142135623730951
>>> import math
>>> math.sqrt(2)
1.4142135623730951
Depending on the input function, you may need to tune the parameters to newton(). The current version uses a starting guess of 1, a tolerance of 10-10 and a maximum iteration count of 106.
For an additional speed-up, you can supply the derivative of the function in question:
>>> sqrt = inverse(lambda x: x**2, lambda x: 2*x)
In fact, without it, the function actually uses the secant method instead of Newton-Raphson, which relies on knowing the derivative.
Check out SymPy, specifically the solver.

Categories