                 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
 


;; FLOW PLAN

(defrecord FlowPlan [node->flow flow->node])

(defn flow-plan->flow-state [{:keys [node->flow]}]
  (let [node->state (into-array (for [_ node->flow] nil))
        node->out-nodes (into-array (for [_ node->flow] #js []))
        node->facts (into-array (for [_ node->flow] #js []))

  (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 :pretended connected)
                 (add-rules [(Rule. [(Recall. :known|pretended (->edge 'x 'y))
                                     (Output. :pretended (->connected 'x 'y))])
                             (Rule. [(Recall. :known|pretended (->edge 'x 'y))
                                     (Recall. :known|pretended (->connected 'y 'z))
                                     (Output. :pretended (->connected 'x 'z))])]))
        state (flow-plan->flow-state plan)]
    (add-facts state :known|pretended edge #js [(->edge 0 1) (->edge 1 2) (->edge 2 3) (->edge 3 1)])
    (time (fixpoint! state))
    (get-facts state :known|pretended connected))

  (enable-console-print!)

  (let [plan (-> empty-flow-plan
                 (add-shape :known edge)
                 (add-shape :pretended connected)
                 (add-rules [(Rule. [(Recall. :known|pretended (->edge 'x 'y))
                                     (Output. :pretended (->connected 'x 'y))])
                             (Rule. [(Recall. :known|pretended (->edge 'x 'y))
                                     (Recall. :known|pretended (->connected 'y 'z))
                                     (Output. :pretended (->connected 'x 'z))])]))
        state (flow-plan->flow-state plan)]
    (add-facts state :known|pretended edge (into-array (for [i (range 100)] (->edge i (inc i)))))
    (js/console.time "new")
    (fixpoint! state)
    (js/console.timeEnd "new")
    (get-facts state :known|pretended connected))
  ;; 5 => 1 ms
  ;; 10 => 8 ms
  ;; 50 => 1093 ms
  ;; 100 => 11492 ms

  (let [plan (-> empty-flow-plan
                 (add-shape :known edge)
                 (add-shape :pretended connected)
                 (add-rules [(Rule. [(Recall. :known|pretended (->edge 'x 'y))
                                     (Compute. (->Let 'z '[x y] "x + y"))
                                     (Output. :pretended (->connected 'z 'z))])]))
        state (flow-plan->flow-state plan)]
    (add-facts state :known|pretended edge (into-array (for [i (range 100)]
                                                         (->edge i (inc i)))))
    (fixpoint! state)
    (get-facts state :known|pretended connected))
  )

;; TIME AND CHANGE

(defn add-facts [state memory shape facts]
  (memory! memory)
  (let [node (get-memory (:plan state) memory shape)
        arr (aget (:node->facts state) node)]
    (doseq [fact facts]
      (apush arr fact))
    state))

(defn get-facts [state memory shape]
  (memory! memory)
  (let [node (get-memory (:plan state) memory shape)
        facts (persistent! (aget (:node->state state) node))]
    (aset (:node->state state) node (transient facts))
    facts))

;; TODO make this incremental
;; TODO wasteful to do the persistent/transient dance when there are no remembered/forgotten facts
(defn tick
  ([plan] (tick plan (flow-plan->flow-state plan)))
  ([plan state]
   (let [new-state (flow-plan->flow-state plan)]
     (doseq [shape (get-in plan [:kind->shape :known])]
       (let [known (transient (get-facts state :known|pretended shape))
             remembered (get-facts state :remembered shape)
             forgotten (get-facts state :forgotten shape)]
         (doseq [fact remembered]
           (when (not (contains? forgotten fact))
             (conj!! known fact)))
         (doseq [fact forgotten]
           (when (not (contains? remembered fact))
             (disj!! known fact)))
         (add-facts new-state :known|pretended shape (persistent! known))))
     new-state)))

(defn tick&fixpoint [plan state]
