mirror of
				https://github.com/KevinMidboe/linguist.git
				synced 2025-10-29 17:50:22 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			321 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			321 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
\* graph.shen --- a library for graph definition and manipulation
 | 
						|
 | 
						|
Copyright (C) 2011,  Eric Schulte
 | 
						|
 | 
						|
*** License:
 | 
						|
 | 
						|
Redistribution and use in source and binary forms, with or without
 | 
						|
modification, are permitted provided that the following conditions are
 | 
						|
met:
 | 
						|
 | 
						|
 - Redistributions of source code must retain the above copyright
 | 
						|
   notice, this list of conditions and the following disclaimer.
 | 
						|
 | 
						|
 - Redistributions in binary form must reproduce the above copyright
 | 
						|
   notice, this list of conditions and the following disclaimer in the
 | 
						|
   documentation and/or other materials provided with the distribution.
 | 
						|
 | 
						|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
						|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
						|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | 
						|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | 
						|
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
						|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | 
						|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
						|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
						|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
						|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
						|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
						|
 | 
						|
*** Commentary:
 | 
						|
 | 
						|
Graphs are represented as two dictionaries one for vertices and one
 | 
						|
for edges.  It is important to note that the dictionary implementation
 | 
						|
used is able to accept arbitrary data structures as keys.  This
 | 
						|
structure technically encodes hypergraphs (a generalization of graphs
 | 
						|
in which each edge may contain any number of vertices).  Examples of a
 | 
						|
regular graph G and a hypergraph H with the corresponding data
 | 
						|
structure are given below.
 | 
						|
 | 
						|
 | 
						|
--G=<graph Vertices Edges>------------------------------------------------
 | 
						|
                            Vertices                  Edges
 | 
						|
                           ----------                -------
 | 
						|
 +----Graph G-----+      hash | key -> value      hash |  key  -> value
 | 
						|
 |                |      -----+------>--------    -----+-------->---------
 | 
						|
 | a---b---c   g  |         1 |  a  -> [1]           1 | [a b] -> [1 2]
 | 
						|
 |     |   |      |         2 |  b  -> [1 2 3]       2 | [b c] -> [2 3]
 | 
						|
 |     d---e---f  |         3 |  c  -> [2 4]         3 | [b d] -> [2 4]
 | 
						|
 |                |         4 |  d  -> [3 5]         4 | [c e] -> [3 5]
 | 
						|
 +----------------+         5 |  e  -> [4 5 6]       5 | [d e] -> [4 5]
 | 
						|
                            6 |  f  -> [6]           6 | [e f] -> [5 6]
 | 
						|
                            7 |  g  -> []
 | 
						|
 | 
						|
 | 
						|
--H=<graph Vertices Edges>------------------------------------------------
 | 
						|
                            Vertices                  Edges
 | 
						|
                           ----------                -------
 | 
						|
                         hash | key -> value      hash |  key  -> value
 | 
						|
 +-- Hypergraph H----+   -----+------>--------    -----+-------->---------
 | 
						|
 |                   |      1 |  a  -> [1]           1 | [a b     [1 2
 | 
						|
 |        +------+   |      2 |  b  -> [1]             |  c d  ->  3 4
 | 
						|
 | +------+------+   |      3 |  c  -> [1]             |  e f]     5 6]
 | 
						|
 | |a b c |d e f |   |      4 |  d  -> [1 2]           |
 | 
						|
 | +------+------+   |      5 |  e  -> [1 2]         2 | [d e     [4 5
 | 
						|
 |        |g h i | j |      6 |  f  -> [1 2]           |  f g  ->  6 7
 | 
						|
 |        +------+   |      7 |  g  -> [2]             |  h i]     8 9]
 | 
						|
 |                   |      8 |  h  -> [2]
 | 
						|
 +-------------------+      9 |  i  -> [2]
 | 
						|
                           10 |  j  -> []
 | 
						|
 | 
						|
 | 
						|
