|
1 | 1 | (ns net.n01se.hassle.core
|
2 | 2 | (:require [clojure.pprint :refer [pprint]]
|
3 | 3 |
|
4 |
| - [net.n01se.hassle.transducers :as t])) |
| 4 | + [net.n01se.hassle.xfnet :as xfn])) |
5 | 5 |
|
6 | 6 | (defn debug
|
7 | 7 | ([x] (debug x x))
|
8 | 8 | ([msg x] (println "DEBUG:" msg) x))
|
9 | 9 |
|
10 |
| -;; implementation |
11 |
| - |
12 |
| -(defn normalize-inputs [inputs] |
13 |
| - (if (set? inputs) |
14 |
| - (mapcat normalize-inputs inputs) |
15 |
| - (if (nil? inputs) |
16 |
| - (list) |
17 |
| - (list inputs)))) |
18 |
| - |
19 |
| -(defn normalize-net |
20 |
| - [label trees] |
21 |
| - (letfn [(walk-trees [net-map trees super-path] |
22 |
| - (reduce |
23 |
| - (fn [net-map [tree-type id sub-trees xf label]] |
24 |
| - (let [node-path [tree-type id]] |
25 |
| - (cond-> net-map |
26 |
| - (not (nil? xf)) |
27 |
| - (assoc-in (conj node-path :xf) xf) |
28 |
| - |
29 |
| - (not (nil? label)) |
30 |
| - (assoc-in (conj node-path :label) label) |
31 |
| - |
32 |
| - (not (or (= tree-type :output) (nil? super-path))) |
33 |
| - (-> (update-in (conj node-path :outputs) (fnil conj #{}) super-path) |
34 |
| - (update-in (conj super-path :inputs) (fnil conj #{}) node-path)) |
35 |
| - |
36 |
| - true |
37 |
| - (walk-trees sub-trees node-path)))) |
38 |
| - net-map |
39 |
| - (normalize-inputs trees)))] |
40 |
| - (walk-trees {:label label} trees nil))) |
41 |
| - |
42 |
| -(defn postwalk [net-xf roots update-fn] |
43 |
| - (let [orig-net-map (net-xf) |
44 |
| - kids (case roots :input :outputs :inputs) |
45 |
| - root-paths (for [k (-> orig-net-map roots keys)] |
46 |
| - [roots k])] |
47 |
| - |
48 |
| - (letfn [(update-node [net-map path] |
49 |
| - (update-in |
50 |
| - net-map path |
51 |
| - (fn [node] |
52 |
| - (update-fn |
53 |
| - path node |
54 |
| - (for [kid-path (kids node)] |
55 |
| - (get-in net-map kid-path)))))) |
56 |
| - |
57 |
| - (visit-node [net-map path] |
58 |
| - (if (-> net-map meta ::visited (contains? path)) |
59 |
| - net-map |
60 |
| - (-> net-map |
61 |
| - (vary-meta update ::visited conj path) |
62 |
| - (visit-nodes (get-in net-map (conj path kids))) |
63 |
| - (update-node path)))) |
64 |
| - |
65 |
| - (visit-nodes [net-map paths] |
66 |
| - (reduce visit-node net-map paths))] |
67 |
| - |
68 |
| - (-> orig-net-map |
69 |
| - (vary-meta assoc ::visited #{}) |
70 |
| - (visit-nodes root-paths))))) |
71 |
| - |
72 |
| -(defn assert-no-outputs [inputs] |
73 |
| - (assert (->> inputs normalize-inputs (map first) (every? #{:input :node})) |
74 |
| - "Output nodes are not allowed as inputs") |
75 |
| - inputs) |
76 |
| - |
77 |
| -;; Attempt 6? 7? at API |
78 |
| -(defn match-tags |
79 |
| - ([xf-map xs] (sequence (match-tags xf-map) xs)) |
80 |
| - ([xf-map] (t/multiplex (map (fn [[k xf]] |
81 |
| - (comp (t/detag k) |
82 |
| - xf)) |
83 |
| - xf-map)))) |
84 |
| - |
85 |
| -(defn make-net-xf |
86 |
| - ([net-xf xs] (sequence (make-net-xf net-xf) xs)) |
87 |
| - ([net-xf] |
88 |
| - (-> net-xf |
89 |
| - (postwalk |
90 |
| - :input |
91 |
| - (fn [[node-type node-id] {:keys [xf inputs outputs]} output-xfs] |
92 |
| - (let [output-xfs' (if (empty? output-xfs) [identity] output-xfs) |
93 |
| - multiplex' (if (= (count output-xfs') 1) first t/multiplex) |
94 |
| - demultiplex' (if (= (count inputs) 1) identity t/demultiplex)] |
95 |
| - (condp = node-type |
96 |
| - :input (multiplex' output-xfs') |
97 |
| - :node (demultiplex' (comp xf (multiplex' output-xfs'))) |
98 |
| - :output (demultiplex' (t/tag node-id)))))) |
99 |
| - :input |
100 |
| - match-tags))) |
101 |
| - |
102 |
| -(defn net |
103 |
| - ([label net-tree xs] (sequence (net net-tree) xs)) |
104 |
| - ([label net-tree] |
105 |
| - (let [net-map (normalize-net label net-tree)] |
106 |
| - ^:xfn |
107 |
| - (fn transducer |
108 |
| - ([] net-map) |
109 |
| - ([rf] ((make-net-xf transducer) rf)))))) |
110 |
| - |
111 |
| -(defn input [k] (list :input k #{})) |
112 |
| -(defn output [k inputs] (list :output k (assert-no-outputs inputs))) |
113 |
| - |
114 |
| -(defn node* [label xf inputs] |
115 |
| - (list :node |
116 |
| - (gensym 'n) |
117 |
| - (assert-no-outputs inputs) |
118 |
| - xf |
119 |
| - label)) |
120 |
| - |
121 |
| -(defmacro node [xf inputs] |
122 |
| - (let [label (if (sequential? xf) |
123 |
| - (if (symbol? (first xf)) |
124 |
| - (if (= (count xf) 1) |
125 |
| - (str (first xf)) |
126 |
| - (if (sequential? (second xf)) |
127 |
| - (str (first xf) " …") |
128 |
| - (if (> (count xf) 2) |
129 |
| - (str (first xf) " " (second xf) " …") |
130 |
| - (str (first xf) " " (second xf)))))) |
131 |
| - (str xf))] |
132 |
| - `(node* '~label ~xf ~inputs))) |
133 |
| - |
134 |
| -(defn embed [net-xf input-map] |
135 |
| - (-> net-xf |
136 |
| - (postwalk |
137 |
| - :output |
138 |
| - (fn [[node-type node-id] {xf :xf label :label} input-xfs] |
139 |
| - (condp = node-type |
140 |
| - :input (input-map node-id) |
141 |
| - :node (node* label xf (set input-xfs)) |
142 |
| - :output (set input-xfs)))) |
143 |
| - :output)) |
144 |
| - |
145 |
| -(defrecord Passive [x] |
146 |
| - clojure.lang.IDeref |
147 |
| - (deref [_] x)) |
148 |
| - |
149 |
| -(defn passive? [x] |
150 |
| - (instance? Passive x)) |
151 |
| - |
152 |
| -(defn passive [x] |
153 |
| - (if (passive? x) |
154 |
| - x |
155 |
| - (Passive. x))) |
156 |
| - |
157 |
| -(defn active? [x] |
158 |
| - (not (passive? x))) |
159 |
| - |
160 |
| -(defn active [x] |
161 |
| - (if (active? x) |
162 |
| - x |
163 |
| - (deref x))) |
164 |
| - |
165 |
| -(defn join [inputs] |
166 |
| - ;; The nodes defined here are mislabeled for readability. Short term fix. |
167 |
| - ;; Longer term, join should be represented as a subnet. |
168 |
| - (let [active-inputs? (mapv active? inputs)] |
169 |
| - (node* |
170 |
| - 'join |
171 |
| - (t/join-index-tags active-inputs?) |
172 |
| - (->> inputs |
173 |
| - (map active) |
174 |
| - (map-indexed |
175 |
| - #(node* (if (active-inputs? %1) 'active 'passive) |
176 |
| - (t/tag %1) |
177 |
| - %2)) |
178 |
| - set)))) |
179 |
| - |
180 |
| -;; printing/debugging |
181 |
| -(defn compact-net-map [net-map] |
182 |
| - (letfn [(compact-paths [paths] (map second paths))] |
183 |
| - (concat |
184 |
| - (map (fn [[k {:keys [outputs]}]] |
185 |
| - [k :outputs (compact-paths outputs)]) |
186 |
| - (:input net-map)) |
187 |
| - (map (fn [[k {:keys [outputs inputs]}]] |
188 |
| - [k :outputs (compact-paths outputs) :inputs (compact-paths inputs)]) |
189 |
| - (:node net-map)) |
190 |
| - (map (fn [[k {:keys [inputs]}]] |
191 |
| - [k :inputs (compact-paths inputs)]) |
192 |
| - (:output net-map))))) |
193 |
| - |
194 |
| -(defn pr-net [net-xf] |
195 |
| - (compact-net-map (net-xf))) |
0 commit comments