Opened 2 years ago

Last modified 10 months ago

#24456 needs_work enhancement

classes for the fields of complex and real numbers

Reported by: vdelecroix Owned by:
Priority: major Milestone: sage-8.2
Component: basic arithmetic Keywords:
Cc: rws, tscrim, egourgoulhon Merged in:
Authors: Vincent Delecroix Reviewers:
Report Upstream: N/A Work issues: merge conflict
Branch: u/rws/24456 (Commits) Commit: febfe35f9a4fd3c509e1ab4e94b9c30e77ab7359
Dependencies: #24464, #24465, #24483, #24457 Stopgaps:

Description (last modified by vdelecroix)

We create (mostly abstract) classes to model the set of complex and real numbers as sage.rings.complex_field.ComplexField and sage.rings.real_field.RealField.

See also task ticket #17713.

Use cases for this new "real field" object:

  1. As some placeholder object to denote the field of real numbers, for example as output of QQ.completion(oo), for domain/codomain of symbolic functions, in manifolds, etc. This implies that it should be a unique object.
  1. As a Sage analogy to PEP 3141: it should provide a way to ask "is x a real number" or "is X a substructure of the reals" or maybe "does parent X represent the real numbers". Also, we should be able to ask "is x an exact or approximate real number". Note that Sage already has partial support for PEP 3141 but only for elements (not parents).
  1. As a class factory for all concrete real fields (e.g. the create_RealField function that is currently used for non-exact approximations).

Change History (53)

comment:1 Changed 2 years ago by vdelecroix

  • Cc rws added

comment:2 Changed 2 years ago by tscrim

  • Cc tscrim added

+1

comment:3 Changed 2 years ago by vdelecroix

:-) pushing in a minute...

comment:4 Changed 2 years ago by vdelecroix

  • Authors set to Vincent Delecroix
  • Description modified (diff)

comment:5 Changed 2 years ago by vdelecroix

  • Branch set to u/vdelecroix/24456
  • Commit set to 78f677ed25ab323d9940a1b038213356aff70a45
  • Status changed from new to needs_review

New commits:

78f677e24456: class for the field of real numbers

comment:6 Changed 2 years ago by vdelecroix

  • Description modified (diff)

comment:7 Changed 2 years ago by vdelecroix

  • Status changed from needs_review to needs_work

comment:8 Changed 2 years ago by git

  • Commit changed from 78f677ed25ab323d9940a1b038213356aff70a45 to 62d2d219c661a375f86ed6fd7c4f90f782fdf11d

Branch pushed to git repo; I updated commit sha1. This was a forced push. New commits:

62d2d2124456: class for the field of real numbers

comment:9 Changed 2 years ago by vdelecroix

  • Status changed from needs_work to needs_review

comment:10 Changed 2 years ago by rws

  • Status changed from needs_review to positive_review

For me this looks fine (I can now create the object and use it in formal expressions) and patchbot is green. If you think this is not enough for a review then please set back to "needs review".

comment:11 Changed 2 years ago by tmonteil

  • Status changed from positive_review to needs_review

comment:12 follow-up: Changed 2 years ago by rws

Thanks. I also had a question turning up while working on #24457. The code here does not support RealField(prec) anymore---the init method only has self argument, is this intended? Since real_mpfr.RealField() will be renamed should create_RealField(prec) be used everywhere instead?

comment:13 in reply to: ↑ 12 Changed 2 years ago by vdelecroix

Replying to rws:

Thanks. I also had a question turning up while working on #24457. The code here does not support RealField(prec) anymore---the init method only has self argument, is this intended?

It is intended: the field of real number is the field of real number (see e.g. wikipedia). The code provided in the branch u/vdelecroix/24456 is new, so it never used to support anything.

Since real_mpfr.RealField() will be renamed should create_RealField(prec) be used everywhere instead?

No. create_RealField is a convenience to handle options for the completion functor. There is no reason to use it directly.

