comparison Induction.cpp @ 15:887c629502a9

refactor: pull method implementations into .cpp files
author Chris Cannam
date Wed, 12 Oct 2011 10:55:52 +0100
parents 4f6626f9ffac
children 33d0b18b2509
comparison
equal deleted inserted replaced
14:f1252b6a7cf5 15:887c629502a9
20 double Induction::maxIOI = 2.500; 20 double Induction::maxIOI = 2.500;
21 double Induction::minIBI = 0.3; 21 double Induction::minIBI = 0.3;
22 double Induction::maxIBI = 1.0; 22 double Induction::maxIBI = 1.0;
23 int Induction::topN = 10; 23 int Induction::topN = 10;
24 24
25
26 AgentList Induction::beatInduction(EventList events) {
27 int i, j, b, bestCount;
28 bool submult;
29 int intervals = 0; // number of interval clusters
30 vector<int> bestn;// count of high-scoring clusters
31 bestn.resize(topN);
32
33 double ratio, err;
34 int degree;
35 int maxClusterCount = (int) ceil((maxIOI - minIOI) / clusterWidth);
36 vector<double> clusterMean;
37 clusterMean.resize(maxClusterCount);
38 vector<int> clusterSize;
39 clusterSize.resize(maxClusterCount);
40 vector<int> clusterScore;
41 clusterScore.resize(maxClusterCount);
42
43 EventList::iterator ptr1, ptr2;
44 Event e1, e2;
45 ptr1 = events.begin();
46 while (ptr1 != events.end()) {
47 e1 = *ptr1;
48 ++ptr1;
49 ptr2 = events.begin();
50 e2 = *ptr2;
51 ++ptr2;
52 while (e2 != e1 && ptr2 != events.end()) {
53 e2 = *ptr2;
54 ++ptr2;
55 }
56 while (ptr2 != events.end()) {
57 e2 = *ptr2;
58 ++ptr2;
59 double ioi = e2.time - e1.time;
60 if (ioi < minIOI) // skip short intervals
61 continue;
62 if (ioi > maxIOI) // ioi too long
63 break;
64 for (b = 0; b < intervals; b++) // assign to nearest cluster
65 if (fabs(clusterMean[b] - ioi) < clusterWidth) {
66 if ((b < intervals - 1) && (
67 fabs(clusterMean[b+1] - ioi) <
68 fabs(clusterMean[b] - ioi)))
69 b++; // next cluster is closer
70 clusterMean[b] = (clusterMean[b] * clusterSize[b] +ioi)/
71 (clusterSize[b] + 1);
72 clusterSize[b]++;
73 break;
74 }
75 if (b == intervals) { // no suitable cluster; create new one
76 if (intervals == maxClusterCount) {
77 // System.err.println("Warning: Too many clusters");
78 continue; // ignore this IOI
79 }
80 intervals++;
81 for ( ; (b>0) && (clusterMean[b-1] > ioi); b--) {
82 clusterMean[b] = clusterMean[b-1];
83 clusterSize[b] = clusterSize[b-1];
84 }
85 clusterMean[b] = ioi;
86 clusterSize[b] = 1;
87 }
88 }
89 }
90 for (b = 0; b < intervals; b++) // merge similar intervals
91 // TODO: they are now in order, so don't need the 2nd loop
92 // TODO: check BOTH sides before averaging or upper gps don't work
93 for (i = b+1; i < intervals; i++)
94 if (fabs(clusterMean[b] - clusterMean[i]) < clusterWidth) {
95 clusterMean[b] = (clusterMean[b] * clusterSize[b] +
96 clusterMean[i] * clusterSize[i]) /
97 (clusterSize[b] + clusterSize[i]);
98 clusterSize[b] = clusterSize[b] + clusterSize[i];
99 --intervals;
100 for (j = i+1; j <= intervals; j++) {
101 clusterMean[j-1] = clusterMean[j];
102 clusterSize[j-1] = clusterSize[j];
103 }
104 }
105 if (intervals == 0)
106 return AgentList();
107 for (b = 0; b < intervals; b++)
108 clusterScore[b] = 10 * clusterSize[b];
109 bestn[0] = 0;
110 bestCount = 1;
111 for (b = 0; b < intervals; b++)
112 for (i = 0; i <= bestCount; i++)
113 if ((i < topN) && ((i == bestCount) ||
114 (clusterScore[b] > clusterScore[bestn[i]]))){
115 if (bestCount < topN)
116 bestCount++;
117 for (j = bestCount - 1; j > i; j--)
118 bestn[j] = bestn[j-1];
119 bestn[i] = b;
120 break;
121 }
122 for (b = 0; b < intervals; b++) // score intervals
123 for (i = b+1; i < intervals; i++) {
124 ratio = clusterMean[b] / clusterMean[i];
125 submult = ratio < 1;
126 if (submult)
127 degree = (int) nearbyint(1/ratio);
128 else
129 degree = (int) nearbyint(ratio);
130 if ((degree >= 2) && (degree <= 8)) {
131 if (submult)
132 err = fabs(clusterMean[b]*degree - clusterMean[i]);
133 else
134 err = fabs(clusterMean[b] - clusterMean[i]*degree);
135 if (err < (submult? clusterWidth : clusterWidth * degree)) {
136 if (degree >= 5)
137 degree = 1;
138 else
139 degree = 6 - degree;
140 clusterScore[b] += degree * clusterSize[i];
141 clusterScore[i] += degree * clusterSize[b];
142 }
143 }
144 }
145
146 AgentList a;
147 for (int index = 0; index < bestCount; index++) {
148 b = bestn[index];
149 // Adjust it, using the size of super- and sub-intervals
150 double newSum = clusterMean[b] * clusterScore[b];
151 int newCount = clusterSize[b];
152 int newWeight = clusterScore[b];
153 for (i = 0; i < intervals; i++) {
154 if (i == b)
155 continue;
156 ratio = clusterMean[b] / clusterMean[i];
157 if (ratio < 1) {
158 degree = (int) nearbyint(1 / ratio);
159 if ((degree >= 2) && (degree <= 8)) {
160 err = fabs(clusterMean[b]*degree - clusterMean[i]);
161 if (err < clusterWidth) {
162 newSum += clusterMean[i] / degree * clusterScore[i];
163 newCount += clusterSize[i];
164 newWeight += clusterScore[i];
165 }
166 }
167 } else {
168 degree = (int) nearbyint(ratio);
169 if ((degree >= 2) && (degree <= 8)) {
170 err = fabs(clusterMean[b] - degree*clusterMean[i]);
171 if (err < clusterWidth * degree) {
172 newSum += clusterMean[i] * degree * clusterScore[i];
173 newCount += clusterSize[i];
174 newWeight += clusterScore[i];
175 }
176 }
177 }
178 }
179 double beat = newSum / newWeight;
180 // Scale within range ... hope the grouping isn't ternary :(
181 while (beat < minIBI) // Maximum speed
182 beat *= 2.0;
183 while (beat > maxIBI) // Minimum speed
184 beat /= 2.0;
185 if (beat >= minIBI) {
186 a.push_back(Agent(beat));
187 }
188 }
189 #ifdef DEBUG_BEATROOT
190 std::cerr << "Induction complete, returning " << a.size() << " agent(s)" << std::endl;
191 #endif
192 return a;
193 } // beatInduction()
194