aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/test/lux/world/time/series/average.lux
blob: 32955cba68e05de9282885842e38c358cf412298 (plain)
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
... This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
... If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.

(.require
 [library
  [lux (.except)
   [abstract
    [monad (.only do)]]
   [control
    ["[0]" try]
    ["[0]" exception]]
   [math
    ["[0]" random (.only Random)]
    [number
     ["n" nat]
     ["f" frac]]]
   [world
    [time
     ["[0]" instant (.use "[1]#[0]" order)]
     ["[0]" duration (.use "[1]#[0]" equivalence)]]]
   [test
    ["_" property (.only Test)]]]]
 [\\library
  ["[0]" / (.only)
   ["/[1]" //]]])

(def (series events)
  (-> Nat
      (Random (/.Series Frac)))
  (do [! random.monad]
    [.let [duration (random.only duration.positive? random.duration)]
     offset (of ! each (duration.framed (duration.up 100 duration.normal_year))
                duration)
     .let [start (instant.after offset instant.epoch)]
     interval (of ! each (duration.framed duration.week)
                  duration)
     data (random.sequence events random.safe_frac)]
    (in [//.#start start
         //.#interval interval
         //.#data data])))

(def (well_windowed? input additional output)
  (All (_ input output)
    (-> (/.Series input) Nat (/.Series output)
        Bit))
  (let [correct_start!
        (instant#< (//.start output)
                   (//.start input))

        correct_size!
        (n.= (n.- (++ additional) (//.size input))
             (//.size output))]
    (and correct_start!
         correct_size!)))

(def .public test
  Test
  (<| (_.covering /._)
      (do [! random.monad]
        [expected_events (of ! each (|>> (n.% 16) (n.+ 8)) random.nat)
         input (series expected_events)
         additional (of ! each (n.% expected_events) random.nat)])
      (all _.and
           (_.coverage [/.cumulative]
             (let [output (/.cumulative input)]
               (and (instant#= (//.start input)
                               (//.start output))
                    (n.= (//.size input)
                         (//.size output)))))
           (_.coverage [/.windows]
             (<| (try.else false)
                 (do try.monad
                   [output (/.windows additional input)]
                   (in (well_windowed? input additional output)))))
           (_.coverage [/.window_size_is_too_large]
             (when (/.windows (++ expected_events) input)
               {try.#Failure error}
               (exception.match? /.window_size_is_too_large error)

               {try.#Success _}
               false))
           (<| (_.for [/.Average])
               (all _.and
                    (_.coverage [/.exponential /.simple /.weighted

                                 /.Factor /.simple_factor]
                      (let [exponential (/.exponential /.simple_factor input)
                            simple (/.simple input)
                            weighted (/.weighted input)]
                        (and (not (f.= exponential simple))
                             (not (f.= exponential weighted))
                             (not (f.= simple weighted)))))
                    (_.coverage [/.moving]
                      (<| (try.else false)
                          (do try.monad
                            [exponential (/.moving (/.exponential /.simple_factor)
                                                   additional
                                                   input)
                             simple (/.moving /.simple
                                              additional
                                              input)
                             weighted (/.moving /.weighted
                                                additional
                                                input)
                             .let [(open "//#[0]") (//.equivalence f.equivalence)

                                   all_are_well_windowed!
                                   (and (well_windowed? input additional exponential)
                                        (well_windowed? input additional simple)
                                        (well_windowed? input additional weighted))

                                   all_are_different!
                                   (not (or (//#= exponential simple)
                                            (//#= exponential weighted)
                                            (//#= simple weighted)))]]
                            (in (and all_are_well_windowed!
                                     all_are_different!)))))
                    ))
           )))