Skip to content

Commit

Permalink
Merge pull request #44 from MastodonC/feature/validate-transitions
Browse files Browse the repository at this point in the history
Feature/validate transitions
  • Loading branch information
seb231 authored Mar 26, 2018
2 parents 9174dd1 + 17b876e commit 0ea42a7
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 75 deletions.
5 changes: 3 additions & 2 deletions src/clj/witan/send/schemas.clj
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,11 @@

(def ValidSettingAcademicYears
(make-ordered-ds-schema [[:setting s/Keyword]
[:setting->group s/Str]
[:setting-group s/Str]
[:min-academic-year AcademicYear]
[:max-academic-year AcademicYear]
[:needs s/Str]]))
[:needs s/Str]
[:setting->setting s/Str]]))

(def PopulationByCalendarAndAcademicYear
{CalendarYear {AcademicYear N}})
Expand Down
66 changes: 28 additions & 38 deletions src/clj/witan/send/send.clj
Original file line number Diff line number Diff line change
Expand Up @@ -216,9 +216,9 @@
(update-ifelse-assoc assoc-first-state second-state + diff)))
transitions))

(defn prep-inputs [initial-state splice-ncy valid-states transition-matrix transition-matrix-filtered
population valid-setting-academic-years original-transitions setting-cost
filter-transitions-from]
(defn prep-inputs [initial-state splice-ncy valid-states valid-transitions transition-matrix
transition-matrix-filtered population valid-setting-academic-years
original-transitions setting-cost filter-transitions-from]
(let [start-map {:population-by-age-state initial-state
:valid-setting-academic-years valid-setting-academic-years
:transition-matrix original-transitions
Expand Down Expand Up @@ -246,19 +246,19 @@
(p/alpha-params-joiner-states valid-states (u/transitions-map transition-matrix-filtered)))

:mover-beta-params (stitch-ay-state-params splice-ncy
(p/beta-params-movers valid-states transition-matrix)
(p/beta-params-movers valid-states transition-matrix-filtered))
(p/beta-params-movers valid-states valid-transitions transition-matrix)
(p/beta-params-movers valid-states valid-transitions transition-matrix-filtered))
:mover-state-alphas (stitch-ay-state-params splice-ncy
(p/alpha-params-movers valid-states transition-matrix)
(p/alpha-params-movers valid-states transition-matrix-filtered))})
(p/alpha-params-movers valid-states valid-transitions transition-matrix)
(p/alpha-params-movers valid-states valid-transitions transition-matrix-filtered))})
(merge start-map
{:joiner-beta-params (p/beta-params-joiners valid-states
transition-matrix
(ds/row-maps population))
:leaver-beta-params (p/beta-params-leavers valid-states transition-matrix)
:joiner-state-alphas (p/alpha-params-joiner-states valid-states (u/transitions-map transition-matrix))
:mover-beta-params (p/beta-params-movers valid-states transition-matrix)
:mover-state-alphas (p/alpha-params-movers valid-states transition-matrix)}))))
:mover-beta-params (p/beta-params-movers valid-states valid-transitions transition-matrix)
:mover-state-alphas (p/alpha-params-movers valid-states valid-transitions transition-matrix)}))))

