Se lo si fa nell'ordine corretto, la sostituzione verrà eseguita in modo iterativo (a meno che non si usi subs(replacement, simultaneous=True)
, che esegue tutte le sostituzioni contemporaneamente).
Il tuo problema è quindi ordinare correttamente le sostituzioni. Quello che vuoi è un topological sort delle sostituzioni. Vale a dire, ogni sostituzione è un nodo in un grafico e c'è un margine da (old1, new1)
a (old2, new2)
se new1
contiene old2
(vale a dire, deve essere sostituito per primo).
SymPy ha un'implementazione di topological_sort
in sympy.utilities.iterables
. Prende una lista di vertici e una lista di bordi (tuple di vertici). Diciamo che avete
replace = [(y, z + 1), (x, y + z), (z, a)]
Siamo in grado di creare una lista di bordi con
from itertools import combinations
edges = [(i, j) for i, j in permutations(replace, 2) if i[1].has(j[0])]
Ordinamento questo dà
>>> from sympy import default_sort_key, topological_sort
>>> topological_sort([replace, edges], default_sort_key)
[(x, y + z), (y, z + 1), (z, a)]
Il terzo argomento di topological_sort
è una chiave utilizzata per rompere i legami. Poiché gli oggetti SymPy non hanno un ordine implicito definito su di essi (<
e >
alza TypeError
in generale), esiste un'implementazione di chiave di ordinamento denominata default_sort_key
che fornisce un ordinamento canonico e coerente (ma arbitrario) di oggetti SymPy.
In una situazione come quella mostrata dal 404 in cui ci sarebbe stato un ciclo infinito, topological_sort
vi avviserà che c'è un ciclo
>>> replace = [(x, y+1), (y, x+1)]
>>> edges = [(i, j) for i, j in permutations(replace, 2) if i[1].has(j[0])]
>>> topological_sort([replace, edges], default_sort_key)
Traceback (most recent call last):
File "<ipython-input-51-72f3bfcfd4ad>", line 1, in <module>
topological_sort([replace, edges], default_sort_key)
File "/Users/aaronmeurer/Documents/Python/sympy/sympy/sympy/utilities/iterables.py", line 882, in topological_sort
raise ValueError("cycle detected")
ValueError: cycle detected
Onestamente, questo dovrebbe essere appena implementato direttamente in subs
tramite un argomento della parola chiave. Vedi https://github.com/sympy/sympy/issues/6257.
Tecnicamente, è una soluzione iterativa, ma è la stessa idea. – Reti43
Questo si bloccherà piuttosto che ritorna incompleto se 'replace' ha loop infiniti, ma è facile da cambiare. – drhagen
@drhagen Buon punto, ho reso il ciclo finito. –