Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/space-sorts' into symbolicutilsi…
Browse files Browse the repository at this point in the history
…nterop
  • Loading branch information
quffaro committed Aug 19, 2024
2 parents d7d6a5b + 7de10e8 commit 2f79b0c
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 58 deletions.
2 changes: 2 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Catlab = "134e5e36-593f-5add-ad60-77f754baafbe"
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
MLStyle = "d8e11817-5142-5d16-987a-aa16d5891078"
Reexport = "189a3867-3050-52da-a836-e630ba90ab69"
StructEquality = "6ec83bb0-ed9f-11e9-3b4c-2b04cb4e219c"
SymbolicUtils = "d1185830-fcd6-423d-90d6-eec64667417b"
Unicode = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"

Expand All @@ -18,6 +19,7 @@ ACSets = "0.2"
Catlab = "0.15, 0.16"
DataStructures = "0.18.13"
MLStyle = "0.4.17"
StructEquality = "2.1.0"
SymbolicUtils = "3.1.2"
Unicode = "1.6"
Reexport = "1.2.2"
Expand Down
118 changes: 79 additions & 39 deletions src/ThDEC.jl
Original file line number Diff line number Diff line change
@@ -1,45 +1,74 @@
module ThDEC

using MLStyle
using StructEquality

import Base: +, -, *

struct SortError <: Exception
message::String
end

@struct_hash_equal struct Space
name::Symbol
dim::Int
end
export Space

dim(s::Space) = s.dim
Base.nameof(s::Space) = s.name

struct SpaceLookup
default::Space
named::Dict{Symbol,Space}
end

@data Sort begin
Scalar()
Form(dim::Int, isdual::Bool)
VField(isdual::Bool)
Form(dim::Int, isdual::Bool, space::Space)
VField(isdual::Bool, space::Space)
end
export Sort, Scalar, Form, VField

const SORT_LOOKUP = Dict(
:Form0 => Form(0, false),
:Form1 => Form(1, false),
:Form2 => Form(2, false),
:DualForm0 => Form(0, true),
:DualForm1 => Form(1, true),
:DualForm2 => Form(2, true),
:Constant => Scalar()
)
function fromexpr(lookup::SpaceLookup, e, ::Type{Sort})
(name, spacename) = @match e begin
name::Symbol => (name, nothing)
:($name{$spacename}) => (name, spacename)
end
space = @match spacename begin
::Nothing => lookup.default
name::Symbol => lookup.named[name]
end
@match name begin
:Form0 => Form(0, false, space)
:Form1 => Form(1, false, space)
:Form2 => Form(2, false, space)
:DualForm0 => Form(0, true, space)
:DualForm1 => Form(1, true, space)
:DualForm2 => Form(2, true, space)
:Constant => Scalar()
end
end

function Base.nameof(s::Scalar)
:Constant
end

function Base.nameof(f::Form)
dual = isdual(f) ? "Dual" : ""
Symbol("$(dual)Form$(dim(f))")
formname = Symbol("$(dual)Form$(dim(f))")
Expr(:curly, formname, dim(space(f)))
end

const VF = VField

dim::Form) = ω.dim
isdual::Form) = ω.isdual
space::Form) = ω.space
export space

isdual(v::VField) = v.isdual
space(v::VField) = v.space

# convenience functions
PrimalForm(i::Int) = Form(i, false)
Expand All @@ -58,20 +87,26 @@ export DualVF
show_duality::Form) = isdual(ω) ? "dual" : "primal"

function Base.show(io::IO, ω::Form)
print(io, isdual(ω) ? "DualForm($(dim(ω)))" : "PrimalForm($(dim(ω)))")
print(io, isdual(ω) ? "DualForm($(dim(ω))) on $(space(ω))" : "PrimalForm($(dim(ω))) on $(space))")
end