(defn build-states-to-change [settings-to-change valid-needs ages years]
(if (= :nil (-> settings-to-change
Expand Down Expand Up @@ -307,10 +307,12 @@
(let [original-transitions transition-matrix
ages (distinct (map :academic-year (ds/row-maps population)))
years (distinct (map :calendar-year (ds/row-maps population)))
valid-needs (->> (ds/row-maps valid-setting-academic-years)
(states/calculate-valid-needs-from-setting-academic-years))
_ (when (not= 1 modify-transition-by)
(prn (str "Modifying transitions by " modify-transition-by)))
initialise-validation (ds/row-maps valid-setting-academic-years)
valid-transitions (states/calculate-valid-mover-transitions initialise-validation)
valid-needs (states/calculate-valid-needs-from-setting-academic-years initialise-validation)
valid-settings (states/calculate-valid-settings-from-setting-academic-years initialise-validation)
valid-states (states/calculate-valid-states-from-setting-academic-years initialise-validation)
valid-year-settings (states/calculate-valid-year-settings-from-setting-academic-years initialise-validation)
states-to-change (when (not= 1 modify-transition-by)
(build-states-to-change settings-to-change valid-needs ages years))
transition-matrix (ds/row-maps transition-matrix)
Expand All @@ -319,40 +321,28 @@
u/full-transitions-map)
result (reduce (fn [m k] (modify-transitions m k * modify-transition-by)) convert states-to-change)]
(mapcat (fn [[k v]] (u/back-to-transitions-matrix k v)) result)))
_ (if (nil? modified-transition-matrix)
(prn "Using input transitions matrix")
(prn "Using modified transitions matrix"))
transitions (if (nil? modified-transition-matrix)
(u/transitions-map transition-matrix)
(u/transitions-map modified-transition-matrix))
_ (if modified-transition-matrix
(prn "Using modified transitions matrix")
(prn "Using input transitions matrix"))
transitions (if modified-transition-matrix
(u/transitions-map modified-transition-matrix)
(u/transitions-map transition-matrix))
transition-matrix-filtered (when filter-transitions-from
(mapcat (fn [year] (filter #(= (:calendar-year %) year) (or modified-transition-matrix transition-matrix))) filter-transitions-from))

initial-state (initialise-model (ds/row-maps initial-send-population))

valid-settings (->> (ds/row-maps valid-setting-academic-years)
(states/calculate-valid-settings-from-setting-academic-years))

valid-states (->> (ds/row-maps valid-setting-academic-years)
(states/calculate-valid-states-from-setting-academic-years))

valid-year-settings (->> (ds/row-maps valid-setting-academic-years)
(states/calculate-valid-year-settings-from-setting-academic-years))]

initial-state (initialise-model (ds/row-maps initial-send-population))]
(when (not= 1 modify-transition-by)
(report/info "Modified transitions by " (report/bold modify-transition-by)))
(if (nil? modified-transition-matrix)
(report/info "Used " (report/bold "input") " transitions matrix\n")
(report/info "Used " (report/bold "modified") " transitions matrix\n"))

(if modified-transition-matrix
(report/info "Used " (report/bold "modified") " transitions matrix\n")
(report/info "Used " (report/bold "input") " transitions matrix\n"))
(s/validate (sc/SENDPopulation+ valid-settings) initial-send-population)
(s/validate (sc/TransitionsMap+ valid-needs valid-settings) transitions)
(s/validate (sc/NeedSettingCost+ valid-needs valid-settings) setting-cost)
{:standard-projection (prep-inputs initial-state splice-ncy valid-states transition-matrix transition-matrix-filtered
{:standard-projection (prep-inputs initial-state splice-ncy valid-states valid-transitions transition-matrix transition-matrix-filtered
population valid-setting-academic-years original-transitions setting-cost
filter-transitions-from)
:scenario-projection (when modified-transition-matrix
(prep-inputs initial-state splice-ncy valid-states modified-transition-matrix
(prep-inputs initial-state splice-ncy valid-states valid-transitions modified-transition-matrix
transition-matrix-filtered population valid-setting-academic-years
original-transitions setting-cost filter-transitions-from))
:modify-transition-by modify-transition-by
Expand Down Expand Up @@ -541,7 +531,7 @@
(report/info (report/bold "Not every historic transition present in projection!") "Consider checking valid state input.\n"))
(when output
(let [valid-settings (assoc (->> (ds/row-maps valid-setting-academic-years)
(reduce #(assoc %1 (:setting %2) (:setting->group %2)) {}))
(reduce #(assoc %1 (:setting %2) (:setting-group %2)) {}))
:NON-SEND "Other" )
years (sort (distinct (map :calendar-year transitions-data)))
initial-projection-year (+ 1 (last years))
Expand Down
5 changes: 5 additions & 0 deletions src/clj/witan/send/utils.clj
Original file line number Diff line number Diff line change
Expand Up @@ -366,3 +366,8 @@

(defn projection->transitions [[state sum]]
(repeat sum (projection-state-to-map state)))

(defn keep-duplicates [seq]
(for [[id freq] (frequencies seq)
:when (> freq 1)]
id))
30 changes: 20 additions & 10 deletions src/cljc/witan/send/params.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -247,10 +247,10 @@
{} valid-states)))

#_(defn beta-params-movers [valid-states transitions]
(weighted-beta-params valid-states transitions (some-fn joiner? leaver?) mover?))
(weighted-beta-params valid-states transitions (some-fn joiner? leaver?) mover?))

#_(defn alpha-params-movers [valid-states valid-year-settings transitions]
(weighted-alpha-params valid-states valid-year-settings transitions mover?))
(weighted-alpha-params valid-states valid-year-settings transitions mover?))

(defn alpha-params-joiner-states [valid-states transitions]
(weighted-joiner-state-alpha-params valid-states transitions))
Expand All @@ -275,9 +275,12 @@
population-per-calendar-year (calculate-population-per-calendar-year population)]
(weighted-joiner-beta-params valid-states joiners-per-calendar-year population-per-calendar-year)))

(defn any-valid-transitions? [state valid-transitions]
(< 1 (count (get valid-transitions (second (s/need-setting state))))))

(defn beta-params-movers
"calculates the rate of the likelihood of a state transitioning for an academic year"
[valid-states transitions]
[valid-states valid-transitions transitions]
(let [academic-years (->> (map first valid-states)
(distinct)
(sort))
Expand All @@ -300,16 +303,18 @@
{} observations)
prior-per-year (continue-for-latter-ays prior-per-year academic-years)]
(reduce (fn [coll [ay state]]
(if-let [beta-params (merge-with +
(get-in observations [ay state])
(get prior-per-year ay))]
(assoc coll [ay state] beta-params)
(if (any-valid-transitions? state valid-transitions)
(if-let [beta-params (merge-with +
(get-in observations [ay state])
(get prior-per-year ay))]
(assoc coll [ay state] beta-params)
coll)
coll))
{} valid-states)))

(defn alpha-params-movers
"calculates the rate of transitions to a new state at academic year X for state Y"
[valid-states transitions]
[valid-states valid-transitions transitions]
(let [academic-years (->> (map first valid-states)
(distinct)
(sort))
Expand Down Expand Up @@ -340,10 +345,15 @@
valid-settings (s/calculate-valid-settings-for-need-ay valid-states)]
(reduce (fn [coll [ay state]]
(let [[need setting] (s/need-setting state)
valid-trans (get valid-transitions setting)
obs (get-in observations [ay state])
ay-obs (get observations-per-ay ay)
settings (get valid-settings [ay need])
prior (->> (zipmap (vec settings) (repeat (/ 1.0 (count settings))))
settings (->> (get valid-settings [ay need])
vec
(into valid-trans)
u/keep-duplicates
vec)
prior (->> (zipmap settings (repeat (/ 1.0 (count settings))))
(merge-with + ay-obs))
prior (dissoc prior setting)
total (->> (vals prior) (apply +))
Expand Down
14 changes: 6 additions & 8 deletions src/cljc/witan/send/states.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,12 @@
(update coll [ay need] (fnil conj #{}) setting)))
{} valid-states))

(defn calculate-valid-mover-transitions [valid-states]
(let [valid-need-settings (calculate-valid-settings-for-need-ay valid-states)]
(mapcat (fn [[ay state']]
(let [[need _] (need-setting state')
settings (get valid-need-settings [(inc ay) need])]
(for [setting settings]
(vector ay state' (state need setting)))))
valid-states)))
(defn aggregate-setting->setting [setting setting->setting]
(hash-map setting (mapv keyword (str/split setting->setting #","))))

(defn calculate-valid-mover-transitions [valid-setting-academic-years]
(reduce into {} (map (fn [row] (aggregate-setting->setting (:setting row) (:setting->setting row)))
valid-setting-academic-years)))

(defn transitions->initial-state
[transitions]
Expand Down
37 changes: 20 additions & 17 deletions test/witan/send/params_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,21 @@
[witan.send.test-utils :as tu]))

(def valid-setting-academic-years
[{:setting :CC, :min-academic-year -4, :max-academic-year 0, :needs "ASD,HI,M,MLD,MSI,OTH,PD,PMLD,SEMH,SLCN,SLD,SPLD,VI"}
{:setting :EO, :min-academic-year -1, :max-academic-year 14, :needs "ASD,HI,M,MLD,MSI,OTH,PD,PMLD,SEMH,SLCN,SLD,SPLD,VI"}
{:setting :FEC, :min-academic-year 12, :max-academic-year 20, :needs "ASD,HI,M,MLD,MSI,OTH,PD,PMLD,SEMH,SLCN,SLD,SPLD,VI"}
{:setting :IMS, :min-academic-year -3, :max-academic-year 14, :needs "ASD,HI,M,MLD,MSI,OTH,PD,PMLD,SEMH,SLCN,SLD,SPLD,VI"}
{:setting :IN, :min-academic-year -4, :max-academic-year 0, :needs "ASD,HI,M,MLD,MSI,OTH,PD,PMLD,SEMH,SLCN,SLD,SPLD,VI"}
{:setting :ISC, :min-academic-year 15, :max-academic-year 20, :needs "ASD,HI,M,MLD,MSI,OTH,PD,PMLD,SEMH,SLCN,SLD,SPLD,VI"}
{:setting :ISCR, :min-academic-year 15, :max-academic-year 20, :needs "ASD,HI,M,MLD,MSI,OTH,PD,PMLD,SEMH,SLCN,SLD,SPLD,VI"}
{:setting :ISS, :min-academic-year 0, :max-academic-year 14, :needs "ASD,HI,M,MLD,MSI,OTH,PD,PMLD,SEMH,SLCN,SLD,SPLD,VI"}
{:setting :ISSR, :min-academic-year 0, :max-academic-year 14, :needs "ASD,HI,M,MLD,MSI,OTH,PD,PMLD,SEMH,SLCN,SLD,SPLD,VI"}
{:setting :IT, :min-academic-year 2, :max-academic-year 15, :needs "ASD,HI,M,MLD,MSI,OTH,PD,PMLD,SEMH,SLCN,SLD,SPLD,VI"}
{:setting :MMS, :min-academic-year -3, :max-academic-year 14, :needs "ASD,HI,M,MLD,MSI,OTH,PD,PMLD,SEMH,SLCN,SLD,SPLD,VI"}
{:setting :MSS, :min-academic-year -3, :max-academic-year 14, :needs "ASD,HI,M,MLD,MSI,OTH,PD,PMLD,SEMH,SLCN,SLD,SPLD,VI"}
{:setting :MU, :min-academic-year -1, :max-academic-year 14, :needs "ASD,HI,M,MLD,MSI,OTH,PD,PMLD,SEMH,SLCN,SLD,SPLD,VI"}
{:setting :OOE, :min-academic-year 6, :max-academic-year 20, :needs "ASD,HI,M,MLD,MSI,OTH,PD,PMLD,SEMH,SLCN,SLD,SPLD,VI"}
{:setting :PRU, :min-academic-year 2, :max-academic-year 14, :needs "ASD,HI,M,MLD,MSI,OTH,PD,PMLD,SEMH,SLCN,SLD,SPLD,VI"}])
[{:setting :CC, :setting->setting "CC,EO,FEC,IMS,IN,ISC,ISCR,ISS,ISSR,IT,MMS,MSS,MU,OOE,PRU" :min-academic-year -4, :max-academic-year 0, :needs "ASD,HI,M,MLD,MSI,OTH,PD,PMLD,SEMH,SLCN,SLD,SPLD,VI"}
{:setting :EO, :setting->setting "CC,EO,FEC,IMS,IN,ISC,ISCR,ISS,ISSR,IT,MMS,MSS,MU,OOE,PRU" :min-academic-year -1, :max-academic-year 14, :needs "ASD,HI,M,MLD,MSI,OTH,PD,PMLD,SEMH,SLCN,SLD,SPLD,VI"}
{:setting :FEC, :setting->setting "CC,EO,FEC,IMS,IN,ISC,ISCR,ISS,ISSR,IT,MMS,MSS,MU,OOE,PRU" :min-academic-year 12, :max-academic-year 20, :needs "ASD,HI,M,MLD,MSI,OTH,PD,PMLD,SEMH,SLCN,SLD,SPLD,VI"}
{:setting :IMS, :setting->setting "CC,EO,FEC,IMS,IN,ISC,ISCR,ISS,ISSR,IT,MMS,MSS,MU,OOE,PRU" :min-academic-year -3, :max-academic-year 14, :needs "ASD,HI,M,MLD,MSI,OTH,PD,PMLD,SEMH,SLCN,SLD,SPLD,VI"}
{:setting :IN, :setting->setting "CC,EO,FEC,IMS,IN,ISC,ISCR,ISS,ISSR,IT,MMS,MSS,MU,OOE,PRU" :min-academic-year -4, :max-academic-year 0, :needs "ASD,HI,M,MLD,MSI,OTH,PD,PMLD,SEMH,SLCN,SLD,SPLD,VI"}
{:setting :ISC, :setting->setting "CC,EO,FEC,IMS,IN,ISC,ISCR,ISS,ISSR,IT,MMS,MSS,MU,OOE,PRU" :min-academic-year 15, :max-academic-year 20, :needs "ASD,HI,M,MLD,MSI,OTH,PD,PMLD,SEMH,SLCN,SLD,SPLD,VI"}
{:setting :ISCR, :setting->setting "CC,EO,FEC,IMS,IN,ISC,ISCR,ISS,ISSR,IT,MMS,MSS,MU,OOE,PRU" :min-academic-year 15, :max-academic-year 20, :needs "ASD,HI,M,MLD,MSI,OTH,PD,PMLD,SEMH,SLCN,SLD,SPLD,VI"}
{:setting :ISS, :setting->setting "CC,EO,FEC,IMS,IN,ISC,ISCR,ISS,ISSR,IT,MMS,MSS,MU,OOE,PRU" :min-academic-year 0, :max-academic-year 14, :needs "ASD,HI,M,MLD,MSI,OTH,PD,PMLD,SEMH,SLCN,SLD,SPLD,VI"}
{:setting :ISSR, :setting->setting "CC,EO,FEC,IMS,IN,ISC,ISCR,ISS,ISSR,IT,MMS,MSS,MU,OOE,PRU" :min-academic-year 0, :max-academic-year 14, :needs "ASD,HI,M,MLD,MSI,OTH,PD,PMLD,SEMH,SLCN,SLD,SPLD,VI"}
{:setting :IT, :setting->setting "CC,EO,FEC,IMS,IN,ISC,ISCR,ISS,ISSR,IT,MMS,MSS,MU,OOE,PRU" :min-academic-year 2, :max-academic-year 15, :needs "ASD,HI,M,MLD,MSI,OTH,PD,PMLD,SEMH,SLCN,SLD,SPLD,VI"}
{:setting :MMS, :setting->setting "CC,EO,FEC,IMS,IN,ISC,ISCR,ISS,ISSR,IT,MMS,MSS,MU,OOE,PRU" :min-academic-year -3, :max-academic-year 14, :needs "ASD,HI,M,MLD,MSI,OTH,PD,PMLD,SEMH,SLCN,SLD,SPLD,VI"}
{:setting :MSS, :setting->setting "CC,EO,FEC,IMS,IN,ISC,ISCR,ISS,ISSR,IT,MMS,MSS,MU,OOE,PRU" :min-academic-year -3, :max-academic-year 14, :needs "ASD,HI,M,MLD,MSI,OTH,PD,PMLD,SEMH,SLCN,SLD,SPLD,VI"}
{:setting :MU, :setting->setting "CC,EO,FEC,IMS,IN,ISC,ISCR,ISS,ISSR,IT,MMS,MSS,MU,OOE,PRU" :min-academic-year -1, :max-academic-year 14, :needs "ASD,HI,M,MLD,MSI,OTH,PD,PMLD,SEMH,SLCN,SLD,SPLD,VI"}
{:setting :OOE, :setting->setting "CC,EO,FEC,IMS,IN,ISC,ISCR,ISS,ISSR,IT,MMS,MSS,MU,OOE,PRU" :min-academic-year 6, :max-academic-year 20, :needs "ASD,HI,M,MLD,MSI,OTH,PD,PMLD,SEMH,SLCN,SLD,SPLD,VI"}
{:setting :PRU, :setting->setting "CC,EO,FEC,IMS,IN,ISC,ISCR,ISS,ISSR,IT,MMS,MSS,MU,OOE,PRU" :min-academic-year 2, :max-academic-year 14, :needs "ASD,HI,M,MLD,MSI,OTH,PD,PMLD,SEMH,SLCN,SLD,SPLD,VI"}])

(def population-dataset
(tu/csv-to-dataset "data/demo/population.csv" sc/PopulationDataset))
Expand All @@ -34,6 +34,9 @@
(-> valid-setting-academic-years
(s/calculate-valid-states-from-setting-academic-years)))

(def valid-transitions
(s/calculate-valid-mover-transitions valid-setting-academic-years))

(def valid-year-settings
(s/calculate-valid-year-settings-from-setting-academic-years valid-setting-academic-years))

Expand All @@ -51,7 +54,7 @@

(testing "Positive mover state alphas for every year with >1 setting"
(let [transitions {}
params (sut/alpha-params-movers valid-states transitions)]
params (sut/alpha-params-movers valid-states valid-transitions transitions)]
(is (empty? (remove (fn [[academic-year state]]
(let [alphas (get params [academic-year state])]
(and (pos? (count alphas))
Expand All @@ -71,7 +74,7 @@

(testing "Positive mover beta params for every valid state"
(let [transitions {}
params (sut/beta-params-movers valid-states transitions)]
params (sut/beta-params-movers valid-states valid-transitions transitions)]
(is (every? (fn [[_ betas]]
(and (pos? (:alpha betas))
(pos? (:beta betas))))
Expand Down

0 comments on commit 0ea42a7

Please sign in to comment.