Skip to content

Commit

Permalink
Merge branch 'jpellegrini-srfi-234'
Browse files Browse the repository at this point in the history
  • Loading branch information
egallesio committed Oct 11, 2024
2 parents da56e45 + 1dd6325 commit 9270fce
Show file tree
Hide file tree
Showing 8 changed files with 397 additions and 4 deletions.
1 change: 1 addition & 0 deletions SUPPORTED-SRFIS
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ implemented in latest version is available at https://stklos.net/srfi.html):
- SRFI-230: Atomic Operations
- SRFI-232: Flexible Curried Procedures
- SRFI-233: INI files
- SRFI-234: Topological Sorting
- SRFI-235: Combinators
- SRFI-236: Evaluating expressions in an unspecified order
- SRFI-238: Codesets
Expand Down
9 changes: 7 additions & 2 deletions doc/HTML/stklos-ref.html
Original file line number Diff line number Diff line change
Expand Up @@ -26954,7 +26954,7 @@ <h2 id="_srfis">13. SRFIs</h2>
<div class="sect2">
<h3 id="_supported_srfis">13.1. Supported SRFIs</h3>
<div class="paragraph">
<p><strong><em>STklos</em></strong> supports <strong>125</strong> finalized SRFIS.
<p><strong><em>STklos</em></strong> supports <strong>126</strong> finalized SRFIS.
Some of these SRFIS are <em>embedded</em> and some are <em>external</em>.</p>
</div>
<div class="paragraph">
Expand Down Expand Up @@ -27086,6 +27086,7 @@ <h3 id="_supported_srfis">13.1. Supported SRFIs</h3>
- <strong><a href="http://srfi.schemers.org/srfi-230/srfi-230.html">SRFI-230</a></strong>&#8201;&#8212;&#8201;<em>Atomic Operations</em><br>
- <strong><a href="http://srfi.schemers.org/srfi-232/srfi-232.html">SRFI-232</a></strong>&#8201;&#8212;&#8201;<em>Flexible Curried Procedures</em><br>
- <strong><a href="http://srfi.schemers.org/srfi-233/srfi-233.html">SRFI-233</a></strong>&#8201;&#8212;&#8201;<em>INI files</em><br>
- <strong><a href="http://srfi.schemers.org/srfi-234/srfi-234.html">SRFI-234</a></strong>&#8201;&#8212;&#8201;<em>Topological sorting</em><br>
- <strong><a href="http://srfi.schemers.org/srfi-235/srfi-235.html">SRFI-235</a></strong>&#8201;&#8212;&#8201;<em>Combinators</em><br>
- <strong><a href="http://srfi.schemers.org/srfi-236/srfi-236.html">SRFI-236</a></strong>&#8201;&#8212;&#8201;<em>Evaluating expressions in an unspecified order</em><br>
- <strong><a href="http://srfi.schemers.org/srfi-238/srfi-238.html">SRFI-238</a></strong>&#8201;&#8212;&#8201;<em>Codesets</em><br>
Expand Down Expand Up @@ -27155,7 +27156,7 @@ <h4 id="_external_srfis">13.2.2. External SRFIs</h4>
</div>
<div class="paragraph">
<p><strong>List of external SRFIs:</strong>
<code>srfi-1</code> <code>srfi-2</code> <code>srfi-4</code> <code>srfi-5</code> <code>srfi-7</code> <code>srfi-9</code> <code>srfi-13</code> <code>srfi-14</code> <code>srfi-17</code> <code>srfi-19</code> <code>srfi-25</code> <code>srfi-26</code> <code>srfi-27</code> <code>srfi-29</code> <code>srfi-35</code> <code>srfi-36</code> <code>srfi-37</code> <code>srfi-41</code> <code>srfi-43</code> <code>srfi-48</code> <code>srfi-51</code> <code>srfi-54</code> <code>srfi-59</code> <code>srfi-60</code> <code>srfi-61</code> <code>srfi-64</code> <code>srfi-66</code> <code>srfi-69</code> <code>srfi-74</code> <code>srfi-89</code> <code>srfi-94</code> <code>srfi-95</code> <code>srfi-96</code> <code>srfi-100</code> <code>srfi-113</code> <code>srfi-115</code> <code>srfi-116</code> <code>srfi-117</code> <code>srfi-125</code> <code>srfi-127</code> <code>srfi-128</code> <code>srfi-129</code> <code>srfi-130</code> <code>srfi-132</code> <code>srfi-133</code> <code>srfi-134</code> <code>srfi-135</code> <code>srfi-137</code> <code>srfi-141</code> <code>srfi-144</code> <code>srfi-151</code> <code>srfi-152</code> <code>srfi-154</code> <code>srfi-156</code> <code>srfi-158</code> <code>srfi-160</code> <code>srfi-161</code> <code>srfi-162</code> <code>srfi-170</code> <code>srfi-171</code> <code>srfi-173</code> <code>srfi-174</code> <code>srfi-175</code> <code>srfi-178</code> <code>srfi-180</code> <code>srfi-185</code> <code>srfi-189</code> <code>srfi-190</code> <code>srfi-196</code> <code>srfi-207</code> <code>srfi-214</code> <code>srfi-215</code> <code>srfi-216</code> <code>srfi-217</code> <code>srfi-221</code> <code>srfi-222</code> <code>srfi-223</code> <code>srfi-224</code> <code>srfi-227</code> <code>srfi-228</code> <code>srfi-229</code> <code>srfi-230</code> <code>srfi-232</code> <code>srfi-233</code> <code>srfi-235</code> <code>srfi-236</code> <code>srfi-238</code></p>
<code>srfi-1</code> <code>srfi-2</code> <code>srfi-4</code> <code>srfi-5</code> <code>srfi-7</code> <code>srfi-9</code> <code>srfi-13</code> <code>srfi-14</code> <code>srfi-17</code> <code>srfi-19</code> <code>srfi-25</code> <code>srfi-26</code> <code>srfi-27</code> <code>srfi-29</code> <code>srfi-35</code> <code>srfi-36</code> <code>srfi-37</code> <code>srfi-41</code> <code>srfi-43</code> <code>srfi-48</code> <code>srfi-51</code> <code>srfi-54</code> <code>srfi-59</code> <code>srfi-60</code> <code>srfi-61</code> <code>srfi-64</code> <code>srfi-66</code> <code>srfi-69</code> <code>srfi-74</code> <code>srfi-89</code> <code>srfi-94</code> <code>srfi-95</code> <code>srfi-96</code> <code>srfi-100</code> <code>srfi-113</code> <code>srfi-115</code> <code>srfi-116</code> <code>srfi-117</code> <code>srfi-125</code> <code>srfi-127</code> <code>srfi-128</code> <code>srfi-129</code> <code>srfi-130</code> <code>srfi-132</code> <code>srfi-133</code> <code>srfi-134</code> <code>srfi-135</code> <code>srfi-137</code> <code>srfi-141</code> <code>srfi-144</code> <code>srfi-151</code> <code>srfi-152</code> <code>srfi-154</code> <code>srfi-156</code> <code>srfi-158</code> <code>srfi-160</code> <code>srfi-161</code> <code>srfi-162</code> <code>srfi-170</code> <code>srfi-171</code> <code>srfi-173</code> <code>srfi-174</code> <code>srfi-175</code> <code>srfi-178</code> <code>srfi-180</code> <code>srfi-185</code> <code>srfi-189</code> <code>srfi-190</code> <code>srfi-196</code> <code>srfi-207</code> <code>srfi-214</code> <code>srfi-215</code> <code>srfi-216</code> <code>srfi-217</code> <code>srfi-221</code> <code>srfi-222</code> <code>srfi-223</code> <code>srfi-224</code> <code>srfi-227</code> <code>srfi-228</code> <code>srfi-229</code> <code>srfi-230</code> <code>srfi-232</code> <code>srfi-233</code> <code>srfi-234</code> <code>srfi-235</code> <code>srfi-236</code> <code>srfi-238</code></p>
</div>
</div>
<div class="sect3">
Expand Down Expand Up @@ -27330,6 +27331,10 @@ <h4 id="_srfi_features">13.2.3. SRFI features</h4>
<td class="tableblock halign-left valign-top"><p class="tableblock">srfi-233</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">topological-sort</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">srfi-234</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">combinators</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">srfi-235</p></td>
</tr>
Expand Down
264 changes: 264 additions & 0 deletions lib/srfi/234.stk
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
;;;;
;;;; 234.stk -- Implementation of SRFI-234
;;;;
;;;; Copyright © 2020 Jeronimo Pellegrini - <j_p@aleph0.info>
;;;;
;;;;
;;;; This program is free software; you can redistribute it and/or modify
;;;; it under the terms of the GNU General Public License as published by
;;;; the Free Software Foundation; either version 3 of the License, or
;;;; (at your option) any later version.
;;;;
;;;; This program is distributed in the hope that it will be useful,
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;;;; GNU General Public License for more details.
;;;;
;;;; You should have received a copy of the GNU General Public License
;;;; along with this program; if not, write to the Free Software
;;;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
;;;; USA.
;;;;
;;;; This file is a derivative work from the implementation of
;;;; this SRFI by Shiro Kawai, John Cowan, Arne Babenhauserheide,
;;;; it is copyrighted as:
;;;;
;;;;;; © 2024 John Cowan, Shiro Kawai, Arthur A. Gleckler, Arne
;;;;;; Babenhauserheide.
;;;;;;
;;;;;; Permission is hereby granted, free of charge, to any person
;;;;;; obtaining a copy of this software and associated documentation
;;;;;; files (the "Software"), to deal in the Software without
;;;;;; restriction, including without limitation the rights to use,
;;;;;; copy, modify, merge, publish, distribute, sublicense, and/or
;;;;;; sell copies of the Software, and to permit persons to whom the
;;;;;; Software is furnished to do so, subject to the following
;;;;;; conditions:
;;;;;;
;;;;;; The above copyright notice and this permission notice
;;;;;; (including the next paragraph) shall be included in all copies
;;;;;; or substantial portions of the Software.
;;;;;;
;;;;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
;;;;;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
;;;;;; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
;;;;;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
;;;;;; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
;;;;;; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
;;;;;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
;;;;;; OTHER DEALINGS IN THE SOFTWARE.
;;;;
;;;; Author: Jeronimo Pellegrini [j_p@aleph0.info]
;;;; Creation date: 10-Oct-2024 17:12 (jpellegrini)
;;;;

