float EditableDenseThreeDimensionalModel::getValueAt(size_t index, size_t n) const { Column c = getColumn(index); if (n < c.size()) return c.at(n); return m_minimum; }
EditableDenseThreeDimensionalModel::Column EditableDenseThreeDimensionalModel::expandAndRetrieve(size_t index) const { // See comment above m_trunc declaration in header assert(index < m_data.size()); Column c = m_data.at(index); if (index == 0) { return c; } int trunc = (int)m_trunc[index]; if (trunc == 0) { return c; } bool top = true; int tdist = trunc; if (trunc < 0) { top = false; tdist = -trunc; } Column p = expandAndRetrieve(index - tdist); int psize = p.size(), csize = c.size(); if (psize != m_yBinCount) { std::cerr << "WARNING: EditableDenseThreeDimensionalModel::expandAndRetrieve: Trying to expand from incorrectly sized column" << std::endl; } if (top) { for (int i = csize; i < psize; ++i) { c.push_back(p.at(i)); } } else { // push_front is very slow on QVector -- but not enough to // make it desirable to choose a different container, since // QVector has all the other advantages for us. easier to // write the whole array out to a new vector Column cc(psize); for (int i = 0; i < psize - csize; ++i) { cc[i] = p.at(i); } for (int i = 0; i < csize; ++i) { cc[i + (psize - csize)] = c.at(i); } return cc; } return c; }
void EditableDenseThreeDimensionalModel::truncateAndStore(size_t index, const Column &values) { assert(index < m_data.size()); //std::cout << "truncateAndStore(" << index << ", " << values.size() << ")" << std::endl; // The default case is to store the entire column at m_data[index] // and place 0 at m_trunc[index] to indicate that it has not been // truncated. We only do clever stuff if one of the clever-stuff // tests works out. m_trunc[index] = 0; if (index == 0 || m_compression == NoCompression || values.size() != m_yBinCount) { // given += values.size(); // stored += values.size(); m_data[index] = values; return; } // Maximum distance between a column and the one we refer to as // the source of its truncated values. Limited by having to fit // in a signed char, but in any case small values are usually // better static int maxdist = 6; bool known = false; // do we know whether to truncate at top or bottom? bool top = false; // if we do know, will we truncate at top? // If the previous column is not truncated, then it is the only // candidate for comparison. If it is truncated, then the column // that it refers to is the only candidate. Either way, we only // have one possible column to compare against here, and we are // being careful to ensure it is not a truncated one (to avoid // doing more work recursively when uncompressing). int tdist = 1; int ptrunc = m_trunc[index-1]; if (ptrunc < 0) { top = false; known = true; tdist = -ptrunc + 1; } else if (ptrunc > 0) { top = true; known = true; tdist = ptrunc + 1; } Column p = expandAndRetrieve(index - tdist); int h = m_yBinCount; if (p.size() == h && tdist <= maxdist) { int bcount = 0, tcount = 0; if (!known || !top) { // count how many identical values there are at the bottom for (int i = 0; i < h; ++i) { if (values.at(i) == p.at(i)) ++bcount; else break; } } if (!known || top) { // count how many identical values there are at the top for (int i = h; i > 0; --i) { if (values.at(i-1) == p.at(i-1)) ++tcount; else break; } } if (!known) top = (tcount > bcount); int limit = h / 4; // don't bother unless we have at least this many if ((top ? tcount : bcount) > limit) { if (!top) { // create a new column with h - bcount values from bcount up Column tcol(h - bcount); // given += values.size(); // stored += h - bcount; for (int i = bcount; i < h; ++i) { tcol[i - bcount] = values.at(i); } m_data[index] = tcol; m_trunc[index] = -tdist; return; } else { // create a new column with h - tcount values from 0 up Column tcol(h - tcount); // given += values.size(); // stored += h - tcount; for (int i = 0; i < h - tcount; ++i) { tcol[i] = values.at(i); } m_data[index] = tcol; m_trunc[index] = tdist; return; } } } // given += values.size(); // stored += values.size(); // std::cout << "given: " << given << ", stored: " << stored << " (" // << ((float(stored) / float(given)) * 100.f) << "%)" << std::endl; // default case if nothing wacky worked out m_data[index] = values; return; }