From 89f15618810fa044dde0cc1f481ac35da78173ff Mon Sep 17 00:00:00 2001 From: Octavian Geagla Date: Sat, 17 Feb 2024 06:38:25 -0700 Subject: [PATCH] More schema / code style (#11) * 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 --- README.md | 2 +- project.clj | 2 +- .../test_coverage_2024-02-16_16-39.png | Bin 0 -> 76745 bytes src/closyr/ga.clj | 2 +- src/closyr/ops/common.clj | 12 +- src/closyr/ops/eval.clj | 12 +- src/closyr/symbolic_regression.clj | 21 ++- src/closyr/util/spec.clj | 120 ++++++++++++++++-- test/closyr/ops_eval_test.clj | 21 +++ test/closyr/symbolic_regression_test.clj | 86 +++++++------ test/closyr/util_spec_test.clj | 56 +++++++- 11 files changed, 259 insertions(+), 75 deletions(-) create mode 100644 screenshots/test_coverage_2024-02-16_16-39.png diff --git a/README.md b/README.md index 47d3b4a..0565929 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/project.clj b/project.clj index 4aac8c2..f5f934e 100644 --- a/project.clj +++ b/project.clj @@ -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"] diff --git a/screenshots/test_coverage_2024-02-16_16-39.png b/screenshots/test_coverage_2024-02-16_16-39.png new file mode 100644 index 0000000000000000000000000000000000000000..bcd17360ebe50f7dfa77ad39ee746d5a26678476 GIT binary patch literal 76745 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 G2K_&UXrW#J literal 0 HcmV?d00001 diff --git a/src/closyr/ga.clj b/src/closyr/ga.clj index d06cf42..da6504c 100644 --- a/src/closyr/ga.clj +++ b/src/closyr/ga.clj @@ -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))] diff --git a/src/closyr/ops/common.clj b/src/closyr/ops/common.clj index ed9c29b..fec2060 100644 --- a/src/closyr/ops/common.clj +++ b/src/closyr/ops/common.clj @@ -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] @@ -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 diff --git a/src/closyr/ops/eval.clj b/src/closyr/ops/eval.clj index f7659dd..8345f09 100644 --- a/src/closyr/ops/eval.clj +++ b/src/closyr/ops/eval.clj @@ -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 diff --git a/src/closyr/symbolic_regression.clj b/src/closyr/symbolic_regression.clj index 120d163..5fae956 100644 --- a/src/closyr/symbolic_regression.clj +++ b/src/closyr/symbolic_regression.clj @@ -299,7 +299,9 @@ :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 @@ -307,13 +309,8 @@ 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)] @@ -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) diff --git a/src/closyr/util/spec.clj b/src/closyr/util/spec.clj index 389bcfb..386f964 100644 --- a/src/closyr/util/spec.clj +++ b/src/closyr/util/spec.clj @@ -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* @@ -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]]) @@ -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?] @@ -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?]]]) @@ -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?]]]) diff --git a/test/closyr/ops_eval_test.clj b/test/closyr/ops_eval_test.clj index 24dd5cd..9c1e2c4 100644 --- a/test/closyr/ops_eval_test.clj +++ b/test/closyr/ops_eval_test.clj @@ -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")))} @@ -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 diff --git a/test/closyr/symbolic_regression_test.clj b/test/closyr/symbolic_regression_test.clj index 8f45de2..35ec1a0 100644 --- a/test/closyr/symbolic_regression_test.clj +++ b/test/closyr/symbolic_regression_test.clj @@ -33,27 +33,32 @@ (let [args* (atom nil)] (binding [ops/*print-top-n* 1] (is (= - (with-redefs-fn {#'symreg/run-ga-iterations-using-record - (fn [run-config run-args] - (reset! args* - [(dissoc run-config :initial-muts :initial-phenos :input-xs-exprs :input-ys-exprs) - (dissoc run-args :extended-domain-args :initial-phenos :input-xs-list)]) - {:iters-done 123 - :final-population {} - :next-step :stop}) - #'symreg/config->log-steps (fn [_ _] 200)} - (fn [] - (symreg/run-app-from-cli-args - {:iterations 20 - :population 20 - :headless true - :xs [0 1 2] - :ys [1 4 19] - :use-flamechart true - :max-leafs 20}))) - {:iters-done 123 - :final-population {} - :next-step :stop})) + (dissoc + (with-redefs-fn {#'symreg/run-ga-iterations-using-record + (fn [run-config run-args] + (reset! args* + [(dissoc run-config :initial-muts :initial-phenos :input-xs-exprs :input-ys-exprs) + (dissoc run-args :extended-domain-args :initial-phenos :input-xs-list)]) + {:iters-done 123 + :final-population {:pop [] + :score-fn #() + :pop-scores [] + :mutation-fn #() + :crossover-fn #()} + :next-step :stop}) + #'symreg/config->log-steps (fn [_ _] 200)} + (fn [] + (symreg/run-app-from-cli-args + {:iterations 20 + :population 20 + :headless true + :xs [0 1 2] + :ys [1 4 19] + :use-flamechart true + :max-leafs 20}))) + :final-population) + {:iters-done 123 + :next-step :stop})) (is (= @args* [{:iters 20 @@ -73,23 +78,28 @@ (let [args* (atom nil)] (binding [ops/*print-top-n* 1] (is (= - (with-redefs-fn {#'symreg/run-ga-iterations-using-record - (fn [run-config run-args] - (reset! args* - [(dissoc run-config :initial-muts :initial-phenos :input-xs-exprs :input-ys-exprs) - (dissoc run-args :extended-domain-args :initial-phenos :input-xs-list)]) - {:iters-done 123 - :final-population {} - :next-step :stop}) - #'symreg/config->log-steps (fn [_ _] 200)} - (fn [] - (symreg/run-app-from-cli-args - {:population 30 - :iterations 20 - :headless true}))) - {:iters-done 123 - :final-population {} - :next-step :stop})) + (dissoc + (with-redefs-fn {#'symreg/run-ga-iterations-using-record + (fn [run-config run-args] + (reset! args* + [(dissoc run-config :initial-muts :initial-phenos :input-xs-exprs :input-ys-exprs) + (dissoc run-args :extended-domain-args :initial-phenos :input-xs-list)]) + {:iters-done 123 + :final-population {:pop [] + :score-fn #() + :pop-scores [] + :mutation-fn #() + :crossover-fn #()} + :next-step :stop}) + #'symreg/config->log-steps (fn [_ _] 200)} + (fn [] + (symreg/run-app-from-cli-args + {:population 30 + :iterations 20 + :headless true}))) + :final-population) + {:iters-done 123 + :next-step :stop})) (is (= @args* [{:iters 20 diff --git a/test/closyr/util_spec_test.clj b/test/closyr/util_spec_test.clj index c5db94f..a30437b 100644 --- a/test/closyr/util_spec_test.clj +++ b/test/closyr/util_spec_test.clj @@ -4,8 +4,60 @@ [clojure.test :refer :all] [closyr.util.spec :as specs] [malli.core :as m] + [malli.error :as me] + [malli.generator :as mg] [malli.instrument :as mi] - [malli.transform :as mt])) + [malli.transform :as mt]) + (:import + (org.matheclipse.core.eval + EvalEngine + ExprEvaluator) + (org.matheclipse.core.expression + F) + (org.matheclipse.core.interfaces + IExpr))) + + +(deftest generates-custom-types + (testing "valid Expr" + (is (instance? + IExpr + (mg/generate #'specs/SymbolicExpr))) + + (is (= + (m/explain #'specs/SymbolicExpr F/C1) + nil))) + + (testing "invalid Expr" + (is (= + (-> (m/explain #'specs/SymbolicExpr 123) :errors count) + 1)) + + (is (= + (me/humanize (m/explain #'specs/SymbolicExpr 0)) + ["should be an IExpr, got 0"]))) + + (testing "valid Evaluator" + (is (= + (class (mg/generate #'specs/SymbolicEvaluator)) + ExprEvaluator)) + + (is (= + (m/explain #'specs/SymbolicEvaluator (ExprEvaluator. + (doto (EvalEngine. true) + (.setQuietMode true)) + true + 0)) + nil))) + + (testing "invalid Evaluator" + (is (= + (-> (m/explain #'specs/SymbolicEvaluator 123) :errors count) + 1)) + + (is (= + (me/humanize (m/explain #'specs/SymbolicEvaluator 0)) + ["should be an ExprEvaluator, got 0"])))) (deftest defined-schemas @@ -66,7 +118,7 @@ (is (= (reduce + 0 (map (fn [[k v]] (count v)) ss)) ;; the number of total defns which have malli/schema metadata in entire src: - 14)))))) + 16)))))) #_(deftest decode-test