diff --git a/.github/workflows/staging-deploy.yml b/.github/workflows/staging-deploy.yml index ba0fc04..e49c2cd 100644 --- a/.github/workflows/staging-deploy.yml +++ b/.github/workflows/staging-deploy.yml @@ -21,7 +21,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.8"] + python-version: ["3.12"] steps: - name: Checkout uses: actions/checkout@v4 diff --git a/app/Dockerfile b/app/Dockerfile index 9f5ca25..f884b48 100755 --- a/app/Dockerfile +++ b/app/Dockerfile @@ -1,7 +1,7 @@ # Base image that bundles AWS Lambda Python 3.8 image with some middleware functions # FROM base-eval-tmp # FROM rabidsheep55/python-base-eval-layer -FROM ghcr.io/lambda-feedback/baseevalutionfunctionlayer:main-3.8 +FROM ghcr.io/lambda-feedback/baseevalutionfunctionlayer:main-3.12 RUN yum install -y git diff --git a/app/context/symbolic.py b/app/context/symbolic.py index 77c41d9..6ba650a 100644 --- a/app/context/symbolic.py +++ b/app/context/symbolic.py @@ -1,5 +1,5 @@ from copy import deepcopy -from sympy import Add, Pow, Mul, Equality, pi, im, I, N +from sympy import Add, Pow, Mul, Equality, pi, im, I, N, oo from sympy import re as real_part from ..utility.expression_utilities import ( @@ -83,6 +83,22 @@ def create_expressions_for_comparison(criterion, parameters_dict, local_substitu return lhs_expr, rhs_expr +def do_comparison_infinite(comparison_symbol, lhs_expr, rhs_expr): + # When either side is infinite, subtracting (e.g. oo - oo) yields nan, making + # the subtraction-based do_comparison unreliable. Compare the sides directly instead. + direct_comparisons = { + "=": lhs_expr == rhs_expr, + ">": lhs_expr > rhs_expr, + ">=": lhs_expr >= rhs_expr, + "<": lhs_expr < rhs_expr, + "<=": lhs_expr <= rhs_expr, + } + try: + return bool(direct_comparisons[comparison_symbol.strip()]) + except Exception: + return None + + def do_comparison(comparison_symbol, expression): comparisons = { "=": lambda expr: bool(expression.cancel().simplify().simplify() == 0), @@ -106,7 +122,12 @@ def check_equality(criterion, parameters_dict, local_substitutions=[]): elif not isinstance(lhs_expr, Equality) and isinstance(rhs_expr, Equality): result = False else: - result = do_comparison(criterion.content, lhs_expr-rhs_expr) + # Subtraction of infinite values (e.g. oo - oo) yields nan rather than 0, + # so we use direct comparison when either side is infinite. + if lhs_expr.is_infinite or rhs_expr.is_infinite: + result = do_comparison_infinite(criterion.content, lhs_expr, rhs_expr) + else: + result = do_comparison(criterion.content, lhs_expr-rhs_expr) # There are some types of expression, e.g. those containing hyperbolic trigonometric functions, that can behave # unpredictably when simplification is applied. For that reason we check several different combinations of # simplifications here in order to reduce the likelihood of false negatives. diff --git a/app/tests/symbolic_evaluation_test.py b/app/tests/symbolic_evaluation_test.py index 607278c..56eda6f 100644 --- a/app/tests/symbolic_evaluation_test.py +++ b/app/tests/symbolic_evaluation_test.py @@ -784,10 +784,6 @@ def test_warning_inappropriate_symbol(self): '(0,002*6800*v)/1,2', '(0.002*6800*v)/1.2' ), - ( - '-∞', - '-inf' - ), ( 'x.y', 'x*y' @@ -1936,6 +1932,11 @@ def test_unexpected_equalities_in_response_that_generates_set(self): result = evaluation_function(response, answer, params) assert result["is_correct"] is False + def test_infinity_unicode_symbol(self): + params = {'strict_syntax': True, 'elementary_functions': True} + result = evaluation_function('-∞', '-inf', params) + assert result["is_correct"] is True + def test_infinity_alias(self): response = "2.694" answer = "infinity" diff --git a/app/utility/expression_utilities.py b/app/utility/expression_utilities.py index 57ca2b9..bc08b5e 100644 --- a/app/utility/expression_utilities.py +++ b/app/utility/expression_utilities.py @@ -62,7 +62,7 @@ def _print_log(self, expr, exp=None): ('acsch', ['arccsch', 'arccosech']), ('asech', ['arcsech']), ('exp', ['Exp']), ('E', ['e']), ('log', ['ln']), ('sqrt', []), ('sign', []), ('Abs', ['abs']), ('Max', ['max']), ('Min', ['min']), ('arg', []), ('ceiling', ['ceil']), ('floor', []), - ('oo',['Infinity', 'inf', 'infinity']), + ('oo',['Infinity', 'inf', 'infinity', '∞']), # Special symbols to make sure plus_minus and minus_plus are not destroyed during preprocessing ('plus_minus', []), ('minus_plus', []), # Below this line should probably not be collected with elementary functions. Some like 'common operations' would be a better name