How to align subgraphs in dot files - alignment

I am trying to align three or more subgraphs using dot files and graphviz. I think my problem is best shown using a few examples:
My first try:
digraph FutopJobFlow {
rankdir=LR;
node [shape=box]
compound=true
subgraph clusterA {label = " A ";
A -> a1;
a1 -> a2;
a2 -> a3;
}
subgraph clusterB {label = " B ";
B -> b1;
b1 -> b2;
}
subgraph clusterC {label = " C ";
C -> c1;
c1 -> c2;
}
A -> B [lhead=clusterB];
B -> C [lhead=clusterC];
X -> A [lhead=clusterA];
Y -> B [lhead=clusterB];
Z -> C [lhead=clusterC];
}
giving this result:
Here the individual subgraphs looks like i would like but the are not aligned. I therefore tried wit the command rank:
digraph FutopJobFlow {
rankdir=LR;
node [shape=box]
compound=true
subgraph clusterA {label = " A ";
A -> a1;
a1 -> a2;
a2 -> a3;
}
subgraph clusterB {label = " B ";
B -> b1;
b1 -> b2;
}
subgraph clusterC {label = " C ";
C -> c1;
c1 -> c2;
}
{rank=same; A; B; C;}
A -> B [lhead=clusterB];
B -> C [lhead=clusterC];
X -> A [lhead=clusterA];
Y -> B [lhead=clusterB];
Z -> C [lhead=clusterC];
}
which result in this graph:
Here the alignment looks good but now the 'A', 'B' and 'C' is no longer inside the subgraphs!
I have tried several other ways to achieve both the alignment and that 'A', 'B' and 'C' is inside their respective subgraphs but with no succes.
Can anybody help?
# Marapet - Thanks it is almost perfect now - it looks like this when i add the 'constraint=false' parameter:
Graph with constraint parameter
It would be perfect if the subgraph 'A' is above 'B' which again is above 'C'.

In the first version of your graph, you can disable the effect on node ranking for the edges between A-B and B-C by adding the attribute constraint=false:
A -> B [lhead=clusterB, constraint=false];
B -> C [lhead=clusterC, constraint=false];
The subgraphs should then be aligned.

Related

Incomplete structured construct at or before this point in pattern matching

So, I'm doing an assignment where I'm supposed to write a function that prints an image based on some a type, figure, which I have defined.
I'm to use this library and it's functions with my own .fsx file, which should then be compiled and able to create images, based on a descriptive "figure"-type ;
https://github.com/diku-dk/img-util-fs
My .fsx code looks like this;
type point = int * int
type color = ImgUtil.color
type figure =
| Circle of point * int * color
| Rectangle of point * point * color
| Mix of figure * figure
let rec colorAt (x,y) figure =
match figure with
| Circle ((cx,cy), r, col) ->
if (x-cx)*(x-cx)+(y-cy)*(y-cy) <= r*r
then Some col else None
| Rectangle ((x0,y0), (x1,y1), col) ->
if x0 <=x && x <= x1 && y0 <= y && y <= y1
then Some col else None
| Mix (f1, f2) ->
match (colorAt (x,y) f1, colorAt (x,y) f2) with
|(None , c) -> c
|(c, None) -> c
|(Some c1, Some c2) ->
let (a1 ,r1 ,g1 ,b1) = ImgUtil.fromColor c1
let (a2 ,r2 ,g2 ,b2) = ImgUtil.fromColor c2
in Some(ImgUtil.fromArgb ((a1+a2)/2, (r1+r2)/2,
(g1+g2)/2, (b1+b2)/2))
let figTest : figure =
Circle ((50,50), 45, ImgUtil.fromRgb(255,0,0))
Rectangle ((40,40), (90,110) ImgUtil.fromRgb (0,0,255))
let makePicture (name:string * x:figure * b:int * h:int) : unit =
let C = ImgUtil.mk b h
for i = 0 to h
do ImgUtil.setLine (ImgUtil.fromRgb(128,128,128)) (0,i) (b,i) C
for n = (0,0) to (b-1,h-1) do
match ImgUtil.getPixel n C with colorAt n x
| None -> (128,128,128)
| Some col -> colorAt n x
do imgUtil.toPngFile ("%A" name) C
do makePicture ("figTest" figTest 101 151)
But when I try to compile the library and my .fsx file I get the error
"8io.fsx(44.13): error FS0010: Incomplete structured construct at or before this point in pattern matching. Expected '->' or other token"
I'm fairly new to coding, and my code might not be usable, but it's the only compiling error I get, so I hope it's salvageable
I think the problem you're asking about is caused by this construct:
match ImgUtil.getPixel n C with colorAt n x
| None -> (128,128,128)
| Some col -> colorAt n x
The problem here is that colorAt n x appears unexpectedly between the with and the first |. A typical match expression should look more like this:
match ImgUtil.getPixel n C with
| None -> (128,128,128)
| Some col -> colorAt n x
Note: I haven't examined your code for correctness. This only addresses the specific syntactical issue identified by the compiler.

