Dear developers, Some time ago I sent a patch to prevent .series() to revert to .expand() internally. This was because in the case that one has polynomial^some_large_integer the expansion will be hopeless. However, I keep running into this kind of problems. To determine the real_ldegree in mul::pseries, still expansion is used with potentially the same problems. I think there are two possible solutions to this problem. (1) Tell your users (me included) that they should not be substituting polynomials into each others when they should have used power series from the start. (2) Create (or ask me to create) a patch that solves this particular case and hope that there will not be ten other instances where .series() is going to crash a program. (3) Forbid any occurance of .expand() in any method or function that may be called from .series(). Create a new method to determine the leading behaviour of any expression. Let .series() use this and let .series() work by calculating power series of subexpressions and combining these into the power series for the entire expression. I am in favour of (3). The only reason not to use (3) would be if someone in this mailing list could come up with an example where (3) clearly is horribly inefficient. What do other people think? Best, Chris Dams
Hi Chris! On Tue, 18 May 2004, Chris Dams wrote:
Some time ago I sent a patch to prevent .series() to revert to .expand() internally. This was because in the case that one has polynomial^some_large_integer the expansion will be hopeless. However, I keep running into this kind of problems. To determine the real_ldegree in mul::pseries, still expansion is used with potentially the same problems.
I think there are two possible solutions to this problem. (1) Tell your users (me included) that they should not be substituting polynomials into each others when they should have used power series from the start. (2) Create (or ask me to create) a patch that solves this particular case and hope that there will not be ten other instances where .series() is going to crash a program. (3) Forbid any occurance of .expand() in any method or function that may be called from .series(). Create a new method to determine the leading behaviour of any expression. Let .series() use this and let .series() work by calculating power series of subexpressions and combining these into the power series for the entire expression.
I am in favour of (3). The only reason not to use (3) would be if someone in this mailing list could come up with an example where (3) clearly is horribly inefficient.
What do other people think?
The third suggestion sounds quite attractive. If I am not mistaken it does, however, lead to some circular reasoning. The question is: how would you go ahead implementing a reliable ldegree routine? Consider a deeply nested expression -- maybe a nested unexpanded polynomial is enough. What's the reliable ldegree? You would recursively descent into the expression tree, inspect candidate expressions, collect their coefficients and finally you would have to test this coefficient for zero, right? If it is zero, then start over again with the next degree. Let's leave the problem of testing for zero aside. That would have to be dodged like we do in other places (pivoting, e.g.). However, come to think about it, that procedure sounds a lot like the process of series expansion itself! *If* we had a series expansion routine which could extract term after term, then we could use it for implementing this reliable ldegree function, I assume. But since our series expansion wants us to agree on an order before we can call it, this does not work. A order guess could lead to way too much computation or it could lead to too few terms. Ugh. In the end, I suspect one would have to fundamentally rewrite the whole series expansion such that it can be used like a stream. Are you with me? Or maybe I'm confused? Regards -richy. -- Richard B. Kreckel <http://www.ginac.de/~kreckel/>
Hi Richy, On Wed, 16 Jun 2004, Richard B. Kreckel wrote:
On Tue, 18 May 2004, Chris Dams wrote:
Some time ago I sent a patch to prevent .series() to revert to .expand() internally. This was because in the case that one has polynomial^some_large_integer the expansion will be hopeless. However, I keep running into this kind of problems. To determine the real_ldegree in mul::pseries, still expansion is used with potentially the same problems.
I think there are two possible solutions to this problem. (1) Tell your users (me included) that they should not be substituting polynomials into each others when they should have used power series from the start. (2) Create (or ask me to create) a patch that solves this particular case and hope that there will not be ten other instances where .series() is going to crash a program. (3) Forbid any occurance of .expand() in any method or function that may be called from .series(). Create a new method to determine the leading behaviour of any expression. Let .series() use this and let .series() work by calculating power series of subexpressions and combining these into the power series for the entire expression.
I am in favour of (3). The only reason not to use (3) would be if someone in this mailing list could come up with an example where (3) clearly is horribly inefficient.
What do other people think?
The third suggestion sounds quite attractive. If I am not mistaken it does, however, lead to some circular reasoning. The question is: how would you go ahead implementing a reliable ldegree routine? Consider a deeply nested expression -- maybe a nested unexpanded polynomial is enough. What's the reliable ldegree? You would recursively descent into the expression tree, inspect candidate expressions, collect their coefficients and finally you would have to test this coefficient for zero, right? If it is zero, then start over again with the next degree. Let's leave the problem of testing for zero aside. That would have to be dodged like we do in other places (pivoting, e.g.).
However, come to think about it, that procedure sounds a lot like the process of series expansion itself!
It sounds like series expansion as it is currently implemented. The difference is that I only want to tell every type of expression how to series expand itself if its subexpressions are series. The multiple (!) differentiation and expansion that occurs in basic::series invites expression explosion. The "deeply nested expression" that you were talking about is likely going to result in this, by the chain rule, especially if a few of the levels in the deep nesting are additions with a not too small amount of terms. Apart from that, I do not think drastic changes are necesary. When I am calculating something by hand on the blackboard, where keeping expressions size in check is even more crital, I will (almost?) always series expand by series expanding subexpressions. It is true that determining the leading term potentially needs series expansion itsself. However, the current ldegree appear to be primarily designed for use with polynomials. I think it would be good if it were supplemented by something that knows how to handle more general expressions.
In the end, I suspect one would have to fundamentally rewrite the whole series expansion such that it can be used like a stream.
This sounds like an iteresting idea. Moreover, it sounds like an efficient idea. The orderloops as they currently appear in GiNaC do not look efficient. They look like potentially duplicating, triplicating, quadruplicating or whatever the work. Another idea that might be feasible this way is allowing more general exponents, say x^1/2+x^3/2+... Best, Chris
Chris, Find below some immature thoughts about what IMHO needs to be addressed in order to construct a more veratile series expansion. On Wed, 16 Jun 2004, Chris Dams wrote: [...]
It is true that determining the leading term potentially needs series expansion itsself. However, the current ldegree appear to be primarily designed for use with polynomials.
I suspect that unless those polynomials are expanded, even the current ldegree could fall into the trap of a vanishing leading coefficient?
I think it would be good if it were supplemented by something that knows how to handle more general expressions.
In the end, I suspect one would have to fundamentally rewrite the whole series expansion such that it can be used like a stream.
This sounds like an iteresting idea. Moreover, it sounds like an efficient idea.
Yes, efficient in time. I'm not so sure about efficiency in space, however. The reason is that currently we go ahead differentiating and later insert the expansion point. When that insertion happens, the series coefficients usually collapse considerably. When we extract term by term from the stream of coefficients, that insertion might not be desireable. If f(x) and g(x) have both been exanded at x==a up to O(x^2), then we have the coefficients f(a), f'(a), f''(a), g(a), g'(a) and g''(a). The streams should hold f''(x) and g''(x) for subsequent computation of higher coefficients. This is not so bad yet, but if we want to compute (f*g)(x) up to order x^2 we can readily assemble the following terms: (f*g)(x)|x==a == f(a)*g(a) + (f'(a)*g(a) + f(a)*g'(a)) * x + (f''(a)*g(a) + 2f'(a)*g'(a) + f(a)*g''(a))/2! * x^2 In addition we would like to also store (f*g)''(x) in order to subsequently extract higher coefficients. However, that is not possible, since it contains f(x), g(x), f'(x) and g'(x) which are not available any more. Remember, we have already .subs(x==a)! Only f(a), g(a), f'(a) and g'(a) are available. So, we would have to store the unsubstituted coefficients as well, which leads to some degree of bloat. But if the series stream objects where the terms are extracted from have controlled lifetime it might not hurt at all?
The orderloops as they currently appear in GiNaC do not look efficient. They look like potentially duplicating, triplicating, quadruplicating or whatever the work.
Another idea that might be feasible this way is allowing more general exponents, say x^1/2+x^3/2+...
Puiseux series are interesting, but they might also be feasible without term-by-term extraction? They aggravate one open question which must be addressed anyways for term-by-term extraction. If one coefficient vanishes, what is supposed to happen? Clearly, we shouldn't skip to the next coefficient because this leads to an infinite loop if the series turns out to be terminating. So, zero should be returned. In the case of Puiseux series, this would require us to be able to foresay what the next term ought to be, is it x^1 or x^3/2 or x^5/4? If we know the common denominator of all exponents of x in the series (4 in the example above) before starting the actual computation, then there is no problem. Regards -richy. PS: BTW, are you aware of Joris van der Hoeven's work on this topic, e.g. <http://www.math.u-psud.fr/~vdhoeven/Publs/2002/relax4.ps.gz>? -- Richard B. Kreckel <http://www.ginac.de/~kreckel/>
participants (2)
-
Chris Dams
-
Richard B. Kreckel