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

Interop with SymbolicUtils #64

Merged
merged 35 commits into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
c2d64b5
symbolicutils interop
olynch Aug 14, 2024
c11d4dd
added spaces to the sorts of forms and vector fields
olynch Aug 16, 2024
7de10e8
integrated changes to ThDEC with DecaSymbolic
olynch Aug 17, 2024
5928cc7
added tests for decasymbolic, but needs wrinkles ironed out. musical …
quffaro Aug 18, 2024
d7d6a5b
reverted src/DiagX to restore exports and adding Project.toml
quffaro Aug 19, 2024
2f79b0c
Merge remote-tracking branch 'origin/space-sorts' into symbolicutilsi…
quffaro Aug 19, 2024
a438192
updated code and tests after merge from space-sorts
quffaro Aug 19, 2024
18a1585
review changes:
jpfairbanks Aug 21, 2024
090ddfe
resolving some comments from code review.
quffaro Aug 22, 2024
d8be4ae
adding @alias and @register macros to make DecaSymbolic function work…
quffaro Aug 27, 2024
77770e5
experimenting with a type-driven approach
quffaro Aug 28, 2024
1fa477b
adding promote_symtype and addressing some of the code review comment…
quffaro Aug 30, 2024
3b265ac
refactoring @operator to integrate with promote_symtype
quffaro Sep 4, 2024
7f8597a
operator macro parses @rule but need to write tests and iron out rela…
quffaro Sep 5, 2024
154e51f
rewriting just needs tests
quffaro Sep 6, 2024
18bb71f
TST: add some klausmeier rewrites
jpfairbanks Sep 9, 2024
4ba6dce
BUG: fix method shadowing for existing operators like +/-
jpfairbanks Sep 9, 2024
82f65ce
added more tests, @operator macro is more flexible
quffaro Sep 10, 2024
e23459f
Merge pull request #73 from AlgebraicJulia/jpf/symbolictypes
quffaro Sep 10, 2024
e82e826
almost round-tripping in klausmeier. equations are not currently pass…
quffaro Sep 10, 2024
f32b3c0
Merge branch 'cm/symbolictypes' of github.com:AlgebraicJulia/Diagramm…
quffaro Sep 10, 2024
ecfa931
added rules function which dispatches on function symbol and the Val(…
quffaro Sep 10, 2024
4603ed9
fixed docs for @operator, fixed Term
quffaro Sep 11, 2024
f2ef1d0
Merge pull request #71 from AlgebraicJulia/cm/symbolictypes
quffaro Sep 11, 2024
5324de3
Loosened aqua tests
GeorgeR227 Sep 12, 2024
0a314a8
fixing bug where (+) always returns Scalar
quffaro Sep 18, 2024
5d5c25d
Expression level rewriting (#69)
GeorgeR227 Oct 3, 2024
70a420d
added tests for errors and consolidated errors with George
quffaro Oct 3, 2024
85572a4
Fixed hodge nameof and more tests
GeorgeR227 Oct 4, 2024
df41b18
Many more tests
GeorgeR227 Oct 4, 2024
6d1edf0
Merge branch 'main' into symbolicutilsinterop
jpfairbanks Oct 4, 2024
ccf0a79
More tests
GeorgeR227 Oct 5, 2024
467a93c
Remove unused functions
GeorgeR227 Oct 9, 2024
7c5155d
Fixed test in acset2symbolics
GeorgeR227 Oct 9, 2024
4f1f327
Added some improvements to naming
GeorgeR227 Oct 10, 2024
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
6 changes: 6 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,18 @@ ACSets = "227ef7b5-1206-438b-ac65-934d6da304b8"
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"

[compat]
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"
julia = "1.6"
8 changes: 7 additions & 1 deletion src/DiagrammaticEquations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,13 @@ using Catlab.Theories
import Catlab.Theories: otimes, oplus, compose, ⊗, ⊕, ⋅, associate, associate_unit, Ob, Hom, dom, codom
using Catlab.Programs
using Catlab.CategoricalAlgebra
import Catlab.CategoricalAlgebra: ∧
using Catlab.WiringDiagrams
using Catlab.WiringDiagrams.DirectedWiringDiagrams
using Catlab.ACSetInterface
using MLStyle
import Unicode
using Reexport

## TODO:
## generate schema from a _theory_
Expand All @@ -61,7 +63,11 @@ include("colanguage.jl")
include("openoperators.jl")
include("deca/Deca.jl")
include("learn/Learn.jl")
include("ThDEC.jl")
include("decasymbolic.jl")

using .Deca
@reexport using .ThDEC
@reexport using .SymbolicUtilsInterop
@reexport using .Deca

end
326 changes: 326 additions & 0 deletions src/ThDEC.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,326 @@
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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add a default constructor that just takes the default name.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Realized this needs to be default name and dimension

export SpaceLookup

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

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()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

name could also be a Parameter or a Literal. Parameters are "constants" that have values that depend on time so in the solver the t variable has to get threaded to them.

end
end

Base.nameof(s::Scalar) = :Constant

function Base.nameof(f::Form; with_dim_parameter=false)
dual = isdual(f) ? "Dual" : ""
formname = Symbol("$(dual)Form$(dim(f))")
if with_dim_parameter
return Expr(:curly, formname, dim(space(f)))
else
return formname
end
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, space::Space) = Form(i, false, space)
export PrimalForm

DualForm(i::Int, space::Space) = Form(i, true, space)
export DualForm

PrimalVF(space::Space) = VF(false, space)
export PrimalVF

DualVF(space::Space) = VF(true, space)
export DualVF

# show methods
show_duality(ω::Form) = isdual(ω) ? "dual" : "primal"

function Base.show(io::IO, ω::Form)
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, 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(
"""
Can not add two forms of different dimensions/dualities/spaces:
$((i1,isdual1,space1)) and $((i2,isdual2,space2))
""")
)
end
end
end

