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

Roe cleanup #161

Open
wants to merge 5 commits into
base: compute-graph
Choose a base branch
from
Open

Roe cleanup #161

wants to merge 5 commits into from

Conversation

quffaro
Copy link
Member

@quffaro quffaro commented Jul 23, 2024

No description provided.

@quffaro quffaro requested a review from olynch July 23, 2024 20:12
Copy link
Member

@olynch olynch left a comment

Choose a reason for hiding this comment

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

General comments:

  1. We should not be using the GATlab nomenclature of ThDEC/models, to avoid confusion
  2. Let's try to make folder structure of test/ mimic the folder structure of src/.

@@ -0,0 +1,222 @@
# """
Copy link
Member

Choose a reason for hiding this comment

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

Maybe this should just be called "roe.jl" and be included into module.jl with no surrounding module?


Struct containing a Function and the vector of Sorts it requires.
"""
@struct_hash_equal struct TypedApplication
Copy link
Member

Choose a reason for hiding this comment

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

This, and other things that have AbstractSort parameters, should be typed based on a subtype of AbstractSort.


""" fix_functions(e)::Union{Symbol, Expr}

Traverses the AST of an expression, replacing the head of :call expressions to its name, a Symbol.
Copy link
Member

Choose a reason for hiding this comment

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

Add to this comment that fix_functions is used for the show method of Vars


""" fresh!(roe::Roe, sort::AbstractSort, name::Symbol)::Var{sort}

Creates a new ("fresh") variable in a Roe given a sort and a name.
Copy link
Member

Choose a reason for hiding this comment

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

Should be something like:

Creates a new variable in a Roe. Specifically, appends a new RootVar with given sort and name to the Roe, adds that RootVar to the e-graph, and returns a Var wrapper around the new e-graph id, with type parameter given by the sort.

@@ -0,0 +1,137 @@
module SSAExtract
Copy link
Member

Choose a reason for hiding this comment

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

Maybe just call this SSAs. And then all the things prefixed with SSA (i.e. SSAVar, etc.) can be SSAs.Var, etc.

end
end

function ι(s1::Sort, s2::Sort)
Copy link
Member

Choose a reason for hiding this comment

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

Either complete these or add TODO comments

import Base: +, -, *

# These operations create calls on a common egraph. We validate the signature by dispatching the operation on the types using methods we defined in Signature.

Copy link
Member

Choose a reason for hiding this comment

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

for binop in [+, *, -, \wedge, ...]
  @eval begin
  function $binop(v1::Var{s1}, v2::Var{s2}) where {s1, s2}
    v1.roe === v2.roe || error("Cannot add variables from different graphs")
    s = $binop(s1, s2)
    Var{s}(v1.roe, addcall!(v1.roe.graph, $binop, (v1.id, v2.id)))
  end
  export $binop
  end
end

Copy link
Member

Choose a reason for hiding this comment

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

This might be the blessed way to do it (also add the overloads with Number) -- we should doublecheck that this will run during precompilation though!

Copy link
Member

Choose a reason for hiding this comment

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

This looks fine to me. Julia's Base does this for op in [+,*...] a lot to define all the possible methods between different numeric types.

Given a matrix and a hodge star (DiagonalHodge() or GeometricHodge()), this returns a lookup dictionary between operators (as TypedApplications) and their corresponding matrices.

"""
function precompute_matrices(sd, hodge)::Dict{TypedApplication, Any}
Copy link
Member

Choose a reason for hiding this comment

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

Maybe this should be called something more generic, like "create_dynamic_model" or something? Basically, what this is doing is creating a Dict that stores a model of the theory of DEC. We can workshop that name though.

::RootVar => rootvar_lookup[expr.head]
::Number => expr.head
_ => begin
op = operator_lookup[TA(expr.head, first.(expr.args))]
Copy link
Member

Choose a reason for hiding this comment

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

op = get(operator_lookup, TA(expr.head, first.(expr.args)), op)

export derivative_cost


