diff --git a/apps/regression/calculation_controller.cpp b/apps/regression/calculation_controller.cpp index 522eb77cd..54e961428 100644 --- a/apps/regression/calculation_controller.cpp +++ b/apps/regression/calculation_controller.cpp @@ -12,6 +12,8 @@ using namespace Shared; namespace Regression { +static inline int max(int x, int y) { return (x>y ? x : y); } + CalculationController::CalculationController(Responder * parentResponder, ButtonRowController * header, Store * store) : TabTableController(parentResponder, this), ButtonRowDelegate(header, nullptr), @@ -97,7 +99,7 @@ Responder * CalculationController::defaultController() { } int CalculationController::numberOfRows() { - return k_totalNumberOfRows; + return 1 + k_totalNumberOfDoubleBufferRows + 4 + maxNumberOfCoefficients() + hasLinearRegression() * 2; } int CalculationController::numberOfColumns() { @@ -114,15 +116,26 @@ void CalculationController::willDisplayCellAtLocation(HighlightCell * cell, int // Calculation title if (i == 0) { - if (j == numberOfRows()-1) { - EvenOddExpressionCell * myCell = static_cast(cell); + bool shouldDisplayRAndR2 = hasLinearRegression(); + int numberRows = numberOfRows(); + if (shouldDisplayRAndR2 && j == numberRows-1) { + EvenOddExpressionCell * myCell = (EvenOddExpressionCell *)cell; myCell->setExpressionLayout(m_r2Layout); return; } MarginEvenOddMessageTextCell * myCell = (MarginEvenOddMessageTextCell *)cell; myCell->setAlignment(1.0f, 0.5f); - I18n::Message titles[k_totalNumberOfRows-1] = {I18n::Message::Mean, I18n::Message::Sum, I18n::Message::SquareSum, I18n::Message::StandardDeviation, I18n::Message::Deviation, I18n::Message::NumberOfDots, I18n::Message::Covariance, I18n::Message::Sxy, I18n::Message::Regression, I18n::Message::A, I18n::Message::B, I18n::Message::R, I18n::Message::Default}; - myCell->setMessage(titles[j-1]); + if (j <= k_regressionCellIndex) { + I18n::Message titles[k_regressionCellIndex] = {I18n::Message::Mean, I18n::Message::Sum, I18n::Message::SquareSum, I18n::Message::StandardDeviation, I18n::Message::Deviation, I18n::Message::NumberOfDots, I18n::Message::Covariance, I18n::Message::Sxy, I18n::Message::Regression}; + myCell->setMessage(titles[j-1]); + return; + } + if (shouldDisplayRAndR2 && j == numberRows - 2) { + myCell->setMessage(I18n::Message::R); + return; + } + I18n::Message titles[5] = {I18n::Message::A, I18n::Message::B, I18n::Message::C, I18n::Message::D, I18n::Message::E}; + myCell->setMessage(titles[j - k_regressionCellIndex - 1]); return; } @@ -153,21 +166,59 @@ void CalculationController::willDisplayCellAtLocation(HighlightCell * cell, int myCell->setSecondText(buffer); return; } - if (i > 0 && j == 9) { - SeparatorEvenOddBufferTextCell * myCell = (SeparatorEvenOddBufferTextCell *)cell; - myCell->setText("ax+b"); + SeparatorEvenOddBufferTextCell * bufferCell = (SeparatorEvenOddBufferTextCell *)cell; + if (i > 0 && j == k_regressionCellIndex) { + Model * model = m_store->modelForSeries(seriesNumber); + // The formula is written as " y=...", we just want the "..." part + const char * formula = I18n::translate(model->formulaMessage()); + bufferCell->setText(formula+3); + return; + } + 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); + char buffer[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)]; + PrintFloat::convertFloatToText(calculation, buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits); + bufferCell->setText(buffer); return; } if (i > 0 && j > k_totalNumberOfDoubleBufferRows) { - assert(j != 9); - CalculPointer calculationMethods[k_totalNumberOfRows-k_totalNumberOfDoubleBufferRows] = {&Store::doubleCastedNumberOfPairsOfSeries, &Store::covariance, &Store::columnProductSum, nullptr, &Store::slope, &Store::yIntercept, &Store::correlationCoefficient, &Store::squaredCorrelationCoefficient}; - double calculation = (m_store->*calculationMethods[j-k_totalNumberOfDoubleBufferRows-1])(seriesNumber); - SeparatorEvenOddBufferTextCell * myCell = (SeparatorEvenOddBufferTextCell *)cell; - char buffer[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)]; - PrintFloat::convertFloatToText(calculation, buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits); - myCell->setText(buffer); - return; + assert(j > k_regressionCellIndex); + int maxNumberCoefficients = maxNumberOfCoefficients(); + Model::Type modelType = m_store->seriesRegressionType(seriesNumber); + 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); + char buffer[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)]; + PrintFloat::convertFloatToText(calculation, buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits); + bufferCell->setText(buffer); + return; + } else { + char buffer[] = {0}; + bufferCell->setText(buffer); + return; + } + } else { + // Fill the current coefficient if needed + int currentNumberOfCoefs = m_store->modelForSeries(seriesNumber)->numberOfCoefficients(); + if (j > k_regressionCellIndex + currentNumberOfCoefs) { + char buffer[] = {0}; + bufferCell->setText(buffer); + return; + } else { + Poincare::Context * globContext = const_cast(static_cast(app()->container()))->globalContext(); + double * coefficients = m_store->coefficientsForSeries(seriesNumber, globContext); + char buffer[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)]; + PrintFloat::convertFloatToText(coefficients[j - k_regressionCellIndex - 1], buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits); + bufferCell->setText(buffer); + return; + } + } } + } KDCoordinate CalculationController::columnWidth(int i) { @@ -229,7 +280,9 @@ int CalculationController::typeAtLocation(int i, int j) { if (i == 0 && j == 0) { return k_hideableCellType; } - if (i == 0 && j == k_totalNumberOfRows-1) { + bool shouldDisplayRAndR2 = hasLinearRegression(); + int numberRows = numberOfRows(); + if (shouldDisplayRAndR2 && i == 0 && j == numberRows-1) { return k_r2CellType; } if (i == 0) { @@ -299,5 +352,25 @@ void CalculationController::unloadView(View * view) { TabTableController::unloadView(view); } +bool CalculationController::hasLinearRegression() const { + int numberOfDefinedSeries = m_store->numberOfNonEmptySeries(); + for (int i = 0; i < numberOfDefinedSeries; i++) { + if (m_store->seriesRegressionType(m_store->indexOfKthNonEmptySeries(i)) == Model::Type::Linear) { + return true; + } + } + return false; +} + +int CalculationController::maxNumberOfCoefficients() const { + int maxNumberCoefficients = 0; + int numberOfDefinedSeries = m_store->numberOfNonEmptySeries(); + for (int i = 0; i < numberOfDefinedSeries; i++) { + int currentNumberOfCoefs = m_store->modelForSeries(m_store->indexOfKthNonEmptySeries(i))->numberOfCoefficients(); + maxNumberCoefficients = max(maxNumberCoefficients, currentNumberOfCoefs); + } + return maxNumberCoefficients; +} + } diff --git a/apps/regression/calculation_controller.h b/apps/regression/calculation_controller.h index 811dafae4..812be6c47 100644 --- a/apps/regression/calculation_controller.h +++ b/apps/regression/calculation_controller.h @@ -41,18 +41,18 @@ public: int reusableCellCount(int type) override; int typeAtLocation(int i, int j) override; private: - constexpr static int k_totalNumberOfRows = 14; constexpr static int k_maxNumberOfDisplayableRows = 11; constexpr static int k_totalNumberOfDoubleBufferRows = 5; + constexpr static int k_maxNumberOfSingleBufferRows = 11; constexpr static int k_numberOfDoubleCalculationCells = Store::k_numberOfSeries * k_totalNumberOfDoubleBufferRows; - constexpr static int k_numberOfCalculationCells = Store::k_numberOfSeries * k_totalNumberOfRows - k_numberOfDoubleCalculationCells; - + constexpr static int k_numberOfCalculationCells = Store::k_numberOfSeries * k_maxNumberOfSingleBufferRows; constexpr static int k_standardCalculationTitleCellType = 0; constexpr static int k_r2CellType = 1; constexpr static int k_columnTitleCellType = 2; constexpr static int k_doubleBufferCalculationCellType = 3; constexpr static int k_standardCalculationCellType = 4; static constexpr int k_hideableCellType = 5; + static constexpr int k_regressionCellIndex = 9; static constexpr KDCoordinate k_cellHeight = 25; static constexpr KDCoordinate k_cellWidth = Ion::Display::Width/2 - Metric::CommonRightMargin/2 - Metric::CommonLeftMargin/2; @@ -63,6 +63,8 @@ private: Responder * tabController() const override; View * loadView() override; void unloadView(View * view) override; + bool hasLinearRegression() const; + int maxNumberOfCoefficients() const; Shared::MarginEvenOddMessageTextCell * m_titleCells[k_maxNumberOfDisplayableRows]; EvenOddExpressionCell * m_r2TitleCell; Poincare::ExpressionLayout * m_r2Layout; diff --git a/apps/shared.universal.i18n b/apps/shared.universal.i18n index a6929d263..bfb582eef 100644 --- a/apps/shared.universal.i18n +++ b/apps/shared.universal.i18n @@ -9,17 +9,20 @@ AtanhCommandWithArg = "atanh(x)" B = "b" BinomialCommandWithArg = "binomial(n,k)" BlankMessage = " " +C = "c" CapitalAlpha = "ALPHA" CeilCommandWithArg = "ceil(x)" ConfidenceCommandWithArg = "confidence(f,n)" ConjCommandWithArg = "conj(z)" CoshCommandWithArg = "cosh(x)" +D = "d" Default = "" DeterminantCommandWithArg = "det(M)" DiffCommandWithArg = "diff(f(x),a)" DimensionCommandWithArg = "dim(M)" DiscreteLegend = "P(X=" DiscriminantFormulaDegree2 = "Δ=b^2-4ac" +E = "e" Equal = "=" FactorCommandWithArg = "factor(n)" FccId = "FCC ID"