Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add an initial Clojure implementation for unit 2.
- Loading branch information
Showing
5 changed files
with
166 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
pom.xml | ||
*jar | ||
/lib/ | ||
/classes/ | ||
.lein-failures | ||
.lein-deps-sum |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
Unit 2 Algorithms in Clojure | ||
============================ | ||
|
||
Usage | ||
----- | ||
|
||
lein deps | ||
lein repl | ||
|
||
(require '[unit02.trees :as trees]) | ||
(trees/search-breadth trees/sample-tree :e) | ||
(trees/search-depth trees/sample-tree :e) | ||
|
||
(require '[unit02.graphs :as graphs]) | ||
(graphs/search-breadth graphs/sample-graph-ny :rochester :albany) | ||
(graphs/search-depth graphs/sample-graph-ny :rochester :albany) |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
(defproject unit02 "1.0.0-SNAPSHOT" | ||
:description "ai-class unit 2 algorithms in Clojure" | ||
:dependencies [[org.clojure/clojure "1.2.1"] | ||
[org.clojure/clojure-contrib "1.2.0"] | ||
[incanter "1.2.4"]] | ||
:dev-dependencies [[lein-marginalia "0.6.1"]]) |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
(ns unit02.graphs) | ||
|
||
|
||
|
||
; Undirected Graph ------------------------------------------------------------ | ||
; | ||
; A graph is a map of label -> node. | ||
; Each node has a label and a list of connections. | ||
; Each connection is a map of label -> cost. | ||
; | ||
; Connections between nodes are undirected, and the cost is the same in both | ||
; directions. | ||
|
||
(defrecord Node [label connections]) | ||
|
||
(defn make-graph [labels connections] | ||
(let [graph (zipmap labels (map #(Node. %1 %2) labels (cycle [{}])))] | ||
(loop [graph graph | ||
connections connections] | ||
(if (empty? connections) | ||
graph | ||
(let [[labels cost] (first connections) | ||
[a b] labels] | ||
(recur (-> graph | ||
(assoc-in [a :connections b] cost) | ||
(assoc-in [b :connections a] cost)) | ||
(rest connections))))))) | ||
|
||
|
||
; Searches -------------------------------------------------------------------- | ||
(defn- path-cost [path graph] | ||
(loop [prev (first path) | ||
path (rest path) | ||
cost 0] | ||
(if (empty? path) | ||
cost | ||
(recur (first path) | ||
(rest path) | ||
(+ cost ((:connections (graph prev)) | ||
(first path))))))) | ||
|
||
(defn- new-targets [path current-node explored graph] | ||
(let [unseen (filter (complement explored) | ||
(keys (:connections current-node))) | ||
new-paths (map #(conj path %) unseen)] | ||
(map #(with-meta % {:cost (path-cost % graph)}) | ||
new-paths))) | ||
|
||
|
||
(defn search [frontier-conj graph start goal] | ||
(loop [explored #{} | ||
frontier (seq [[start]]) | ||
examined 1] | ||
(let [path (first frontier) | ||
current (last path)] | ||
(if (= current goal) | ||
{:path path | ||
:examined examined | ||
:cost (:cost (meta path))} | ||
(when current | ||
(recur (conj explored current) | ||
(let [current-node (graph current)] | ||
(frontier-conj (rest frontier) | ||
(new-targets path current-node explored graph))) | ||
(inc examined))))))) | ||
|
||
|
||
(defn frontier-conj-breadth [frontier children] | ||
(concat frontier children)) | ||
|
||
(defn frontier-conj-depth [frontier children] | ||
(concat children frontier)) | ||
|
||
|
||
(def search-breadth (partial search frontier-conj-breadth)) | ||
(def search-depth (partial search frontier-conj-depth)) | ||
|
||
; Sample Graph ---------------------------------------------------------------- | ||
(def sample-graph-ny | ||
(make-graph [:buffalo :rochester :syracuse :binghamton :new-york-city] | ||
{[:buffalo :rochester] 75 | ||
[:syracuse :rochester] 90 | ||
[:ithaca :rochester] 90 | ||
[:ithaca :binghamton] 50 | ||
[:ithaca :syracuse] 60 | ||
[:binghamton :syracuse] 75 | ||
[:binghamton :rochester] 141 | ||
[:binghamton :new-york-city] 176 | ||
[:syracuse :new-york-city] 247 | ||
[:albany :new-york-city] 150 | ||
[:albany :syracuse] 150})) |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
(ns unit02.trees) | ||
|
||
|
||
; Tree ------------------------------------------------------------------------ | ||
; | ||
; A tree is equivalent to a single node. A single node is a record: | ||
; | ||
; {:label :foo :children [... nodes ...]} | ||
|
||
(defrecord Node [label children]) | ||
|
||
; Searches -------------------------------------------------------------------- | ||
(defn- search [frontier-conj tree goal] | ||
; frontier is a sequence of vectors representing paths we still need to try: | ||
; ([Node :a, Node :b], [Node :a, Node :c], ...) | ||
(loop [frontier (seq [[tree]]) | ||
examined 1] | ||
(let [path (first frontier) | ||
current (last path)] | ||
(if (= (:label current) goal) | ||
{:path (map :label path) | ||
:examined examined} | ||
(recur (frontier-conj (rest frontier) | ||
(map #(conj path %) (:children current))) | ||
(inc examined)))))) | ||
|
||
|
||
(defn- frontier-conj-depth [frontier children] | ||
(concat children frontier)) | ||
|
||
(defn- frontier-conj-breadth [frontier children] | ||
(concat frontier children)) | ||
|
||
|
||
(def search-depth (partial search frontier-conj-depth)) | ||
(def search-breadth (partial search frontier-conj-breadth)) | ||
|
||
; Sample Tree ----------------------------------------------------------------- | ||
; | ||
; a | ||
; b c | ||
; d e f g | ||
|
||
(def sample-tree (Node. :a [(Node. :b [(Node. :d []) | ||
(Node. :e [])]) | ||
(Node. :c [(Node. :f []) | ||
(Node. :g [])])])) |