diff --git a/apps/regression/calculation_controller.cpp b/apps/regression/calculation_controller.cpp index 021760dc2..4d24c7c26 100644 --- a/apps/regression/calculation_controller.cpp +++ b/apps/regression/calculation_controller.cpp @@ -176,8 +176,8 @@ void CalculationController::willDisplayCellAtLocation(HighlightCell * cell, int const int numberSignificantDigits = Preferences::LargeNumberOfSignificantDigits; if (i > 0 && j > 0 && j <= k_totalNumberOfDoubleBufferRows) { ArgCalculPointer calculationMethods[k_totalNumberOfDoubleBufferRows] = {&Store::meanOfColumn, &Store::sumOfColumn, &Store::squaredValueSumOfColumn, &Store::standardDeviationOfColumn, &Store::varianceOfColumn}; - double calculation1 = (m_store->*calculationMethods[j-1])(seriesNumber, 0); - double calculation2 = (m_store->*calculationMethods[j-1])(seriesNumber, 1); + double calculation1 = (m_store->*calculationMethods[j-1])(seriesNumber, 0, false); + double calculation2 = (m_store->*calculationMethods[j-1])(seriesNumber, 1, false); EvenOddDoubleBufferTextCellWithSeparator * myCell = (EvenOddDoubleBufferTextCellWithSeparator *)cell; constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(numberSignificantDigits); char buffer[bufferSize]; @@ -196,8 +196,16 @@ void CalculationController::willDisplayCellAtLocation(HighlightCell * cell, int } if (i > 0 && j > k_totalNumberOfDoubleBufferRows && j < k_regressionCellIndex) { assert(j != k_regressionCellIndex); - CalculPointer calculationMethods[] = {&Store::doubleCastedNumberOfPairsOfSeries, &Store::covariance, &Store::columnProductSum}; - double calculation = (m_store->*calculationMethods[j-k_totalNumberOfDoubleBufferRows-1])(seriesNumber); + double calculation = 0; + const int calculationIndex = j-k_totalNumberOfDoubleBufferRows-1; + if (calculationIndex == 0) { + calculation = m_store->doubleCastedNumberOfPairsOfSeries(seriesNumber); + } else if (calculationIndex == 1) { + calculation = m_store->covariance(seriesNumber); + } else { + assert(calculationIndex == 2); + calculation = m_store->columnProductSum(seriesNumber); + } constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(numberSignificantDigits); char buffer[bufferSize]; PoincareHelpers::ConvertFloatToText(calculation, buffer, bufferSize, numberSignificantDigits); @@ -228,8 +236,8 @@ void CalculationController::willDisplayCellAtLocation(HighlightCell * cell, int if (j > k_regressionCellIndex + maxNumberCoefficients) { // Fill r and r2 if needed if (modelType == Model::Type::Linear) { - CalculPointer calculationMethods[2] = {&Store::correlationCoefficient, &Store::squaredCorrelationCoefficient}; - double calculation = (m_store->*calculationMethods[j - k_regressionCellIndex - maxNumberCoefficients - 1])(seriesNumber); + const int calculationIndex = j - k_regressionCellIndex - maxNumberCoefficients - 1; + double calculation = calculationIndex == 0 ? m_store->correlationCoefficient(seriesNumber) : m_store->squaredCorrelationCoefficient(seriesNumber); constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(numberSignificantDigits); char buffer[bufferSize]; PoincareHelpers::ConvertFloatToText(calculation, buffer, bufferSize, numberSignificantDigits); diff --git a/apps/regression/model/linear_model.h b/apps/regression/model/linear_model.h index 6f1c91153..4fd9d2988 100644 --- a/apps/regression/model/linear_model.h +++ b/apps/regression/model/linear_model.h @@ -12,7 +12,7 @@ public: I18n::Message formulaMessage() const override { return I18n::Message::LinearRegressionFormula; } double evaluate(double * modelCoefficients, double x) const override; double levelSet(double * modelCoefficients, double xMin, double step, double xMax, double y, Poincare::Context * context) override; - virtual void fit(Store * store, int series, double * modelCoefficients, 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 2; } int bannerLinesCount() const override { return 3; } diff --git a/apps/regression/model/power_model.cpp b/apps/regression/model/power_model.cpp index 928e25514..c152c9c1d 100644 --- a/apps/regression/model/power_model.cpp +++ b/apps/regression/model/power_model.cpp @@ -61,6 +61,12 @@ double PowerModel::partialDerivate(double * modelCoefficients, int derivateCoeff return 0.0; } +void PowerModel::fit(Store * store, int series, double * modelCoefficients, Poincare::Context * context) { + /* Y1 = aX1^b => ln(Y1) = ln(a) + b*ln(X1)*/ + modelCoefficients[0] = exp(store->yIntercept(series, true)); + modelCoefficients[1] = store->slope(series, true); +} + bool PowerModel::dataSuitableForFit(Store * store, int series) const { if (!Model::dataSuitableForFit(store, series)) { return false; diff --git a/apps/regression/model/power_model.h b/apps/regression/model/power_model.h index ac544e5c1..638467386 100644 --- a/apps/regression/model/power_model.h +++ b/apps/regression/model/power_model.h @@ -13,10 +13,11 @@ public: double evaluate(double * modelCoefficients, double x) const override; double levelSet(double * modelCoefficients, double xMin, double step, double xMax, double y, Poincare::Context * context) override; double partialDerivate(double * modelCoefficients, int derivateCoefficientIndex, double x) const override; + void fit(Store * store, int series, double * modelCoefficients, Poincare::Context * context) override; int numberOfCoefficients() const override { return 2; } int bannerLinesCount() const override { return 2; } protected: - virtual bool dataSuitableForFit(Store * store, int series) const override; + bool dataSuitableForFit(Store * store, int series) const override; }; } diff --git a/apps/regression/store.cpp b/apps/regression/store.cpp index ceba3633a..0afd7941a 100644 --- a/apps/regression/store.cpp +++ b/apps/regression/store.cpp @@ -204,45 +204,53 @@ float Store::minValueOfColumn(int series, int i) const { return minColumn; } -double Store::squaredValueSumOfColumn(int series, int i) const { +double Store::squaredValueSumOfColumn(int series, int i, bool lnOfSeries) const { double result = 0; for (int k = 0; k < numberOfPairsOfSeries(series); k++) { - result += m_data[series][i][k]*m_data[series][i][k]; + if (lnOfSeries) { + result += log(m_data[series][i][k]) * log(m_data[series][i][k]); + } else { + result += m_data[series][i][k]*m_data[series][i][k]; + } } return result; } -double Store::columnProductSum(int series) const { +double Store::columnProductSum(int series, bool lnOfSeries) const { double result = 0; for (int k = 0; k < numberOfPairsOfSeries(series); k++) { - result += m_data[series][0][k]*m_data[series][1][k]; + if (lnOfSeries) { + result += log(m_data[series][0][k]) * log(m_data[series][1][k]); + } else { + result += m_data[series][0][k] * m_data[series][1][k]; + } } return result; } -double Store::meanOfColumn(int series, int i) const { - return numberOfPairsOfSeries(series) == 0 ? 0 : sumOfColumn(series, i)/numberOfPairsOfSeries(series); +double Store::meanOfColumn(int series, int i, bool lnOfSeries) const { + return numberOfPairsOfSeries(series) == 0 ? 0 : sumOfColumn(series, i, lnOfSeries)/numberOfPairsOfSeries(series); } -double Store::varianceOfColumn(int series, int i) const { - double mean = meanOfColumn(series, i); - return squaredValueSumOfColumn(series, i)/numberOfPairsOfSeries(series) - mean*mean; +double Store::varianceOfColumn(int series, int i, bool lnOfSeries) const { + double mean = meanOfColumn(series, i, lnOfSeries); + return squaredValueSumOfColumn(series, i, lnOfSeries)/numberOfPairsOfSeries(series) - mean*mean; } -double Store::standardDeviationOfColumn(int series, int i) const { - return std::sqrt(varianceOfColumn(series, i)); +double Store::standardDeviationOfColumn(int series, int i, bool lnOfSeries) const { + return std::sqrt(varianceOfColumn(series, i, lnOfSeries)); } -double Store::covariance(int series) const { - return columnProductSum(series)/numberOfPairsOfSeries(series) - meanOfColumn(series, 0)*meanOfColumn(series, 1); +double Store::covariance(int series, bool lnOfSeries) const { + return columnProductSum(series, lnOfSeries)/numberOfPairsOfSeries(series) - meanOfColumn(series, 0, lnOfSeries)*meanOfColumn(series, 1, lnOfSeries); } -double Store::slope(int series) const { - return LinearModelHelper::Slope(covariance(series), varianceOfColumn(series, 0)); +double Store::slope(int series, bool lnOfSeries) const { + return LinearModelHelper::Slope(covariance(series, lnOfSeries), varianceOfColumn(series, 0, lnOfSeries)); } -double Store::yIntercept(int series) const { - return LinearModelHelper::YIntercept(meanOfColumn(series, 1), meanOfColumn(series, 0), slope(series)); +double Store::yIntercept(int series, bool lnOfSeries) const { + return LinearModelHelper::YIntercept(meanOfColumn(series, 1, lnOfSeries), meanOfColumn(series, 0, lnOfSeries), slope(series, lnOfSeries)); } double Store::yValueForXValue(int series, double x, Poincare::Context * globalContext) { diff --git a/apps/regression/store.h b/apps/regression/store.h index da5a24252..dfdc682c1 100644 --- a/apps/regression/store.h +++ b/apps/regression/store.h @@ -56,14 +56,14 @@ public: // Calculation double * coefficientsForSeries(int series, Poincare::Context * globalContext); double doubleCastedNumberOfPairsOfSeries(int series) const; - double squaredValueSumOfColumn(int series, int i) const; - double columnProductSum(int series) const; - double meanOfColumn(int series, int i) const; - double varianceOfColumn(int series, int i) const; - double standardDeviationOfColumn(int series, int i) const; - double covariance(int series) const; - double slope(int series) const; - double yIntercept(int series) const; + double squaredValueSumOfColumn(int series, int i, bool lnOfSeries = false) const; + double columnProductSum(int series, bool lnOfSeries = false) const; + double meanOfColumn(int series, int i, bool lnOfSeries = false) const; + double varianceOfColumn(int series, int i, bool lnOfSeries = false) const; + double standardDeviationOfColumn(int series, int i, bool lnOfSeries = false) const; + double covariance(int series, bool lnOfSeries = false) const; + double slope(int series, bool lnOfSeries = false) const; + double yIntercept(int series, bool lnOfSeries = false) const; double yValueForXValue(int series, double x, Poincare::Context * globalContext); double xValueForYValue(int series, double y, Poincare::Context * globalContext); double correlationCoefficient(int series) const; @@ -89,8 +89,7 @@ private: Poincare::Preferences::AngleUnit m_angleUnit; }; -typedef double (Store::*ArgCalculPointer)(int, int) const; -typedef double (Store::*CalculPointer)(int) const; +typedef double (Store::*ArgCalculPointer)(int, int, bool) const; typedef void (Store::*RangeMethodPointer)(); } diff --git a/apps/shared/double_pair_store.cpp b/apps/shared/double_pair_store.cpp index d298aa21b..b35c56de7 100644 --- a/apps/shared/double_pair_store.cpp +++ b/apps/shared/double_pair_store.cpp @@ -98,12 +98,12 @@ int DoublePairStore::indexOfKthNonEmptySeries(int k) const { return 0; } -double DoublePairStore::sumOfColumn(int series, int i) const { +double DoublePairStore::sumOfColumn(int series, int i, bool lnOfSeries) const { assert(series >= 0 && series < k_numberOfSeries); assert(i == 0 || i == 1); double result = 0; for (int k = 0; k < m_numberOfPairs[series]; k++) { - result += m_data[series][i][k]; + result += lnOfSeries ? log(m_data[series][i][k]) : m_data[series][i][k]; } return result; } diff --git a/apps/shared/double_pair_store.h b/apps/shared/double_pair_store.h index 465b78a9d..9c8859612 100644 --- a/apps/shared/double_pair_store.h +++ b/apps/shared/double_pair_store.h @@ -47,7 +47,7 @@ public: int indexOfKthNonEmptySeries(int k) const; // Calculations - double sumOfColumn(int series, int i) const; + double sumOfColumn(int series, int i, bool lnOfSeries = false) const; bool seriesNumberOfAbscissaeGreaterOrEqualTo(int series, int i) const; uint32_t storeChecksum() const; uint32_t storeChecksumForSeries(int series) const;