¿Puede Sympy simplificar una expresión racional recopilando varios términos?

Aug 19 2020

Dada una expresión racional Ecomo la que se muestra a continuación, busco usar Sympy para simplificarla a algo parecido a F(definido en el segundo bloque del código de Python a continuación):

import sympy as sp

a, b, c, d, n, t, A, B, C = sp.symbols('a, b, c, d, n, t, A, B, C', real = True)

E = n/(c-b) * ( B - (c-b)/(c-a)*A - (b-a)/(c-a)*B ) * (c-t)/(c-b) + n/(c-b) * ( (d-c)/(d-b)*B + (c-b)/(d-b)*C - B ) * (t-b)/(c-b)

print(sp.pretty( E ))
print(sp.pretty( E.simplify() ))

esto imprime

           ⎛     B⋅(-c + d)   C⋅(-b + c)⎞             ⎛  A⋅(-b + c)   B⋅(-a + b)    ⎞
n⋅(-b + t)⋅⎜-B + ────────── + ──────────⎟   n⋅(c - t)⋅⎜- ────────── - ────────── + B⎟
           ⎝       -b + d       -b + d  ⎠             ⎝    -a + c       -a + c      ⎠
───────────────────────────────────────── + ─────────────────────────────────────────
                        2                                           2                
                (-b + c)                                    (-b + c)
                
                
-n⋅((a - c)⋅(b - t)⋅(-B⋅(b - d) + B⋅(c - d) + C⋅(b - c)) + (b - d)⋅(c - t)⋅(A⋅(b - c) + B⋅(a - b) - B⋅(a - c))) 
────────────────────────────────────────────────────────────────────────────────────────────────────────────────
                                                           2                                                    
                                            (a - c)⋅(b - c) ⋅(b - d) 

Sin embargo, la expresión puede simplificarse aún más, manualmente, cuyo resultado he etiquetado F:

F = n/(c-a) * (B - A) * (c-t)/(c-b) + n/(d-b) * (C - B) * (t-b)/(c-b)

print(sp.pretty( F ))
print((F-E).simplify())

Esto produce

n⋅(-A + B)⋅(c - t)   n⋅(-B + C)⋅(-b + t)
────────────────── + ───────────────────
(-a + c)⋅(-b + c)     (-b + c)⋅(-b + d) 


0

He buscado en varias opciones, incluyendo factor(), collect()y apart(), pero ninguna de ellas parece producir expresiones que tengan la misma estructura que F. ¿Algún consejo sobre cómo proceder?

Además, me preguntaba si la bonita función de impresión de Sympy se puede ajustar de alguna manera para

  1. Mantenga el orden original de las variables tanto en el numerador como en el denominador (por ejemplo, B - Aen lugar de -A + B). Actualmente, el orden está invertido en la mayoría de los casos, lo que se ve bastante feo con los signos menos iniciales.
  2. Muestre fracciones compuestas como productos de fracciones simples (por ejemplo , a/b c/den lugar de ac/bd), aunque en ciertos casos, por supuesto, puede ser ambiguo dónde/cómo "dividir" dichas fracciones compuestas.

Respuestas

2 OscarBenjamin Aug 23 2020 at 21:35

La situación aquí es que tienes una Addde dos términos. Cada término por separado se puede simplificar usando factorpero los factores a cancelar son diferentes para cada uno, por lo que llamando factoral conjunto Addno se encuentra la posible cancelación.

Con eso en mente, debemos tener cuidado de procesar los términos de Addforma independiente, lo que podemos hacer accediendo a .args:

In [122]: E.func(*(factor(term) for term in E.args))
Out[122]: 
n⋅(A - B)⋅(-c + t)   n⋅(B - C)⋅(-b + t)
────────────────── - ──────────────────
 (a - c)⋅(b - c)      (b - c)⋅(b - d) 

El orden de las variables en realidad lo determina la impresora cuando muestra la expresión y no es necesariamente el mismo que el orden interno de los argumentos o necesariamente el orden utilizado cuando creó la expresión. Sin embargo, una llamada a signsimppuede normalizar los signos menos en la expresión

In [123]: signsimp(_)
Out[123]: 
  n⋅(A - B)⋅(c - t)   n⋅(B - C)⋅(b - t)
- ───────────────── + ─────────────────
   (a - c)⋅(b - c)     (b - c)⋅(b - d)