Search code examples
clojuregenetic-programming

How do I define a safe sqrt function in clojure?


I am using fungp (a genetic programming tool) to model a complex function and having trouble with sqrt.

Basically, I have to pass a vector of functions and their arity into fungp so that it can compose expressions from them. The expressions will then be evaluated and the best one will be returned. This vector of functions looks like:

(def functions
  '[[+ 2]
  [- 2]
  [* 2]
  [fungp.util/abs 1]
  [fungp.util/sdiv 2]
  [fungp.util/sin 1]
  [fungp.util/sqrt 1]
  [inc 1]
  [dec 1]])

That setup gives me a hundred lines of errors like:

#<ClassCastException java.lang.ClassCastException: java.lang.Double cannot be cast to clojure.lang.IFn>

Which I believe is due to the definition of fungp.util/sqrt:

(defn sqrt [x] (if (x > 0) (Math/sqrt x) 0))

I think the 0 is causing the failure to evaluate, but I'm not sure. I've tried defining my own version of the safe square root, but couldn't get the syntax correct.

So, this is where I'm stuck. I need a version of square root that is safe (returns 0 for negative inputs) and evaluates properly in the fungp expression.

EDIT: For completeness, this is one of the (many) variations I've tried for writing my own square root wrapper:

(defn sqrt-fn [x] `(if (~x > 0) (Math/sqrt ~x) 0))

And the output (the middle bit is the expression that was generated from the functions):

#<ClassCastException java.lang.ClassCastException: clojure.lang.Cons cannot be cast to java.lang.Number>

(let [] (- (dec (- (- (fungp.util/sin (tutorial.tut1/sqrt-fn 8.0)) (fungp.util/sdiv (* x 2.0) (dec 9.0))) (fungp.util/sdiv (tutorial.tut1/sqrt-fn (* x x)) (- (- x 4.0) (+ x x))))) (fungp.util/sdiv (tutorial.tut1/sqrt-fn (fungp.util/sin (
+ (dec x) (inc x)))) (fungp.util/sdiv (* (inc (inc 1.0)) (* (+ x 9.0) (fungp.util/sin 9.0))) (tutorial.tut1/sqrt-fn (- (tutorial.tut1/sqrt-fn x) (fungp.util/abs 3.0)))))))

NullPointerException   clojure.lang.Numbers.ops (Numbers.java:942)

I am not writing the expressions, so if there are extra parentheses or missing parentheses, they are coming from the way that I've defined sqrt.


Solution

  • There are a couple of things wrong with this:

    (defn sqrt-fn [x] `(if (~x > 0) (Math/sqrt ~x) 0))
    

    First, as hinted at in the comments, (x > 0) is trying to call x (presumably a number) as a function. > is the function, so it must come first, as in (> x 0).

    Also, you probably don't want they syntax quote here - that prevents evaluation of the contents, so your function is returning a quoted list of symbols.