The real_field.RealField in this branch has (almost) nothing to do with real_mpfr.RealField.

comment:14 Changed 2 years ago by tscrim

Some comments:

  • I think the completion of ZZ should be in a separate ticket for better granularity.
  • Similarly for changing the output of CompletionFunctor to have prec.
  • Should be "field of real numbers".
  • Why the check for façade sets in those tests? Are tests failing otherwise? I don't think they should be necessary...
  • It would be nice if RealField could be a common ABC for all classes that model R, but that is not possible because it inherits from Singleton (IMO, is a shortcoming of that class, but that is a different issue).

comment:15 follow-up: Changed 2 years ago by jdemeyer

I don't quite understand the purpose of this new RealField. Maybe it would be good to elaborate on that.

Why is this thing a Parent? Given that it doesn't have Elements (in the Sage sense), it probably should be a CategoryObject and not a Parent.

comment:16 Changed 2 years ago by jdemeyer

  • Status changed from needs_review to needs_work

comment:17 Changed 2 years ago by jdemeyer

  • Summary changed from class for the field of real number to class for the field of real numbers

comment:18 in reply to: ↑ 15 Changed 2 years ago by rws

Replying to jdemeyer:

I don't quite understand the purpose of this new RealField. Maybe it would be good to elaborate on that.

#24171 depends on this.

comment:19 Changed 2 years ago by jdemeyer

OK, I sort of see where this is going. But it doesn't explain why it is a Parent.

comment:20 Changed 2 years ago by vdelecroix

  • Dependencies set to #24464, #24465
  • Description modified (diff)

I am fine making it a CategoryObject with category Fields().Infinite().

comment:21 follow-up: Changed 2 years ago by tscrim

This is initialized as a facade parent, so it should not have an Element class.

comment:22 in reply to: ↑ 21 ; follow-up: Changed 2 years ago by jdemeyer

Replying to tscrim:

This is initialized as a facade parent

Why? As I said above, I don't see why this should be a Parent in the first place.

Also, it would be good to replace the coerce_map_from method by a real PEP 3119 check like

sage: R = RealField()  # abstract real numbers
sage: issubclass(RR, R)
True

Is that in line with what you have in mind?

comment:23 in reply to: ↑ 22 ; follow-ups: Changed 2 years ago by vdelecroix

Replying to jdemeyer:

Replying to tscrim:

This is initialized as a facade parent

Why? As I said above, I don't see why this should be a Parent in the first place.

Also, it would be good to replace the coerce_map_from method by a real PEP 3119 check like

sage: R = RealField()  # abstract real numbers
sage: issubclass(RR, R)
True

Is that in line with what you have in mind?

This is the kind of purposes I want this class for. RealField() should know about all ways of modelling concretely real numbers in Sage (but how?) and it should be possible to query it about real number questions, like the example you mentioned (but how?). The main problem I have is how to handle the distinction between exact subrings (e.g. QQ) versus approximations (e.g. RDF).

Note that in your example we might also want to make the following works

sage: import numbers
sage: isinstance(RR.element_class, numbers.Real)

comment:24 in reply to: ↑ 23 Changed 2 years ago by jdemeyer

Replying to vdelecroix:

This is the kind of purposes I want this class for.

Excellent! A big +1 from me.

comment:25 in reply to: ↑ 23 Changed 2 years ago by jdemeyer

Replying to vdelecroix:

sage: import numbers
sage: isinstance(RR.element_class, numbers.Real)

This already works except for the fact that RR doesn't have an element_class attribute:

sage: import numbers
sage: isinstance(RR.an_element(), numbers.Real)
True

But I'd really like it to work on the parent since it's the parent which models the real numbers. Also, the coercion framework mostly works with parents, so this could be useful there too.

Last edited 2 years ago by jdemeyer (previous) (diff)

