How to draw bidirectional graph in Graphviz ordering levels by distance from some specified node (BFS order) - graphviz

I have a graph in a form of an adjacency list. I want to draw it vertically and specify the root to be AA. I want to order the nodes in the levels by their BFS distance from the node AA (so in this case AA is on lavel 0 alone, JW HX MA KO are on level 1 etc...). How do I do that? Is there any automatic way? I don't want to specify levels manually by {rank=same; JW; HX; MA; KO;}...
The graph is below:
strict graph {
NV -- {ZV CG YB HX OY};
NU -- {DA MA OA DK};
VU -- {PS FX};
JW -- {AA MD};
RI -- {OY DG};
DG -- {TG RI DF EV KW};
PH -- {KW OW LT LZ};
KZ -- {ET QV CK MS};
IX -- {TS DO};
MS -- {LZ KZ};
IL -- {DO ET};
EJ -- {AV JY};
DK -- {NU CG};
YB -- {NV PS};
OA -- {YA NU};
DA -- {NU RG};
KO -- {AA TG};
RG -- {DF DA ZV MD LB};
MA -- {AA NU};
OW -- {DO PH};
KW -- {DG PH};
DO -- {IX IL CZ OW};
DF -- {RG DG};
TG -- {DG KO};
LB -- {RG FX};
HX -- {AA NV};
GB -- {AV XK};
CG -- {DK NV};
LT -- {AO PH};
FX -- {LB HY VU};
ET -- {IL KZ};
CK -- {UX KZ};
LZ -- {PH MS};
YA -- {JY OA};
TS -- {NO IX};
NO -- {TS};
XK -- {GB};
PS -- {EV VU YB};
AA -- {JW HX MA KO};
MD -- {JW RG};
JM -- {QV HY AO};
AV -- {EJ GB};
AO -- {JM LT};
JY -- {YA EJ};
OY -- {NV RI};
UX -- {CZ CK};
HY -- {JM FX};
EV -- {PS DG};
CZ -- {UX DO};
ZV -- {NV RG};
QV -- {JM KZ};
}

