Skip to content

Commit

Permalink
More schema / code style (#11)
Browse files Browse the repository at this point in the history
* more schema / code style

* test cases for eval

* test coverage update

* more schema

* more schema

* spec refac / fine-grained

* spec refac more breakout

* fix tests

* WIP expr schema

* bump deps

* schema for expr evaluator

* expr/eval schema tests
  • Loading branch information
ogeagla authored Feb 17, 2024
1 parent 96a3815 commit 89f1561
Show file tree
Hide file tree
Showing 11 changed files with 259 additions and 75 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ An example of using the GUI:

Coverage looks like this if you run `lein cloverage`:

![test_coverage_2024-02-16_11-15.png](screenshots%2Ftest_coverage_2024-02-16_11-15.png)
![test_coverage_2024-02-16_16-39.png](screenshots%2Ftest_coverage_2024-02-16_16-39.png)

## How It Works

Expand Down
2 changes: 1 addition & 1 deletion project.clj
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
[io.github.vincenzopalazzo/material-ui-swing "1.1.4"]
[io.github.material-ui-swing/DarkStackOverflowTheme "0.0.1-rc3"]

[ch.qos.logback/logback-classic "1.4.14"]
[ch.qos.logback/logback-classic "1.5.0"]
[org.slf4j/jcl-over-slf4j "2.0.12"]

[org.slf4j/slf4j-api "2.0.12"]
Expand Down
Binary file added screenshots/test_coverage_2024-02-16_16-39.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/closyr/ga.clj
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@
(partition-all 2 pop-chunk))))
(mapcat identity))

pop-scores (pmap first new-pop-data)
pop-scores (vec (pmap first new-pop-data))
new-pop (->> (pmap second new-pop-data)
(mapcat identity)
(vec))]
Expand Down
12 changes: 6 additions & 6 deletions src/closyr/ops/common.clj
Original file line number Diff line number Diff line change
Expand Up @@ -267,11 +267,11 @@
extra-pts (* x-range-pct-extend (count input-xs-vec))
x-range-extend-pt-sz (/ (* x-range-pct-extend x-range-sz) extra-pts)

x-head (reverse
(mapv
(fn [i]
(- x-min (* (inc i) x-range-extend-pt-sz)))
(range extra-pts)))
x-head (vec (reverse
(mapv
(fn [i]
(- x-min (* (inc i) x-range-extend-pt-sz)))
(range extra-pts))))

x-tail (mapv
(fn [i]
Expand All @@ -280,7 +280,7 @@

x-tail-list (exprs->exprs-list (doubles->exprs x-tail))
x-head-list (exprs->exprs-list (doubles->exprs x-head))
xs (concat x-head input-xs-vec x-tail)]
xs (vec (concat x-head input-xs-vec x-tail))]
{:xs xs
:x-head x-head
:x-head-list x-head-list
Expand Down
12 changes: 9 additions & 3 deletions src/closyr/ops/eval.clj
Original file line number Diff line number Diff line change
Expand Up @@ -62,22 +62,28 @@
(= "Indeterminate" (str eval-p)))))


(defn- ^IExpr get-arg
[^IExpr expr i ^IExpr default]
(.getArg expr i default))


