diff --git a/README.md b/README.md index 0119e2c..47d3b4a 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-15_10-13.png](screenshots%2Ftest_coverage_2024-02-15_10-13.png) +![test_coverage_2024-02-16_11-15.png](screenshots%2Ftest_coverage_2024-02-16_11-15.png) ## How It Works diff --git a/nomis-ns-graph.png b/nomis-ns-graph.png index a362612..90347ce 100644 Binary files a/nomis-ns-graph.png and b/nomis-ns-graph.png differ diff --git a/project.clj b/project.clj index 1abcde1..4aac8c2 100644 --- a/project.clj +++ b/project.clj @@ -5,6 +5,7 @@ :url "https://www.eclipse.org/legal/epl-2.0/"} :dependencies [[org.clojure/clojure "1.11.1"] [org.clojure/core.async "1.6.681"] + [metosin/malli "0.14.0"] [org.clojure/tools.cli "1.0.219"] diff --git a/screenshots/test_coverage_2024-02-16_11-15.png b/screenshots/test_coverage_2024-02-16_11-15.png new file mode 100644 index 0000000..82d12f7 Binary files /dev/null and b/screenshots/test_coverage_2024-02-16_11-15.png differ diff --git a/src/closyr/core.clj b/src/closyr/core.clj index a948f15..edea976 100644 --- a/src/closyr/core.clj +++ b/src/closyr/core.clj @@ -3,8 +3,8 @@ (:require [clojure.string :as str] [clojure.tools.cli :as cli] - [closyr.dataset.csv :as input-csv] - [closyr.log :as log] + [closyr.util.csv :as input-csv] + [closyr.util.log :as log] [closyr.symbolic-regression :as symreg]) (:import (java.io diff --git a/src/closyr/ga.clj b/src/closyr/ga.clj index 412cb01..d06cf42 100644 --- a/src/closyr/ga.clj +++ b/src/closyr/ga.clj @@ -1,8 +1,8 @@ (ns closyr.ga (:refer-clojure :exclude [rand rand-int rand-nth shuffle]) (:require - [closyr.log :as log] - [closyr.dataset.prng :refer :all])) + [closyr.util.log :as log] + [closyr.util.prng :refer :all])) (set! *warn-on-reflection* true) diff --git a/src/closyr/ops.clj b/src/closyr/ops.clj index bd887c4..db1ee74 100644 --- a/src/closyr/ops.clj +++ b/src/closyr/ops.clj @@ -3,11 +3,12 @@ (:require [clojure.core.async :as async :refer [go go-loop timeout !! ! chan put! take! alts!! alts! close!]] [clojure.string :as str] - [closyr.dataset.prng :refer :all] - [closyr.log :as log] + [closyr.util.prng :refer :all] + [closyr.util.log :as log] [closyr.ops.common :as ops-common] [closyr.ops.eval :as ops-eval] - [closyr.ops.modify :as ops-modify]) + [closyr.ops.modify :as ops-modify] + [closyr.util.spec :as specs]) (:import (java.text DecimalFormat) @@ -74,7 +75,9 @@ (and (number? n) (Double/isNaN n)))) -(defn- compute-residual +(defn compute-residual + "Compute the residual (difference) between 2 number (y-values)" + {:malli/schema [:=> [:cat number? number?] number?]} [expected actual] (let [res (if (not-finite? actual) max-resid @@ -281,6 +284,7 @@ (reset! test-timer* (Date.)) (log/info i "-step pop size: " pop-size + " points: " (count input-ys-vec) " max leafs: " max-leafs " took secs: " took-s " phenos/s: " (Math/round ^double (/ (* pop-size *log-steps*) took-s)) @@ -303,3 +307,6 @@ :best-p95-score (:score best-p95-v) :best-p90-score (:score best-p90-v)})))) (reset! sim-stats* {})) + + +(specs/instrument-all!) diff --git a/src/closyr/ops/common.clj b/src/closyr/ops/common.clj index 0c7c5d0..027cc8e 100644 --- a/src/closyr/ops/common.clj +++ b/src/closyr/ops/common.clj @@ -2,8 +2,9 @@ (:refer-clojure :exclude [rand rand-int rand-nth shuffle]) (:require [clojure.core.async :as async :refer [go go-loop timeout !! ! chan put! take! alts!! alt!! close!]] - [closyr.dataset.prng :refer :all] - [closyr.log :as log]) + [closyr.util.prng :refer :all] + [closyr.util.log :as log] + [closyr.util.spec :as specs]) (:import (java.util Date @@ -257,6 +258,7 @@ (defn extend-xs "Add extra xs on either side of the provided range" + {:malli/schema [:=> [:cat [:sequential number?]] map?]} [input-xs-vec] (let [x-min (first input-xs-vec) x-max (last input-xs-vec) @@ -284,3 +286,6 @@ :x-head-list x-head-list :x-tail x-tail :x-tail-list x-tail-list})) + + +(specs/instrument-all!) diff --git a/src/closyr/ops/eval.clj b/src/closyr/ops/eval.clj index 2584d5f..ffe1bc7 100644 --- a/src/closyr/ops/eval.clj +++ b/src/closyr/ops/eval.clj @@ -1,7 +1,8 @@ (ns closyr.ops.eval (:require - [closyr.log :as log] - [closyr.ops.common :as ops-common]) + [closyr.util.log :as log] + [closyr.ops.common :as ops-common] + [closyr.util.spec :as specs]) (:import (org.matheclipse.core.eval EvalControlledCallable @@ -38,6 +39,7 @@ (defn ^IExpr eval-phenotype-on-expr-args "Eval an expr at every point in the args" + {:malli/schema [:=> [:cat #'specs/GAPhenotype some?] any?]} [{^IAST expr :expr ^ISymbol x-sym :sym ^ExprEvaluator util :util p-id :id :as pheno} ^"[Lorg.matheclipse.core.interfaces.IExpr;" expr-args] (try @@ -90,8 +92,9 @@ (defn eval-vec-pheno "Evaluate a phenotype's expr on input xs/ys vecs" + {:malli/schema [:=> [:cat #'specs/GAPhenotype #'specs/SolverEvalArgs] [:or [:vector number?] nil?]]} [p - {:keys [input-xs-list input-xs-count input-ys-vec] + {:keys [input-xs-list input-xs-count] :as run-args}] (let [^IExpr new-expr (:expr p) ^IExpr eval-p (eval-phenotype-on-expr-args p input-xs-list)] @@ -164,3 +167,6 @@ {:xs xs :ys evaluated-ys})) + + +(specs/instrument-all!) diff --git a/src/closyr/ops/initialize.clj b/src/closyr/ops/initialize.clj index 69f731f..76f5824 100644 --- a/src/closyr/ops/initialize.clj +++ b/src/closyr/ops/initialize.clj @@ -1,7 +1,8 @@ (ns closyr.ops.initialize (:require - [closyr.log :as log] - [closyr.ops.common :as ops-common]) + [closyr.util.log :as log] + [closyr.ops.common :as ops-common] + [closyr.util.spec :as specs]) (:import (org.matheclipse.core.expression AST @@ -21,6 +22,7 @@ (defn initial-phenotypes "Initial exprs scaled up in quantity to use in GA evolution" + {:malli/schema [:=> [:cat pos-int?] #'specs/GAPopulationPhenotypes]} [p-count] (let [^ISymbol x ops-common/sym-x] (->> @@ -31,6 +33,7 @@ (defn initial-mutations "All mutations to use in GA evolutions" + {:malli/schema [:=> [:cat] [:vector #'specs/GAMutation]]} [] [{:op :modify-fn :label "Derivative" @@ -61,8 +64,8 @@ :modifier-fn (fn ^IExpr [{^IAST expr :expr ^ISymbol x-sym :sym :as pheno}] (F/Plus expr (F/Divide 1 F/C100)))} - {:op :modify-fn - :label "-1/100" + {:op :modify-fn + :label "-1/100" :modifier-fn (fn ^IExpr [{^IAST expr :expr ^ISymbol x-sym :sym :as pheno}] (F/Subtract expr (F/Divide 1 F/C100)))} @@ -659,3 +662,6 @@ (if (ops-common/should-modify-branch leaf-count pheno) (F/Subtract ie (F/num 0.1)) ie))}]) + + +(specs/instrument-all!) diff --git a/src/closyr/ops/modify.clj b/src/closyr/ops/modify.clj index 8e17acc..72bb871 100644 --- a/src/closyr/ops/modify.clj +++ b/src/closyr/ops/modify.clj @@ -3,9 +3,10 @@ (:require [clojure.core.async :as async :refer [go go-loop timeout !! ! chan put! take! alts!! alt!! close!]] [clojure.string :as str] - [closyr.dataset.prng :refer :all] - [closyr.log :as log] - [closyr.ops.common :as ops-common]) + [closyr.ops.common :as ops-common] + [closyr.util.log :as log] + [closyr.util.prng :refer :all] + [closyr.util.spec :as specs]) (:import (java.util.function Function) @@ -139,6 +140,17 @@ (defn crossover "Do phenotype crossover on their expr AST" + {:malli/schema + [:=> + + ;; inputs: + [:cat + pos-int? + #'specs/GAPhenotype + #'specs/GAPhenotype] + + ;; outputs: + #'specs/GAPhenotype]} [max-leafs {^IAST e1 :expr ^ISymbol x-sym :sym ^ExprEvaluator util :util :as p} {^IAST e2 :expr :as p-discard}] @@ -184,6 +196,23 @@ (defn apply-modifications "Apply a sequence of modifications" + {:malli/schema + [:=> + + ;; inputs: + [:cat + pos-int? + pos-int? + [:sequential #'specs/GAMutation] + #'specs/GAPhenotype + #'specs/GAPhenotype] + + ;; outputs: + [:map {:closed true} + [:new-pheno #'specs/GAPhenotype] + [:iters int?] + [:mods [:sequential #'specs/GAMutation]]]]} + [max-leafs mods-count initial-muts p-winner p-discard] (loop [iters 0 mods-left-to-apply mods-count @@ -237,26 +266,29 @@ (concat (repeat 40 1)) (concat (repeat 30 2)) (concat (repeat 20 3)) - (concat (repeat 18 4)) - (concat (repeat 16 5)) - (concat (repeat 15 6)) - (concat (repeat 14 7)) - (concat (repeat 13 8)) - (concat (repeat 12 9)) - (concat (repeat 11 10)) - (concat (repeat 10 11)) - (concat (repeat 9 12)) - (concat (repeat 8 13)) - (concat (repeat 7 14)) - (concat (repeat 6 15)) - (concat (repeat 5 16)) - (concat (repeat 4 17)) - (concat (repeat 3 18)) - (concat (repeat 2 19)) - (concat (repeat 1 20)) + (concat (repeat 15 4)) + (concat (repeat 12 5)) + (concat (repeat 10 6)) + (concat (repeat 9 7)) + (concat (repeat 8 8)) + (concat (repeat 7 9)) + (concat (repeat 6 10)) + (concat (repeat 5 11)) + (concat (repeat 4 12)) + (concat (repeat 3 13)) + (concat (repeat 2 14)) + (concat (repeat 1 15)) + ;; (concat (repeat 5 16)) + ;; (concat (repeat 4 17)) + ;; (concat (repeat 3 18)) + ;; (concat (repeat 2 19)) + ;; (concat (repeat 1 20)) ;; (concat (repeat 3 21)) ;; (concat (repeat 2 22)) ;; (concat (repeat 1 23)) ;; (concat (repeat 1 24)) ;; (concat (repeat 1 25)) vec)) + + +(specs/instrument-all!) diff --git a/src/closyr/symbolic_regression.clj b/src/closyr/symbolic_regression.clj index 54f7c41..abad4e5 100644 --- a/src/closyr/symbolic_regression.clj +++ b/src/closyr/symbolic_regression.clj @@ -2,12 +2,14 @@ (:require [clojure.core.async :as async :refer [go go-loop timeout !! ! chan put! take! alts!! alts! close!]] [closyr.ga :as ga] - [closyr.log :as log] + [closyr.util.log :as log] [closyr.ops :as ops] [closyr.ops.common :as ops-common] [closyr.ops.initialize :as ops-init] + [closyr.util.spec :as specs] [closyr.ui.gui :as gui] [flames.core :as flames] + [malli.core :as m] [seesaw.core :as ss]) (:import (java.util @@ -466,6 +468,8 @@ (init [this] + (specs/validate! "SolverRunConfig" specs/SolverRunConfig run-config) + (specs/validate! "SolverRunArgs" specs/SolverRunArgs run-args) (let [{:keys [iters initial-phenos initial-muts use-gui?]} run-config start (print-and-save-start-time iters initial-phenos) init-pop (ga/initialize @@ -476,7 +480,8 @@ (log/info "Running with logging every n steps: " (:log-steps run-config)) - (assoc this :ga-result init-pop + (assoc this + :ga-result init-pop :iters-to-go iters :start-ms start))) @@ -488,10 +493,13 @@ iters-to-go (:iters-to-go this)] (binding [ops/*log-steps* log-steps] (if (zero? iters-to-go) - (assoc this :status :done :result {:iters-done (- iters iters-to-go) - :final-population population - :next-step :wait}) + (assoc this + :status :done + :result {:iters-done (- iters iters-to-go) + :final-population population + :next-step :wait}) (let [{scores :pop-scores :as ga-result} (ga/evolve population)] + (specs/validate! "GAPopulation" specs/GAPopulationPhenotypes (:pop ga-result)) (ops/report-iteration iters-to-go iters ga-result run-args run-config) (assoc this :ga-result ga-result :iters-to-go (next-iters iters-to-go scores))))))) @@ -534,11 +542,10 @@ return-value)) -(defn- run-ga-iterations-using-record +(defn run-ga-iterations-using-record "Run GA evolution iterations on initial population" - [{:keys [iters initial-phenos initial-muts use-gui?] :as run-config} - run-args] - + {:malli/schema [:=> [:cat #'specs/SolverRunConfig #'specs/SolverRunArgs] #'specs/SolverRunResults]} + [run-config run-args] (loop [solver-state (init (map->SolverStateController {:run-config run-config :run-args run-args}))] (let [[recur? next-solver-state] (run-iteration solver-state)] (if recur? @@ -700,8 +707,22 @@ (System/exit 0))) +(def ^:private CLIArgs + [:map + {:closed true} + [:log-level {:optional true} keyword?] + [:iterations any?] + [:population any?] + [:headless any?] + [:xs {:optional true} any?] + [:ys {:optional true} any?] + [:use-flamechart {:optional true} any?] + [:max-leafs {:optional true} any?]]) + + (defn run-app-from-cli-args "Run app from CLI args" + {:malli/schema [:=> [:cat #'CLIArgs] #'specs/SolverRunResults]} [{:keys [iterations population headless xs ys use-flamechart max-leafs] :as cli-opts}] (log/info "CLI: run from options: " cli-opts) (let [run-config {:initial-phenos (ops-init/initial-phenotypes population) @@ -722,6 +743,11 @@ result)) +;; todo: feel kind of hacky to have to call this in ?every? ns that has defn schema +(specs/instrument-all!) + + +(comment (println "FN SCHEMAS: " (m/function-schemas))) (comment (macroexpand-1 `(log/info "Hello"))) (comment (log/info "Hello")) (comment (run-app-without-gui)) diff --git a/src/closyr/ui/gui.clj b/src/closyr/ui/gui.clj index c9f240a..1a44ab7 100644 --- a/src/closyr/ui/gui.clj +++ b/src/closyr/ui/gui.clj @@ -2,9 +2,9 @@ (:require [clojure.core.async :as async :refer [go go-loop timeout !! ! chan put! alts!]] [clojure.java.io :as io] - [closyr.dataset.csv :as input-csv] + [closyr.util.csv :as input-csv] [closyr.dataset.inputs :as input-data] - [closyr.log :as log] + [closyr.util.log :as log] [closyr.ui.plot :as plot] [seesaw.behave :as sb] [seesaw.border :as sbr] @@ -455,7 +455,7 @@ (defn- settings-max-leafs-on-change [^MouseEvent e] (let [b (.getText ^JRadioButtonMenuItem (.getSource e))] - (swap! experiment-settings* assoc :max-leafs (Double/parseDouble b)) + (swap! experiment-settings* assoc :max-leafs (Integer/parseInt b)) (log/info "max leafs changed to " b))) diff --git a/src/closyr/dataset/csv.clj b/src/closyr/util/csv.clj similarity index 96% rename from src/closyr/dataset/csv.clj rename to src/closyr/util/csv.clj index 714fa67..445071d 100644 --- a/src/closyr/dataset/csv.clj +++ b/src/closyr/util/csv.clj @@ -1,8 +1,8 @@ -(ns closyr.dataset.csv +(ns closyr.util.csv (:require [clojure.data.csv :as csv] [clojure.java.io :as io] - [closyr.log :as log])) + [closyr.util.log :as log])) (set! *warn-on-reflection* true) diff --git a/src/closyr/log.clj b/src/closyr/util/log.clj similarity index 99% rename from src/closyr/log.clj rename to src/closyr/util/log.clj index 611e92a..5c3bc92 100644 --- a/src/closyr/log.clj +++ b/src/closyr/util/log.clj @@ -1,4 +1,4 @@ -(ns closyr.log +(ns closyr.util.log (:require [clojure.pprint :as pprint] [clojure.string :as str]) diff --git a/src/closyr/dataset/prng.clj b/src/closyr/util/prng.clj similarity index 98% rename from src/closyr/dataset/prng.clj rename to src/closyr/util/prng.clj index 402e74f..247c854 100644 --- a/src/closyr/dataset/prng.clj +++ b/src/closyr/util/prng.clj @@ -1,4 +1,4 @@ -(ns closyr.dataset.prng +(ns closyr.util.prng (:refer-clojure :exclude [rand rand-int rand-nth shuffle]) (:import (clojure.lang diff --git a/src/closyr/util/spec.clj b/src/closyr/util/spec.clj new file mode 100644 index 0000000..57324de --- /dev/null +++ b/src/closyr/util/spec.clj @@ -0,0 +1,115 @@ +(ns closyr.util.spec + (:require + [clojure.pprint :as pp] + [closyr.util.log :as log] + [malli.core :as m] + [malli.error :as me] + [malli.instrument :as mi])) + + +(def ^:dynamic *check-schema* + "Toggle checking schema and potentially throwing exceptions" + true) + + +(defn validate! + "Check that an object o is compliant with schema s with name n, or throw exception" + [n s o] + (when (and *check-schema* (not (m/validate s o))) + (let [explained (me/humanize (m/explain s o))] + (log/error "Error in input schema: " n) + (pp/pprint [n explained]) + (throw (Exception. (str "Error, input failed schema: " [n explained]))))) + true) + + +(defn instrument-all! + "Instrument all defn schema" + [] + (when *check-schema* + (mi/collect!) + (mi/instrument!))) + + +#_(defn- disable-validate-instrumentation! + "Turn off all schema checks" + [] + (alter-var-root #'*check-schema* (constantly false)) + (mi/unstrument! + {:filters [(apply mi/-filter-ns (concat (keys (m/function-schemas)) + ['closyr.util.spec-test + 'cursive.tests.runner + 'user]))]})) + + +(def GAPhenotype + [:map + {:closed true} + [:id {:optional true} :uuid] + [:sym some?] + [:expr {:optional true} any?] + [:score {:optional true} number?] + [:util {:optional true} any?] + [:last-op {:optional true} :string] + [:mods-applied {:optional true} :int]]) + + +(def GAPopulationPhenotypes + [:vector #'GAPhenotype]) + + +(def GAMutation + [:map + {:closed true} + [:op :keyword] + [:label {:optional true} :string] + [:leaf-modifier-fn {:optional true} fn?] + [:modifier-fn {:optional true} fn?] + [:find-expr {:optional true} some?] + [:replace-expr {:optional true} some?]]) + + +(def SolverRunConfig + [:map + {:closed true} + [:iters pos-int?] + [:initial-phenos #'GAPopulationPhenotypes] + [:initial-muts [:sequential #'GAMutation]] + [:use-gui? :boolean] + [:max-leafs pos-int?] + [:input-phenos-count {:optional true} pos-int?] + [:log-steps pos-int?] + [:use-flamechart [:maybe :boolean]] + [:input-xs-exprs [:sequential some?]] + [:input-ys-exprs [:sequential some?]]]) + + +(def SolverRunArgs + [:map + {:closed true} + [:sim->gui-chan {:optional true} some?] + [:sim-stop-start-chan {:optional true} some?] + [:extended-domain-args map?] + [:input-xs-list some?] + [:input-xs-count pos-int?] + [:input-xs-vec [:vector double?]] + [:input-ys-vec [:vector double?]] + [:input-iters pos-int?] + [:initial-phenos [:maybe [:sequential map?]]] + [:input-phenos-count [:maybe pos-int?]] + [:max-leafs [:maybe pos-int?]]]) + + +(def SolverEvalArgs + [:map + {:closed false} + [:input-xs-list some?] + [:input-xs-count pos-int?]]) + + +(def SolverRunResults + [:map + {:closed true} + [:iters-done number?] + [:final-population map?] + [:next-step :keyword]]) diff --git a/test/closyr/ops_common_test.clj b/test/closyr/ops_common_test.clj index 4a5ce37..fae2364 100644 --- a/test/closyr/ops_common_test.clj +++ b/test/closyr/ops_common_test.clj @@ -98,6 +98,19 @@ {"1/5+Sin(ArcSin(x))" 1})))))))) +(deftest simplify-with-ignore-presets + (testing "simplify ignore" + (reset! ops-common/do-not-simplify-fns* {"x" 1}) + (let [x (F/Dummy "x")] + (is (= (update (ops-common/maybe-simplify {:expr x}) + :expr str) + {:expr "x" + :simple? true})) + (is (= @ops-common/do-not-simplify-fns* + {"x" 2}))) + (reset! ops-common/do-not-simplify-fns* {}))) + + (deftest simplify-test (testing "simplify trig compose" (let [x (F/Dummy "x")] @@ -113,7 +126,7 @@ (fn [] (let [x (F/Dummy "x")] (is (= (dissoc (update (ops-common/maybe-simplify {:expr (F/Log (F/ArcSin x)) :util (ops-common/new-util)}) - :expr str) + :expr str) :util) {:expr "Log(ArcSin(x))" :simple? true})))))) @@ -132,17 +145,6 @@ :expr str)) {:expr "1+Sqrt(x)+Cos(x)+Sin(x)+2*(Cos(ArcSin(x))+Tan(ArcSin(x)))"})))) - (testing "simplify ignore" - (reset! ops-common/do-not-simplify-fns* {"x" 1}) - (let [x (F/Dummy "x")] - (is (= (update (ops-common/maybe-simplify {:expr x}) - :expr str) - {:expr "x" - :simple? true})) - (is (= @ops-common/do-not-simplify-fns* - {"x" 2}))) - (reset! ops-common/do-not-simplify-fns* {})) - (testing "simplify sum" (let [x (F/Dummy "x")] (is (= (binding [ops-common/*simplify-max-leafs* 100] diff --git a/test/closyr/ops_modify_test.clj b/test/closyr/ops_modify_test.clj index f48108f..4431b86 100644 --- a/test/closyr/ops_modify_test.clj +++ b/test/closyr/ops_modify_test.clj @@ -2,7 +2,7 @@ (:require [clojure.core.async :as async :refer [go go-loop timeout !! ! chan put! take! alts!! alt!! close!]] [clojure.test :refer :all] - [closyr.dataset.prng :as prng] + [closyr.util.prng :as prng] [closyr.ops.common :as ops-common] [closyr.ops.initialize :as ops-init] [closyr.ops.modify :as ops-modify]) diff --git a/test/closyr/ops_test.clj b/test/closyr/ops_test.clj index 8e926a8..5b4b278 100644 --- a/test/closyr/ops_test.clj +++ b/test/closyr/ops_test.clj @@ -1,7 +1,7 @@ (ns closyr.ops-test (:require [clojure.test :refer :all] - [closyr.dataset.prng :as prng] + [closyr.util.prng :as prng] [closyr.ops :as ops] [closyr.ops.common :as ops-common] [closyr.ops.eval :as ops-eval] diff --git a/test/closyr/symbolic_regression_test.clj b/test/closyr/symbolic_regression_test.clj index 02a1ecb..8814eb4 100644 --- a/test/closyr/symbolic_regression_test.clj +++ b/test/closyr/symbolic_regression_test.clj @@ -35,7 +35,9 @@ (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)]) - {:next-step :stop}) + {:iters-done 123 + :final-population {} + :next-step :stop}) #'symreg/config->log-steps (fn [_ _] 200)} (fn [] (symreg/run-app-from-cli-args @@ -46,7 +48,9 @@ :ys [1 4 19] :use-flamechart true :max-leafs 20}))) - {:next-step :stop})) + {:iters-done 123 + :final-population {} + :next-step :stop})) (is (= @args* [{:iters 20 @@ -71,14 +75,18 @@ (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)]) - {:next-step :stop}) + {: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}))) - {:next-step :stop})) + {:iters-done 123 + :final-population {} + :next-step :stop})) (is (= @args* [{:iters 20 diff --git a/test/closyr/dataset_prng_test.clj b/test/closyr/util_prng_test.clj similarity index 91% rename from test/closyr/dataset_prng_test.clj rename to test/closyr/util_prng_test.clj index f6a1bd2..05b767d 100644 --- a/test/closyr/dataset_prng_test.clj +++ b/test/closyr/util_prng_test.clj @@ -1,7 +1,7 @@ -(ns closyr.dataset-prng-test +(ns closyr.util-prng-test (:require [clojure.test :refer :all] - [closyr.dataset.prng :as prng])) + [closyr.util.prng :as prng])) (defn- test-rand-int-gen diff --git a/test/closyr/util_spec_test.clj b/test/closyr/util_spec_test.clj new file mode 100644 index 0000000..be18e74 --- /dev/null +++ b/test/closyr/util_spec_test.clj @@ -0,0 +1,89 @@ +(ns closyr.util-spec-test + (:require + [clojure.pprint :as pp] + [clojure.test :refer :all] + [closyr.util.spec :as specs] + [malli.core :as m] + [malli.instrument :as mi])) + + +(deftest defined-schemas + (testing "GAPhenotype failure case" + (is (thrown? Exception + (specs/validate! + "test-pheno" + #'specs/GAPhenotype + {})))) + + (testing "GAMutation failure case" + (is (thrown? Exception + (specs/validate! + "test-mutation" + #'specs/GAMutation + {})))) + + (testing "GAPopulation failure case" + (is (thrown? Exception + (specs/validate! + "test-pop" + #'specs/GAPopulationPhenotypes + {})))) + + + (testing "SolverRunConfig failure case" + (is (thrown? Exception + (specs/validate! + "test-solver-run-config" + #'specs/SolverRunConfig + {})))) + + (testing "SolverRunArgs failure case" + (is (thrown? Exception + (specs/validate! + "test-solver-run-args" + #'specs/SolverRunArgs + {})))) + + (testing "SolverRunResults failure case" + (is (thrown? Exception + (specs/validate! + "test-solver-run-results" + #'specs/SolverRunResults + {}))))) + + +(deftest check-instrumented + (testing "All default defns" + (do + (require 'closyr.symbolic-regression) + (let [ss (m/function-schemas)] + (is (= + (count ss) + ;; the number of ns which contain defns which have malli/schema metadata in entire src: + 6)) + + (is (= + (reduce + 0 (map (fn [[k v]] (count v)) ss)) + ;; the number of total defns which have malli/schema metadata in entire src: + 10)))))) + + +#_(deftest check-can-uninstrument + (testing "Can de-instrument" + (let [_ (#'specs/disable-validate-instrumentation!)] + (mi/unstrument!) + + + + (is (= (specs/validate! + "test-solver-run-results" + #'specs/SolverRunResults + {}) + true)) + + (is (= (#'ops/compute-residual nil nil) + ops/max-resid)) + + + (is (= (ops-common/extend-xs [0.1 "a"]) + [])))))