 
 ;; TODO: generalize goal condition, etc.
 
+(deftype PartialResult [result-pairs max-reward])
+
 (defn incremental-dijkstra 
   "Expand queue items until (1) goal, or (2) (queue-cutoff queue min-reward). 
    Safe against recursive calls in expand-fn, which takes a node and min-reward and
-   returns [[old-node new-reward] & [new-node reward]*]"
+   returns a PartialResult of nodes."
   [queue min-reward expand-fn goal-fn]
   (loop []
     (or (let [cutoff (queue-best-reward queue)] 
-          (when (not (viable? cutoff min-reward)) cutoff)) 
+          (when (not (viable? cutoff min-reward)) (PartialResult nil cutoff))) 
         (let [[best best-reward] (pop-queue queue)]
-          (or (when-let [g (goal-fn best)] [g best-reward])
+          (or (when-let [g (goal-fn best)] (PartialResult [[g best-reward]] (queue-best-reward queue)))
               (let [next-min-reward (max min-reward (queue-best-reward queue))]
                 (queues/pq-replace! queue best (make-queue-priority best-reward))
-                (let [[[_ new-reward] & new-items] (expand-fn best next-min-reward)]
-                  (assert (identical? _ best))
-                  (queues/pq-replace! queue best (make-queue-priority new-reward))
-                  (doseq [[ni nr] new-items] 
+                (let [{:keys [result-pairs max-reward]} (expand-fn best next-min-reward)]
+                  (queues/pq-replace! queue best (make-queue-priority max-reward))
+                  (doseq [[ni nr] result-pairs] 
                     (queues/pq-add! queue ni (make-queue-priority nr)))
                   (recur))))))))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Outcome maps ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
+
+(defn make-descendents [state action prim-constructor ref-constructor]
+  (if (env/primitive? action)
+      (when-let [[ss sr] (and (env/applicable? action state) (env/successor action state))]
+        [(prim-constructor ss sr)])
+    (map ref-constructor (hierarchy/immediate-refinements action state))))
 
 (defn generalize-outcome-pair [[outcome-state reward] gen-state reward-to-gen-state]
   [(vary-meta (env/apply-effects gen-state (env/extract-effects outcome-state)) assoc 


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; State-Abstracted Search ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defn make-search-in-context [subsearch context-state context-reward]
  (reify IncrementalSearch
    (next-solution-or-cutoff [min-reward]
      (let [result (next-solution-or-cutoff subsearch (- min-reward context-reward))]
        (if (number? result) (+ result context-reward)
          (generalize-outcome-pair result context-state context-reward))))))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    (fn cache-factory []
      (let [index-atom   (atom 0)]
        (reify IncrementalSearch
          (next-partial-solution [min-reward]
            (if (< @index-atom (count @result-vec-atom))
                (let [[_ rew :as result] (nth @result-vec-atom @index-atom)]
                  (if (>= rew min-reward)
                      (do (swap! index-atom inc) 
                          (PartialResult [result] 
                                         (max (get @result-vec-atom @index-atom Double/NEGATIVE_INFINITY) 
                                              @next-reward-atom)))
                    (PartialResult nil rew)))
              (if (viable? @next-reward-atom min-reward)
                  (let [{:keys [result-pairs max-reward]} (next-partial-solution search-problem min-reward)]
                    (reset! next-reward-atom max-reward)
                    (swap!  result-vec-atom into result-pairs)
                    (recur min-reward))
                (PartialResult nil @next-reward-atom)))))))))

(def #^HashMap *problem-cache*)