# TODO: VField
@nospecialize
function +(s1::Sort, s2::Sort)
@match (s1, s2) begin
(Scalar(), Scalar()) => Scalar()
(Scalar(), Form(i, isdual)) ||
(Form(i, isdual), Scalar()) => Form(i, isdual)
(Form(i1, isdual1), Form(i2, isdual2)) =>
if (i1 == i2) && (isdual1 == isdual2)
(Scalar(), Form(i, isdual, space)) ||
(Form(i, isdual, space), Scalar()) => Form(i, isdual, space)
(Form(i1, isdual1, space1), Form(i2, isdual2, space2)) =>
if (i1 == i2) && (isdual1 == isdual2) && (space1 == space2)
Form(i1, isdual1)
else
throw(SortError("Cannot add two forms of different dimensions/dualities: $((i1,isdual1)) and $((i2,isdual2))"))
throw(SortError(
"""
Can not add two forms of different dimensions/dualities/spaces:
$((i1,isdual1,space1)) and $((i2,isdual2,space2))
""")
)
end
end
end
Expand All @@ -84,13 +119,15 @@ end
# Negation is always valid
-(s::Sort) = s

# TODO: VField
@nospecialize
function *(s1::Sort, s2::Sort)
@match (s1, s2) begin
(Scalar(), Scalar()) => Scalar()
(Scalar(), Form(i, isdual)) ||
(Form(i, isdual), Scalar()) => Form(i, isdual)
(Form(_, _), Form(_, _)) => throw(SortError("Cannot scalar multiply a form with a form. Maybe try `∧`??"))
(Scalar(), Form(i, isdual, space)) ||
(Form(i, isdual, space), Scalar()) => Form(i, isdual)
(Form(_, _, _), Form(_, _, _)) =>
throw(SortError("Cannot scalar multiply a form with a form. Maybe try `∧`??"))
end
end

Expand All @@ -100,17 +137,20 @@ function as_sub(n::Int)
join(map(d -> SUBSCRIPT_DIGIT_0 + d, digits(n)))
end

# TODO: VField
@nospecialize
function (s1::Sort, s2::Sort)
@match (s1, s2) begin
(Form(i, isdual), Scalar()) || (Scalar(), Form(i, isdual)) => Form(i, isdual)
(Form(i1, isdual), Form(i2, isdual)) =>
if i1 + i2 <= 2
Form(i1 + i2, isdual)
(Form(i, isdual, space), Scalar()) || (Scalar(), Form(i, isdual, space)) =>
Form(i, isdual, space)
(Form(i1, isdual1, space1), Form(i2, isdual2, space2)) => begin
(isdual1 == isdual2) && (space1 == space2) || throw(SortError("Can only take a wedge product of two forms of the same duality on the same space"))
if i1 + i2 <= dim(space)
Form(i1 + i2, isdual, space)
else
throw(SortError("Can only take a wedge product when the dimensions of the forms add to less than 2: tried to wedge product $i1 and $i2"))
throw(SortError("Can only take a wedge product when the dimensions of the forms add to less than n, where n = $(dim(space)) is the dimension of the ambient space: tried to wedge product $i1 and $i2"))
end
_ => throw(SortError("Can only take a wedge product of two forms of the same duality"))
end
end
end

Expand All @@ -125,11 +165,11 @@ end
function d(s::Sort)
@match s begin
Scalar() => throw(SortError("Cannot take exterior derivative of a scalar"))
Form(i, isdual) =>
if i <= 1
Form(i + 1, isdual)
Form(i, isdual, space) =>
if i < dim(space)
Form(i + 1, isdual, space)
else
throw(SortError("Cannot take exterior derivative of a n-form for n >= 1"))
throw(SortError("Cannot take exterior derivative of a k-form for k >= n, where n = $(dim(space)) is the dimension of its ambient space"))
end
end
end
Expand All @@ -142,21 +182,21 @@ end
function (s::Sort)
@match s begin
Scalar() => throw(SortError("Cannot take Hodge star of a scalar"))
Form(i, isdual) => Form(2 - i, !isdual)
VF(isdual) => throw(SortError("Cannot take the Hodge star of a vector field"))
Form(i, isdual, space) => Form(dim(space) - i, !isdual, space)
end
end

function Base.nameof(::typeof(★), s)
inv = isdual(s) ? "⁻¹" : ""
Symbol("$(as_sub(isdual(s) ? 2 - dim(s) : dim(s)))$(inv)")
Symbol("$(as_sub(isdual(s) ? dim(space(s)) - dim(s) : dim(s)))$(inv)")
end

