diff options
Diffstat (limited to 'projectionhistory.cpp')
-rw-r--r-- | projectionhistory.cpp | 191 |
1 files changed, 186 insertions, 5 deletions
diff --git a/projectionhistory.cpp b/projectionhistory.cpp index bd55431..f450e0e 100644 --- a/projectionhistory.cpp +++ b/projectionhistory.cpp @@ -1,19 +1,66 @@ #include "projectionhistory.h" -ProjectionHistory::ProjectionHistory(QObject *parent) - : QObject(parent) +#include <algorithm> +#include <cmath> + +#include "mp.h" +#include "numericrange.h" + +ProjectionHistory::ProjectionHistory(const arma::mat &X, + const arma::uvec &cpIndices) + : m_type(ObserverCurrent) + , m_X(X) + , m_cpIndices(cpIndices) + , m_rpIndices(X.n_rows - cpIndices.n_elem) + , m_cpSelectionEmpty(true) + , m_rpSelectionEmpty(true) + , m_values(X.n_rows) + , m_prevValues(X.n_rows) + , m_firstValues(X.n_rows) , m_hasFirst(false) , m_hasPrev(false) { + m_distX = mp::dist(m_X); + + NumericRange<arma::uword> allIndices(0, m_X.n_rows); + std::set_symmetric_difference(allIndices.cbegin(), allIndices.cend(), + m_cpIndices.cbegin(), m_cpIndices.cend(), m_rpIndices.begin()); + + computeAlphas(); } +void ProjectionHistory::computeAlphas() +{ + m_influences.set_size(m_X.n_rows); + m_alphas.set_size(m_rpIndices.n_elem, m_cpIndices.n_elem); + + for (arma::uword i = 0; i < m_rpIndices.n_elem; i++) { + double sum = 0; + const arma::rowvec &x = m_X.row(m_rpIndices[i]); + for (arma::uword j = 0; j < m_cpIndices.n_elem; j++) { + double norm = arma::norm(x - m_X.row(m_cpIndices[j])); + m_alphas(i, j) = 1.0 / std::max(norm * norm, 1e-6); + sum += m_alphas(i, j); + } + + for (arma::uword j = 0; j < m_cpIndices.n_elem; j++) { + m_alphas(i, j) /= sum; + } + } +} void ProjectionHistory::undo() { if (m_hasPrev) { m_hasPrev = false; m_Y = m_prevY; + m_distY = m_prevDistY; + m_values = m_prevValues; - emit undoPerformed(m_Y); + emit undoPerformed(); + emit currentMapChanged(m_Y); + if (m_cpSelectionEmpty && m_rpSelectionEmpty) { + emitValuesChanged(); + } } } @@ -22,8 +69,14 @@ void ProjectionHistory::reset() if (m_hasFirst) { m_hasPrev = false; m_Y = m_firstY; + m_distY = m_firstDistY; + m_values = m_firstValues; - emit resetPerformed(m_Y); + emit resetPerformed(); + emit currentMapChanged(m_Y); + if (m_cpSelectionEmpty && m_rpSelectionEmpty) { + emitValuesChanged(); + } } } @@ -32,14 +85,142 @@ void ProjectionHistory::addMap(const arma::mat &Y) if (m_hasFirst) { m_hasPrev = true; m_prevY = m_Y; + m_prevDistY = m_distY; + m_prevValues = m_values; } m_Y = Y; + m_distY = mp::dist(Y); + + mp::aggregatedError(m_distX, m_distY, m_values); if (!m_hasFirst) { m_hasFirst = true; m_firstY = m_Y; + m_firstDistY = m_distY; + m_firstValues = m_values; + } + + emit currentMapChanged(m_Y); + if (m_cpSelectionEmpty && m_rpSelectionEmpty) { + emitValuesChanged(); + } +} + +bool ProjectionHistory::setType(ObserverType type) +{ + if (m_type == type) { + return true; + } + + if ((type == ObserverDiffPrevious && !m_hasPrev) + || (type == ObserverDiffFirst && !m_hasFirst)) { + return false; + } + + m_type = type; + if (!m_cpSelectionEmpty || !m_rpSelectionEmpty) { + // We changed our type, but cannot emit values since we have non-empty + // selections + return true; + } + return emitValuesChanged(); +} + +void ProjectionHistory::setCPSelection(const std::vector<bool> &cpSelection) +{ + m_cpSelection.clear(); + for (int i = 0; i < cpSelection.size(); i++) { + if (cpSelection[i]) { + m_cpSelection.push_back(i); + } + } + m_cpSelectionEmpty = m_cpSelection.empty(); + + if (!m_cpSelectionEmpty) { + // compute the influence of CP selection on each RP + for (arma::uword rp = 0; rp < m_rpIndices.n_elem; rp++) { + m_influences[m_rpIndices[rp]] = 0; + const arma::rowvec &row = m_alphas.row(rp); + for (auto cp: m_cpSelection) { + m_influences[m_rpIndices[rp]] += row[cp]; + } + } + + emit rpValuesChanged(m_influences(m_rpIndices)); + } else { + emitValuesChanged(); + } +} + +void ProjectionHistory::setRPSelection(const std::vector<bool> &rpSelection) +{ + m_rpSelection.clear(); + for (int i = 0; i < rpSelection.size(); i++) { + if (rpSelection[i]) { + m_rpSelection.push_back(i); + } + } + m_rpSelectionEmpty = m_rpSelection.empty(); + + if (!m_rpSelectionEmpty) { + // compute how influent is each CP on RP selection + for (arma::uword cp = 0; cp < m_cpIndices.n_elem; cp++) { + m_influences[m_cpIndices[cp]] = 0; + for (auto rp: m_rpSelection) { + m_influences[m_cpIndices[cp]] += m_alphas(rp, cp); + } + } + + emit cpValuesChanged(m_influences(m_cpIndices)); + } else { + emit cpValuesChanged(arma::vec()); + } +} + +bool ProjectionHistory::emitValuesChanged() const +{ + switch (m_type) { + case ObserverCurrent: + emit rpValuesChanged(m_values(m_rpIndices)); + emit valuesChanged(m_values); + return true; + case ObserverDiffPrevious: + if (m_hasPrev) { + arma::vec diff = m_values - m_prevValues; + emit rpValuesChanged(diff(m_rpIndices)); + emit valuesChanged(diff); + return true; + } + return false; + case ObserverDiffFirst: + if (m_hasFirst) { + arma::vec diff = m_values - m_firstValues; + emit rpValuesChanged(diff(m_rpIndices)); + emit valuesChanged(diff); + return true; + } + return false; + default: + return false; + } +} + +void ProjectionHistory::setRewind(double t) +{ + if (!m_hasPrev) { + return; + } + + arma::mat Y = m_Y * t + m_prevY * (1.0 - t); + emit mapRewound(Y); + + if (!m_cpSelectionEmpty || !m_rpSelectionEmpty) { + return; } - emit mapAdded(m_Y); + arma::vec values = m_values * t + m_prevValues * (1.0 - t); + emit cpValuesRewound(values(m_cpIndices)); + emit rpValuesRewound(values(m_rpIndices)); + emit valuesRewound(values); } |