# Type-checking inverse of addition follows addition
-(s1::Sort, s2::Sort) = +(s1, s2)

# TODO error for Forms

# 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, 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

const SUBSCRIPT_DIGIT_0 = '₀'

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, 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(space1)
Form(i1 + i2, isdual1, space1)
else
throw(SortError("Can only take a wedge product when the dimensions of the forms add to less than n, where n = $(dim(space1)) is the dimension of the ambient space: tried to wedge product $i1 and $i2"))
end
end
end
end

function Base.nameof(::typeof(∧), s1, s2)
Symbol("∧$(as_sub(dim(s1)))$(as_sub(dim(s2)))")
end

@nospecialize
∂ₜ(s::Sort) = s

@nospecialize
function d(s::Sort)
@match s begin
Scalar() => throw(SortError("Cannot take exterior derivative of a scalar"))
Form(i, isdual, space) =>
if i < dim(space)
Form(i + 1, isdual, space)
else
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

function Base.nameof(::typeof(d), s)
Symbol("d$(as_sub(dim(s)))")
end

@nospecialize
function ★(s::Sort)
@match s begin
Scalar() => throw(SortError("Cannot take Hodge star of a scalar"))
VF(isdual, space) => 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) ? dim(space(s)) - dim(s) : dim(s)))$(inv)")
end

@nospecialize
function ι(s1::Sort, s2::Sort)
@match (s1, s2) begin
(VF(true, space), Form(i, true, space)) => Form(i, false, space) # wrong
(VF(true, space), Form(i, false, space)) => DualForm(i, true, space)
_ => throw(SortError("Can only define the discrete interior product on:
PrimalVF, DualForm(i)
DualVF(), PrimalForm(i)
."))
end
end

# in practice, a scalar may be treated as a constant 0-form.
function ♯(s::Sort)
@match s begin
Scalar() => PrimalVF()
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.

# TODO
function Base.nameof(::typeof(♯), s)
Symbol("♯s")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should there be a $ before s here?

end


function ♭(s::Sort)
@match s begin
VF(true, space) => Form(1, false, space)
_ => throw(SortError("Can only apply ♭ to dual vector fields"))
end
end

# TODO
function Base.nameof(::typeof(♭), s)
Symbol("♭s")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should there be a $ before s here?

end

# OTHER

function ♭♯(s::Sort)
@match s begin
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, space) => Form(0, isdual, space)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a 1-laplacian for 1 forms. And lapl of a scalar should be the scalar 0.

_ => throw(SortError("Δ is not defined for $s"))
end
end

const OPERATOR_LOOKUP = Dict(
:⋆₀ => ★,
:⋆₁ => ★,
:⋆₂ => ★,

# Inverse Hodge Stars
:⋆₀⁻¹ => ★,
:⋆₁⁻¹ => ★,
:⋆₂⁻¹ => ★,

# Differentials
:d₀ => d,
:d₁ => d,

# Dual Differentials
:dual_d₀ => d,
:d̃₀ => d,
:dual_d₁ => d,
:d̃₁ => d,

# Wedge Products
:∧₀₁ => ∧,
:∧₁₀ => ∧,
:∧₀₂ => ∧,
:∧₂₀ => ∧,
:∧₁₁ => ∧,

# Primal-Dual Wedge Products
:∧ᵖᵈ₁₁ => ∧,
:∧ᵖᵈ₀₁ => ∧,
:∧ᵈᵖ₁₁ => ∧,
:∧ᵈᵖ₁₀ => ∧,

# Dual-Dual Wedge Products
:∧ᵈᵈ₁₁ => ∧,
:∧ᵈᵈ₁₀ => ∧,
:∧ᵈᵈ₀₁ => ∧,

# Dual-Dual Interior Products
:ι₁₁ => ι,
:ι₁₂ => ι,

# Dual-Dual Lie Derivatives
# :ℒ₁ => ℒ,

# Dual Laplacians
# :Δᵈ₀ => Δ,
# :Δᵈ₁ => Δ,

# Musical Isomorphisms
:♯ => ♯,
:♯ᵈ => ♯, :♭ => ♭,

# Averaging Operator
# :avg₀₁ => avg,

# Negatives
:neg => -,

# Basics

:- => -,
:+ => +,
:* => *,
:/ => /,
:.- => .-,
:.+ => .+,
:.* => .*,
:./ => ./,
)

end
Loading
Loading