Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More semi-ring algebras #9

Merged
merged 6 commits into from
Sep 24, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,27 @@ Tropical number algebra, still under development.
pkg> add TropicalNumbers
```

## Semiring and Tropical Algebras

A [`Semiring`](https://en.wikipedia.org/wiki/Semiring) is a set R equipped with two binary operations + and ⋅, called addition and multiplication, such that:

* (R, +) is a monoid with identity element called 0;
* (R, ⋅) is a monoid with identity element called 1;
* Addition is commutative;
* Multiplication by the additive identity 0 annihilates ;
* Multiplication left- and right-distributes over addition;
* Explicitly stated, (R, +) is a commutative monoid.

[`Tropical number`](https://en.wikipedia.org/wiki/Tropical_geometry) are a set of semiring algebras, described as
* (R, +, ⋅, 0, 1).
where R is the set, + and ⋅ are the opeartions and 0, 1 are their identity element, respectively.

In this package, the following tropical algebras are implemented:
* TropicalAndOr, ([T, F], or, and, false, true);
* Tropical (TropicalMaxPlus), (ℝ, max, +, -Inf, 0);
* TropicalMinPlus, (ℝ, min, +, Inf, 0);
* TropicalMaxMul, (ℝ⁺, max, ⋅, 0, 1).

## Why another tropical number?

Related packages includes
Expand All @@ -23,4 +44,4 @@ Tropical numbers in these packages contains an extra field `isinf`. Which is not
Most importantly, we are going to release a BLAS package for tropical numbers, which is two orders faster than naive Julia loops. If a tropical number is defined as a composite data structure, it is hard to utilize SIMD.

## Ecosystem
* [TropicalGEMM](https://github.com/TensorBFS/TropicalGEMM.jl), Tropical matrix multiplication with close to optimal speed.
* [TropicalGEMM](https://github.com/TensorBFS/TropicalGEMM.jl), Tropical matrix multiplication with close to optimal speed.
71 changes: 63 additions & 8 deletions src/TropicalNumbers.jl
Original file line number Diff line number Diff line change
@@ -1,24 +1,63 @@
module TropicalNumbers

export Tropical, TropicalF64, TropicalF32, TropicalF16, CountingTropicalF16, CountingTropicalF32, CountingTropicalF64, content
export CountingTropical
export TropicalTypes
export content, neginf, posinf
export TropicalTypes, AbstractSemiring

export TropicalAndOr
export Tropical, TropicalF64, TropicalF32, TropicalF16
export TropicalMaxMul, TropicalMaxMulF64, TropicalMaxMulF32, TropicalMaxMulF16
export TropicalMaxPlus, TropicalMaxPlusF64, TropicalMaxPlusF32, TropicalMaxPlusF16
export TropicalMinPlus, TropicalMinPlusF64, TropicalMinPlusF32, TropicalMinPlusF16
export CountingTropical, CountingTropicalF16, CountingTropicalF32, CountingTropicalF64

include("tropical.jl")

"""
AbstractSemiring <: Number

A [`Semiring`](https://en.wikipedia.org/wiki/Semiring) is a set R equipped with two binary operations + and ⋅, called addition and multiplication, such that:

* (R, +) is a monoid with identity element called 0;
* (R, ⋅) is a monoid with identity element called 1;
* Addition is commutative;
* Multiplication by the additive identity 0 annihilates ;
* Multiplication left- and right-distributes over addition;
* Explicitly stated, (R, +) is a commutative monoid.

[`Tropical number`](https://en.wikipedia.org/wiki/Tropical_geometry) are a set of semiring algebras, described as
* (R, +, ⋅, 0, 1).
where R is the set, + and ⋅ are the opeartions and 0, 1 are their identity element, respectively.

In this package, the following tropical algebras are implemented:
* TropicalAndOr, ([T, F], or, and, false, true);
* Tropical (TropicalMaxPlus), (ℝ, max, +, -Inf, 0);
* TropicalMinPlus, (ℝ, min, +, Inf, 0);
* TropicalMaxMul, (ℝ⁺, max, ⋅, 0, 1).

We implemented fast tropical matrix multiplication in [`TropicalGEMM`](https://github.com/TensorBFS/TropicalGEMM.jl/) and [`CuTropicalGEMM`](https://github.com/ArrogantGao/CuTropicalGEMM.jl/).
"""
abstract type AbstractSemiring <: Number end

include("tropical_maxplus.jl")
include("tropical_andor.jl")
include("tropical_minplus.jl")
include("tropical_maxmul.jl")
include("counting_tropical.jl")

const TropicalTypes{T} = Union{CountingTropical{T}, Tropical{T}}
const TropicalMaxPlus = Tropical

# alias
# defining constants like `TropicalF64`.
for NBIT in [16, 32, 64]
@eval const $(Symbol(:Tropical, :F, NBIT)) = Tropical{$(Symbol(:Float, NBIT))}
@eval const $(Symbol(:TropicalMaxPlus, :F, NBIT)) = TropicalMaxPlus{$(Symbol(:Float, NBIT))}
@eval const $(Symbol(:TropicalMinPlus, :F, NBIT)) = TropicalMinPlus{$(Symbol(:Float, NBIT))}
@eval const $(Symbol(:TropicalMaxMul, :F, NBIT)) = TropicalMaxMul{$(Symbol(:Float, NBIT))}
@eval const $(Symbol(:CountingTropical, :F, NBIT)) = CountingTropical{$(Symbol(:Float, NBIT)),$(Symbol(:Float, NBIT))}
end

# alias
for T in [:Tropical, :CountingTropical]
# defining constants like `TropicalF64`.
for T in [:Tropical, :TropicalMaxMul, :TropicalMinPlus, :CountingTropical]
for OP in [:>, :<, :(==), :>=, :<=, :isless]
@eval Base.$OP(a::$T, b::$T) = $OP(a.n, b.n)
end
Expand All @@ -28,14 +67,30 @@ for T in [:Tropical, :CountingTropical]
Base.isapprox(x::AbstractArray{<:$T}, y::AbstractArray{<:$T}; kwargs...) = all(isapprox.(x, y; kwargs...))
Base.show(io::IO, ::MIME"text/plain", t::$T) = Base.show(io, t)
Base.isnan(x::$T) = isnan(content(x))
end
end

for T in [:TropicalAndOr]
for OP in [:>, :<, :(==), :>=, :<=, :isless]
@eval Base.$OP(a::$T, b::$T) = $OP(a.n, b.n)
end
@eval begin
content(x::$T) = x.n
Base.isapprox(x::AbstractArray{<:$T}, y::AbstractArray{<:$T}; kwargs...) = all(isapprox.(x, y; kwargs...))
Base.show(io::IO, ::MIME"text/plain", t::$T) = Base.show(io, t)
Base.isnan(x::$T) = isnan(content(x))
end
end

for T in [:Tropical, :TropicalMaxMul, :TropicalMinPlus, :CountingTropical]
@eval begin
# this is for CUDA matmul
Base.:(*)(a::$T, b::Bool) = b ? a : zero(a)
Base.:(*)(b::Bool, a::$T) = b ? a : zero(a)
Base.:(/)(a::$T, b::Bool) = b ? a : a / zero(a)
Base.:(/)(b::Bool, a::$T) = b ? inv(a) : zero(a)
Base.div(a::$T, b::Bool) = b ? a : a / zero(a)
Base.div(b::Bool, a::$T) = b ? inv(a) : zero(a)
Base.div(a::$T, b::Bool) = b ? a : a ÷ zero(a)
Base.div(b::Bool, a::$T) = b ? one(a) ÷ a : zero(a)
end
end

Expand Down
53 changes: 53 additions & 0 deletions src/tropical_andor.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@


"""
TropicalAndOr <: Number

TropicalAndOr is a semiring algebra, can be described by
* TropicalAndOr, ([T, F], or, and, false, true).

It maps
* `+` to `or` in regular algebra,
* `*` to `and` in regular algebra,
* `1` to `true` in regular algebra,
* `0` to `false` in regular algebra.

Example
-------------------------
```jldoctest; setup=:(using TropicalNumbers)
julia> TropicalAndOr(true) + TropicalAndOr(false)
trueₜ