Purescript Union of Rows

I've been trying to develop a component system in Purescript, using a Component typeclass which specifies an eval function. The eval function for can be recursively called by a component for each sub-component of the component, in essence fetching the input's values.
As components may wish to use run-time values, a record is also passed into eval. My goal is for the rows in the Record argument of the top-level eval to be required to include all the rows of every sub-component. This is not too difficult for components which do not use any rows themselves, but their single sub-component does, as we can simply pass along the sub-components rows to the component's. This is shown in evalIncrement.
import Prelude ((+), one)
import Data.Symbol (class IsSymbol, SProxy(..))
import Record (get)
import Prim.Row (class Cons, class Union)
class Component a b c | a -> b where
eval :: a -> Record c -> b
data Const a = Const a
instance evalConst :: Component (Const a) a r where
eval (Const v) r = v
data Var (a::Symbol) (b::Type) = Var
instance evalVar ::
( IsSymbol a
, Cons a b r' r) => Component (Var a b) b r where
eval _ r = get (SProxy :: SProxy a) r
data Inc a = Inc a
instance evalInc ::
( Component a Int r
) => Component (Inc a) Int r where
eval (Inc a) r = (eval a r) + one
All of the above code works correctly. However, once I try to introduce a component which takes multiple input components and merges their rows, I cannot seem to get it to work. For example, when trying to use the class Union from Prim.Row:
data Add a b = Add a b
instance evalAdd ::
( Component a Int r1
, Component b Int r2
, Union r1 r2 r3
) => Component (Add a b) Int r3 where
eval (Add a b) r = (eval a r) + (eval b r)
The following error is produced:
No type class instance was found for
Processor.Component a3
Int
r35
while applying a function eval
of type Component t0 t1 t2 => t0 -> { | t2 } -> t1
to argument a
while inferring the type of eval a
in value declaration evalAdd
where a3 is a rigid type variable
r35 is a rigid type variable
t0 is an unknown type
t1 is an unknown type
t2 is an unknown type
In fact, even modifying the evalInc instance to use a dummy Union with an empty row produces a similar error, like so:
instance evalInc :: (Component a Int r, Union r () r1)
=> Component (Increment a) Int r1 where
Am I using Union incorrectly? Or do I need further functional dependencies for my class - I do not understand them very well.
I am using purs version 0.12.0
r ∷ r3 but it is being used where an r1 and r2 are required, so there is a type mismatch. A record {a ∷ A, b ∷ B} cannot be given where {a ∷ A} or {b ∷ B} or {} is expected. However, one can say this:
f ∷ ∀ s r. Row.Cons "a" A s r ⇒ Record r → A
f {a} = a
In words, f is a function polymorphic on any record containing a label "a" with type A. Similarly, you could change eval to:
eval ∷ ∀ s r. Row.Union c s r ⇒ a → Record r → b
In words, eval is polymorphic on any record which contains at least the fields of c. This introduces a type ambiguity which you will have to resolve with a proxy.
eval ∷ ∀ proxy s r. Row.Union c s r ⇒ proxy c → a → Record r → b
The eval instance of Add becomes:
instance evalAdd ∷
( Component a Int r1
, Component b Int r2
, Union r1 s1 r3
, Union r2 s2 r3
) => Component (Add a b) Int r3 where
eval _ (Add a b) r = eval (RProxy ∷ RProxy r1) a r + eval (RProxy ∷ RProxy r2) b r
From here, r1 and r2 become ambiguous because they're not determined from r3 alone. With the given constraints, s1 and s2 would also have to be known. Possibly there is a functional dependency you could add. I am not sure what is appropriate because I am not sure what the objectives are of the program you are designing.
As the instance for Var is already polymorphic (or technically open?) due to the use of Row.Cons, ie
eval (Var :: Var "a" Int) :: forall r. { "a" :: Int | r } -> Int
Then all we have to is use the same record for the left and right evaluation, and the type system can infer the combination of the two without requiring a union:
instance evalAdd ::
( Component a Int r
, Component b Int r
) => Component (Add a b) Int r where
eval (Add a b) r = (eval a r) + (eval b r)
This is more obvious when not using typeclasses:
> f r = r.foo :: Int
> g r = r.bar :: Int
> :t f
forall r. { foo :: Int | r } -> Int
> :t g
forall r. { bar :: Int | r } -> Int
> fg r = (f r) + (g r)
> :t fg
forall r. { foo :: Int, bar :: Int | r } -> Int
I think the downside to this approach compared to #erisco's is that the open row must be in the definition of instances like Var, rather than in the definition of eval? It is also not enforced, so if a Component doesn't use open rows then a combinator such as Add no longer works.
The benefit is the lack of the requirement for the RProxies, unless they are not actually needed for eriscos implementation, I haven't checked.
Update:
I worked out a way of requiring eval instances to be closed, but it makes it quite ugly, making use of pick from purescript-record-extra.
I'm not really sure why this would be better over the above option, feels like I'm just re-implementing row polymorphism
import Record.Extra (pick, class Keys)
...
instance evalVar ::
( IsSymbol a
, Row.Cons a b () r
) => Component (Var a b) b r where
eval _ r = R.get (SProxy :: SProxy a) r
data Add a b = Add a b
evalp :: forall c b r r_sub r_sub_rl trash
. Component c b r_sub
=> Row.Union r_sub trash r
=> RL.RowToList r_sub r_sub_rl
=> Keys r_sub_rl
=> c -> Record r -> b
evalp c r = eval c (pick r)
instance evalAdd ::
( Component a Int r_a
, Component b Int r_b
, Row.Union r_a r_b r
, Row.Nub r r_nub
, Row.Union r_a trash_a r_nub
, Row.Union r_b trash_b r_nub
, RL.RowToList r_a r_a_rl
, RL.RowToList r_b r_b_rl
, Keys r_a_rl
, Keys r_b_rl
) => Component (Add a b) Int r_nub where
eval (Add a b) r = (evalp a r) + (evalp b r)
eval (Add (Var :: Var "a" Int) (Var :: Var "b" Int) ) :: { a :: Int , b :: Int } -> Int
eval (Add (Var :: Var "a" Int) (Var :: Var "a" Int) ) :: { a :: Int } -> Int

neo4j: how to eliminate subpaths from the result

i want to return paths of size 0..4 starting from node a. but i want to return only the longest paths (skip subpaths). For graph:
a -> b - > c
|
| -> d
i'd like to return only a -> b -> c and a -> d but not a nor a -> b
edit
it means that if there is a path longer than 4, i still need the longest paths of size 0..4. so for:
a -> b -> c -> d -> e -> f
i'd like to get a -> b -> c -> d -> e
To get all paths up to length 4 that start at a root node and either end at a leaf node or have a length of 4:
MATCH path = (a)-[*0..4]->(b)
WHERE NOT ()-->(a) AND (LENGTH(path) = 4 OR NOT (b)-->())
RETURN path;
Reproducing with your sample data set:
CREATE (a:Node {name:"A"})-[:RELATION]->(b:Node {name:"B"})-[:RELATION]->(c:Node {name:"C"}),
(a)-[:RELATION]->(d:Node {name:"D"})
You can restrict the returned paths doing a WHERE this way:
match path = (a)-[*0..4]->(b)
where not ()-->(a) and not (b)-->()
return path
The output will be:
╒═══════════════════════════════════════════════════════════╕
│"path" │
╞═══════════════════════════════════════════════════════════╡
│[{"name":"A"},{},{"name":"B"},{"name":"B"},{},{"name":"C"}]│
├───────────────────────────────────────────────────────────┤
│[{"name":"A"},{},{"name":"D"}] │
└───────────────────────────────────────────────────────────┘

Vertically aligning a node joining subgraphs in Graphviz

I give the following input to Dot:
digraph G {
subgraph cluster1 {
fontsize = 20;
label = "Group 1";
A -> B -> C -> D;
style = "dashed";
}
subgraph {
O [shape=box];
}
subgraph cluster2 {
fontsize = 20;
label = "Group 2";
Z -> Y -> X -> W [dir=back];
style = "dashed";
}
D -> O [constraint=false];
W -> O [constraint=false, dir=back];
}
And it produces:
How can I align node O so that it has the same rank as D and W? That is, a graph that looks like:
A Z
| |
B Y
| |
C X
| |
D-O-W
Adding
{ rank=same; D; O; W; }
yields the error
Warning: D was already in a rankset, ignored in cluster G
Warning: W was already in a rankset, ignored in cluster G
I'm thinking I can hack it by adding invisible nodes and edges to the subgraph of O, but I was wondering if I was missing some Dot magic.
You could use an approach with rankdir=LR and use constraint=false for the edges inside the clusters:
digraph G {
rankdir=LR;
subgraph cluster1 {
fontsize = 20;
label = "Group 1";
rank=same;
A -> B -> C -> D [constraint=false];
style = "dashed";
}
subgraph cluster2 {
fontsize = 20;
label = "Group 2";
rank=same;
Z -> Y -> X -> W [dir=back, constraint=false];
style = "dashed";
}
O [shape=box];
D -> O -> W;
}
It's not dot magic :-), but it achieves this:
Hacking with invisible nodes does also work:
digraph G {
subgraph cluster1 {
fontsize = 20;
label = "Group 1";
A -> B -> C -> D;
style = "dashed";
}
subgraph {
O1[style=invis];
O2[style=invis];
O3[style=invis];
O [shape=box];
O1 -> O2 -> O3 -> O [style=invis];
}
subgraph cluster2 {
fontsize = 20;
label = "Group 2";
Z -> Y -> X -> W [dir=back];
style = "dashed";
}
edge[constraint=false];
D -> O -> W;
}
The result is almost identical:

How to match multiple copies of a value?

F#'s pattern matching is very powerful so it felt natural to write:
match (tuple1, tuple2) with
| ((a, a), (a, a)) -> "all values are the same"
| ((a, b), (a, b)) -> "tuples are the same"
| ((a, b), (a, c)) -> "first values are the same"
// etc
However, the first pattern match gives a compiler error:
'a' is bound twice in this pattern
Is there a cleaner way to do it than the following?
match (tuple1, tuple2) with
| ((a, b), (c, d)) when a = b && b = c && c = d -> "all values are the same"
| ((a, b), (c, d)) when a = c && b = d -> "tuples are the same"
| ((a, b), (c, d)) when a = c -> "first values are the same"
// etc
This is a perfect use case for F#'s "active patterns". You can define a couple of them like this:
let (|Same|_|) (a, b) =
if a = b then Some a else None
let (|FstEqual|_|) ((a, _), (c, _)) =
if a = c then Some a else None
And then clean up your pattern matching with them; note how the first case (where all values are equal) uses the nested Same pattern to check that the first and second elements of the tuple are equal:
match tuple1, tuple2 with
| Same (Same x) ->
"all values are the same"
| Same (x, y) ->
"tuples are the same"
| FstEqual a ->
"first values are the same"
| _ ->
failwith "TODO"
Performance tip: I like to mark simple active patterns like these with inline -- since the logic within the active patterns is simple (just a few IL instructions), it makes sense to inline them and avoid the overhead of a function call.
You can use parameterized active patterns to remedy the issue.
let (|TuplePairPattern|_|) ((p1, p2), (p3, p4)) ((a, b), (c, d)) =
let matched =
[(p1, a); (p2, b); (p3, c); (p4, d)]
|> Seq.groupBy fst
|> Seq.map (snd >> Set.ofSeq)
|> Seq.forall (fun s -> Set.count s = 1)
if matched then Some () else None
Particularly, you should define a pattern in a form of literals (chars, strings, etc).
match tuple1, tuple2 with
| TuplePairPattern(('a', 'a'), ('a', 'a')) -> "all values are the same"
| TuplePairPattern(('a', 'b'), ('a', 'b')) -> "tuples are the same"
| TuplePairPattern(("a", "b"), ("a", "c")) -> "first values are the same"
// etc
I think, the most elegant way can be accomplished by combining two excellent answers provided by #Stephen Swensen and #pad.
The first idea is that the structure (a tuple containing two tuples) can be unpacked once, instead of doing it in every match case.
The second idea is working with sequences of values, all of which must be equal to each other.
Here's the code:
let comparer ((a,b),(c,d)) =
let same = Set.ofSeq >> Set.count >> ((=) 1)
if same[a; b; c; d] then "all values are the same"
elif same[a; c] && same[b; d] then "tuples are the same"
elif same[a; c] then "first values are the same"
else "none of above"
You may change elif's into a match, but does not seem feasible to me.
In practice, I would probably unpack the tuples up-front and then do a series of if / then / else expressions:
let a,b = tuple1
let c,d = tuple2
if a = b && b = c && c = d then "all values are the same"
elif a = c && b = d then "tuples are the same"
elif a = c then "first values are the same"
...
If you find yourself doing this frequently, an active pattern might be warranted (and in the case of 2-tuples, a complete active pattern would be doable and likely preferable - exhaustive matches are "safer" than non-exhaustive matches). Or, perhaps you need a more sophisticated data structure.

Resources