Last active
January 5, 2023 01:53
-
-
Save ccidral/4816a84eaa0c8d758e8c3cd93790e9b6 to your computer and use it in GitHub Desktop.
DFS in Clojure: persistent vs transient
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns dfs | |
(:require [clojure.java.io :as io] | |
[clojure.string :as str])) | |
;; the dfs fns below are adapted from https://gist.github.com/xfthhxk/3810ecfaae8f066e2162ab02108ccadb | |
(defn load-graph [filepath] | |
(with-open [rdr (io/reader filepath)] | |
(let [[_vertices _edges & lines] (line-seq rdr)] | |
(reduce (fn [g line] | |
(let [[v w] (str/split line #" ") | |
v (Integer/parseInt v) | |
w (Integer/parseInt w)] | |
(-> g | |
(update v #(conj (or % []) w)) | |
(update w #(conj (or % []) v))))) | |
{} | |
lines)))) | |
;; wget https://algs4.cs.princeton.edu/41graph/largeG.txt | |
(defonce large-g | |
(load-graph "/path/to/largeG.txt")) | |
(defn graph-search | |
"dfs graph search using persistent collections." | |
[g start] | |
(loop [next [start] | |
visited #{}] | |
(cond | |
(empty? next) | |
visited | |
(visited (peek next)) | |
(recur (pop next) visited) | |
:else | |
(let [v (peek next) | |
neighbors (g v) | |
next (into (pop next) neighbors) | |
visited (conj visited v)] | |
(recur next visited))))) | |
(comment | |
(count (time (graph-search large-g 0)))) | |
(defn peek! [tv] | |
(get tv (dec (count tv)))) | |
(defn into! [to from] | |
(reduce #(conj! %1 %2) to from)) | |
(defn graph-search-with-transients | |
"dfs graph search using transient collections." | |
[g start] | |
(persistent! | |
(loop [next (transient [start]) | |
visited (transient #{})] | |
(cond | |
(zero? (count next)) | |
visited | |
(get visited (peek! next)) | |
(recur (pop! next) visited) | |
:else | |
(let [v (peek! next) | |
next (into! (pop! next) (g v)) | |
visited (conj! visited v)] | |
(recur next visited)))))) | |
(comment | |
(count (time (graph-search-with-transients large-g 0)))) | |
(defn run-with-persistent | |
[& _] | |
(dotimes [_ 5] | |
(time (graph-search large-g 0)))) | |
;; $ clojure -X dfs/run-with-transient | |
;; "Elapsed time: 5545.410697 msecs" | |
;; "Elapsed time: 5425.255928 msecs" | |
;; "Elapsed time: 5459.086837 msecs" | |
;; "Elapsed time: 5519.741187 msecs" | |
;; "Elapsed time: 5575.652866 msecs" | |
(defn run-with-transient | |
[& _] | |
(dotimes [_ 5] | |
(time (graph-search-with-transients large-g 0)))) | |
;; $ clojure -X dfs/run-with-persistent | |
;; "Elapsed time: 4594.230125 msecs" | |
;; "Elapsed time: 4434.272369 msecs" | |
;; "Elapsed time: 4497.725457 msecs" | |
;; "Elapsed time: 4336.609415 msecs" | |
;; "Elapsed time: 4282.192125 msecs" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment