-
Notifications
You must be signed in to change notification settings - Fork 0
/
default.cljc
113 lines (98 loc) · 3.74 KB
/
default.cljc
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
(ns mapdag.runtime.default
"Reference implementation for executing mapdag Graphs - a portable interpreter."
(:require [mapdag.step :as mdg]
[mapdag.analysis]
[mapdag.error]))
(defn compute
"Executes a mapdag Graph on the supplied inputs to return the required outputs.
Given:
- `graph`: a mapdag Graph
- `inputs map`: a map from input keys to input values
- `output-keys`: a sequence of input or Step names (this sequence may be empty or nil)
returns a map from the output keys to their computed values.
Only the necessary intermediary computations will be performed.
Missing inputs and dependency cycles will be tolerated, but only if they can't be reached from given output keys."
[graph inputs-map output-keys]
(mapdag.analysis/validate-graph graph
(keys inputs-map)
output-keys)
(letfn [(ensure-key [acc step-name]
(if (contains? acc step-name)
acc
(if (contains? inputs-map step-name)
(assoc acc
step-name
(get inputs-map step-name))
(if-some [{:as step
compute-fn :mapdag.step/compute-fn
deps-names :mapdag.step/deps}
(get graph step-name)]
(let [acc1 (reduce ensure-key acc deps-names)
deps-values (mapv acc1 deps-names)
;; FIXME error management
v (try
(apply compute-fn deps-values)
(catch Throwable err
(throw
(ex-info
(str "Error computing step " (pr-str step-name) ": " (pr-str :mapdag.step/compute-fn) " threw.")
(merge
{:mapdag.error/reason :mapdag.errors/compute-fn-threw
:mapdag.trace/deps-values deps-values ;; INTRO a vector, the values taken by the dependencies of this Step when the error was thrown. (Val, 20 May 2020)
:mapdag.step/name step-name}
step)
err))))]
(assoc acc1 step-name v))
(throw
(ex-info
(str "Missing step or input: " (pr-str step-name))
{:mapdag.error/reason :mapdag.errors/missing-step-or-input
:mapdag.step/name step-name}))))))]
(let [computed (reduce ensure-key {} output-keys)]
(into {}
(map
(fn [step-name]
[step-name (get computed step-name)]))
output-keys))))
(comment
(def inputs-map
{:xs [0. 1. 1.2 -1.2]})
(def graph
{:N (mdg/step [:xs] count)
:sum (mdg/step [:xs]
(fn [xs] (apply + 0. xs)))
:mean (mdg/step [:sum :N]
(fn [sum N]
(/ sum N)))
:squares (mdg/step [:xs]
(fn [xs]
(mapv #(* % %) xs)))
:sum-squares (mdg/step [:squares]
(fn [s2] (apply + 0. s2)))
:variance (mdg/step [:mean :sum-squares :N]
(fn [mean sum-squares N]
(-
(/ sum-squares N)
(* mean mean))))
:stddev (mdg/step [:variance]
(fn [variance] (Math/sqrt variance)))})
(compute
graph
inputs-map
[:N :mean :variance])
=> {:N 4, :mean 0.25000000000000006, :variance 0.9075}
(compute
graph
{}
[:N :mean :variance])
*e
(compute
graph
{:xs ["I'm not a number!"]}
[:N :mean :variance])
*e
(compute
graph
inputs-map
[:N :DOES-NOT-EXIST])
*e)