![]() | 1 | initial version |
;; This buffer is for text that is not saved, and for Lisp evaluation. ;; To create a file, visit it with ‘C-x C-f’ and enter text in its buffer.
The complexity can be reduced only by suitable specialization(s) as early as possible.
Here are some words about the way i would try to speed up computations in situations that are (very) similar to the given sample. Let t0, t1, t2
be the three components of the given list Txp
. (In general there may be more, and the program should be written using the suitable iterators.)
Let us inspect their denominators, the only source of problems. I am working in a purely algebraic context:
sage: R.<q1,q2,q3,q4,M,tB1,tB2> = PolynomialRing(QQ)
sage: F = FractionField(R)
Then let Txp
be as in the posted question.
We look into the components.
sage: t0, t1, t2 = Txp
sage: t0.denominator().factor()
(q2 - 1) * (q1 - 1) * q4^2 * (-q1*q2*tB1 + tB2) * (q1*q2*tB2 - M) * (q1*q2*tB2 - tB1) * (q1*q2*tB1 - M)
sage: t1.denominator().factor()
(-1) * (-q1 + q2) * (q2 - 1) * q4^2 * (-q2^2*M + q1*tB2) * (-q2^2*M + q1*tB1) * (-q2^2*tB1 + q1*tB2) * (q2^2*tB2 - q1*tB1)
sage: t2.denominator().factor()
(-1) * (-q1 + q2) * (q1 - 1) * q4^2 * (-q1^2*M + q2*tB2) * (-q1^2*M + q2*tB1) * (-q1^2*tB1 + q2*tB2) * (q1^2*tB2 - q2*tB1)
sage:
So in this toy example we identify the "common part" $(q_1-1)(q_2-1)(q_2-q1)$ as being problematic. (We can already set $q_3=1$ inside $t_0,t_1,t_2$.) However, using only a specialization of $q_1=1$ first, the problematic part is in fact only $(q_1-1)$. For instance, if $f_0,f_1,f_2,\dots $ are fractions (in the fraction field) with no poles in $q=1$, then knowing that $$\frac 1{q-1}f_0+\frac 1{q-1}f_1+\frac 1{q-1}f_2+\dots$$ has no poles in $q=1$ lets us replace the above expression by $$\frac 1{q-1}(f_0-f_0(1))+\frac 1{q-1}(f_1-f_1(1))+\frac 1{q-1}(f_2-f_2(1))+\dots$$ without changing the limit in $q=1$. (Here $f_j(1)$ is the evaluation of $f_j$ in $q=1$.)
So in our case, we would immediately replace t0, t1, t2
by their evaluation in q3 = 1
, and probably in the use case there is also some preferred order of susbtitution.
sage: t0, t1, t2 = t0(q3=1), t1(q3=1), t2(q3=1)
Then we replace t0
by $(f_0-f_0(1))/(q_1-1)$, where the fraction $f_0$ is the simplified version of $t_0(q-1)$. The same applies also for the other components. We must know for this that $q_1=1$ is a simple pole.
f0 = t0.numerator().factor() / (t0.denominator().factor() / (q1 - 1))
f1 = t1.numerator().factor() / (t1.denominator().factor() / (q1 - 1))
f2 = t2.numerator().factor() / (t2.denominator().factor() / (q1 - 1))
t0 = (f0 - f0(q1=1)).factor()/(q1 - 1)
t1 = (f1 - f1(q1=1)).factor()/(q1 - 1)
t2 = (f2 - f2(q1=1)).factor()/(q1 - 1)
It turns out that here are some factors $(q_2-q_1)$ and $(q_2-1)$ in the expressions t0, t1, t2
involved.
Since we know that the sum expression is well defined, there must be a factor $(q_2-q_1)$ in its numerator to compensate
this factor from the denominator.
So we eliminate in a pedestrian manner this factor in a similar fashion.
I have some problems to write the same code for the new t0
, which is a factorization object and has no numerator and denominator
methods. Note that there is an iterator over the factors, and one can easily remove the one factor q2 - q1
from the list of factors in a new object. To keep code in a small shape i will coerce to an F
-object.
t0 = F(t0.expand())
t1 = F(t1.expand())
t2 = F(t2.expand())
f0 = t0.numerator().factor() / (t0.denominator().factor() / (q1 - q2))
f1 = t1.numerator().factor() / (t1.denominator().factor() / (q1 - q2))
f2 = t2.numerator().factor() / (t2.denominator().factor() / (q1 - q2))
t0 = (f0 - f0(q1=q2)).factor()/(q1 - q2)
t1 = (f1 - f1(q1=q2)).factor()/(q1 - q2)
t2 = (f2 - f2(q1=q2)).factor()/(q1 - q2)
We can now plug in $q_1=1$.
t0, t1, t2 = t0(q1=1), t1(q1=1), t2(q1=1)
And after that the same step is done once more for the substitution $q_2=1$.
t0 = F(t0.expand())
t1 = F(t1.expand())
t2 = F(t2.expand())
f0 = t0.numerator().factor() / (t0.denominator().factor() / (q2 - 1))
f1 = t1.numerator().factor() / (t1.denominator().factor() / (q2 - 1))
f2 = t2.numerator().factor() / (t2.denominator().factor() / (q2 - 1))
t0 = (f0 - f0(q2=1)).factor()/(q2 - 1)
t1 = (f1 - f1(q2=1)).factor()/(q2 - 1)
t2 = (f2 - f2(q2=1)).factor()/(q2 - 1)
We can now plug in $q_2=1$.
t0, t1, t2 = t0(q2=1), t1(q2=1), t2(q2=1)
This gives an other value, which still contains $q_4$.
A similar procedure has to be applied to tp
.