-
Notifications
You must be signed in to change notification settings - Fork 0
/
graph.spad
5638 lines (5161 loc) · 226 KB
/
graph.spad
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
)if false
\documentclass{article}
\usepackage{axiom}
\usepackage{url}
\newcommand{\File}[1]{\url{#1}}
\begin{document}
\title{graph theory related mathematical structures}
\author{Martin J Baker}
\maketitle
\begin{abstract}
Graphs, in addition to being interesting structures in their own
right, have importance in representing data structures, finite
automata, communication networks and so on.
A graph is a example of a mathematical entity which can be thought
of as a set together with a structure on that set. It can be drawn
in a way that is visually easy to understand and so is very
helpful in understanding such structures.
For more information and diagrams see:
\url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/}
\end{abstract}
\eject
\tableofcontents
\eject
\section{Notation}
This is an implementation mostly of finite directed graphs (finite
undirected graphs are possible by having arrows in both directions
or by using UndirectedGraph domain).
A graph has two parts:
\begin{itemize}
\item A set of 'vertices', 'objects' or 'nodes'.
\item A set of 'arrows' or 'edges'
\end{itemize}
I will treat all these alternative terms equivalently and may switch
between them in this document. I mostly use 'arrows' for directed
graphs and 'edges' for undirected. The term 'object' is sometimes
used to suggest that we ignore any internal structure in the object
but we use the term 'vertex' more generally.
We need definitions for other graph-related terminology such as
trees and forest and so on. There tend to be widely accepted
definitions for undirected graphs but there seem to be more
options and variations for these definitions as applied to
directed graphs.
I have therefore drawn up two sets of definitions in order to
make these issues clearer:
\subsection{Definitions for undirected graph}
\begin{itemize}
\item vertex
\item edge
\item graph
\item path or route - a sequence of alternating vertex and edges,
starting and ending with a vertex, where every edge connects the
nodes it is between. In certain circumstances we will specify a
path by its nodes only, or by its edges only, where this can be
done unambiguously.
\item connected graph - A graph where there is a path from every
vertex to every other vertex.
\item loop - a path from a vertex back to itself which does not
use other nodes or edges more than once.
\item tree - A graph which is connected and has no loops (adding
any edge to a tree will create a loop). Note : this is different
from Tree domain in pan-Axiom because no vertex is designated
as the root.
\item forest - A graph which has no loops (and in not necessarily
connected)(a disjoint union of trees).
\item spanning tree of G - A subgraph of G which is a tree and
contains all the vertices of G.
\item spanning forest of G - A subgraph of G which is a forest
and contains all the vertices of G.
\end{itemize}
\subsection{Definitions for directed graph}
\begin{itemize}
\item arrow - an edge with a specified direction
\item directed acyclic graph (DAG) - A graph without any cycles,
in a directed graph this is not necessarily a tree. A DAG defines
a partial order.
\item tree - This is where the definition starts to get more fuzzy
for the directed case. There are lots of sub-definitions:
\begin{itemize}
\item polytree - a directed graph with at most one undirected path
between any two vertices.
\item oriented tree - same as polytree
\item directed tree - a directed graph which would be a tree if
the directions on the arrows were ignored.
\item arborescence - arrows are all directed towards a particular
vertex, or all directed away from a particular vertex.
\item rooted tree - one vertex has been designated the root and
the arrows are all towards or all away from the root.
\item free tree - tree without any designated root.
\item tree-order - partial ordering on the vertices of a tree.
\end{itemize}
\end{itemize}
\section{Design Issues}
So far, only finite graphs are implemented, these all extend the
category FiniteGraph (FGRPH). It would be interesting to find ways
to encode repetitive or repeating structures in an efficient way,
to represent infinite graphs, but that is not implemented yet.
We allow:
\begin{itemize}
\item multiple arrows between the same vertices,
\item arrows from a vertex back to itself,
\item arrows may cross each other.
\end{itemize}
There are some disciplines where these are not allowed, for
example in homology theory there is the concept of
'planar graphs', but we don't yet support such constraints.
To support such structures the user would have to enforce such
constraints externally.
Currently, although graphs can be drawn in a plane, they are not
constrained to the plane in any way.
We have various implementations of FiniteGraph such as:
\begin{itemize}
\item DirectedGraph
\item UndirectedGraph
\item WeightedGraph
\item FunctionGraph
\item MultifunctionGraph
\end{itemize}
The purpose of these is described below:
\section{DirectedGraph and UndirectedGraph}
We start with the concept of a graph as a set of external 'objects'
(graph defined over a set of some type) together with pairs of
indices to represent the arrows.
Because the arrows are defined in terms of indices this means that the
order of the objects becomes important and therefore must be held in a
list/array rather than a set. The issue of list verses array is a
performance issue, more of that later.
For DirectedGraph then:
arrow(x, y) is not necessarily equal to arrow(y, x)
Whereas for UndirectedGraph then:
arrow(x, y) = arrow(y, x) so in searches we should always get a match
regardless of order.
Therefore these domains are represented in the same way, the
difference being whether order is taken into account when comparing
arrows.
In the case of UndirectedGraph, when we request a list of all arrows,
then the list will contain both arrow(x, y) and arrow(y, x) for
compatibility with DirectedGraph. That is:
An UndirectedGraph with arrow(x, y) is equivalent to:
A DirectedGraph with arrow(x, y) and arrow(y, x).
Both DirectedGraph and UndirectedGraph have additional information
for notation and for drawing diagrams as discussed below.
\section{WeightedGraph}
This domain is the same as directed graph except that each vertex
and each arrow has additional information (of category
OrderedAbelianMonoid) to represent its 'weight'. This is used for
route finding and related operations. Instead of choosing the route
with the lowest number of hops, this domain chooses the route with
the lowest overall weight. That is, the weight for a given route is
the sum of the weights associated with each vertex and each arrow
that the route passes through.
Currently, only the weights for the arrows and not the weights for
the vertices are used, I plan to correct this in the future.
\section{FunctionGraph and MultifunctionGraph}
The purpose of these domains is to use graphs to represent various
types of mapping, including endomaps, maps between different sets,
Cayley graphs, (and related stuff like Schreier coset graph,
graphs of permutations and so on). We can do various operations
such as the coAdjoint and contraAdjoint functions. In addition to
the graphs themselves representing maps we can also define each
individual arrow to represent a map (see second order graph
section below).
Because we are representing mappings we place two additional
constraints on the graph:
\begin{itemize}
\item We have a fixed number of outgoing arrows per vertex.
\item The ordering of outgoing arrows is significant.
\end{itemize}
To illustrate the second point imagine a Cayley graph with a
red arrow and a blue arrow leaving each node, now imagine if,
on one vertex, we swap the red and blue arrows, this would
completely change the structure being represented. Chances are
that it would no longer be a valid group. So ordering preservation
is very important.
These above constraints mean that these graphs are coded more
efficiently by using specific domains for them.
In 'FunctionGraph' each vertex has one outgoing arrow and In
'MultifunctionGraph' each vertex has exactly 'n' outgoing arrows
where 'n' is the same for every vertex.
They use a different representation where the arrow information
is directly associated with each vertex. As its name suggests
'FunctionGraph' can represent a function, a mapping where the
domain and codomain are the same finite set of objects over which
it is defined (endomap). 'MultifunctionGraph' can represent
multiple function graphs such as Cayley graphs. Although these are
special cases of the general graph, and could have used the general
coding it is more efficient coding them in this way. They have a
number of functions which are not applicable to the general case.
It seems to me that there is a complimentary coding of graph where
the arrows are a set of external objects and each node would be
defined as two lists of indices : a list of incoming nodes and a list
of outgoing nodes. I have not implemented this complimentary coding
because its more complicated and I can't think of a use for it.
\section{Extra information for Diagrams and Notation}
Now I come to a contentious issue, the
representation so far includes only the information required to
define the pure mathematical structures but there is other
information associated with graphs which helps to make it more
human understandable such as names for arrows and diagram
coordinates. I think this notational and graphical information
is very important because there are great benefits to human users
in being able to 'see' the structure in an accessible way. As a
general rule I think it is important to separate out these issues
and as far as I can I put the graphics stuff into the graphics
framework : 'scene.spad.pamphlet'. However, in this case, I have
not managed to separate out these issues.
I did consider creating a wrapper domain, which would be external
to the graph code, that would allow annotation and coordinate
information to be associated with a vertex.
\begin{verbatim}
objectWrapper(S)
....
Rep := Record(value : S, name : String, posX : NNI, posY : NNI)
\end{verbatim}
However, if we want to do this with arrow information (which we
do), then we would have to have a separate external arrow domain.
There might be some benefits to this but its also quite messy, if
we continue to use indexes then they have no meaning outside the
graph and if we specify to objects directly then there are
efficiency issues. If we do all that then, the Rep will be free of
annotation and coordinate information, but the graph code still
needs to know about coordinate information. For example, if we
are taking the product of two graphs, then we can combine the
coordinate of the two operands to generate useful coordinate
information for the product graph as a whole.
So, in the end, I could not separate out the graphical/annotation
information. It was just easier and more efficient to leave this
information in Rep even though it goes against certain principles.
There is another issue about what goes into Rep, at the moment only
certain combinations of graph type types are possible, for instance,
we can't have a function 'FunctionGraph' with weighted arrows, it
would be more general to allow all combinations of graph? If we do
then the memory usage goes up a bit but if we don't then we need
lots of combinations of domains:
\begin{itemize}
\item Weighted nodes + directed graph
\item Weighted arrows + directed graph
\item Weighted nodes + weighted arrows + directed graph
\item Weighted nodes + undirected graph
\item Weighted arrows + undirected graph
\item Weighted nodes + weighted arrows + undirected graph
\item Weighted nodes + function graph
\item ... and so on
\end{itemize}
There are other types of graph that I would like to experiment with,
for instance, what I think of as a multilevel graph which perhaps
could be implemented in equivalent ways:
\begin{itemize}
\item As a graph whose elements are themselves graphs, where the outer
graph can see inside (has arrows between the nodes of) the inner
graph.
\item As a set of graphs with mappings between them, where the whole
system is treated as a graph.
\item As a graph which also has arrows between the arrows.
\end{itemize}
How should these graph structures fit in and relate to the rest of
the Axiom code library? It seems to me that structures like Tree,
POSET/lattice are special cases of graph? Also there may be more
general structures like Closed Cartesian Category (CCC) that should
be categories in the code library?
\section{Possible Changes to Structure}
Currently we have various graph domains, for instance:
\begin{itemize}
\item DirectedGraph has a list of vertices together with the arrows
represented as pairs of indices, like this,
Rep := Record(objects : List OBJT, arrows : List ARROW)
This is closest to the usual definition of graphs.
\item MultifunctionGraph has the outgoing arrows together with
the vertices, like this,
Rep := Record(objects : List MFOBJT)
MFOBJT ==> Record(value : S, next : List NNI, .... )
\end{itemize}
The reason that I have used the second type is to allow graphs to
represent various types of mappings such as Cayley graphs. To do
this I would like the option to constrain graphs so that:
\begin{itemize}
\item We have a fixed number of outgoing arrows per vertex.
\item The order of outgoing arrows is significant.
\end{itemize}
Waldek has suggested that this representation could be more
efficient for all types of FiniteGraph, but without the constraints,
I want to keep a version of FiniteGraph with these constraints in
order to more efficiently represent various mappings including
Cayley graphs. I also want to be able to represent endomaps as
graphs and relate that to maps between graphs.
Waldek points out that such constraints are related to regular
graphs. There are various other regularity conditions and it
seems unnatural to single out the fixed number of outgoing arrows
condition and not the others.
So it seems to me that there are 3 possible representations of graph
under consideration:
\begin{itemize}
\item (1) as pairs of vertices (where each pair represents an arrow)
\item (2) as a list of records containing a vertex and a list of its
adjacent vertices.
\item (3) as adjacency matrix.
\end{itemize}
Option 2 does look like the coding that would use least memory? It
also looks like it would be easy to convert to the other forms? 2
seems like a version of 1 where, all the arrows with a given first
node are grouped together in a separate list. Also each record in 2
represents a row in the adjacency matrix. So it is a coding of
adjacency matrix that is more efficient for sparse matrix (many
vertices, few arrows) in that zeroes are not stored.
So I can see advantages to converting DirectedGraph to option 2 before we
try to find efficient algorithms for loop detection, route finding and
so on. However I do have some concerns so I'm not quite sure. It seems
like 1 is the canonical form of graph also there seems to be a partial
symmetry between vertices and arrows that gets lost in 2.
For instance,
\begin{itemize}
\item option 1 seems more efficient if we want to iterate through arrows
while doing some operation on vertices.
\item option 2 seems more efficient if we want to iterate through vertices
while doing some operation on arrows.
\end{itemize}
Perhaps when working on algorithms there may be possibilities for
simplification by swapping between these.
Also both Ralf and Franz have advocated putting arrow into a separate
domain (mainly as a way to have versions with/without notation and
coordinate info). Another motivation for Franz is for undirected
graphs and equality of edges is awkward otherwise.
Also Franz believe that the FiniteGraph category should not contain
specific methods/operations, only declarations common to all graphs,
and generic operations common to different graph domains can be outsourced
into packages.
\section{Wider Structure Issues}
There seem to be lots of structures that are special cases of
graph (can be represented and drawn as graphs with additional
restrictions) such as lists, trees,
POSET, lattice, groups.... Could this be coded in the category
structure in some way? It seems to cut across existing category
structure. Or would there just be coercions between these and graphs?
Also would it make sense to have more general categories? One
particular category that I would like to implement is closed Cartesian
category.
On this wiki page there is a box on the right "Graph families defined
by their automorphisms"
\url{http : //en.wikipedia.org/wiki/Regular_graph}
Could this make a suitable basis for subtypes of graph?
\section{Mutable and Non-mutable}
These graphs are mutable, this is because graph structures can be
very big, it would seem awkward and messy to insist that a very
big graph be entered on one line.
Beyond that I cant think of any particular reason to modify graphs
once they are constructed, although its possible such a requirement
could occur in the future.
\section{Performance Issues}
There is plenty of scope to improve the code. I have not tested how
well it scales up (in terms of memory usage and runtime) but I suspect
not very well at the moment. I think there is a lot of scope to
improve the algorithms used.
There is the issue (pointed out by Waldek) of using lists verses
arrays in Rep. If we are thinking about how well this would scale up
then I guess:
\begin{itemize}
\item mutable (using List) would be more efficient for constructing
very large graphs.
\item immutable (using array) would be more efficient for
deconstructing/using the graphs once they have been constructed.
\end{itemize}
I guess it would be nice to have both mutable and immutable graphs but
that would add even more permutations of domain types.
\section{To Do}
\begin{itemize}
\item Check out definitions of 'spanningForestNode' and
'spanningTreeArrow' to make sure there is no source of confusion.
\item At the moment the loop detection uses 'spanningForestNode'
as it is. I realise this is very inefficient (in terms of memory and
runtime), I want to improve the loop detection and routing algorithms
(perhaps use Floyd's algorithm or something line that) and not use
spanningForestNode for this purpose. Although I think
spanningForestNode should still be provided as it represents an
important concept.
\item Need to improve SVG output. Reduce crossing arrows and
overlapping of elements. Implement more sophisticated layout
algorithms.
\item I would like two-way graphical interaction by the user, so
for instance, a user could drag a vertex and its arrows would
move with it. This type of interaction is not possible by
writing code in SPAD.
\iten Use node weights, in addition to arrow weights, for routing.
\item I would also like to experiment with the connection between
(duality?) this code and the computing framework. That is use graphs
to implement finite-state machine, Turing machine, etc.
\end{itemize}
\section{Tutorial}
We will construct a graph over 'String'. If you don't care what
the graph is constructed over, then 'String' is a good choice,
as it allows us to use the string to name the nodes.
In (2) we create a minimal graph with 2 vertices "a" and "b" and
no arrows between them.
We can add additional vertices using 'addObject!' as in (3)
And we can add arrows as in (4) and (5)
\begin{verbatim}
(1) -> GS := DirectedGraph(String)
(1) DirectedGraph(String)
Type : Type
(2) -> hs := directedGraph(["a","b"])$GS
(2) "a","b"
Type : DirectedGraph(String)
(3) -> addObject!(hs,"c")$GS
(3) "a","b","c"
Type : DirectedGraph(String)
(4) -> addArrow!(hs,"alpha",1,2)
(4) "a","b","c"|"alpha":"a"->"b"
Type : DirectedGraph(String)
(5) -> addArrow!(hs,"alpha",2,3)
(5) "a","b","c"|"alpha":"a"->"b","alpha":"b"->"c"
Type : DirectedGraph(String)
\end{verbatim}
We now have a graph and we can check out various things about
it. When we refer to a vertex we do so by its index number so,
say we want to check if there is an arrow from "a" to "b", then
"a" is index 1 and "b" is index 2. So we do this in (6) which
confirms there is an arrow from "a" to "b". Note that, since
this is a directed graph, the result in the other direction
may be different as in (7).
\begin{verbatim}
(6) -> isDirectSuccessor?(hs, 1::NNI, 2::NNI)
(6) true
Type : Boolean
(7) -> isDirectSuccessor?(hs, 2::NNI, 1::NNI)
(7) false
Type : Boolean
\end{verbatim}
The graph generated so far does not have any information to help
us draw it out. If we want to tell it the position of the vertices
we have to construct it in a slightly different way. Now create
graph suitable for diagram:
\begin{verbatim}
(8) -> OBJT ==> Record(value : String, posX : NNI, posY : NNI)
Type : Void
(9) -> oba:OBJT := ["a",10,10]
(9) [value= "a",posX= 10,posY= 10]
Type : Record(value : String, posX : NonNegativeInteger,
posY : NonNegativeInteger)
(10) -> obb:OBJT := ["b",10,60]
(10) [value= "b",posX= 10,posY= 60]
Type : Record(value : String, posX : NonNegativeInteger,
posY : NonNegativeInteger)
(11) -> obc:OBJT := ["c",60,10]
(11) [value= "c",posX= 60,posY= 10]
Type : Record(value : String,
posX : NonNegativeInteger, posY : NonNegativeInteger)
(12) -> hs2 := directedGraph([oba, obb, obc])$GS
(12) "a","b","c"
Type : DirectedGraph(String)
(13) -> addArrow!(hs2,"alpha",1,2)$GS
(13) "a","b","c"|"alpha":"a"->"b"
Type : DirectedGraph(String)
(14) -> addArrow!(hs2,"beta",2,3)$GS
(14) "a","b","c"|"alpha":"a"->"b","beta":"b"->"c"
Type : DirectedGraph(String)
(15) -> diagramSvg("testGraph/testGraph1s1.svg",hs2,true)
Type : Void
\end{verbatim}
In the same way that other algebras have special elements like
"0" and "1" there are special elements in Graph which we can
construct as follows:
\begin{verbatim}
(16) -> T := terminal("a")$GS
(16) "a"|"loop":"a"->"a"
Type : DirectedGraph(String)
(17) -> I := initial()$GS
(17)
Type : DirectedGraph(String)
\end{verbatim}
Now lets explore the methods for combining the graphs, these include:
\begin{verbatim}
"+":(%,%) -> % Sum : disjoint union of nodes with arrows from
appropriate input
merge : (%, %) -> % Sum : union (not necessarily disjoint) of nodes
with arrows merged in from appropriate input, if arrow exists from
both inputs then it will be duplicated.
"*":(%,%) -> GRPHPROD Tensor product : the tensor product G*H of
graphs G and H is a graph such that the vertex set of G*H is the
Cartesian product V(G) x V(H); and any two vertices (u, u') and (v, v')
are adjacent in G x H if and only if u' is adjacent with v' and u is
adjacent with v.
cartesian : (%, %) -> GRPHPROD Cartesian product : the vertex set of
G o H is the Cartesian product V(G) x V(H) and any two vertices (u, u')
and (v, v') are adjacent in G o H if and only if either u = v and u' is
adjacent with v' in H, or u' = v' and u is adjacent with v in G.
\end{verbatim}
First lets construct a new graph to work with:
\begin{verbatim}
(18) -> hs3 := directedGraph(["x","y"])$GS
(18) "x","y"
Type : DirectedGraph(String)
(19) -> addArrow!(hs3,"beta",1,2)
(19) "x","y"|"beta":"x"->"y"
Type : DirectedGraph(String)
\end{verbatim}
We can construct the (tensor) product of this with our original graph
\begin{verbatim}
(20) -> hs4 := hs*hs3
(20)
["a","x"],["a","y"],["b","x"],["b","y"],["c","x"],["c","y"]|
"alpha*beta":["a","x"]->["b","y"],
"alpha*beta":["b","x"]->["c","y"]
Type : DirectedGraph(Product(String, String))
\end{verbatim}
Or the Cartesian product:
\begin{verbatim}
(21) -> hs5 := cartesian(hs2, hs3)
(21)
["a","x"],["a","y"],["b","x"],["b","y"],["c","x"],["c","y"]|
"beta#1":["a","x"]->["a","y"],
"alpha#1":["a","x"]->["b","x"],
"alpha#2":["a","y"]->["b","y"],
"beta#2":["b","x"]->["b","y"],
"beta#1":["b","x"]->["c","x"],
"beta#2":["b","y"]->["c","y"],
"beta#3":["c","x"]->["c","y"]
Type : DirectedGraph(Product(String, String))
(22) -> diagramSvg("testGraph/testGraph1s2.svg",hs5,true)
Type : Void
\end{verbatim}
In addition to outputing to a diagram we can also output other
information about the graph in matrix form:
The incidence matrix represents the graph by a matrix of size
|V| by |E|
where:
\begin{itemize}
\item V = number of vertices
\item E = number of edges
\item entry [vertex, arrow] = arrow endpoint
\item data (simplest case : 1 - incident, 0 - not incident).
\end{itemize}
\begin{verbatim}
(23) -> incidenceMatrix(hs5)
+1 0 0 0 0 0+
|1 0 0 0 0 0|
|0 1 0 0 0 0|
(23) |0 0 1 0 0 0|
|0 0 1 0 0 0|
|0 0 0 1 0 0|
+0 0 0 0 1 0+
Type : Matrix(NonNegativeInteger)
\end{verbatim}
The adjacency matrix is an n by n matrix A, where n is the number
of vertices in the graph. If there is an arrow from a vertex x to
a vertex y, then the element ax, y is 1 (or in general the number
of xy edges), otherwise it is 0. In computing, this matrix makes
it easy to find subgraphs, and to reverse a directed graph.
\begin{verbatim}
(24) -> adjacencyMatrix(hs5)
+0 0 0 0 0 0+
|1 0 0 0 0 0|
|1 0 0 0 0 0|
(24) |0 1 1 0 0 0|
|0 0 1 0 0 0|
+0 0 0 1 1 0+
Type : Matrix(NonNegativeInteger)
\end{verbatim}
The laplacian matrix also known as "Kirchhoff matrix" or "Admittance
matrix" where:
entry [i, j] =
\begin{itemize}
\item inDegree(vi) if i = j (number of incoming links)
\item -1 if i not = j and vi is adjacent to vj
\item 0 otherwise
\end{itemize}
Alternatively this is defined as D - A, where D is the diagonal
degree matrix. It contains both adjacency information and degree
information. There are other, similar matrices, that are also
called "Laplacian matrices" of a graph.
\begin{verbatim}
(25) -> laplacianMatrix(hs5)
+ 0 0 0 0 0 0+
|- 1 1 0 0 0 0|
|- 1 0 1 0 0 0|
(25) | 0 - 1 - 1 2 0 0|
| 0 0 - 1 0 1 0|
+ 0 0 0 - 1 - 1 2+
Type : Matrix(Integer)
\end{verbatim}
Distance matrices are related to adjacency matrices, with the
differences that:
\begin{itemize}
\item a) the latter only provides the information which vertices
are connected but does not tell about costs or distances between
the vertices and
\item b) an entry of a distance matrix is smaller if two elements
are closer, while "close" (connected) vertices yield larger entries
in an adjacency matrix.
\end{itemize}
\begin{verbatim}
(26) -> distanceMatrix(hs5)
+0 - 1 - 1 - 1 - 1 - 1+
|1 0 - 1 - 1 - 1 - 1|
(26) |1 - 1 0 - 1 - 1 - 1|
|2 1 1 0 - 1 - 1|
|2 - 1 1 - 1 0 - 1|
+3 2 2 1 1 0 +
Type : Matrix(Integer)
\end{verbatim}
\section{Second Order Graphs}
This software can model second order graphs, that is, graphs whose
vertices are also graphs. It can also use graphs to model various
types of mappings. This page shows the approach I am taking to these
things.
Second order graphs seems to be related to 2-category structures, see
[2] Wiki page about 2-categories. There may be other equivalent
structures:
\begin{itemize}
\item As a graph whose elements are themselves graphs, where the outer
graph can see inside (has arrows between the nodes of) the inner
graph.
\item As a set of graphs with mappings between them, where the whole
system is treated as a graph.
\item As a graph which also has arrows between the arrows.
\end{itemize}
To show how I have implemented this I have written the following
example. We construct 4 graphs of type INNER := DirectedGraph(String).
Then we construct an OUTER graph over these INNER graphs.
\begin{verbatim}
(1) -> INNER := DirectedGraph(String)
(1) DirectedGraph(String)
Type : Type
(2) -> P := directedGraph(["a","b","c","d"])$INNER
(2) "a","b","c","d"
Type : DirectedGraph(String)
(3) -> addArrow!(P,"alpha",1,2)
(3) "a","b","c","d"|"alpha":"a"->"b"
Type : DirectedGraph(String)
(4) -> addArrow!(P,"beta",1,3)
(4) "a","b","c","d"|"alpha":"a"->"b","beta":"a"->"c"
Type : DirectedGraph(String)
(5) -> addArrow!(P,"gamma",2,4)
(5) "a","b","c","d"|"alpha":"a"->"b","beta":"a"->"c",
"gamma":"b"->"d"
Type : DirectedGraph(String)
(6) -> addArrow!(P,"delta",3,4)
(6)
"a","b","c","d"|"alpha":"a"->"b","beta":"a"->"c",
"gamma":"b"->"d","delta":"c"->"d"
Type : DirectedGraph(String)
(7) -> Q := directedGraph(["x","y"])$INNER
(7) "x","y"
Type : DirectedGraph(String)
(8) -> addArrow!(Q,"alpha",1,2)
(8) "x","y"|"alpha":"x"->"y"
Type : DirectedGraph(String)
(9) -> R := directedGraph(["1","2"])$INNER
(9) "1","2"
Type : DirectedGraph(String)
(10) -> addArrow!(R,"alpha",1,2)
(10) "1","2"|"alpha":"1"->"2"
Type : DirectedGraph(String)
(11) -> S := directedGraph(["t"])$INNER
(11) "t"
Type : DirectedGraph(String)
(12) -> OUTER := DirectedGraph(INNER)
(12) DirectedGraph(DirectedGraph(String))
Type : Type
(13) -> ML := directedGraph([P, Q, R, S])$OUTER
(13) 1, 2, 3, 4
Type : DirectedGraph(DirectedGraph(String))
(14) -> addArrow!(ML,"alpha",1,2)
(14) 1,2,3,4|"alpha":1->2
Type : DirectedGraph(DirectedGraph(String))
(15) -> addArrow!(ML,"beta",1,3)
(15) 1,2,3,4|"alpha":1->2,"beta":1->3
Type : DirectedGraph(DirectedGraph(String))
(16) -> addArrow!(ML,"gamma",2,4)
(16) 1,2,3,4|"alpha":1->2,"beta":1->3,"gamma":2->4
Type : DirectedGraph(DirectedGraph(String))
(17) -> addArrow!(ML,"delta",3,4)
(17) 1,2,3,4|"alpha":1->2,"beta":1->3,"gamma":2->4,"delta":3->4
Type : DirectedGraph(DirectedGraph(String))
(18) -> diagramSvg("testGraph/testGraphml1.svg",ML,false)
Type : Void
\end{verbatim}
As you can see this OUTER graph is hard to display in text format on
the command line. However its easier to see what's going on when we
look at the diagram it produces.
So far the above diagram does not show how individual vertices in one
inner graph map to the individual vertices in another inner graph. To
do this we need to define these maps, this is done by using a 'List NNI'
where the 'nth entry in the list represents the 'from' index and its
value represents the 'to' index. We put this map as the last entry in
the 'addArrow!' calls below. To display this information we use a
variant of 'diagramSvg' called 'deepDiagramSvg' which looks inside
the arrows to see how individual inner vertices map as follows:
\begin{verbatim}
(19) -> ML2 := directedGraph([P, Q, R, S])$OUTER
(19) 1, 2, 3, 4
Type : DirectedGraph(DirectedGraph(String))
(20) -> addArrow!(ML2,"alpha",1,2,[1,2,1,2])
(20) 1,2,3,4|"alpha":1->2
Type : DirectedGraph(DirectedGraph(String))
(21) -> addArrow!(ML2,"beta",1,3,[1,2,1,2])
(21) 1,2,3,4|"alpha":1->2,"beta":1->3
Type : DirectedGraph(DirectedGraph(String))
(22) -> addArrow!(ML2,"gamma",2,4,[1,1])
(22) 1,2,3,4|"alpha":1->2,"beta":1->3,"gamma":2->4
Type : DirectedGraph(DirectedGraph(String))
(23) -> addArrow!(ML2,"delta",3,4,[1,1])
(23) 1,2,3,4|"alpha":1->2,"beta":1->3,"gamma":2->4,"delta":3->4
Type : DirectedGraph(DirectedGraph(String))
(24) -> deepDiagramSvg("testGraph/testGraphml2.svg",ML2,false)
Type : Void
\end{verbatim}
So the arrows now know about both the inner and the outer graphs.
The diagram can now 'see' inside the inner graphs.
We can now try the 'flatten' function. This takes a second order
graph, such as the one that we have already constructed and flatten
it into a first order graph.
\begin{verbatim}
(25) -> ML3 := flatten(ML2)$INNER
(25)
"a","b","c","d","x","y","1","2","t"|"alpha":"a"->"b",
"beta":"a"->"c","gamma":"b"->"d","delta":"c"->"d",
"alpha":"x"->"y","alpha":"1"->"2","alpha":"a"->"x",
"alpha":"b"->"y","alpha":"c"->"x","alpha":"d"->"y",
"beta":"a"->"1","beta":"b"->"2","beta":"c"->"1",
"beta":"d"->"2","gamma":"x"->"t","gamma":"y"->"t",
"delta":"1"->"t","delta":"2"->"t"
Type : DirectedGraph(String)
(26) -> diagramSvg("testGraph/testGraphml3.svg",ML3,false)
Type : Void
\end{verbatim}
The first order graph that we have constructed includes the arrows
from both the inner and the outer graphs.
As it stands there are a lot of limitations with the above code (it
is not completely general).
\begin{itemize}
\item It only works if the outer graph is of type
'DirectedGraph(DirectedGraph(String))' it would be better if it could
be more general such as any implementation of
'FiniteGraph(FiniteGraph(SetCategory))'.
\item The code also makes certain assumptions about the coordinate
ranges of the inner graphs and if this is not valid then the inner
diagrams may overlap the circles.
\end{itemize}
\section{Tutorial}
This graph framework has many methods to create graph instances, click on the following links for details:
\begin{itemize}
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/construct/index.htm#individual}
Constructing graphs by building up individual objects and arrows.
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/construct/index.htm#adjacency}
Constructing from adjacency matrix.
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/construct/index.htm#standard}
Constructing standard types.
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/product/index.htm}
Combining existing graphs using sum and product.
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/map/index.htm}
Mapping from an existing graph.
\end{itemize}
We now have a graph and we can check out various things about it by calling functions such as those listed below. Click on these function names for more information:
\begin{itemize}
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/viewing/index.htm#matrix}
Matrix representations:
\begin{itemize}
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/viewing/index.htm#incidence}
incidenceMatrix
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/viewing/index.htm#adjacency}
adjacencyMatrix
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/viewing/index.htm#laplacian}
laplacianMatrix
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/viewing/index.htm#distance}
distanceMatrix
\end{itemize}
\item about whole graph:
\begin{itemize}
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/viewing/index.htm#acyclic}
isAcyclic?
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/viewing/index.htm#acyclic}
isFunctional?
\end{itemize}
\item about specific nodes
\begin{itemize}
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/viewing/index.htm#isDirectSuccessor}
isDirectSuccessor?
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/viewing/index.htm#isDirectSuccessor}isGreaterThan?
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/viewing/index.htm#isDirectSuccessor}
isFixPoint?
\end{itemize}
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/viewing/index.htm#arrowName}
arrowName -- the name of arrow a->b
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/viewing/index.htm#inDegree}
inDegree -- the number of arrows leading in to node 'a' in graph 's'
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/viewing/index.htm#outDegree}
outDegree -- the number of arrows leading out of node 'a' in graph 's'
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/viewing/index.htm#nodeFromNode}
nodeFromNode -- index of all nodes with a direct arrow leading in to node 'a' in graph 's'
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/viewing/index.htm#nodeToNode}
nodeToNode -- index of all nodes with a direct arrow leading out of node 'a' in graph 's'
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/viewing/index.htm#arrowsFromNode}
arrowsFromNode -- index of all arrows leading to a given node
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/viewing/index.htm#arrowsToNode}
arrowsToNode -- index of all arrows leading from a given node
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/viewing/index.htm#nodeFromArrow}
nodeFromArrow -- index of all nodes with a direct arrow leading in to arrow 'a' in graph 's'
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/viewing/index.htm#nodeToArrow}
nodeToArrow -- index of all nodes with a direct arrow leading out of arrow 'a' in graph 's'
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/viewing/index.htm#arrowsFromArrow}
arrowsFromArrow -- index of all arrows leading to a given arrow
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/viewing/index.htm#arrowsToArrow}
arrowsToArrow -- index of all arrows leading from a given arrow
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/viewing/index.htm#max}
min and max can be over whole graph or over a subset of nodes
\begin{itemize}
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/viewing/index.htm#max}
min -- there is an arrow or a sequence of arrows from this node to every other node
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/viewing/index.htm#max}
max -- there is an arrow or a sequence of arrows to this node from every other node
\end{itemize}
\end{itemize}
Now lets explore the methods for combining the graphs, these include:
\begin{itemize}
\item "\url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/product/index.htm}
+" (Sum) : disjoint union of nodes with arrows from appropriate input
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/product/index.htm}
merge : (Sum) : union (not necessarily disjoint) of nodes with arrows merged in from appropriate input, if arrow exists from both inputs then it will be duplicated.
\item "\url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/product/index.htm}
*" : Tensor product : the tensor product G*H of graphs G and H is a graph such that the vertex set of G*H is the Cartesian product V(G) x V(H); and any two vertices (u,u') and (v,v') are adjacent in G*H if and only if u' is adjacent with v' and u is adjacent with v.
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/product/index.htm}
cartesian : Cartesian product : the vertex set of G o H is the Cartesian product V(G) x V(H) and any two vertices (u, u') and (v, v') are adjacent in G o H if and only if either u = v and u' is adjacent with v' in H, or u' = v' and u is adjacent with v in G.
\end{itemize}
There is a much more detailed tutorial for these operations \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/product/index.htm}
here.
Maps:
\begin{itemize}
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/map/index.htm#function}
Maps in FunctionGraph
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/map/index.htm#mapContra}
mapContra
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/map/index.htm#adjoint}
coAdjoint and contraAdjoint
\end{itemize}
Loops and Routes:
\begin{itemize}
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/loops/index.htm#tree}
Spanning Tree
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/loops/index.htm#loops}
Loops
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/loops/index.htm#routes}
Routes
\end{itemize}
Specialised variants of graph:
\begin{itemize}
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/special/index.htm#function}
Function Graphs
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/special/index.htm#undirected}
Undirected Graphs
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/special/index.htm#multifunction}
Multifunction Graphs
\item \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/special/index.htm#weighted}
Weighted Graphs
\end{itemize}
To follow the whole tutorial start on \url{http://www.euclideanspace.com/prog/scratchpad/mycode/discrete/graph/construct/index.htm}
this page with constructing graphs.
\section{Loop Tutorial}
The aim of this domain is to hold a loop as a sequence of node or arrow
indexes. We consider two loops equal if they go through the same
nodes/arrows in the same order, regardless of where we happen to
start in the sequence.
So I took an arbitrary decision to store the loop with the smallest
index first (I can't think of a more canonical form) This is done
in the loop constructor.
So in the following [5, 6, 2, 8] is = to [2, 8, 5, 6] (they are both stored
as [2, 8, 5, 6]) but different to [5, 2, 6, 8] (which is stored as
[2, 6, 8, 5])
\begin{verbatim}
(9) -> l1 := loop([5::NNI, 6::NNI, 2::NNI, 8::NNI])
(9) "[->2->8->5->6]"
Type : Loop
(10) -> l2 := loop([2::NNI, 8::NNI, 5::NNI, 6::NNI])
(10) "[->2->8->5->6]"
Type : Loop
(11) -> l3 := loop([5::NNI, 2::NNI, 6::NNI, 8::NNI])
(11) "[->2->6->8->5]"
Type : Loop
(12) -> (l1 = l2)::Boolean
(12) true
Type : Boolean