-
Notifications
You must be signed in to change notification settings - Fork 194
Correct asin/acos for infinite arguments #795
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
996a33f
to
c2e3acf
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! Thanks, @skirpichev!
Hmm, I forgot to add explicit test with zero for the mp context... Also note using But we have in Mathematica:
Ditto Diofant/SymPy:
So, it's a compatibility break: In this case, I think, it's worth to do. I don't see good reasons why real component was zeroed c.f. case of finite big argument: Mathematica just discards finite components of a complex number with presence of infinity, so it looks consistent for this CAS, but not for diofant/sympy. @oscarbenjamin ? |
Well, we have a disgrepancy for diofant/sympy evaluation rules and mpmath already in v1.3.0:
Probably this affects a lot of functions (but in many cases it might be a mpmath fault, see e.g. #776). I believe, this example is a bug on CAS's side. Following invariant should be preserved: |
According to https://en.cppreference.com/w/cpp/numeric/complex/asin special cases,
for any positive finite While the special cases do not specify the case where Notice that the sign difference on the branch cut that has been discussed in #786 which also demonstrates the systematic inconsistency between FP and symbolic software. Sympy |
I think, these are taken into account correctly.
In fact, they do, same rule "If z is x+∞i (for any positive finite x), the result is +∞+π/2" + conjugation for asinh // https://en.cppreference.com/w/c/numeric/complex/casinh You are correct, for zero you just have to account it's sign.
It's not an inconsistency. FP arithmetic with signed zero just can't represent the value directly on the branch cut. I'm trying to document that. CCC rule does work for elementary functions, but it's tricky to specify on which side we choose to be continuous in general case...
I would guess it's a blindly copy from Mathematica, where e.g.
Here above trick does make sense; Mathematica has only concept of DirectedInfinity/ComplexInfinity, but in the Diofant/SymPy:
|
Draft PR for the Diofant to fix evaluation rules: diofant/diofant#1396 I think, that the SymPy should implement something like that. Current evaluation rules could be broken also by rewrite rules, for example:
|
I have contemplated whether this should be changed so that there is only directed infinity and complex infinity. I'm not sure that |
Yes, maybe that should be changed that way. Pros: this will match current limit output. For example, in the mentioned Diofant's pr:
This could be fixed, however. Or documented as a feature of the limit algorithm:)
Why not? It's just as meaningful as "oo*I" == "positive infinity on the imaginary line". This one - on the shifted line. Of course, there is possible another meaning: "directed infinity with argument pi/2". But above interpretation seems to be useful and widespread notation, e.g. for integrals:
Sort of. Clearly, you lose something e.g. in the following example (current SymPy):
And if the mp context will adopt that convention - there will be yet another difference wrt the fp context. |
Within the rectangular form of complex numbers that |
I think that's an implementation detail. E.g. we could trivially change back and forth to the polar form in finite case.
Infinite complex numbers per the c11 have 8 variants as directed infinities, e.g. |
Absolutely. The OT remark was for the complex infinity as the top point of Riemann sphere that Mathematica
I think that is a topic for libraries that use mpmath, such as sympy, but for mpmath which is about multiple-precision arithmetic, it would be off-topic, IMHO. |
It is widespread notation to use |
As well as
I see. Lets then put #793 on hold, I'll factor out other commits to a separate pr. I would appreciate if you could discuss this issue in the SymPy community. (Maybe you could mention also #786: the current decision clearly will not make sense if the mp context got signed zeros, see #167) I doubt you convinced me so far. The notion of complex numbers with infinite components seems to be well defined, used in textbooks and in numerical libraries. Etc, see #795 (comment) I think that CAS's could support this notion together with directed infinity, which is already possible in the Diofant/SymPy:
Regarding limits issue, you will have to fix something in the SymPy anyway, because:
What about integrals over
I.e. "lets just use that for pretty-printing". Ok. |
BTW, Mathematica's convention doesn't look consistent (i.e. there is more than just DirectedInfinity and zoo): addition/subtraction of DirectedInfinity'es left intact:
|
I think that we might be misunderstanding each other when talking about directed infinities. To me a directed infinity is Maybe Mathematica's DirectedInfinity is something different and maybe also this (my) notion of directed infinity does not really work in mpmath... |
No, it's exactly that one. And how you can see, Mathematica uses more infinity types. Not sure why BTW: >>> gmpy2.asin(cmath.inf)
mpc('1.5707963267948966+infj')
>>> flint.acb(cmath.inf).asin() # I hope flint.ctx has no option like gmpy2's allow_complex?
nan + nanj |
In fact, it seems that the algorithm is correct in the imaginary part (if the imaginary component of argument is not a nan). So, here is a simplified patch, that fix the real part at the end. |
It is just not clear what model of "infinity" is being used when we have something like In my notion of directed infinity With SymPy: In [1]: oo + (-oo)
Out[1]: nan
In [2]: I*oo + oo
Out[2]: ∞ + ∞⋅ⅈ
In [3]: re(I*oo + oo)
Out[3]: ∞
In [4]: arg(I*oo + oo)
Out[4]:
π
─
4 I don't like the |
The
Indeed. In somewhat a funny way...
I would prefer to keep last two cases unevaluated too. On contrary,
That's consistent with https://en.cppreference.com/w/c/numeric/complex/carg:
(Diofant/SymPy says it's 0...) See also Kahan's "“Branch cuts for complex elementary functions" paper. This looks as a special case for a directed infinity (in this case expansion/collection is legal, as well as for other similar 3 cases):
|
But we also have: In [1]: expand((2+I)*oo)
Out[1]: ∞ + ∞⋅ⅈ
In [2]: arg(_)
Out[2]:
π
─
4 This is inconsistent with my idea of directed infinity for which the argument is the defining feature i.e.
Yes, and the limit of the composite function ( Evaluation with infinities should only work if all interpretations of the evaluation as a limit are equivalent which is why |
I didn't say such expansions are correct in all cases. This example is a bug. Seems to be an instance of sympy/sympy#4596, which is really solvable.
I doubt we have many options here. Either we could consider C as a metric space ( In the first case, we have only But in the second, we have all kind of
|
No it doesn't have anything to do with automatic distribution: In [1]: e = (2+I)*oo
In [2]: e
Out[2]: ∞⋅(2 + ⅈ)
In [3]: arg(e)
Out[3]: atan(1/2)
In [4]: e.expand()
Out[4]: ∞ + ∞⋅ⅈ
In [5]: arg(e.expand())
Out[5]:
π
─
4 If In [7]: limit(arg(x+I*x**2), x, oo)
Out[7]:
π
─
2
In [8]: limit(arg(x**2+I*x), x, oo)
Out[8]: 0 |
Oh, I see, that's fixed in the SymPy. I would definitely want to backport that for the Diofant.
IIUC, "mul" helper for expand just blindly do multiplication term-by-term. Again, this is a bug: in this case, SymPy shouldn't do it (there is kwarg
Hmm, why not?
|
No, it is not fixed. It just doesn't apply in this particular case because neither factor is a Rational.
The limits are all well defined but not the same. The problem is that if we don't have a limit but rather an expression with infinities like As I said above:
|
Sure, I meant that. I realize, that sympy/sympy#4596 is not fixed. (Though, it's interesting how many test failures are if distribution will be disabled for non-integer Rational's.)
Just as with oo.
No. All such limits are equal to Unfortunately, I was wrong in another point: such limits can't represent values like
So, returning to our special case, both
have sense. But which one we will use to define Both kinds of infinities are useful: I think useful definition of |
Ok, I'm going to merge this tomorrow: #793 (comment) In short, it seems there is no compatibility break: we just extend the present (e.g. in v1.3) convention to other arguments with infinite components, besides |
closes #793