From 53cafc45945021c90e5e14a99127d2df60b7196b Mon Sep 17 00:00:00 2001
From: "Pascal J. Bourguignon"
Date: Wed, 8 Jun 2011 03:35:33 +0200
Subject: [PATCH] Updated p80 and p37. Added Makefile.

Makefile  6 +
compileall.lisp  17 ++
index.html  82 
p37.lisp  3 +
p80.lisp  562 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 587 insertions(+), 83 deletions()
create mode 100644 Makefile
create mode 100644 p80.lisp
diff git a/Makefile b/Makefile
new file mode 100644
index 0000000..9567d4a
 /dev/null
+++ b/Makefile
@@ 0,0 +1,6 @@
+LISP=clisp ansi E utf8
+all:
+ $(LISP) compileall.lisp
+clean:
+ rm f *.lib *.fas *.fasl *.x86f
+
diff git a/compileall.lisp b/compileall.lisp
index 6fac660..e4c9aca 100644
 a/compileall.lisp
+++ b/compileall.lisp
@@ 53,5 +53,22 @@
"p56.lisp"
"p57.lisp"
"drawtree.lisp" "p58.lisp"
+ "p61.lisp"
+ "p61a.lisp"
+ "p62.lisp"
+ "p62a.lisp"
+ "p63.lisp"
+ "p64.lisp"
+ "p65.lisp"
+ "p66.lisp"
+ "p67.lisp"
+ "p68.lisp"
+ "p69.lisp"
+ "p70b.lisp"
+ "p70c.lisp"
+ "p70.lisp"
+ "p71.lisp"
+ "p72.lisp"
+ "p73.lisp"
))
(load (compilefile src)))
diff git a/index.html b/index.html
index 01d415a..67fae1a 100644
 a/index.html
+++ b/index.html
@@ 194,88 +194,6 @@ P60 (**) Construct heightbalanced binary trees with a given number of nodes
Find out how many heightbalanced trees exist for N = 15.


Graphs

A graph is defined as a set of nodes and a set of edges, where each edge is a pair of nodes.

There are several ways to represent graphs in Prolog. One method is to represent each edge separately as one clause (fact). In this form, the graph depicted below is represented as the following predicate:
[graph1]

edge(h,g).
edge(k,f).
edge(f,b).
...

We call this edgeclause form. Obviously, isolated nodes cannot be represented. Another method is to represent the whole graph as one data object. According to the definition of the graph as a pair of two sets (nodes and edges), we may
use the following Prolog term to represent the example graph:

graph([b,c,d,f,g,h,k],[e(b,c),e(b,f),e(c,f),e(f,k),e(g,h)])

We call this graphterm form. Note, that the lists are kept sorted, they are really sets, without duplicated elements. Each edge appears only once in the edge list; i.e. an edge from a node x to another node y is represented as e(x,y),
the term e(y,x) is not present. The graphterm form is our default representation. In SWIProlog there are predefined predicates to work with sets.

A third representation method is to associate with each node the set of nodes that are adjacent to that node. We call this the adjacencylist form. In our example:

[n(b,[c,f]), n(c,[b,f]), n(d,[]), n(f,[b,c,k]), ...]

The representations we introduced so far are Prolog terms and therefore well suited for automated processing, but their syntax is not very userfriendly. Typing the terms by hand is cumbersome and errorprone. We can define a more
compact and "humanfriendly" notation as follows: A graph is represented by a list of atoms and terms of the type XY (i.e. functor '' and arity 2). The atoms stand for isolated nodes, the XY terms describe edges. If an X appears as
an endpoint of an edge, it is automatically defined as a node. Our example could be written as:

[bc, fc, gh, d, fb, kf, hg]

We call this the humanfriendly form. As the example shows, the list does not have to be sorted and may even contain the same edge multiple times. Notice the isolated node d. (Actually, isolated nodes do not even have to be atoms in
the Prolog sense, they can be compound terms, as in d(3.75,blue) instead of d in the example).

