Commit 17e84aae by David Ormsbee

Merge pull request #9 from MITx/pmitros/complex-numbers-fix

Complex numbers now work in problems
parents bc604fca 37452f3a
...@@ -10,3 +10,4 @@ db.newaskbot ...@@ -10,3 +10,4 @@ db.newaskbot
db.oldaskbot db.oldaskbot
flushdb.sh flushdb.sh
build build
\#*\#
\ No newline at end of file
...@@ -5,6 +5,7 @@ import operator ...@@ -5,6 +5,7 @@ import operator
import re import re
import numpy import numpy
import numbers
import scipy.constants import scipy.constants
from pyparsing import Word, alphas, nums, oneOf, Literal from pyparsing import Word, alphas, nums, oneOf, Literal
...@@ -121,7 +122,7 @@ def evaluator(variables, functions, string, cs=False): ...@@ -121,7 +122,7 @@ def evaluator(variables, functions, string, cs=False):
def number_parse_action(x): # [ '7' ] -> [ 7 ] def number_parse_action(x): # [ '7' ] -> [ 7 ]
return [super_float("".join(x))] return [super_float("".join(x))]
def exp_parse_action(x): # [ 2 ^ 3 ^ 2 ] -> 512 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.reverse()
x=reduce(lambda a,b:b**a, x) x=reduce(lambda a,b:b**a, x)
return x return x
...@@ -130,7 +131,7 @@ def evaluator(variables, functions, string, cs=False): ...@@ -130,7 +131,7 @@ def evaluator(variables, functions, string, cs=False):
return x[0] return x[0]
if 0 in x: if 0 in x:
return float('nan') 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) return 1./sum(x)
def sum_parse_action(x): # [ 1 + 2 - 3 ] -> 0 def sum_parse_action(x): # [ 1 + 2 - 3 ] -> 0
total = 0.0 total = 0.0
...@@ -217,4 +218,7 @@ if __name__=='__main__': ...@@ -217,4 +218,7 @@ if __name__=='__main__':
print evaluator({},{}, "-(7+5)") print evaluator({},{}, "-(7+5)")
print evaluator({},{}, "-0.33") print evaluator({},{}, "-0.33")
print evaluator({},{}, "-.33") print evaluator({},{}, "-.33")
print evaluator({},{}, "5+1*j")
print evaluator({},{}, "j||1")
print evaluator({},{}, "e^(j*pi)")
print evaluator({},{}, "5+7 QWSEKO") print evaluator({},{}, "5+7 QWSEKO")
import json import json
import math import math
import numbers
import numpy import numpy
import random import random
import scipy import scipy
...@@ -37,7 +38,7 @@ class numericalresponse(object): ...@@ -37,7 +38,7 @@ class numericalresponse(object):
def __init__(self, xml, context): def __init__(self, xml, context):
self.xml = xml self.xml = xml
self.correct_answer = contextualize_text(xml.get('answer'), context) 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', self.tolerance_xml = xml.xpath('//*[@id=$id]//responseparam[@type="tolerance"]/@default',
id=xml.get('id'))[0] id=xml.get('id'))[0]
self.tolerance = contextualize_text(self.tolerance_xml, context) self.tolerance = contextualize_text(self.tolerance_xml, context)
...@@ -49,7 +50,10 @@ class numericalresponse(object): ...@@ -49,7 +50,10 @@ class numericalresponse(object):
student_answer = student_answers[self.answer_id] student_answer = student_answers[self.answer_id]
try: try:
correct = compare_with_tolerance (evaluator(dict(),dict(),student_answer), self.correct_answer, self.tolerance) 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') raise StudentInputError('Invalid input -- please use a number only')
if correct: if correct:
...@@ -141,7 +145,7 @@ class formularesponse(object): ...@@ -141,7 +145,7 @@ class formularesponse(object):
except: except:
#traceback.print_exc() #traceback.print_exc()
raise StudentInputError("Error in formula") 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"} return {self.answer_id:"incorrect"}
if not compare_with_tolerance(student_result, instructor_result, self.tolerance): if not compare_with_tolerance(student_result, instructor_result, self.tolerance):
return {self.answer_id:"incorrect"} return {self.answer_id:"incorrect"}
...@@ -153,9 +157,9 @@ class formularesponse(object): ...@@ -153,9 +157,9 @@ class formularesponse(object):
keys and all non-numeric values stripped out. All values also keys and all non-numeric values stripped out. All values also
converted to float. Used so we can safely use Python contexts. 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 \ k.isalnum() and \
(type(d[k]) == float or type(d[k]) == int) ]) isinstance(d[k], numbers.Number)])
return d return d
def get_answers(self): def get_answers(self):
......
...@@ -20,7 +20,7 @@ class ModelsTest(unittest.TestCase): ...@@ -20,7 +20,7 @@ class ModelsTest(unittest.TestCase):
variables={'R1':2.0, 'R3':4.0} variables={'R1':2.0, 'R3':4.0}
functions={'sin':numpy.sin, 'cos':numpy.cos} 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({'R1': 2.0, 'R3':4.0}, {}, "13"), 13)
self.assertEqual(calc.evaluator(variables, functions, "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) self.assertEqual(calc.evaluator({'a': 2.2997471478310274, 'k': 9, 'm': 8, 'x': 0.66009498411213041}, {}, "5"), 5)
...@@ -30,6 +30,8 @@ class ModelsTest(unittest.TestCase): ...@@ -30,6 +30,8 @@ class ModelsTest(unittest.TestCase):
self.assertEqual(calc.evaluator(variables, functions, "R1*R3"), 8.0) 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, "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, "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 exception_happened = False
try: try:
calc.evaluator({},{}, "5+7 QWSEKO") calc.evaluator({},{}, "5+7 QWSEKO")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment