Opened 10 years ago

Closed 7 years ago

Last modified 6 years ago

#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) Commit:
Dependencies: #13125 Stopgaps:

Description (last modified by vbraun)

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 9 years ago by tscrim

More oddities to fix:

sage: oo
+Infinity
sage: RR(oo) # Note the capitalization
+infinity
sage: oo * oo    
+Infinity
sage: RR(oo) * CC(oo)
+infinity - NaN*I
sage: CC(5) * CC(oo)
+infinity - NaN*I
sage: RR(5) * RR(oo)
+infinity
sage: oo * unsigned_infinity
Infinity
sage: RR(oo) * unsigned_infinity
ValueError: oo times number < oo not defined

Fixing this will probably also fix #9547.

comment:2 Changed 8 years ago by tscrim

This is related to #14045.

comment:3 Changed 8 years ago by tscrim

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.

See also #14088.

Last edited 8 years ago by tscrim (previous) (diff)

comment:4 Changed 7 years ago by jdemeyer

  • Milestone changed from sage-5.11 to sage-5.12

comment:5 Changed 7 years ago by eviatarbach

See also #14857.

As well, things like this:

sage: bool(SR(oo) > 5)
False

comment:6 Changed 7 years ago by zimmerma

see also my comment about limit in #14857: shouldn't limit return an element of InfinityRing? for Infinity, +Infinity, -Infinity?

Paul

comment:7 Changed 7 years ago by pbruin

  • Priority changed from major to 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 .

Last edited 7 years ago by pbruin (previous) (diff)

comment:8 Changed 7 years ago by was

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 7 years ago by pbruin

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 7 years ago by vbraun_spam

  • Milestone changed from sage-6.1 to sage-6.2

comment:11 Changed 7 years ago by vbraun_spam

  • Milestone changed from sage-6.2 to sage-6.3

comment:12 Changed 7 years ago by vbraun

  • Branch set to u/vbraun/infinity_ring

comment:13 Changed 7 years ago by vbraun

  • Authors set to Volker Braun
  • Commit set to f96c67ec2103455ab72783f4c4eb4484e588fdd5
  • Dependencies set to 13125

New commits:

308d16bImplement RealSet - finite unions of open/closed/semi-closed subsets of the real line.
a861752Further improvements to RealSet
15ef91cTrac #13125: reviewer's patch: fix typos, add module to set refman
d7e2c53Merge branch 'develop' into ticket/13125
142aa88add tests for comparison of infinity with other ring elements
e4303eafix element constructor of the infinity ring
fa497eehandle conversion of RIF into InfinityRing
563a877also handle conversion of symbolic infinity
cef5700Merge branch 'develop' into t/13125/ticket/13125
f96c67estrip out grant acknowledgement

comment:14 Changed 7 years ago by vbraun

  • Reviewers set to 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 7 years ago by git

  • Commit changed from f96c67ec2103455ab72783f4c4eb4484e588fdd5 to cd9242959af9fda6d5351f8410889b36d6b6a392

Branch pushed to git repo; I updated commit sha1. New commits:

cd92429also add conversion (not: coercion) for CC -> infinity ring

comment:16 Changed 7 years ago by vbraun

  • 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 7 years ago by vbraun

  • Status changed from new to needs_review

comment:18 Changed 7 years ago by vbraun

  • Priority changed from critical to blocker

comment:19 Changed 7 years ago by pbruin

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: Changed 7 years ago by vbraun

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 in reply to: ↑ 20 Changed 7 years ago by pbruin

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 7 years ago by git

  • Commit changed from cd9242959af9fda6d5351f8410889b36d6b6a392 to 34c8fec6c9b5fe83376bd6a48b52718f62658144

Branch pushed to git repo; I updated commit sha1. New commits:

34c8fecfix addition/subtraction of unsigned infinity

comment:23 Changed 7 years ago by pbruin

  • Status changed from needs_review to positive_review

OK, I think this is enough improvement for now.

comment:24 Changed 7 years ago by git

  • Commit changed from 34c8fec6c9b5fe83376bd6a48b52718f62658144 to 3531287276d95f0a60b762c4dc5475bee4860cba
  • Status changed from positive_review to needs_review

Branch pushed to git repo; I updated commit sha1 and set ticket back to needs_review. New commits:

3531287forbid conversion from unsigned infinity to RR, RDF

comment:25 Changed 7 years ago by vbraun