comment:26 Changed 2 years ago by egourgoulhon

  • Cc egourgoulhon added

comment:27 Changed 2 years ago by egourgoulhon

It would be nice if this could serve as the base field for real manifolds. For the moment we have:

sage: M = Manifold(3, 'M', field='real'); M
3-dimensional differentiable manifold M
sage: M.base_field()
Real Field with 53 bits of precision
sage: M.base_field() is RR
True

which is a bit awkward, since all subsequent calculus on M has nothing to do with RR. Actually RR is used as a proxy for the field of real numbers, so it would be very nice to replace it by something closer to the actual field of real numbers, as the new RealField proposed here (as far as I understand).

Last edited 2 years ago by egourgoulhon (previous) (diff)

comment:28 follow-ups: Changed 2 years ago by tmonteil

Sorry for being mute, i did not have time to write something when i put this ticket back on needs-review, but i did not want it to be merged that way. Blitzkrieg is not the way, there have been too much projects within Sage dying because of a lack of consensus, and i do not want the idea of a "genuine" real field to end like this.

Of course i am in favor of having such an abstraction and i am happy that some people support this as well, however when i promoted such an idea in various sage days, tutorials, discussions, tickets, it was clear from that experience that there was no consensus about that question, at all.

Hence, i think that a collectively approved decision on such subject should happen before code. For example, the proposed branch implies behaviors such as (random undocumented examples):

sage: R = QQ.completion(infinity, infinity) ; R
Real Field

sage: QQbar(sqrt(2)).parent()
Algebraic Field
sage: R(QQbar(sqrt(2))).parent()
Algebraic Real Field

sage: QQbar(sqrt(1)).parent()
Algebraic Field
sage: R(QQbar(sqrt(1))).parent()
Rational Field

sage: 0.1 in R
False

sage: R(RDF(0.1))
1/10

sage: R(pi)
ValueError: Can't coerce `pi` in any parent `Real Field` is a facade for

sage: R(ZZ(1)).parent()
Rational Field

Which behavior do we want for this ? Which interplay with existing representations of real numbers ? What are the implications in the whole Sage ? How do we ensure a smooth transition from the current ill-named RR and a genuine RR corresponding to the field of real numbers ? Since real numbers are everywhere, we should think about the consequences before being tied with wrong design and the imperative of backward compatibility.

All this to say that we need to have a plan with a boarder view, on which the community agrees.

Note that Ralf opened a ticket on that subject, and since ticket #17713 already has some debates on this subject and a similar purpose, let me suggest to continue the discussion there (so that we collect every input in a single place), and make it a task with appropriate subtickets once we reach a consensus.

comment:29 follow-up: Changed 2 years ago by rws

The depending ticket #24171 could work with numbers.* as well, as the objects are used only internally.

comment:30 in reply to: ↑ 29 Changed 2 years ago by rws

Replying to rws:

The depending ticket #24171 could work with numbers.* as well, as the objects are used only internally.

Ah no, the numbers classes are abstract, sorry.

comment:31 in reply to: ↑ 28 ; follow-up: Changed 2 years ago by vdelecroix

Replying to tmonteil:

For example, the proposed branch implies behaviors such as (random undocumented examples):

The current RealField as it is in the branch is a facade. Which means that it does not have any element of its own. The sets for which it is a facade are concrete subrings/subfields of the set of real numbers. In the current branch it is only QQ and AA. Beyond adding more subrings/subfields, I don't see how it could be otherwise.

All the examples you mention come from the way _element_constructor_ is designed for facade sets. For each set for which it is a facade the element constructor tries a conversion to this set. The behavior might be wrong, I am just explaining the mechanic.

sage: QQbar(sqrt(2)).parent() Algebraic Field sage: R(QQbar(sqrt(2))).parent() Algebraic Real Field

This is because AA(QQbar(sqrt(2))) is the first to succeed (QQ(QQbar(sqrt(2))) does not).