--G=<graph Vertices Edges>-------Graph with associated edge/vertex data---------
 | 
						|
                            Vertices                    Edges
 | 
						|
                           ----------                  -------
 | 
						|
 +----Graph G-----+      hash | key -> value        hash |  key  -> value
 | 
						|
 |   4   6     7  |      -----+------>--------      -----+-------->---------
 | 
						|
 |0a---b---c   g  |         1 |  a  -> (@p 0 [1])      1 | [a b] -> (@p 4 [1 2])
 | 
						|
 |    1|  3|      |         2 |  b  -> [1 2 3]         2 | [b c] -> (@p 6 [2 3])
 | 
						|
 |     d---e---f  |         3 |  c  -> [2 4]           3 | [b d] -> (@p 1 [2 4])
 | 
						|
 |       2   5    |         4 |  d  -> [3 5]           4 | [c e] -> (@p 3 [3 5])
 | 
						|
 +----------------+         5 |  e  -> [4 5 6]         5 | [d e] -> (@p 2 [4 5])
 | 
						|
                            6 |  f  -> [6]             6 | [e f] -> (@p 5 [5 6])
 | 
						|
                            7 |  g  -> (@p 7 [])
 | 
						|
 | 
						|
V = # of vertices
 | 
						|
E = # of edges
 | 
						|
M = # of vertex edge associations
 | 
						|
 | 
						|
size = size of all vertices +            all vertices stored in Vertices dict
 | 
						|
       M * sizeof(int) * 4 +             indices into Vertices & Edge dicts
 | 
						|
       V * sizeof(dict entry) +          storage in the Vertex dict
 | 
						|
       E * sizeof(dict entry) +          storage in the Edge dict
 | 
						|
       2 * sizeof(dict)                  the Vertices and Edge dicts
 | 
						|
 | 
						|
*** Code: *\
 | 
						|
(require dict)
 | 
						|
(require sequence)
 | 
						|
 | 
						|
(datatype graph
 | 
						|
  Vertices : dictionary;
 | 
						|
     Edges : dictoinary;
 | 
						|
  ===================
 | 
						|
  (vector symbol Vertices Edges);)
 | 
						|
 | 
						|