""" vfield :: (Decaroe -> (StateVars, ParamVars)) -> VectorFieldFunction
Copy link
Member

Choose a reason for hiding this comment

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

Right now this is hacked to assume that there only one state variable and only one parameter variable, because we haven't integrated with ComponentArrays yet: we should integrate with ComponentArrays.

Copy link
Member

Choose a reason for hiding this comment

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

"integrating with ComponentArrays" should just mean that you assume the state variable and parameter variables can be accessed by symbolic keys, and that what you get back from indexing will be either a vector or a scalar value so you use broadcasted operations when necessary.

It is a pretty light lift from the users perspective.

@olynch olynch changed the base branch from main to compute-graph July 23, 2024 20:50
DEC/tests/DEC.jl Outdated

# we can reuse the mesh and operator lookup
_vf = vfield(new_heat_equation, operator_lookup)

Choose a reason for hiding this comment

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

this one won't run for me

_vf = vfield(new_heat_equation, operator_lookup) # XXX: brooken
ERROR: KeyError: key Scalar() * PrimalForm(0) not found
Stacktrace:
  [1] getindex
    @ ./dict.jl:477 [inlined]
  [2] (::DEC.Models.ThDEC.var"#toexpr#15"{Dict{TypedApplication, Any}, Dict{RootVar, Union{Expr, Symbol}}})(expr::SSAExpr)
    @ DEC.Models.ThDEC ~/.julia/dev/GATlab/DEC/src/models/ThDEC/ThDEC.jl:97
  [3] (::DEC.Models.ThDEC.var"#7#17")(::Any)
    @ DEC.Models.ThDEC ~/.julia/dev/GATlab/DEC/src/models/ThDEC/ThDEC.jl:126
  [4] iterate
    @ ./generator.jl:48 [inlined]
  [5] collect_to!
    @ ./array.jl:838 [inlined]
  [6] collect_to_with_first!
    @ ./array.jl:816 [inlined]
  [7] collect(itr::Base.Generator{Base.Iterators.Enumerate{Vector{SSAExpr}}, DEC.Models.ThDEC.var"#7#17"})
    @ Base ./array.jl:790
  [8] map
    @ ./abstractarray.jl:3402 [inlined]
  [9] vfield(model::Any, operator_lookup::Dict{TypedApplication, Any})
    @ DEC.Models.ThDEC ~/.julia/dev/GATlab/DEC/src/models/ThDEC/ThDEC.jl:125
 [10] top-level scope
    @ REPL[26]:1

Copy link
Member Author

Choose a reason for hiding this comment

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

Right, @olynch and I reviewed this today and decided we need to just tweak the code to use Julia's * operation. This and the other comments should be resolved tomorrow

@jpfairbanks
Copy link
Member

High level thought @olynch, we discussed on Thursday in lab meeting that the Roe stuff is just based on Metatheory.jl so it doesn't really need Gatlab integration yet. Should this PR end up in DiagrammaticEquations.jl?

@KevinDCarlson
Copy link

High level thought @olynch, we discussed on Thursday in lab meeting that the Roe stuff is just based on Metatheory.jl so it doesn't really need Gatlab integration yet. Should this PR end up in DiagrammaticEquations.jl?

That’d be sick if it’s reasonable

# :Δᵈ₁ => Δᵈ(Val{1},sd)

# # Musical Isomorphisms
TA(♯, Sort[PrimalForm(1)]) => Decapodes.dec_♯_p(sd), # Primal(1) -> PVField
Copy link
Member

Choose a reason for hiding this comment

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

As discussed on Zulip and offline, this dict needs to be refactored to emit functions based on input and output types both. This is to accommodate e.g. the fact that there is a $$\flat_{pp}$$ and a $$\flat_{pd}$$. See Figure 5.2.

Copy link
Member

Choose a reason for hiding this comment

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

At this level, the output type is determined by the input types, so I'm not really sure what this means.

Copy link
Member

@lukem12345 lukem12345 Aug 5, 2024

Choose a reason for hiding this comment

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

In the DEC, an e.g. sharp operator can be defined which takes a primal form and outputs a primal vector field, while another sharp operator takes a primal form and emits a dual vector field. Both of these can coexist.

The appearance of dual complexes leads to a proliferation of the operators in the discrete theory. For example there are
primal-primal, primal-dual etc. versions of many operators. This is of course unique to the discrete side.

From hirani

function TypedApplication(head::Function, sorts::Vector{Sort}) where Sort
new{Sort}(head, sorts)
end
end
Copy link
Member

Choose a reason for hiding this comment

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

@struct_hash_equal struct TypedApplication{Sort<:AbstractSort}
  head::Function
  insorts::Vector{Sort}
  outsorts::Vector{Sort}

  function TypedApplication(head::Function, sorts::Vector{Sort}) where Sort
    new{Sort}(head, sorts)
  end
end

TA(♯, Sort[PrimalForm(1)]) => Decapodes.dec_♯_p(sd), # Primal(1) -> PVField
TA(♯, Sort[DualForm(1)]) => Decapodes.dec_♯_d(sd), # Dual(1) -> DVField

TA(♭, Sort[DualVF()]) => Decapodes.dec_♭(sd), # DVField -> Primal(1)
Copy link
Member

Choose a reason for hiding this comment

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

TA(♭, Sort[DualVF()], Sort[Primal(1)]) => Decapodes.dec_♭(sd)

Copy link
Member

Choose a reason for hiding this comment

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

Und so weiter


"""
function create_dynamic_model(sd, hodge)::Dict{TypedApplication, Any}
Dict{TypedApplication, Any}(
Copy link
Member

Choose a reason for hiding this comment

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

We need to special-case sums of more than 32 forms.

We need to not do sums two-at-a-time.

Given a matrix and a hodge star (DiagonalHodge() or GeometricHodge()), this returns a lookup dictionary between operators (as TypedApplications) and their corresponding matrices.

"""
function create_dynamic_model(sd, hodge)::Dict{TypedApplication, Any}
Copy link
Member

Choose a reason for hiding this comment

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

Purposes of using a Dict here vs. an @match block?

Copy link
Member

Choose a reason for hiding this comment

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

I think the blessed way to do this is going to actually be to create a memoized function/lazy dict. Best of both worlds: we don't have to compute operators that we don't need, and we don't have to compute operators multiple times.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants