web-dev-qa-db-fra.com

Comment résoudre des équations en Python?

Disons que j'ai une équation:

2x + 6 = 12

Avec l'algèbre, nous pouvons voir que x = 3. Comment puis-je faire un programme en Python qui peut résoudre pour x? Je suis nouveau dans la programmation, et j'ai regardé eval() et exec() mais je ne sais pas comment les faire faire ce que je veux. Je ne veux pas utiliser de bibliothèques externes (par exemple SAGE), je veux le faire en Python.

21
user1221937

Que diriez-vous SymPy ? Leur solveur ressemble à ce dont vous avez besoin. Jetez un œil à leur code source si vous voulez construire vous-même la bibliothèque…

28
eumiro

Il existe deux façons d'aborder ce problème: numériquement et symboliquement.

Pour le résoudre numériquement, vous devez d'abord le coder comme une fonction "exécutable" - coller une valeur, extraire une valeur. Par exemple,

def my_function(x):
    return 2*x + 6

Il est tout à fait possible d'analyser une chaîne pour créer automatiquement une telle fonction; dites que vous analysez 2x + 6 dans une liste, [6, 2] (où l'index de la liste correspond à la puissance de x - donc 6 * x ^ 0 + 2 * x ^ 1). Ensuite:

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

Vous avez ensuite besoin d'une autre fonction qui branche à plusieurs reprises une valeur x à votre fonction, examine la différence entre le résultat et ce qu'il veut trouver et ajuste sa valeur x pour (espérons-le) minimiser la différence.

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')

Il y a beaucoup de problèmes potentiels ici - trouver une bonne valeur x de départ, en supposant que la fonction a réellement une solution (c'est-à-dire qu'il n'y a pas de réponses réelles à x ^ 2 + 2 = 0), atteignant les limites de la précision de calcul, etc. Mais dans ce cas, la fonction de minimisation des erreurs convient et nous obtenons un bon résultat:

solve(my_func, 16)    # returns (x =) 5.000000000000496

Notez que cette solution n'est pas absolument, exactement correcte. Si vous en avez besoin pour être parfait, ou si vous voulez essayer de résoudre des familles d'équations analytiquement, vous devez vous tourner vers une bête plus compliquée: un solveur symbolique.

Un solveur symbolique, comme Mathematica ou Maple, est un système expert avec beaucoup de règles intégrées ("connaissances") sur l'algèbre, le calcul, etc. il "sait" que la dérivée du péché est cos, que la dérivée de kx ^ p est kpx ^ (p-1), et ainsi de suite. Lorsque vous lui donnez une équation, il essaie de trouver un chemin, un ensemble d'applications de règles, d'où il est (l'équation) à l'endroit où vous voulez être (la forme la plus simple possible de l'équation, qui est, espérons-le, la solution) .

Votre exemple d'équation est assez simple; une solution symbolique pourrait ressembler à:

=> 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])

et voici votre solution: x = 5.

J'espère que cela donne la saveur de l'idée; les détails de la mise en œuvre (trouver un bon ensemble complet de règles et décider quand chaque règle doit être appliquée) peuvent facilement consommer de nombreuses années-homme d'efforts.

17
Hugh Bothwell

Python peut être bon, mais ce n'est pas Dieu ...

Il existe plusieurs façons de résoudre des équations. SymPy a déjà été mentionné, si vous recherchez des solutions analytiques.

Si vous êtes content d'avoir une solution numérique, Numpy a quelques routines qui peuvent vous aider. Si vous êtes simplement intéressé par des solutions aux polynômes, numpy.roots fonctionnera. Plus précisément pour le cas que vous avez mentionné:

>>> import numpy
>>> numpy.roots([2,-6])
array([3.0])

Pour des expressions plus compliquées, jetez un œil à scipy.fsolve.

De toute façon, vous ne pouvez pas échapper à l'aide d'une bibliothèque.

9
Pascal Bugnion

Si vous voulez seulement résoudre le extrêmement limité ensemble d'équations mx + c = y Pour un entier positif m, c, y, Alors cela fera:

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)

Quelques tests:

>>> solve_linear_equation("2x+4=12")
x = 4.000000
>>> solve_linear_equation("123x+456=789")
x = 2.707317
>>> 

Si vous voulez reconnaître et résoudre arbitraires équations, comme sin(x) + e^(i*pi*x) = 1, alors vous devrez implémenter une sorte de moteur mathématique symbolique, similaire à maxima, Mathematica, solve() de MATLAB ou Symbolic Toolbox, etc. En tant que novice, cela dépasse votre ken.

6
Li-aung Yip

Utilisez un outil différent. Quelque chose comme Wolfram Alpha , Maple , R , Octave , - Matlab ou tout autre progiciel d'algèbre.

En tant que débutant, vous ne devriez probablement pas tenter de résoudre un problème aussi simple.

4
user3850