(define-module srfi/234
(import
(scheme base)
(scheme case-lambda)
(srfi 1)
(srfi 11) ;; let-values
(srfi 26)) ;; cut
(export topological-sort
topological-sort/details
edgelist->graph
edgelist/inverted->graph
graph->edgelist
graph->edgelist/inverted
connected-components)

(define topological-sort
(case-lambda
((graph) (topological-sort-impl graph equal? #f))
((graph eq) (topological-sort-impl graph eq #f))
((graph eq nodes) (topological-sort-impl graph eq nodes))))

(define topological-sort/details
(case-lambda
((graph) (topological-sort-impl/details graph equal? #f))
((graph eq) (topological-sort-impl/details graph eq #f))
((graph eq nodes) (topological-sort-impl/details graph eq nodes))))

(define (topological-sort-impl graph eq nodes)
(let-values (((v0 v1 v2)
(topological-sort-impl/details graph eq nodes)))
v0))

(define (topological-sort-impl/details graph eq nodes)
(define table (map (lambda (n)
(cons (car n) 0))
graph))
(define queue '())
(define result '())

;; set up - compute number of nodes that each node depends on.
(define (set-up)
(for-each
(lambda (node)
(for-each
(lambda (to)
(define p (assoc to table eq))
(if p
(set-cdr! p (+ 1 (cdr p)))
(set! table (cons
(cons to 1)
table))))
(cdr node)))
graph))

;; traverse
(define (traverse)
(unless (null? queue)
(let ((n0 (assoc (car queue) graph eq)))
(set! queue (cdr queue))
(when n0
(for-each
(lambda (to)
(define p (assoc to table eq))
(when p
(let ((cnt (- (cdr p) 1)))
(when (= cnt 0)
(set! result (cons to result))
(set! queue (cons to queue)))
(set-cdr! p cnt))))
(cdr n0)))
(traverse))))

(set-up)
(set! queue
(apply append
(map
(lambda (p)
(if (= (cdr p) 0)
(list (car p))
'()))
table)))
(set! result queue)
(traverse)
(let ((rest (filter (lambda (e)
(not (zero? (cdr e))))
table)))
(if (null? rest)
(values
(if nodes
;; replace indizes by node values
(let loop ((res '()) (result result))
(if (null? result)
res
(loop (cons (vector-ref nodes (car result)) res)
(cdr result))))
(reverse result))
#f #f)
(values #f "graph has circular dependency" (map car rest)))))

;; Calculate the connected components from a graph of in-neighbors
;; implements Kosaraju's algorithm: https://en.wikipedia.org/wiki/Kosaraju%27s_algorithm
(define (connected-components graph)
(define nodes-with-inbound-links (map car graph))
;; graph of out-neighbors
(define graph/inverted (edgelist->graph (graph->edgelist/inverted graph)))
(define nodes-with-outbound-links (map car graph/inverted))
;; for simplicity this uses a list of nodes to query for membership. This is expensive.
(define visited '())
(define vertex-list '())
;; create vertex-list sorted with outbound elements first
(define (visit! node)
(cond ((member node visited) '())
(else
;; mark as visited before traversing
(set! visited (cons node visited))
;; this uses the graph: the outbound connections
(let ((node-in-graph (assoc node graph)))
(when node-in-graph
(for-each visit! (cdr node-in-graph))))
;; add to list after traversing
(set! vertex-list (cons node vertex-list)))))
;; for simplicity this uses a list of nodes to query for membership. This is expensive.
(define in-component '())
(define components '())
;; assign nodes to their components
(define (assign! u root)
(unless (member u in-component)
(set! in-component (cons u in-component))
(set! components (cons (cons u (car components)) (cdr components)))
;; this uses the graph/inverted: the inbound connections
(let ((node-in-graph (assoc u graph/inverted)))
(when node-in-graph
(for-each (cut assign! <> root) (cdr node-in-graph))))))
(define (assign-as-component! u)
(unless (member u in-component)
(set! components (cons '() components))
(assign! u u)))
(for-each visit! nodes-with-outbound-links)
(for-each assign-as-component! vertex-list)
components)

;; convert an edgelist '((a b) (a c) (b e)) to a graph '((a b c) (b e))
(define edgelist->graph
(case-lambda
((edgelist) (edgelist->graph-impl edgelist assoc))
((edgelist asc) (edgelist->graph-impl edgelist asc))))
(define (edgelist->graph-impl edgelist asc)
(let loop ((graph '()) (edges edgelist))
(cond
((null? edges) (reverse! graph))
((asc (car (car edges)) graph)
(let* ((edge (car edges))
(left (car edge))
(graph-entry (asc left graph))
(right (car (cdr edge))))
;; adjust the right-most cdr
(let lp ((entry graph-entry))
(if (null? (cdr entry))
(set-cdr! entry (list right))
(lp (cdr entry))))
(loop graph (cdr edges))))
;; use apply list to break up immutable pairs
(else (loop (cons (apply list (car edges)) graph) (cdr edges))))))

;; convert an inverted edgelist '((b a) (c a) (e b)) to a graph '((a b c) (b e))
(define edgelist/inverted->graph
(case-lambda
((edgelist) (edgelist/inverted->graph-impl edgelist assoc))
((edgelist asc) (edgelist/inverted->graph-impl edgelist asc))))
(define (edgelist/inverted->graph-impl edgelist asc)
(let loop ((graph '()) (edges edgelist))
(cond
((null? edges) (reverse! graph))
((asc (car (cdr (car edges))) graph)
(let* ((edge (car edges))
(left (car (cdr edge)))
(graph-entry (asc left graph))
(right (car edge)))
;; adjust the right-most cdr
(let lp ((entry graph-entry))
(if (null? (cdr entry))
(set-cdr! entry (list right))
(lp (cdr entry))))
(loop graph (cdr edges))))
;; reverse instead of reverse! to avoid immutable lists
(else (loop (cons (reverse (car edges)) graph) (cdr edges))))))

(define (graph->edgelist graph)
(graph->edgelist/base graph (lambda (top) (list (car top) (car (cdr top))))))

(define (graph->edgelist/inverted graph)
(graph->edgelist/base graph (lambda (top) (list (car (cdr top)) (car top)))))

(define (graph->edgelist/base graph top-to-edge-fun)
(let loop ((edgelist '()) (graph graph))
(cond ((null? graph)
(reverse! edgelist))
((null? (car graph))
(loop edgelist (cdr graph)))
((null? (cdr (car graph)))
(loop edgelist (cdr graph)))
(else
(let* ((top (car graph))
(edge (top-to-edge-fun top))
(rest (cdr (cdr top))))
(loop (cons edge edgelist)
(cons (cons (car top) rest) (cdr graph))))))))
)

(provide "srfi/234")
3 changes: 3 additions & 0 deletions lib/srfi/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ SRC_STK = 1.stk \
230.stk \
232.stk \
233.stk \
234.stk \
235.stk \
236.stk \
244.stk
Expand Down Expand Up @@ -257,6 +258,7 @@ SRC_OSTK = 1.ostk \
230.ostk \
232.ostk \
233.ostk \
234.ostk \
235.ostk \
236.ostk \
244.ostk
Expand Down Expand Up @@ -337,6 +339,7 @@ SUFFIXES = .stk .ostk .stk -incl.c .$(SO) .c
217.ostk: ../stklos/itrie.$(SO)
221.ostk: 41.ostk 158.ostk
224.ostk: ../scheme/comparator.ostk
234.ostk: 1.ostk 11.ostk 26.ostk
235.ostk: 1.ostk


Expand Down
3 changes: 3 additions & 0 deletions lib/srfi/Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,7 @@ SRC_STK = 1.stk \
230.stk \
232.stk \
233.stk \
234.stk \
235.stk \
236.stk \
244.stk
Expand Down Expand Up @@ -624,6 +625,7 @@ SRC_OSTK = 1.ostk \
230.ostk \
232.ostk \
233.ostk \
234.ostk \
235.ostk \
236.ostk \
244.ostk
Expand Down Expand Up @@ -1057,6 +1059,7 @@ STKLOS_BINARY ?= ../../src/stklos
217.ostk: ../stklos/itrie.$(SO)
221.ostk: 41.ostk 158.ostk
224.ostk: ../scheme/comparator.ostk
234.ostk: 1.ostk 11.ostk 26.ostk
235.ostk: 1.ostk

25.$(SO): 25-incl.c 25.c
Expand Down
2 changes: 1 addition & 1 deletion lib/srfis.stk
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@
;; 231 Intervals and Generalized Arrays (Updated^2)
(232 "Flexible Curried Procedures" () "srfi-232")
(233 "INI files" (ini-files) "srfi-233")
;; 234 Topological sorting (draft)
(234 "Topological sorting" (topological-sort) "srfi-234")
(235 "Combinators" (combinators) "srfi-235")
(236 "Evaluating expressions in an unspecified order" () "srfi-236")
;; 237 R6RS Records (refined)
Expand Down
Loading

0 comments on commit 9270fce

Please sign in to comment.