JuliaLang / julia

The Julia Programming Language
https://julialang.org/
MIT License
45.89k stars 5.49k forks source link

Abstract type between `AbstractFloat` and `Real` #15086

Closed Synthetica9 closed 5 years ago

Synthetica9 commented 8 years ago

I ran into this issue when trying to make linspace spit out fixed point numbers (Courtesy of Jeff Bezanson's FixedPointNumbers.jl). The problem is that linspace asks for an AbstractFloat. At first, this seems entirely reasonable; given the help availiable in the console:

help?> AbstractFloat
search: AbstractFloat

  No documentation found.

  Summary:

  abstract AbstractFloat <: Real

  Subtypes:

  BigFloat
  Float16
  Float32
  Float64

The supertype (Real) would be too broad, since it would include integers, and any of its subtypes (BigFloat, Float16, Float32, and Float64) would be too restrictive.

However, there is no way for anyone to create an type that isn't technically a floating point, yet does support continuous values. We already have such a type, namely Rational.

I propose that an abstract type ContinuousReal be placed as a subtype of Real, and that Rational and AbstractFloat be made subtypes of it; and that the type requirements of library functions be updated to match where appropriate.

tkelman commented 8 years ago

Rationals aren't really continuous, and neither are fixed precision floats or fixed point numbers. It's a good idea though, but could maybe use a more accurate name.

jiahao commented 8 years ago

Strictly speaking, a set cannot be 'continuous' (in the mathematical sense, only functions and their generalizations are said to be continuous). The closest notion I can think of is that of meagreness, but a name like MeagreReal, while more correct, seem obscure and hard to discover. (It also doesn't really differentiate integers and rationals...)

JeffBezanson commented 8 years ago

Maybe AbstractRational? Both fixed and floating point types represent rational numbers.

simonbyrne commented 8 years ago

Well integers are rationals as well.

I'm slightly skeptical of expanding this hierarchy too much, as it does add to the cognitive load (not to mention ambiguity warnings).

JeffreySarnoff commented 8 years ago

This same situation holds with any enhanced or extended or otherwise qualified realization of a floating point type. I can't comment on the ambiguity warnings. AbstractFloat <: AbstractRational <: AbstractReal <: Number would be helpful to me, and allow better specificity when protocols come along. Pulling Complex into the hierarchy probably simplifies stuff over time. AbstractFloat <: AbstractRational <: AbstractReal <: AbstractComplex <: Number

Synthetica9 commented 8 years ago

@JeffreySarnoff Why should AbstractComplex be pulled into the hierarchy? What number types are there that are a Number, but not an AbstractComplex?

JeffreySarnoff commented 8 years ago

@Synthetica9 Quaternions (used in computer graphics), Dual Numbers (used in automatic differentiation), Dual Quaternions (used in robotics), Split Complex Numbers (used in special relativity) ...

Synthetica9 commented 8 years ago

@JeffreySarnoff I suppose those are all valid cases. I'm still not sure if AbstractComplex would be the right call; but it might very well be. (I also don't think I'm quite qualified to speak on the subject)

SaraWolffs commented 8 years ago

Apologies for huge comment, short version at the bottom.

Confession first: I'm the one who made up the original ContinuousReal name in a discussion about this which resulted in @Synthetica9 posting. It's a sloppy name, mathematically speaking, but there is some justification possible for the choice made intuitively: It'd encompass all T<:Real admitting meaningfully continuous endomorfisms (meaning the standard topology on the set approximated by T is not discrete).

AbstractReal<:AbstractComplex seems sane for the same reasons Integer<:Real is: the subtype relation encodes a subset relation of the underlying sets. A good reason for subtyping, but under that convention, AbstractRational would correspond to Q... which has Z as a subset, implying Integer<:AbstractRational, and we're back where we started, as @simonbyrne noted.

What we want here is not an abstract type corresponding to a set, to be subtyped by all types corresponding to subsets. Instead, we want an abstract type corresponding to a set of types, this being the set of all subtypes of Real closed under /, to be subtyped by all types in that set (and supertyped by any universally shared supertypes of the elements).

Calling such types AbstractRational sounds reasonable, since rationals are constructed precisely to be the closure of integers under / (that is, Q is the fraction field of Z. Which, incidentally, offers a third option, Fractional)

Given these differences in what subtyping signifies, I don't think I like the idea of having AbstractRational<:AbstractReal<:AbstractComplex if AbstractRational is the abstract type we're discussing here. Various reasons discussed below, short version: Neither AbstractReal nor AbstractComplex should exist under those names: Either those types don't follow the same naming convention as AbstractRational, which is confusing, or they do, which has a lot of issues.

End of main comment, some discussion of Abstract*

The naming convention would be non-uniform if AbstractReal corresponded to R with subset subtypes and AbstractComplex corresponded to C with with subset subtypes, while AbstractRational corresponded to the set of types closed under / with element subtypes.

The alternative, AbstractReal and AbstractComplex following the convention set by AbstractRational, is probably even worse:

First, something which is not a problem but needs to be noted: it would require AbstractComplex<:AbstractRational && AbstractReal<:AbstractRational, not AbstractRational<:AbstractReal<:AbstractComplex,

Second, it would be quite senseless/useless: AbstractReal would signify being compact (closed under 'limit'), but such closures have an annoying tendency to be either uncountable, and therefore not representable by any type, or useless, with only eventually constant sequences having limits. AbstractComplex would represent algebraic closure, which kind of is possible, but would be better served by a different name, since the algebraic closure of Z also includes, for instance, sqrt(2)+(3/2)im, which is not a Complex{Integer} as one would expect.

Short version

Mea culpa on ContinuousReal AbstractRational sounds good Fractional or Fraction might also work AbstractReal and AbstractComplex are quite problematic if AbstractRational is chosen, and should not be introduced.

J-Sarnoff commented 8 years ago

@Garnasha would you mind clarifying: I understand your point that the nature of Float<:Rational is different from Real <: Complex. Forgetting about the name chosen -- or choosing whatever names are best -- do you object to a numeric hierarchy where Integer <: Rational <: Real <: Complex and Irrational <: Real <: Complex?

JeffreySarnoff commented 8 years ago

and if so, why

JeffBezanson commented 8 years ago

I dislike Real <: Complex, because Complex is a field extension, and not an essential abstraction of the real numbers. One can invent all sorts of field extensions Foo, and having done that doesn't mean everybody must consider Real a subtype of Foo.

JeffreySarnoff commented 8 years ago

Thank you for the clarification, that makes sense.

StefanKarpinski commented 8 years ago

I agree. We identify the the reals with a subset of the complex plane in math, but they aren't by construction actually a subset. Similarly with integers and rationals. And UInt8 is not a subset of Int64 even though the set of mathematical values are a subset.

SaraWolffs commented 8 years ago

@JeffBezanson the same can be said for Integer <: Real though, or even Rational <: Real : both those extension are also one of many possibilities. That's not to say it isn't a valid concern, but it's not open and shut. And while Complex is just one extension, it is by far the most popular algebraic closure of R.

There's a more abstract discussion possible here, which I'm opening a separate issue on because it threatened to become rather off-topic here (the topic here being the introduction of AbstractRational to encode closure under /). Short version: a much more liberal approach to subtype specifications might be possible (without upsetting internal representation), thanks to the Julia approach to inheritance, rendering the Real<:SomeExtension discussion moot.

Edit

Never mind, that discussion presupposes support for multiple inheritance, since that makes the type hierarchy a DAG rather than a tree, allowing the addition of a supertype to an existing type. In a tree hierarchy, it doesn't work.

In that light, Real <: Complex is probably not the way to go.

eschnett commented 8 years ago

Instead of using subsets, this is more elegantly solved with traits. With a trait, you specify what properties a certain type must have (e.g. "closed under division"), and then an arbitrary number of types can implement this trait.

SaraWolffs commented 8 years ago

+1 for traits, I think (would have to read more) but are they an official part of the language, or at least going to be?

tkelman commented 8 years ago

It's likely that something trait/protocol-like will make its way into the language before 1.0. We'll need to work out the right design, which will take some time.

oxinabox commented 8 years ago

I ran into this as an issue today, I wanted a function to be allowed to take any number, so long as division was certain to not throw a Inexact Error. I was thinking AbstractField (but that is a confusing name since we use the keyword field already). I wanted to be able to pass Rationals, Floats, Complexs, and DuelNumbers of the aformentioned.

Then I realized that I don't actually have to enforce this in the function signature (though it would be nice to be able to), I can just let the exact error propagate up.

vtjnash commented 5 years ago

This probably would have been better captured as a discourse discussion, since it's not really an issue, just a question that could be a PR. Closing as not-a-bug, but discussion may continue (or perhaps restart on discourse, where there might be more commenters). As the above commenter (oxinabox) noted, however, duck-typing may be better.