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
Related
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 am trying to make an algebra solver, so I have to find the coefficients of x in an expression. Currently this is the code I have to take an input:
equation = input("Enter equation: ")
LHS, RHS = equation.split("=")[0], equation.split("=")[1]
##Remove whitespaces
LHS, RHS = LHS.replace(" ",""), RHS.replace(" ","")
Now I want to get the coefficients of x in the expressions LHS and RHS, how can I do this?
And also, the coefficients may not be just numbers but they may be of the form (2*3+4)x. I think this can be done using the eval() function but I don't know how to apply it.
Note: I want to do this with plain python, without using any modules which are not built-in.
In case it's only one variable and thus only one coefficient you could divide the respective variable/site by x.
Taking your example:
(2*3+4)x
dividing by x gives us the coefficient:
(2*3.4)
If that's not the approach you want to take, you could also convert the expression into a string and exclude "x", as such:
coefficientLHS = LHS.replace("x", "")
However, you should use this cautious as you might have algebra expressions in front of your variable, so regex implementation would be advisable.
Another approach would be to use the module Poly:
x = symbols("x")
coefLHS = Poly(LHS, x)
coefLHS.coeffs()
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.
I have series with two symbols and I need to find sum with two-point accuracy. I checked results for some parts using sympy, and I know the answer, but I have no idea how to prove it. I don't even know how to prove convergence using sympy
import sympy as sp
i, j = sp.symbols('i, j', integer = True)
S = sp.Sum(sp.Sum(1/(i * j)*sp.sin(sp.pi*i/2)*
sp.sin(sp.pi*(2*j-1)/2)/sp.sinh(sp.pi*i), (i, 1,sp.oo )),(j,1,sp.oo))
S.is_convergent()
returns
NotImplementedError: convergence checking for more that one symbol
containing series is not handled
In principle, you can evaluate a Sympy Sum by calling either the method .doit(), which returns a closed-form expression (if Sympy is able to find one), or by calling the method .n(), which returns a numerical approximation of the sum (floating point number). In this case, both options do not work (I would expect at least the .n() to give an answer).
As a workaround, you could try to perform a simplification of the sum and then attempt to evaluate it. In particular,
S.factor()
returns
which transforms the double-index sum into the product of two single-index sums. Calling
S.factor().doit()
returns
which implies that the second sum cannot be evaluated in closed-form. However, .n() works now.
S.factor().n()
0.0599820444370520
Assume we have a function with unknown formula, given few inputs and results of this function, how can we get the function's formula.
For example we have inputs x and y and result r in format (x,y,r)
[ (2,4,8) , (3,6,18) ]
And the desired function can be
f(x,y) = x * y
As you post the question, the problem is too generic. If you want to find any formula mapping the given inputs to the given result, there are simply too many possible formulas. In order to make sense of this, you need to somehow restrict the set of functions to consider. For example you could say that you're only interested in polynomial solutions, i.e. where
r = sum a_ij * x^i * y^j for i from 0 to n and j from 0 to n - i
then you have a system of equations, with the a_ij as parameters to solve for. The higher the degree n the more such parameters you'd have to find, so the more input-output combinations you'd need to know. Variations of this use rational functions (so you divide by another polynomial), or allow some trigonometric functions, or something like that.
If your setup were particularly easy, you'd have just linear equations, i.e. r = a*x + b*y + c. As you can see, even that has three parameters a,b,c so you can't uniquely find all three of them just given the two inputs you provided in your question. And even then the result would not be the r = x*y you were aiming for, since that's technically of degree 2.
If you want to point out that r = x*y is a particularly simple formula, and you would like to look for simple formulas, then one approach would be enumerating formulas in order of increasing complexity. But if you do this without parameters (since ugly parameters will make a simple formula like a*x + b*y + c appear complex), then it's hard to guilde this enumeration towards the one you want, so you'd really have to enumerate all possible formulas, which will become infeasible very quickly.