julia> TropicalAndOr(true) * TropicalAndOr(false)
falseₜ

julia> one(TropicalAndOr)
trueₜ

GiggleLiu marked this conversation as resolved.
Show resolved Hide resolved
julia> zero(TropicalAndOr)
falseₜ
```
"""
struct TropicalAndOr <: AbstractSemiring
n::Bool
TropicalAndOr(x::T) where T <: Bool = new(x)
end

Base.show(io::IO, t::TropicalAndOr) = Base.print(io, "$(t.n)ₜ")

Base.:*(a::TropicalAndOr, b::TropicalAndOr) = TropicalAndOr(a.n && b.n)

Base.:+(a::TropicalAndOr, b::TropicalAndOr) = TropicalAndOr(a.n || b.n)

Base.typemin(::Type{TropicalAndOr}) = TropicalAndOr(false)
Base.zero(::Type{TropicalAndOr}) = typemin(TropicalAndOr)
Base.zero(::TropicalAndOr) = zero(TropicalAndOr)

Base.one(::Type{TropicalAndOr}) = TropicalAndOr(true)
Base.one(::TropicalAndOr) = one(TropicalAndOr)

# inverse and division
Base.inv(x::TropicalAndOr) = TropicalAndOr(!x.n)

# bool type only have two values
Base.isapprox(x::TropicalAndOr, y::TropicalAndOr; kwargs...) = ispprox(x.n, y.n; kwargs...)
74 changes: 74 additions & 0 deletions src/tropical_maxmul.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@


"""
TropicalMaxMul{T} <: AbstractSemiring

TropicalMaxMul is a semiring algebra, can be described by
* TropicalMaxMul, (ℝ⁺, max, ⋅, 0, 1).

It maps
* `+` to `max` in regular algebra,
* `*` to `*` in regular algebra,
* `1` to `1` in regular algebra,
* `0` to `0` in regular algebra.

Example
-------------------------
```jldoctest; setup=:(using TropicalNumbers)
julia> TropicalMaxMul(1.0) + TropicalMaxMul(3.0)
3.0ₓ

julia> TropicalMaxMul(1.0) * TropicalMaxMul(3.0)
3.0ₓ

julia> one(TropicalMaxMulF64)
1.0ₓ

GiggleLiu marked this conversation as resolved.
Show resolved Hide resolved
julia> zero(TropicalMaxMulF64)
0.0ₓ
```
"""
struct TropicalMaxMul{T} <: AbstractSemiring
n::T
function TropicalMaxMul{T}(x) where T
@assert x >= 0 || isnan(x)
new{T}(T(x))
end
function TropicalMaxMul(x::T) where T
@assert x >= 0 || isnan(x)
new{T}(x)
end
function TropicalMaxMul{T}(x::TropicalMaxMul{T}) where T
@assert x.n >= 0 || isnan(x)
x
end
function TropicalMaxMul{T1}(x::TropicalMaxMul{T2}) where {T1,T2}
@assert x.n >= 0 || isnan(x)
new{T1}(T2(x.n))
end
end

Base.show(io::IO, t::TropicalMaxMul) = Base.print(io, "$(t.n)ₓ")

Base.:^(a::TropicalMaxMul, b::Real) = TropicalMaxMul(a.n ^ b)
Base.:^(a::TropicalMaxMul, b::Integer) = TropicalMaxMul(a.n ^ b)
Base.:*(a::TropicalMaxMul, b::TropicalMaxMul) = TropicalMaxMul(a.n * b.n)

Base.:+(a::TropicalMaxMul, b::TropicalMaxMul) = TropicalMaxMul(max(a.n, b.n))
Base.typemin(::Type{TropicalMaxMul{T}}) where T = TropicalMaxMul(zero(T))
Base.typemax(::Type{TropicalMaxMul{T}}) where T = TropicalMaxMul(posinf(T))
Base.zero(::Type{TropicalMaxMul{T}}) where T = TropicalMaxMul(zero(T))
Base.zero(::TropicalMaxMul{T}) where T = zero(TropicalMaxMul{T})

Base.one(::Type{TropicalMaxMul{T}}) where T = TropicalMaxMul(one(T))
Base.one(::TropicalMaxMul{T}) where T = one(TropicalMaxMul{T})

# inverse and division
Base.inv(x::TropicalMaxMul{T}) where T = TropicalMaxMul(one(T) / x.n)
Base.:/(x::TropicalMaxMul, y::TropicalMaxMul) = TropicalMaxMul(x.n / y.n)
Base.div(x::TropicalMaxMul, y::TropicalMaxMul) = TropicalMaxMul(x.n ÷ y.n)

Base.isapprox(x::TropicalMaxMul, y::TropicalMaxMul; kwargs...) = isapprox(x.n, y.n; kwargs...)

# promotion rules
Base.promote_type(::Type{TropicalMaxMul{T1}}, b::Type{TropicalMaxMul{T2}}) where {T1, T2} = TropicalMaxMul{promote_type(T1,T2)}
27 changes: 14 additions & 13 deletions src/tropical.jl → src/tropical_maxplus.jl
Original file line number Diff line number Diff line change
@@ -1,41 +1,41 @@
export Tropical, TropicalF64, TropicalF32, TropicalF16, content

# define the neginf and posinf
neginf(::Type{T}) where T = typemin(T)
neginf(::Type{T}) where T<:AbstractFloat = typemin(T)
neginf(::Type{T}) where T<:Rational = typemin(T)
neginf(::Type{T}) where T<:Integer = T(-999999)
neginf(::Type{Int16}) = Int16(-16384)
neginf(::Type{Int8}) = Int8(-64)
posinf(::Type{T}) where T = - neginf(T)

"""
Tropical{T} <: Number

[Tropical number](https://en.wikipedia.org/wiki/Tropical_geometry) is a semiring algebra that maps
TropicalMaxPlus{T} = Tropical{T} <: AbstractSemiring

TropicalMaxPlus is a semiring algebra, can be described by
* Tropical (TropicalMaxPlus), (ℝ, max, +, -Inf, 0).

It maps
* `+` to `max` in regular algebra,
* `*` to `+` in regular algebra,
* `1` to `0` in regular algebra,
* `0` to `-Inf` in regular algebra (for integer content types, this is chosen as a mall integer).

We implemented fast tropical matrix multiplication in [`TropicalGEMM`](https://github.com/TensorBFS/TropicalGEMM.jl/).
* `0` to `-Inf` in regular algebra (for integer content types, this is chosen as a small integer).

Example
-------------------------
```jldoctest; setup=:(using TropicalNumbers)
julia> Tropical(1.0) + Tropical(3.0)
julia> TropicalMaxPlus(1.0) + TropicalMaxPlus(3.0)
3.0ₜ

julia> Tropical(1.0) * Tropical(3.0)
julia> TropicalMaxPlus(1.0) * TropicalMaxPlus(3.0)
4.0ₜ

julia> one(TropicalF64)
julia> one(TropicalMaxPlusF64)
0.0ₜ

julia> zero(TropicalF64)
julia> zero(TropicalMaxPlusF64)
-Infₜ
```
"""
struct Tropical{T} <: Number
struct Tropical{T} <: AbstractSemiring
n::T
Tropical{T}(x) where T = new{T}(T(x))
function Tropical(x::T) where T
Expand All @@ -49,6 +49,7 @@ struct Tropical{T} <: Number
end
end


Base.show(io::IO, t::Tropical) = Base.print(io, "$(t.n)ₜ")

Base.:^(a::Tropical, b::Real) = Tropical(a.n * b)
Expand Down
Loading