sage: QQbar(sqrt(1)).parent() Algebraic Field sage: R(QQbar(sqrt(1))).parent() Rational Field

This is because QQ(QQbar(sqrt(1))) does succeed.

sage: 0.1 in R False

As it should be!

sage: R(RDF(0.1)) 1/10

Because QQ(RDF(0.1)) works that way.

sage: R(pi) ValueError?: Can't coerce pi in any parent Real Field is a facade for

Because there is not yet any subset of the real numbers handling pi. As soon as there is one, it should be added to the facades and the above will work.

sage: R(ZZ(1)).parent() Rational Field

This is because QQ(ZZ(1)) is the first to succeed (we might add ZZ to the list of facades).

Which behavior do we want for this?

For me, the current behavior of element construction is close to what it should be. To make things smoother, we might want to modify the QQbar -> QQ to a QQbar -> AA. This can be achieved by using a friend complex field on which we could call .real(). More precisely

def _element_constructor_(self, x):
    if parent(x) in self.facade_for():
        return x

    CC = ComplexField()   # the genuine one of course
    try:
        z = CC(x)
    except (ValueError,TypeError):
        pass
    else:
        if z.is_real():   # does not currently work for QQbar
            return z.real()

    raise ValueError("x not recognized as a real number")

Which interplay with existing representations of real numbers?

This is precisely the question in 23 that you are not helping with by asking it again.

What are the implications in the whole Sage?

Just new features. To be able to do

  • mathematical construction relying on an (abstract) field of real numbers (such as manifolds, see 27)
  • querries like "is parent X is a model for real numbers" (see 22 and follow-up)

How do we ensure a smooth transition from the current ill-named RR and a genuine RR corresponding to the field of real numbers?

This question is beyond the scope of this ticket. But see #24457.

Since real numbers are everywhere, we should think about the consequences before being tied with wrong design and the imperative of backward compatibility.

All this to say that we need to have a plan with a boarder view, on which the community agrees.

Note that Ralf opened a ticket on that subject, and since ticket #17713 already has some debates on this subject and a similar purpose, let me suggest to continue the discussion there (so that we collect every input in a single place), and make it a task with appropriate subtickets once we reach a consensus.

To balance, let me add that ticket #17713 was opened 3 years ago, contains three messages and no concrete proposal. It refers to another ticket #15944 that was untouched during 4 years. This ticket on the other hand, started with a concrete proposal and 4 people expressed their opinions. I am about to propose a new version taking into account all comments. We are also not likely to merge it soon as the discussion is going on.

Tickets are also dying because of absence of action. Status-quo is not the way to go either.

comment:32 Changed 2 years ago by vdelecroix

  • Dependencies changed from #24464, #24465 to #24464, #24465, #24483
  • Description modified (diff)
  • Summary changed from class for the field of real numbers to classes for the fields of complex and real numbers

comment:33 in reply to: ↑ 28 Changed 2 years ago by jdemeyer

Replying to tmonteil:

sage: R(QQbar(sqrt(2))).parent()
Algebraic Real Field

sage: R(QQbar(sqrt(1))).parent()
Rational Field

sage: R(RDF(0.1))
1/10

sage: R(pi)
ValueError: Can't coerce `pi` in any parent `Real Field` is a facade for

sage: R(ZZ(1)).parent()
Rational Field

All of these could be fixed by simply not letting R be a Parent and disallowing R(anything). As I said in some comments above, I don't see why R should be a Parent (facade or not).

comment:34 in reply to: ↑ 31 Changed 2 years ago by jdemeyer

Replying to vdelecroix:

sage: 0.1 in R
False

As it should be!

If you think that 0.1 should not be contained in the field of real numbers, you'll need to justify that better. For me, it is obvious that 0.1 is a real number, such that 0.1 in R must be True.

comment:35 in reply to: ↑ 28 Changed 2 years ago by jdemeyer