@nospecialize
function ι(s1::Sort, s2::Sort)
@match (s1, s2) begin
(VF(true), Form(i, true)) => PrimalForm() # wrong
(VF(true), Form(i, false)) => DualForm()
(VF(true, space), Form(i, true, space)) => PrimalForm() # wrong
(VF(true, space), Form(i, false, space)) => DualForm()
_ => throw(SortError("Can only define the discrete interior product on:
PrimalVF, DualForm(i)
DualVF(), PrimalForm(i)
Expand All @@ -168,7 +208,7 @@ end
function (s::Sort)
@match s begin
Scalar() => PrimalVF()
Form(1, isdual) => VF(isdual)
Form(1, isdual, space) => VF(isdual, space)
_ => throw(SortError("Can only take ♯ to 1-forms"))
end
end
Expand All @@ -182,7 +222,7 @@ end

function (s::Sort)
@match s begin
VF(true) => PrimalForm(1)
VF(true, space) => PrimalForm(1, false, space)
_ => throw(SortError("Can only apply ♭ to dual vector fields"))
end
end
Expand All @@ -196,15 +236,15 @@ end

function ♭♯(s::Sort)
@match s begin
Form(i, isdual) => Form(i, !isdual)
Form(i, isdual, space) => Form(i, !isdual, space)
_ => throw(SortError("♭♯ is only defined on forms."))
end
end

# Δ = ★d⋆d, but we check signature here to throw a more helpful error
function Δ(s::Sort)
@match s begin
Form(0, isdual) => Form(0, isdual)
Form(0, isdual, space) => Form(0, isdual, space)
_ => throw(SortError("Δ is not defined for $s"))
end
end
Expand Down
44 changes: 25 additions & 19 deletions src/decasymbolic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,50 +20,56 @@ abstract type DECType <: Number end
"""
i: dimension: 0,1,2, etc.
d: duality: true = dual, false = primal
s: name of the space (a symbol)
n: dimension of the space
"""
struct FormT{i,d} <: DECType end
struct FormT{i,d,s,n} <: DECType end
export FormT

struct VFieldT{d} <: DECType end
struct VFieldT{d,s,n} <: DECType end
export VFieldT

dim(::Type{<:FormT{d}}) where {d} = d
isdual(::Type{FormT{i,d}}) where {i,d} = d

# convenience functions
const PrimalFormT{i} = FormT{i,false}
const PrimalFormT{i,s,n} = FormT{i,false,s,n}
export PrimalFormT

const DualFormT{i} = FormT{i,true}
const DualFormT{i,s,n} = FormT{i,true,s,n}
export DualFormT

const PrimalVFT = VFieldT{false}
const PrimalVFT{s,n} = VFieldT{false,s,n}
export PrimalVFT

const DualVFT = VFieldT{true}
const DualVFT{s,n} = VFieldT{true,s,n}
export DualVFT

# convert Real to DecType
Sort(::Type{<:Real}) = Scalar()
# ##
#
# ##

# convert Real to ThDEC
Sort(::Type{<:Real}) = Scalar()
Sort(::Real) = Scalar()

# convert DECType to ThDEC
Sort(::Type{FormT{i,d}}) where {i,d} = Form(i, d)
# convert Real to DecType
function Sort(::Type{FormT{i,d,s,n}}) where {i,d,s,n}
Form(i, d, Space(s, n))
end

# convert DECType to ThDEC
Sort(::Type{VFieldT{d}}) where {d} = VField(d)
function Sort(::Type{VFieldT{d,s,n}}) where {d,s,n}
VField(d, Space(s, n))
end

Sort(::BasicSymbolic{T}) where {T} = Sort(T)

# convert Form to DECType
Number(f::Form) = FormT{dim(f), isdual(f)}

# convert VField to DECType
Number(v::VField) = VFieldT{isdual(v)}

# convert number to real
Number(s::Scalar) = Real

Number(f::Form) = FormT{dim(f),isdual(f), nameof(space(f)), dim(space(f))}

Number(v::VField) = VFieldT{isdual(v), nameof(space(v)), dim(space(v))}

# for every unary operator in our theory, take a BasicSymbolic type, convert its type parameter to a Sort in our theory, and return a term
unop_dec = [:∂ₜ, :d, :★, :♯, :♭, :-]
for unop in unop_dec
Expand Down

0 comments on commit 2f79b0c

Please sign in to comment.