Skip to content

Commit e53c8c9

Browse files
committed
Add DotEdgeWeightedDigraph and supporting methods
1 parent 8af98e6 commit e53c8c9

File tree

8 files changed

+230
-1
lines changed

8 files changed

+230
-1
lines changed

doc/display.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ gap> Splash(DotDigraph(RandomDigraph(4)));
102102
<ManSection>
103103
<Attr Name="DotDigraph" Arg="digraph"/>
104104
<Oper Name="DotColoredDigraph" Arg="digraph, vert, edge"/>
105+
<Oper Name="DotColoredEdgeWeightedDigraph" Arg="digraph, vert, edge, weight"/>
105106
<Oper Name="DotVertexLabelledDigraph" Arg="digraph"/>
106107
<Oper Name="DotVertexColoredDigraph" Arg="digraph, vert"/>
107108
<Oper Name="DotEdgeColoredDigraph" Arg="digraph, edge"/>
@@ -124,6 +125,13 @@ gap> Splash(DotDigraph(RandomDigraph(4)));
124125
are not the appropriate size, or have holes then the function will return
125126
an error.<P/>
126127

128+
<C>DotColoredEdgeWeightedDigraph</C> differs from <C>DotColoredDigraph</C>
129+
only in that the values given in the third list <A>weight</A> is used to
130+
label the weights of the edges of the graph when displayed. The list
131+
<A>weight</A> should be a list of equal length to the lists for vertex and
132+
edge colours. If the lists are not the appropriate size, or have holes,
133+
then the function will return an error.<P/>
134+
127135
<C>DotVertexColoredDigraph</C> differs from <C>DotDigraph</C> only in
128136
that the values in given in the list are used to color the vertices
129137
of the graph when displayed. The list for vertex colours should be
@@ -152,6 +160,8 @@ gap> Splash(DotDigraph(RandomDigraph(4)));
152160
The string returned by <C>DotDigraph</C> or
153161
<C>DotVertexLabelledDigraph</C> can be written to a file using
154162
the command <Ref Func="FileString" BookName="GAPDoc"/>.<P/>
163+
164+
See also <Ref Oper="DotEdgeWeightedDigraph"/>. <P/>
155165
<Example><![CDATA[
156166
gap> D := CompleteDigraph(4);
157167
<immutable complete digraph with 4 vertices>

doc/weights.xml

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,3 +364,70 @@ gap> RandomUniqueEdgeWeightedDigraph(IsEulerianDigraph, 5, 1 / 3);
364364
</Description>
365365
</ManSection>
366366
<#/GAPDoc>
367+
368+
<#GAPDoc Label="DotEdgeWeightedDigraph">
369+
<ManSection>
370+
<Oper Name="DotEdgeWeightedDigraph" Arg="digraph[, path][, colors]"/>
371+
<Returns>A string.</Returns>
372+
<Description>
373+
This operation produces a graphical representation of the edge-weighted
374+
digraph <A>digraph</A>, in <E>dot</E> format. Its output will be similar to
375+
that of <Ref Attr="DotDigraph"/>, but the diagram will also show the weights
376+
of the digraph's edges. <P/>
377+
378+
If the optional argument <A>path</A> is specified, it should be a list of
379+
lists describing a path in <A>digraph</A>, in the format described in <Ref
380+
Oper="DigraphPath"/>. If specified, the path's edges will be highlighted in
381+
the diagram, as will its start and end vertices. <P/>
382+
383+
If the optional argument <A>colors</A> is specified, it should be a record
384+
containing any of the following components:
385+
386+
<List>
387+
<Item>
388+
<A>vert</A>: the colour of ordinary vertices (default "grey");
389+
</Item>
390+
<Item>
391+
<A>edge</A>: the colour of ordinary edges (default "black");
392+
</Item>
393+
<Item>
394+
<A>highlight</A>: the colour of any edges on <A>path</A>, if any
395+
(default "blue");
396+
</Item>
397+
<Item>
398+
<A>source</A>: the colour of the first vertex in <A>path</A>, if any
399+
(default "yellowgreen");
400+
</Item>
401+
<Item>
402+
<A>dest</A>: the colour of the final vertex in <A>path</A>, if any
403+
(default "lightpink").
404+
</Item>
405+
</List>
406+
407+
Each value in the record should be a string representing a colour understood
408+
by the <C>GraphViz</C> software. For details about this format, see
409+
<URL>https://www.graphviz.org</URL>. If any of the above components are not
410+
specified, or if no <A>colors</A> argument is given, the default value will
411+
be used. <P/>
412+
413+
The output of this operation can be passed to <Ref Func="Splash"/> to
414+
attempt to display it graphically on the computer's screen. <P/>
415+
416+
<Example><![CDATA[
417+
gap> gr := EdgeWeightedDigraph([[2], [3], []], [[10], [15], []]);
418+
<immutable edge-weighted digraph with 3 vertices, 2 edges>
419+
gap> path := EdgeWeightedDigraphShortestPath(g, 2, 3);
420+
[ [ 2, 3 ], [ 1 ] ]
421+
gap> Print(DotEdgeWeightedDigraph(gr, path));
422+
//dot
423+
digraph hgn{
424+
node [shape=circle]
425+
1[color=gray, style=filled]
426+
2[color=yellowgreen, style=filled]
427+
3[color=lightpink, style=filled]
428+
1 -> 2[color=black, label=10]
429+
2 -> 3[color=blue, label=15]
430+
}]]></Example>
431+
</Description>
432+
</ManSection>
433+
<#/GAPDoc>

doc/z-chap5.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
<#Include Label="DigraphMinimumCut">
3636
<#Include Label="DigraphMinimumCutSet">
3737
<#Include Label="RandomUniqueEdgeWeightedDigraph">
38+
<#Include Label="DotEdgeWeightedDigraph">
3839
</Section>
3940

4041
<Section><Heading>Orders</Heading>

gap/display.gd

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
DeclareAttribute("DotDigraph", IsDigraph);
1212
DeclareOperation("DotColoredDigraph", [IsDigraph, IsList, IsList]);
13+
DeclareOperation("DotColoredEdgeLabelledDigraph",
14+
[IsDigraph, IsList, IsList, IsList]);
1315
DeclareOperation("DotVertexColoredDigraph", [IsDigraph, IsList]);
1416
DeclareOperation("DotEdgeColoredDigraph", [IsDigraph, IsList]);
1517
DeclareOperation("DotVertexLabelledDigraph", [IsDigraph]);

gap/display.gi

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,21 @@ function(D, vert, edge)
157157
fi;
158158
end);
159159

160+
InstallMethod(DotColoredEdgeLabelledDigraph,
161+
"for a digraph by out-neighbours and three lists",
162+
[IsDigraphByOutNeighboursRep, IsList, IsList, IsList],
163+
function(D, vert, edge, weight)
164+
local vert_func, edge_func;
165+
# See https://graphs.grevian.org/example
166+
if DIGRAPHS_ValidVertColors(D, vert)
167+
and DIGRAPHS_ValidEdgeColors(D, edge) then
168+
vert_func := i -> StringFormatted("[color={}, style=filled]", vert[i]);
169+
edge_func := {i, j} -> StringFormatted("[color={}, label={}]",
170+
edge[i][j], weight[i][j]);
171+
return DIGRAPHS_DotDigraph(D, [vert_func], [edge_func]);
172+
fi;
173+
end);
174+
160175
InstallMethod(DotVertexColoredDigraph,
161176
"for a digraph by out-neighbours and a list",
162177
[IsDigraphByOutNeighboursRep, IsList],

gap/weights.gd

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,9 @@ DeclareOperation("RandomUniqueEdgeWeightedDigraph",
5252
[IsFunction, IsPosInt, IsFloat]);
5353
DeclareOperation("RandomUniqueEdgeWeightedDigraph",
5454
[IsFunction, IsPosInt, IsRat]);
55+
56+
# 7. Drawing edge weighted digraphs
57+
DeclareOperation("DotEdgeWeightedDigraph", [IsDigraph]);
58+
DeclareOperation("DotEdgeWeightedDigraph", [IsDigraph, IsList]);
59+
DeclareOperation("DotEdgeWeightedDigraph", [IsDigraph, IsRecord]);
60+
DeclareOperation("DotEdgeWeightedDigraph", [IsDigraph, IsList, IsRecord]);

gap/weights.gi

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -895,3 +895,63 @@ DIGRAPHS_RandomEdgeWeightedDigraphFilt);
895895
InstallMethod(RandomUniqueEdgeWeightedDigraph,
896896
"for a function, a pos int, and a rational", [IsFunction, IsPosInt, IsRat],
897897
DIGRAPHS_RandomEdgeWeightedDigraphFilt);
898+
899+
#############################################################################
900+
# 7. Drawing edge weighted digraphs
901+
#############################################################################
902+
903+
InstallMethod(DotEdgeWeightedDigraph, "for a digraph",
904+
[IsDigraph],
905+
digraph -> DotEdgeWeightedDigraph(digraph, [[], []], rec()));
906+
907+
InstallMethod(DotEdgeWeightedDigraph, "for a digraph and a list",
908+
[IsDigraph, IsList],
909+
{digraph, path} -> DotEdgeWeightedDigraph(digraph, path, rec()));
910+
911+
InstallMethod(DotEdgeWeightedDigraph, "for a digraph and a record",
912+
[IsDigraph, IsRecord],
913+
{digraph, colors} -> DotEdgeWeightedDigraph(digraph, [[], []], colors));
914+
915+
InstallMethod(DotEdgeWeightedDigraph, "for a digraph, a list, and a record",
916+
[IsDigraph, IsList, IsRecord],
917+
function(digraph, path, colors)
918+
local default_colors, edge, vert, source, dest, name, vertColours,
919+
edgeColours, path_verts, path_edge_indices, path_length, i;
920+
921+
# Use default colours for any that aren't specified
922+
default_colors := rec(highlight := "blue",
923+
edge := "black",
924+
vert := "gray",
925+
source := "yellowgreen",
926+
dest := "lightpink");
927+
for name in RecNames(colors) do
928+
if IsBound(default_colors.(name)) then
929+
default_colors.(name) := colors.(name);
930+
else
931+
Error("3rd arg <colors> contains unsupported option named '", name, "'");
932+
fi;
933+
od;
934+
colors := default_colors;
935+
936+
# fill with basic colours
937+
vertColours := ListWithIdenticalEntries(DigraphNrVertices(digraph),
938+
colors.vert);
939+
edgeColours := List(OutNeighbours(digraph),
940+
outs_u -> List(outs_u, _ -> colors.edge));
941+
942+
# highlight the path
943+
path_verts := path[1];
944+
path_edge_indices := path[2];
945+
path_length := Length(path_edge_indices);
946+
if not IsEmpty(path_verts) then
947+
for i in [1 .. path_length] do
948+
edgeColours[path_verts[i]][path_edge_indices[i]] := colors.highlight;
949+
od;
950+
vertColours[path_verts[1]] := colors.source;
951+
vertColours[path_verts[path_length + 1]] := colors.dest;
952+
fi;
953+
954+
# draw with the weights as labels
955+
return DotColoredEdgeLabelledDigraph(digraph, vertColours, edgeColours,
956+
EdgeWeights(digraph));
957+
end);

tst/standard/weights.tst

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
#############################################################################
1010
##
1111

12-
#@local D, d, distances, edges, gr, m, parents, r, tree
12+
#@local D, d, distances, edges, gr, m, parents, path, r, tree
1313
gap> START_TEST("Digraphs package: standard/weights.tst");
1414
gap> LoadPackage("digraphs", false);;
1515

@@ -503,6 +503,74 @@ true
503503
gap> SortedList(Flat(EdgeWeights(D))) = [1 .. DigraphNrEdges(D)];
504504
true
505505
506+
#############################################################################
507+
# 7. Drawing edge-weighted digraphs
508+
#############################################################################
509+
510+
# Trivial example
511+
gap> gr := EdgeWeightedDigraph([[2], []], [[10], []]);;
512+
gap> Print(DotEdgeWeightedDigraph(gr));
513+
//dot
514+
digraph hgn{
515+
node [shape=circle]
516+
1[color=gray, style=filled]
517+
2[color=gray, style=filled]
518+
1 -> 2[color=black, label=10]
519+
}
520+
521+
# Cycle example
522+
gap> gr := EdgeWeightedDigraph(CycleDigraph(5), [[10], [4], [8], [2], [8]]);;
523+
gap> path := DigraphPath(gr, 3, 1);
524+
[ [ 3, 4, 5, 1 ], [ 1, 1, 1 ] ]
525+
gap> Print(DotEdgeWeightedDigraph(gr, path, rec(highlight := "red")));
526+
//dot
527+
digraph hgn{
528+
node [shape=circle]
529+
1[color=lightpink, style=filled]
530+
2[color=gray, style=filled]
531+
3[color=yellowgreen, style=filled]
532+
4[color=gray, style=filled]
533+
5[color=gray, style=filled]
534+
1 -> 2[color=black, label=10]
535+
2 -> 3[color=black, label=4]
536+
3 -> 4[color=red, label=8]
537+
4 -> 5[color=red, label=2]
538+
5 -> 1[color=red, label=8]
539+
}
540+
541+
# Large example
542+
gap> gr := EdgeWeightedDigraph(
543+
> [[5, 7], [5], [1, 3, 6], [1, 3], [4, 5], [1, 2], [6]],
544+
> [[8, 4], [12], [11, 2, 10], [3, 7], [9, 13], [1, 6], [5]]);
545+
<immutable edge-weighted digraph with 7 vertices, 13 edges>
546+
gap> path := EdgeWeightedDigraphShortestPath(gr, 1, 2);
547+
[ [ 1, 7, 6, 2 ], [ 2, 1, 2 ] ]
548+
gap> Print(DotEdgeWeightedDigraph(gr, path));
549+
//dot
550+
digraph hgn{
551+
node [shape=circle]
552+
1[color=yellowgreen, style=filled]
553+
2[color=lightpink, style=filled]
554+
3[color=gray, style=filled]
555+
4[color=gray, style=filled]
556+
5[color=gray, style=filled]
557+
6[color=gray, style=filled]
558+
7[color=gray, style=filled]
559+
1 -> 5[color=black, label=8]
560+
1 -> 7[color=blue, label=4]
561+
2 -> 5[color=black, label=12]
562+
3 -> 1[color=black, label=11]
563+
3 -> 3[color=black, label=2]
564+
3 -> 6[color=black, label=10]
565+
4 -> 1[color=black, label=3]
566+
4 -> 3[color=black, label=7]
567+
5 -> 4[color=black, label=9]
568+
5 -> 5[color=black, label=13]
569+
6 -> 1[color=black, label=1]
570+
6 -> 2[color=blue, label=6]
571+
7 -> 6[color=blue, label=5]
572+
}
573+
506574
#
507575
gap> DIGRAPHS_StopTest();
508576
gap> STOP_TEST("Digraphs package: standard/weights.tst", 0);

0 commit comments

Comments
 (0)