Unfortunately, dot on its own can't produce the graph you want. Dot's ranking algorithm is (almost) based on longest path instead of shortest path.
However, the Graphviz system also includes the dijkstra program (http://www.graphviz.org/pdf/dijkstra.1.pdf) that will annotate a graph with a distance attribute an a previous node attribute (along the shortest path) (Although the dijkstra algorithm differs from the BFS algorithm, I expect the results to be the same.)
As dot does not allow explicitly setting ranks (except for source and sink, some extra coding is needed to:
create subgraphs for the rank=same groupings
identify the "top" node - rank=source
set constraint=false on most edges (bidirectional graph causes dot to confuse ranks
set constraint=true on those edges that comprise shortest paths
The programming is done in gvpr (http://www.graphviz.org/pdf/gvpr.1.pdf), also included in the Graphviz package.
The gvpr program shortestPath.gvpr:
E{
$.constraint="false"; // default to false
}
BEG_G{
graph_t SG;
node_t aNode;
edge_t anEdge;
int D, oD, i, cnt;
float Df;
string tmpStr, pref="__addedSubg__";
string sameRank[], tok[int];
}
N{
if (hasAttr($, "dist") && $.dist!=""){
Df=(float)$.dist;
D=(int)Df; // convert to integer
$.Dist=D;
sameRank[D]=sprintf("%s %s", sameRank[D], $.name);
//print("// dist ", $.name, " ", $.dist, " ", D, " ", sameRank[D]);
if (hasAttr($, "prev") && $.prev!=""){
aNode=node($G, $.prev);
anEdge=edge(aNode, $, "");
// anEdge.constraint="true";
}
}
}
BEG_G{
}
N{
if (hasAttr($, "prev") && $.prev!=""){
aNode=node($G, $.prev);
if ($.Dist==aNode.Dist+1){
anEdge=edge(aNode, $, "");
anEdge.constraint="true";
}
}
}
END_G{
for (sameRank[D]){
print("// D SAME ", D, " ", sameRank[D]);
tmpStr=sprintf("%s%i", pref, D);
SG=subg($G, tmpStr);
if (D==0)
SG.rank="source";
else
SG.rank="same";
unset(tok);
cnt=tokens(sameRank[D], tok);
for (tok[i]){
aNode=node($G, tok[i]);
subnode(SG, aNode);
}
}
}
And a (Linux) command line of:
dijkstra -p AA autoRank0.gv|gvpr -c -f shortestPath.gvpr|dot -Tpng >oo.png
Giving:

Related

Top-left to bottom-right tree in Graphviz

Say I start with this:
graph {
graph [splines=ortho]
node [fontname="Sans-Serif" shape=record]
rankdir=LR
"Parent" -- "Child 1"
"Parent" -- "Child 2"
"Parent" -- "Child 3"
"Parent" -- "Child 4 and then some"
}
This yields:
What do I need to change to get this instead (and so on for subequent levels)?
Thanks!
Surprisingly difficult. Ortho replaced by DIY ortho-like edges, using pseudo-invisible nodes.
graph {
// note: renaming the nodes was optional
graph [splines=false ] // was ortho
node [fontname="Sans-Serif" shape=rect ] // record features unused
rankdir=LR // ranks are now vertical!
{ // non-visible nodes (i1 i2 i3 i4) used to connect edges
rank=same
node [label="" peripheries=0] // keep same size as other nodes,
// but do not draw (peripheries)
edge [headclip=false tailclip=false] // draw center-to-center
i1:c -- i2:c -- i3:c -- i4:c
}
{node [group=T] P C1} //group used to place "child 1" w/ parent
P [label="Parent"]
{
rank=same
C1 [label="Child 1"]
C2 [label="Child 2"]
C3 [label="Child 3"]
C4 [label="Child 4 and then some"]
}
P -- i1 [headclip=false]
edge [tailclip=false]
i1 -- C1
i2 -- C2
i3 -- C3
i4 -- C4
}
Giving:

Freemarker trimming right spaces not working

I will be as simple as possible , i have the below template.ftl
B E G L E I T Z E T T E L Intern
FUER DATEI: ${content.fileName}
--------------------------------------------------------------------------------
BELEGLOSER DATENTRAEGERAUSTAUSCH
ERZ. SYSTEM: ${content.system}
INITIATOR: ${content.initiator}
DATEI ID: ${content.fileID}
And i want to output :
B E G L E I T Z E T T E L Intern
FUER DATEI: FileName
--------------------------------------------------------------------------------
BELEGLOSER DATENTRAEGERAUSTAUSCH
ERZ. SYSTEM: SYSTEMX
INITIATOR: Initiator
DATEI ID: FileID
But what i get instead ... let's say for the above example is :
B E G L E I T Z E T T E L Intern
FUER DATEI: FileName
--------------------------------------------------------------------------------
BELEGLOSER DATENTRAEGERAUSTAUSCH
ERZ. SYSTEM: SYSTEMX
INITIATOR: Initiator
DATEI ID: FileID
In other words the column is not properly aligned
How can i fix this problem in FreeMarker :) ?
Add <#rt> for trimming right spaces
B E G L E I T Z E T T E L Intern
FUER DATEI: ${content.fileName}<#rt>
--------------------------------------------------------------------------------
BELEGLOSER DATENTRAEGERAUSTAUSCH
ERZ. SYSTEM: ${content.system}<#rt>
INITIATOR: ${content.initiator}<#rt>
DATEI ID: ${content.fileID}<#rt>
rt (for right trim): Ignore all trailing white-space in this line.
Notice to add new lines between lines, for example:
B E G L E I T Z E T T E L Intern
FUER DATEI: ${content.fileName}<#rt>
--------------------------------------------------------------------------------
Here is the answer , i used something not very complex:
<#assign lineWidth = 80>
B E G L E I T Z E T T E L Intern
<#compress>FUER DATEI: </#compress>${content.fileName?left_pad(lineWidth-"FUER DATEI:"?length," ")}
--------------------------------------------------------------------------------
BELEGLOSER DATENTRAEGERAUSTAUSCH
<#compress>ERZ. SYSTEM: </#compress>${content.system?left_pad(lineWidth-"ERZ. SYSTEM:"?length," ")}
<#compress>INITIATOR: </#compress>${content.initiator?left_pad(lineWidth-"INITIATOR:"?length," ")}
<#compress>DATEI ID: </#compress>${content.fileID?left_pad(lineWidth-"DATEI ID:"?length," ")}
So let's take the 3 first lines of code :
<#assign lineWidth = 80>
B E G L E I T Z E T T E L Intern
<#compress>FUER DATEI: </#compress>${content.fileName?left_pad(lineWidth-"FUER DATEI:"?length," ")}
1. Firstly i assign a variable lineWidth which represents the maximum line width of the file.
2. Then for each line i eat all the spaces using <#compress>
3. Then i added the value and left added the needed spaces in a way that everything aligns right.
----- BOSS LEVEL BELOW - using functions -----
<#assign lineWidth = 80>
<#function createLine prefix value >
<#return prefix + value?left_pad(lineWidth - prefix?length," ")>
</#function>
B E G L E I T Z E T T E L Intern
${createLine("FUER DATEI:",content.fileName)}
--------------------------------------------------------------------------------
BELEGLOSER DATENTRAEGERAUSTAUSCH
${createLine("ERZ. SYSTEM:",content.system)}
${createLine("INITIATOR:",content.initiator)}
${createLine("DATEI ID:",content.fileID)}
${createLine("SAMMELREFERENZ ID:",content.referenceID)}
${createLine("RSTELLUNGSDATUM:",content.creationDate)}

Graphviz: drawing nodes in given order to correctly draw tree

I'm trying to draw a tree but have a problem with the following approach:
Use of 'invisible' nodes to connect levels of tree,
Use 'rank same' to draw nodes on the same level
Using this code I get following result
graph G{
edge [arrowhead = none];
splines = ortho;
rankdir = LR;
node [ shape="box" fixedsize = true width = 4 height = 1];
{ rank = same; "C" }
{ rank = same;
"B"
"A"
}
{ rank = same;
"F"
"D"
"E"
}
node [ shape="cricle" width = 0 height = 0 style=invis];
{ rank = same;
"B_Inv_Parent_1"
"C_Inv_Even_Children_0"
"A_Inv_Parent_1"
}
{ rank = same;
"F_Inv_Parent_2"
"D_Inv_Parent_2"
"A_Inv_Even_Children_1"
"E_Inv_Parent_2"
}
"C" -- "C_Inv_Even_Children_0";
"B_Inv_Parent_1" -- "C_Inv_Even_Children_0" -- "A_Inv_Parent_1";
"B_Inv_Parent_1" -- "B";
"A_Inv_Parent_1" -- "A";
"B" -- "F_Inv_Parent_2";
"F_Inv_Parent_2" -- "F";
"A" -- "A_Inv_Even_Children_1";
"D_Inv_Parent_2" -- "A_Inv_Even_Children_1" -- "E_Inv_Parent_2";
"D_Inv_Parent_2" -- "D";
"E_Inv_Parent_2" -- "E";
}
I have a problem in the 3rd level: D is drawn on top of the picture thus making a connection with E not ideal.
I would like to have the same results as with C, B and A.
I think the problem is with the order of nodes definition however, I can't manage to get it working whatever order I define them in.
Can anyone spot another problem with my code and suggest a fix?
I have cleaned up your code and re-arranged a few lines - after all, I think that introducing
F_Inv_Parent_2 -- D_Inv_Parent_2 -- A_Inv_Even_Children_1 -- E_Inv_Parent_2;
has been the key. You don't need to define edge arrows since you don't have a directed graph, and there is a typo in shape="cricle".
Here my edited version
graph G
{
splines = ortho;
rankdir = LR;
// node definitions
node [ shape="box" fixedsize = true width = 4 height = 1];
C
{ rank = same; B A }
{ rank = same; F D E }
node [ shape="point" width = 0 height = 0 ];
{ rank = same;
B_Inv_Parent_1
C_Inv_Even_Children_0
A_Inv_Parent_1 }
{ rank = same;
F_Inv_Parent_2
D_Inv_Parent_2
A_Inv_Even_Children_1
E_Inv_Parent_2 }
// edges
C -- C_Inv_Even_Children_0;
B_Inv_Parent_1 -- C_Inv_Even_Children_0 -- A_Inv_Parent_1;
B_Inv_Parent_1 -- B -- F_Inv_Parent_2;
A_Inv_Parent_1 -- A -- A_Inv_Even_Children_1;
F_Inv_Parent_2 -- D_Inv_Parent_2 -- A_Inv_Even_Children_1 -- E_Inv_Parent_2;
F_Inv_Parent_2 -- F;
D_Inv_Parent_2 -- D;
E_Inv_Parent_2 -- E;
}
and the result:
EDIT: I may have misunderstood your intention how you want to connect the third level - if so, replace
F_Inv_Parent_2 -- D_Inv_Parent_2 -- A_Inv_Even_Children_1 -- E_Inv_Parent_2;
with
F_Inv_Parent_2 -- D_Inv_Parent_2[ style = invis ];
D_Inv_Parent_2 -- A_Inv_Even_Children_1 -- E_Inv_Parent_2;
which gives you
EDIT No. 2, in response to yr comment:
Adding weight to the edge helps straightening it - I give the full code even though only two lines have changed (plus comments), for easier copy & paste:
graph G
{
splines = ortho;
rankdir = LR;
// node definitions
node [ shape="box" fixedsize = true width = 4 height = 1];
C
{ rank = same; B A }
{ rank = same; F D E }
node [ shape="point" width = 0 height = 0 ];
{ rank = same;
B_Inv_Parent_1
C_Inv_Even_Children_0
A_Inv_Parent_1 }
{ rank = same;
F_Inv_Parent_2
D_Inv_Parent_2
A_Inv_Even_Children_1
E_Inv_Parent_2 }
// edges
C -- C_Inv_Even_Children_0;
B_Inv_Parent_1 -- C_Inv_Even_Children_0 -- A_Inv_Parent_1;
// add extra weight to the continouous connection between four levels:
B_Inv_Parent_1 -- B -- F_Inv_Parent_2 -- F[ weight = 10 ];
// no weight here:
A_Inv_Parent_1 -- A -- A_Inv_Even_Children_1;
F_Inv_Parent_2 -- D_Inv_Parent_2[ style = invis ];
D_Inv_Parent_2 -- A_Inv_Even_Children_1 -- E_Inv_Parent_2;
// F_Inv_Parent_2 -- F; ### moved
D_Inv_Parent_2 -- D;
E_Inv_Parent_2 -- E;
}
Which gives you the disired straight line from B via F_Inv_Parent_2 to F which is actually the grandchild:

Grouping Edges in DOT (Graphviz)

Is there a way to group edges together into a single bus in DOT/Graphviz, while still fraying the edges near nodes?
Eg:
Changing this:
graph my_graph {
rankdir=LR
A -- B;
A -- B;
A -- B;
A -- B;
A -- B;
A -- B;
A -- B;
A -- B;
A -- B;
A -- C;
}
into something like this:
One way to do it is with dummy [shape=point] nodes, like so:
graph my_graph {
rankdir=LR;
{rank = same; B; C;}
aa [ shape=point ];
bb [ shape=point ];
A -- aa;
A -- aa;
A -- aa;
A -- aa;
A -- aa;
A -- aa;
A -- aa;
A -- aa;
A -- aa;
aa -- bb [ penwidth=4.0];
bb -- B;
bb -- B;
bb -- B;
bb -- B;
bb -- B;
bb -- B;
bb -- B;
bb -- B;
bb -- B;
A -- C;
}
This has some downsides though:
it doubles the number of edges in your source file, and makes it hard to manage.
If you have head and tail labels, then you need to place them accordingly.
It mucks up your node ranks, so you have to manually adjust all the other nodes.
The frayed ends are still rounded and taking up a lot of space. This might be fixable by setting the splines attribute, but I haven't been able to get it to work (it seems like no multiple edges between two nodes are always shown as splines no matter what the value of splines is).
Another option:
There's also the concentrate attribute, but this will only collect lines going to the same point. It will not 1) fray ends or 2) increase line thickness to represent the bus:
graph my_graph {
rankdir=LR
concentrate=true;
A -- B;
A -- B;
A -- B;
A -- B;
A -- B;
A -- B;
A -- B;
A -- B;
A -- B;
A -- C;
}

Error in Eiffel implementation of Burnikel and Ziegler algorithm 2

I need another set of eyes to tell me what is wrong with my Eiffel implementation of Burnikel and Ziegler's division, specifically "Algorithm 2 - 3n/2n". The Eiffel feature is shown below. The type "like Current" is an ARRAYED_LIST [NATURAL_8]. In other words, the implementation uses digits (i.e. limbs) containing 8-bit values, so numbers are in base-256. A manual trace of a failing call follows. (Sorry the arguments are so large, but I cannot reproduce the error with shorter values.) Execution follows step 3b in this case.
Here's the problem. The algorithm seems to be fine to Step 5, where the remainder "r" ends up with more digits then the divisor. I believe the error is in step 3b, perhaps with the call to feature `ones' which is "supposed" to supply a value that is "Beta^n - 1". (Maybe I do not understand B&Z's "Beta^n" notation.
Here is the Eiffel code:
three_by_two_divide (a, a3, b: like Current): TUPLE [quot, rem: like Current]
-- Called by `two_by_one_divide'. It has similar structure as
-- `div_three_halves_by_two_halfs', but the arguments to this
-- function have type {JJ_BIG_NATURAL} instead of like `digit'.
-- See Burnikel & Zieler, "Fast Recursive Division", pp 4-8,
-- Algorithm 2.
require
n_not_odd: b.count >= div_limit and b.count \\ 2 = 0
b_has_2n_digits: b.count = a3.count * 2
a_has_2n_digits: a.count = a3.count * 2
local
n: INTEGER
a1, a2: like Current
b1, b2: like Current
tup: TUPLE [quot, rem: like Current]
q, q1, q2, r, r1: like Current
c, d: like Current
do
n := b.count // 2
-- 1) Split `a'
a1 := new_sub_number (n + 1, a.count, a)
a2 := new_sub_number (1, n.max (1), a)
-- 2) Split `b'.
b1 := new_sub_number (n + 1, b.count, b)
b2 := new_sub_number (1, n.max (1), b)
-- 3) Distinguish cases.
if a1 < b1 then
-- 3a) compute Q = floor ([A1,A2] / B1 with remainder.
if b1.count < div_limit then
tup := school_divide (a, b1)
else
tup := two_by_one_divide (a, b1)
end
q := tup.quot
r1 := tup.rem
else
-- 3b) Q = beta^n - 1 and ...
q := ones (n)
-- ... R1 = [A1,A2] - [B1,0] + [0,B1] = [A1,A2] - QB1.
r1 := a + b1
if n > 1 then
b1.shift_left (n)
else
b1.bit_shift_left (zero_digit.bit_count // 2)
end
r1.subtract (b1)
end
-- 4) D = Q * B2
d := q * b2
-- 5) R1 * B^n + A3 - D. (The paper says "a4".)
r1.shift_left (n)
r := r1 + a3 - d
-- 6) As long as R < 0, repeat
from
until not r.is_negative
loop
r := r + b
q.decrement
end
check
remainder_small_enough: r.count <= b.count
-- because remainder must be less than divisor.
end
Result := [q, r]
ensure
-- n_digit_remainder: Result.rem.count = b.count // 2
quotient_has_correct_count: Result.quot.count <= b.count // 2
end
In the trace, the arrow points to a line I believe is bad, but I don't know what to do with it. Here is the trace:
three_by_two_divide (a = [227,26,41,95,169,93,135,110],
a3 = [92,164,19,39],
b = [161,167,158,41,164,0,0,0])
n := b.count // 2 = 4
-- 1) Split `a'.
a1 := new_sub_number (n + 1, a.count, a) = [227,26,41,95]
a2 := new_sub_number (1, n.max (1), a) = [169,93,135,110]
-- 2) Split `b'.
b1 := new_sub_number (n + 1, b.count, b) = [161,167,158,41]
b2 := new_sub_number (1, n.max (1), b) = [164,0,0,0]
-- 3b) Q = beta^n -1 and ...
--> q := ones (4) = [255,255,255,255] <-- Is this the error?
-- ... R1 = [A1,A2] - [B1,0] + [0,B1].
r1 := a + b1 = [227,26,41,96,75,5,37,151]
b1.shift_left (n) = [161,167,158,41,0,0,0,0]
r1.subtract (b1) = [65,114,139,55,75,5,37,151]
d := q * b2 = [163,255,255,255,92,0,0,0]
r1.shift_left (n) = [227,25,135,184,172,220,37,151,0,0,0,0] -- too big!
r := r1 + a3 - d -= [227,25,135,184,8,220,37,152,0,164,19,39] -- too big!
I know this is long, but any help is appreciated.
I would suggest to check that r1 = [65,114,139,55,75,5,37,151] is still the same before doing r1.shift_left (n). There are two options:
d := q * b2 affects r1 while it should not. Most probably there is some aliasing, i.e. r1 is aliased with some other variable that is updated and this aliasing should be removed.
r1 is still the same after d := q * b2. The issue is with shift_left that fails to (re)initialize some data or uses global data that it should not.

Resources