Not so fast, I was implementing your suggestion ;-)

comment:26 Changed 7 years ago by pbruin

  • Status changed from needs_review to positive_review

Even better!

comment:27 Changed 7 years ago by tscrim

  • Status changed from positive_review to 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.

Last edited 7 years ago by tscrim (previous) (diff)

comment:28 Changed 7 years ago by pbruin

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: Changed 7 years ago by vbraun

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 in reply to: ↑ 29 Changed 7 years ago by pbruin

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()
True

Do 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"?

Last edited 7 years ago by pbruin (previous) (diff)

comment:31 Changed 7 years ago by vbraun

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 7 years ago by pbruin

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 7 years ago by vbraun

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 7 years ago by pbruin

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 7 years ago by tscrim

  • Dependencies changed from 13125 to #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 7 years ago by vbraun

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: Changed 7 years ago by tscrim

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 in reply to: ↑ 37 ; follow-up: Changed 7 years ago by pbruin

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 on B.

No, the operation 4 // 2 is defined in ZZ, but not after coercion to Zmod(8), for example.

comment:39 in reply to: ↑ 38 ; follow-up: Changed 7 years ago by tscrim

Replying to pbruin:

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.

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 in ZZ, but not after coercion to Zmod(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 in reply to: ↑ 39 ; follow-up: Changed 7 years ago by pbruin

Replying to tscrim:

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.

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 in ZZ, but not after coercion to Zmod(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.

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 in reply to: ↑ 40 ; follow-up: Changed 7 years ago by tscrim

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 in reply to: ↑ 41 Changed 7 years ago by vbraun

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 7 years ago by tscrim

Then this should be true:

sage: RIF(1, 2) == RIF(1, 2)
False

since they are clearly equal as sets.

comment:44 Changed 7 years ago by vbraun

sage: cmp(RIF(1,0), RIF(1,0))
0

comment:45 follow-up: Changed 7 years ago by 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

comment:46 in reply to: ↑ 45 ; follow-up: Changed 7 years ago by vbraun

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 in reply to: ↑ 46 Changed 7 years ago by pbruin

Replying to vbraun:

sage: RIF(0,1) > infinity
True

Dependent on memory locations, YMMV

I know, it's just that this example made me realise how annoying that can be.

comment:48 Changed 7 years ago by pbruin

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 7 years ago by tscrim

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.

Last edited 7 years ago by tscrim (previous) (diff)

comment:50 Changed 7 years ago by vbraun

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 7 years ago by pbruin

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 7 years ago by git

  • Commit changed from 3531287276d95f0a60b762c4dc5475bee4860cba to 632643fe5e637c44d2cbc017189c1373efd672e1

Branch pushed to git repo; I updated commit sha1. New commits:

632643fdocument the RIF comparison with infinity

comment:53 Changed 7 years ago by vbraun

  • Status changed from needs_info to needs_review

comment:54 Changed 7 years ago by pbruin

  • Branch changed from u/vbraun/infinity_ring to u/pbruin/11506-infinity_ring
  • Commit changed from 632643fe5e637c44d2cbc017189c1373efd672e1 to 00eb409c89a37ccb181c6f7489675b042e2d72ae
  • Status changed from needs_review to positive_review

trivial reviewer patch (fix typo)

comment:55 Changed 7 years ago by vbraun

well the semicolon was intentional, but I'm also fine with a period.

comment:56 Changed 7 years ago by vbraun

  • Branch changed from u/pbruin/11506-infinity_ring to u/vbraun/11506-infinity_ring

comment:57 Changed 7 years ago by vbraun

  • Branch changed from u/vbraun/11506-infinity_ring to 00eb409c89a37ccb181c6f7489675b042e2d72ae
  • Resolution set to fixed
  • Status changed from positive_review to closed

comment:58 Changed 7 years ago by mmezzarobba

  • Commit 00eb409c89a37ccb181c6f7489675b042e2d72ae deleted

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(), and RealField() (Reals(p), RealField(p) can probably stay). Replace RR by RFP.
  • 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 and RealIntervalField. Rename them to something like IR (a common notation in interval analysis) and RealFloatingPointIntervals.
  • 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 and Reals refer to/return RLF (or perhaps some new implementation that better models the "true" reals).
  • Idem for CC, CIF etc.
Last edited 6 years ago by mmezzarobba (previous) (diff)
Note: See TracTickets for help on using tickets.