This commit is contained in:
Bridger Maxwell
2012-02-04 11:53:42 -05:00
7 changed files with 127 additions and 11 deletions

View File

@@ -1,17 +1,41 @@
import copy
import math
import operator
import numpy
from pyparsing import Word, alphas, nums, oneOf, Literal
from pyparsing import ZeroOrMore, OneOrMore, StringStart
from pyparsing import StringEnd, Optional, Forward
from pyparsing import CaselessLiteral, Group, StringEnd
from pyparsing import NoMatch, stringEnd
default_functions = {'sin' : numpy.sin,
'cos' : numpy.cos,
'tan' : numpy.tan,
'sqrt': numpy.sqrt,
'log10':numpy.log10,
'log2':numpy.log2,
'ln': numpy.log,
'arccos':numpy.arccos,
'arcsin':numpy.arcsin,
'arctan':numpy.arctan,
'abs':numpy.abs
}
default_variables = {'j':numpy.complex(0,1),
'e':numpy.complex(numpy.e)
}
def evaluator(variables, functions, string):
''' Evaluate an expression. Variables are passed as a dictionary
from string to value. Unary functions are passed as a dictionary
from string to function '''
all_variables = copy.copy(default_variables)
all_variables.update(variables)
all_functions = copy.copy(default_functions)
all_functions.update(functions)
if string.strip() == "":
return float('nan')
ops = { "^" : operator.pow,
@@ -38,7 +62,7 @@ def evaluator(variables, functions, string):
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) == float] # Ignore ^
x = [e for e in x if type(e) in [float, numpy.float64, numpy.complex]] # Ignore ^
x.reverse()
x=reduce(lambda a,b:b**a, x)
return x
@@ -68,7 +92,7 @@ def evaluator(variables, functions, string):
prod=op(prod, e)
return prod
def func_parse_action(x):
return [functions[x[0]](x[1])]
return [all_functions[x[0]](x[1])]
number_suffix=reduce(lambda a,b:a|b, map(Literal,suffixes.keys()), NoMatch()) # SI suffixes and percent
(dot,minus,plus,times,div,lpar,rpar,exp)=map(Literal,".-+*/()^")
@@ -94,14 +118,14 @@ def evaluator(variables, functions, string):
# Handle variables passed in. E.g. if we have {'R':0.5}, we make the substitution.
# Special case for no variables because of how we understand PyParsing is put together
if len(variables)>0:
varnames = sreduce(lambda x,y:x|y, map(lambda x: CaselessLiteral(x), variables.keys()))
varnames.setParseAction(lambda x:map(lambda y:variables[y], x))
if len(all_variables)>0:
varnames = sreduce(lambda x,y:x|y, map(lambda x: CaselessLiteral(x), all_variables.keys()))
varnames.setParseAction(lambda x:map(lambda y:all_variables[y], x))
else:
varnames=NoMatch()
# Same thing for functions.
if len(functions)>0:
funcnames = sreduce(lambda x,y:x|y, map(lambda x: CaselessLiteral(x), functions.keys()))
if len(all_functions)>0:
funcnames = sreduce(lambda x,y:x|y, map(lambda x: CaselessLiteral(x), all_functions.keys()))
function = funcnames+lpar.suppress()+expr+rpar.suppress()
function.setParseAction(func_parse_action)
else:
@@ -119,7 +143,7 @@ def evaluator(variables, functions, string):
if __name__=='__main__':
variables={'R1':2.0, 'R3':4.0}
functions={'sin':math.sin, 'cos':math.cos}
functions={'sin':numpy.sin, 'cos':numpy.cos}
print "X",evaluator(variables, functions, "10000||sin(7+5)-6k")
print "X",evaluator(variables, functions, "13")
print evaluator({'R1': 2.0, 'R3':4.0}, {}, "13")

View File

@@ -90,7 +90,7 @@ def modx_dispatch(request, module=None, dispatch=None, id=None):
ajax_return=instance.handle_ajax(dispatch, request.POST)
# Save the state back to the database
s.state=instance.get_state()
if not instance.get_score():
if instance.get_score():
s.grade=instance.get_score()['score']
s.save()
# Return whatever the module wanted to return to the client/caller

View File

@@ -13,7 +13,9 @@ from django.http import HttpResponse, Http404
from django.shortcuts import redirect
from django.template import Context, loader
from mitxmako.shortcuts import render_to_response, render_to_string
#from django.views.decorators.csrf import ensure_csrf_cookie
from django.db import connection
from django.views.decorators.cache import cache_control
from lxml import etree
@@ -31,6 +33,7 @@ etree.set_default_parser(etree.XMLParser(dtd_validation=False, load_dtd=False,
template_imports={'urllib':urllib}
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
def profile(request):
''' User profile. Show username, location, etc, as well as grades .
We need to allow the user to change some of these settings .'''
@@ -207,6 +210,7 @@ def render_accordion(request,course,chapter,section):
return {'init_js':render_to_string('accordion_init.js',context),
'content':render_to_string('accordion.html',context)}
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
def index(request, course="6.002 Spring 2012", chapter="Using the System", section="Hints"):
''' Displays courseware accordion, and any associated content.
'''