aboutsummaryrefslogtreecommitdiff
path: root/projectionhistory.cpp
diff options
context:
space:
mode:
authorSamuel Fadel <samuelfadel@gmail.com>2016-02-12 19:03:51 -0200
committerSamuel Fadel <samuelfadel@gmail.com>2016-02-12 19:03:51 -0200
commit5bd1fec462466d605f974fa27c3b00826a1bab57 (patch)
tree6cfefd8bd5c81644755c3be197f7ab2d60cd268b /projectionhistory.cpp
parent95a77b04a6855b26d340aaca5e3030a7d1a7cb3c (diff)
Refactoring of Projection{Observer,History} & ManipulationHandler.
ProjectionObserver class has been removed, all of its functionality is now inside class ProjectionHistory, thus dealing with the design problem mentioned in the previous commit. ProjectionHistory is now also responsible for all rewinding functionality, which makes more sense.
Diffstat (limited to 'projectionhistory.cpp')
-rw-r--r--projectionhistory.cpp191
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);
}