Hi,

I hit a bit of a set-back today with my integration code. Specifically, I am getting wrong results, because of improper treatment of branch cuts.

As a first example consider

sin(sqrt(z)) - sin(sqrt(w)),

where we want to substitute z=exp(I*pi)=-1 and w=exp(-I*pi)=-1. If we do this naively, the answer comes out as zero, but what we (at least I, in my integration code) mean is 2*sin(I).

I have for now been alleviating this problem (since I started the integration code) by explicitely tracking the branch we are on by (essentially) substituting early z=|z|*exp(I*arg(z)/pi*my_pi), where my_pi is a dummy that is not recognised by any of the simplifications code. When doing this, the above expression gets changed to

sin(exp(I*my_pi/2)) - sin(exp(-I*my_pi/2))

and in the end we can safely substitute pi for my_pi and get a correctly computed branch.


However, this does not work for all functions. Generically, this will fail when we replace sin(sqrt(z)) above by a non-elementary function (i.e. one that is not recognised by the simplification machinery) branched at the origin. A particular example I have hit is uppergamma(0, z). As you may know, the function uppergamma(s, z) (for fixed s) is an entire function when s is a positive integer, satisfies uppergamma(s, z) = z**s * F(s, z) for an entire function F if s is not an integer, and satisfies uppergamma(s, exp(2*pi*I*n)*z) = uppergamma(s, z) + 2*pi*n/factorial(-s) for non-positive integral s.

My question thus is how to put this information into code. Notice that all functions in question come from meijer g-functions, but I don't think there is a chance of understanding the monodromy action in this generality (but I would love to be wrong!). Assuming this is true, the best I could come up with would be to add ._eval_rewrite_as_{un,}branched functions to special functions, perhaps even with a default implementation raising NotImplementedError. This would be somewhat akin to the ._eval_rewrite_as{in,}tractable used for gruntz' algorithm.

[Since the answer is likely messy, any code should obviously try to avoid calling these functions at any cost, but that is something I can take care of locally.]

In more detail, somewhere in functions/elementary/complexes.py I would add principal_branch(z) which represents z with its argument converted to range (-pi, pi], and argument_period(z) which then satisfies z = principal_branch(z)*exp(I*2*pi*argument_period(z)). Then e.g. uppergamma._rewrite_as_unbranched could return an expression involving these functions. The integration code would use a sequence of operations as follows to compute the branch of the result:

# TODO try to avoid this when possible
res = res.rewrite('unbranched')
res = res.subs(my_pi, pi)
res = res.rewrite('branched')

My real questions are then as follows, I guess:

1. Does anyone see a better way around the issue?
2. Any suggestions for a better interface?

Thanks,
Tom

--
You received this message because you are subscribed to the Google Groups 
"sympy" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/sympy?hl=en.

Reply via email to