                 Lookup (lookup-update! (:index-node flow) (:key-ixes flow) (:val-ixes flow))))))
     (FlowState. node->state node->out-nodes node->facts node->update! trace plan)))
 
-(defn memory->node [memory]
-  (case memory
-    :known 0
-    :pretended 1
-    :remembered 2
-    :forgotten 3))
-
-(defn memory->nodes [memory]
-  (case memory
-    :known [0]
-    :pretended [1]
-    :remembered [2]
-    :forgotten [3]
-    :known&pretended [0 1]))
-
 (def empty-flow-plan
-  (FlowPlan. [(Union. #{}) (Union. #{}) (Union. #{}) (Union. #{})] {}))
-
-(defn add-output [flow-plan node memory]
-  (update-in flow-plan [:node->flow (memory->node memory) :nodes] conj node))
+  (FlowPlan. [] {} {} {}))
+
+(defn add-flow-without-memo [{:keys [node->flow flow->node] :as flow-plan} flow]
+  (let [node (count node->flow)
+        node->flow (conj node->flow flow)
+        flow->node (assoc flow->node flow node)]
+    [(assoc flow-plan :node->flow node->flow :flow->node flow->node) node]))
 
 (defn add-flow [{:keys [node->flow flow->node] :as flow-plan} flow]
-  (if-let [node (flow->node flow)]
+  (if-let [node (get flow->node flow)]
     [flow-plan node]
-    (let [node (count node->flow)
-          node->flow (conj node->flow flow)
-          flow->node (assoc flow->node flow node)]
-      [(FlowPlan. node->flow flow->node) node])))
+    (add-flow-without-memo flow-plan flow)))
+
+(defn memory! [memory]
+  (assert (#{:known|pretended :remembered :forgotten} memory) (pr-str memory)))
+
+(defn add-memory [{:keys [node->flow memory->shape->node] :as flow-plan} memory shape]
+  (memory! memory)
+  (let [[flow-plan node] (add-flow-without-memo flow-plan (Union. #{}))
+        memory->shape->node (assoc-in memory->shape->node [memory shape] node)]
+    (assoc flow-plan :memory->shape->node memory->shape->node)))
+
+(defn add-shape [flow-plan kind shape]
+  (case kind
+    :pretended (-> flow-plan
+                   (add-memory :known|pretended shape)
+                   (update-in [:kind->shape kind] #(conj (or % #{}) shape)))
+    :known (-> flow-plan
+               (add-memory :known|pretended shape)
+               (add-memory :remembered shape)
+               (add-memory :forgotten shape)
+               (update-in [:kind->shape kind] #(conj (or % #{}) shape)))))
+
+(defn get-memory [{:keys [memory->shape->node]} memory shape]
+  (memory! memory)
+  (or (get-in memory->shape->node [memory shape])
+      (assert false (str "No node for " (pr-str memory) " " (pr-str shape)))))
+
+(defn add-input [flow-plan output-node memory shape]
+  (update-in flow-plan [:node->flow output-node :nodes] conj (get-memory flow-plan memory shape)))
+
+(defn add-output [flow-plan input-node memory shape]
+  (update-in flow-plan [:node->flow (get-memory flow-plan memory shape) :nodes] conj input-node))
+
 
 ;; IXES
 

    Output (let [{:keys [memory pattern]} clause
                 _ (assert (every? (set vars) (pattern->vars pattern)))
                 [plan output-node] (add-flow plan (FilterMap. nodes (pattern->constructor vars pattern)))
                 plan (add-output plan output-node memory)]
             [plan nodes vars])))

(comment


(defn rules->plan [rules]
  (add-rules empty-flow-plan rules))

(comment
  (deffact edge "[x] has an edge to [y]")
  (deffact connected "[x] is connected to [y]")

  (let [plan (-> empty-flow-plan
                 (add-shape :known edge)
                 (add-shape :known connected)
                 (add-rules
                  [(Rule. [(Recall. :known|pretended (->edge 'x 'y))
                           (Output. :remembered (->connected 'x 'y))])
                   (Rule. [(Recall. :known|pretended (->edge 'x 'y))
                           (Recall. :known|pretended (->connected 'y 'z))
                           (Output. :remembered (->connected 'x 'z))])]))
        state-0 (flow-plan->flow-state plan)]
    (add-facts state-0 :known|pretended edge #js [(->edge 0 1) (->edge 1 2) (->edge 2 3) (->edge 3 1)])
  (fixpoint! state-0)
  (for [state (take 5 (iterate #(tick&fixpoint plan %) state-0))]
    (count (get-facts state :known|pretended connected))))
  )

;; RESOLVE
