Equation solving in Python - python

I am trying to solve equations such as the following for x:
Here the alpha's and K are given, and N will be upwards of 1,000. Is there a way to specify the LHS given an np.array for the alpha's using sympy? My hope was to define:
eqn = Eq(LHR - K)
solve(eqn,x)
by telling sympy that LHS= sum( a_i + x).
Any tips on solvers which would do this the fastest would also be appreciated. Thanks!
I was hoping for something like:
from sympy import Symbol, symbols, solve, summation, log
import numpy as np
N=10
K=1
alpha=np.random.randn(N, 1)
x = Symbol('x')
i = Symbol('i')
eqn = summation(log(x+alpha[i]), (i, 1, N))
solve(eqn-K,x)

You can't index a NumPy array with a SymPy symbol. Since your sum is finite, just use the Python sum function:
>>> alpha=np.random.randn(1, N)
>>> sum([log(x + i) for i in alpha[0]])
log(x - 1.85289943713841) + log(x - 1.40121781484552) + log(x - 1.21850393539695) + log(x - 0.605693136420962) + log(x - 0.575839713282035) + log(x - 0.105389419698408) + log(x + 0.415055726774043) + log(x + 0.71601559149345) + log(x + 0.866995633213984) + log(x + 1.12521825562504)
But even so, I don't get why you don't just rewrite this as (x - alpha[0])*(x - alpha[1])*...*(x - alpha[N - 1]) - exp(K), as suggested by Warren Weckesser. You can then use a numerical solver like SymPy's nsolve or something from another library to solve this numerically
>>> nsolve(Mul(*[(x - i) for i in alpha[0]]) - exp(K), 1)
mpf('1.2696755961730152')
You could also solve the log expression numerically, but unless your logs can have negative arguments, these should be the same.

Related

Lagrange Multipliers /w sympy

I am currently trying to find the maximum radius of a circle I can manifest between existing circles around it.
i.e. I'm trying to find not only the maximum radius, but the center point most suited for it over a specific given straight line.
In order to find said maxima I'm trying to implement a generalized Lagrange multipliers solution using sympy.
If "n" represents the amount of constraints I have, then I was able to:
Create n symbols generator.
Perform the necessary nth-gradient over the Lagrange function
Manifest the required inequalities (from constraints) to achieve the list of equalities and inequalities needed to be solved.
The code:
from sympy import S
from sympy import *
import sympy as smp
#Lagrange Multipliers
def sympy_distfun(cx,cy,radius):
x,y=smp.symbols('x y',real=True)
return sqrt((x-cx)**2+(y-cy)**2)-radius
def sympy_circlefun(cx,cy,radius):
x,y=smp.symbols('x y',real=True)
return (x-cx)**2+(y-cy)**2-radius**2
def sympy_linefun(slope,b):
x,y=smp.symbols('x y',real=True)
return slope*x+b-y
def lagrange_multiplier(objective,constraints):
x,y=smp.symbols('x y',real=True)
a=list(smp.symbols('a0:%d'%len(constraints),real=True))
cons=[constraints[i]*a[i] for i in range(len(a))]
L=objective+(-1)*sum(cons)
gradL=[smp.diff(L,var) for var in [x,y]+a]
constraints=[(con)>= 0 for con in constraints]
eqs=gradL+constraints
vars=a+[x,y]
solution=smp.solve(eqs[0],vars)
#solution=smp.solveset(eqs,vars)
print(solution)
line=sympy_linefun(0.66666,-4.3333)
dist=sympy_distfun(11,3,4)
circlefunc1=sympy_circlefun(11,3,4)
circlefunc2=sympy_circlefun(0,0,3)
lagrange_multiplier(dist,[line,circlefunc1,circlefunc2])
But, when using smp.solveset(eqs,vars) I encounter the error message:
ValueError: [-0.66666*a0 - a1*(2*x - 22) - 2*a2*x + (x - 11)/sqrt((x - 11)**2 + (y - 3)**2), a0 - a1*(2*y - 6) - 2*a2*y + (y - 3)/sqrt((x - 11)**2 + (y - 3)**2), -0.66666*x + y + 4.3333, -(x - 11)**2 - (y - 3)**2 + 16, -x**2 - y**2 + 9, 0.66666*x - y - 4.3333 >= 0, (x - 11)**2 + (y - 3)**2 - 16 >= 0, x**2 + y**2 - 9 >= 0] is not a valid SymPy expression
When using: solution=smp.solve(eqs[0],vars) to try and solve one equation, it sends sympy into a CPU crushing frenzy and it obviously fails to complete the calculation. I made sure to declare all variables as real so i fail to see why it takes so long to solve.
Would like to understand what I'm missing when it comes to handling multiple inequalities with sympy, and if there is a more optimized faster way to solve Lagrange multiplication I'd love to give it a try

Are there tricks and tweaks for unevaluated integrals in SymPy?

I try to verify some formula from a paper concerning mechanics by retracing their derivation, involving some integrals like these:
The original source suggests that the solution is possible, but it seems quite tricky. I tried my best with SymPy (also with Maxima and Mathematica) fiddling around with different assumptions and simplifications, without any success:
import sympy as sp
from IPython.display import display, Math
x = sp.symbols('x', nonnegative=True, real=True, finite=True)
a = sp.symbols('a', positive=True, real=True, finite=True)
b = sp.symbols('b', positive=True, real=True, finite=True)
# print("assumptions for x:", x.assumptions0)
# print("assumptions for a, b:", r.assumptions0)
expr = x/(b + 2*(a-sp.sqrt(x)*sp.sqrt(2*a-x)))**3
expr = sp.expand(expr)
display(Math("e = "+sp.latex(expr)))
integ = sp.integrate(expr, (x, 0, a))
display(Math("integ = "+sp.latex(integ)))
SymPy returns my integrals unevaluated. Are there any other tricks and tweaks I could try to get a solution? The parameter a and b are physical dimensions (finite positive real numbers).
The answer found using Rubi is
(a^2*(2*a + b)^4*(Sqrt[2*a - Sqrt[-4*a - b]*Sqrt[b]]*Sqrt[2*a + Sqrt[-4*a - b]*Sqrt[b]]*
(Sqrt[b]*(-2*a + b)*Sqrt[-(4*a + b)^2] + 6*a*Sqrt[-4*a - b]*(2*a + b)*ArcTan[(2*a)/(Sqrt[b]*Sqrt[4*a + b])]) -
6*a*(2*a + b)^2*Sqrt[4*a + b]*ArcTanh[Sqrt[2*a - Sqrt[-4*a - b]*Sqrt[b]]/Sqrt[2*a + Sqrt[-4*a - b]*Sqrt[b]]] +
6*a*(2*a + b)^2*Sqrt[4*a + b]*ArcTanh[Sqrt[2*a + Sqrt[-4*a - b]*Sqrt[b]]/Sqrt[2*a - Sqrt[-4*a - b]*Sqrt[b]]]))/
(2*(2*a - Sqrt[-4*a - b]*Sqrt[b])^(5/2)*(2*a + Sqrt[-4*a - b]*Sqrt[b])^(5/2)*Sqrt[-4*a - b]*b^(5/2)*(4*a + b)^(5

Python; Solving equation equal to zero

How I can equate an equation to zero then solve it (the purpose is to eliminate the denominator).
y=(x**2-2)/3*x
In Matlab this works:
solution= solve(y==0,x)
but not in python.
from sympy import *
x, y = symbols('x y')
y=(x**2-2)/3*x
# set the expression, y, equal to 0 and solve
result = solve(Eq(y, 0))
print(result)
Another solution:
from sympy import *
x, y = symbols('x y')
equation = Eq(y, (x**2-2)/3*x)
# Use sympy.subs() method
result = solve(equation.subs(y, 0))
print(result)
Edit (even simpler):
from sympy import *
x, y = symbols('x y')
y=(x**2-2)/3*x
# solve the expression y (by default set equal to 0)
result = solve(y)
print(result)
If you want only to eliminate the denominator, then you can split it into numerator and denominator. If the equation is already appear as a fraction and you want the numerator then
>>> y=(x**2-2)/(3*x); y # note parentheses around denom, is that what you meant?
(x**2 - 2)/(3*x)
>>> numer(_)
x**2 - 2
But if the equation appears as a sum then you can put it over a denominator and perhaps factor to identify numerator factors that must be zero in order to solve the equation:
>>> y + x/(x**2+2)
x/(x**2 + 2) + (x**2 - 2)/(3*x)
>>> n, d = _.as_numer_denom(); (n, d)
(3*x**2 + (x**2 - 2)*(x**2 + 2), 3*x*(x**2 + 2))
>>> factor(n)
(x - 1)*(x + 1)*(x**2 + 4)
>>> solve(_)
[-1, 1, -2*I, 2*I]
You don't have to factor the numerator before attempting to solve, however. But I sometimes find it useful when working with a specific equation.
If you have an example of an equation that is solved quickly elsewhere but not in SymPy, please post it.

SymPy "solves" a differential equation it shouldn't solve

Here's what I did:
from sympy import *
x = symbols("x")
y = Function("y")
dsolve(diff(y(x),x) - y(x)**x)
The answer I get (SymPy 1.0) is:
Eq(y(x), (C1 - x*(x - 1))**(1/(-x + 1)))
But that's wrong. Both Mathematica and Maple can't solve this ODE. What's happening here?
A bug. SymPy thinks it's a Bernoulli equation
y' = P(x) * y + Q(x) * y**n
without checking that the exponent n is constant. So the solution is wrong.
I raised an issue on SymPy tracker. It should be soon fixed in the development version of SymPy and subsequently in version 1.2. (As an aside, 1.0 is a bit old, many things have improved in 1.1.1 although not that one.)
With the correction, SymPy recognizes there is no explicit solution and resorts to power series method, producing a few terms of the power series:
Eq(y(x), x + x**2*log(C1)/2 + x**3*(log(C1)**2 + 2/C1)/6 + x**4*(log(C1)**3 + 9*log(C1)/C1 - 3/C1**2)/24 + x**5*(log(C1)**4 + 2*(log(C1) - 1/C1)*log(C1)/C1 + 2*(2*log(C1) - 1/C1)*log(C1)/C1 + 22*log(C1)**2/C1 - 20*log(C1)/C1**2 + 20/C1**2 + 8/C1**3)/120 + C1 + O(x**6))
You don't have to wait for the patch to get this power series, it can be obtained by giving SymPy a "hint":
dsolve(diff(y(x), x) - y(x)**x, hint='1st_power_series')
Works better with an initial condition:
dsolve(diff(y(x), x) - y(x)**x, ics={y(0): 1}, hint='1st_power_series')
returns
Eq(y(x), 1 + x + x**3/3 - x**4/8 + 7*x**5/30 + O(x**6))

Numerical and analytical equation solving in python or matlab

Let's suppose that I have two transcendental functions f(x, y) = 0 and g(a, b) = 0.
a and b depend on y, so if I could solve the first equation analytically for y, y = f(x), I could have the second function depending only on x and thus solving it numerically.
I prefer to use python, but if matlab is able to handle this is ok for me.
Is there a way to solve analytically trascendent functions for a variable with python/matlab? Taylor is fine too, as long as I can choose the order of approximation.
I tried running this through Sympy like so:
import sympy
j, k, m, x, y = sympy.symbols("j k m x y")
eq = sympy.Eq(k * sympy.tan(y) + j * sympy.tan(sympy.asin(sympy.sin(y) / x)), m)
eq.simplify()
which turned your equation into
Eq(m, j*sin(y)/(x*sqrt(1 - sin(y)**2/x**2)) + k*tan(y))
which, after a bit more poking, gives us
k * tan(y) + j * sin(y) / sqrt(x**2 - sin(y)**2) == m
We can find an expression for x(y) like
sympy.solve(eq, x)
which returns
[-sqrt(j**2*sin(y)**2/(k*tan(y) - m)**2 + sin(y)**2),
sqrt(j**2*sin(y)**2/(k*tan(y) - m)**2 + sin(y)**2)]
but an analytic solution for y(x) fails.

Categories