Chris@19
|
1
|
Chris@19
|
2 module em_onecolumn;
|
Chris@19
|
3
|
Chris@19
|
4 mm = load may.mathmisc;
|
Chris@19
|
5 vec = load may.vector;
|
Chris@19
|
6 mat = load may.matrix;
|
Chris@19
|
7
|
Chris@19
|
8 inRange ranges instrument note =
|
Chris@19
|
9 note >= ranges[instrument].lowest and note <= ranges[instrument].highest;
|
Chris@19
|
10
|
Chris@19
|
11 initialise ranges templates notes =
|
Chris@19
|
12 (instruments = keys ranges;
|
Chris@19
|
13 {
|
Chris@19
|
14 pitches = // z in the original. 1 per note
|
Chris@19
|
15 vec.randoms notes,
|
Chris@19
|
16 sources = // u in the original. 1 per note-instrument
|
Chris@19
|
17 mapIntoHash id
|
Chris@19
|
18 do instrument:
|
Chris@19
|
19 vec.fromList
|
Chris@19
|
20 (map do note:
|
Chris@19
|
21 if inRange ranges instrument note then 1 else 0 fi
|
Chris@19
|
22 done [0..notes-1])
|
Chris@19
|
23 done instruments,
|
Chris@19
|
24 instruments,
|
Chris@19
|
25 templates,
|
Chris@19
|
26 ranges,
|
Chris@19
|
27 lowest = head
|
Chris@19
|
28 (sort (map do i: ranges[i].lowest done instruments)),
|
Chris@19
|
29 highest = head (reverse
|
Chris@19
|
30 (sort (map do i: ranges[i].highest done instruments))),
|
Chris@19
|
31 });
|
Chris@19
|
32
|
Chris@19
|
33 epsilon = 1e-16;
|
Chris@19
|
34
|
Chris@19
|
35 select predicate = concatMap do v: if predicate v then [v] else [] fi done;
|
Chris@19
|
36
|
Chris@19
|
37 distributionsFor data instrument note =
|
Chris@19
|
38 {
|
Chris@19
|
39 w = mat.getColumn note data.templates[instrument],
|
Chris@19
|
40 p = vec.at data.pitches note,
|
Chris@19
|
41 s = vec.at data.sources[instrument] note,
|
Chris@19
|
42 };
|
Chris@19
|
43
|
Chris@19
|
44 performExpectation data column =
|
Chris@19
|
45 (estimate =
|
Chris@19
|
46 fold do acc instrument:
|
Chris@19
|
47 fold do acc note:
|
Chris@19
|
48 { w, p, s } = distributionsFor data instrument note;
|
Chris@19
|
49 vec.add [acc, vec.scaled (p * s) w];
|
Chris@19
|
50 done acc [data.ranges[instrument].lowest ..
|
Chris@19
|
51 data.ranges[instrument].highest]
|
Chris@19
|
52 done (vec.consts epsilon (vec.length column)) data.instruments;
|
Chris@19
|
53 vec.divide column estimate);
|
Chris@19
|
54
|
Chris@19
|
55 performMaximisation data column q =
|
Chris@19
|
56 (pitchTop = vec.fromList
|
Chris@19
|
57 (map do note:
|
Chris@19
|
58 fold do acc instrument:
|
Chris@19
|
59 { w, p, s } = distributionsFor data instrument note;
|
Chris@19
|
60 fold do acc bin:
|
Chris@19
|
61 acc + s * (vec.at w bin) * (vec.at column bin);
|
Chris@19
|
62 done acc [0..vec.length column - 1]
|
Chris@19
|
63 done epsilon data.instruments;
|
Chris@19
|
64 done [data.lowest .. data.highest]);
|
Chris@19
|
65 pitchBottom = vec.sum pitchTop;
|
Chris@19
|
66
|
Chris@19
|
67 /* sourceTop = vec.fromList
|
Chris@19
|
68 (map do instrument:
|
Chris@19
|
69 fold do acc note:
|
Chris@19
|
70 { w, p, s } = distributionsFor data instrument note;
|
Chris@19
|
71 fold do acc bin:
|
Chris@19
|
72 acc + p * (vec.at w bin) * (vec.at column bin);
|
Chris@19
|
73 done acc [0..vec.length column - 1]
|
Chris@19
|
74 done epsilon [data.lowest .. data.highest]
|
Chris@19
|
75 done data.instruments);
|
Chris@19
|
76 sourceBottom = vec.sum sourceTop;
|
Chris@19
|
77 */
|
Chris@19
|
78 data with {
|
Chris@19
|
79 pitches = vec.divideBy pitchBottom pitchTop,
|
Chris@19
|
80 // sources = vec.divideBy sourceBottom sourceTop
|
Chris@19
|
81 });
|
Chris@19
|
82
|
Chris@19
|
83 {
|
Chris@19
|
84 initialise,
|
Chris@19
|
85 performExpectation,
|
Chris@19
|
86 performMaximisation,
|
Chris@19
|
87 }
|
Chris@19
|
88
|
Chris@19
|
89
|