mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-18 16:27:34 +01:00
[Regression] Add affine regression
This commit is contained in:
@@ -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 \
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 "
|
||||
|
||||
@@ -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
|
||||
|
||||
51
apps/regression/model/affine_model.cpp
Normal file
51
apps/regression/model/affine_model.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
24
apps/regression/model/affine_model.h
Normal file
24
apps/regression/model/affine_model.h
Normal 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
|
||||
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user