Toutes mes excuses pour le titre (peut-être trompeur) et la question probablement déroutante elle-même, j'ai beaucoup de mal à formuler mon problème et surtout à le compresser en une seule phrase pour le titre. Je veux trouver les racines d'une fonction f (w, t, some_other_args)
avec deux variables, w
et t
, en utilisant python. La vraie structure des fonctions est vraiment longue et compliquée, vous pouvez la trouver à la fin de ce post. L'important est qu'il contienne la ligne suivante:
import math as m from scipy import optimize import numpy as np def func(t, w, r_1, r_2, r_3): k = 1.5 * m.sqrt((1.0 - w) / (1.0 - 0.25 * w)) k23 = 2 * k / 3 z1 = 1 / (1 + k23) z2 = 1 / (1 - k23) z3 = 3 * ((1 / 5 + r_1 - r_2 - 1 / 5 * r_1 * r_2) / (z1 - r_2 * z2)) * m.exp(t * (k - 1)) z4 = -(z2 - r_2 * z1) / (z1 - r_2 * z2) * m.exp(2 * k * t) z5 = -(z1 - r_2 * z2) / (z2 - r_2 * z1) z6 = 3 * (1 - r_2 / 5) / (z2 - r_2 * z1) beta_t = r_3 / (z2 / z1 * m.exp(2 * k * t) + z5) * (z6 - 3 / (5 * z1) * m.exp(t * (k - 1))) alpha_t = beta_t * z5 - r_3 * z6 beta_r = (z3 - r_1 / 5 / z2 * m.exp(-2 * t) * 3 - 3 / z2) / (z1 / z2 + z4) alpha_r = -z1 / z2 * beta_r - 3 / z2 - 3 / 5 * r_1 / z2 * m.exp(-2 * t) It_1 = 1 / 4 * w / (1 - 8 / 5 * w) * (alpha_t * z2 * m.exp(-k * t) + beta_t * z1 * m.exp(k * t) + 3 * r_3 * m.exp(-t)) Ir_1 = (1 / 4 * w / (1 - 8 / 5 * w)) * (z1 * alpha_r + z2 * beta_r + 3 / 5 + 3 * r_1 * m.exp(-2 * t)) T = It_1 + m.exp(-t) * r_3 R = Ir_1 + m.exp(-2 * t) * r_1 return [T, R] def calc_1(t, w, T, R, r_1, r_2, r_3): t_begin = float(t[0]) T_new, R_new = func(t_begin, w, r_1, r_2, r_3) a = abs(-1 + T_new/T) b = abs(-1 + R_new/R) return np.array([a, b]) def calc_2(x, T, R, r_1, r_2, r_3): t = x[0] w = x[1] T_new, R_new = func(t, w, r_1, r_2, r_3) a = abs(T - T_new) b = abs(R - R_new) return np.array([a, b]) def approximate_w(R): k = (1 - R) / (R + 2 / 3) w_approx = (1 - ((2 / 3 * k) ** 2)) / (1 - ((1 / 3 * k) ** 2)) return w_approx def approximate_t(w, T, R, r_1, r_2, r_3): t = optimize.root(calc_1, x0=np.array([10, 0]), args=(w, T, R, r_1, r_2, r_3)) return t.x[0] def solve(T, R, r_1, r_2, r_3): w_x = approximate_w(R) t_x = approximate_t(w_x, T, R, r_1, r_2, r_3) sol = optimize.fsolve(calc_2, x0=np.array([t_x, w_x]), args=(T, R, r_1, r_2, r_3)) return sol # Values for testing: T = 0.09986490557943692 R = 0.8918728343037964 r_1 = 0 r_2 = 0 r_3 = 1 print(solve(T, R, r_1, r_2, r_3))
Cela signifie que w
ne peut pas dépasser 1, car cela conduirait à calculer la racine carrée d'un nombre négatif, ce qui, bien sûr, est impossible. J'ai des algorithmes pour calculer les valeurs approximatives de w
et t
en utilisant d'autres valeurs dans ma fonction, mais elles sont très inexactes.
Donc, j'essaye pour calculer les racines avec scipy.optimize.fsolve
(après avoir essayé littéralement tous les algorithmes de recherche de racines que j'ai pu trouver en ligne, j'ai trouvé que celui-ci était le meilleur pour ma fonction) en utilisant ces valeurs approximatives comme points de départ, qui ressemblerait à ceci:
w_approx: 0.9960090844989311 t_approx: 24.26777844720981 Values: t:24.26777844720981, w:0.9960090844989311 Values: t:24.26777844720981, w:0.9960090844989311 Values: t:24.26777844720981, w:0.9960090844989311 Values: t:24.267778808827888, w:0.9960090844989311 Values: t:24.26777844720981, w:0.996009099340623 Values: t:16.319554685876746, w:1.0096680915775516 solution = optimize.fsolve(f, x0=np.array([t_approx, w_approx]), args=(some_other_args)) File "C:\Users\...\venv\lib\site-packages\scipy\optimize\minpack.py", line 148, in fsolve res = _root_hybr(func, x0, args, jac=fprime, **options) File "C:\Users\...\venv\lib\site-packages\scipy\optimize\minpack.py", line 227, in _root_hybr ml, mu, epsfcn, factor, diag) File "C:\Users\...\algorithm.py", line 9, in f k = 1.5 * m.sqrt((1.0 - w) / (1.0 - 0.25 * w)) ValueError: math domain error
Pour la plupart des valeurs, cela fonctionne parfaitement. Si w
est trop proche de 1, cependant, il arrive toujours un moment où fsolve
essaie une valeur supérieure à 1 pour w
, qui, dans turn, lève une ValueError
(car calculer la racine d'un nombre négatif est mathématiquement impossible). Voici un exemple d'impression des valeurs que fsolve
utilise, où w
devrait être quelque part autour de 0.997:
solution = optimize.fsolve(f, x0=np.array([t_approx, w_approx]), args=(some_other_args))
Alors, comment puis-je dire à Optimize.fsolve
que w
ne peut pas être plus grand que 1? Ou quels sont les algorithmes alternatifs pour faire quelque chose comme ça (je connais brentq
et ainsi de suite, mais tous nécessitent de donner un intervalle pour les deux racines, ce que je ne sais pas que vous voulez faire.)?
Code de test (Ce qui est important à noter ici: même si func
est théoriquement censé calculer R
et T
étant donné t
et w
, je dois l'utiliser dans l'autre sens. C'est un peu maladroit, mais je n'y parviens tout simplement pas réécrire la fonction pour qu'elle accepte T, R
pour calculer t, w
- c'est un peu trop pour mon expertise mathématique médiocre;)):
k = 1.5 * m.sqrt((1.0 - w) / (1.0 - 0.25 * w))
3 Réponses :
Qu'en est-il de logistique l'argument que vous voulez contraindre? Je veux dire, à l'intérieur de f
, vous pourriez faire
solution = optimize.fsolve(f, x0=np.array([t_approx, w_approx]), args=(some_other_args)) free_w = solution[0] w = 1/(1 + np.exp(-free_w))
Et puis, il vous suffirait d'appliquer la même transformation logistique à la valeur de la solution de free_w
pour obtenir w
*. Voir
import numpy as np def f(free_w, ...): w = 1/(1 + np.exp(-free_w)) # w will always lie between 0 and 1 ... return zeros
Une question @Flob?
Ne perdriez-vous pas la précision si w
est proche de 0 ou 1, c'est-à-dire que free_w
s'approche de ± ∞?
@meowgoesthedog Cela tout dépend de la tolérance que vous avez définie pour vos zéros
. Mais en pratique, et avec des valeurs tol
très restrictives, j'ai toujours mes contraintes respectées bien avant de perdre de la précision.
comme ça free_w = 1 / (1 + np.exp (-w))
à la fin de mon algorithme?
meow va le chien a raison, mais il n'est pas nécessaire d'appliquer la fonction réciproque @Flob.
C'est une idée vraiment intéressante, merci. Mais utiliser cela me donne des erreurs mathématiques à certains autres points de mon calcul ( ZeroDivisionError
par exemple) et t
se rapproche de -39000, où il devrait plutôt être autour de 24 ...
@Flob vous n'avez pas montré ce qu'est t
et comment il se rapporte à w
. Collez la fonction dans votre message ou ajoutez un lien vers celui-ci.
@meowgoesthedog regarde mon autre question < / a> concernant exactement le même problème (qui n'a pas obtenu de réponse à l'époque ...)
@Flob. J'aimerais reproduire vos résultats mais je ne peux pas. Quel est votre some_other_args
? 1,0,1
?
dans mon autre question, que j'ai liée dans le commentaire ci-dessus, j'ai donné quelques valeurs pour tester
Tu l'as fait. Mais ces valeurs n'ont aucun sens. Votre système ne peut pas être résolu si certains de ses degrés de liberté sont annulés comme vous le faites.
J'ai essayé de simplifier le tout pour cette question, parce que la façon dont j'ai posé la dernière fois, je n'ai pas pu obtenir de réponse. La chose que je devrais faire est de réécrire ma fonction pour être capable de calculer w
et t
en dépendance de R
et T < / code>, mais en regardant la fonction, vous comprendrez peut-être que c'est tout simplement impossible.
@Flob Nous n'avons pas le temps de regarder votre homme de fonction. Je veux juste copier le tout et reproduire vos résultats. Je ne te comprends pas. Voulez-vous obtenir de l'aide ou quoi?
@Flob Le dernier conseil que je peux vous donner (dans votre cas précis) est de ne pas exprimer vos contraintes en termes de niveau. Au lieu de cela, exprimez-les en termes relatifs. En utilisant votre autre question, je veux dire, renvoie [-1 + z [0] / T, -1 + z [1] / R]
. Acclamations
hm, je viens de réaliser que ma vieille question contient des erreurs. Bien. Merci pour votre aide, je suppose que je n'aurai pas d'autre choix que d'ajouter le code à cette question même si je voulais éviter cela
@Kanak Ajout du code complet pour copier et coller et reproduire mon erreur ci-dessus, si vous êtes toujours intéressé
Vous devriez essayer de définir explicitement votre fonction avant de l'optimiser, de cette façon vous pourrez vérifier plus facilement le domaine.
Essentiellement, vous avez une fonction de T et R. cela a fonctionné pour moi:
def func_to_solve(TR_vector, r_1, r_2, r_3): T, R = TR_vector # what you are trying to find w_x = approximate_w(R) t_x = approximate_t(w_x, T, R, r_1, r_2, r_3) return (calc_2([t_x, w_x], T, R, r_1, r_2, r_3)) def solve(TR, r_1, r_2, r_3): sol = optimize.fsolve(func_to_solve, x0=TR, args=(r_1, r_2, r_3)) return sol
Remplacez également m.exp
par np.exp
Merci d'avoir pris le temps de lire tout cela. J'ai oublié d'expliquer ceci: même si func
est théoriquement censé calculer T, R
étant donné t
et w
, je dois l'utiliser dans l'autre sens. C'est un peu maladroit, mais je n'arrive tout simplement pas à réécrire la fonction pour qu'elle accepte T, R
pour calculer t, w
- c'est un peu trop pour mon expertise mathématique médiocre;))
La manière la plus "mathématiquement correcte" serait de mettre cette fonction implicitement et de laisser le programme le faire fonctionner .. bien sûr, cela coûte numériquement. J'ai compris que vous utilisiez une approximation pour éviter cela. Dans tous les cas, si vous utilisez votre fonction pseudo-explicite, c'est une bonne pratique de la définir avant de l'optimiser: de cette façon, vous pouvez A) le tracer et vérifier les problèmes de domaine, B) le résoudre en utilisant différents algorithmes d'optimisation. Vous pouvez toujours utiliser quelque chose comme scipy.optimize.minimize
qui vous permet d'utiliser des limites
Votre erreur signalée se produit car fsolve
ne peut pas gérer les restrictions implicites lors de la conversion de w
en k
. Cela peut être résolu radicalement en inversant cette dépendance, rendant func
dépendant de t
et k
à la place.
t= 14.860121342410327, k= 0.026653140486605, w= 0.999763184675043
Supprimez ensuite les valeurs absolues des valeurs de fonction dans calc1
et calc2
. Cela ne rend vos solutions que comme des points non différentiables, ce qui est mauvais pour tout algorithme de recherche de racine. Les changements de signe et les racines lisses sont bons pour les méthodes de type Newton.
def approximate_k(R): k = (1 - R) / (R + 2 / 3) return k def solve(T, R, r_1, r_2, r_3): k_x = approximate_k(R) t_x = 10 sol = optimize.fsolve(calc_2, x0=np.array([t_x, k_x]), args=(T, R, r_1, r_2, r_3)) return sol t,k = solve(T, R, r_1, r_2, r_3) print "t=%20.15f, k=%20.15f, w=%20.15f"%(t, k, k2w(k))
Cela n'a pas beaucoup de sens de trouver la valeur de t
en résolvant l'équation garder w
resp. k
corrigé, cela ne fait que doubler l'effort de calcul.
def calc_2(x, T, R, r_1, r_2, r_3): t = x[0] k = x[1] T_new, R_new = func(t, k, r_1, r_2, r_3) a = T - T_new b = R - R_new return np.array([a, b])
Avec ces modifications, la solution
def w2k(w): return 3 * m.sqrt((1.0 - w) / (4.0 - w)) #k = 1.5 * m.sqrt((1.0 - w) / (1.0 - 0.25 * w)) # (k/3)**2 * (4-w)= 1-w def k2w(k): return 4 - 3/(1-(k/3)**2) def func(t, k, r_1, r_2, r_3): w = k2w(k) print "t=%20.15f, k=%20.15f, w=%20.15f"%(t,k,w) ...
se trouve dans 15 évaluations de fonctions.
Merci d'avoir pris le temps d'y réfléchir! Ça a l'air prometteur, je vais l'essayer rn. Une question: dans résoudre
, est-il intentionnel de donner w_x
au lieu de k_x
dans le tableau x0
? si oui, d'où vient w_x
dans ce cas?
Non, bien sûr que non, il n'y a pas de telle variable définie à ce stade. J'ai manqué cela lors du remplacement des noms de variables. Merci.
J'aime vraiment cette solution et elle a fonctionné avec quelques petites modifications! Merci!
Avez-vous une limite inférieure finie (n basée sur l'interprétation ) pour
w
?Je sais que
w
se situe toujours entre 0 et 1.En fonction de votre fonction réelle, vous pouvez essayer d'utiliser
scipy.optimize.minimize
, qui permet de passer des contraintes, peut-être mêmeless_squares
.J'ai essayé les deux il y a quelque temps, il y avait d'autres problèmes avec eux, mais je ne me souviens pas exactement - je vais l'examiner à nouveau.
l'utilisation de
Optimize.minimize
génère l'erreur suivante:File "C: \ Users \ ... \ Optimize \ Optimize.py", ligne 663, dans _approx_fprime_helper grad [k] = (f ( * ((xk + d,) + args)) - f0) / d [k] ValueError: définition d'un élément de tableau avec une séquence.