 (defprotocol Subproblem
   (stub              [s])
   (output-set        [s])
-  (tree-summarizer   [s] "Summarizer that includes children.")
   (terminal?         [s] "Subproblem will not return any outputs.")
   (refine-input      [s refined-input-set] "Return a child stub."))
 
-(defn- subproblem-name [s] (stub-name (stub s)))
+(defn- sp-name [s] (stub-name (stub s)))
+(defn- sp-sf [s] (stub-factory (stub s)))
 
 (defmethod print-method angelic.search.implicit.dash_astar.Subproblem [sp o]
-  (print-method (format "#<SP$%8h %s>" (System/identityHashCode (stub sp)) (subproblem-name sp)) o))
-
-
-(defn- connect-subsuming! [child subsuming-sp]
-  (when subsuming-sp (summaries/connect! child (tree-summarizer subsuming-sp) true)))
+  (print-method (format "#<SP$%8h %s>" (System/identityHashCode (stub sp)) (sp-name sp)) o))
 
 (defn- add-sp-child! [sp child-sp]
   (assert (not (terminal? sp)))
   (summaries/summary-changed-local! sp)
   (add-output! sp child-sp))
 
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;  Tree Summarizer  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-
-
-;; TODO: propagate top-down-bounds downward in smarter way using existing IS?
-;; TODO: we need to make sure tree sums get called on add-output! first to ensure
-;;       consistency with top-down-bounds ? 
-;; TODO: top-down bound business does not actually help at all
-
-;;  (except ensuring consistency if we're asserting it...)
-;; When we create a stub, we also get: tree summarizer, subsumption-thing.
-;; (subsumption-children are parent tree-summarizers).
-;; Subsumption-thing is subsumption-child of stub, summarizer, tree-summarizer.
-;; Tree-summarizers also remember best bound, this gives us consistency
-;; How do they pass to children, though?
-;; Apparent cycle -- tree summarizer has children that are child tree-summarizers,
-;; And, these children should have the parent TS as a subsumption child.
-;; Key: this is only to preserve info from original SP, subsumption..
-;; This info should go into subsumption-thing.
-;; Subsumption-thing is just ordinary max over children, + self, + TS?
-;; ->>(We rely on eager updates to make sure it gets updated?)
-
-;; TDB should not actually go into TS, children should be directly bounded?
-;; All children, including inner SP, should do it fine.
-;; This means that every thing has exactly one subsumption parent ... which is nice.
-;; How does consistency get approached ?
-;; We just have the cycle, but would be great if we didn't have to go in child --> ts --> st --> children
-;; cycle every time things to up -- maybe ST just doesn't update ord. parents.
-;; TODO: figure this out later. 
-
-
-;; Can goall the way down to nearest sum, I guess...
-;; Subsumer gets attached to subsumer of any child (or inner child?)
-
-;; What do we do about multiple ways to express a given plan ? ? ? ?
-;; Can normalize or not, interesting question... start without. 
-
-(defprotocol TreeSummarizer
-  (top-down-bound    [s])
-  (add-top-down-bound! [s b]))
-
-(defn- tree-summarizer? [s] (instance? angelic.search.implicit.dash_astar.TreeSummarizer s))
-
-(defn- make-tree-summarizer [init-bound]
- (let [tdb-atom (atom  init-bound)]
-   (traits/reify-traits [summaries/simple-cached-node]
-     TreeSummarizer (top-down-bound [s] @tdb-atom)
-                    (add-top-down-bound! [s b]
-                      (when (< b @tdb-atom) ;; ;; Note: adding < current max-reward actually hurts...
-                        (reset! tdb-atom b)
-                        (doseq [c (summaries/node-ordinary-children s)]
-                          (when (tree-summarizer? c)
-                            (add-top-down-bound! c b)))
-                        (summaries/summary-changed! s)))    
-     summaries/Summarizable (summarize [s] (summaries/or-summary s  @tdb-atom)))))
-
-(defn- init-tree-summarizer! [ts inner-sp subsuming-sp]
-  (connect-and-watch! ts inner-sp
-    (fn [child-sp]
-      (summaries/connect! ts (tree-summarizer child-sp) false)
-      (add-top-down-bound! (tree-summarizer child-sp) (top-down-bound ts))
-      (summaries/summary-changed! ts))) ;; TODO: speedup by checking child reward? 
-  (connect-subsuming! ts subsuming-sp))
-
-(defn- get-inner-sp [ts]
-  (->> (summaries/node-ordinary-children ts)
-       (remove tree-summarizer?)
-       util/safe-singleton))
-
-(defn- ts-str [sp])
-(defmethod print-method angelic.search.implicit.dash_astar.TreeSummarizer [ts o]
-  (let [stub (stub (get-inner-sp ts))]
-    (print-method (format "#<TS$%8h %s>" (System/identityHashCode stub) (stub-name stub)) o)))
-
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;  Subproblem Impl  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-(traits/deftrait simple-subproblem [stb out-set ts term? ri-fn] [] [watched-node]
+(traits/deftrait simple-subproblem [stb out-set term? ri-fn] [] [watched-node]
   Subproblem (stub            [s] stb)
              (output-set      [s] out-set)
-             (tree-summarizer [s] ts)
              (terminal?       [s] term?)
              (refine-input    [s ni] (ri-fn s ni)))
 
-
-(defn- make-simple-subproblem [stub subsuming-sp out-set terminal? summary-fn ri-fn init-bound]
-  (let [ts  (make-tree-summarizer init-bound)
-        ret (traits/reify-traits [(simple-subproblem stub out-set ts terminal? ;; Note ni may have different context.
-                                                     (fn [s ni] (if (= ni (input-set stub)) stub (ri-fn s ni))))]
-              summaries/Summarizable (summarize [s] (summary-fn s (top-down-bound ts))))]
-    (init-tree-summarizer! ts ret subsuming-sp)
-    ret))
-
-
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;     Wrappers     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;     Output Collection     ;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-
-(declare make-output-collecting-subproblem)
-(defn- make-output-collecting-stub [inner-stub]
-  (assert (not (= (first (stub-name inner-stub)) :OS)))
-  (assert (not (= (first (stub-name inner-stub)) :SA)))
-  (make-wrapping-stub
-   [[:OS (stub-name inner-stub)] (input-set inner-stub)]
-   inner-stub make-output-collecting-subproblem))
-
-
-(defn- =-state-sets [s1 s2]
-  (util/assert-is (= (state/current-context s1) (state/current-context s2)) "%s" [s1 s2])
-  (= s1 s2))
-
-(defn- make-output-collecting-subproblem [stb inner-sp]
-  (let [;        counter (HashMap.)
-        ts  (tree-summarizer inner-sp)
-        ret (traits/reify-traits 
-             [(simple-subproblem stb (output-set inner-sp) ts false
-                                 #(doto (if (= (input-set stb) %2) stb (refine-input inner-sp %2)) ;Needed when SA off
-                                    (-> stub-name first #{:SA :OS} assert)))]
-             summaries/Summarizable (summarize [s] (summaries/or-summary s (top-down-bound ts))))]
-    (connect-and-watch! ret inner-sp
-      (fn child-watch [o]
-        (if (=-state-sets (output-set inner-sp) (output-set o))
-          (do (connect-and-watch! ret o child-watch)
-              (summaries/summary-changed! ret))
-          (do #_ (let [c (.get counter (input-set (stub o)))]
-                (when c (println c (stub-name (stub o))))
-                (.put counter (input-set (stub o)) (inc (or c 0))))
-              
-              (if (#{:SA :OS} (first (subproblem-name o))) 
-                (add-sp-child! ret o)
-                (connect-and-watch-stub! ret (make-output-collecting-stub (stub o)) #(add-sp-child! ret %))))))) ;; No update needed
-    ret))
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;     State Abstraction     ;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-
-(declare make-state-abstracted-subproblem)
-(defn- make-eager-state-abstracted-stub [inner-stub in-set]
-  (make-wrapping-stub [[:SA (stub-name inner-stub)] in-set] inner-stub make-state-abstracted-subproblem))
-
-
-(defn- make-deliberate-state-abstracted-stub [inner-stub in-set]
-  (if-let [out (get-stub-output inner-stub)]
-    (let [done? (atom false)  
-          ret
-          (traits/reify-traits
-           [(simple-stub [:SA (stub-name inner-stub) in-set] in-set)]
-           summaries/Summarizable
-           (summarize [s]
-            (if @done? summary/+worst-simple-summary+
-                (summary/make-live-simple-summary
-                 (summary/max-reward (summaries/summary (tree-summarizer out))) s)))   
-           Evaluable
-           (evaluate! [s] (reset! done? true)
-            (set-stub-output! s (make-state-abstracted-subproblem s out))))]
-      (summaries/connect! ret out false)
-      ret)
-    (make-eager-state-abstracted-stub inner-stub in-set)))
-
-
-(defn- make-state-abstracted-stub [inner-stub in-set]
-  ((case *state-abstraction*
-     :eager make-eager-state-abstracted-stub
-     :deliberate make-deliberate-state-abstracted-stub)
-   inner-stub in-set))
-
-
-;; Note: subsumed subproblems can have different irrelevant vars
-(defn- make-state-abstracted-subproblem [stb inner-sp]
-  (let [ts  (tree-summarizer inner-sp)
-        in  (input-set stb)
-        out (state/transfer-effects in (output-set inner-sp))
-        ri-fn #(if (=-state-sets %2 in) stb (refine-input inner-sp %2))
-        ret (traits/reify-traits
-             [summaries/or-summarizable (simple-subproblem stb out ts (terminal? inner-sp) ri-fn)])]
-    (connect-and-watch! ret inner-sp
-      (fn [o] (connect-and-watch-stub-up! ret (make-state-abstracted-stub (stub o) in) #(add-sp-child! ret %))))
-    ret))
+;; Note: summary-fn should take subsuming-bound into account.
+(defn- make-simple-subproblem [stub out-set terminal? summary-fn ri-fn]
+  (traits/reify-traits
+   [(simple-subproblem stub out-set ts terminal? ;; Note ni may have different context.
+                       (fn [s ni] (if (= ni (input-set stub)) stub (ri-fn s ni))))]
+   summaries/Summarizable (summarize [s] (summary-fn s 0))))
+
 
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;;;;;;;;;;;;;;;;;;;;;;;;;     Core Subproblems     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;      Names       ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+(defn atomic-name [fs] [:Atomic fs])
+(defn pair-name [l r] [:Pair l r])
+
+(defn left-factor [s]
+  (loop [s (next s) ret (first s)]
+    (if s
+      (recur (next s) (pair-name ret (first s)))
+      ret)))
+
+(defn right-factor [[f & r]]
+  (if (seq r)
+    (pair-name f (right-factor r))
+    f))
+
+(defn- make-fs-seq-name [fs-seq]
+  (assert (seq fs-seq))
+  ((if *left-recursive* left-factor right-factor)
+   (map atomic-name fs-seq)))
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;      Atomic       ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (declare make-fs-seq-stub get-atomic-stub)
 
-(defn- make-atomic-subproblem [stub function-set subsuming-sp out-set reward status]
-  (let [inp-set  (input-set stub)
-        ri-fn    (fn [s ri] (get-atomic-stub s ri function-set))]
+(defn- make-atomic-subproblem [stb out-set reward status subsuming-sp]
+  (let [inp-set  (input-set stb)
+        ri-fn    (fn [s ri] (get-stub (stub-factory stb) inp-set s))]
     (cond (not (= status :live))
           (make-simple-subproblem
-           stub subsuming-sp out-set true
-           (fn [s b] (summary/make-simple-summary (min b reward) status s)) ri-fn reward)
+           stb out-set true
+           (fn [s b] (summary/make-simple-summary (min (subsuming-bound s) b reward) status s)) ri-fn)
           
           (and subsuming-sp (not (terminal? subsuming-sp))) 
-          (let [ret (make-simple-subproblem stub subsuming-sp out-set false summaries/or-summary ri-fn reward)]
+          (let [ret (make-simple-subproblem stb subsuming-sp out-set false summaries/or-summary ri-fn)]
             (connect-and-watch! ret subsuming-sp
               (fn [sub-out]
                 (connect-and-watch-stub-up! ret (refine-input sub-out inp-set) #(add-sp-child! ret %))))
             ret)
           
-          :else 
-          (let [ret (make-simple-subproblem stub subsuming-sp out-set false summaries/or-summary ri-fn reward)]
-            (doseq [child (map #(make-fs-seq-stub inp-set %) (fs/child-seqs function-set inp-set))]
-              (connect-and-watch-stub! ret child #(add-sp-child! ret %)))
+          :else ;; TODO
+          (let [ret (make-simple-subproblem stb out-set false summaries/or-summary ri-fn)]
+            (doseq [child-name (map make-fs-seq-name (fs/child-seqs function-set inp-set))]
+              (connect-and-watch-stub! ret (get-stub-by-name child-name inp-set)
+                 #(add-sp-child! ret %)))
             ret))))
 
 ;; Note: this is double-stage to lazily generate children.  Could be simpler single-stage.
-(defn- make-atomic-stub [name subsuming-sp inp-set function-set]
-  (let [state (atom :ready) ;; set to [out-set reward] after first eval, then :go after second.
-        ret
-        (traits/reify-traits [(simple-stub name inp-set)]
-         summaries/Summarizable
-         (summarize [s]
-           (cond (= :ready @state) (summary/make-live-simple-summary (summaries/subsuming-bound s) s)
-                 (= :go    @state) summary/+worst-simple-summary+
-                 :else             (summary/make-live-simple-summary
-                                    (min (summaries/subsuming-bound s) (second @state)) s)))   
-         Evaluable
-         (evaluate! [s]
-           (assert (not (= :go @state)))
-           (let [ready? (= :ready @state)]
-             (if-let [[out-set reward :as op] (if ready? (fs/apply-opt function-set inp-set) @state)]
-               (let [status (if ready? (fs/status function-set inp-set)   :live)]
-;                 (println "eval" s ready? status reward)
-                 (if (or (not ready?) (not (= status :live)))
-                   (do (reset! state :go)
-                       (->> (make-atomic-subproblem s function-set subsuming-sp out-set reward status)
-                            (set-stub-output! s)))
-                   (do (reset! state op) (summaries/summary-changed! s))))
-               (do (reset! state :go) (summaries/summary-changed! s))))))]
-    (connect-subsuming! ret subsuming-sp)
-    ret))
-
-;; Note: we must always wrap in S-A stub to get effects out of logger. 
-(defn- get-atomic-stub [subsuming-sp inp-set function-set]
-  (let [full-name [:Atomic (fs/fs-name function-set)
-                   (if *state-abstraction* (fs/extract-context function-set inp-set) inp-set)]
-        make-stub #(let [r (make-atomic-stub [:Atomic (fs/fs-name function-set)] subsuming-sp % function-set)]
-                     (if *collect-equal-outputs* (make-output-collecting-stub r) r))]
-    (if-let [^HashMap dc *decompose-cache*]
-      (if *state-abstraction*
-        (let [stub (util/cache-with dc full-name (make-stub (fs/get-logger function-set inp-set)))]
-          (make-state-abstracted-stub stub inp-set))   
-        (util/cache-with dc full-name (make-stub inp-set)))
-     (make-stub inp-set))))
+(defn- make-atomic-stub [sf inp-set subsuming-sp]
+  (let [state (atom :ready)]  ;; set to [out-set reward] after first eval, then :go after second.
+    (traits/reify-traits [(simple-stub sf inp-set)]
+      summaries/Summarizable
+      (summarize [s]
+       (cond (= :ready @state) (summary/make-live-simple-summary (summaries/subsuming-bound s) s)
+             (= :go    @state) summary/+worst-simple-summary+
+             :else             (summary/make-live-simple-summary
+                                (min (summaries/subsuming-bound s) (second @state)) s)))   
+      Evaluable
+      (evaluate! [s]
+        (assert (not (= :go @state)))
+        (let [fs     (second (sf-name sf))
+              ready? (= :ready @state)]
+          (if-let [[out-set reward :as op] (if ready? (fs/apply-opt fs inp-set) @state)]
+            (let [status (if ready? (fs/status fs inp-set)   :live)]
+              (if (or (not ready?) (not (= status :live)))
+                (do (reset! state :go)
+                    (->> (make-atomic-subproblem s subsuming-sp out-set reward status)
+                         (set-stub-output! s)))
+                (do (reset! state op) (summaries/summary-changed! s))))
+            (do (reset! state :go) (summaries/summary-changed! s))))))))
+
+(defmethod make-stub-factory :Atomic [[_ fs :as n]]
+  (make-simple-stub-factory n make-atomic-stub))
+
+;; TODO: subsuming-sp should get connected to atomic-stub outside of make-atomic-stub
+;; (since it may already exist)!
+;; Note: we must always wrap in S-A stub to get effects out of logger.
+(comment
+ (defn- get-atomic-stub [subsuming-sp inp-set function-set]
+   (let [full-name [:Atomic (fs/fs-name function-set)
+                    (if *state-abstraction* (fs/extract-context function-set inp-set) inp-set)]
+         make-stub #(let [r (make-atomic-stub [:Atomic (fs/fs-name function-set)] subsuming-sp % function-set)]
+                      (if *collect-equal-outputs* (make-output-collecting-stub r) r))]
+     (if-let [^HashMap dc *decompose-cache*]
+       (if *state-abstraction*
+         (let [stub (util/cache-with dc full-name (make-stub (fs/get-logger function-set inp-set)))]
+           (make-state-abstracted-stub stub inp-set))   
+         (util/cache-with dc full-name (make-stub inp-set)))
+       (make-stub inp-set)))))
 
 
 


(declare make-pair-stub1 make-pair-stub2)

;; NOTE: subsumption doesn't seem to help
;; TODO: fix up subsuming, parent, etc.
;; nils at bottom should chase subsuming-sp.
;; Note: this is the only place logic depends on summary.  Potential for problems?
(defn- make-pair-subproblem [subsuming-sp pair-stub left-sp right-sp]
  (let [expand-right? (and (summary/solved? (summaries/summary left-sp)) (empty? (get-outputs left-sp)))
        kids (if expand-right? [(tree-summarizer left-sp) right-sp] [left-sp (tree-summarizer right-sp)])
        ss   (summaries/make-sum-summarizer kids)
        ret (make-simple-subproblem
             pair-stub subsuming-sp (output-set right-sp) false             
             (if (or expand-right? (not *collect-equal-outputs*)) summaries/or-summary
                 (let [left-done? (atom false)] ;; Manually take into account left-solved, when no output message.
                   (fn [s b] 

(defn- connect-and-watch-stub-up! [p c f]
  (when (connect-and-watch-stub! p c f) (summaries/summary-changed! p)))

(defn- make-wrapping-stub [[sf in-set] inner-stub sp-fn]
  (let [ret (traits/reify-traits [summaries/or-summarizable (simple-stub sf in-set)])]
    (connect-and-watch-stub! ret inner-stub #(set-stub-output! ret (sp-fn ret %)))
    ret))

