Ask Your Question

Revision history [back]

click to hide/show revision 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.