-
Notifications
You must be signed in to change notification settings - Fork 7
/
parameters.clj
123 lines (104 loc) · 3.76 KB
/
parameters.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
(ns com.yetanalytics.datasim.input.parameters
"Parameter input specs and parsing."
(:require [clojure.spec.alpha :as s]
[java-time.api :as t]
[xapi-schema.spec :as xs]
[com.yetanalytics.pan.objects.profile :as prof]
[com.yetanalytics.pan.objects.pattern :as pat]
[com.yetanalytics.datasim.util.random :as random]
[com.yetanalytics.datasim.util.errors :as errs])
(:import [clojure.lang ExceptionInfo]
[java.time.zone ZoneRulesException]
[java.time Instant]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Specs
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; All options are optional, but everything except `end` will get defaults
;; (optional) start of the simulation (inclusive), 8601 stamp
(s/def ::start
::xs/timestamp)
;; (optional) start of the returned statements (if after ::start).
;; This lets us page through sims to later times. Defaults to ::start
(s/def ::from
::xs/timestamp)
;; (optional) end of the simulation (exclusive), 8601 stamp
(s/def ::end
(s/nilable ::xs/timestamp))
(defn- timezone-string? [s]
(try (t/zone-id s)
(catch ExceptionInfo exi
(if (= ZoneRulesException (type (ex-cause exi)))
false
(throw exi)))))
;; (optional) timezone, defaults to UTC
(s/def ::timezone
(s/and string?
not-empty
timezone-string?))
;; Seed is required, but will be generated if not present
(s/def ::seed
int?)
;; Max number of statements returned
(s/def ::max
pos-int?)
;; Max number of bound restarts before giving up
(s/def ::maxRestarts
pos-int?)
;; Restrict Generation to these profile IDs
(s/def ::genProfiles
(s/every ::prof/id))
;; Restrict Generation to these pattern IDs
(s/def ::genPatterns
(s/every ::pat/id))
(defn- ordered-timestamps?
"Are the `start`, `from`, and `end` timestamps ordered properly?"
[{:keys [start from end]}]
(let [start-t (t/instant start)
?from-t (some->> from t/instant)
?end-t (some->> end t/instant)]
(and (or (not ?end-t)
(t/before? start-t ?end-t))
(or (not ?end-t)
(not ?from-t)
(t/before? ?from-t ?end-t))
(or (not ?from-t)
(= ?from-t start-t)
(t/before? start-t ?from-t)))))
(s/def ::parameters
(s/and
(s/keys :req-un [::start
::timezone
::seed]
:opt-un [::end
::from
::max
::maxRestarts
::genProfiles
::genPatterns])
ordered-timestamps?))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Validation
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn validate-parameters
[parameters]
(some->> (s/explain-data ::parameters parameters)
(errs/explain-to-map-coll ::parameters)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Defaults
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def utc-timezone "UTC")
(def default-max-restarts 5)
(defn apply-defaults
"Apply defaults to `params` with the current time and a random seed.
If `params` is not provided simply return the default parameters."
([]
(apply-defaults {}))
([{:keys [start from timezone seed maxRestarts] :as params}]
(merge
params
(let [start (or start (.toString (Instant/now)))]
{:start start
:from (or from start)
:timezone (or timezone utc-timezone)
:seed (or seed (random/rand-unbound-int (random/rng)))
:maxRestarts (or maxRestarts default-max-restarts)}))))