[graph2]
When the edges are directed we call them arcs. These are represented by ordered pairs. Such a graph is called directed graph. To represent a directed graph, the forms discussed above are slightly modified. The example graph opposite is
represented as follows:

Arcclause form
 arc(s,u).
 arc(u,r).
 ...

Graphterm form
 digraph([r,s,t,u,v],[a(s,r),a(s,u),a(u,r),a(u,s),a(v,u)])

Adjacencylist form
 [n(r,[]),n(s,[r,u]),n(t,[]),n(u,[r]),n(v,[u])]
 Note that the adjacencylist does not have the information on whether it is a graph or a digraph.

Humanfriendly form
 [s > r, t, u > r, s > u, u > s, v > u]

Finally, graphs and digraphs may have additional information attached to nodes and edges (arcs). For the nodes, this is no problem, as we can easily replace the single character identifiers with arbitrary compound terms, such as city
('London',4711). On the other hand, for edges we have to extend our notation. Graphs with additional information attached to edges are called labelled graphs.

[graph3]

Arcclause form
 arc(m,q,7).
 arc(p,q,9).
 arc(p,m,5).

Graphterm form
 digraph([k,m,p,q],[a(m,p,7),a(p,m,5),a(p,q,9)])

Adjacencylist form
 [n(k,[]),n(m,[q/7]),n(p,[m/5,q/9]),n(q,[])]
 Notice how the edge information has been packed into a term with functor '/' and arity 2, together with the corresponding node.

Humanfriendly form
 [p>q/9, m>q/7, k, p>m/5]

The notation for labelled graphs can also be used for socalled multigraphs, where more than one edge (or arc) are allowed between two given nodes.

P80 (***) Conversions
 Write predicates to convert between the different graph representations. With these predicates, all representations are equivalent; i.e. for the following problems you can always pick freely the most convenient form. The reason
 this problem is rated (***) is not because it's particularly difficult, but because it's a lot of work to deal with all the special cases.

P81 (**) Path from one node to another one
 Write a predicate path(G,A,B,P) to find an acyclic path P from node A to node b in the graph G. The predicate should return all paths via backtracking.
P82 (*) Cycle from a given node
Write a predicate cycle(G,A,P) to find a closed path (cycle) P starting at a given node A in the graph G. The predicate should return all cycles via backtracking.
diff git a/p37.lisp b/p37.lisp
index 6b1bc24..52ba793 100644
 a/p37.lisp
