#11506 closed defect (fixed)
Fix the infinity ring.
Reported by: | vbraun | Owned by: | AlexGhitza |
---|---|---|---|
Priority: | blocker | Milestone: | sage-6.3 |
Component: | algebra | Keywords: | |
Cc: | burcin | Merged in: | |
Authors: | Volker Braun | Reviewers: | Peter Bruin |
Report Upstream: | N/A | Work issues: | |
Branch: | 00eb409 (Commits, GitHub, GitLab) | Commit: | |
Dependencies: | #13125 | Stopgaps: |
Description (last modified by )
Comparisons in the infinity ring are broken, mostly because it does not correctly coerce infinities from other rings into it. It also needs to be updated for the new coercion framework.
Also, sage/rings/infinity.py
has no author or copyright notice.
Comparisons with SR or complex fields are still sometimes weird as
- SR doesn't coerce to the infinity ring, since we want symbolic comparisons with infinity
- Complex numbers have phases, but the infinity ring only supports +/-
- CC/CDF have a weird model for their own infinity representation:
These shall be dealt with elsewhere as they can't be fixed on the side of the infinity ring.
Change History (58)
comment:1 Changed 11 years ago by
comment:3 Changed 10 years ago by
Some progress as of 5.7.beta3
:
sage: InfinityRing(RR(oo)) +Infinity sage: InfinityRing(CC(oo)) +Infinity sage: oo == RR(oo) True sage: float('inf') * unsigned_infinity Infinity sage: oo == CC(oo) # This is okay because we want an unsigned infinity False
But still more to go:
sage: CC(oo) == unsigned_infinity # This is not False sage: CC(oo) * CC(oo) # Worse case, I think it should be "+infinty - 0*I" (consistent with python), best would be "+infinity" +infinity - NaN*I sage: InfinityRing(SR(oo)) TypeError:
And some even more fun:
sage: oo*i - unsigned_infinity Infinity sage: oo*i + unsigned_infinity Infinity sage: oo*i (I)*Infinity sage: oo*i + oo --------------------------------------------------------------------------- RuntimeError Traceback (most recent call last) <ipython-input-17-05765816106c> in <module>() ----> 1 oo*i + oo ... RuntimeError: indeterminate expression: infinity - infinity encountered.
comment:4 Changed 9 years ago by
Milestone: | sage-5.11 → sage-5.12 |
---|
comment:5 Changed 9 years ago by
comment:6 Changed 9 years ago by
see also my comment about limit
in #14857: shouldn't limit
return an element of InfinityRing? for Infinity, +Infinity, -Infinity
?
Paul
comment:7 Changed 9 years ago by
Priority: | major → critical |
---|
The following is an extremely serious error:
sage: Infinity in RR True
This is mathematical nonsense.
Less polemically phrased, it has the potential to be dangerously confusing. It reflects the implementation choice that multiprecision reals are also able to represent infinity.
Besides, it contradicts the documentation of the infinity "ring", the parent of Infinity
, which states that the infinity "ring" does not have a coercion map to any actual rings.
Infinity in CC
does correctly return False
.
See also https://groups.google.com/forum/#!topic/sage-devel/sHyLWNcItl4 .
comment:8 Changed 9 years ago by
Besides, it contradicts the documentation of the infinity "ring", the parent of Infinity, which states that the infinity "ring" does not have a coercion map to any actual rings.
Let me argue for the same thing as you, but more precisely and technically based on the internal design decisions in Sage.
First note that there is no implicit coercion map from InfinityRing
to RR, where coercion is as defined http://www.sagemath.org/doc/tutorial/tour_coercion.html.
sage: RR.has_coerce_map_from(InfinityRing) False sage: InfinityRing.has_coerce_map_from(RR) True
However, there is a *conversion* map:
sage: f = RR.convert_map_from(InfinityRing); f Conversion map: From: The Infinity Ring To: Real Field with 53 bits of precision sage: f(oo) +infinity sage: oo.parent() The Infinity Ring
Conversion (not coercion) paired with equality testing (see below) is what is used for "in" testing systematically throughout Sage. For example, the following uses conversion:
sage: 2/1 in ZZ True
The above would be false if it used only automatic coercion, since there is no automatic coercion from the rationals (parent of 2/1) to ZZ. "In" works by applying the conversion map, then testing *equality* between the original object and the converted object, e.g., :
sage: ZZ(2/1) == 2/1 True
However, this equality test does use implicit coercion.
In the case of "+infinity":
sage: RR(oo) # fine +infinity sage: RR(oo) == oo # that this is true is what is really wrong.... True
That RR(oo) == oo
evaluates to True is the real bug, since == is supposed to mean *equal* under an implicit coercion map, e.g.:
sage: 2/1 == 2 # coerce both to QQ True sage: 2 == Mod(2,7) # coerce both to Z/7Z True sage: 2/1 == Mod(2,7) # FALSE! As it should be -- no *implicit* coercion to a common parent, so they can't be equal False
With CC things work right: CC(oo) != oo
:
sage: CC(oo) +infinity sage: f = CC.convert_map_from(InfinityRing); f Conversion map: From: The Infinity Ring To: Complex Field with 53 bits of precision sage: f(oo) +infinity sage: f(oo) == oo False sage: CC(oo) == oo # good False
This is mathematical nonsense.
For the record, I'm a little uncomfortable with this way of arguing, since we're talking about numerical analysis and numerical computation here, in actual software, which is something that numerical analysts, IEEE committees, etc., have thought about these issues for a while. They have very good reasons to represent various infinities as special cases, and have well defined rules about their behavior.
Nonetheless, I have to agree with your conclusion. I think the fix is to make it so RR(oo) == oo
returns False. When that is sorted out, then oo in RR
should return False as well, as explained above. One can *explicitly* construct a = RR(oo)
if needed, and for this infinity, a in RR
will be true.
comment:9 Changed 9 years ago by
Here is a more systematic list with things that work correctly and things that don't (compiled from earlier comments, with various additions). We should probably have several tickets instead of trying to solve all problems at once.
Most basic operations in the signed and unsigned infinity rings work as expected:
sage: infinity.parent() The Infinity Ring sage: unsigned_infinity.parent() The Unsigned Infinity Ring sage: oo is infinity True sage: oo is Infinity True sage: infinity == unsigned_infinity True sage: -infinity == unsigned infinity True sage: infinity == -infinity False sage: oo * oo +Infinity sage: oo * unsigned_infinity Infinity
The coercion maps also work as expected:
sage: UnsignedInfinityRing.has_coerce_map_from(InfinityRing) True sage: InfinityRing.has_coerce_map_from(UnsignedInfinityRing) False sage: UnsignedInfinityRing.has_coerce_map_from(RR) True sage: UnsignedInfinityRing.has_coerce_map_from(CC) True sage: InfinityRing.has_coerce_map_from(RR) True sage: InfinityRing.has_coerce_map_from(CC) False sage: RR.has_coerce_map_from(UnsignedInfinityRing) False sage: CC.has_coerce_map_from(UnsignedInfinityRing) False sage: RR.has_coerce_map_from(InfinityRing) False sage: CC.has_coerce_map_from(InfinityRing) False
The following is debatable, since it makes the arbitrary choice that unsigned infinity is "more positive than negative":
sage: InfinityRing(unsigned_infinity) +Infinity # this should probably raise an error
The following wrongly suggests that UnsignedInfinityRing
is ordered:
sage: UnsignedInfinityRing(0) A number less than infinity # should be "A finite number"
A seemingly arbitrary typographical inconsistency (upper-case I vs. lower-case i):
sage: oo +Infinity sage: RR(oo) +infinity
Conversion to InfinityRing
and UnsignedInfinityRing
:
sage: InfinityRing(RR(oo)) +Infinity # OK sage: InfinityRing(CC(oo)) +Infinity # should raise an error (complex infinity is unsigned) UnsignedInfinityRing(CC(oo)) A number less than infinity # should be Infinity UnsignedInfinityRing(CC(oo)) A number less than infinity # should be Infinity
Arithmetic in RR
:
sage: RR(5) * RR(oo) +infinity # OK sage: RR(oo) * unsigned_infinity ... ValueError: oo times number < oo not defined # should be Infinity
CC
currently contains many infinity elements, whereas it should contain at most one (the point at infinity in the Riemann sphere):
sage: RR(oo) * CC(oo) +infinity - NaN*I # should be "complex infinity" sage: CC(5) * CC(oo) +infinity - NaN*I # should be "complex infinity"
Conversion from InfinityRing
and UnsignedInfinityRing
:
sage: RR(oo) +infinity # OK sage: RR(unsigned_infinity) +infinity # should raise an error sage: CC(oo) +infinity # should be "complex infinity" sage: CC(unsigned_infinity) +infinity # should be "complex infinity sage: f = RR.convert_map_from(InfinityRing); f Conversion map: From: The Infinity Ring To: Real Field with 53 bits of precision sage: f(oo) +infinity # OK sage: f(InfinityRing(0)) ... TypeError: Unable to convert x (='Zero') to real number. # should be 0.000000000000000 sage: f(InfinityRing(1)) TypeError: Unable to convert x (='Apositivefinitenumber') to real number. # OK sage: f(InfinityRing(-1)) TypeError: Unable to convert x (='Anegativefinitenumber') to real number. # OK sage: f = CC.convert_map_from(InfinityRing); f Conversion map: From: The Infinity Ring To: Complex Field with 53 bits of precision sage: f(oo) +infinity # should be "complex infinity" sage: f(InfinityRing(0)) TypeError: unable to coerce to a ComplexNumber: <class 'sage.rings.infinity.FiniteNumber'> # should be 0.000000000000000 sage: f(InfinityRing(1)) TypeError: unable to coerce to a ComplexNumber: <class 'sage.rings.infinity.FiniteNumber'> # OK sage: f(InfinityRing(-1)) TypeError: unable to coerce to a ComplexNumber: <class 'sage.rings.infinity.FiniteNumber'> # OK
Comparison:
sage: RR(oo) == oo True # might be OK; William Stein (comment:8) disagrees sage: RR(oo) == unsigned_infinity False # True might be acceptable sage: CC(oo) == oo False # OK sage: CC(oo) == unsigned_infinity False # True might be acceptable sage: CC(oo) == RR(oo) True # OK
Membership testing:
sage: Infinity in RR True # should be False sage: Infinity in CC False # OK sage: unsigned_infinity in RR False # OK sage: unsigned_infinity in CC False # OK
Problems with the symbolic ring:
sage: InfinityRing(SR(oo)) ... TypeError: # should be +Infinity sage: oo*i (I)*Infinity # should probably be Infinity sage: oo*i + oo ... RuntimeError: indeterminate expression: infinity - infinity encountered. # OK sage: bool(SR(oo) > 5) False # should be True sage: oo*i - unsigned_infinity Infinity # OK sage: oo*i + unsigned_infinity Infinity # OK
comment:10 Changed 9 years ago by
Milestone: | sage-6.1 → sage-6.2 |
---|
comment:11 Changed 9 years ago by
Milestone: | sage-6.2 → sage-6.3 |
---|
comment:12 Changed 9 years ago by
Branch: | → u/vbraun/infinity_ring |
---|
comment:13 Changed 9 years ago by
Authors: | → Volker Braun |
---|---|
Commit: | → f96c67ec2103455ab72783f4c4eb4484e588fdd5 |
Dependencies: | → 13125 |
New commits:
308d16b | Implement RealSet - finite unions of open/closed/semi-closed subsets of the real line.
|
a861752 | Further improvements to RealSet
|
15ef91c | Trac #13125: reviewer's patch: fix typos, add module to set refman
|
d7e2c53 | Merge branch 'develop' into ticket/13125
|
142aa88 | add tests for comparison of infinity with other ring elements
|
e4303ea | fix element constructor of the infinity ring
|
fa497ee | handle conversion of RIF into InfinityRing
|
563a877 | also handle conversion of symbolic infinity
|
cef5700 | Merge branch 'develop' into t/13125/ticket/13125
|
f96c67e | strip out grant acknowledgement
|
comment:14 Changed 9 years ago by
Reviewers: | → Peter Bruin |
---|
IMHO things like i*oo
make sense, we should just support arbitrary phases instead of only +/-
. I did implement that in pynac so it works in the symbolic ring. But extending the infinity ring is a different ticket. In the absence of an infinity ring with phases, comparisons with complex numbers will always be somewhat wonky. But then that is not too bad since they can't really be compared.
I disagree with the "Infinity in RR
should be false" discussion above. In Sage, RR
can represent plus/minus infinity because RDF
can represent infinity by IEEE. The fact that RR(oo) == oo
is the whole point of the infinity ring, namely to have consistent comparisons across various rings that can represent infinity.
comment:15 Changed 9 years ago by
Commit: | f96c67ec2103455ab72783f4c4eb4484e588fdd5 → cd9242959af9fda6d5351f8410889b36d6b6a392 |
---|
Branch pushed to git repo; I updated commit sha1. New commits:
cd92429 | also add conversion (not: coercion) for CC -> infinity ring
|
comment:16 Changed 9 years ago by
Description: | modified (diff) |
---|
Also, the following two are equally incorrect:
sage: infinity == unsigned_infinity True sage: 2+7 == Mod(2,7) True
Both violate Python rules for equality and hashes. But as long as we want the latter we also have to accept the former.
comment:17 Changed 9 years ago by
Status: | new → needs_review |
---|
comment:18 Changed 9 years ago by
Priority: | critical → blocker |
---|
comment:19 Changed 9 years ago by
I mostly agree with the changes made; they fix some bugs and don't seem to introduce new weirdness.
I still don't believe that Infinity in RR
is a good thing; I don't think the arguments for it are strong enough to justify what to me feels like a huge pain in the eye. But it's not too directly related to the other points addressed in this ticket, so let's leave it at that for now.
Also, in my opinion, having one complex infinity for each argument is really just as arbitrary as the current situation of having complex infinities where the real and imaginary parts can each be a real number, or positive or negative infinity. But this too is something for another time.
Now here is something that to me looks like a bug even if you believe that RR
should contain +Infinity
and -Infinity
:
sage: unsigned_infinity in RR True
This is because of the following two circumstances: RR(unsigned_infinity)
is defined (as RR(infinity)
, to be precise), and RR(infinity) == unsigned_infinity
returns True. I would prefer making RR(unsigned_infinity)
raise an error, if this can be done without breaking too much.
And here is a strange inconsistency:
sage: unsigned_infinity - oo*i ... ValueError: oo - oo not defined sage: unsigned_infinity + oo*i Infinity
I think this is best resolved by making the second example raise a ValueError
like the first one; it seems to me that neither addition nor subtraction makes sense in the unsigned infinity "ring".
comment:20 follow-up: 21 Changed 9 years ago by
unsigned_infinity in RR
returns true because there are coercions RR -> signed infinity ring -> unsigned infinity ring:
sage: get_coercion_model().explain(unsigned_infinity, RR(oo), operator.eq) Coercion on right operand via Conversion map: From: Real Field with 53 bits of precision To: The Unsigned Infinity Ring Arithmetic performed after coercions. Result lives in The Unsigned Infinity Ring The Unsigned Infinity Ring
We could disallow the conversion RR(unsigned_infinity) but it would not change anything.
I agree with you that the infinity representation in CDF and CC sucks, but thats another ticket...
comment:21 Changed 9 years ago by
Replying to vbraun:
unsigned_infinity in RR
returns true because there are coercions RR -> signed infinity ring -> unsigned infinity ring:
Yes, and I think that isn't a problem.
We could disallow the conversion RR(unsigned_infinity) but it would not change anything.
Well, if I'm not mistaken, at least it would make unsigned_infinity in RR
return False (because the conversion needs to succeed for this to return True), which was my point.
It seems my last point wasn't very clear, so here an equivalent example without complex infinities:
sage: unsigned_infinity + unsigned_infinity Infinity sage: unsigned_infinity - unsigned_infinity ... ValueError: oo - oo not defined
I think we should raise an error for addition, i.e. make the code of _add_()
work in an analogous way to that of _sub_()
. (Not that this was caused by your patch; the thing with the +i
and -i
just led me to this inconsistency.)
comment:22 Changed 9 years ago by
Commit: | cd9242959af9fda6d5351f8410889b36d6b6a392 → 34c8fec6c9b5fe83376bd6a48b52718f62658144 |
---|
Branch pushed to git repo; I updated commit sha1. New commits:
34c8fec | fix addition/subtraction of unsigned infinity
|
comment:23 Changed 9 years ago by
Status: | needs_review → positive_review |
---|
OK, I think this is enough improvement for now.
comment:24 Changed 9 years ago by
Commit: | 34c8fec6c9b5fe83376bd6a48b52718f62658144 → 3531287276d95f0a60b762c4dc5475bee4860cba |
---|---|
Status: | positive_review → needs_review |
Branch pushed to git repo; I updated commit sha1 and set ticket back to needs_review. New commits:
3531287 | forbid conversion from unsigned infinity to RR, RDF
|
comment:27 Changed 9 years ago by
Status: | positive_review → needs_info |
---|
As per #13125, I still disagree this:
sage: RIF(0, oo) [0.00000000000000000 .. +infinity] sage: RIF(0, oo) == oo True
If a discussion on sage-devel thinks this okay, then this can be merged, but I think this could very easily lead to wrong results.
comment:28 Changed 9 years ago by
I forgot about the discussion about this on #13125. I think that RIF
shouldn't coerce into the infinity ring, and that conversion should succeed if and only if the interval is finite or equal to either [-infinity .. -infinity]
or [+infinity .. +infinity]
. To motivate why there shouldn't be a coercion, I would say that RIF
and InfinityRing
are two models for underdetermined (and possibly infinite) real numbers, but that they happen to be incompatible models with regard to the data they record. In other words, neither of them is a "finer" approximation of the extended real numbers than the other.
comment:29 follow-up: 30 Changed 9 years ago by
If anything it is about more coarse approximation, this is why there is a coercion RR -> signed infinity -> unsigned infinity.
There is also a coercion RR -> RIF. IMHO there ought to be a pushout, and right now its the infinity ring. Arguably it should be a better structure that also knows about semi-infinite intervals. But until you write one we only have the infinity ring.
Really, the only question right now is whether unbounded intervals ought to coerce into a finite number or infinity. The convention that I chose is where
sage: RIF(0,oo) == oo == RIF(0,oo).center() True
Do you really want RIF(0,oo) < oo == RIF(0,oo).center()
? Because that is the only alternative.
comment:30 Changed 9 years ago by
Replying to vbraun:
If anything it is about more coarse approximation, this is why there is a coercion RR -> signed infinity -> unsigned infinity.
It is more coarse to certain extent; on the other hand RIF
does not in general specify whether an element is positive, negative, zero, plus or minus infinity.
There is also a coercion RR -> RIF. IMHO there ought to be a pushout, and right now its the infinity ring. Arguably it should be a better structure that also knows about semi-infinite intervals.
Indeed, something like a InfinityIntervalRing
(although we may want a less silly name); its elements should be intervals in the ordered set
-infinity < -finite < 0 < +finite < +infinity
[Edit: we don't necessarily have to create a new structure, maybe we can just let the existing infinity ring have such intervals as elements and regard the existing elements as one-element intervals.]
Really, the only question right now is whether unbounded intervals ought to coerce into a finite number or infinity. The convention that I chose is where
sage: RIF(0,oo) == oo == RIF(0,oo).center() TrueDo you really want
RIF(0,oo) < oo == RIF(0,oo).center()
? Because that is the only alternative.
Would there be anything against not trying to implement conversion RIF
-> InfinityRing
in this ticket at all (i.e. letting it raise an error like it does now), and fix comparison in a better way (and on a different ticket) by implementing this "infinity interval ring"?
Conversion from RIF
to the current InfinityRing
is already broken anyway, even when there are no infinities involved; do you convert the interval [-1, 1] into "a negative finite number", "zero", or "a positive finite number"?
comment:31 Changed 9 years ago by
Again, no coercion to the infinity ring means: comparison by memory address. Which will a) not be the one you like and b) inconsistent across different runs / platforms. Maybe we can't fix a) right away, but we must fix b).
comment:32 Changed 9 years ago by
Given that comparison of RIF
elements with infinity is broken, and there is no good way to fix it with the current InfinityRing
, users have to work around it by comparing upper and lower endpoings separately, until someone implements these "intervals in the infinity ring". If that is the case, then why is it so urgent to make comparison of RIF
elements with infinity sort of work right now?
comment:33 Changed 9 years ago by
All I'm saying is that the current state is a clear improvement over what we currently have. Do you want me to revert to the old behaviour of comparison by memory address, causing hard-to-debug errors where the sort order depends on the machine and time of the day?
comment:34 Changed 9 years ago by
To be honest I personally don't care too much about this specific problem, and I would be happy to set the ticket back to positive review if Travis can live with that.
comment:35 Changed 9 years ago by
Dependencies: | 13125 → #13125 |
---|
IMO this makes things worse: a potential subtle bug is better than a (generally) mathematically wrong answer. Irregardless, this is not a coercion as it is not a ring morphism:
sage: RIF(0, oo) - RIF(0, oo) [-infinity .. +infinity] sage: InfinityRing(RIF(0, oo) - RIF(0, oo)) +Infinity sage: InfinityRing(RIF(0, oo)) - InfinityRing(RIF(0, oo)) --------------------------------------------------------------------------- SignError Traceback (most recent call last) ... SignError: cannot add infinity to minus infinity
comment:36 Changed 9 years ago by
Of course its not a ring homomorphism. Neither RIF nor the infinity ring are even additive Abelian groups.
sage: x = RIF(0,1); x - x == 0 False
comment:37 follow-up: 38 Changed 9 years ago by
There should be a bit better check of equality in RIF as x - x
will be 0 because we know we are subtracting the same number (even if we don't know the exact number). However RIF(0,1) - RIF(0,1)
may or may not be 0, we don't know because the left and right terms may or may not be the same value. So IMO it still is a field (it also is in the category of Fields
), but doing exact comparisons can be difficult.
Now the infinity ring is a actually a semiring, but nevertheless it still has less structure. Even if we don't want to consider which category, the basic promise of coercion is that if you can do operation #
on (2 elements of) A
, then you can do the same (equivalent?) operation on B
.
comment:38 follow-up: 39 Changed 9 years ago by
Replying to tscrim:
So IMO it still is a field (it also is in the category of
Fields
)
RIF
is definitely not a field (and neither are RR
and RDF
). They are Sage objects that approximate the field R of real numbers in different ways, but none of these Sage objects satisfies the axioms of a field.
Now the infinity ring is a actually a semiring, but nevertheless it still has less structure.
I don't understand this. Addition of +Infinity
and -Infinity
is undefined in the infinity ring, or is this what you mean by "less structure"?
Even if we don't want to consider which category, the basic promise of coercion is that if you can do operation
#
on (2 elements of)A
, then you can do the same (equivalent?) operation onB
.
No, the operation 4 // 2
is defined in ZZ
, but not after coercion to Zmod(8)
, for example.
comment:39 follow-up: 40 Changed 9 years ago by
Replying to pbruin:
RIF
is definitely not a field (and neither areRR
andRDF
). They are Sage objects that approximate the field R of real numbers in different ways, but none of these Sage objects satisfies the axioms of a field.
Since there is oo
in RIF
, I agree with you, it's actually not a field. Although I would say that if we remove oo
, I would say it is a field. But this is a separate point, because the break is in the addition, not the multiplication. So would you say RIF
is an additive abelian group?
I also found some strange behavior with RIF
:
sage: oo in RIF True sage: RIF(oo) [+infinity .. +infinity] sage: RIF(oo) / RIF(oo) [.. NaN ..] sage: RIF(oo) / RIF(0) [-infinity .. +infinity] sage: RIF(oo) * RIF(0) 0
I don't understand this. Addition of
+Infinity
and-Infinity
is undefined in the infinity ring, or is this what you mean by "less structure"?
Yes (another example would be the tropical semiring).
No, the operation
4 // 2
is defined inZZ
, but not after coercion toZmod(8)
, for example.
In this case, division is not a part of the structure of ZZ
, so perhaps I should amend my statement above to when you can always do operation #
(i.e. it is guaranteed by the category). For RIF
, subtraction is guaranteed to work.
comment:40 follow-up: 41 Changed 9 years ago by
Replying to tscrim:
Since there is
oo
inRIF
, I agree with you, it's actually not a field. Although I would say that if we removeoo
, I would say it is a field.
No, see below.
But this is a separate point, because the break is in the addition, not the multiplication. So would you say
RIF
is an additive abelian group?
As Volker pointed out, it isn't, even if we remove infinity. And since it isn't an additive Abelian group, it certainly isn't a field either. Moreover, the set of non-zero, non-infinite elements is not a group under multiplication. For example, the interval [-1, 1] has neither an additive nor a multiplicative inverse.
I also found some strange behavior with
RIF
:sage: oo in RIF True sage: RIF(oo) [+infinity .. +infinity] sage: RIF(oo) / RIF(oo) [.. NaN ..] sage: RIF(oo) / RIF(0) [-infinity .. +infinity] sage: RIF(oo) * RIF(0) 0
That does look slightly inconsistent, especially the last one, but I don't have enough experience with RIF
to say if this is intended.
I don't understand this. Addition of
+Infinity
and-Infinity
is undefined in the infinity ring, or is this what you mean by "less structure"?Yes (another example would be the tropical semiring).
I still don't get your point. The tropical semiring is a semiring, while InfinityRing
is not a semiring.
No, the operation
4 // 2
is defined inZZ
, but not after coercion toZmod(8)
, for example.In this case, division is not a part of the structure of
ZZ
, so perhaps I should amend my statement above to when you can always do operation#
(i.e. it is guaranteed by the category). ForRIF
, subtraction is guaranteed to work.
That depends on what you mean by "work":
sage: RIF(oo) - RIF(oo) [.. NaN ..]
Maybe this should return [-infinity .. +infinity]
, then it would cooperate nicely with the future support for "intervals in the infinity ring" (comments 29 and 30 above).
comment:41 follow-up: 42 Changed 9 years ago by
Replying to pbruin:
As Volker pointed out, it isn't, even if we remove infinity. And since it isn't an additive Abelian group, it certainly isn't a field either. Moreover, the set of non-zero, non-infinite elements is not a group under multiplication. For example, the interval [-1, 1] has neither an additive nor a multiplicative inverse. ... That depends on what you mean by "work":
sage: RIF(oo) - RIF(oo) [.. NaN ..]Maybe this should return
[-infinity .. +infinity]
, then it would cooperate nicely with the future support for "intervals in the infinity ring" (comments 29 and 30 above).
From my understanding, elements in RIF aren't intervals as sets, they are a single point that's guaranteed to be within in the interval. Thus if we fix a real element x
in an interval, say [-1, 1]
, then x - x == 0
should be true (which I would say that it does not is currently a bug). However doing something like RIF(-1,1) - RIF(-1, 1)
gets two (essentially) random numbers in the interval [-1, 1]
and subtracts them and RIF
tells us the result is guaranteed to lie in [-2, 2]
.
Well...at least if we throw out the exact values of +/-oo
and the NaN
...(and it's essentially a field to the average user)
We also have this behavior with the current branch:
sage: InfinityRing(RIF(oo) - RIF(oo)) A positive finite number sage: InfinityRing(float("NaN")) A negative finite number
At least it maps this over. So to add to the question list, how do we handle this too? Keep it as is?
I still don't get your point. The tropical semiring is a semiring, while InfinityRing? is not a semiring.
Okay, I'm going to take a deep breath and try to make I'm not missing any cases or over simplifying things.
In RIF
(with [.. NaN ..]
), we have an additive abelian semigroup as we have an associative binary operation.
For InfinityRing
, we have 5 elements: [-oo, n, 0, p, oo]
where n
and p
are finite negative and positive numbers respectively. The following additions are defined (up to commutation):
-oo + [n, 0, p] -> -oo n + [n, 0] -> n p + [0, p] -> p oo + [n, 0, p] -> oo
but none of the others (and multiplication is worse). So it doesn't have any fully defined binary operations on the entire set.
I didn't miss any cases, right? If so, then this is when I say "less structure".
comment:42 Changed 9 years ago by
Replying to tscrim:
From my understanding, elements in RIF aren't intervals as sets
No, they are intervals as sets. This is how RIF is implemented, and this is how it behaves.
comment:43 Changed 9 years ago by
Then this should be true:
sage: RIF(1, 2) == RIF(1, 2) False
since they are clearly equal as sets.
comment:45 follow-up: 46 Changed 9 years ago by
I am now convinced of Volker's position to immediately fix this (to the extent possible with the current InfinityRing
). This example (without the patch applied) is decisive for me:
sage: RIF(0,1) > infinity True
comment:46 follow-up: 47 Changed 9 years ago by
Replying to pbruin:
I am now convinced of Volker's position to immediately fix this (to the extent possible with the current
InfinityRing
). This example (without the patch applied) is decisive for me:sage: RIF(0,1) > infinity True
Dependent on memory locations, YMMV
comment:47 Changed 9 years ago by
Replying to vbraun:
sage: RIF(0,1) > infinity TrueDependent on memory locations, YMMV
I know, it's just that this example made me realise how annoying that can be.
comment:48 Changed 9 years ago by
I think we should just document the behaviour of the RIF
-> InfinityRing
conversion implemented by this ticket and add a warning that this may change in the future. If everyone finds that acceptable as a (partial/temporary if you like) solution, we can close this ticket as far as I'm concerned.
comment:49 Changed 9 years ago by
However cmp
is for totally ordered sets and RIF
is not, so I don't trust it here (plus it's deprecated in python3):
sage: P = Poset([['a', 'b'], []], facade=False) sage: a = P('a') sage: b = P('b') sage: a < b False sage: b < a False sage: a > b False sage: b > a False sage: cmp(a, b) 0 sage: a == b False
So what's happening is in cmp(a, b)
, because neither a
is less/greater than b
nor vice versa, it's saying they must be equal (because it is supposed to be a totally ordered set).
I'd be okay with a big warning in the doc and a printed warning when coercing (semi)infinity intervals into the infinity ring.
comment:50 Changed 9 years ago by
I'm against printing BS warnings, the various comparison in RIF are already complicated and and more motivated by what one can do vs what is mathematically desirable.
comment:51 Changed 9 years ago by
I'm also against a printed warning, but a line or two in the docstring of the relevant _element_constructor_
and/or _coerce_map_from_
methods would be appropriate in my opinion.
comment:52 Changed 9 years ago by
Commit: | 3531287276d95f0a60b762c4dc5475bee4860cba → 632643fe5e637c44d2cbc017189c1373efd672e1 |
---|
Branch pushed to git repo; I updated commit sha1. New commits:
632643f | document the RIF comparison with infinity
|
comment:53 Changed 9 years ago by
Status: | needs_info → needs_review |
---|
comment:54 Changed 9 years ago by
Branch: | u/vbraun/infinity_ring → u/pbruin/11506-infinity_ring |
---|---|
Commit: | 632643fe5e637c44d2cbc017189c1373efd672e1 → 00eb409c89a37ccb181c6f7489675b042e2d72ae |
Status: | needs_review → positive_review |
trivial reviewer patch (fix typo)
comment:55 Changed 9 years ago by
well the semicolon was intentional, but I'm also fine with a period.
comment:56 Changed 9 years ago by
Branch: | u/pbruin/11506-infinity_ring → u/vbraun/11506-infinity_ring |
---|
comment:57 Changed 9 years ago by
Branch: | u/vbraun/11506-infinity_ring → 00eb409c89a37ccb181c6f7489675b042e2d72ae |
---|---|
Resolution: | → fixed |
Status: | positive_review → closed |
comment:58 Changed 9 years ago by
Commit: | 00eb409c89a37ccb181c6f7489675b042e2d72ae |
---|
I am a bit late to comment on this, but let me add my 2 cents about what infinity in RR
should return and related questions.
The way I understand it:
RR
essentially is an interface to MPFR. It is not, has never been and cannot be the right model for the field of real numbers in sage.RIF
being based on MPFI, its elements are sets. As a general rule, operations on these elements are required to return over-approximations of the image of their operands, period. Note that this could apply to boolean predicates: in an ideal world,[1,3] = [2,4]
would return something like{True, False}
. But some compromises are necessary, in part because sage keeps abusing Python's equality and comparison operators instead of defining its own "mathematical" equality.
So I think the problems raised by Peter and Travis are mostly due to unfortunate name choices and cannot be solved without breaking lots of existing code. The best plan I can come up with would be something like this:
- Deprecate
RR
,Reals()
, andRealField()
(Reals(p)
,RealField(p)
can probably stay). ReplaceRR
byRFP
. - Make it clear in the documentation that these parents represent sets of floating-point numbers—particular subsets of the dyadic rationals, augmented with special values such as ±∞ and equipped with well-defined, if peculiar, operations—, not the field of real numbers.
- While we're at it, deprecate
RIF
andRealIntervalField
. Rename them to something likeIR
(a common notation in interval analysis) andRealFloatingPointIntervals
. - Stop pretending any of these are fields (or even semigroups). Perhaps introduce a category of "approximate fields" (for lack of a better name).
- After the deprecation period, consider making
RR
andReals
refer to/returnRLF
(or perhaps some new implementation that better models the "true" reals). - Idem for
CC
,CIF
etc.
More oddities to fix:
Fixing this will probably also fix #9547.