To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

Statistics Download as Zip
| Branch: | Revision:

root / src / may / vector.yeti @ 595:3b1f2aa8d36b

History | View | Annotate | Download (11.4 KB)

1

    
2
/**
3
 * Vectors. A May vector is a typesafe, immutable wrapper around a Java
4
 * primitive array of doubles.
5
 *
6
 * Although not as convenient and flexible as a Yeti array<number> or
7
 * list<number>, a vector can be faster and more compact when dealing
8
 * with dense data of suitable range and precision such as sampled
9
 * sequences.
10
 *
11
 * Because vectors are immutable, functions that transform them will
12
 * return the original data for identity transformations
13
 * (e.g. resizing to the vector's existing length).
14
 */
15

    
16
module may.vector;
17

    
18
import java.util: Arrays;
19
import may.bits: VectorBits;
20

    
21
{ floor, ceil } = load may.mathmisc;
22

    
23
/// Return a vector of n zeros.
24
zeros n is number -> ~double[] =
25
    new double[n];
26

    
27
/// Return a vector of length n, containing all m.
28
consts m n is number -> number -> ~double[] =
29
   (a = zeros n;
30
    Arrays#fill(a, m);
31
    a);
32

    
33
/// Return a vector of length n, containing all ones.
34
ones n = consts 1.0 n;
35

    
36
/// Return a vector of length n, containing random values.
37
randoms n is number -> ~double[] =
38
   (map \(Math#random()) [1..n]) as ~double[];
39

    
40
/// Return a vector of the values in the given list.
41
fromList l is list?<number> -> ~double[] =
42
    l as ~double[];
43

    
44
/// Return the given vector as a list.
45
list' a is ~double[] -> list<number> =
46
    list a;
47

    
48
/// Return the given vector as a Yeti array.
49
array' a is ~double[] -> array<number> =
50
    array a;
51

    
52
/// Return the length of the given vector.
53
length' v is ~double[] -> number =
54
    length v;
55

    
56
/// Return true if the given vector is empty (has length 0).
57
empty?' =
58
    empty? . list';
59

    
60
/// Return element n in the given vector v. (The function name and
61
/// argument order are chosen for symmetry with the similar standard
62
/// library array function.)
63
at' v n is ~double[] -> number -> number =
64
    v[n];
65

    
66
/// Return the given vector as a Java primitive float array.
67
floats a is ~double[] -> ~float[] =
68
   (len = length' a;
69
    f = new float[len];
70
    for [0..len-1] do i:
71
        f[i] := a[i];
72
    done;
73
    f);
74

    
75
/// Return a vector of the values in the given Java primitive float array.
76
fromFloats ff is ~float[] -> ~double[] =
77
   (len = length (list ff);
78
    a = new double[len];
79
    for [0..len-1] do i:
80
        a[i] := ff[i];
81
    done;
82
    a);
83

    
84
/// Return true if the given vectors are equal, using the standard ==
85
/// comparator on their elements.
86
equal v1 v2 is ~double[] -> ~double[] -> boolean =
87
    list v1 == list v2;
88

    
89
/// Return true if the given vectors are equal, when applying the
90
/// given numerical comparator to each element.
91
equalUnder comparator v1 v2 =
92
    length' v1 == length' v2 and
93
        all id (map2 comparator (list v1) (list v2));
94

    
95
/// Return another copy of the given vector.
96
copyOf v is ~double[] -> ~double[] =
97
    Arrays#copyOf(v, length v);
98

    
99
/// Return the given vector as a primitive array. Modifying the
100
/// array contents will not affect the original vector.
101
primitive = copyOf;
102

    
103
/// Return a new vector containing a subset of the elements of the
104
/// given vector, from index start (inclusive) to index finish
105
/// (exclusive). (The function name and argument order are chosen for
106
/// symmetry with the standard library slice and strSlice functions.)
107
slice v start finish is ~double[] -> number -> number -> ~double[] =
108
   (len = length v;
109
    if start == 0 and finish == len then v
110
    elif start < 0 then slice v 0 finish
111
    elif start > len then slice v len finish
112
    elif finish < start then slice v start start
113
    elif finish > len then slice v start len
114
    else
115
        Arrays#copyOfRange(v, start, finish);
116
    fi);
117

    
118
/// Return a vector of length n, containing the contents of the given
119
/// vector v. If v is longer than n, the contents will be truncated;
120
/// if shorter, they will be padded with zeros.
121
resizedTo n v is number -> ~double[] -> ~double[] =
122
    if n == length v then v;
123
    else Arrays#copyOf(v, n);
124
    fi;
125

    
126
/// Return a vector that is the reverse of the given vector.  Name
127
/// chosen (in preference to passive "reversed") for symmetry with the
128
/// standard library list reverse function.
129
reverse v is ~double[] -> ~double[] =
130
   (len = length v;
131
    a = new double[len];
132
    for [0..len-1] do i:
133
        a[len-i-1] := v[i];
134
    done;
135
    a);
136

    
137
/// Return a single new vector that contains the contents of all the
138
/// given vectors, in order. (Unlike the standard module list concat
139
/// function, this one cannot be lazy.)
140
concat' vv is list?<~double[]> -> ~double[] =
141
    case vv of
142
        [v]: v;
143
        v0::rest:
144
           (len = sum (map length' vv);
145
            vout = Arrays#copyOf(v0 is ~double[], len);
146
            var base = length' v0;
147
            for rest do v: 
148
                vlen = length' v;
149
                System#arraycopy(v, 0, vout, base, vlen);
150
                base := base + vlen;
151
            done;
152
            vout);
153
        _: zeros 0;
154
    esac;
155

    
156
/// Return a single new vector that contains the contents of the given
157
/// vector, repeated n times. The vector will therefore have length n
158
/// times the length of v.
159
repeated v n is ~double[] -> number -> ~double[] =
160
    concat' (map \(v) [1..n]);
161

    
162
sum' v is ~double[] -> number = 
163
    VectorBits#sum(v);
164

    
165
max' v is ~double[] -> number = 
166
   (var mx = 0;
167
    for [0..length v - 1] do i:
168
        if i == 0 or v[i] > mx then
169
            mx := v[i];
170
        fi
171
    done;
172
    mx);
173

    
174
maxindex v is ~double[] -> number =
175
   (var mx = 0;
176
    var mi = -1;
177
    for [0..length v - 1] do i:
178
        if i == 0 or v[i] > mx then
179
            mx := v[i];
180
            mi := i;
181
        fi
182
    done;
183
    mi);
184

    
185
min' v is ~double[] -> number = 
186
   (var mn = 0;
187
    for [0..length v - 1] do i:
188
        if i == 0 or v[i] < mn then
189
            mn := v[i];
190
        fi
191
    done;
192
    mn);
193

    
194
minindex v is ~double[] -> number =
195
   (var mn = 0;
196
    var mi = -1;
197
    for [0..length v - 1] do i:
198
        if i == 0 or v[i] < mn then
199
            mn := v[i];
200
            mi := i;
201
        fi
202
    done;
203
    mi);
204

    
205
mean v is ~double[] -> number =
206
    case length v of
207
        0: 0;
208
        len: sum' v / len
209
    esac;
210

    
211
sorted v is ~double[] -> ~double[] =
212
   (v' = copyOf v;
213
    Arrays#sort(v');
214
    v');
215

    
216
quantile q v is number -> ~double[] -> number =
217
    if empty? v then 0
218
    else
219
        v = sorted v;
220
        dist = q * (length v - 1);
221
        low = floor dist;
222
        high = ceil dist;
223
        if low == high then v[low]
224
        else
225
            v[low] * (high - dist) + v[high] * (dist - low);
226
        fi;
227
    fi;
228

    
229
median v is ~double[] -> number =
230
    quantile 0.5 v;
231

    
232
listOp f vv =
233
    case vv of
234
    [v]: v;
235
    v::rest:
236
       (out = copyOf v;
237
        for rest (f out);
238
        out);
239
    _: failWith "Empty argument list";
240
    esac;
241

    
242
//!!! doc: throws exception if not all inputs are of the same length
243
add vv is list?<~double[]> -> ~double[] =
244
    listOp do out v: VectorBits#addTo(out, v) done vv;
245

    
246
//!!! doc: throws exception if not all inputs are of the same length
247
subtract v1 v2 is ~double[] -> ~double[] -> ~double[] =
248
    listOp do out v: VectorBits#subtractFrom(out, v) done [v1, v2];
249

    
250
//!!! doc: throws exception if not all inputs are of the same length
251
multiply vv is list?<~double[]> -> ~double[] =
252
    listOp do out v: VectorBits#multiplyBy(out, v) done vv;
253

    
254
//!!! doc: throws exception if not all inputs are of the same length
255
divide v1 v2 is ~double[] -> ~double[] -> ~double[] = 
256
    listOp do out v: VectorBits#divideBy(out, v) done [v1, v2];
257

    
258
scaled n v is number -> ~double[] -> ~double[] =
259
    if n == 1 then v
260
    else VectorBits#scaled(v, n);
261
    fi;
262

    
263
divideBy n v is number -> ~double[] -> ~double[] =
264
    // Not just "scaled (1/n)" -- this way we get exact rationals. In fact
265
    // the unit test for this function will fail if we use scaled (1/n)
266
    if n == 1 then v
267
    else fromList (map (/ n) (list v));
268
    fi;
269

    
270
sqr v =
271
   (out = copyOf v;
272
    VectorBits#multiplyBy(out, v);
273
    out);
274

    
275
rms =
276
    sqrt . mean . sqr;
277

    
278
abs' v is ~double[] -> ~double[] =
279
    fromList (map abs (list v));
280

    
281
negative v is ~double[] -> ~double[] =
282
    fromList (map (0-) (list v));
283

    
284
sqrt' v is ~double[] -> ~double[] =
285
    fromList (map sqrt (list v));
286

    
287
unityNormalised v is ~double[] -> ~double[] = 
288
   (m = max' (abs' v);
289
    if m != 0 then
290
        divideBy m v;
291
    else
292
        v;
293
    fi);
294

    
295
euclideanDistance v1 v2 is ~double[] -> ~double[] -> number =
296
    VectorBits#euclideanDistance(v1, v2);
297

    
298
zipped vv is list?<~double[]> -> ~double[] =
299
    case vv of
300
    [v]: v;
301
    first::rest:
302
       (len = length' first;
303
        if len != min' (fromList (map length' vv)) then
304
            failWith "Vectors must all be of the same length";
305
        fi;
306
        fromList
307
           (concat
308
              (map do i:
309
                   map do v:
310
                       at' v i
311
                       done vv
312
                   done [0..len-1])));
313
     _: zeros 0;
314
    esac;
315

    
316
unzipped n v is number -> ~double[] -> array<~double[]> =
317
    if n == 1 then array [v]
318
    else 
319
        len = length' v;
320
        vv = array (map \(new double[ceil(len / n)]) [1..n]);
321
        for [0..len-1] do x:
322
            vv[x % n][int (x / n)] := at' v x;
323
        done;
324
        array vv;
325
    fi;
326

    
327
typedef opaque vector_t = ~double[];
328

    
329
{
330
    zeros,
331
    consts,
332
    ones,
333
    randoms,
334
    vector v = v,
335
    primitive,
336
    floats,
337
    fromFloats,
338
    fromList,
339
    list = list',
340
    array = array',
341
    length = length',
342
    empty? = empty?',
343
    at = at',
344
    equal,
345
    equalUnder,
346
    slice,
347
    resizedTo,
348
    reverse,
349
    sorted,
350
    repeated,
351
    concat = concat',
352
    sum = sum',
353
    mean,
354
    median,
355
    quantile,
356
    add,
357
    subtract,
358
    multiply,
359
    divide,
360
    scaled,
361
    divideBy,
362
    abs = abs',
363
    negative,
364
    sqr,
365
    sqrt = sqrt',
366
    rms,
367
    max = max',
368
    min = min',
369
    maxindex,
370
    minindex,
371
    unityNormalised,
372
    euclideanDistance,
373
    zipped,
374
    unzipped,
375
} as {
376
    zeros is number -> vector_t,
377
    consts is number -> number -> vector_t,
378
    ones is number -> vector_t,
379
    randoms is number -> vector_t,
380
    vector is ~double[] -> vector_t,
381
    primitive is vector_t -> ~double[],
382
    floats is vector_t -> ~float[],
383
    fromFloats is ~float[] -> vector_t,
384
    fromList is list?<number> -> vector_t,
385
    list is vector_t -> list<number>,
386
    array is vector_t -> array<number>,
387
    length is vector_t -> number,
388
    empty? is vector_t -> boolean,
389
    at is vector_t -> number -> number,
390
    equal is vector_t -> vector_t -> boolean,
391
    equalUnder is (number -> number -> boolean) -> vector_t -> vector_t -> boolean,
392
    slice is vector_t -> number -> number -> vector_t,
393
    resizedTo is number -> vector_t -> vector_t,
394
    reverse is vector_t -> vector_t,
395
    sorted is vector_t -> vector_t,
396
    repeated is vector_t -> number -> vector_t,
397
    concat is list?<vector_t> -> vector_t,
398
    sum is vector_t -> number,
399
    mean is vector_t -> number,
400
    median is vector_t -> number,
401
    quantile is number -> vector_t -> number,
402
    add is list?<vector_t> -> vector_t,
403
    subtract is vector_t -> vector_t -> vector_t,
404
    multiply is list?<vector_t> -> vector_t, 
405
    divide is vector_t -> vector_t -> vector_t, 
406
    scaled is number -> vector_t -> vector_t,
407
    divideBy is number -> vector_t -> vector_t, 
408
    abs is vector_t -> vector_t,
409
    negative is vector_t -> vector_t,
410
    sqr is vector_t -> vector_t,
411
    sqrt is vector_t -> vector_t,
412
    rms is vector_t -> number,
413
    max is vector_t -> number,
414
    min is vector_t -> number,
415
    maxindex is vector_t -> number,
416
    minindex is vector_t -> number,
417
    unityNormalised is vector_t -> vector_t,
418
    euclideanDistance is vector_t -> vector_t -> number,
419
    zipped is list?<vector_t> -> vector_t,
420
    unzipped is number -> vector_t -> array<vector_t>,
421
}
422