(package graph- [graph graph? vertices edges add-vertex
 | 
						|
                 add-edge has-edge? has-vertex? edges-for
 | 
						|
                 neighbors connected-to connected? connected-components
 | 
						|
                 vertex-partition bipartite?
 | 
						|
                 \* included from the sequence library\ *\
 | 
						|
                 take drop take-while drop-while range flatten
 | 
						|
                 filter complement seperate zip indexed reduce
 | 
						|
                 mapcon partition partition-with unique frequencies
 | 
						|
                 shuffle pick remove-first interpose subset?
 | 
						|
                 cartesian-product
 | 
						|
                 \* included from the dict library\ *\
 | 
						|
                 dict? dict dict-> <-dict contents key? keys vals
 | 
						|
                 dictionary make-dict]
 | 
						|
 | 
						|
(define graph?
 | 
						|
  X -> (= graph (<-address X 0)))
 | 
						|
 | 
						|
(define make-graph
 | 
						|
  \* create a graph with specified sizes for the vertex dict and edge dict *\
 | 
						|
  {number --> number --> graph}
 | 
						|
  Vertsize Edgesize ->
 | 
						|
    (let Graph (absvector 3)
 | 
						|
      (do (address-> Graph 0 graph)
 | 
						|
          (address-> Graph 1 (make-dict Vertsize))
 | 
						|
          (address-> Graph 2 (make-dict Edgesize))
 | 
						|
          Graph)))
 | 
						|
 | 
						|
(defmacro graph-macro
 | 
						|
  \* return a graph taking optional sizes for the vertex and edge dicts *\
 | 
						|
  [graph] -> [make-graph 1024 1024]
 | 
						|
  [graph N] -> [make-graph N 1024]
 | 
						|
  [graph N M] -> [make-graph N M])
 | 
						|
 | 
						|
(define vert-dict Graph -> (<-address Graph 1))
 | 
						|
 | 
						|
(define edge-dict Graph -> (<-address Graph 2))
 | 
						|
 | 
						|
(define vertices
 | 
						|
  {graph --> (list A)}
 | 
						|
  Graph -> (keys (vert-dict Graph)))
 | 
						|
 | 
						|
(define edges
 | 
						|
  {graph --> (list (list A))}
 | 
						|
  Graph -> (keys (edge-dict Graph)))
 | 
						|
 | 
						|
(define get-data
 | 
						|
  Value V -> (if (tuple? Value)
 | 
						|
                 (fst Value)
 | 
						|
                 (error (make-string "no data for ~S~%" V))))
 | 
						|
 | 
						|
(define vertex-data
 | 
						|
  Graph V -> (get-data (<-dict (vert-dict Graph) V) V))
 | 
						|
 | 
						|
(define edge-data
 | 
						|
  Graph V -> (get-data (<-dict (edge-dict Graph) V) V))
 | 
						|
 | 
						|
(define resolve
 | 
						|
  {(vector (list A)) --> (@p number number) --> A}
 | 
						|
  Vector (@p Index Place) -> (nth (+ 1 Place) (<-vector Vector Index)))
 | 
						|
 | 
						|
(define resolve-vert
 | 
						|
  {graph --> (@p number number) --> A}
 | 
						|
  Graph Place -> (resolve (<-address (vert-dict Graph) 2) Place))
 | 
						|
 | 
						|
(define resolve-edge
 | 
						|
  {graph --> (@p number number) --> A}
 | 
						|
  Graph Place -> (resolve (<-address (edge-dict Graph) 2) Place))
 | 
						|
 | 
						|
(define edges-for
 | 
						|
  {graph --> A --> (list (list A))}
 | 
						|
  Graph Vert -> (let Val (trap-error (<-dict (vert-dict Graph) Vert) (/. E []))
 | 
						|
                     Edges (if (tuple? Val) (snd Val) Val)
 | 
						|
                  (map (lambda X (fst (resolve-edge Graph X))) Val)))
 | 
						|
 | 
						|
(define add-vertex-w-data
 | 
						|
  \* add a vertex to a graph *\
 | 
						|
  {graph --> A --> B --> A}
 | 
						|
  G V Data -> (do (dict-> (vert-dict G) V (@p Data (edges-for G V))) V))
 | 
						|
 | 
						|
(define add-vertex-w/o-data
 | 
						|
  \* add a vertex to a graph *\
 | 
						|
  {graph --> A --> B --> A}
 | 
						|
  G V -> (do (dict-> (vert-dict G) V (edges-for G V)) V))
 | 
						|
 | 
						|
(defmacro add-vertex-macro
 | 
						|
  [add-vertex G V]   -> [add-vertex-w/o-data G V]
 | 
						|
  [add-vertex G V D] -> [add-vertex-w-data G V D])
 | 
						|
 | 
						|
(define update-vert
 | 
						|
  \* in a dict, add an edge to a vertex's edge list *\
 | 
						|
  {vector --> (@p number number) --> A --> number}
 | 
						|
  Vs Edge V -> (let Store (<-address Vs 2)
 | 
						|
                    N (hash V (limit Store))
 | 
						|
                    VertLst (trap-error (<-vector Store N) (/. E []))
 | 
						|
                    Contents (trap-error (<-dict Vs V) (/. E []))
 | 
						|
                 (do (dict-> Vs V (if (tuple? Contents)
 | 
						|
                                      (@p (fst Contents)
 | 
						|
                                          (adjoin Edge (snd Contents)))
 | 
						|
                                      (adjoin Edge Contents)))
 | 
						|
                     (@p N (length VertLst)))))
 | 
						|
 | 
						|
(define update-edges-vertices
 | 
						|
  \* add an edge to a graph *\
 | 
						|
  {graph --> (list A) --> (list A)}
 | 
						|
  Graph Edge ->
 | 
						|
  (let Store (<-address (edge-dict Graph) 2)
 | 
						|
       EdgeID (hash Edge (limit Store))
 | 
						|
       EdgeLst (trap-error (<-vector Store EdgeID) (/. E []))
 | 
						|
    (map (update-vert (vert-dict Graph) (@p EdgeID (length EdgeLst))) Edge)))
 | 
						|
 | 
						|
(define add-edge-w-data
 | 
						|
  G E D -> (do (dict-> (edge-dict G) E (@p D (update-edges-vertices G E))) E))
 | 
						|
 | 
						|
(define add-edge-w/o-data
 | 
						|
  G E -> (do (dict-> (edge-dict G) E (update-edges-vertices G E)) E))
 | 
						|
 | 
						|
(defmacro add-edge-macro
 | 
						|
  [add-edge G E]   -> [add-edge-w/o-data G E]
 | 
						|
  [add-edge G E V] -> [add-edge-w-data G E V])
 | 
						|
 | 
						|
(define has-edge?
 | 
						|
  {graph --> (list A) --> boolean}
 | 
						|
  Graph Edge -> (key? (edge-dict Graph) Edge))
 | 
						|
 | 
						|
(define has-vertex?
 | 
						|
  {graph --> A --> boolean}
 | 
						|
  Graph Vertex -> (key? (vert-dict Graph) Vertex))
 | 
						|
 | 
						|
(define neighbors
 | 
						|
  \* Return the neighbors of a vertex *\
 | 
						|
  {graph --> A --> (list A)}
 | 
						|
  Graph Vert -> (unique (mapcon (remove-first Vert) (edges-for Graph Vert))))
 | 
						|
 | 
						|
(define connected-to-
 | 
						|
  {graph --> (list A) --> (list A) --> (list A)}
 | 
						|
  Graph [] Already -> Already
 | 
						|
  Graph New Already ->
 | 
						|
  (let Reachable (unique (mapcon (neighbors Graph) New))
 | 
						|
       New (difference Reachable Already)
 | 
						|
    (connected-to- Graph New (append New Already))))
 | 
						|
 | 
						|
(define connected-to
 | 
						|
  \* return all vertices connected to the given vertex, including itself *\
 | 
						|
  {graph --> A --> (list A)}
 | 
						|
  Graph V -> (connected-to- Graph [V] [V]))
 | 
						|
 | 
						|
(define connected?
 | 
						|
  \* return if a graph is fully connected *\
 | 
						|
  {graph --> boolean}
 | 
						|
  Graph -> (reduce (/. V Acc
 | 
						|
                       (and Acc
 | 
						|
                            (subset? (vertices Graph) (connected-to Graph V))))
 | 
						|
                   true (vertices Graph)))
 | 
						|
 | 
						|
(define connected-components-
 | 
						|
  \* given a graph return a list of connected components *\
 | 
						|
  {graph --> (list A) --> (list (list A)) --> (list graph)}
 | 
						|
  Graph [] _ -> []
 | 
						|
  Graph VS [] -> (map (/. V (let Component (graph 1 0)
 | 
						|
                              (do (add-vertex Component V) Component)))
 | 
						|
                      VS)
 | 
						|
  Graph [V|VS] ES ->
 | 
						|
    (let Con-verts (connected-to Graph V)
 | 
						|
         Con-edges (filter (/. E (subset? E Con-verts)) ES)
 | 
						|
         Component (graph (length Con-verts) (length Con-edges))
 | 
						|
      (do (map (add-edge-w/o-data Component) Con-edges)
 | 
						|
          (cons Component (connected-components- Graph
 | 
						|
                                                 (difference VS Con-verts)
 | 
						|
                                                 (difference ES Con-edges))))))
 | 
						|
 | 
						|
(define connected-components
 | 
						|
  {graph --> (list graph)}
 | 
						|
  Graph -> (connected-components- Graph (vertices Graph) (edges Graph)))
 | 
						|
 | 
						|
(define place-vertex
 | 
						|
  \* given a graph, vertex and list of partitions, partition the vertex *\
 | 
						|
  {graph --> A --> (list (list A)) --> (list (list A))}
 | 
						|
  Graph V [] -> (if (element? V (neighbors Graph V))
 | 
						|
                    (simple-error
 | 
						|
                     (make-string "self-loop ~S, no vertex partition" V))
 | 
						|
                    [[V]])
 | 
						|
  Graph V [C|CS] -> (let Neighbors (neighbors Graph V)
 | 
						|
                      (if (element? V Neighbors)
 | 
						|
                          (simple-error
 | 
						|
                           (make-string "self-loop ~S, no vertex partition" V))
 | 
						|
                          (if (empty? (intersection C Neighbors))
 | 
						|
                              [[V|C]|CS]
 | 
						|
                              [C|(place-vertex Graph V CS)]))))
 | 
						|
 | 
						|
(define vertex-partition
 | 
						|
  \* partition the vertices of a graph *\
 | 
						|
  {graph --> (list (list A))}
 | 
						|
  Graph -> (reduce (place-vertex Graph) [] (vertices Graph)))
 | 
						|
 | 
						|
(define bipartite?
 | 
						|
  \* check if a graph is bipartite *\
 | 
						|
  {graph --> boolean}
 | 
						|
  Graph -> (= 2 (length (vertex-partition Graph))))
 | 
						|
 | 
						|
)
 | 
						|
 | 
						|
\* simple tests
 | 
						|
 | 
						|
(set g (graph))
 | 
						|
(add-edge (value g) [chris patton])
 | 
						|
(add-edge (value g) [eric chris])
 | 
						|
(add-vertex (value g) nobody)
 | 
						|
(has-edge? (value g) [patton chris])
 | 
						|
(edges-for (value g) chris)
 | 
						|
(neighbors (value g) chris)
 | 
						|
(neighbors (value g) nobody)
 | 
						|
(connected-to (value g) chris)
 | 
						|
(connected? (value g))
 | 
						|
(connected-components (value g)) <- fail when package wrapper is used
 | 
						|
(map (function vertices) (connected-components (value g)))
 | 
						|
 | 
						|
*\ |