Question

Je dois souvent résoudre des problèmes non linéaires dans lesquels le nombre de variables dépasse le nombre de contraintes (ou parfois l'inverse). Généralement, certaines des contraintes ou variables sont redondantes d'une manière compliquée. Est-il possible de résoudre ces problèmes?

La plupart des solveurs SciPy semblent supposer que le nombre de contraintes est égal au nombre de variables, et que le jacobien est inversible. leastsq fonctionne parfois, mais il ne cherche même pas lorsque les contraintes sont moins que le nombre de variables. Je me rends compte que je pouvais courir fmin sur linalg.norm(F), mais cela est beaucoup moins efficace que toute méthode qui utilise la jacobienne.

Voici un exemple d'un problème qui montre ce dont je parle. Il a évidemment une solution, mais leastsq donne une erreur. Bien sûr, cet exemple est facile à résoudre à la main, je l'ai mis ici pour montrer la question.

import numpy as np
import scipy.optimize

mat = np.random.randn(5, 7)

def F(x):
    y = np.dot(mat, x)
    return np.array([ y[0]**2 + y[1]**3 + 12, y[2] + 17 ])

x0 = np.random.randn(7)
scipy.optimize.leastsq(F, x0)

Le message d'erreur que je reçois est:

Traceback (most recent call last):
  File "question.py", line 13, in <module>
    scipy.optimize.leastsq(F, x0)
  File "/home/dstahlke/apps/scipy/lib64/python2.7/site-packages/scipy/optimize/minpack.py", line 278, in leastsq
    raise TypeError('Improper input: N=%s must not exceed M=%s' % (n,m))
TypeError: Improper input: N=7 must not exceed M=2

J'ai parcouru le net pour une réponse et ont même demandé sur la liste de diffusion SciPy, et n'a obtenu aucune réponse. Pour l'instant je piraté la source SciPy de telle sorte que les utilisations du solveur de newton_krylov pinv(), mais je ne pense pas que ce soit une solution optimale.

Était-ce utile?

La solution

Que diriez-vous redimensionner le tableau de retour de F () au nombre de variables:

import numpy as np
import scipy.optimize

mat = np.random.randn(5, 7)

def F(x):
    y = np.dot(mat, x)
    return np.resize(np.array([ y[0]**2 + y[1]**3 + 12, y[2] + 17]), 7)

while True:    
    x0 = np.random.randn(7)
    r = scipy.optimize.leastsq(F, x0)
    err = F(r[0])
    norm =  np.dot(err, err)
    if norm < 1e-6:
        break

print err
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top