[python] How can I solve equations in Python?

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.

This question is related to python calculator equation

The answer is


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.


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.


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.


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.


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…