-
Notifications
You must be signed in to change notification settings - Fork 58
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
Another macro for constructing ACSets! #354
base: main
Are you sure you want to change the base?
Conversation
Theoretically, we could even add type-checking to this! |
Whoa that is awesome. While variable names are a pain in the neck in the implementation, they are super helpful for humans writing the input. |
Yeah, I'm totally not attached to Also, I'm thinking about adding a feature to this where you can use it to add things to an existing acset, and I kind of want to have @present_acset g2 <: g1 begin
...
end Is it too weird to have that, when we normally use |
What if we used the unicode \subset? it parses as a binary operator. |
On a roll lately with the macros! Thoughts:
g2 = @named_acset g1 begin
...
end
@named_acset DecGraph{Symbol} begin
(w,x,y,z) :: V
(a,b,c,d) :: E(src=[w,x,y,z], tgt=[x,y,z,w], dec=E)
end |
If we are thinking about adding incrementally to an existing ACSet X (defining maps out of X) we should also think about creating sub ACSets (defining maps into X) and use similar syntax for those operations. |
I'm not sure exactly how that would work, can you elaborate with an example? If I'm parsing what you are saying correctly, then I think it might only work in cases where the "naming attribute" is uniquely indexed. But that is an important special case! |
Also, question, should I replace the tuple syntax Naming things is so hard!! |
Name of the macroI think integrating this with the features of the main Taking Evan's example above: @acset DecGraph{Symbol} begin
(w,x,y,z) :: V
(a,b,c,d) :: E(src=[w,x,y,z], tgt=[x,y,z,w], dec=E)
end If you made the left hand sides Integer ranges, then we could subsume the number based acset macro @named_acset DecGraph{Symbol} begin
1:4 :: V
1:4 :: E(src=[1,2,3,4], tgt=[2,3,4,1], dec=[:a,:b,:c,:d])
end Then you could default to ranges that start at 1 @named_acset DecGraph{Symbol} begin
4 :: V
4 :: E(src=[1,2,3,4], tgt=[2,3,4,1], dec=[:a,:b,:c,:d])
end Distinguishing extension from making a new ACSetI think taking g2 = @named_acset g1 begin
...
end and maybe @acset g1 \to g2 begin
...
end as a way of specifying g2 and a map from g1 to g2 together would be a great feature. When we say that we "add data to an existing acset X, we are really saying that we construct a new acset Y and a map from X to Y. When we say that X is a subacset of Y, then we are really specifying X and map from X into Y. Since we think of inheritance of schemas as a functor from the parent schema into the child schema, which induces a pullback functor of the corresponding acsets, I think we should use that approach as a unified doctrine of inheritance. So when an acset inherits from another (by extension) that is a hom from the base acset to the extended acset. One of the lessons of categorical algebra is that everything gets easier if you think about computing homs instead of computing objects. I think we should apply it here and make these inheritance/extensions/inclusions work by constructing homs between acsets. |
Totally agree with @jpfairbanks about the naming issue: we should unify the The point about sub-ACSets is also good and would partly address #349. |
One thing is that it doesn't actually make sense to declare an arbitrary range But I'm glad that this solves the naming issue; we just call it all Still there is a problem about the need to syntactically delineate Also, what if we use some sigil to indicate which attribute is the naming attribute? Like @acset DecGraph{Symbol} begin
(w,x,y,z) :: V
(a,b,c,d) :: E(src=[w,x,y,z], tgt=[x,y,z,w], !dec)
end Also, I think that the row-wise assignment that I pushed off in the last macro would be good here @acset DecGraph{Symbol} begin
(w,x,y,z) :: V
@define E(src,tgt,!dec) begin
a = w,x
b = x,y
c = y,z
d = z,w
end
end |
Hell, if we wanted to be really fancy, we could have something like @acset DecGraph{Symbol} begin
(w,x,y,z) :: V
@define E(src,tgt,!dec), formula = src -> tgt begin
a = w -> x
b = x -> y
c = y -> z
d = z -> w
end
end I have no idea how easy it would be to implement, but if we ever really need a flex, we can refer back to this comment and try to get it working. Though, now that I think about it, we might be able to use the machinery from @match e begin
Expr(:call, :(->), src, tgt) => (src,tgt)
_ => error()
end |
In relation to all this, I had a thought when I was walking today. It is useful to have persistent names for elements of an acset for defining functions in/out of them. However, logically these names aren't really attributes; they should have no mathematical impact. It would also be annoying to have to define new ACSet types with uniquely indexed names every time you wanted to define maps using human-friendly syntax (i.e., not just integers). My proposed solution for this is that we implement a Tables.jl-compatible typed dataframe that can be indexed by numbers and also symbols. This could be as simple as a StructVector + Dict{Symbol,Int}. Then any acset schema can be used with or without names for its elements. Then @acset would automatically work with this, and would additionally set attributes based on the names given in the code if also specified. This would mean that you could use the same names when extending an acset as when you originally defined it. And of course, it would be easy to write a function that strips away all the names, changing the type to a Tables.jl implementation without symbol-indexing. Thoughts? |
I was inspired to write this while reading Sophie Libkind's post; there was a section where she created an acset and I thought "there must be a better way."
Example usage:
produces the same result as
Each "with_names" argument allows you to capture the symbols used in the macro as attributes in the final ACSet.