Replying to tmonteil:

Hence, i think that a collectively approved decision on such subject should happen before code.

+1

It is clear that people support the idea of having a true "real field" object in Sage. However, it is not clear at all what kind of object this should be and how it should be used.

comment:36 follow-up: Changed 2 years ago by jdemeyer

Maybe we should start by thinking about possible use cases for this "real field":

  1. As some placeholder object to denote the field of real numbers, for example as output of QQ.completion(oo). This implies that it should be a unique object.
  1. As a Sage analogy to PEP 3141: it should provide a way to ask "is x a real number" or "is X a substructure of the reals" or maybe "does parent X represent the real numbers". Note that Sage already has partial support for PEP 3141 but only for elements (not parents).

comment:37 Changed 2 years ago by vdelecroix

  • Dependencies changed from #24464, #24465, #24483 to #24464, #24465, #24483, #24457

comment:38 Changed 2 years ago by vdelecroix

  • Description modified (diff)

comment:39 in reply to: ↑ 36 ; follow-ups: Changed 2 years ago by vdelecroix

Replying to jdemeyer:

Maybe we should start by thinking about possible use cases for this "real field":

  1. As some placeholder object to denote the field of real numbers, for example as output of QQ.completion(oo). This implies that it should be a unique object.

Agreed.

  1. As a Sage analogy to PEP 3141: it should provide a way to ask "is x a real number" or "is X a substructure of the reals" or maybe "does parent X represent the real numbers". Note that Sage already has partial support for PEP 3141 but only for elements (not parents).

I want to be able distinguish between exact subrings and non-exact approximations. This is for coercion reasons: each exact subring coerces into all non-exact approximations. This is also why I claimed that 0.1 in R should be False.

Let me add

  1. As a way to check for is x an exact real number? and is x a non-exact real number?. We should specify clearly that isinstance(x, numbers.Real) means exact real or non-exact real (I take that as given because both issubclass(int, numbers.Real) and issubclass(float, numbers.Real) are True).
  1. As a pointers to all real field implementations (exact subrings and non-exact approximations). In particular it should contain a class factory for all concrete real fields (e.g. the create_RealField function that is currently used for non-exact approximations).

comment:40 Changed 2 years ago by tscrim

If you want to ask about exact reals, you should have a 2', where you have a subclass of generic all reals class for the exact reals.

comment:41 Changed 2 years ago by vdelecroix

Concerning approximations (like floating point numbers), there are often the three special values NaN, +inf and -inf which are not real numbers (in the mathematical sense). For -inf and +inf one can still argue that they approximate very negative and very positive reals. But NaN is not an approximation of anything. This is one more argument for having RealField() to mean exact real numbers.

On the other hand, Python numbers.Real means both floating and exact. Having different semantic for RealField() and numbers.Real might be disturbing.

comment:42 in reply to: ↑ 39 Changed 2 years ago by jdemeyer

Replying to vdelecroix:

This is also why I claimed that 0.1 in R should be False.

I still don't get this. Please elaborate...

comment:43 Changed 2 years ago by jdemeyer

  • Description modified (diff)

comment:44 in reply to: ↑ 39 ; follow-up: Changed 2 years ago by jdemeyer

Replying to vdelecroix:

  1. As a pointers to all real field implementations (exact subrings and non-exact approximations). In particular it should contain a class factory for all concrete real fields (e.g. the create_RealField function that is currently used for non-exact approximations).

What is the it in this last sentence?

comment:45 follow-up: Changed 2 years ago by vdelecroix

Replying to jdemeyer:

Replying to vdelecroix:

This is also why I claimed that 0.1 in R should be False.

I still don't get this. Please elaborate...

For me RealField means the field of real numbers in the mathematical sense together with its exact operations +, -, log, exp, etc. Floating-point numbers do not respect exactness of operations and for me do not qualify as being real numbers. I agree that you can think of a floating point number in two ways. As an approximation of a real number "m ± 2-e" or as a diadic number "p 2-n". The latter is the actual datastructure but it is mostly useless to think of it this way when doing mathematics. This is moreover how it works in Sage: QQ coerces into RealField(prec) and not the contrary even though RealField(prec) is formally a subset of QQ.

comment:46 in reply to: ↑ 44 ; follow-up: Changed 2 years ago by vdelecroix

Replying to jdemeyer:

Replying to vdelecroix:

  1. As a pointers to all real field implementations (exact subrings and non-exact approximations). In particular it should contain a class factory for all concrete real fields (e.g. the create_RealField function that is currently used for non-exact approximations).

What is the it in this last sentence?

I meant the genuine real field that we are trying to design.

comment:47 in reply to: ↑ 46 Changed 2 years ago by jdemeyer

  • Description modified (diff)

Replying to vdelecroix:

I meant the genuine real field that we are trying to design.

OK, so what would it mean for a Python object (representing the real field) to "contain a class factory"? Do you want something like

sage: R = RealField()
sage: R.create(prec=53, implementation="mpfr")
Real Floating-point field with 53 bits of precision

or maybe

sage: R = RealField()
sage: R(prec=53, implementation="mpfr")
Real Floating-point field with 53 bits of precision

comment:48 in reply to: ↑ 45 ; follow-up: Changed 2 years ago by jdemeyer

Replying to vdelecroix:

For me RealField means the field of real numbers in the mathematical sense together with its exact operations +, -, log, exp, etc. Floating-point numbers do not respect exactness of operations and for me do not qualify as being real numbers.

That point of view is technically mathematically true but also completely useless. Clearly, the real floating-point field is meant to model the real numbers. For technical reasons, the operations are not exact. But that is an implementation detail and not a mathematical property. For practical purposes, it behaves as a field.

I do agree that it makes sense to differentiate between exact real fields and approximate real fields, but both are real fields.

comment:49 in reply to: ↑ 48 Changed 2 years ago by vdelecroix

Replying to jdemeyer:

Replying to vdelecroix:

For me RealField means the field of real numbers in the mathematical sense together with its exact operations +, -, log, exp, etc. Floating-point numbers do not respect exactness of operations and for me do not qualify as being real numbers.

That point of view is technically mathematically true but also completely useless. Clearly, the real floating-point field is meant to model the real numbers.

Indeed!

For technical reasons, the operations are not exact. But that is an implementation detail and not a mathematical property. For practical purposes, it behaves as a field.

It is not associative! Equality dramatically fails! This is not a detail.

I do agree that it makes sense to differentiate between exact real fields and approximate real fields, but both are real fields.

I also agree and IMHO, for consistency with numbers.Real, the genuine RealField should be both used for approximate (= projection) and exact (= subset). And this should be very clearly stated.

comment:50 Changed 2 years ago by vdelecroix

  • Description modified (diff)

comment:51 Changed 2 years ago by rws

  • Branch changed from u/vdelecroix/24456 to u/rws/24456

comment:52 Changed 2 years ago by rws

  • Commit changed from 62d2d219c661a375f86ed6fd7c4f90f782fdf11d to febfe35f9a4fd3c509e1ab4e94b9c30e77ab7359
  • Status changed from needs_work to needs_review

Rebased on the dependency.


New commits:

875c23124483: merge complex_number/complex_field into complex_mpfr
f3ed18c24483: fix interpreters
14c975324483: fix imports and doctests
1fdb61cMerge branch 'develop' into t/24483/24483
aefb4df24483: fix import
febfe35Merge branch 'u/vdelecroix/24456' of git://trac.sagemath.org/sage into tmp18

comment:53 Changed 10 months ago by dkrenn

  • Status changed from needs_review to needs_work
  • Work issues set to merge conflict

Does not apply anymore.

Note: See TracTickets for help on using tickets.