Nearer and nearer to working. No DTree testing yet, but other things good.
This commit is contained in:
parent
45f6b972c7
commit
99fce9c98f
|
@ -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})
|
||||
|
|
|
@ -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)))
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue