I looked here in many other questions, but none of them do what I want, some rely on messing with lots of settings totally unrelated to the cluster itself, and hoping it will end where you want.
Basically I want a cluster to be the last one, no matter what, like the "rank=sink" option would do to a node, but to a cluster.
How I do that without resorting to mininum length edges and other ugly hacks?
EDIT: end I mean the end of the graph, the bottommost item on the default direction, or rightmost item in the LR one.
I am unaware of anything as nice as rank=... However, This works pretty well:
Embed "everything else" within a (new) cluster. add peripheries=0 if you like
Create 1 or more invisible edges from nodes near the bottom of the "everything else" cluster to nodes near the top of the "end" cluster
digraph {
subgraph cluster0{
peripheries=0
a->b->c->d->e->f
}
subgraph cluster1{
x1->x2
}
f->x1 [style=dashed ]
}
Related
I've read many blog posts, articles, presentation and videos, even inspected V8's source code, both the bytecode generator, the sea-of-nodes graph generator and the optimization phases, and still couldn't find an answer.
V8's optimizing compiler, TurboFan, uses an IR of type "sea of nodes". All of the academic articles I found about it says that it's basically a CFG combined with a data-flow graph, and as such has two type of edges to connect nodes: data edges and control edges. Basically, if you take only the data edges you form a data-flow graph while if you choose the control edges you get a control flow graph.
However, TurboFan has one more edge type: "effect edges" (and effect phis). I suppose that this is what this slide means when it says that this is not "sea" of nodes but "soup" of nodes, because I couldn't find this term anywhere else. From what I understood, effect edges help the compiler keep the structure of statements/expressions that if reordered will have a visible side-effect. The example everyone uses is o.f = o.f + 1: the load has to come before the store (or we'll read the new value), and the addition has to come before the store, too (or otherwise we'll store the old value and uselessly increment the result).
But I cannot understand: isn't this the goal of control edges? From searching through the code I can see that almost every node has an effect edge and a control edge. Their uses isn't obvious though. From what I understand, in sea of nodes you use control edges to constrain evaluation order. So why do we need both effect and control edges? Probably I'm missing something fundamental, but I can't find it.
TL;DR: What's the use of effect edges and EffectPhi nodes, and how they're different from control edges.
Great thanks.
The idea of a sea-of-nodes compiler is that IR nodes have maximum freedom to move around. That's why in a snippet like o.f = o.f + 1, the sequence load-add-store is not considered "control flow". Only conditions and branches are. So if we slightly extend the example:
if (condition) {
o.f = o.f + 1;
} else {
// something else
}
then, as you describe in the question, effect dependencies ensure that load-add-store are scheduled in this order, and control dependencies ensure that all three operations are only performed if condition is true (technically, if the true-branch of the if-condition is taken). Note that this is important even for the load; for instance, o might be an invalid object if condition is false, and attempting to load its f property might cause a segfault in that case.
I have a large, but not really huge(?) graph, with 13 subgraph clusters containing about 100 nodes and 3,147 edges.
Dot crashes on Windows and seg faults on Linux.
This question suggests that the solution is to use neato, rather than dot.
But, this page says
Please note there are some quirks here ... only the DOT and FDP layout methods seem to support subgraphs
My output is a huge, black ball of spaghetti, no matter how far I zoom in. So I removed all of the messages but one, and that showed that the subgrphs appear to be drawn nested in each other.
They are absolutely not nested in the source file; here's a sample, with commercially sensitive names changed:
digraph G {
labelloc="t"; // place the label at the top (b seems to be default)
label="XXX message passing";
rankdir = "LR"
newrank = "true"
subgraph cluster_AAA {
label="AAA"
rank="same"
AAA_1
}
subgraph cluster_BBB {
label="BBB"
rank="same"
BBB_1
BBB_2
}
subgraph cluster_CCC {
label="CCC"
rank="same"
CCC_1
CCC_2
CCC_3
}
That certainly seems to be syntactically correct (the edges follow after).
So, it seems like that linked page was correct:
only the DOT and FDP layout methods seem to support subgraphs
BUT, it also seems like I need neato for a large graph.
What are my options?
[Updtae] I ran fdp and got the following error message
Error: node "xxx" is contained in two non-comparable clusters "AAA" and "BBB"
That seems to give a clue. Is it really the case that a node name may not be used in two clusters?
If so, the solution would seem to be to precede the node names with the cluster name ...
so I do not have a general solution to solve your problem.
But have you had a look at "mars"?
It's a command line tool designed specifically for the use of graphviz programs with very large graphs.
You can find it here: https://github.com/marckhoury/mars
I'm looking for a way to disable edge routing during rendering of dot graphs.
Ideally this would be a per-edge option, but disabling routing altogether would be helpful as well.
The graphs I'm generating represent syntax trees with additional edges from the usage of an identifier to its declaration as shown below.
Simple DAST
Now, this is still mostly readable, but with larger graphs the blue edges get very confusing very quickly, since dot seems to love routing them all over the place.
Complex DAST
I would prefer if they just went in a straight (or curved) line between the two nodes, ignoring all overlap with nodes and other edges.
Unfortunately I've been unable to find a way to achieve this effect and honestly I doubt it is even possible.
A similar question has been asked before, but I decided to open a new one anyway due to the following reasons:
I don't require the nodes to stay in a fixed position
Apart from the blue edges, my graph is always a tree (no edge overlap to worry about)
Running dot in multiple passes is unfortunately not an option for me
The other question is over 6 years old, so maybe a feature was added since then
My attempts so far:
Added "overlap=true" to the graph settings
Added "overlap=true" to individual edges
Neither of these seems to have any effect whatsoever.
The file layout is pretty simple (excerpt):
digraph {
node [shape=Mrecord];
graph [ordering=out, overlap=true, nodesep=0.3, ranksep=1];
...
# ReferenceLiteral rec
node0 -> node40 [style=dashed, color=blue, constraint=false]
node0 [shape=box style=filled label="rec" fillcolor="#cccccc"]
...
# PortNode Record
node28:p0:s -> node40:n
node28:p1_0:s -> node7:n
node28 [label="{Record|{<p0>Name|{Elements|{<p1_0>1}}}}"]
...
# DeclarationLiteral rec
node40 [shape=box style=filled label="rec" fillcolor="#cccccc"]
...
}
First - I've looked through similar looking questions but they did not solve my problem, this is no repetition (I hope).
I'm building and programming a robot with an Arduino Nano that is supposed to solve a maze. It gets put somewhere in the maze and then has to find an item. The next time it is supposed to go straight to the item (it does not have to be the shortest way but no dead ends allowed).
It is not necessary to know the whole maze because as long as he has one way to the item it is good. As I said, I don't need the shortest way.
The maze is 2D, I just put black tape on a white table and the robot is supposed to use a line sensor to follow the lines.
There are no other sensors to orientate himself. First I thought of making an 2D array and each field of the maze a field in there. But since it's just a normal line sensor the robot doesn't know if a straight line is one or two fields long and the whole thing does not work.
I also tried DFS or something like that but a similar problem here. The maze is circular and how is the robot supposed to know the Node was already found before and it is the same?
It would be nice if anyone had an idea!
Although orientation is a little bit fuzzy it is possible by using the decisions. A decision has to be reproducable. It could be represented by a class:
public class Decision {
boolean[] directions = new boolean[2]; // 0 = left, 1 = straight, 2 = right
// at least 2 of them should be true or it is no decision
int path; // 0-2 to mark the current path
}
Create a stack of decisions.
If there is only one possible direction at the beginning (back doesn't count and is treated later), then move forward until you meet the first decision.
Push the decision with all possible directions on the stack.
Set path to the first possible direction and move that way.
If you end up with another decision: continue at 3.
If you find the token: abort, you found a reproducible way without dead-ends.
If it is a dead-end: return to the previous decision node (the first one one the way back) and continue with 6.
Pop the decision and try the next possible direction (set the new path and push the decision) and continue at 5.
Unless you have tried all directions, then move back another decision and continue with 6.
If there are no more decisions (the special case mentioned above, we went in the wrong direction at the beginning): move forward until you meet the first decision and continue at 3. This means you need another boolean variable to indicate if you should go backwards right at the beginning.
You have to be careful when coming back from left and want to try straight next you would have to turn left and don't go straight. So there is a little calculation involved.
The algorithm has a problem for loop shaped decisions if you start the wrong way at the beginning. I think this could be escaped by setting an upper boundary, e.g. if you still haven't found the token and met 30 decision nodes (going forward), then you are probably running in circles, so go back to start and now instead of trying the directions in increasing order, try them in decreasing order.
I was wondering if someone could help me understand this problem. I prepared a small diagram because it is much easier to explain it visually.
alt text http://img179.imageshack.us/img179/4315/pon.jpg
Problem I am trying to solve:
1. Constructing the dependency graph
Given the connectivity of the graph and a metric that determines how well a node depends on the other, order the dependencies. For instance, I could put in a few rules saying that
node 3 depends on node 4
node 2 depends on node 3
node 3 depends on node 5
But because the final rule is not "valuable" (again based on the same metric), I will not add the rule to my system.
2. Execute the request order
Once I built a dependency graph, execute the list in an order that maximizes the final connectivity. I am not sure if this is a really a problem but I somehow have a feeling that there might exist more than one order in which case, it is required to choose the best order.
First and foremost, I am wondering if I constructed the problem correctly and if I should be aware of any corner cases. Secondly, is there a closely related algorithm that I can look at? Currently, I am thinking of something like Feedback Arc Set or the Secretary Problem but I am a little confused at the moment. Any suggestions?
PS: I am a little confused about the problem myself so please don't flame on me for that. If any clarifications are needed, I will try to update the question.
It looks like you are trying to determine an ordering on requests you send to nodes with dependencies (or "partial ordering" for google) between nodes.
If you google "partial order dependency graph", you get a link to here, which should give you enough information to figure out a good solution.
In general, you want to sort the nodes in such a way that nodes come after their dependencies; AKA topological sort.
I'm a bit confused by your ordering constraints vs. the graphs that you picture: nothing matches up. That said, it sounds like you have soft ordering constraints (A should come before B, but doesn't have to) with costs for violating the constraint. An optimal algorithm for scheduling that is NP-hard, but I bet you could get a pretty good schedule using a DFS biased towards large-weight edges, then deleting all the back edges.
If you know in advance the dependencies of each node, you can easily build layers.
It's amusing, but I faced the very same problem when organizing... the compilation of the different modules of my application :)
The idea is simple:
def buildLayers(nodes):
layers = []
n = nodes[:] # copy the list
while not len(n) == 0:
layer = _buildRec(layers, n)
if len(layer) == 0: raise RuntimeError('Cyclic Dependency')
for l in layer: n.remove(l)
layers.append(layer)
return layers
def _buildRec(layers, nodes):
"""Build the next layer by selecting nodes whose dependencies
already appear in `layers`
"""
result = []
for n in nodes:
if n.dependencies in flatten(layers): result.append(n) # not truly python
return result
Then you can pop the layers one at a time, and each time you'll be able to send the request to each of the nodes of this layer in parallel.
If you keep a set of the already selected nodes and the dependencies are also represented as a set the check is more efficient. Other implementations would use event propagations to avoid all those nested loops...
Notice in the worst case you have O(n3), but I only had some thirty components and there are not THAT related :p