Skip to content

Commit 94be202

Browse files
Mark PowersMark Powers
authored andcommitted
Initial commit
0 parents  commit 94be202

21 files changed

+2772
-0
lines changed

.gitattributes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Auto detect text files and perform LF normalization
2+
* text=auto

9781484264270.jpg

27.6 KB
Loading

Contributing.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Contributing to Apress Source Code
2+
3+
Copyright for Apress source code belongs to the author(s). However, under fair use you are encouraged to fork and contribute minor corrections and updates for the benefit of the author(s) and other readers.
4+
5+
## How to Contribute
6+
7+
1. Make sure you have a GitHub account.
8+
2. Fork the repository for the relevant book.
9+
3. Create a new branch on which to make your change, e.g.
10+
`git checkout -b my_code_contribution`
11+
4. Commit your change. Include a commit message describing the correction. Please note that if your commit message is not clear, the correction will not be accepted.
12+
5. Submit a pull request.
13+
14+
Thank you for your contribution!

LICENSE.txt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
Freeware License, some rights reserved
2+
3+
Copyright (c) 2021 Vsevolod Domkin
4+
5+
Permission is hereby granted, free of charge, to anyone obtaining a copy
6+
of this software and associated documentation files (the "Software"),
7+
to work with the Software within the limits of freeware distribution and fair use.
8+
This includes the rights to use, copy, and modify the Software for personal use.
9+
Users are also allowed and encouraged to submit corrections and modifications
10+
to the Software for the benefit of other users.
11+
12+
It is not allowed to reuse, modify, or redistribute the Software for
13+
commercial use in any way, or for a user’s educational materials such as books
14+
or blog articles without prior permission from the copyright holder.
15+
16+
The above copyright notice and this permission notice need to be included
17+
in all copies or substantial portions of the software.
18+
19+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
AUTHORS OR COPYRIGHT HOLDERS OR APRESS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25+
SOFTWARE.
26+
27+

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Apress Source Code
2+
3+
This repository accompanies [*Programming Algorithms in Lisp*](https://www.apress.com/9781484264270) by Vsevolod Domkin (Apress, 2021).
4+
5+
[comment]: #cover
6+
![Cover image](9781484264270.jpg)
7+
8+
Download the files as a zip using the green button, or clone the repository to your machine using Git.
9+
10+
## Releases
11+
12+
Release v1.0 corresponds to the code in the published book, without corrections or updates.
13+
14+
## Contributions
15+
16+
See the file Contributing.md for more information on how you can contribute to this repository.

ch1-complexity.lisp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
(in-package :progalgs)
2+
3+
4+
(defun mat-max (mat)
5+
(let (max)
6+
(dotimes (i (array-dimension mat 0))
7+
(dotimes (j (array-dimension mat 1))
8+
(when (or (null max)
9+
(> (aref mat i j) max))
10+
(setf max (aref mat i j)))))
11+
max))
12+
13+
(deftest mat-max ()
14+
(should be null (mat-max #2A()))
15+
(shoould be = 42 (mat-max #2A((42))))
16+
(should be = 6 (mat-max #2A((1 2 3) (4 5 6)))))

ch10-graphs.lisp

Lines changed: 306 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,306 @@
1+
(in-package :progalgs)
2+
3+
4+
(defstruct node
5+
id edges)
6+
7+
(defstruct edge
8+
src dst label)
9+
10+
(defstruct (graph (:conc-name nil) (:print-object pprint-graph))
11+
(nodes (make-hash-table))) ; mapping of node ids to nodes
12+
13+
(defun pprint-graph (graph stream)
14+
(let ((ids (sort (rtl:keys (nodes graph)) '<)))
15+
(format stream "~{ ~A~}~%" ids) ; here, Tab is used for space
16+
(dolist (id1 ids)
17+
(let ((node (rtl:? graph 'nodes id1)))
18+
(format stream "~A" id1)
19+
(dolist (id2 ids)
20+
(format stream " ~:[~;x~]" ; here, Tab as well
21+
(find id2 (rtl:? node 'edges) :key 'edge-dst)))
22+
(terpri stream)))))
23+
24+
(defun init-graph (edges)
25+
(rtl:with ((rez (make-graph))
26+
(nodes (nodes rez)))
27+
(loop :for (src dst) :in edges :do
28+
(let ((src-node (rtl:getsethash src nodes (make-node :id src))))
29+
(rtl:getset# dst nodes (make-node :id dst))
30+
(push (make-edge :src src :dst dst)
31+
(rtl:? src-node 'edges))))
32+
rez))
33+
34+
;; TODO (deftest graph ()
35+
;; CL-USER> (init-graph '((7 8)
36+
;; (1 3)
37+
;; (1 2)
38+
;; (3 4)
39+
;; (3 5)
40+
;; (2 4)
41+
;; (2 5)
42+
;; (5 4)
43+
;; (5 6)
44+
;; (4 6)))
45+
46+
(defun topo-sort (graph)
47+
(let ((nodes (nodes graph))
48+
(visited (make-hash-table))
49+
(rez (rtl:vec)))
50+
(rtl:dokv (id node nodes)
51+
(unless (gethash id visited)
52+
(visit node nodes visited rez)))
53+
rez))
54+
55+
(defun visit (node nodes visited rez)
56+
(dolist (edge (node-edges node))
57+
(rtl:with ((id (edge-dst edge))
58+
(child (elt nodes id)))
59+
(unless (find id rez)
60+
(assert (not (gethash id visited)) nil
61+
"The graph isn't acyclic for vertex: ~A" id)
62+
(setf (gethash id visited) t)
63+
(visit child nodes visited rez))))
64+
(vector-push-extend (node-id node) rez)
65+
rez)
66+
67+
(deftest topo-sort ()
68+
(should be equalp #(8 7 6 4 5 2 3 1)
69+
(topo-sort (init-graph '((7 8)
70+
(1 3)
71+
(1 2)
72+
(3 4)
73+
(3 5)
74+
(2 4)
75+
(2 5)
76+
(5 4)
77+
(5 6)
78+
(4 6))))))
79+
80+
(defvar *heap-indices*)
81+
82+
(defun prim-mst (graph)
83+
(let ((initial-weights (list))
84+
(mst (list))
85+
(total 0)
86+
(*heap-indices* (make-hash-table))
87+
weights
88+
edges
89+
cur)
90+
(rtl:dokv (id node (nodes graph))
91+
(if cur
92+
(push (rtl:pair id (or (elt edges id)
93+
;; a standard constant that is
94+
;; a good enough substitute for infinity
95+
most-positive-fixnum))
96+
initial-weights)
97+
(setf cur id
98+
edges (node-edges node))))
99+
(setf weights (heapify initial-weights))
100+
(loop
101+
(rtl:with (((id weight) (heap-pop weights)))
102+
(unless id (return))
103+
(when (elt edges id)
104+
;; if not, we have moved to the new connected component
105+
;; so there's no edge connecting it to the previous one
106+
(push (rtl:pair cur id) mst)
107+
(incf total weight))
108+
(rtl:dokv (id w edges)
109+
(when (< w weight)
110+
(heap-decrease-key weights id w)))
111+
(setf cur id
112+
edges (rtl:? graph 'nodes id 'edges))))
113+
(values mst
114+
total)))
115+
116+
(defun heap-down (vec beg &optional (end (length vec)))
117+
(let ((l (hlt beg))
118+
(r (hrt beg)))
119+
(when (< l end)
120+
(let ((child (if (or (>= r end)
121+
(> (aref vec l)
122+
(aref vec r)))
123+
l r)))
124+
(when (> (aref vec child)
125+
(aref vec beg))
126+
(rotatef (gethash (aref vec beg) *heap-indices*)
127+
(gethash (aref vec child) *heap-indices*))
128+
(rotatef (aref vec beg)
129+
(aref vec child))
130+
(heap-down vec child end)))))
131+
vec)
132+
133+
(defun heap-decrease-key (vec key decrement)
134+
(let ((i (pop (gethash key *heap-indices*))))
135+
(unless i (error "No key ~A found in the heap: ~A" key vec))
136+
(when (null (gethash key *heap-indices*))
137+
(remhash key *heap-indices*))
138+
(push i (gethash (- key decrement) *heap-indices*))
139+
(decf (aref vec i) decrement)
140+
(heap-up vec i)))
141+
142+
(defun heap-up (vec i)
143+
(rtl:with ((i-key (aref vec i))
144+
(parent (hparent i))
145+
(parent-key (aref vec parent)))
146+
(when (> i-key parent-key)
147+
(rtl:removef i (gethash i-key *heap-indices*))
148+
(rtl:removef parent (gethash parent-key *heap-indices*))
149+
(push i (gethash parent-key *heap-indices*))
150+
(push parent (gethash i-key *heap-indices*))
151+
(rotatef (aref vec i)
152+
(aref vec parent))
153+
(heap-up vec parent)))
154+
vec)
155+
156+
(defun heap-up-correct (vec i)
157+
(let ((parent (hparent i)))
158+
(when (> (aref vec i)
159+
(aref vec parent))
160+
(rotatef (gethash (aref vec i) *heap-indices*)
161+
(gethash (aref vec parent) *heap-indices*)))
162+
(rotatef (aref vec i)
163+
(aref vec parent))
164+
(heap-up vec parent))
165+
vec)
166+
167+
(defun heap-decrease-key-correct (vec key decrement)
168+
(let ((i (gethash key *heap-indices*)))
169+
(unless i (error "No key ~A found in the heap: ~A" key vec))
170+
(remhash key *heap-indices*)
171+
(setf (gethash (- key decrement) *heap-indices*) i)
172+
(decf (aref vec i) decrement)
173+
(heap-up vec i)))
174+
175+
(defstruct heap-item
176+
key val)
177+
178+
(defun heap-up (vec i)
179+
(rtl:with ((i-key (heap-item-key (aref vec i)))
180+
(parent (hparent i))
181+
(parent-key (heap-item-key (aref vec parent))))
182+
(when (> i-key parent-kea)
183+
(rtl:removef i (gethash i-key *heap-indices*))
184+
(rtl:removef parent (gethash parent-key *heap-indices*))
185+
(push i (gethash parent-key *heap-indices*))
186+
(push parent (gethash i-key *heap-indices*))
187+
(rotatef (aref vec i)
188+
(aref vec parent))
189+
(heap-up vec parent)))
190+
vec)
191+
192+
;; TODO (deftest heap2 ()
193+
194+
(defstruct (spf-node (:include node))
195+
(weight most-positive-fixnum)
196+
(path (list)))
197+
198+
(defun spf (graph src dst)
199+
(rtl:with ((nodes (graph-nodes graph))
200+
(spf (list))
201+
;; the following code should express initialize the heap
202+
;; with a single node of weight 0 and all other nodes
203+
;; of weight MOST-POSITIVE-FIXNUM
204+
;; (instead of running a O(n*log n) HEAPIFY)
205+
(weights (init-weights-heap nodes src)))
206+
(loop
207+
(rtl:with (((id weight) (heap-pop weights)))
208+
(cond ((eql id dst)
209+
(let ((dst (elt nodes dst)))
210+
;; we return two values: the path and its length
211+
(return (values (cons dst (spf-node-path dst))
212+
(spf-node-weight dst)))))
213+
((= most-positive-fixnum weight)
214+
(return))) ; no path exists
215+
(dolist (edge (rtl:? nodes id 'edges))
216+
(rtl:with ((cur (edge-dst edge))
217+
(node (elt nodes cur))
218+
(w (+ weight (spf-node-weight cur))))
219+
(when (< w (spf-node-weight node))
220+
(heap-decrease-key weights cur w)
221+
(setf (spf-node-weight node) w
222+
(spf-node-path node) (cons (rtl:? nodes id)
223+
(rtl:? nodes id 'path))))))))))
224+
225+
;; TODO (deftest spf ()
226+
227+
(defstruct mf-edge
228+
beg end capacity)
229+
230+
(defun max-flow (g)
231+
(let ((rg (copy-array g)) ; residual graph
232+
(rez 0))
233+
(loop :for path := (aug-path rg) :while path :do
234+
(let ((flow most-positive-fixnum))
235+
;; the flow along the path is the residual capacity of the thinnest edge
236+
(dolist (edge path)
237+
(let ((cap (mf-edge-capacity edge)))
238+
(when (< (abs cap) flow)
239+
(setf flow (abs cap)))))
240+
(dolist (edge path)
241+
(with-slots (beg end) edge
242+
(decf (aref rg beg end) flow)
243+
(incf (aref rg end beg) flow)))
244+
(incf rez flow)))
245+
rez))
246+
247+
(defun aug-path (g)
248+
(rtl:with ((sink (1- (array-dimension g 0)))
249+
(visited (make-array (1+ sink) :initial-element nil)))
250+
(labels ((dfs (g i)
251+
(if (zerop (aref g i sink))
252+
(dotimes (j sink)
253+
(unless (or (zerop (aref g i j))
254+
(aref visited j))
255+
(rtl:when-it (dfs g j)
256+
(setf (aref visited j) t)
257+
(return (cons (make-mf-edge
258+
:beg i :end j
259+
:capacity (aref g i j))
260+
rtl:it)))))
261+
(list (make-mf-edge
262+
:beg i :end sink
263+
:capacity (aref g i sink))))))
264+
(dfs g 0))))
265+
266+
(deftest max-flow ()
267+
(should be = 7 (max-flow #2A((0 4 4 0 0 0)
268+
(0 0 0 4 2 0)
269+
(0 0 0 1 2 0)
270+
(0 0 0 0 0 3)
271+
(0 0 0 0 0 5)))))
272+
273+
;; code prototypes
274+
275+
(defun pagerank (g &key (d 0.85) (repeat 100))
276+
(rtl:with ((n (length (nodes g)))
277+
(pr (make-arrray n :initial-element (/ 1 n))))
278+
(loop :repeat repeat :do
279+
(let ((pr2 (map 'vector (lambda (x) (- 1 (/ d n)))
280+
pr)))
281+
(rtl:dokv (i node nodes)
282+
(let ((p (aref pr i))
283+
(m (length (node-children node))))
284+
(rtl:dokv (j child (node-children node)))
285+
(incf (aref pr2 j) (* d (/ p m)))))
286+
(setf pr pr2)))
287+
pr))
288+
289+
(defun pr1 (node n p &key (d 0.85))
290+
(let ((pr (make-arrray n :initial-element 0))
291+
(m (hash-table-count (node-children node))))
292+
(rtl:dokv (j child (node-children node))
293+
(setf (aref pr j) (* d (/ p m))))
294+
pr))
295+
296+
(defun pagerank-mr (g &key (d 0.85) (repeat 100))
297+
(rtl:with ((n (length (nodes g)))
298+
(pr (make-arrray n :initial-element (/ 1 n))))
299+
(loop :repeat repeat :do
300+
(setf pr (map 'vector (lambda (x)
301+
(- 1 (/ d n)))
302+
(reduce 'vec+ (map 'vector (lambda (node p)
303+
(pr1 node n p :d d))
304+
(nodes g)
305+
pr)))))
306+
pr))

0 commit comments

Comments
 (0)