comparison data/model/EditableDenseThreeDimensionalModel.cpp @ 534:6038cb6fcd30

* Some simple compression for dense 3d models that actually represent multirate data such as wavelet transform outputs. If a column has many elements at top or bottom that are the same as those of an earlier column, store a reference to that one and truncate the duplicate values.
author Chris Cannam
date Fri, 23 Jan 2009 13:31:51 +0000
parents 55ad231c9db7
children 3ccf48fb81d6
comparison
equal deleted inserted replaced
533:55ad231c9db7 534:6038cb6fcd30
21 #include <QStringList> 21 #include <QStringList>
22 22
23 #include <iostream> 23 #include <iostream>
24 24
25 #include <cmath> 25 #include <cmath>
26 #include <cassert>
26 27
27 EditableDenseThreeDimensionalModel::EditableDenseThreeDimensionalModel(size_t sampleRate, 28 EditableDenseThreeDimensionalModel::EditableDenseThreeDimensionalModel(size_t sampleRate,
28 size_t resolution, 29 size_t resolution,
29 size_t yBinCount, 30 size_t yBinCount,
30 bool notifyOnAdd) : 31 bool notifyOnAdd) :
66 } 67 }
67 68
68 Model * 69 Model *
69 EditableDenseThreeDimensionalModel::clone() const 70 EditableDenseThreeDimensionalModel::clone() const
70 { 71 {
72 QMutexLocker locker(&m_mutex);
73
71 EditableDenseThreeDimensionalModel *model = 74 EditableDenseThreeDimensionalModel *model =
72 new EditableDenseThreeDimensionalModel 75 new EditableDenseThreeDimensionalModel
73 (m_sampleRate, m_resolution, m_yBinCount); 76 (m_sampleRate, m_resolution, m_yBinCount);
74 77
75 model->m_minimum = m_minimum; 78 model->m_minimum = m_minimum;
139 142
140 EditableDenseThreeDimensionalModel::Column 143 EditableDenseThreeDimensionalModel::Column
141 EditableDenseThreeDimensionalModel::getColumn(size_t index) const 144 EditableDenseThreeDimensionalModel::getColumn(size_t index) const
142 { 145 {
143 QMutexLocker locker(&m_mutex); 146 QMutexLocker locker(&m_mutex);
144 147 if (index >= m_data.size()) return Column();
145 Column result; 148 return expandAndRetrieve(index);
146
147 if (index < m_data.size()) {
148 result = m_data.at(index);
149 } else {
150 result.clear();
151 }
152
153 while (result.size() < m_yBinCount) result.push_back(m_minimum);
154 return result;
155 } 149 }
156 150
157 float 151 float
158 EditableDenseThreeDimensionalModel::getValueAt(size_t index, size_t n) const 152 EditableDenseThreeDimensionalModel::getValueAt(size_t index, size_t n) const
159 { 153 {
160 QMutexLocker locker(&m_mutex); 154 Column c = getColumn(index);
161 155 if (n < c.size()) return s.at(n);
162 if (index < m_data.size()) {
163 const Column &s = m_data.at(index);
164 // std::cerr << "index " << index << ", n " << n << ", res " << m_resolution << ", size " << s.size()
165 // << std::endl;
166 if (n < s.size()) return s.at(n);
167 }
168
169 return m_minimum; 156 return m_minimum;
157 }
158
159 static int given = 0, stored = 0;
160
161 void
162 EditableDenseThreeDimensionalModel::truncateAndStore(size_t index,
163 const Column &values)
164 {
165 assert(index < m_data.size());
166
167 //std::cout << "truncateAndStore(" << index << ", " << values.size() << ")" << std::endl;
168
169 m_trunc[index] = 0;
170 if (index == 0 || values.size() != m_yBinCount) {
171 given += values.size();
172 stored += values.size();
173 m_data[index] = values;
174 return;
175 }
176
177 static int maxdist = 120;
178
179 bool known = false;
180 bool top = false;
181
182 int tdist = 1;
183 int ptrunc = m_trunc[index-1];
184 if (ptrunc < 0) {
185 top = false;
186 known = true;
187 tdist = -ptrunc + 1;
188 } else if (ptrunc > 0) {
189 top = true;
190 known = true;
191 tdist = ptrunc + 1;
192 }
193
194 Column p = expandAndRetrieve(index - tdist);
195 int h = m_yBinCount;
196
197 if (p.size() == h && tdist <= maxdist) {
198
199 int bcount = 0, tcount = 0;
200 if (!known || !top) {
201 for (int i = 0; i < h; ++i) {
202 if (values.at(i) == p.at(i)) ++bcount;
203 else break;
204 }
205 }
206 if (!known || top) {
207 for (int i = h; i > 0; --i) {
208 if (values.at(i-1) == p.at(i-1)) ++tcount;
209 else break;
210 }
211 }
212 if (!known) top = (tcount > bcount);
213
214 int limit = h / 4;
215 if ((top ? tcount : bcount) > limit) {
216
217 if (!top) {
218 Column tcol(h - bcount);
219 given += values.size();
220 stored += h - bcount;
221 for (int i = bcount; i < h; ++i) {
222 tcol[i - bcount] = values.at(i);
223 }
224 m_data[index] = tcol;
225 m_trunc[index] = -tdist;
226 //std::cout << "bottom " << bcount << " as col at " << -tdist << std::endl;
227 return;
228 } else {
229 Column tcol(h - tcount);
230 given += values.size();
231 stored += h - tcount;
232 for (int i = 0; i < h - tcount; ++i) {
233 tcol[i] = values.at(i);
234 }
235 m_data[index] = tcol;
236 m_trunc[index] = tdist;
237 //std::cout << "top " << tcount << " as col at " << -tdist << std::endl;
238 return;
239 }
240 }
241 }
242
243 given += values.size();
244 stored += values.size();
245
246 // std::cout << "given: " << given << ", stored: " << stored << " ("
247 // << ((float(stored) / float(given)) * 100.f) << "%)" << std::endl;
248
249 m_data[index] = values;
250 return;
251 }
252
253 EditableDenseThreeDimensionalModel::Column
254 EditableDenseThreeDimensionalModel::expandAndRetrieve(size_t index) const
255 {
256 assert(index < m_data.size());
257 Column c = m_data.at(index);
258 if (index == 0) {
259 return c;
260 }
261 int trunc = (int)m_trunc[index];
262 if (trunc == 0) {
263 return c;
264 }
265 bool top = true;
266 int tdist = trunc;
267 if (trunc < 0) { top = false; tdist = -trunc; }
268 Column p = expandAndRetrieve(index - tdist);
269 if (p.size() != m_yBinCount) {
270 std::cerr << "WARNING: EditableDenseThreeDimensionalModel::expandAndRetrieve: Trying to expand from incorrectly sized column" << std::endl;
271 }
272 if (top) {
273 for (int i = c.size(); i < p.size(); ++i) {
274 c.push_back(p.at(i));
275 }
276 } else {
277 for (int i = int(p.size()) - int(c.size()); i >= 0; --i) {
278 c.push_front(p.at(i));
279 }
280 }
281 return c;
170 } 282 }
171 283
172 void 284 void
173 EditableDenseThreeDimensionalModel::setColumn(size_t index, 285 EditableDenseThreeDimensionalModel::setColumn(size_t index,
174 const Column &values) 286 const Column &values)
175 { 287 {
176 QMutexLocker locker(&m_mutex); 288 QMutexLocker locker(&m_mutex);
177 289
178 while (index >= m_data.size()) { 290 while (index >= m_data.size()) {
179 m_data.push_back(Column()); 291 m_data.push_back(Column());
292 m_trunc.push_back(0);
180 } 293 }
181 294
182 bool allChange = false; 295 bool allChange = false;
183 296
184 if (values.size() > m_yBinCount) m_yBinCount = values.size(); 297 // if (values.size() > m_yBinCount) m_yBinCount = values.size();
185 298
186 for (size_t i = 0; i < values.size(); ++i) { 299 for (size_t i = 0; i < values.size(); ++i) {
187 float value = values[i]; 300 float value = values[i];
188 if (std::isnan(value) || std::isinf(value)) { 301 if (std::isnan(value) || std::isinf(value)) {
189 continue; 302 continue;
197 allChange = true; 310 allChange = true;
198 } 311 }
199 m_haveExtents = true; 312 m_haveExtents = true;
200 } 313 }
201 314
202 m_data[index] = values; 315 truncateAndStore(index, values);
316
317 assert(values == expandAndRetrieve(index));
203 318
204 long windowStart = index; 319 long windowStart = index;
205 windowStart *= m_resolution; 320 windowStart *= m_resolution;
206 321
207 if (m_notifyOnAdd) { 322 if (m_notifyOnAdd) {
251 } 366 }
252 367
253 bool 368 bool
254 EditableDenseThreeDimensionalModel::shouldUseLogValueScale() const 369 EditableDenseThreeDimensionalModel::shouldUseLogValueScale() const
255 { 370 {
371 QMutexLocker locker(&m_mutex);
372
256 QVector<float> sample; 373 QVector<float> sample;
257 QVector<int> n; 374 QVector<int> n;
258 375
259 for (int i = 0; i < 10; ++i) { 376 for (int i = 0; i < 10; ++i) {
260 size_t index = i * 10; 377 size_t index = i * 10;
308 } 425 }
309 426
310 QString 427 QString
311 EditableDenseThreeDimensionalModel::toDelimitedDataString(QString delimiter) const 428 EditableDenseThreeDimensionalModel::toDelimitedDataString(QString delimiter) const
312 { 429 {
430 QMutexLocker locker(&m_mutex);
313 QString s; 431 QString s;
314 for (size_t i = 0; i < m_data.size(); ++i) { 432 for (size_t i = 0; i < m_data.size(); ++i) {
315 QStringList list; 433 QStringList list;
316 for (size_t j = 0; j < m_data.at(i).size(); ++j) { 434 for (size_t j = 0; j < m_data.at(i).size(); ++j) {
317 list << QString("%1").arg(m_data.at(i).at(j)); 435 list << QString("%1").arg(m_data.at(i).at(j));
324 void 442 void
325 EditableDenseThreeDimensionalModel::toXml(QTextStream &out, 443 EditableDenseThreeDimensionalModel::toXml(QTextStream &out,
326 QString indent, 444 QString indent,
327 QString extraAttributes) const 445 QString extraAttributes) const
328 { 446 {
447 QMutexLocker locker(&m_mutex);
448
329 // For historical reasons we read and write "resolution" as "windowSize" 449 // For historical reasons we read and write "resolution" as "windowSize"
330 450
331 std::cerr << "EditableDenseThreeDimensionalModel::toXml" << std::endl; 451 std::cerr << "EditableDenseThreeDimensionalModel::toXml" << std::endl;
332 452
333 Model::toXml 453 Model::toXml