diff --git a/apps/regression/store.cpp b/apps/regression/store.cpp index af5ff04af..8e9de77d3 100644 --- a/apps/regression/store.cpp +++ b/apps/regression/store.cpp @@ -16,7 +16,7 @@ Store::Store() : /* Dots */ -int Store::closestVerticalDot(int direction, float x) { +int Store::closestVerticalDot(int series, int direction, float x) { float nextX = INFINITY; float nextY = INFINITY; int selectedDot = -1; @@ -25,26 +25,26 @@ int Store::closestVerticalDot(int direction, float x) { * - the next dot is the closest one in abscissa to x * - the next dot is above the regression curve if direction == 1 and below * otherwise */ - for (int index = 0; index < m_numberOfPairs; index++) { - if ((m_xMin <= m_data[0][index] && m_data[0][index] <= m_xMax) && - (std::fabs(m_data[0][index] - x) < std::fabs(nextX - x)) && - ((m_data[1][index] - yValueForXValue(m_data[0][index]) >= 0) == (direction > 0))) { + for (int index = 0; index < m_numberOfPairs[series]; index++) { + if ((m_xMin <= m_data[series][0][index] && m_data[series][0][index] <= m_xMax) && + (std::fabs(m_data[series][0][index] - x) < std::fabs(nextX - x)) && + ((m_data[series][1][index] - yValueForXValue(m_data[series][0][index]) >= 0) == (direction > 0))) { // Handle edge case: if 2 dots have the same abscissa but different ordinates - if (nextX != m_data[0][index] || ((nextY - m_data[1][index] >= 0) == (direction > 0))) { - nextX = m_data[0][index]; - nextY = m_data[1][index]; + if (nextX != m_data[series][0][index] || ((nextY - m_data[series][1][index] >= 0) == (direction > 0))) { + nextX = m_data[series][0][index]; + nextY = m_data[series][1][index]; selectedDot = index; } } } // Compare with the mean dot - double meanX = meanOfColumn(0); - double meanY = meanOfColumn(1); + double meanX = meanOfColumn(series, 0); + double meanY = meanOfColumn(series, 1); if (m_xMin <= meanX && meanX <= m_xMax && (std::fabs(meanX - x) < std::fabs(nextX - x)) && ((meanY - yValueForXValue(meanX) >= 0) == (direction > 0))) { if (nextX != meanX || ((nextY - meanY >= 0) == (direction > 0))) { - selectedDot = m_numberOfPairs; + selectedDot = m_numberOfPairs[series]; } } return selectedDot; @@ -53,54 +53,54 @@ int Store::closestVerticalDot(int direction, float x) { int Store::nextDot(int direction, int dot) { float nextX = INFINITY; int selectedDot = -1; - double meanX = meanOfColumn(0); + double meanX = meanOfColumn(series, 0); float x = meanX; - if (dot >= 0 && dot < m_numberOfPairs) { + if (dot >= 0 && dot < m_numberOfPairs[series]) { x = get(0, dot); } /* We have to scan the Store in opposite ways for the 2 directions to ensure to * select all dots (even with equal abscissa) */ if (direction > 0) { - for (int index = 0; index < m_numberOfPairs; index++) { + for (int index = 0; index < m_numberOfPairs[series]; index++) { /* The conditions to test are in this order: * - the next dot is the closest one in abscissa to x * - the next dot is not the same as the selected one * - the next dot is at the right of the selected one */ - if (std::fabs(m_data[0][index] - x) < std::fabs(nextX - x) && + if (std::fabs(m_date[series][0][index] - x) < std::fabs(nextX - x) && (index != dot) && - (m_data[0][index] >= x)) { + (m_date[series][0][index] >= x)) { // Handle edge case: 2 dots have same abscissa - if (m_data[0][index] != x || (index > dot)) { - nextX = m_data[0][index]; + if (m_date[series][0][index] != x || (index > dot)) { + nextX = m_date[series][0][index]; selectedDot = index; } } } // Compare with the mean dot if (std::fabs(meanX - x) < std::fabs(nextX - x) && - (m_numberOfPairs != dot) && + (m_numberOfPairs[series] != dot) && (meanX >= x)) { if (meanX != x || (x > dot)) { - selectedDot = m_numberOfPairs; + selectedDot = m_numberOfPairs[series]; } } } else { // Compare with the mean dot if (std::fabs(meanX - x) < std::fabs(nextX - x) && - (m_numberOfPairs != dot) && + (m_numberOfPairs[series] != dot) && (meanX <= x)) { - if (meanX != x || (m_numberOfPairs < dot)) { + if (meanX != x || (m_numberOfPairs[series] < dot)) { nextX = meanX; - selectedDot = m_numberOfPairs; + selectedDot = m_numberOfPairs[series]; } } - for (int index = m_numberOfPairs-1; index >= 0; index--) { - if (std::fabs(m_data[0][index] - x) < std::fabs(nextX - x) && + for (int index = m_numberOfPairs[series]-1; index >= 0; index--) { + if (std::fabs(m_date[series][0][index] - x) < std::fabs(nextX - x) && (index != dot) && - (m_data[0][index] <= x)) { + (m_date[series][0][index] <= x)) { // Handle edge case: 2 dots have same abscissa - if (m_data[0][index] != x || (index < dot)) { - nextX = m_data[0][index]; + if (m_date[series][0][index] != x || (index < dot)) { + nextX = m_date[series][0][index]; selectedDot = index; } } @@ -111,9 +111,9 @@ int Store::nextDot(int direction, int dot) { /* Window */ -void Store::setDefault() { - float min = minValueOfColumn(0); - float max = maxValueOfColumn(0); +void Store::setDefault(int series) { + float min = minValueOfColumn(series, 0); + float max = maxValueOfColumn(series, 0); float range = max - min; setXMin(min - k_displayLeftMarginRatio*range); setXMax(max + k_displayRightMarginRatio*range); @@ -122,98 +122,98 @@ void Store::setDefault() { /* Calculations */ -float Store::maxValueOfColumn(int i) { +float Store::maxValueOfColumn(int series, int i) { float max = -FLT_MAX; - for (int k = 0; k < m_numberOfPairs; k++) { - if (m_data[i][k] > max) { - max = m_data[i][k]; + for (int k = 0; k < m_numberOfPairs[series]; k++) { + if (m_data[series][i][k] > max) { + max = m_data[series][i][k]; } } return max; } -float Store::minValueOfColumn(int i) { +float Store::minValueOfColumn(int series, int i) { float min = FLT_MAX; - for (int k = 0; k < m_numberOfPairs; k++) { - if (m_data[i][k] < min) { - min = m_data[i][k]; + for (int k = 0; k < m_numberOfPairs[series]; k++) { + if (m_data[series][i][k] < min) { + min = m_data[series][i][k]; } } return min; } -double Store::squaredValueSumOfColumn(int i) { +double Store::squaredValueSumOfColumn(int series, int i) { double result = 0; - for (int k = 0; k < m_numberOfPairs; k++) { - result += m_data[i][k]*m_data[i][k]; + for (int k = 0; k < m_numberOfPairs[series]; k++) { + result += m_data[series][i][k]*m_data[series][i][k]; } return result; } -double Store::columnProductSum() { +double Store::columnProductSum(int series) { double result = 0; - for (int k = 0; k < m_numberOfPairs; k++) { - result += m_data[0][k]*m_data[1][k]; + for (int k = 0; k < m_numberOfPairs[series]; k++) { + result += m_date[series][0][k]*m_date[series][1][k]; } return result; } -double Store::meanOfColumn(int i) { - return m_numberOfPairs == 0 ? 0 : sumOfColumn(i)/m_numberOfPairs; +double Store::meanOfColumn(int series, int i) { + return m_numberOfPairs[series] == 0 ? 0 : sumOfColumn(series, i)/m_numberOfPairs[series]; } -double Store::varianceOfColumn(int i) { - double mean = meanOfColumn(i); - return squaredValueSumOfColumn(i)/m_numberOfPairs - mean*mean; +double Store::varianceOfColumn(int series, int i) { + double mean = meanOfColumn(series, i); + return squaredValueSumOfColumn(series, i)/m_numberOfPairs[series] - mean*mean; } -double Store::standardDeviationOfColumn(int i) { - return std::sqrt(varianceOfColumn(i)); +double Store::standardDeviationOfColumn(int series, int i) { + return std::sqrt(varianceOfColumn(series, i)); } -double Store::covariance() { - return columnProductSum()/m_numberOfPairs - meanOfColumn(0)*meanOfColumn(1); +double Store::covariance(int series) { + return columnProductSum(series)/m_numberOfPairs[series] - meanOfColumn(series, 0)*meanOfColumn(series, 1); } -double Store::slope() { - return covariance()/varianceOfColumn(0); +double Store::slope(int series) { + return covariance(series)/varianceOfColumn(series, 0); } -double Store::yIntercept() { - return meanOfColumn(1) - slope()*meanOfColumn(0); +double Store::yIntercept(int series) { + return meanOfColumn(series, 1) - slope(series)*meanOfColumn(series, 0); } -double Store::yValueForXValue(double x) { - return slope()*x+yIntercept(); +double Store::yValueForXValue(int series, double x) { + return slope(series)*x+yIntercept(series); } -double Store::xValueForYValue(double y) { - return std::fabs(slope()) < DBL_EPSILON ? NAN : (y - yIntercept())/slope(); +double Store::xValueForYValue(int series, double y) { + return std::fabs(slope(series)) < DBL_EPSILON ? NAN : (y - yIntercept(series))/slope(series); } -double Store::correlationCoefficient() { - double sd0 = standardDeviationOfColumn(0); - double sd1 = standardDeviationOfColumn(1); - return (sd0 == 0.0 || sd1 == 0.0) ? 1.0 : covariance()/(sd0*sd1); +double Store::correlationCoefficient(int series) { + double sd0 = standardDeviationOfColumn(series, 0); + double sd1 = standardDeviationOfColumn(series, 1); + return (sd0 == 0.0 || sd1 == 0.0) ? 1.0 : covariance(series)/(sd0*sd1); } -double Store::squaredCorrelationCoefficient() { - double cov = covariance(); - double v0 = varianceOfColumn(0); - double v1 = varianceOfColumn(1); +double Store::squaredCorrelationCoefficient(int series) { + double cov = covariance(series); + double v0 = varianceOfColumn(series, 0); + double v1 = varianceOfColumn(series, 1); return (v0 == 0.0 || v1 == 0.0) ? 1.0 : cov*cov/(v0*v1); } -InteractiveCurveViewRangeDelegate::Range Store::computeYRange(InteractiveCurveViewRange * interactiveCurveViewRange) { +InteractiveCurveViewRangeDelegate::Range Store::computeYRange(int series, InteractiveCurveViewRange * interactiveCurveViewRange) { float min = FLT_MAX; float max = -FLT_MAX; - for (int k = 0; k < m_numberOfPairs; k++) { - if (m_xMin <= m_data[0][k] && m_data[0][k] <= m_xMax) { - if (m_data[1][k] < min) { - min = m_data[1][k]; + for (int k = 0; k < m_numberOfPairs[series]; k++) { + if (m_xMin <= m_date[series][0][k] && m_date[series][0][k] <= m_xMax) { + if (m_date[series][1][k] < min) { + min = m_date[series][1][k]; } - if (m_data[1][k] > max) { - max = m_data[1][k]; + if (m_date[series][1][k] > max) { + max = m_date[series][1][k]; } } } diff --git a/apps/regression/store.h b/apps/regression/store.h index 9c295cc81..59dd10fdc 100644 --- a/apps/regression/store.h +++ b/apps/regression/store.h @@ -12,37 +12,37 @@ public: // Dots /* Return the closest dot to x above the regression curve if direction > 0, * below otherwise*/ - int closestVerticalDot(int direction, float x); + int closestVerticalDot(int series, int direction, float x); /* Return the closest dot to dot given on the right if direction > 0, * on the left otherwise*/ - int nextDot(int direction, int dot); + int nextDot(int series, int direction, int dot); // Window void setDefault() override; // Calculation - double numberOfPairs() const { return m_numberOfPairs; } - double squaredValueSumOfColumn(int i); - double columnProductSum(); - double meanOfColumn(int i); - double varianceOfColumn(int i); - double standardDeviationOfColumn(int i); - double covariance(); - double slope(); - double yIntercept(); - double yValueForXValue(double x); - double xValueForYValue(double y); - double correlationCoefficient(); - double squaredCorrelationCoefficient(); + double numberOfPairs(int series) const { return m_numberOfPairs; } + double squaredValueSumOfColumn(int series, int i); + double columnProductSum(int series); + double meanOfColumn(int series, int i); + double varianceOfColumn(int series, int i); + double standardDeviationOfColumn(int series, int i); + double covariance(int series); + double slope(int series); + double yIntercept(int series); + double yValueForXValue(int series, double x); + double xValueForYValue(int series, double y); + double correlationCoefficient(int series); + double squaredCorrelationCoefficient(int series); private: constexpr static float k_displayTopMarginRatio = 0.12f; constexpr static float k_displayRightMarginRatio = 0.05f; constexpr static float k_displayBottomMarginRatio = 0.5f; constexpr static float k_displayLeftMarginRatio = 0.05f; - InteractiveCurveViewRangeDelegate::Range computeYRange(InteractiveCurveViewRange * interactiveCurveViewRange) override; + InteractiveCurveViewRangeDelegate::Range computeYRange(int series, InteractiveCurveViewRange * interactiveCurveViewRange) override; float addMargin(float x, float range, bool isMin) override; - float maxValueOfColumn(int i); - float minValueOfColumn(int i); + float maxValueOfColumn(int series, int i); + float minValueOfColumn(int series, int i); }; typedef double (Store::*ArgCalculPointer)(int);