+++ b/p37.lisp
@@ 14,13 +14,14 @@ P37 (**) Calculate Euler's totient function phi(m) (improved).
Note that a ** b stands for the b'th power of a.
"
+;;; https://secure.wikimedia.org/wikipedia/en/wiki/Euler%27s_totient_function#Computing_Euler.27s_function
(defun phi (m)
;; (p1  1) * p1 ** (m1  1)
;; + (p2  1) * p2 ** (m2  1)
;; + (p3  1) * p3 ** (m3  1)
;; + ...
 (reduce (function +)
+ (reduce (function *)
(mapcar (lambda (item)
(destructuringbind (pi mi) item
(* (1 pi) (expt pi (1 mi)))))
diff git a/p80.lisp b/p80.lisp
new file mode 100644
index 0000000..29e60ed
 /dev/null
+++ b/p80.lisp
@@ 0,0 +1,562 @@
+#(and) "
+
+Graphs
+
+A graph is defined as a set of nodes and a set of edges, where each
+edge is a pair of nodes.
+
+There are several ways to represent graphs in Prolog. One method is to
+represent each edge separately as one clause (fact). In this form, the
+graph depicted below is represented as the following predicate:
+
+[graph1]
+
+edge(h,g).
+edge(k,f).
+edge(f,b).
+...
+
+We call this edgeclause form. Obviously, isolated nodes cannot be
+represented. Another method is to represent the whole graph as one
+data object. According to the definition of the graph as a pair of two
+sets (nodes and edges), we may use the following Prolog term to
+represent the example graph:
+
+graph([b,c,d,f,g,h,k],[e(b,c),e(b,f),e(c,f),e(f,k),e(g,h)])
+
+We call this graphterm form. Note, that the lists are kept sorted,
+they are really sets, without duplicated elements. Each edge appears
+only once in the edge list; i.e. an edge from a node x to another node
+y is represented as e(x,y), the term e(y,x) is not present. The
+graphterm form is our default representation. In SWIProlog there are
+predefined predicates to work with sets.
+
+A third representation method is to associate with each node the set
+of nodes that are adjacent to that node. We call this the
+adjacencylist form. In our example:
+
+[n(b,[c,f]), n(c,[b,f]), n(d,[]), n(f,[b,c,k]), ...]
+
+The representations we introduced so far are Prolog terms and
+therefore well suited for automated processing, but their syntax is
+not very userfriendly. Typing the terms by hand is cumbersome and
+errorprone. We can define a more compact and \"humanfriendly\"
+notation as follows: A graph is represented by a list of atoms and
+terms of the type XY (i.e. functor '' and arity 2). The atoms stand
+for isolated nodes, the XY terms describe edges. If an X appears as
+an endpoint of an edge, it is automatically defined as a node. Our
+example could be written as:
+
+[bc, fc, gh, d, fb, kf, hg]
+
+We call this the humanfriendly form. As the example shows, the list
+does not have to be sorted and may even contain the same edge multiple
+times. Notice the isolated node d. (Actually, isolated nodes do not
+even have to be atoms in the Prolog sense, they can be compound terms,
+as in d(3.75,blue) instead of d in the example).
+
+[graph2]
+
+When the edges are directed we call them arcs. These are represented
+by ordered pairs. Such a graph is called directed graph. To represent
+a directed graph, the forms discussed above are slightly modified. The
+example graph opposite is represented as follows:
+
+Arcclause form
+ arc(s,u).
+ arc(u,r).
+ ...
+
+Graphterm form
+ digraph([r,s,t,u,v],[a(s,r),a(s,u),a(u,r),a(u,s),a(v,u)])
+
+Adjacencylist form
+ [n(r,[]),n(s,[r,u]),n(t,[]),n(u,[r]),n(v,[u])]
+
+ Note that the adjacencylist does not have the information on
+ whether it is a graph or a digraph.
+
+Humanfriendly form
+
+ [s > r, t, u > r, s > u, u > s, v > u]
+
+Finally, graphs and digraphs may have additional information attached
+to nodes and edges (arcs). For the nodes, this is no problem, as we
+can easily replace the single character identifiers with arbitrary
+compound terms, such as city ('London',4711). On the other hand, for
+edges we have to extend our notation. Graphs with additional
+information attached to edges are called labelled graphs.
+
+[graph3]
+
+Arcclause form
+ arc(m,q,7).
+ arc(p,q,9).
+ arc(p,m,5).
+
+Graphterm form
+ digraph([k,m,p,q],[a(m,p,7),a(p,m,5),a(p,q,9)])
+
+Adjacencylist form
+ [n(k,[]),n(m,[q/7]),n(p,[m/5,q/9]),n(q,[])]
+
+ Notice how the edge information has been packed into a term with
+ functor '/' and arity 2, together with the corresponding node.
+
+Humanfriendly form
+ [p>q/9, m>q/7, k, p>m/5]
+
+The notation for labelled graphs can also be used for socalled
+multigraphs, where more than one edge (or arc) are allowed between
+two given nodes.
+"
+
+
+
+#(and) "
+
+P80 (***) Conversions
+
+ Write predicates to convert between the different graph
+ representations. With these predicates, all representations are
+ equivalent; i.e. for the following problems you can always pick
+ freely the most convenient form. The reason this problem is rated
+ (***) is not because it's particularly difficult, but because it's
+ a lot of work to deal with all the special cases.
+
+"
+
+
+
+#(and) "
+
+A similar set of representations are possible in lisp too. As always,
+hiding the representation behind an abstraction will allow to
+implement generic algorithms, and to change the representation at
+will. We may even design an abstraction allowing to change the
+representation on the fly, eg. between two phases of a processing, to
+provide better algorithmic complexities.
+
+To easily write and print graphs, we'll use a sexp which must be a
+list containing either isolated nodes (noncons objects), or lists of
+two or more elements (fromnode tonode [:key value ...]) representing
+each edge or arc.
+
+We could easily write a function to map more sugary sexp syntax to
+this form, or even a reader macro parsing a syntax with all the
+intricacy wanted, but it's hardly worth the pain.
+
+We'll also allow property lists to store any kind of attributes to the
+arcs or edges.
+"
+
+
+;;; Graph classes
+
+(defclass graph ()
+ ((representation :initarg :representation
+ :documentation "The actual representation of the graph."))
+ (:documentation "
+This abstract class represents a graph, and is the superclass of a
+directedgraph and undirectedgraph that can be represented in several
+ways.
+"))
+
+(defmethod printobject ((self graph) stream)
+ (printunreadableobject (self stream :identity t :type t)
+ (let ((repname (classname (classof (slotvalue self 'representation)))))
+ (format stream "as a~:[~;n~] ~A" (find (char (string repname) 0) "AEIOUY") repname))
+ (format stream " with ~A node~:*~P and ~A edge~:*~P"
+ (length (nodes self)) (length (edges self))))
+ self)
+
+(defclass undirectedgraph (graph)
+ ()
+ (:documentation "
+Undirected graphs can have only representations with edges.
+"))
+
+
+(defclass attributes ()
+ ((propertylist :initform '()
+ :accessor propertylist :initarg :propertylist
+ :accessor properties :initarg :properties)))
+
+
+(defclass edge (attributes)
+ ((nodes :accessor edgenodes :initarg :nodes))
+ (:documentation "
+An undirected edge. The order of the two nodes in the edgenodes list
+is irrelevant.
+"))
+
+
+(defclass directedgraph (graph)
+ ()
+ (:documentation "
+Undirected graphs can have only representations with arcs.
+"))
+
+(defclass arc (attributes)
+ ((from :accessor arcfrom :initarg :from)
+ (to :accessor arcto :initarg :to))
+ (:documentation "
+A directed arc, from the FROM node to the TO node.
+Note: the API allow for unidrected
+"))
+
+
+
+(defclass graphrepresentation ()
+ ()
+ (:documentation "An abstract graph representation."))
+
+(defclass undirectedgraphrepresentation ()
+ ()
+ (:documentation "An abstract undirected graph representation."))
+
+(defclass directedgraphrepresentation ()
+ ()
+ (:documentation "An abstract directed graph representation."))
+
+
+
+;;; Generic functions
+;; We define here the fundamental operations for graph
+;; representations, as generic functions. A method is defined on
+;; graph, that just forwards the call to the graph representation.
+
+(defgeneric nodes (gr)
+ (:documentation "Returns the list of nodes in the graph or graph representation")
+ (:method ((g graph)) (nodes (slotvalue g 'representation))))
+
+(defgeneric addnode (gr node)
+ (:documentation "Adds a new node to the graph or graph representation.
+Return NODE.")
+ (:method ((g graph) node) (addnode (slotvalue g 'representation) node)))
+
+(defgeneric removenode (gr node)
+ (:documentation "
+If NODE is a node of the graph or graph representation, then remove
+it, as well as all arcs connecting it. Return NODE.")
+ (:method ((g graph) node) (removenode (slotvalue g 'representation) node)))
+
+
+
+(defgeneric edges (gr)
+ (:documentation "
+Returns the list of edges in the undirected graph or graph
+representation.")
+ (:method ((g undirectedgraph)) (edges (slotvalue g 'representation))))
+
+(defgeneric addedgebetweennodes (gr from to &key &allowotherkeys)
+ ;; Notice we leave ADDEDGE to name a generic function of two arguments: (gr edge)
+ ;; Optional key arguments may be defined for additionnal
+ ;; initializers for edges (such as weights, etc).
+ (:documentation "
+Adds a new edge the graph or graph representation, between the FROM
+and the TO node. If the graph or graph representation is undirected,
+then two arcs are added, from FROM to TO and from TO to FROM. If
+either FROM or TO is not a node of GR, then it's added before.
+Return the new EDGE.")
+ (:method ((g undirectedgraph) from to &rest args &key &allowotherkeys)
+ (apply (function addedgebetweennodes) (slotvalue g 'representation) from to args)))
+
+(defgeneric removeedge (gr edge)
+ (:documentation "
+If EDGE is an edge of the graph or graph representation,then remove it.
+Return EDGE.")
+ (:method ((g undirectedgraph) edge) (removeedge (slotvalue g 'representation) edge)))
+
+
+
+(defgeneric arcs (gr)
+ (:documentation "Returns the list of arcs in the graph or graph representation.
+If the graph or graph representation is undirected, then each edge produces two arcs.")
+ (:method ((g directedgraph))
+ (arcs (slotvalue g 'representation)))
+ (:method ((g undirectedgraph))
+ (mapcan (lambda (edge)
+ (destructuringbind (left right) (edgenodes edge)
+ (list (makeinstance 'arc :from left :to right :properties (properties edge))
+ (makeinstance 'arc :from right :to left :properties (properties edge)))))
+ (edges (slotvalue g 'representation)))))
+
+(defgeneric addarcbetweennodes (gr from to &key &allowotherkeys)
+ ;; Notice we leave ADDARC to name a generic function of two arguments: (gr arc)
+ ;; Optional key arguments may be defined for additionnal
+ ;; initializers for arcs (such as weights, etc).
+ (:documentation "
+Adds a new arc the graph or graph representation, between the FROM
+and the TO node. If either FROM or TO is not a node of GR,
+then it's added before. Return the new ARC.")
+ (:method ((g directedgraph) from to &rest args &key &allowotherkeys)
+ (apply (function addarcbetweennodes) (slotvalue g 'representation) from to args)))
+
+(defgeneric removearc (gr arc)
+ (:documentation "
+If ARC is an arc of the graph or graph representation,then remove it.
+The nodes are not changed. Return ARC.")
+ (:method ((g directedgraph) node) (removearc (slotvalue g 'representation) arc)))
+
+
+
+
+(defgeneric tosexp (object)
+ (:documentation "
+Returns a sexp representing the graph.
+The sexp should be accepted by the method FROMSEXP
+of the same graph class.
+"))
+
+(defgeneric fromsexp (object sexp)
+ (:documentation "
+Replaces the graph nodes and edges with the data from the given SEXP.
+Returns GR.
+"))
+
+
+
+
+(defun nodesandlinkstosexp (nodes links)
+ (flet ((nodesfromlinks (links)
+ (mapcan (lambda (link) (list (first link) (second link))) links)))
+ (append (setdifference nodes (nodesfromlinks links)) links)))
+
+(defmethod tosexp ((self edge))
+ (concatenate 'list (edgenodes self) (properties self)))
+
+(defmethod tosexp ((self arc))
+ (concatenate 'list (list (arcfrom self) (arcto self)) (properties self)))
+
+(defmethod tosexp ((g directedgraph))
+ (nodesandlinkstosexp (nodes g) (mapcar (function tosexp) (arcs g))))
+
+(defmethod tosexp ((g undirectedgraph))
+ (nodesandlinkstosexp (nodes g) (mapcar (function tosexp) (edges g))))
+
+
+
+(defmethod clearrepresentation ((g graph))
+ (setf (slotvalue g 'representation) (makeinstance (classof (slotvalue g 'representation)))))
+
+(defmethod parsegraphsexp ((g graph) sexp addlink)
+ (let ((rep (clearrepresentation g)))
+ (loop
+ :for item :in sexp
+ :do (if (consp item)
+ (apply addlink rep item)
+ (addnode rep item))
+ :finally (return rep))))
+
+(defmethod fromsexp ((g undirectedgraph) sexp)
+ (setf (slotvalue g 'representation)
+ (parsegraphsexp g sexp (function addedgebetweennodes)))
+ g)
+
+(defmethod fromsexp ((g directedgraph) sexp)
+ (setf (slotvalue g 'representation)
+ (parsegraphsexp g sexp (function addarcbetweennodes)))
+ g)
+
+
+
+;; We'd want to
+;; (definemodifymacro deletef (element list) delete)
+;; but the order of the argument is not consistent.
+
+(defmacro deletef (item sequenceplace &rest args &key key test testnot)
+ (declare (ignore key test testnot))
+ (multiplevaluebind (vars vals storevars writerform readerform)
+ (getsetfexpansion sequenceplace)
+ `(let* (,@(mapcar (function list) vars vals)
+ (,(car storevars) ,readerform))
+ (when (cdr storevars)
+ (error "Cannot DELETE from a place with multiple values."))
+ (setf ,(car storevars) (delete ,item ,(car storevars) ,@args))
+ ,writerform)))
+
+
+
+
+;;; Edge list representation
+;;; In this representation we only keep a list of links.
+
+(defclass edgelistrepresentation (undirectedgraphrepresentation)
+ ((edges :accessor edges :initarg :edges :initform '())))
+
+(defmethod addedgebetweennodes ((gr edgelistrepresentation) from to &rest properties &key &allowotherkeys)
+ (let ((edge (makeinstance 'edge
+ :nodes (list from to)
+ :properties properties)))
+ (push edge (edges gr))
+ edge))
+
+(defmethod removeedge ((gr edgelistrepresentation) edge)
+ (deletef edge (edges gr))
+ edge)
+
+(defmethod nodes ((gr edgelistrepresentation))
+ (deleteduplicates (loop
+ :for edge :in (edges gr)
+ :for nodes = (edgenodes edge)
+ :collect (first nodes) :collect (second nodes))))
+
+(defmethod addnode ((gr edgelistrepresentation) node)
+ (error "Cannot add isolated nodes to a graph represented by a list of edges."))
+
+(defmethod removenode ((gr edgelistrepresentation) node)
+ (setf (edges gr) (deleteif (lambda (edge) (member node (edgenodes edge))) (edges gr)))
+ node)
+
+
+
+;;; Edge list and nodes representation
+;;; In this representation in addition to the list of edge, we
+;;; maintain a list of nodes, so we may have isolated nodes too.
+
+(defclass edgeandnodelistrepresentation (edgelistrepresentation)
+ ((nodes :accessor nodes :initarg :nodes :initform '())))
+
+(defmethod addedgebetweennodes ((gr edgeandnodelistrepresentation) from to &key &allowotherkeys)
+ (addnode gr from)
+ (addnode gr to)
+ (callnextmethod))
+
+(defmethod addnode ((gr edgeandnodelistrepresentation) node)
+ (pushnew node (nodes gr))
+ node)
+
+(defmethod removenode ((gr edgeandnodelistrepresentation) node)
+ (remove node (nodes gr))
+ (callnextmethod))
+
+
+
+
+;;; adjacency list representation
+;;; In this representation, we have a hashtable mapping from nodes to
+;;; lists of attributed links to nodes. This allow for directed graphs.
+;;; Notice that each node is present in the hashtable as a key, so
+;;; isolated nodes are easily represented.
+
+(defclass link (attributes)
+ ((node :accessor linknode :initarg :node)))
+
+(defclass adjacencylistrepresentation (directedgraphrepresentation)
+ ((adjacencylist :initform (makehashtable)
+ :reader adjacencylist)))
+
+
+(defmethod nodes ((gr adjacencylistrepresentation))
+ (let ((nodes '()))
+ (maphash (lambda (from adjacents)
+ (declare (ignore adjacents))
+ (push from nodes))
+ (adjacencylist gr))
+ nodes))
+
+(defmethod addnode ((gr adjacencylistrepresentation) node)
+ (unless (gethash node (adjacencylist gr))
+ (setf (gethash node (adjacencylist gr)) '()))
+ node)
+
+(defmethod removenode ((gr adjacencylistrepresentation) node)
+ (let ((al (adjacencylist gr)))
+ (when (remhash node al)
+ (maphash (lambda (from adjacents)
+ ;; I assume it's faster to call (setf gethash)
+ ;; than to call member or find.
+ (setf (gethash from al) (delete node adjacents :key (function linknode))))
+ al)))
+ node)
+
+
+(defmethod arcs ((gr adjacencylistrepresentation))
+ (let ((arcs '()))
+ (maphash (lambda (from adjacents)
+ (setf arcs (nconc (mapcar (lambda (to)
+ (makeinstance 'arc
+ :from from
+ :to (linknode to)
+ :properties (copylist (properties to))))
+ adjacents)
+ arcs)))
+ (adjacencylist gr))
+ arcs))
+
+(defmethod addarcbetweennodes ((gr adjacencylistrepresentation) from to &rest properties &key &allowotherkeys)
+ (addnode gr from)
+ (addnode gr to)
+ (pushnew (makeinstance 'link :node to :properties properties) (gethash from (adjacencylist gr)))
+ (makeinstance 'arc
+ :from from
+ :to to
+ :properties (copylist properties)))
+
+(defmethod removearc ((gr adjacencylistrepresentation) arc)
+ (deletef to (gethash (arcfrom arc) (adjacencylist gr)))
+ arc)
+
+
+
+;;;
+
+(defun makeedgegraph (data)
+ (fromsexp (makeinstance 'undirectedgraph
+ :representation (makeinstance 'edgelistrepresentation))
+ data))
+
+(defun makeedgeandnodegraph (data)
+ (fromsexp (makeinstance 'undirectedgraph
+ :representation (makeinstance 'edgeandnodelistrepresentation))
+ data))
+
+(defun makeadjacencylistgraph (data)
+ (fromsexp (makeinstance 'directedgraph
+ :representation (makeinstance 'adjacencylistrepresentation))
+ data))
+
+
+(defun setequalp (a b)
+ (and (subsetp a b :test (function equal))
+ (subsetp b a :test (function equal))))
+
+(defun test/tosexp ()
+ (dolist (test '(()
+ (a b c)
+ ((a b) (b c))
+ ((b c) (f c) (g h) d (f b) (k f) (h g))
+ ((s r) t (u r) (s u) (u s) (v u))
+ ((p q :weight 9) (m q :weight 7) k (p m :weight 5))))
+ (assert (setequalp test (tosexp (makeedgeandnodegraph test))))
+ (assert (setequalp test (tosexp (makeadjacencylistgraph test)))))
+ (dolist (test '(()
+ ((a b) (b c))
+ ((b c) (f c) (g h) (f b) (k f) (h g))
+ ((s r) (u r) (s u) (u s) (v u))
+ ((p q :weight 9) (m q :weight 7) (p m :weight 5))))
+ (assert (setequalp test (tosexp (makeedgegraph test)))))
+ :success)
+
+;; (test/tosexp)
+
+
+;; Converting from one graph representation to another can be realized with:
+;; (make...graph (tosexp originalgraph))
+;; or use copyfrom to replace the contents of the current graph with
+;; those of the other graph:
+
+(defmethod copyfrom ((g graph) (other graph))
+ "Make G a graph equal to OTHER"
+ (clearrepresentation)
+ ;; Just out of lazyness, we go thru sexps.
+ (fromsexp (slotvalue g 'representation) (tosexp other))
+ ;; if a faster conversion is required, we could get (nodes other)
+ ;; and (edges other) or (arcs other) and loop of them to add them to
+ ;; the target graph.
+ g)
+
+
+;;; THE END ;;;
+

2.1.4