         root  (get-sa-node cache init (hierarchy/TopLevelAction e [(hierarchy/initial-plan henv)]))]
     (loop [cutoff 0 last-cutoff 0]
       (let [result (expand-sa-node root cache cutoff init 0.0 last-cutoff)]
-;        (println "TOP" (:cutoff result) cutoff last-cutoff result)
         (cond (not (empty? (:result-map result)))
                 (let [[k v] (util/first-maximal-element val (:result-map result))]
-;                  (println k)
                   [(:opt (meta k)) v])
               (> (:cutoff result) Double/NEGATIVE_INFINITY)
                 (recur (:cutoff result) cutoff))))))

;; This version may be inefficient in graphy domains, but should still be complete+optimal
;; (as long as rewards for primitives are strictly negative)

;; TODO: pass incremental updates upwards. 
;; Difficulty: nodes with multiple ancestors.



(deftype PartialResult [result-map cutoff])


;; A PartialResult stores a map from states to rewards, where a state is present
;; iff it has reward > cutoff. 

(deftype SANode [context action result-map-atom queue])

;(defstruct sanode-struct :context :action :result-map-atom :queue)
;(defn SANode [c a r q] (struct sanode-struct c a r q))

;; Represents an action sequence from a state, with sanode representing the first action in remaining-actions.
 ; (or nil, if remaining-actions is empty.)
(deftype SANodeEntry [state sanode reward-to-state remaining-actions hash-code] :as this
  Object
  (equals [y] (or (identical? this y) (and (= state (:state y)) (= remaining-actions (:remaining-actions y)))))
  (hashCode [] hash-code))

(defn make-sanode-entry [state sanode reward-to-state remaining-actions]
  (SANodeEntry state sanode reward-to-state remaining-actions
               (unchecked-add (int (hash state)) (unchecked-multiply (int 13) (int (hash remaining-actions))))))

(defn make-queue [initial-elements]
  (let [q (queues/make-graph-search-pq)]

    (do (assert (pred (get m k) v)) m)
    (assoc m k v)))


(defn extract-effect [state context opt]
  (vary-meta (env/extract-effects state context) assoc :opt opt))

(defn stitch-effect-map [effect-map state reward-to-state]
  (util/map-map1 
   (fn [[effects local-reward]]
     [(vary-meta (env/apply-effects state effects) assoc 
                 :opt (concat (:opt (meta state)) (:opt (meta effects))))
      (+ reward-to-state local-reward)]) 
   effect-map))



(declare get-sa-node)
(defn get-sanode-entry [cache state reward-to-state actions]
  (make-sanode-entry state 
   (when (seq actions) (get-sa-node cache state (first actions)))
   reward-to-state actions))

(defn get-sa-node [#^HashMap cache s a]
  "Create a new sa-node, or returned the cached copy if it exists."
  (let [context (env/precondition-context a s)]
    (util/cache-with cache [(env/action-name a) (env/extract-context s context)]
      (let [s     (env/get-logger s)
            prim? (env/primitive? a)
            [ss r] (when-let [x (and prim? (env/applicable? a s) (env/successor a s))] x)] ;pun        
        (SANode context a 
          (atom (if ss {(extract-effect ss context [a]) r} {})) 
          (make-queue (for [ref (when-not prim? (hierarchy/immediate-refinements a s))]
                        [(get-sanode-entry cache s 0.0 ref) 0.0])))))))


;; May return states better than next-best, but these will be held at the parent.
(defn expand-sa-node [node #^HashMap cache next-best state reward-to-state last-cutoff]
