diff --git a/apps/graph/Makefile b/apps/graph/Makefile index de03db3d6..2c87734dc 100644 --- a/apps/graph/Makefile +++ b/apps/graph/Makefile @@ -42,7 +42,6 @@ i18n_files += $(call i18n_without_universal_for,graph/base) tests_src += $(addprefix apps/graph/test/,\ caching.cpp \ helper.cpp \ - range.cpp \ ) $(eval $(call depends_on_image,apps/graph/app.cpp,apps/graph/graph_icon.png)) diff --git a/apps/graph/test/range.cpp b/apps/graph/test/range.cpp deleted file mode 100644 index defda15e7..000000000 --- a/apps/graph/test/range.cpp +++ /dev/null @@ -1,182 +0,0 @@ -#include -#include "helper.h" -#include - -using namespace Poincare; -using namespace Shared; - -namespace Graph { - -void assert_range_inclusion_predicate(const char * definition, ContinuousFunction::PlotType type, const float * xList, size_t length, bool testInclusion) { - /* Test that all points (x, f(x)) for x in xList are either included in the - * range if testIncluded is true, or exculded from the range if testInclusion - * is false. - * If f(x) is not finite, only the presence of x in the horizontal range is - * tested. */ - GlobalContext globalContext; - ContinuousFunctionStore functionStore; - ContinuousFunction * f = addFunction(definition, type, &functionStore, &globalContext); - - float xMin = FLT_MAX, xMax = - FLT_MAX, yMin = FLT_MAX, yMax = - FLT_MAX; - f->rangeForDisplay(&xMin, &xMax, &yMin, &yMax, &globalContext); - assert(xMin <= xMax && yMin <= yMax); - - for (size_t i = 0; i < length; i++) { - float x = xList[i]; - float y = f->evaluateXYAtParameter(x, &globalContext).x2(); - assert(std::isfinite(x)); - if (!testInclusion) { - quiz_assert(xMin > x || x > xMax || (std::isfinite(y) && (yMin > y || y > yMax))); - } else { - /* The program can miss the exact abscissa of an extremum, resulting in - * bounds that are close from its value but that do not encompass it. We - * thus test the inclusion of (x, f(x)) along with two neighbouring - * points. */ - float dx = (xMax - xMin) / (Ion::Display::Width / 2); - float y1 = f->evaluateXYAtParameter(x - dx, &globalContext).x2(), y2 = f->evaluateXYAtParameter(x + dx, &globalContext).x2(); - quiz_assert(xMin <= x - && x <= xMax - && (!std::isfinite(y) - || (yMin <= y && y <= yMax) - || (yMin <= y1 && y1 <= yMax) - || (yMin <= y2 && y2 <= yMax))); - } - } -} - -void assert_range_includes_points(const char * definition, ContinuousFunction::PlotType type, const float * xList, size_t length) { assert_range_inclusion_predicate(definition, type, xList, length, true); } -void assert_range_excludes_points(const char * definition, ContinuousFunction::PlotType type, const float * xList, size_t length) { assert_range_inclusion_predicate(definition, type, xList, length, false); } - -void assert_range_includes_single_point(const char * definition, ContinuousFunction::PlotType type, float x) { assert_range_includes_points(definition, type, &x, 1); } -void assert_range_excludes_single_point(const char * definition, ContinuousFunction::PlotType type, float x) { assert_range_excludes_points(definition, type, &x, 1); } - -void assert_range_includes_and_bounds_asymptotes(const char * definition, const float * asymptotesXList, size_t length) { - /* The value for delta is the step the old algorithm used to sample a - * cartesian function, causing functions such as 1/x to be evaluated too - * close to 0. */ - constexpr float delta = 1.f / 32.f; - for (size_t i = 0; i < length; i++) { - float x = asymptotesXList[i]; - assert_range_includes_single_point(definition, Cartesian, x); - assert_range_excludes_single_point(definition, Cartesian, x - delta); - assert_range_excludes_single_point(definition, Cartesian, x + delta); - } -} - -void assert_range_shows_enough_periods(const char * definition, float period, Preferences::AngleUnit angleUnit = Preferences::AngleUnit::Degree) { - /* The graph should display at least 3 periods, but no more than 7. */ - constexpr int lowNumberOfPeriods = 3, highNumberOfPeriods = 8; - - GlobalContext globalContext; - ContinuousFunctionStore functionStore; - ContinuousFunction * f = addFunction(definition, Cartesian, &functionStore, &globalContext); - - Preferences::sharedPreferences()->setAngleUnit(angleUnit); - if (angleUnit != Preferences::AngleUnit::Degree) { - f->setPlotType(Cartesian, angleUnit, &globalContext); - } - - float xMin = FLT_MAX, xMax = - FLT_MAX, yMin = FLT_MAX, yMax = - FLT_MAX; - f->rangeForDisplay(&xMin, &xMax, &yMin, &yMax, &globalContext); - assert(xMin <= xMax && yMin <= yMax); - float numberOfPeriods = (xMax - xMin) / period; - - quiz_assert(lowNumberOfPeriods <= numberOfPeriods && numberOfPeriods <= highNumberOfPeriods); -} - -void assert_range_displays_entire_polar_function(const char * definition) { - GlobalContext globalContext; - ContinuousFunctionStore functionStore; - ContinuousFunction * f = addFunction(definition, Polar, &functionStore, &globalContext); - - float xMin = FLT_MAX, xMax = - FLT_MAX, yMin = FLT_MAX, yMax = - FLT_MAX; - f->rangeForDisplay(&xMin, &xMax, &yMin, &yMax, &globalContext); - assert(xMin <= xMax && yMin <= yMax); - - for (float t = f->tMin(); t < f->tMax(); t += f->rangeStep()) { - const Coordinate2D xy = f->evaluateXYAtParameter(t, &globalContext); - if (!std::isfinite(xy.x1()) || !std::isfinite(xy.x2())) { - continue; - } - quiz_assert(xMin <= xy.x1() && xy.x1() <= xMax && yMin <= xy.x2() && xy.x2() <= yMax); - } -} - -QUIZ_CASE(graph_range_polynomes) { - assert_range_includes_single_point("37", Cartesian, 0.f); - assert_range_includes_single_point("x-1", Cartesian, 1.f); - assert_range_includes_single_point("100+x", Cartesian, -100.f); - assert_range_includes_single_point("x^2-20*x+101", Cartesian, 10.f); - - constexpr float array1[2] = {-2.f, 3.f}; - assert_range_includes_points("(x+2)*(x-3)", Cartesian, array1, 2); - - constexpr float array2[2] = {-1.f, 0.5f}; - assert_range_includes_points("2*x^2+x-1", Cartesian, array2, 2); - - constexpr float array3[6] = {-3.f, 3.f, -2.f, 2.f, -1.f, 1.f}; - assert_range_includes_points("(x+3)(x+2)(x+1)(x-1)(x-2)(x-3)", Cartesian, array3, 6); - - constexpr float array4[3] = {0.f, 4.f, 5.f}; - assert_range_includes_points("x^5-5*x^4", Cartesian, array4, 3); -} - -QUIZ_CASE(graph_range_exponential) { - assert_range_includes_single_point("ℯ^x", Cartesian, 0.f); - assert_range_excludes_single_point("ℯ^x", Cartesian, 4.f); - - assert_range_includes_single_point("ℯ^(-x)", Cartesian, 0.f); - assert_range_excludes_single_point("ℯ^(-x)", Cartesian, -4.f); - - constexpr float array1[3] = {1.f, 5.f, 1e-1f}; - assert_range_includes_points("ln(x)", Cartesian, array1, 3); - assert_range_excludes_single_point("ln(x)", Cartesian, 1e-3f); - - constexpr float array2[2] = {-1.f, 3.f}; - assert_range_includes_points("2-ℯ^(-x)", Cartesian, array2, 2); - assert_range_excludes_single_point("2-ℯ^(-x)", Cartesian, 50.f); - assert_range_excludes_single_point("2-ℯ^(-x)", Cartesian, -10.f); - - assert_range_includes_single_point("x^x", Cartesian, 0.5f); - assert_range_excludes_single_point("x^x", Cartesian, -5.f); - assert_range_includes_single_point("x^(1/x)", Cartesian, 1e-3f); -} - -QUIZ_CASE(graph_range_fractions) { - constexpr float array1[1] = {0.f}; - assert_range_includes_and_bounds_asymptotes("1/x", array1, 1); - assert_range_includes_and_bounds_asymptotes("1/x^2", array1, 1); - - constexpr float array2[2] = {-2.f, 2.f}; - assert_range_includes_and_bounds_asymptotes("1/(x^2-4)", array2, 2); - - constexpr float array3[1] = {-100.f}; - assert_range_includes_and_bounds_asymptotes("1/(x+100)", array3, 1); -} - -QUIZ_CASE(graph_range_periodic) { - assert_range_shows_enough_periods("sin(x)", 2*M_PI, Preferences::AngleUnit::Radian); - assert_range_shows_enough_periods("sin(x)", 360.f); - assert_range_shows_enough_periods("sin(x)+10", 2*M_PI, Preferences::AngleUnit::Radian); - assert_range_shows_enough_periods("sin(x)+10", 360.f); - assert_range_shows_enough_periods("cos(x)", 2*M_PI, Preferences::AngleUnit::Radian); - assert_range_shows_enough_periods("cos(x)", 360.f); - assert_range_shows_enough_periods("sin(x)/x", 2*M_PI, Preferences::AngleUnit::Radian); - assert_range_shows_enough_periods("sin(x)/x", 360.f); - assert_range_shows_enough_periods("x*sin(x)", 2*M_PI, Preferences::AngleUnit::Radian); - assert_range_shows_enough_periods("x*sin(x)", 360.f); - assert_range_shows_enough_periods("ln(sin(x))", 2*M_PI, Preferences::AngleUnit::Radian); - assert_range_shows_enough_periods("ln(sin(x))", 360.f); - constexpr float array1[2] = {-1.f, 1.f}; - assert_range_includes_points("x*sin(1/x)", Cartesian, array1, 2); -} - -QUIZ_CASE(graph_range_polar) { - assert_range_displays_entire_polar_function("1"); - assert_range_displays_entire_polar_function("θ"); - assert_range_displays_entire_polar_function("sin(θ)"); - assert_range_displays_entire_polar_function("sin(10θ)"); - assert_range_displays_entire_polar_function("ln(θ)"); -} - -}