aboutsummaryrefslogtreecommitdiff
path: root/core/math.nom
blob: feb64cb4efbc693ee49a649161bf91d01dbd1309 (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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#!/usr/bin/env nomsu -V4.8.8.6
#
    This file defines some common math literals and functions

use "core/metaprogramming.nom"
use "core/text.nom"
use "core/operators.nom"
use "core/control_flow.nom"
use "core/collections.nom"

# Literals:
test:
    assume (all of [inf, NaN, pi, tau, golden ratio, e]) or barf "\
        ..math constants failed"
    %nan = (NaN)
    assume (%nan != %nan) or barf "NaN failed"
compile [infinity, inf] to (Lua value "math.huge")
compile [not a number, NaN, nan] to (Lua value "(0/0)")
compile [pi, Pi, PI] to (Lua value "math.pi")
compile [tau, Tau, TAU] to (Lua value "(2*math.pi)")
compile [golden ratio] to (Lua value "((1+math.sqrt(5))/2)")
compile [e] to (Lua value "math.exp(1)")

# Functions:
test:
    assume (("5" as a number) == 5)
compile [% as a number, % as number] to (Lua value "tonumber(\(% as lua expr))")

test:
    assume (..)
        all of [..]
            abs 5, | 5 |, sqrt 5, √ 5, sine 5, cosine 5, tangent 5, arc sine 5, arc cosine 5
            arc tangent 5, arc tangent 5 / 10, hyperbolic sine 5, hyperbolic cosine 5
            hyperbolic tangent 5, e^ 5, ln 5, log base 2 of 5, floor 5, ceiling 5, round 5
    ..or barf "math functions failed"
compile [absolute value %, | % |, abs %] to (..)
    Lua value "math.abs(\(% as lua expr))"

compile [square root %, square root of %, √ %, sqrt %] to (..)
    Lua value "math.sqrt(\(% as lua expr))"

compile [sine %, sin %] to (Lua value "math.sin(\(% as lua expr))")
compile [cosine %, cos %] to (Lua value "math.cos(\(% as lua expr))")
compile [tangent %, tan %] to (Lua value "math.tan(\(% as lua expr))")
compile [arc sine %, asin %] to (Lua value "math.asin(\(% as lua expr))")
compile [arc cosine %, acos %] to (Lua value "math.acos(\(% as lua expr))")
compile [arc tangent %, atan %] to (Lua value "math.atan(\(% as lua expr))")
compile [arc tangent %y / %x, atan2 %y %x] to (..)
    Lua value "math.atan2(\(%y as lua expr), \(%x as lua expr))"

compile [hyperbolic sine %, sinh %] to (Lua value "math.sinh(\(% as lua expr))")
compile [hyperbolic cosine %, cosh %] to (Lua value "math.cosh(\(% as lua expr))")
compile [hyperbolic tangent %, tanh %] to (..)
    Lua value "math.tanh(\(% as lua expr))"

compile [e^ %, exp %] to (Lua value "math.exp(\(% as lua expr))")
compile [natural log %, ln %, log %] to (Lua value "math.log(\(% as lua expr))")
compile [log % base %base, log base %base of %] to (..)
    Lua value "math.log(\(% as lua expr), \(%base as lua expr))"

compile [floor %] to (Lua value "math.floor(\(% as lua expr))")
compile [ceiling %, ceil %] to (Lua value "math.ceil(\(% as lua expr))")
compile [round %, % rounded] to (Lua value "math.floor(\(% as lua expr) + .5)")

test:
    assume ((463 to the nearest 100) == 500) or barf "rounding failed"
    assume ((2.6 to the nearest 0.25) == 2.5) or barf "rounding failed"
action [%n to the nearest %rounder] (..)
    =lua "(\%rounder)*math.floor((\%n / \%rounder) + .5)"

# Any/all/none
compile [all of %items, all %items] to:
    unless (%items.type is "List"):
        return (Lua value "utils.all(\(%items as lua expr))")
    %clauses = (((% as lua expr)::as smext) for % in %items)
    return (Lua value "(\(%clauses::joined with " and "))")

parse [not all of %items, not all %items] as (not (all of %items))
compile [any of %items, any %items] to:
    unless (%items.type is "List"):
        return (Lua value "utils.any(\(%items as lua expr))")
    %clauses = (((% as lua expr)::as smext) for % in %items)
    return (Lua value "(\(%clauses::joined with " or "))")

parse [none of %items, none %items] as (not (any of %items))
compile [sum of %items, sum %items] to:
    unless (%items.type is "List"):
        return (Lua value "utils.sum(\(%items as lua expr))")
    %clauses = (((% as lua expr)::as smext) for % in %items)
    return (Lua value "(\(%clauses::joined with " + "))")

parse [if all of %items %body, if all of %items then %body] as (..)
    if (all of %items) %body
parse [unless all of %items %body, unless all of %items then %body] as (..)
    if (not (all of %items)) %body
parse [if any of %items %body, if any of %items then %body] as (..)
    if (any of %items) %body
parse [unless any of %items %body, unless any of %items then %body] as (..)
    if (not (any of %items)) %body
parse [if none of %items %body, if none of %items then %body] as (..)
    if (not (any of %items)) %body
parse [unless none of %items %body, unless none of %items then %body] as (..)
    if (any of %items) %body

parse [if all of %items %body else %else, if all of %items then %body else %else] as (..)
    if (all of %items) %body else %else
parse [unless all of %items %body else %else, unless all of %items then %body else %else] as (..)
    if (not (all of %items)) %body else %else
parse [if any of %items %body else %else, if any of %items then %body else %else] as (..)
    if (any of %items) %body else %else
parse [unless any of %items %body else %else, unless any of %items then %body else %else] as (..)
    if (not (any of %items)) %body else %else
parse [if none of %items %body else %else, if none of %items then %body else %else] as (..)
    if (not (any of %items)) %body else %else
parse [unless none of %items %body else %else, unless none of %items then %body else %else] as (..)
    if (any of %items) %body else %else

compile [product of %items, product %items] to:
    unless (%items.type is "List"):
        return (Lua value "utils.product(\(%items as lua expr))")
    %clauses = (((% as lua expr)::as smext) for % in %items)
    return (Lua value "(\(%clauses::joined with " * "))")

action [avg of %items, average of %items] (=lua "(utils.sum(\%items)/#\%items)")
compile [min of %items, smallest of %items, lowest of %items] to (..)
    Lua value "utils.min(\(%items as lua expr))"

compile [max of %items, biggest of %items, largest of %items, highest of %items] to (..)
    Lua value "utils.max(\(%items as lua expr))"

test:
    assume ((min of [3, -4, 1, 2] by % = (% * %)) == 1)
    assume ((max of [3, -4, 1, 2] by % = (% * %)) == -4)
parse [min of %items by %item = %value_expr] as (..)
    result of:
        set {%best:nil, %best_key:nil}
        for %item in %items:
            %key = %value_expr
            if ((%best == (nil)) or (%key < %best_key)):
                set {%best:%item, %best_key:%key}
        
        return %best

parse [max of %items by %item = %value_expr] as (..)
    result of:
        set {%best:nil, %best_key:nil}
        for %item in %items:
            %key = %value_expr
            if ((%best == (nil)) or (%key > %best_key)):
                set {%best:%item, %best_key:%key}
        
        return %best

# Random functions
action [seed random with %] (..)
    lua> "\
        ..math.randomseed(\%);
        for i=1,20 do math.random(); end"

parse [seed random] as (seed random with (=lua "os.time()"))
compile [random number, random, rand] to (Lua value "math.random()")
compile [random int %n, random integer %n, randint %n] to (..)
    Lua value "math.random(\(%n as lua expr))"

compile [..]
    random from %low to %high, random number from %low to %high
    rand %low %high
..to (Lua value "math.random(\(%low as lua expr), \(%high as lua expr))")

action [random choice from %elements, random choice %elements, random %elements] (..)
    =lua "\%elements[math.random(#\%elements)]"