From 99fce9c98f8034bc5c63c25a5026438cc952ffbc Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Thu, 14 Aug 2025 11:16:20 +0100 Subject: [PATCH] Nearer and nearer to working. No DTree testing yet, but other things good. --- project.clj | 2 +- src/arboretum/dengine/dengine.clj | 15 ++++---- src/arboretum/dengine/kb.clj | 58 ++++++++++++++++++------------- test/dengine/feature_test.clj | 3 +- 4 files changed, 45 insertions(+), 33 deletions(-) diff --git a/project.clj b/project.clj index 6cd34cf..43b2a75 100644 --- a/project.clj +++ b/project.clj @@ -5,5 +5,5 @@ :url "https://www.eclipse.org/legal/epl-2.0/"} :dependencies [[org.clojure/clojure "1.11.1"] [org.clojure/clojure "1.12.0"] - [com.taoensso/timbre "4.10.0"]] + [com.taoensso/telemere "1.0.1"]] :repl-options {:init-ns arboretum.dengine.core}) diff --git a/src/arboretum/dengine/dengine.clj b/src/arboretum/dengine/dengine.clj index 108b00f..7207bec 100644 --- a/src/arboretum/dengine/dengine.clj +++ b/src/arboretum/dengine/dengine.clj @@ -2,14 +2,14 @@ (:require [arboretum.dengine.kb :refer [!kb find-case-for find-feature-for remember!]] [arboretum.dengine.protocols :refer [Case]] - [taoensso.timbre :as timbre :refer [log]])) + [taoensso.telemere :refer [log!]])) (defn dengine [feat c] (let [c' (if (satisfies? Case c) c (-> @!kb :cases c)) f' (find-feature-for @!kb feat)] - ;; (log (format "Inferring value of `%s` for `%s`" - ;; (:case-id c') (:feature-id f'))) + (log! {:msg (format "Inferring value of `%s` for `%s`" + (:case-id c') (:feature-id f'))}) (when (nil? c') (throw (ex-info "Unknown or invalid case" {:case-identifier c}))) (when (:rootnode f') @@ -19,15 +19,16 @@ (defn decide-feat [feat c] (let [c' (find-case-for @!kb c) f' (find-feature-for @!kb feat) - v (.knowledge @!kb (.case-id c') (.feature-id f')) + v (.knowledge @!kb (:case-id c') (:feature-id f')) k (cond v v (:rootnode f') (dengine f' c') :else {:value (:default f') :authority :default :reason (format "I assumed %s was %s of %s." - (:name f') + (:proposition f') (:default f') - (.name c'))})] - (remember! f' c' k) + (:case-name c'))})] + (log! {:msg "decide-feat" :value k}) + (remember! (:case-id c') (:feature-id f') k) (:value k))) diff --git a/src/arboretum/dengine/kb.clj b/src/arboretum/dengine/kb.clj index b62f1d3..8f9f0ff 100644 --- a/src/arboretum/dengine/kb.clj +++ b/src/arboretum/dengine/kb.clj @@ -2,12 +2,7 @@ (:require [arboretum.dengine.protocols :refer [Case Feature KB]] [clojure.pprint :refer [pprint]] - [taoensso.timbre :as timbre :refer [log trace debug info warn error fatal report - logf tracef debugf infof warnf errorf fatalf reportf - spy]])) - - -;; (timbre/set-ns-min-level! :info) + [taoensso.telemere :refer [log!]])) (defn find-case-for [kb c] (cond (satisfies? Case c) c @@ -16,6 +11,11 @@ {:case c :type (type c)})))) +(defn find-case-id [kb c] + (cond + (and (keyword? c) (-> kb :cases c)) c + (satisfies? Case c) (:case-id c))) + (defn find-feature-for [kb f] (cond (satisfies? Feature f) f (keyword? f) (-> kb :features f) @@ -23,10 +23,18 @@ {:case f :type (type f)})))) -(defn do-is? [kb case-or-id feature-or-id] +(defn find-feature-id [kb f] + (cond + (and (keyword? f) (-> kb :features f)) f + (satisfies? Feature f) (:feature-id f))) + +(defn do-knowledge [kb case-or-id feature-or-id] (let [c (find-case-for kb case-or-id) - f (find-feature-for kb feature-or-id)] - (-> c :knowledge (:feature-id f) :value))) + f (find-feature-id kb feature-or-id)] + (-> c :knowledge f))) + +(defn do-is? [kb case-or-id feature-or-id] + (-> (do-knowledge kb case-or-id feature-or-id) :value)) (defrecord KBImpl [^clojure.lang.APersistentMap cases ^clojure.lang.APersistentMap features] KB @@ -37,9 +45,7 @@ (is? [this case-or-id feature-or-id] (do-is? this case-or-id feature-or-id)) (knowledge [this case-or-id feature-or-id] - (let [c (find-case-for this case-or-id) - f (find-feature-for this feature-or-id)] - (-> c :knowledge (:feature-id f))))) + (do-knowledge this case-or-id feature-or-id))) (def !kb "The one instance of the knowledge base." @@ -48,18 +54,22 @@ (defn remember! "Remember this `value` for the feature with this `feature-id` of the case with this `case-id`. Return the `value`." - [case-id feature-id value] - ;; (log (format "Remembering case `%s`, feature `%s`, value `%s`" - ;; case-id feature-id value)) - (cond - (boolean? value) (swap! !kb assoc-in - [:cases case-id :knowledge feature-id :value] value) - (map? value) (swap! !kb assoc-in - [:cases case-id :knowledge feature-id] value) - :else (throw (ex-info "Unexpected value?" {:case-id case-id - :feature-id feature-id - :value value}))) - value) + ([case-id feature-id value] + (let [v (cond (boolean? value) {:value value} + (and (map? value) (boolean? (:value value))) value) + c (find-case-id @!kb case-id) + f (find-feature-id @!kb feature-id)] + (when-not (and v c f) + (throw (ex-info "Missing data in remember!" {:value value + :v v + :feature-id feature-id + :f f + :case-id case-id + :c c}))) + (log! {:msg (format "Remembering case `%s`, feature `%s`, value `%s`" + case-id feature-id (:value v))}) + (swap! !kb assoc-in [:cases c :knowledge f] v) + (:value v)))) (defn persist [filepath] (let [p (if (empty? filepath) "kb.edn" filepath)] diff --git a/test/dengine/feature_test.clj b/test/dengine/feature_test.clj index 3745e78..e6e1c04 100644 --- a/test/dengine/feature_test.clj +++ b/test/dengine/feature_test.clj @@ -15,7 +15,8 @@ (deftest feature-impl-test (testing "Testing feature implementation" - (let [f (add-feature! "is entitled to Widow's Allowance" :is-entitled-to-widows-allowance false nil) + (let [f (add-feature! "is entitled to Widow's Allowance" + :is-entitled-to-widows-allowance false nil) c (add-case! "Mrs Nora Trellis" :case_1 {:married {:value true :authority :user