cjdoris / Infinity.jl

Representation of infinity in Julia
https://juliahub.com/docs/Infinity/
MIT License
14 stars 4 forks source link

Combine with InfiniteArrays.Infinity? #25

Open dlfivefifty opened 4 years ago

dlfivefifty commented 4 years ago

InfiniteArrays.jl currently has several infinite types and could make sense to unify this with this package. In particular I have

  1. Infinity <: Integer. This is because it represents cardinality, and so need it to be an Integer to work with the array interfaces. Note I believe in interpreting Integer as an an interface, not a mathematical definition, so since Infinity conforms to the Integer interface this is a valid definition.
  2. SignedInfinity <: Integer, to support +∞ and -∞.
  3. OrientedInfinity{T<:Real} <: Number. This is for infinities in the complex plane (unfortunately there's no AbstractComplex to subtype)

What do you think? It will take some thought, in particular I would propose at least:

  1. Rename Infinity.jl as Infinities.jl
  2. Move to JuliaMath
  3. Rename Infinite as Infinity (adjective -> noun)
  4. Decide whether Infinity <: Integer makes sense, or whether that should be another type called InfiniteCardinality.
cjdoris commented 4 years ago

Hi @dlfivefifty, thanks for your message. I've been mulling it over. Yes I'm favour of your proposal in general.

Currently this package has the following types:

  1. Infinite <: Real (signed infinity)
  2. InfExtendedReal{T<:Real} <: Real (essentially Union{T,Infinite})
  3. InfExtendedTime{T<:TimeType} <: TimeType (essentially Union{T,Infinite})

The original motivation for the package was the InfExtendedReal type, not Infinite itself, hence why Infinite is not as well thought through --- it basically only exists to be coerced to another type.

Over on #11 I was already considering making Infinity non-real (so Infinite <: Any) because the package now supports non-number kinds of infinity, like infinite time, and also adding more specialised types like InfiniteReal <: Real, InfiniteTime <: TimeType so that we can support sensible default promotions like promote_rule(InfiniteReal, T<:Real) = InfExtendedReal{T}.

In response to your proposals:

  1. I don't know how to change the name of a registered package, but I assume it's possible. Or perhaps you add a new one and depracate the old one? Also see 3.
  2. Yes that makes sense. Again, I don't know how you move a registered package.
  3. I went with the current naming scheme because the Number hierarchy already uses adjectives like Real and Rational, but then I suppose Float is a verb and all of these terms are colloquially also used as nouns, so I'm happy to change Infinite to Infinity and Infinity to Infinities
  4. I don't think the base Infinity type should have any supertypes, because there are different sorts of non-integer infinity (e.g. infinite time), but I'd be happy to have more specialised infinite types.

So I think the types should look like this:

  1. Infinity <: Any, a singleton type with ∞ = Infinity().
  2. SignedInfinity <: Any, a signed type with a signbit::Bool field, and -∞ = SignedInfinity(true).
  3. URealInfinity <: Real and RealInfinity <: Real are the unsigned and signed real infinity types.
  4. (Perhaps UIntegerInfinity <: Unsigned and IntegerInfinity <: Signed for unsigned and signed integer infinities.)
  5. ComplexInfinity{T} <: Number for complex infinities with a phase of type T.
  6. All the InfExtended* types we currently support.

It sounds like a lot, but for most users it suffices to just use and coercion will deal with the rest.

Some things I'm not sure about:

  1. It's not clear to me if having IntegerInfinity is useful in addition to RealInfinity. You might suggest having RealInfinity <: Signed but infinity isn't really a (mathematical) integer, and in the absence of an official interface for Integer I don't think we should add a non-integer type to it. I don't think it could satisfy any reasonable interface anyway --- e.g. there is no choice of mod(∞,10) so that the identity mod(∞+1,10) == mod(mod(∞,10)+1,10) holds. On the other hand, the Real interface already contains infinities (Inf and 1//0).
  2. We could supply helper unions, such as IntegerOrInfinity = Union{Integer, RealInfinity, URealInfinity, InfExtended{<:Integer}}.
  3. Perhaps ComplexInfinity{T} should not store the phase as a T but the sign as a Complex{T}? Then we could have z*∞ = Complex(sign(z)) where z::Complex, analagously to -∞ = SignedInfinity(true).
  4. If so, then for consistence perhaps SignedInfinity should be represented not by its signbit::Bool but by its sign::Int8 ∈ {-1,1}.
dlfivefifty commented 4 years ago

In my usage I absolutely need an infinity that's a subtype or Integer to interface with the array interface successfully. Note I also use aleph infinities in ContinuumArrays.jl for higher order cardinalities.

So perhaps we do this:

const InfiniteCardinality{K} <: Integer end

const ℵ₀ = InfiniteCardinality{0}()
cjdoris commented 4 years ago

Do you just need infinite cardinalities, or do you also need the IntegerInfinity type I suggested above, because they are different things? Some use cases might be helpful for me to understand.

dlfivefifty commented 4 years ago

For the most part, just infinite cardinalities. Though there was a need to negate them ( probably somewhere in the array code it called -length(a)) so I also have SignedInfinity <: Integer. I could probably live without this being an Integer though we'd have to experiment with the code to see if that breaks anything.

We should think if there's a cleaner way to extend number systems. For reals and integers there's always a choice between adding two or one infinity. For complex's there's a choice between one infinity and an infinity from each direction.

cjdoris commented 4 years ago

The main goal of this package is to provide a useful notion of infinity that sits within the existing base Julia types. The existing infinities Inf and 1//0 are signed and represent the directional notion of infinity, so this is what Infinity does too. I think its most natural/useful for users of this package, and extends naturally to types which are ordered but have no ring structure, such as Date (and it preserves the ordering).

If you want the unique projective infinity, then I suppose we could have a singleton type ProjectiveInfinity <: ProjectiveNumber <: Number and also extension types ProjectiveInteger, ProjectiveReal, ProjectiveComplex <: ProjectiveNumber.

As for infinite cardinals, it seems reasonable to have something like InfiniteCardinal <: Unsigned (and SignedInfiniteCardinal <: Signed). I'm a bit confused why it's so important that these are Integers though: ContinuumArrays is build on QuasiArrays, and those by design allow more general indexing, so you aren't restricted to integers?

dlfivefifty commented 4 years ago

Because InfiniteArrays.jl supports infinite sized AbstractArrays. Julia's array code assumes length returns an Integer so it is essential that the infinite cardinalities are <: Integer

cjdoris commented 4 years ago

Makes sense. So what do you think of my earlier 6 point proposal?

dlfivefifty commented 4 years ago

Ahhh!!! Accidentally closed the window with a detailed response to all your comments 😰

The main point: I think Infinity <: Number makes sense, and things like "infinite time" handled via units, e.g.:

julia> using InfiniteArrays, Unitful, Unitful.DefaultSymbols

julia> ∞ * hr
∞ hr

That would not be possible if Infinity <: Any.

cjdoris commented 4 years ago

Oh no!!!

I think you might be right --- overloading the meaning of to mean other sorts of infinities does seem wrong.

I think we'll still need something like InfiniteTime <: TimeType for interoperability with DateTime though, and reasonable conversions like Time(∞) or something.

So the proposal becomes:

  1. Infinity <: Real, singleton type, ∞=Infinity(), representing the positive real infinity.
  2. SignedInfinity <: Real for and -∞, represented by its sign.
  3. ComplexInfinity <: Number for z * ∞ where z is a complex unit, represented by sign(z).
  4. InfiniteCardinal <: Integer for infinite cardinals. Also SignedInfiniteCardinal if you need negative ones.
  5. InfiniteTime <: TimeType for infinite times (i.e. means "infinitely far in the future"), represented by a SignedInfinity. Also maybe UInfiniteTime for the unsigned version. Construct like Time(∞) or something.
  6. All the InfExtended* stuff.
dlfivefifty commented 4 years ago

Yes I like this

cjdoris commented 4 years ago

@fchorney @omus FYI the plan is to move this package over to https://github.com/JuliaMath/Infinities.jl. It is being renamed to Infinities, what is currently Infinite will be renamed to SignedInfinity, we'll be adding a singleton ∞=Infinity() and some other purely-infinite types. All the InfExtended* stuff will remain as-is. See my previous comment here for details.

Let me know if you have any more PRs soon. If not, I'll release a version and that will be the last one on this repo. Then we'll copy the repo to its new home, make the planned changes, and register it.

@dlfivefifty Sounds reasonable?

dlfivefifty commented 4 years ago

I'll copy over my code now with the new naming scheme.