Skip to content

Commit

Permalink
Merge pull request #142 from AlgebraicJulia/llm/ascii
Browse files Browse the repository at this point in the history
  • Loading branch information
lukem12345 authored Oct 8, 2023
2 parents abb94f8 + fc8c8f8 commit 53b23a5
Show file tree
Hide file tree
Showing 7 changed files with 245 additions and 34 deletions.
1 change: 1 addition & 0 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ makedocs(
"Decapodes.jl" => "index.md",
"Overview" => "overview.md",
"Equations" => "equations.md",
"ASCII Operators" => "ascii.md",
"Misc Features" => "bc_debug.md",
"Pipe Flow" => "poiseuille.md",
"Glacial Flow" => "ice_dynamics.md",
Expand Down
27 changes: 27 additions & 0 deletions docs/src/ascii.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# ASCII and Vector Calculus Operators

Some users may have trouble entering unicode characters like ⋆ or ∂ in their development environment. So, we offer the following ASCII equivalents. Further, some users may like to use vector calculus symbols instead of exterior calculus symbols where possible. We offer support for such symbols as well.

## ASCII Equivalents

| Unicode | ASCII | Meaning |
| ------- | ----- | ------- |
| ∂ₜ | dt | derivative w.r.t. time |
|| star | Hodge star, generalizing transpose |
| Δ | lapl | laplacian |
|| wedge | wedge product, generalizing the cross product |
| ⋆⁻¹ | star\_inv | Hodge star, generalizing transpose |
| ∘(⋆,d,⋆) | div | divergence, a.k.a. ∇⋅ |

## Vector Calculus Equivalents

| Vec | DEC | How to enter |
| -------- | ---------------- | -------------------------- |
| grad | d | grad |
| div | ∘(⋆,d,⋆) | div |
| curl | ∘(d,⋆) | curl |
|| d | \nabla |
| ∇ᵈ | ∘(⋆,d,⋆) | \nabla \<tab\> \\^d \<tab\> |
| ∇x | ∘(d,⋆) | \nabla \<tab\> x |
| adv(X,Y) | ∘(⋆,d,⋆)(X∧Y) | adv |

2 changes: 1 addition & 1 deletion docs/src/equations.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,4 @@ infer_types!(oscillator)
to_graphviz(oscillator)
```

Often you will have a linear material where you are scaling by a constant, and a nonlinear version of that material where that scaling is replaced by a generic nonlinear function. This is why we allow Decapodes to represent both of these types of equations.
Often you will have a linear material where you are scaling by a constant, and a nonlinear version of that material where that scaling is replaced by a generic nonlinear function. This is why we allow Decapodes to represent both of these types of equations.
2 changes: 1 addition & 1 deletion src/Decapodes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ using Base.Iterators

import Unicode

export normalize_unicode, DerivOp, append_dot,
export normalize_unicode, DerivOp, append_dot, unicode!, vec_to_dec!,
SchDecapode, SchNamedDecapode, AbstractDecapode, AbstractNamedDecapode, Decapode, NamedDecapode, SummationDecapode, fill_names!, dot_rename!, expand_operators, add_constant!, add_parameter, infer_types!, resolve_overloads!, op1_inf_rules_1D, op2_inf_rules_1D, op1_inf_rules_2D, op2_inf_rules_2D, op1_res_rules_1D, op2_res_rules_1D, op1_res_rules_2D, op2_res_rules_2D,
Term, Var, Judgement, Eq, AppCirc1, AppCirc2, App1, App2, Plus, Tan, term, parse_decapode,
VectorForm, PhysicsState, findname, findnode,
Expand Down
151 changes: 120 additions & 31 deletions src/decapodeacset.jl
Original file line number Diff line number Diff line change
Expand Up @@ -285,35 +285,35 @@ These are the default rules used to do type inference in the 1D exterior calculu
"""
op1_inf_rules_1D = [
# Rules for ∂ₜ
(src_type = :Form0, tgt_type = :Form0, op_names = [:∂ₜ]),
(src_type = :Form1, tgt_type = :Form1, op_names = [:∂ₜ]),
(src_type = :Form0, tgt_type = :Form0, op_names = [:∂ₜ,:dt]),
(src_type = :Form1, tgt_type = :Form1, op_names = [:∂ₜ,:dt]),

# Rules for d
(src_type = :Form0, tgt_type = :Form1, op_names = [:d, :d₀]),
(src_type = :DualForm0, tgt_type = :DualForm1, op_names = [:d, :dual_d₀, :d̃₀]),

# Rules for ⋆
(src_type = :Form0, tgt_type = :DualForm1, op_names = [:, :₀]),
(src_type = :Form1, tgt_type = :DualForm0, op_names = [:, :₁]),
(src_type = :DualForm1, tgt_type = :Form0, op_names = [:, :₀⁻¹]),
(src_type = :DualForm0, tgt_type = :Form1, op_names = [:, :₁⁻¹]),
(src_type = :Form0, tgt_type = :DualForm1, op_names = [:, :, :star]),
(src_type = :Form1, tgt_type = :DualForm0, op_names = [:, :, :star]),
(src_type = :DualForm1, tgt_type = :Form0, op_names = [:, :₀⁻¹, :star_inv]),
(src_type = :DualForm0, tgt_type = :Form1, op_names = [:, :₁⁻¹, :star_inv]),

# Rules for Δ
(src_type = :Form0, tgt_type = :Form0, op_names = [, :Δ₀]),
(src_type = :Form1, tgt_type = :Form1, op_names = [, :Δ₁]),
(src_type = :Form0, tgt_type = :Form0, op_names = [, :Δ₀, :lapl]),
(src_type = :Form1, tgt_type = :Form1, op_names = [, :Δ₁, :lapl]),

# Rules for δ
(src_type = :Form1, tgt_type = :Form0, op_names = [, :δ₁]),
(src_type = :Form1, tgt_type = :Form0, op_names = [, :δ₁, :codif]),

# Rules for negation
(src_type = :Form0, tgt_type = :Form0, op_names = [:neg, :(-)]),
(src_type = :Form1, tgt_type = :Form1, op_names = [:neg, :(-)])]

op2_inf_rules_1D = [
# Rules for ∧₀₀, ∧₁₀, ∧₀₁
(proj1_type = :Form0, proj2_type = :Form0, res_type = :Form0, op_names = [:, :₀₀]),
(proj1_type = :Form1, proj2_type = :Form0, res_type = :Form1, op_names = [:, :₁₀]),
(proj1_type = :Form0, proj2_type = :Form1, res_type = :Form1, op_names = [:, :₀₁]),
(proj1_type = :Form0, proj2_type = :Form0, res_type = :Form0, op_names = [:, :₀₀, :wedge]),
(proj1_type = :Form1, proj2_type = :Form0, res_type = :Form1, op_names = [:, :₁₀, :wedge]),
(proj1_type = :Form0, proj2_type = :Form1, res_type = :Form1, op_names = [:, :₀₁, :wedge]),

# Rules for L₀, L₁
(proj1_type = :Form1, proj2_type = :Form0, res_type = :Form0, op_names = [:L, :L₀]),
Expand Down Expand Up @@ -356,9 +356,9 @@ These are the default rules used to do type inference in the 2D exterior calculu
"""
op1_inf_rules_2D = [
# Rules for ∂ₜ
(src_type = :Form0, tgt_type = :Form0, op_names = [:∂ₜ]),
(src_type = :Form1, tgt_type = :Form1, op_names = [:∂ₜ]),
(src_type = :Form2, tgt_type = :Form2, op_names = [:∂ₜ]),
(src_type = :Form0, tgt_type = :Form0, op_names = [:∂ₜ, :dt]),
(src_type = :Form1, tgt_type = :Form1, op_names = [:∂ₜ, :dt]),
(src_type = :Form2, tgt_type = :Form2, op_names = [:∂ₜ, :dt]),

# Rules for d
(src_type = :Form0, tgt_type = :Form1, op_names = [:d, :d₀]),
Expand All @@ -367,22 +367,22 @@ op1_inf_rules_2D = [
(src_type = :DualForm1, tgt_type = :DualForm2, op_names = [:d, :dual_d₁, :d̃₁]),

# Rules for ⋆
(src_type = :Form0, tgt_type = :DualForm2, op_names = [:, :₀]),
(src_type = :Form1, tgt_type = :DualForm1, op_names = [:, :₁]),
(src_type = :Form2, tgt_type = :DualForm0, op_names = [:, :₂]),
(src_type = :Form0, tgt_type = :DualForm2, op_names = [:, :, :star]),
(src_type = :Form1, tgt_type = :DualForm1, op_names = [:, :, :star]),
(src_type = :Form2, tgt_type = :DualForm0, op_names = [:, :, :star]),

(src_type = :DualForm2, tgt_type = :Form0, op_names = [:, :₀⁻¹]),
(src_type = :DualForm1, tgt_type = :Form1, op_names = [:, :₁⁻¹]),
(src_type = :DualForm0, tgt_type = :Form2, op_names = [:, :₂⁻¹]),
(src_type = :DualForm2, tgt_type = :Form0, op_names = [:, :₀⁻¹, :star_inv]),
(src_type = :DualForm1, tgt_type = :Form1, op_names = [:, :₁⁻¹, :star_inv]),
(src_type = :DualForm0, tgt_type = :Form2, op_names = [:, :₂⁻¹, :star_inv]),

# Rules for Δ
(src_type = :Form0, tgt_type = :Form0, op_names = [, :Δ₀]),
(src_type = :Form1, tgt_type = :Form1, op_names = [, :Δ₁]),
(src_type = :Form2, tgt_type = :Form2, op_names = [, :Δ₂]),
(src_type = :Form0, tgt_type = :Form0, op_names = [, :Δ₀, :lapl]),
(src_type = :Form1, tgt_type = :Form1, op_names = [, :Δ₁, :lapl]),
(src_type = :Form2, tgt_type = :Form2, op_names = [, :Δ₂, :lapl]),

# Rules for δ
(src_type = :Form1, tgt_type = :Form0, op_names = [, :δ₁]),
(src_type = :Form2, tgt_type = :Form1, op_names = [, :δ₂]),
(src_type = :Form1, tgt_type = :Form0, op_names = [, :δ₁, :codif]),
(src_type = :Form2, tgt_type = :Form1, op_names = [, :δ₂, :codif]),

# Rules for negation
(src_type = :Form0, tgt_type = :Form0, op_names = [:neg, :(-)]),
Expand All @@ -391,9 +391,9 @@ op1_inf_rules_2D = [

op2_inf_rules_2D = vcat(op2_inf_rules_1D, [
# Rules for ∧₁₁, ∧₂₀, ∧₀₂
(proj1_type = :Form1, proj2_type = :Form1, res_type = :Form2, op_names = [:, :₁₁]),
(proj1_type = :Form2, proj2_type = :Form0, res_type = :Form2, op_names = [:, :₂₀]),
(proj1_type = :Form0, proj2_type = :Form2, res_type = :Form2, op_names = [:, :₀₂]),
(proj1_type = :Form1, proj2_type = :Form1, res_type = :Form2, op_names = [:, :₁₁, :wedge]),
(proj1_type = :Form2, proj2_type = :Form0, res_type = :Form2, op_names = [:, :₂₀, :wedge]),
(proj1_type = :Form0, proj2_type = :Form2, res_type = :Form2, op_names = [:, :₀₂, :wedge]),

(proj1_type = :Form1, proj2_type = :DualForm2, res_type = :DualForm2, op_names = [:L]),

Expand Down Expand Up @@ -566,8 +566,13 @@ op1_res_rules_1D = [
(src_type = :Form1, tgt_type = :DualForm0, resolved_name = :₁, op = :),
(src_type = :DualForm1, tgt_type = :Form0, resolved_name = :₀⁻¹, op = :),
(src_type = :DualForm0, tgt_type = :Form1, resolved_name = :₁⁻¹, op = :),
(src_type = :Form0, tgt_type = :DualForm1, resolved_name = :₀, op = :star),
(src_type = :Form1, tgt_type = :DualForm0, resolved_name = :₁, op = :star),
(src_type = :DualForm1, tgt_type = :Form0, resolved_name = :₀⁻¹, op = :star),
(src_type = :DualForm0, tgt_type = :Form1, resolved_name = :₁⁻¹, op = :star),
# Rules for δ.
(src_type = :Form1, tgt_type = :Form0, resolved_name = :δ₁, op = )]
(src_type = :Form1, tgt_type = :Form0, resolved_name = :δ₁, op = ),
(src_type = :Form1, tgt_type = :Form0, resolved_name = :δ₁, op = :codif)]

# We merge 1D and 2D rules since it seems op2 rules are metric-free. If
# this assumption is false, this needs to change.
Expand All @@ -576,6 +581,9 @@ op2_res_rules_1D = [
(proj1_type = :Form0, proj2_type = :Form0, res_type = :Form0, resolved_name = :₀₀, op = :),
(proj1_type = :Form1, proj2_type = :Form0, res_type = :Form1, resolved_name = :₁₀, op = :),
(proj1_type = :Form0, proj2_type = :Form1, res_type = :Form1, resolved_name = :₀₁, op = :),
(proj1_type = :Form0, proj2_type = :Form0, res_type = :Form0, resolved_name = :₀₀, op = :wedge),
(proj1_type = :Form1, proj2_type = :Form0, res_type = :Form1, resolved_name = :₁₀, op = :wedge),
(proj1_type = :Form0, proj2_type = :Form1, res_type = :Form1, resolved_name = :₀₁, op = :wedge),
# Rules for L.
(proj1_type = :Form1, proj2_type = :Form0, res_type = :Form0, resolved_name = :L₀, op = :L),
(proj1_type = :Form1, proj2_type = :Form1, res_type = :Form1, resolved_name = :L₁, op = :L),
Expand All @@ -599,17 +607,29 @@ op1_res_rules_2D = [
(src_type = :DualForm2, tgt_type = :Form0, resolved_name = :₀⁻¹, op = :),
(src_type = :DualForm1, tgt_type = :Form1, resolved_name = :₁⁻¹, op = :),
(src_type = :DualForm0, tgt_type = :Form2, resolved_name = :₂⁻¹, op = :),
(src_type = :Form0, tgt_type = :DualForm2, resolved_name = :₀, op = :star),
(src_type = :Form1, tgt_type = :DualForm1, resolved_name = :₁, op = :star),
(src_type = :Form2, tgt_type = :DualForm0, resolved_name = :₂, op = :star),
(src_type = :DualForm2, tgt_type = :Form0, resolved_name = :₀⁻¹, op = :star),
(src_type = :DualForm1, tgt_type = :Form1, resolved_name = :₁⁻¹, op = :star),
(src_type = :DualForm0, tgt_type = :Form2, resolved_name = :₂⁻¹, op = :star),
# Rules for δ.
(src_type = :Form2, tgt_type = :Form1, resolved_name = :δ₂, op = ),
(src_type = :Form1, tgt_type = :Form0, resolved_name = :δ₁, op = ),
(src_type = :Form2, tgt_type = :Form1, resolved_name = :δ₂, op = :codif),
(src_type = :Form1, tgt_type = :Form0, resolved_name = :δ₁, op = :codif),
# Rules for ∇².
# TODO: Call this :nabla2 in ASCII?
(src_type = :Form0, tgt_type = :Form0, resolved_name = :∇²₀, op = :∇²),
(src_type = :Form1, tgt_type = :Form1, resolved_name = :∇²₁, op = :∇²),
(src_type = :Form2, tgt_type = :Form2, resolved_name = :∇²₂, op = :∇²),
# Rules for Δ.
(src_type = :Form0, tgt_type = :Form0, resolved_name = :Δ₀, op = ),
(src_type = :Form1, tgt_type = :Form1, resolved_name = :Δ₁, op = ),
(src_type = :Form1, tgt_type = :Form1, resolved_name = :Δ₂, op = )]
(src_type = :Form1, tgt_type = :Form1, resolved_name = :Δ₂, op = ),
(src_type = :Form0, tgt_type = :Form0, resolved_name = :Δ₀, op = :lapl),
(src_type = :Form1, tgt_type = :Form1, resolved_name = :Δ₁, op = :lapl),
(src_type = :Form1, tgt_type = :Form1, resolved_name = :Δ₂, op = :lapl)]

# We merge 1D and 2D rules directly here since it seems op2 rules
# are metric-free. If this assumption is false, this needs to change.
Expand All @@ -618,6 +638,9 @@ op2_res_rules_2D = vcat(op2_res_rules_1D, [
(proj1_type = :Form1, proj2_type = :Form1, res_type = :Form2, resolved_name = :₁₁, op = :),
(proj1_type = :Form2, proj2_type = :Form0, res_type = :Form2, resolved_name = :₂₀, op = :),
(proj1_type = :Form0, proj2_type = :Form2, res_type = :Form2, resolved_name = :₀₂, op = :),
(proj1_type = :Form1, proj2_type = :Form1, res_type = :Form2, resolved_name = :₁₁, op = :wedge),
(proj1_type = :Form2, proj2_type = :Form0, res_type = :Form2, resolved_name = :₂₀, op = :wedge),
(proj1_type = :Form0, proj2_type = :Form2, res_type = :Form2, resolved_name = :₀₂, op = :wedge),
# Rules for L.
(proj1_type = :Form1, proj2_type = :Form2, res_type = :Form2, resolved_name = :L₂, op = :L),
(proj1_type = :Form1, proj2_type = :DualForm2, res_type = :DualForm2, resolved_name = :L₂ᵈ, op = :L),
Expand Down Expand Up @@ -663,3 +686,69 @@ Resolve function overloads based on types of src and tgt.
resolve_overloads!(d::SummationDecapode) =
resolve_overloads!(d, op1_res_rules_2D, op2_res_rules_2D)

function replace_names!(d::SummationDecapode, op1_repls::Vector{Pair{Symbol, Any}}, op2_repls::Vector{Pair{Symbol, Symbol}})
for (orig,repl) in op1_repls
for i in collect(incident(d, orig, :op1))
d[i, :op1] = repl
end
end
for (orig,repl) in op2_repls
for i in collect(incident(d, orig, :op2))
d[i, :op2] = repl
end
end
d
end

ascii_to_unicode_op1 = Pair{Symbol, Any}[
(:dt => :∂ₜ),
(:star => :),
(:lapl => ),
(:codif => ),
(:star_inv => :⁻¹)]

ascii_to_unicode_op2 = [
(:wedge => :)]

""" function unicode!(d::SummationDecapode)
Replace ASCII operators with their Unicode equivalents.
"""
unicode!(d::SummationDecapode) = replace_names!(d, ascii_to_unicode_op1, ascii_to_unicode_op2)

vec_to_dec_op1 = [
(:grad => :d),
(:div => [:,:d,:]),
(:curl => [:d,:]),
(:∇ => :d),
(Symbol("∇ᵈ") => [:,:d,:]),
# Note: This is x, not \times.
(Symbol("∇x") => [:d,:])]

vec_to_dec_op2 = Pair{Symbol, Symbol}[]

""" function vec_to_dec!(d::SummationDecapode)
Replace Vector Calculus operators with Discrete Exterior Calculus equivalents.
"""
function vec_to_dec!(d::SummationDecapode)
# Perform simple substitutions.
replace_names!(d, vec_to_dec_op1, vec_to_dec_op2)

# Replace `adv` with divergence of ∧.
advs = incident(d, :adv, :op2)
adv_tgts = d[advs, :res]

# Intermediate wedges.
wedge_tgts = add_parts!(d, :Var, length(adv_tgts), name=map(i -> Symbol("•_adv_$i"), eachindex(advs)), type=:infer)
# Divergences.
add_parts!(d, :Op1, length(adv_tgts), src=wedge_tgts, tgt=adv_tgts, op1=fill([:,:d,:],length(advs)))
# Point advs to the intermediates.
d[collect(advs), :res] = wedge_tgts

# Replace adv with ∧.
d[collect(advs), :op2] = fill(:,length(advs))

d
end

1 change: 1 addition & 0 deletions src/language.jl
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ term(expr::Expr) = begin
@match expr begin
#TODO: Would we want ∂ₜ to be used with general expressions or just Vars?
Expr(:call, :∂ₜ, b) => Tan(Var(b))
Expr(:call, :dt, b) => Tan(Var(b))

Expr(:call, Expr(:call, :, a...), b) => AppCirc1(a, term(b))
Expr(:call, a, b) => App1(a, term(b))
Expand Down
Loading

0 comments on commit 53b23a5

Please sign in to comment.