-
Notifications
You must be signed in to change notification settings - Fork 46
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
Adding Hypergraph object #664
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Interpretation boxes are necessary either way because we need them for large hypergraphs that cannot be plotted. Also, if we do return full-size plots, we'll have to be able to disable them (for performance), which means we need the
GraphLayout
option as well. So, I think we should keep it only as interpretation boxes for now. - Since
Hyperedge
's are returned byEdgeList
, yes, of course, we need to export them. But I'm not sure we needHyperedge
at all. - I don't know where we might want to use mixed types, but I think it would be best to design an API that would allow us to have that in the future. If we keep hyperedges as lists for now, we'll be able to do that later with custom hyperedge. However, we cannot use
Hyperedge[v1, v2, ...]
as there wouldn't be a place to put the symmetry. - The default in SetReplace has always been
"Ordered"
for hypergraphs. As far as I remember,HypergraphPlot
is the only function that even supports other types. I don't think we need to specify the orderness type at all in the first iteration, but if we do, it should certainly default to"Ordered"
.
Reviewed 1 of 1 files at r1.
Reviewable status: all files reviewed, 14 unresolved discussions (waiting on @daneelsan)
Kernel/Hypergraph.m, line 7 at r1 (raw file):
PackageExport["Hypergraph"] PackageExport["HypergraphQ"] PackageExport["HypergraphOrderedQ"]
I suggest changing ordered/unordered to an enum (could be strings or symbols for now), as we might want to expand to more than two varieties in the future. For example, "Ordered"
, "Unordered"
, "Cyclic"
, "Directed"
.
Kernel/Hypergraph.m, line 7 at r1 (raw file):
PackageExport["Hypergraph"] PackageExport["HypergraphQ"] PackageExport["HypergraphOrderedQ"]
If Hyperedge
is returned by EdgeList
, it should be exported.
Kernel/Hypergraph.m, line 39 at r1 (raw file):
SyntaxInformation[Hypergraph] = {"ArgumentsPattern" -> {hyperedges_, orderedQ_.}}; Hypergraph[hyperedges_, orderedQ : (True | False) : False] ? System`Private`HoldEntryQ :=
Why would it default to False
? We almost always deal either with ordered or directed hypergraphs.
Kernel/Hypergraph.m, line 39 at r1 (raw file):
SyntaxInformation[Hypergraph] = {"ArgumentsPattern" -> {hyperedges_, orderedQ_.}}; Hypergraph[hyperedges_, orderedQ : (True | False) : False] ? System`Private`HoldEntryQ :=
It needs to generate messages if hyperedges
is not valid. (We need to keep this consistent with the rest of SetReplace until we figure out what to do with the new approach.)
Kernel/Hypergraph.m, line 46 at r1 (raw file):
]; hypergraphQ = MatchQ[{(_List | _Hyperedge) ...}];
If we implement Hyperedge
in this way, we won't be able to make them ordered/unordered in the future. It might be better to do it as Hyperedge[{vertices...}, symmetry]
. Or, if we require uniform symmetries for all edges, I don't see any reason not to keep them as simple lists.
Kernel/Hypergraph.m, line 72 at r1 (raw file):
(* HypergraphPlot *) Hypergraph /: HypergraphPlot[hypergraph_Hypergraph ? HypergraphQ, opts___] := HypergraphPlot[Normal[hypergraph], opts];
The problem with implementing it like this (instead of in HypergraphPlot
) is that it won't be able to generate messages correctly if something fails, e.g.,
HypergraphPlot[Hypergraph[{{2, 3}, {1, 2}, {2, 3}}], f -> 3]
Kernel/Hypergraph.m, line 88 at r1 (raw file):
Hypergraph, hypergraph, HypergraphPlot[hypergraph, ImageSize -> {29, 29}],
Note that this fails for empty hyperedges, e.g.,
Hypergraph[{{}, {}, {1, 2, 3}}]
Kernel/Hypergraph.m, line 88 at r1 (raw file):
Hypergraph, hypergraph, HypergraphPlot[hypergraph, ImageSize -> {29, 29}],
The plots should depend on the hypergraph type and should probably be disabled for now for anything other than ordered and cyclic hypergraphs.
Kernel/Hypergraph.m, line 88 at r1 (raw file):
Hypergraph, hypergraph, HypergraphPlot[hypergraph, ImageSize -> {29, 29}],
Also note cases like this:
Hypergraph[{{{2, 3}, {2, 3}}, {{2, 3}, {2, 3}}}]
Although I think the correct solution is to stop HypergraphPlot
from being listable (it was a bad idea in the first place).
Kernel/Hypergraph.m, line 88 at r1 (raw file):
Hypergraph, hypergraph, HypergraphPlot[hypergraph, ImageSize -> {29, 29}],
The plot should be disabled for large hypergraphs.
Kernel/Hypergraph.m, line 98 at r1 (raw file):
(* WolframModel *) Hypergraph /: WolframModel[rule_, hypergraph_Hypergraph, args___] :=
WolframModel
should only accept ordered hypergraphs.
Kernel/Hypergraph.m, line 98 at r1 (raw file):
(* WolframModel *) Hypergraph /: WolframModel[rule_, hypergraph_Hypergraph, args___] :=
Same problem here as HypergraphPlot
: it won't be able to generate messages correctly if something fails.
Kernel/Hypergraph.m, line 103 at r1 (raw file):
(* HypergraphToGraph *) Hypergraph /: HypergraphToGraph[hypergraph_Hypergraph, args___] :=
This depends on whether the hypergraph is ordered/unordered/directed as well.
Kernel/Hypergraph.m, line 112 at r1 (raw file):
(*Does CanonicalHypergraph take into consideration if the hypergraph is ordered?*) Hypergraph /: (func : ResourceFunction["CanonicalHypergraph"])[hypergraph_Hypergraph ? HypergraphQ] :=
We cannot have dependencies on resource functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewable status: all files reviewed, 14 unresolved discussions (waiting on @daneelsan and @maxitg)
Kernel/Hypergraph.m, line 7 at r1 (raw file):
Previously, maxitg (Max Piskunov) wrote…
If
Hyperedge
is returned byEdgeList
, it should be exported.
Agree.
Kernel/Hypergraph.m, line 7 at r1 (raw file):
Previously, maxitg (Max Piskunov) wrote…
I suggest changing ordered/unordered to an enum (could be strings or symbols for now), as we might want to expand to more than two varieties in the future. For example,
"Ordered"
,"Unordered"
,"Cyclic"
,"Directed"
.
I know we discussed this before, but I forgot about the differences between these types of edges.
I think "Ordered" means {a, b, c}
is different from {a, c, b}
.
Does "Directed" relate to how this hyperedge would be converted to a set of edges? E.g. {a, b, c}
would become {a -> b, b -> c}
.
"Cyclic" (Directed) then means {a, b, c}
-> {a -> b, b -> c, c -> a}
?
Kernel/Hypergraph.m, line 112 at r1 (raw file):
Previously, maxitg (Max Piskunov) wrote…
We cannot have dependencies on resource functions.
Yes, forgot to remove these.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewable status: all files reviewed, 14 unresolved discussions (waiting on @daneelsan and @maxitg)
Kernel/Hypergraph.m, line 7 at r1 (raw file):
Previously, daneelsan (Daniel Sanchez) wrote…
I know we discussed this before, but I forgot about the differences between these types of edges.
I think "Ordered" means{a, b, c}
is different from{a, c, b}
.
Does "Directed" relate to how this hyperedge would be converted to a set of edges? E.g.{a, b, c}
would become{a -> b, b -> c}
.
"Cyclic" (Directed) then means{a, b, c}
->{a -> b, b -> c, c -> a}
?
- Ordered hyperedge is a sequence. There is no symmetry. Every position is different. Same as
List
{a, b, c}
. - Directed is a pair of multisets, like an event hypergraph. It has two distinct parts, but vertices are not ordered within each part:
{<|a, b, c|>, <|d, e, f|>}
. This can correspond to event inputs and outputs. - Cyclic means there is a cyclic symmetry.
{a, b, c}
,{b, c, a}
and{c, a, b}
are treated as identical.
So, to answer your questions:
- Yes.
- No,
{a, b, c}
is not a valid edge for a directed hypergraph. It should be{a, b} -> {c}
,{a} -> {b, c}
or something like that. - Kind of, except there is a difference between
{{a, b, c}}
and{{a, b}, {b, c}, {c, a}}
.
…pergraph, adding hypergraph symmetries, removing Hyperedge symbol, etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewable status: 0 of 1 files reviewed, 14 unresolved discussions (waiting on @daneelsan and @maxitg)
Kernel/Hypergraph.m, line 7 at r1 (raw file):
Previously, maxitg (Max Piskunov) wrote…
- Ordered hyperedge is a sequence. There is no symmetry. Every position is different. Same as
List
{a, b, c}
.- Directed is a pair of multisets, like an event hypergraph. It has two distinct parts, but vertices are not ordered within each part:
{<|a, b, c|>, <|d, e, f|>}
. This can correspond to event inputs and outputs.- Cyclic means there is a cyclic symmetry.
{a, b, c}
,{b, c, a}
and{c, a, b}
are treated as identical.So, to answer your questions:
- Yes.
- No,
{a, b, c}
is not a valid edge for a directed hypergraph. It should be{a, b} -> {c}
,{a} -> {b, c}
or something like that.- Kind of, except there is a difference between
{{a, b, c}}
and{{a, b}, {b, c}, {c, a}}
.
Thanks for the explanation!
I've supported these as "enums"... but now that I read what you said, for Directed
I need to change the check I do to the hyperedges ({___List}
is not enough anymore).
Kernel/Hypergraph.m, line 39 at r1 (raw file):
Previously, maxitg (Max Piskunov) wrote…
It needs to generate messages if
hyperedges
is not valid. (We need to keep this consistent with the rest of SetReplace until we figure out what to do with the new approach.)
Returning Failure
's for now... let me know what you think
Kernel/Hypergraph.m, line 39 at r1 (raw file):
Previously, maxitg (Max Piskunov) wrote…
Why would it default to
False
? We almost always deal either with ordered or directed hypergraphs.
Done.
Kernel/Hypergraph.m, line 46 at r1 (raw file):
Previously, maxitg (Max Piskunov) wrote…
If we implement
Hyperedge
in this way, we won't be able to make them ordered/unordered in the future. It might be better to do it asHyperedge[{vertices...}, symmetry]
. Or, if we require uniform symmetries for all edges, I don't see any reason not to keep them as simple lists.
Keeping it as simple lists :)
Kernel/Hypergraph.m, line 72 at r1 (raw file):
Previously, maxitg (Max Piskunov) wrote…
The problem with implementing it like this (instead of in
HypergraphPlot
) is that it won't be able to generate messages correctly if something fails, e.g.,HypergraphPlot[Hypergraph[{{2, 3}, {1, 2}, {2, 3}}], f -> 3]
Agree.
Kernel/Hypergraph.m, line 88 at r1 (raw file):
Previously, maxitg (Max Piskunov) wrote…
The plot should be disabled for large hypergraphs.
What should be the cutoff?
Kernel/Hypergraph.m, line 88 at r1 (raw file):
Previously, maxitg (Max Piskunov) wrote…
Also note cases like this:
Hypergraph[{{{2, 3}, {2, 3}}, {{2, 3}, {2, 3}}}]Although I think the correct solution is to stop
HypergraphPlot
from being listable (it was a bad idea in the first place).
Yes, in hindsight that looks wrong. I'll remove that once I support Hypergraph
in HypergraphPlot
.
Kernel/Hypergraph.m, line 88 at r1 (raw file):
Previously, maxitg (Max Piskunov) wrote…
Note that this fails for empty hyperedges, e.g.,
Hypergraph[{{}, {}, {1, 2, 3}}]
So this should be handled when HypergraphPlot
receives a Hypergraph
, right?
Kernel/Hypergraph.m, line 88 at r1 (raw file):
Previously, maxitg (Max Piskunov) wrote…
The plots should depend on the hypergraph type and should probably be disabled for now for anything other than ordered and cyclic hypergraphs.
What should be the default icon? The one from WolframModelEvolutionObject
?
Kernel/Hypergraph.m, line 98 at r1 (raw file):
Previously, maxitg (Max Piskunov) wrote…
Same problem here as
HypergraphPlot
: it won't be able to generate messages correctly if something fails.
Agree, I'll move the definition over there.
Kernel/Hypergraph.m, line 112 at r1 (raw file):
Previously, daneelsan (Daniel Sanchez) wrote…
Yes, forgot to remove these.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewed 1 of 1 files at r2.
Reviewable status: all files reviewed, 9 unresolved discussions (waiting on @daneelsan)
Kernel/Hypergraph.m, line 7 at r1 (raw file):
Previously, daneelsan (Daniel Sanchez) wrote…
Thanks for the explanation!
I've supported these as "enums"... but now that I read what you said, forDirected
I need to change the check I do to the hyperedges ({___List}
is not enough anymore).
Yeah, maybe for "Directed" we should use something like this: DirectedEdge[{1, 2, 3}, {3, 4, 5}]
?
Kernel/Hypergraph.m, line 39 at r1 (raw file):
Previously, daneelsan (Daniel Sanchez) wrote…
Returning
Failure
's for now... let me know what you think
I think we should do the same thing everywhere. So, I suggest using the mechanism from A0$messages.m
for now to return unevaluated. I also still think throwing failures would be better than returning them. The main issue with returning failures is that it's too silent. If a function is not supposed to return anything, or if what it returns is ignored (or interpreted incorrectly by the subsequent code), it would be impossible to tell that something wrong has happened.
Also, note that it currently prints messages for an incorrect number of arguments. That needs to be consistent as well.
Kernel/Hypergraph.m, line 88 at r1 (raw file):
Previously, daneelsan (Daniel Sanchez) wrote…
So this should be handled when
HypergraphPlot
receives aHypergraph
, right?
Well, yes, ideally we want to fix HypergraphPlot
so that it can display empty edges in some way (which is mostly a graphical design question).
Kernel/Hypergraph.m, line 88 at r1 (raw file):
Previously, daneelsan (Daniel Sanchez) wrote…
What should be the default icon? The one from
WolframModelEvolutionObject
?
I'm not sure we should display an icon at all. It might be misleading if the icon is usually correct, but not always. However, if we do have an icon, maybe it's better to use one that does not look like a HypergraphPlot
at all?
Kernel/Hypergraph.m, line 88 at r1 (raw file):
Previously, daneelsan (Daniel Sanchez) wrote…
What should be the cutoff?
That's a good question. Maybe a second (inferred from the number of edges)? That would cause issues if one tries to return lots of hypergraphs simultaneously, but it's not any worse than what Graph
is doing. Ideally, we want to plot asynchronously so that we don't interfere with the front end, but I don't think that's possible.
Kernel/Hypergraph.m, line 24 at r2 (raw file):
$hypergraphSymmetries = {"Ordered", "Unordered", "Cyclic", "Directed"}; SetUsage @ "HypergraphSymmetry[hg$] returns the symmetry of the hypergraph hg$.";
I think this needs some explanation of what symmetry is.
Kernel/Hypergraph.m, line 41 at r2 (raw file):
<| "ObjectType" -> Hypergraph, "Symmetry" -> HypergraphSymmetry,
HypergraphSymmetry[obj]
Kernel/Hypergraph.m, line 54 at r2 (raw file):
System`Private`ConstructNoEntry[Hypergraph, hyperedges, symmetry]; Hypergraph::invalidHyperedges = "The argument at position 1 should be ";
This does not appear to be used anywhere.
Kernel/Hypergraph.m, line 56 at r2 (raw file):
Hypergraph::invalidHyperedges = "The argument at position 1 should be "; hypergraph[hyperedges_] := hypergraph[hyperedges, "Ordered"];
Isn't this redundant with Default[Hypergraph, 2]
above?
…ailure. Added a naive criterion to not use HypergraphPlot in the boxes. Not allowing Directed for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewable status: 0 of 1 files reviewed, 9 unresolved discussions (waiting on @daneelsan and @maxitg)
Kernel/Hypergraph.m, line 7 at r1 (raw file):
Previously, maxitg (Max Piskunov) wrote…
Yeah, maybe for "Directed" we should use something like this:
DirectedEdge[{1, 2, 3}, {3, 4, 5}]
?
That makes sense. But that would not be "global" symmetry, right?
Kernel/Hypergraph.m, line 39 at r1 (raw file):
Previously, maxitg (Max Piskunov) wrote…
I think we should do the same thing everywhere. So, I suggest using the mechanism from
A0$messages.m
for now to return unevaluated. I also still think throwing failures would be better than returning them. The main issue with returning failures is that it's too silent. If a function is not supposed to return anything, or if what it returns is ignored (or interpreted incorrectly by the subsequent code), it would be impossible to tell that something wrong has happened.Also, note that it currently prints messages for an incorrect number of arguments. That needs to be consistent as well.
Yes, I agree that returning Failure
's is too silent. I'll change back to messages + unevaluated code.
Kernel/Hypergraph.m, line 88 at r1 (raw file):
Previously, maxitg (Max Piskunov) wrote…
Well, yes, ideally we want to fix
HypergraphPlot
so that it can display empty edges in some way (which is mostly a graphical design question).
I thought {}
had to be ignored 🤔
Kernel/Hypergraph.m, line 88 at r1 (raw file):
Previously, maxitg (Max Piskunov) wrote…
I'm not sure we should display an icon at all. It might be misleading if the icon is usually correct, but not always. However, if we do have an icon, maybe it's better to use one that does not look like a
HypergraphPlot
at all?
Yeah, I can't design a generic hypergraph icon...
Kernel/Hypergraph.m, line 88 at r1 (raw file):
Previously, maxitg (Max Piskunov) wrote…
That's a good question. Maybe a second (inferred from the number of edges)? That would cause issues if one tries to return lots of hypergraphs simultaneously, but it's not any worse than what
Graph
is doing. Ideally, we want to plot asynchronously so that we don't interfere with the front end, but I don't think that's possible.
Using 100 edges as the cutoff for now...
Kernel/Hypergraph.m, line 41 at r2 (raw file):
Previously, maxitg (Max Piskunov) wrote…
HypergraphSymmetry[obj]
Done.
Kernel/Hypergraph.m, line 54 at r2 (raw file):
Previously, maxitg (Max Piskunov) wrote…
This does not appear to be used anywhere.
Done.
Kernel/Hypergraph.m, line 56 at r2 (raw file):
Previously, maxitg (Max Piskunov) wrote…
Isn't this redundant with
Default[Hypergraph, 2]
above?
I would have liked to use Default
, but I don't know how to make this work:
((expr : Hypergraph[args___]) ? System`Private`HoldEntryQ) /; CheckArguments[expr, {1, 2}] :=
Somewhere in there should be a symmetry_.
, but don't know how.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewed 1 of 1 files at r3.
Reviewable status: all files reviewed, 7 unresolved discussions (waiting on @daneelsan)
Kernel/Hypergraph.m, line 7 at r1 (raw file):
Previously, daneelsan (Daniel Sanchez) wrote…
That makes sense. But that would not be "global" symmetry, right?
It cannot be a single group for all hyperedges because they can contain different numbers of vertices, e.g., {1, 2} -> {3}
and {1} -> {2, 3}
. But the same would also be the case for other symmetries since the symmetry groups would have different sizes based on the hyperedge spec. So, we cannot specify the symmetry group globally in any case. It has to be a function from a hyperedge spec to a group, in which case it works for the "Directed"
case as well.
Essentially,
"Ordered" -> (SymmetricGroup[1] &)
"Unordered" -> (SymmetricGroup @* Length)
"Cyclic" -> (CyclicGroup @* Length)
"Directed" -> PermutationGroup[Join[
GroupElements[SymmetricGroup[Length[#[[1]]]]],
GroupElements[SymmetricGroup[Length[#[[2]]]]] /. n_Integer :> n + Length[#[[1]]]]] &
Kernel/Hypergraph.m, line 88 at r1 (raw file):
Previously, daneelsan (Daniel Sanchez) wrote…
I thought
{}
had to be ignored 🤔
Why would they be ignored? They are perfectly reasonably 0-arity hyperedges. So perhaps we can plot them as circles away from the main graph. I.e., the same as unary edges but without a vertex inside.
So, if a graph has 2 0-arity edges, we might plot it like these:
In[] := HypergraphPlot[{{}, {}, {1, 2, 3}, {3, 4}, {4, 1}}]
(* HypergraphPlot[{{0}, {0}, {1, 2, 3}, {3, 4}, {4, 1}}, VertexStyle -> <|0 -> White|>] *)
Or, perhaps, like this:
In[] := HypergraphPlot[{{}, {}, {1, 2, 3}, {3, 4}, {4, 1}}]
(* HypergraphPlot[{{0}, {-1}, {1, 2, 3}, {3, 4}, {4, 1}}, VertexStyle -> <|n_ /; n <= 0 -> White|>] *)
It wouldn't even be difficult to implement because one can use the trick of adding transparent vertex/vertices.
Kernel/Hypergraph.m, line 88 at r1 (raw file):
Previously, daneelsan (Daniel Sanchez) wrote…
Yeah, I can't design a generic hypergraph icon...
I think the one for Graph
is just a zoomed-in example of a GraphPlot
. Maybe, we can do something similar with HypergraphPlot
as well.
Kernel/Hypergraph.m, line 88 at r1 (raw file):
Previously, daneelsan (Daniel Sanchez) wrote…
Using 100 edges as the cutoff for now...
Sounds reasonable.
Kernel/Hypergraph.m, line 56 at r2 (raw file):
Previously, daneelsan (Daniel Sanchez) wrote…
I would have liked to use
Default
, but I don't know how to make this work:((expr : Hypergraph[args___]) ? System`Private`HoldEntryQ) /; CheckArguments[expr, {1, 2}] :=
Somewhere in there should be a
symmetry_.
, but don't know how.
Why not simply put it as
hypergraph[hyperedges : {___List}, symmetry : Alternatives @@ $hypergraphSymmetries : "Ordered"] :=
System`Private`ConstructNoEntry[Hypergraph, hyperedges, symmetry];
Kernel/Hypergraph.m, line 64 at r3 (raw file):
hypergraph[hyperedges_, symmetry : Alternatives @@ $hypergraphSymmetries] := throw[Failure["invalidHyperedges"]];
You need to pass an empty association as the second argument of Failure
. Otherwise, message
fails because it cannot join "expr"
into it.
Kernel/Hypergraph.m, line 95 at r3 (raw file):
getIcon[hg_] /; (!disablePlotQ[hg] && MemberQ[$edgeTypes, HypergraphSymmetry[hg]]) := HypergraphPlot[EdgeList[hg], HypergraphSymmetry[hg], ImageSize -> {29, 29}];
It looks like the image size is not consistent between HypergraphPlot
s and $evolutionObjectIcon
. Perhaps, it might be better to try the same code as $graphIcon
uses, i.e.,
ImageSize -> Dynamic[{
Automatic,
3.5` CurrentValue["FontCapHeight"] / AbsoluteCurrentValue[Magnification]}]
This reverts commit fdd397b.
Changes
Hypergraph
object, accessors and upvalues.Comments
Various designs questions:
How to represent theDecided on using a summary box.Hypergraph
object in a notebook? Interpretation boxes (e.g. SparseArrays) or Graph-like plots?The symbolDecided to not use the symbol yet, just a list.Hyperedge
is private for now. Should this be exposed?Should we consider hypergraphs with mixed types ofDecided to use "global" symmetries for now.Hyperedges
? See Hypergraph head symbol #494 (comment)"ordered" was added (needs to be discussed) because many functions in WFR made the distinction. See:
ToDo
HypergraphPlot
Hypergraph
(e.g.RandomHypergraph
)Examples
Hypergraph
("Ordered"
by default):Hypergraph
:Information
:This change is