Usage

A semiring over a set $S$ is an algebraic structure $(S, \oplus, \otimes, \bar{0}, \bar{1})$ where $\oplus$ and $\otimes$ are two binary operators called "addition" and "multiplication" and $\bar{0}$ and $\bar{1}$ are their respective neutral element.

Simple example

Load the module

using Semirings

The usual workflow when is to first declare a semiring type and then perform a computation

S = LogSemiring{Float64,1}
(S(-2.3) + one(S)) * S(-1)

# output
LogSemiring{Float64, 1}(-0.904454535402037)

The neutral elements $\bar{0}$ and $\bar{1}$ can be instantiated with the zero and one functions respectively:

S = BoolSemiring
isone(one(S) + one(S)), iszero(zero(S) * one(S))

# output
(true, true)

Input / Output

Semirings can written and read from binary stream

S = TropicalSemiring{Float32}
io = IOBuffer()
write(io, S(2.4))
read(seekstart(io), S)

# output
TropicalSemiring{Float32}(2.4f0, 1)

It is also possible to create semiring S<:Semiring{T} from a textual representation with parse:

S = TropicalSemiring{Float32}
parse(S, "0.123")

# output
TropicalSemiring{Float32}(0.123f0, 1)
Warning

This will work only if the type T wrapped by semiring type S can be created from parse.

Automatic Differentiation

Computation over sermiings should be differentiable (for semiring over numeric values) with reverse-mode differentiation backend relying upon ChainRulesCore.jl. Here is an example with Zygote.

using Semirings
using Zygote

S = LogSemiring{Float32,2}
gradient(S(1), S(2), S(3)) do x, y , z
   val(z * (x + y))
end

# output
(SemiringTangent{Float64}(0.11920294090533493), SemiringTangent{Float64}(0.8807972175070349), SemiringTangent{Float32}(1.0f0))
Info

Importantly, the function that needs to be differentiated should return the value of the semiring (not the semiring itself). Hence, your function should end with a call to val(...).