(defn- result-args->doubles
[^IExpr eval-p i]
(try
(let [^IExpr res (.getArg eval-p (inc i) F/Infinity)]
(let [^IExpr res (get-arg eval-p (inc i) F/Infinity)]
(if (.isReal res)
(ops-common/expr->double res)
Double/POSITIVE_INFINITY))
(catch Exception e
(log/error "Error in evaling function on input values: " (str eval-p) " : " e)
(log/error "Error in evaling function on input values: "
(str eval-p) " : " (or (.getMessage e) e))
Double/POSITIVE_INFINITY)))


(defn- result-args->constant-input
[^IExpr eval-p ^IExpr new-expr i]
(try
(let [^IExpr arg0 (.getArg eval-p 0 F/Infinity)]
(let [^IExpr arg0 (get-arg eval-p 0 F/Infinity)]
(ops-common/expr->double
(if (.isReal new-expr)
new-expr
Expand Down
21 changes: 9 additions & 12 deletions src/closyr/symbolic_regression.clj
Original file line number Diff line number Diff line change
Expand Up @@ -299,21 +299,18 @@
:sim-stop-start-chan sim-stop-start-chan}))


(defn- update-plot-input-data
(defn update-plot-input-data
"Get new data from GUI and generate necessary solver inputs"
{:malli/schema [:=> [:cat #'specs/SolverGUIMessage] #'specs/SolverGUIInputArgs]}
[{new-state :new-state
input-data-x :input-data-x
input-data-y :input-data-y
input-iters :input-iters
input-phenos-count :input-phenos-count
max-leafs :max-leafs}]

(let [input-xs-exprs (if input-data-x
(ops-common/doubles->exprs input-data-x)
example-input-xs-exprs)
input-ys-exprs (if input-data-y
(ops-common/doubles->exprs input-data-y)
example-input-ys-exprs)

(let [input-xs-exprs (ops-common/doubles->exprs input-data-x)
input-ys-exprs (ops-common/doubles->exprs input-data-y)
input-ys-vec (ops-common/exprs->doubles input-ys-exprs)
input-xs-vec (ops-common/exprs->doubles input-xs-exprs)]

Expand All @@ -322,12 +319,12 @@
:input-ys-vec input-ys-vec
:input-iters input-iters
:input-phenos-count input-phenos-count
:max-leafs max-leafs})

@sim-input-args*))
:max-leafs max-leafs})))


(defn- restart-with-new-inputs
(defn restart-with-new-inputs
"Get new inputs and restart solver"
{:malli/schema [:=> [:cat #'specs/SolverGUIMessage] keyword?]}
[msg]
(log/info "~~~ Restarting experiment! ~~~")
(update-plot-input-data msg)
Expand Down
120 changes: 109 additions & 11 deletions src/closyr/util/spec.clj
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
(ns closyr.util.spec
(:require
[clojure.pprint :as pp]
[clojure.test.check.generators :as gen]
[closyr.util.log :as log]
[malli.core :as m]
[malli.error :as me]
[malli.instrument :as mi]))
[malli.generator :as mg]
[malli.instrument :as mi]
[malli.transform :as mt])
(:import
(org.matheclipse.core.eval
EvalEngine
ExprEvaluator)
(org.matheclipse.core.expression
F)
(org.matheclipse.core.interfaces
IExpr)))


(def ^:dynamic *check-schema*
Expand Down Expand Up @@ -42,14 +53,59 @@
'user]))]}))


(def ^:private SymbolicEvaluator
(m/-simple-schema
{:type :user/symbolic-evaluator
:pred #(instance? ExprEvaluator %)
:type-properties {:error/fn (fn [error _] (str "should be an ExprEvaluator, got " (:value error)))
:error/message "should be ExprEvaluator"
:gen/gen (gen/let [f1 (gen/large-integer* {:min 1 :max 100})]
(gen/return
(ExprEvaluator.
(doto (EvalEngine. true)
(.setQuietMode true))
true
0)))}}))


(def ^:private SymbolicExpr
(m/-simple-schema
{:type :user/symbolic-expr
:pred #(instance? IExpr %)
:type-properties {:error/fn (fn [error _] (str "should be an IExpr, got " (:value error)))
:error/message "should be IExpr"
:gen/gen (gen/let [f1 (gen/large-integer* {:min -1000 :max 1000})
f2 (gen/double* {:min -1000.0 :max 1000.0})]
(let [x (F/Dummy "x")]
(gen/elements
(mapv
(fn [^IExpr expr]
(F/Times (F/num (float f2))
(F/Plus expr (F/num (float f1)))))
[x
(F/Sin x)
(F/Cos x)
(F/Exp x)
(F/Log x)
(F/Sqrt x)
(F/Times x F/C2)
(F/Plus x F/C5)
(F/Times x x)
(F/Times x (F/Times x x))]))))}}))


(def ^:private NumberVector
[:vector number?])


(def ^:private GAPhenotype
[:map
{:closed true}
[:id {:optional true} :uuid]
[:sym some?]
[:expr {:optional true} some?]
[:expr {:optional true} #'SymbolicExpr]
[:score {:optional true} number?]
[:util {:optional true} any?]
[:util {:optional true} [:maybe #'SymbolicEvaluator]]
[:last-op {:optional true} :string]
[:mods-applied {:optional true} :int]])

Expand All @@ -61,7 +117,7 @@
(def ^:private GAMutation
[:map
{:closed true}
[:op :keyword]
[:op [:enum :modify-substitute :modify-fn :modify-leafs :modify-branches :modify-ast-head]]
[:label {:optional true} :string]
[:leaf-modifier-fn {:optional true} fn?]
[:modifier-fn {:optional true} fn?]
Expand All @@ -84,18 +140,28 @@
[:input-ys-exprs [:sequential some?]]])


(def ^:private ExtendedDomainArgs
[:map
{:closed true}
[:xs #'NumberVector]
[:x-head #'NumberVector]
[:x-head-list some?]
[:x-tail #'NumberVector]
[:x-tail-list some?]])


(def ^:private SolverRunArgs
[:map
{:closed true}
[:sim->gui-chan {:optional true} some?]
[:sim-stop-start-chan {:optional true} some?]
[:extended-domain-args map?]
[:extended-domain-args #'ExtendedDomainArgs]
[:input-xs-list some?]
[:input-xs-count pos-int?]
[:input-xs-vec [:vector number?]]
[:input-ys-vec [:vector number?]]
[:input-xs-vec #'NumberVector]
[:input-ys-vec #'NumberVector]
[:input-iters pos-int?]
[:initial-phenos [:maybe [:sequential map?]]]
[:initial-phenos [:maybe #'GAPopulationPhenotypes]]
[:input-phenos-count [:maybe pos-int?]]
[:max-leafs [:maybe pos-int?]]])

Expand All @@ -110,14 +176,46 @@
(def ^:private ScoreFnArgs
[:map
{:closed false}
[:input-ys-vec [:vector number?]]
[:input-ys-vec #'NumberVector]
[:input-xs-list some?]
[:input-xs-count pos-int?]])


(def ^:private GAPopulation
[:map
{:closed true}
[:pop #'GAPopulationPhenotypes]
[:score-fn fn?]
[:pop-scores #'NumberVector]
[:mutation-fn fn?]
[:crossover-fn fn?]])


(def ^:private SolverRunResults
[:map
{:closed true}
[:iters-done number?]
[:final-population map?]
[:next-step :keyword]])
[:final-population #'GAPopulation]
[:next-step [:enum :wait :stop :restart]]])


(def ^:private SolverGUIInputArgs
[:map
{:closed true}
[:input-xs-exprs some?]
[:input-xs-vec #'NumberVector]
[:input-ys-vec #'NumberVector]
[:input-iters pos-int?]
[:input-phenos-count pos-int?]
[:max-leafs [:maybe pos-int?]]])


(def ^:private SolverGUIMessage
[:map
{:closed true}
[:new-state [:enum :start :pause :stop :restart]]
[:input-data-x #'NumberVector]
[:input-data-y #'NumberVector]
[:input-iters pos-int?]
[:input-phenos-count pos-int?]
[:max-leafs {:optional true} [:maybe pos-int?]]])
21 changes: 21 additions & 0 deletions test/closyr/ops_eval_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,17 @@
:input-xs-count 1})))
nil)))


(testing "with failing get-arg handles error"
(is (=
(with-redefs-fn {#'ops-eval/get-arg (fn [_ _ _] (throw (Exception. "Test exception")))}
(fn []
(ops-eval/eval-vec-pheno
(ops-common/->phenotype x (F/Subtract x F/C1D2) nil)
{:input-xs-list (ops-common/exprs->exprs-list (ops-common/doubles->exprs [0.5]))
:input-xs-count 1})))
[##Inf])))

(testing "with failing conversion throws exception"
(is (thrown? Exception
(with-redefs-fn {#'ops-common/expr->double (fn [_] (throw (Exception. "Test exception")))}
Expand All @@ -129,6 +140,16 @@
{:input-xs-list (ops-common/exprs->exprs-list (ops-common/doubles->exprs [0.5 1.0]))
:input-xs-count 1}))))))

(testing "with failing conversion handles error"
(is (=
(with-redefs-fn {#'ops-eval/get-arg (fn [_ _ _] (F/num 0.1))}
(fn []
(ops-eval/eval-vec-pheno
(ops-common/->phenotype x (F/Subtract x F/C1D2) nil)
{:input-xs-list (ops-common/exprs->exprs-list (ops-common/doubles->exprs [0.5 1.0]))
:input-xs-count 1})))
[0.1])))

(testing "can eval various fns for simple inputs 2"
(is (= (mapv
ops-common/expr->double
Expand Down
Loading

0 comments on commit 89f1561

Please sign in to comment.