[Regression] Add affine regression

This commit is contained in:
Joachim LF
2020-04-29 07:29:38 +02:00
committed by LeaNumworks
parent c955f45457
commit 833f6ec778
15 changed files with 103 additions and 17 deletions

View File

@@ -8,6 +8,7 @@ app_regression_test_src += $(addprefix apps/regression/,\
)
app_regression_test_src += $(addprefix apps/regression/model/,\
affine_model.cpp \
cubic_model.cpp \
exponential_model.cpp \
linear_model.cpp \

View File

@@ -10,6 +10,7 @@ ValueNotReachedByRegression = "Wert in diesem Fenster nicht erreicht"
NumberOfDots = "Punktanzahl"
Covariance = "Kovarianz"
Linear = "Lineare"
Affine = "Affine"
Quadratic = "Quadratische"
Cubic = "Kubische"
Quartic = "Biquadratische"

View File

@@ -10,6 +10,7 @@ ValueNotReachedByRegression = "Value not reached in this window"
NumberOfDots = "Number of points"
Covariance = "Covariance"
Linear = "Linear"
Affine = "Affine"
Quadratic = "Quadratic"
Cubic = "Cubic"
Quartic = "Quartic"

View File

@@ -10,6 +10,7 @@ ValueNotReachedByRegression = "Valor no alcanzado en esta ventana"
NumberOfDots = "Número de puntos"
Covariance = "Covarianza"
Linear = "Lineal"
Affine = "Affine"
Quadratic = "Cuadrática"
Cubic = "Cúbica"
Quartic = "Cuártica"

View File

@@ -10,6 +10,7 @@ ValueNotReachedByRegression = "Valeur non atteinte dans cette fenêtre"
NumberOfDots = "Nombre de points"
Covariance = "Covariance"
Linear = "Linéaire"
Affine = "Affine"
Quadratic = "Quadratique"
Cubic = "Cubique"
Quartic = "Quartique"

View File

@@ -10,6 +10,7 @@ ValueNotReachedByRegression = "Valor não alcançado nesta janela"
NumberOfDots = "Número de pontos"
Covariance = "Covariancia"
Linear = "Linear"
Affine = "Affine"
Quadratic = "Quadrática"
Cubic = "Cúbica"
Quartic = "Quarto grau"

View File

@@ -1,3 +1,4 @@
AffineRegressionFormula = " y=a·x "
QuadraticRegressionFormula = " y=a·x^2+b·x+c "
CubicRegressionFormula = " y=a·x^3+b·x^2+c·x+d "
QuarticRegressionFormula = " y=a·x^4+b·x^3+c·x^2+d·x+e "

View File

@@ -187,14 +187,15 @@ void GraphController::reloadBannerView() {
coefficientName++;
}
if (m_store->seriesRegressionType(*m_selectedSeriesIndex) == Model::Type::Linear) {
if (m_store->seriesRegressionType(*m_selectedSeriesIndex) == Model::Type::Linear || m_store->seriesRegressionType(*m_selectedSeriesIndex) == Model::Type::Affine) {
int index = model->numberOfCoefficients();
// Set "r=..."
numberOfChar = 0;
legend = " r=";
double r = m_store->correlationCoefficient(*m_selectedSeriesIndex);
numberOfChar += strlcpy(buffer, legend, bufferSize);
numberOfChar += PoincareHelpers::ConvertFloatToText<double>(r, buffer + numberOfChar, bufferSize - numberOfChar, Preferences::LargeNumberOfSignificantDigits);
m_bannerView.subTextAtIndex(2)->setText(buffer);
m_bannerView.subTextAtIndex(0+index)->setText(buffer);
// Set "r2=..."
numberOfChar = 0;
@@ -202,11 +203,11 @@ void GraphController::reloadBannerView() {
double r2 = m_store->squaredCorrelationCoefficient(*m_selectedSeriesIndex);
numberOfChar += strlcpy(buffer, legend, bufferSize);
numberOfChar += PoincareHelpers::ConvertFloatToText<double>(r2, buffer + numberOfChar, bufferSize - numberOfChar, Preferences::LargeNumberOfSignificantDigits);
m_bannerView.subTextAtIndex(3)->setText(buffer);
m_bannerView.subTextAtIndex(1+index)->setText(buffer);
// Clean the last subview
buffer[0] = 0;
m_bannerView.subTextAtIndex(4)->setText(buffer);
m_bannerView.subTextAtIndex(2+index)->setText(buffer);
} else {
// Empty all non used subviews

View File

@@ -0,0 +1,51 @@
#include "affine_model.h"
#include "../store.h"
#include <poincare/layout_helper.h>
#include <math.h>
#include <assert.h>
using namespace Poincare;
namespace Regression {
Layout AffineModel::layout() {
if (m_layout.isUninitialized()) {
const char * s = "a·X";
m_layout = LayoutHelper::String(s, strlen(s), k_layoutFont);
}
return m_layout;
}
double AffineModel::evaluate(double * modelCoefficients, double x) const {
double a = modelCoefficients[0];
return a*x;
}
double AffineModel::levelSet(double * modelCoefficients, double xMin, double step, double xMax, double y, Poincare::Context * context) {
double a = modelCoefficients[0];
double b = modelCoefficients[1];
if (a == 0) {
return NAN;
}
return y-b;
}
void AffineModel::fit(Store * store, int series, double * modelCoefficients, Poincare::Context * context) {
modelCoefficients[0] = store->slope(series);
modelCoefficients[1] = store->yIntercept(series);
}
double AffineModel::partialDerivate(double * modelCoefficients, int derivateCoefficientIndex, double x) const {
if (derivateCoefficientIndex == 0) {
// Derivate: x
return x;
}
if (derivateCoefficientIndex == 1) {
// Derivate: 1;
return 1;
}
assert(false);
return 0.0;
}
}

View File

@@ -0,0 +1,24 @@
#ifndef REGRESSION_AFFINE_MODEL_H
#define REGRESSION_AFFINE_MODEL_H
#include "model.h"
namespace Regression {
class AffineModel : public Model {
public:
using Model::Model;
Poincare::Layout layout() override;
I18n::Message formulaMessage() const override { return I18n::Message::AffineRegressionFormula; }
double evaluate(double * modelCoefficients, double x) const override;
double levelSet(double * modelCoefficients, double xMin, double step, double xMax, double y, Poincare::Context * context) override;
void fit(Store * store, int series, double * modelCoefficients, Poincare::Context * context) override;
double partialDerivate(double * modelCoefficients, int derivateCoefficientIndex, double x) const override;
int numberOfCoefficients() const override { return 1; }
int bannerLinesCount() const override { return 2; }
};
}
#endif

View File

@@ -15,16 +15,17 @@ class Model {
public:
enum class Type : uint8_t {
Linear = 0,
Quadratic = 1,
Cubic = 2,
Quartic = 3,
Logarithmic = 4,
Exponential = 5,
Power = 6,
Trigonometric = 7,
Logistic = 8
Affine = 1,
Quadratic = 2,
Cubic = 3,
Quartic = 4,
Logarithmic = 5,
Exponential = 6,
Power = 7,
Trigonometric = 8,
Logistic = 9
};
static constexpr int k_numberOfModels = 9;
static constexpr int k_numberOfModels = 10;
static constexpr int k_maxNumberOfCoefficients = 5; // This has to verify: k_maxNumberOfCoefficients < Matrix::k_maxNumberOfCoefficients
virtual ~Model() = default;
virtual Poincare::Layout layout() = 0;

View File

@@ -82,7 +82,7 @@ HighlightCell * RegressionController::reusableCell(int index, int type) {
void RegressionController::willDisplayCellAtLocation(HighlightCell * cell, int i, int j) {
assert(i == 0);
assert(j >= 0 && j < k_numberOfRows);
I18n::Message messages[k_numberOfRows] = {I18n::Message::Linear, I18n::Message::Quadratic, I18n::Message::Cubic, I18n::Message::Quartic, I18n::Message::Logarithmic, I18n::Message::Exponential, I18n::Message::Power, I18n::Message::Trigonometrical, I18n::Message::Logistic};
I18n::Message messages[k_numberOfRows] = {I18n::Message::Linear, I18n::Message::Affine, I18n::Message::Quadratic, I18n::Message::Cubic, I18n::Message::Quartic, I18n::Message::Logarithmic, I18n::Message::Exponential, I18n::Message::Power, I18n::Message::Trigonometrical, I18n::Message::Logistic};
MessageTableCellWithExpression * castedCell = static_cast<MessageTableCellWithExpression *>(cell);
castedCell->setMessage(messages[j]);
castedCell->setLayout(m_store->regressionModel((Model::Type) j)->layout());

View File

@@ -31,7 +31,7 @@ public:
int numberOfRows() const override { return k_numberOfRows; }
void willDisplayCellAtLocation(HighlightCell * cell, int i, int j) override;
private:
constexpr static int k_numberOfRows = 9;
constexpr static int k_numberOfRows = 10;
constexpr static int k_numberOfCells = 6; // (240 - 70) / 35
MessageTableCellWithExpression m_regressionCells[k_numberOfCells];
SelectableTableView m_selectableTableView;

View File

@@ -11,7 +11,7 @@ using namespace Shared;
namespace Regression {
static_assert(Model::k_numberOfModels == 9, "Number of models changed, Regression::Store() needs to adapt");
static_assert(Model::k_numberOfModels == 10, "Number of models changed, Regression::Store() needs to adapt");
static_assert(Store::k_numberOfSeries == 3, "Number of series changed, Regression::Store() needs to adapt (m_seriesChecksum)");
Store::Store() :
@@ -285,7 +285,7 @@ double Store::squaredCorrelationCoefficient(int series) const {
}
Model * Store::regressionModel(int index) {
Model * models[Model::k_numberOfModels] = {&m_linearModel, &m_quadraticModel, &m_cubicModel, &m_quarticModel, &m_logarithmicModel, &m_exponentialModel, &m_powerModel, &m_trigonometricModel, &m_logisticModel};
Model * models[Model::k_numberOfModels] = {&m_linearModel, &m_affineModel, &m_quadraticModel, &m_cubicModel, &m_quarticModel, &m_logarithmicModel, &m_exponentialModel, &m_powerModel, &m_trigonometricModel, &m_logisticModel};
return models[index];
}

View File

@@ -11,6 +11,7 @@
#include "model/quadratic_model.h"
#include "model/quartic_model.h"
#include "model/trigonometric_model.h"
#include "model/affine_model.h"
#include "../shared/interactive_curve_view_range.h"
#include "../shared/double_pair_store.h"
#include <escher/responder.h>
@@ -79,6 +80,7 @@ private:
uint32_t m_seriesChecksum[k_numberOfSeries];
Model::Type m_regressionTypes[k_numberOfSeries];
LinearModel m_linearModel;
AffineModel m_affineModel;
QuadraticModel m_quadraticModel;
CubicModel m_cubicModel;
QuarticModel m_quarticModel;