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

Add "space" to the sort of forms/vfields #65

Merged
merged 2 commits into from
Aug 19, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ ACSets = "227ef7b5-1206-438b-ac65-934d6da304b8"
Catlab = "134e5e36-593f-5add-ad60-77f754baafbe"
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
MLStyle = "d8e11817-5142-5d16-987a-aa16d5891078"
StructEquality = "6ec83bb0-ed9f-11e9-3b4c-2b04cb4e219c"
SymbolicUtils = "d1185830-fcd6-423d-90d6-eec64667417b"
Unicode = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"

Expand All @@ -17,6 +18,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"
julia = "1.6"
118 changes: 79 additions & 39 deletions src/ThDEC.jl
Original file line number Diff line number Diff line change
@@ -1,44 +1,73 @@
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 @@ -57,20 +86,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 @@ -83,13 +118,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 @@ -99,17 +136,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 @@ -124,11 +164,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 @@ -141,20 +181,20 @@ end
function ★(s::Sort)
@match s begin
Scalar() => throw(SortError("Cannot take Hodge star of a scalar"))
Form(i, isdual) => Form(2 - i, !isdual)
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 @@ -166,15 +206,15 @@ 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
# musical isos may be defined for any combination of (primal/dual) form -> (primal/dual) vf.

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 @@ -183,15 +223,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
28 changes: 16 additions & 12 deletions src/decasymbolic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,43 +12,47 @@ 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
struct FormT{i,d,s,n} <: DECType
end
export FormT

struct VFieldT{d} <: DECType
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

function Sort(::Type{FormT{i,d}}) where {i,d}
Form(i, d)
function Sort(::Type{FormT{i,d,s,n}}) where {i,d,s,n}
Form(i, d, Space(s, n))
end

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

function 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

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

function Sort(::Type{<:Real})
Expand Down
Loading