(defn- process-sqrt
"Given an unwrapped symbolic expression of the form `(sqrt x)`, returns a new,
unsimplified symbolic expression with any even power removed from underneath
the square root.
For example:
```clojure
(process-sqrt
'(sqrt (* x (expt y 2) (expt z 4))))
;;=> (* (sqrt x) y (expt z 2))
```"
[expr]
(let [fact-exp (factor (first (sym/operands expr)))
expt (sym/symbolic-operator 'expt)
* (sym/symbolic-operator '*)
sqrt (sym/symbolic-operator 'sqrt)
even? (fn [n]
(and (v/native-integral? n)
(even? n)))]
(loop [factors (if (sym/product? fact-exp)
(sym/operands fact-exp)
[fact-exp])
odds 1
evens 1]
(if (empty? factors)
(do (when-not (= evens 1)
(ul/assume! `(~'non-negative? ~evens)
'root-out-squares))
(* (sqrt odds) evens))
(let [[f & more] factors]
(if (sym/expt? f)
(let [[b e] (sym/operands f)]
(if-not (even? e)
(recur more
(* f odds)
evens)
(recur more
odds
(let [power (quot e 2)]
(cond (> power 1) (* evens (expt b power))
(= power 1) (* evens b)
:else evens)))))
(recur more
(* f odds)
evens)))))))