diff --git a/.gitignore b/.gitignore index 295307932f..f98fdf7bf9 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ db.newaskbot db.oldaskbot flushdb.sh build +\#*\# \ No newline at end of file diff --git a/djangoapps/courseware/capa/calc.py b/djangoapps/courseware/capa/calc.py index 63c5c9de01..fb64c58139 100644 --- a/djangoapps/courseware/capa/calc.py +++ b/djangoapps/courseware/capa/calc.py @@ -5,6 +5,7 @@ import operator import re import numpy +import numbers import scipy.constants from pyparsing import Word, alphas, nums, oneOf, Literal @@ -121,7 +122,7 @@ def evaluator(variables, functions, string, cs=False): def number_parse_action(x): # [ '7' ] -> [ 7 ] return [super_float("".join(x))] def exp_parse_action(x): # [ 2 ^ 3 ^ 2 ] -> 512 - x = [e for e in x if type(e) in [float, numpy.float64, numpy.complex]] # Ignore ^ + x = [e for e in x if isinstance(e, numbers.Number)] # Ignore ^ x.reverse() x=reduce(lambda a,b:b**a, x) return x @@ -130,7 +131,7 @@ def evaluator(variables, functions, string, cs=False): return x[0] if 0 in x: return float('nan') - x = [1./e for e in x if type(e) == float] # Ignore ^ + x = [1./e for e in x if isinstance(e, numbers.Number)] # Ignore || return 1./sum(x) def sum_parse_action(x): # [ 1 + 2 - 3 ] -> 0 total = 0.0 @@ -217,4 +218,7 @@ if __name__=='__main__': print evaluator({},{}, "-(7+5)") print evaluator({},{}, "-0.33") print evaluator({},{}, "-.33") + print evaluator({},{}, "5+1*j") + print evaluator({},{}, "j||1") + print evaluator({},{}, "e^(j*pi)") print evaluator({},{}, "5+7 QWSEKO") diff --git a/djangoapps/courseware/capa/responsetypes.py b/djangoapps/courseware/capa/responsetypes.py index 56ea51ddb9..c173eb6faf 100644 --- a/djangoapps/courseware/capa/responsetypes.py +++ b/djangoapps/courseware/capa/responsetypes.py @@ -1,5 +1,6 @@ import json import math +import numbers import numpy import random import scipy @@ -37,7 +38,7 @@ class numericalresponse(object): def __init__(self, xml, context): self.xml = xml self.correct_answer = contextualize_text(xml.get('answer'), context) - self.correct_answer = float(self.correct_answer) + self.correct_answer = complex(self.correct_answer) self.tolerance_xml = xml.xpath('//*[@id=$id]//responseparam[@type="tolerance"]/@default', id=xml.get('id'))[0] self.tolerance = contextualize_text(self.tolerance_xml, context) @@ -49,7 +50,10 @@ class numericalresponse(object): student_answer = student_answers[self.answer_id] try: correct = compare_with_tolerance (evaluator(dict(),dict(),student_answer), self.correct_answer, self.tolerance) - except: + # We should catch this explicitly. + # I think this is just pyparsing.ParseException, calc.UndefinedVariable: + # But we'd need to confirm + except: raise StudentInputError('Invalid input -- please use a number only') if correct: @@ -141,7 +145,7 @@ class formularesponse(object): except: #traceback.print_exc() raise StudentInputError("Error in formula") - if math.isnan(student_result) or math.isinf(student_result): + if numpy.isnan(student_result) or numpy.isinf(student_result): return {self.answer_id:"incorrect"} if not compare_with_tolerance(student_result, instructor_result, self.tolerance): return {self.answer_id:"incorrect"} @@ -153,9 +157,9 @@ class formularesponse(object): keys and all non-numeric values stripped out. All values also converted to float. Used so we can safely use Python contexts. ''' - d=dict([(k, float(d[k])) for k in d if type(k)==str and \ + d=dict([(k, numpy.complex(d[k])) for k in d if type(k)==str and \ k.isalnum() and \ - (type(d[k]) == float or type(d[k]) == int) ]) + isinstance(d[k], numbers.Number)]) return d def get_answers(self): diff --git a/djangoapps/courseware/tests.py b/djangoapps/courseware/tests.py index b0d7cad19f..2b2b354177 100644 --- a/djangoapps/courseware/tests.py +++ b/djangoapps/courseware/tests.py @@ -20,7 +20,7 @@ class ModelsTest(unittest.TestCase): variables={'R1':2.0, 'R3':4.0} functions={'sin':numpy.sin, 'cos':numpy.cos} - self.assertEqual(calc.evaluator(variables, functions, "10000||sin(7+5)-6k"), 4000.0) + self.assertTrue(abs(calc.evaluator(variables, functions, "10000||sin(7+5)+0.5356"))<0.01) self.assertEqual(calc.evaluator({'R1': 2.0, 'R3':4.0}, {}, "13"), 13) self.assertEqual(calc.evaluator(variables, functions, "13"), 13) self.assertEqual(calc.evaluator({'a': 2.2997471478310274, 'k': 9, 'm': 8, 'x': 0.66009498411213041}, {}, "5"), 5) @@ -30,6 +30,8 @@ class ModelsTest(unittest.TestCase): self.assertEqual(calc.evaluator(variables, functions, "R1*R3"), 8.0) self.assertTrue(abs(calc.evaluator(variables, functions, "sin(e)-0.41"))<0.01) self.assertTrue(abs(calc.evaluator(variables, functions, "k*T/q-0.025"))<0.001) + self.assertTrue(abs(calc.evaluator(variables, functions, "e^(j*pi)")+1)<0.00001) + self.assertTrue(abs(calc.evaluator(variables, functions, "j||1")-0.5-0.5j)<0.00001) exception_happened = False try: calc.evaluator({},{}, "5+7 QWSEKO")