def grade(element_html, data): element = lxml.html.fragment_fromstring(element_html) name = pl.get_string_attrib(element, 'answers-name') variables = get_variables_list( pl.get_string_attrib(element, 'variables', VARIABLES_DEFAULT)) allow_complex = pl.get_boolean_attrib(element, 'allow-complex', ALLOW_COMPLEX_DEFAULT) weight = pl.get_integer_attrib(element, 'weight', WEIGHT_DEFAULT) # Get true answer (if it does not exist, create no grade - leave it # up to the question code) a_tru = data['correct_answers'].get(name, None) if a_tru is None: return # Get submitted answer (if it does not exist, score is zero) a_sub = data['submitted_answers'].get(name, None) if a_sub is None: data['partial_scores'][name] = {'score': 0, 'weight': weight} return # Parse true answer if isinstance(a_tru, str): # this is so instructors can specify the true answer simply as a string a_tru = phs.convert_string_to_sympy(a_tru, variables, allow_complex=allow_complex) else: a_tru = phs.json_to_sympy(a_tru, allow_complex=allow_complex) # Parse submitted answer if isinstance(a_sub, str): # this is for backward-compatibility a_sub = phs.convert_string_to_sympy(a_sub, variables, allow_complex=allow_complex) else: a_sub = phs.json_to_sympy(a_sub, allow_complex=allow_complex) # Check equality correct = a_tru.equals(a_sub) if correct: data['partial_scores'][name] = {'score': 1, 'weight': weight} else: data['partial_scores'][name] = {'score': 0, 'weight': weight}
def grade(element_html, data): element = lxml.html.fragment_fromstring(element_html) name = pl.get_string_attrib(element, 'answers-name') variables = get_variables_list(pl.get_string_attrib(element, 'variables', None)) allow_complex = pl.get_boolean_attrib(element, 'allow-complex', False) weight = pl.get_integer_attrib(element, 'weight', 1) # Get true answer (if it does not exist, create no grade - leave it # up to the question code) a_tru = data['correct_answers'].get(name, None) if a_tru is None: return # Get submitted answer (if it does not exist, score is zero) a_sub = data['submitted_answers'].get(name, None) if a_sub is None: data['partial_scores'][name] = {'score': 0, 'weight': weight} return # Parse true answer if isinstance(a_tru, str): # this is so instructors can specify the true answer simply as a string a_tru = phs.convert_string_to_sympy(a_tru, variables, allow_complex=allow_complex) else: a_tru = phs.json_to_sympy(a_tru, allow_complex=allow_complex) # Parse submitted answer if isinstance(a_sub, str): # this is for backward-compatibility a_sub = phs.convert_string_to_sympy(a_sub, variables, allow_complex=allow_complex) else: a_sub = phs.json_to_sympy(a_sub, allow_complex=allow_complex) # Check equality correct = a_tru.equals(a_sub) if correct: data['partial_scores'][name] = {'score': 1, 'weight': weight} else: data['partial_scores'][name] = {'score': 0, 'weight': weight}
def from_json(v): """from_json(v) If v has the format {'_type':..., '_value':...} as would have been created using to_json(...), then it is replaced: '_type': 'complex' -> complex '_type': 'ndarray' -> non-complex ndarray '_type': 'complex_ndarray' -> complex ndarray '_type': 'sympy' -> sympy.Expr '_type': 'sympy_matrix' -> sympy.Matrix If v encodes an ndarray and has the field '_dtype', this function recovers its dtype. This function does not try to recover information like the assumptions on variables in a sympy expression. If v does not have the format {'_type':..., '_value':...}, then it is returned without change. """ if isinstance(v, dict): if '_type' in v: if v['_type'] == 'complex': if ('_value' in v) and ('real' in v['_value']) and ('imag' in v['_value']): return complex(v['_value']['real'], v['_value']['imag']) else: raise Exception( 'variable of type complex should have value with real and imaginary pair' ) elif v['_type'] == 'ndarray': if ('_value' in v): if ('_dtype' in v): return np.array(v['_value']).astype(v['_dtype']) else: return np.array(v['_value']) else: raise Exception( 'variable of type ndarray should have value') elif v['_type'] == 'complex_ndarray': if ('_value' in v) and ('real' in v['_value']) and ('imag' in v['_value']): if ('_dtype' in v): return (np.array(v['_value']['real']) + np.array(v['_value']['imag']) * 1j).astype( v['_dtype']) else: return np.array(v['_value']['real']) + np.array( v['_value']['imag']) * 1j else: raise Exception( 'variable of type complex_ndarray should have value with real and imaginary pair' ) elif v['_type'] == 'sympy': return json_to_sympy(v) elif v['_type'] == 'sympy_matrix': if ('_value' in v) and ('_variables' in v) and ('_shape' in v): value = v['_value'] variables = v['_variables'] shape = v['_shape'] M = sympy.Matrix.zeros(shape[0], shape[1]) for i in range(0, shape[0]): for j in range(0, shape[1]): M[i, j] = convert_string_to_sympy( value[i][j], variables) return M else: raise Exception( 'variable of type sympy_matrix should have value, variables, and shape' ) elif v['_type'] == 'dataframe': if ('_value' in v) and ('index' in v['_value']) and ( 'columns' in v['_value']) and ('data' in v['_value']): val = v['_value'] return pandas.DataFrame(index=val['index'], columns=val['columns'], data=val['data']) else: raise Exception( 'variable of type dataframe should have value with index, columns, and data' ) else: raise Exception('variable has unknown type {:s}'.format( v['_type'])) return v
def render(element_html, data): element = lxml.html.fragment_fromstring(element_html) name = pl.get_string_attrib(element, 'answers-name') label = pl.get_string_attrib(element, 'label', None) variables_string = pl.get_string_attrib(element, 'variables', None) variables = get_variables_list(variables_string) display = pl.get_string_attrib(element, 'display', 'inline') allow_complex = pl.get_boolean_attrib(element, 'allow-complex', False) imaginary_unit = pl.get_string_attrib(element, 'imaginary-unit-for-display', 'i') if data['panel'] == 'question': editable = data['editable'] raw_submitted_answer = data['raw_submitted_answers'].get(name, None) operators = ', '.join(['cos', 'sin', 'tan', 'exp', 'log', 'sqrt', '( )', '+', '-', '*', '/', '^', '**']) constants = ', '.join(['pi, e']) info_params = { 'format': True, 'variables': variables_string, 'operators': operators, 'constants': constants, 'allow_complex': allow_complex, } with open('pl-symbolic-input.mustache', 'r', encoding='utf-8') as f: info = chevron.render(f, info_params).strip() with open('pl-symbolic-input.mustache', 'r', encoding='utf-8') as f: info_params.pop('format', None) info_params['shortformat'] = True shortinfo = chevron.render(f, info_params).strip() html_params = { 'question': True, 'name': name, 'label': label, 'editable': editable, 'info': info, 'shortinfo': shortinfo, 'uuid': pl.get_uuid(), 'allow_complex': allow_complex, } partial_score = data['partial_scores'].get(name, {'score': None}) score = partial_score.get('score', None) if score is not None: try: score = float(score) if score >= 1: html_params['correct'] = True elif score > 0: html_params['partial'] = math.floor(score * 100) else: html_params['incorrect'] = True except Exception: raise ValueError('invalid score' + score) if display == 'inline': html_params['inline'] = True elif display == 'block': html_params['block'] = True else: raise ValueError('method of display "%s" is not valid (must be "inline" or "block")' % display) if raw_submitted_answer is not None: html_params['raw_submitted_answer'] = escape(raw_submitted_answer) with open('pl-symbolic-input.mustache', 'r', encoding='utf-8') as f: html = chevron.render(f, html_params).strip() elif data['panel'] == 'submission': parse_error = data['format_errors'].get(name, None) html_params = { 'submission': True, 'label': label, 'parse_error': parse_error, 'uuid': pl.get_uuid() } if parse_error is None: a_sub = data['submitted_answers'][name] if isinstance(a_sub, str): # this is for backward-compatibility a_sub = phs.convert_string_to_sympy(a_sub, variables, allow_complex=allow_complex) else: a_sub = phs.json_to_sympy(a_sub, allow_complex=allow_complex) a_sub = a_sub.subs(sympy.I, sympy.Symbol(imaginary_unit)) html_params['a_sub'] = sympy.latex(a_sub) else: raw_submitted_answer = data['raw_submitted_answers'].get(name, None) if raw_submitted_answer is not None: html_params['raw_submitted_answer'] = escape(raw_submitted_answer) partial_score = data['partial_scores'].get(name, {'score': None}) score = partial_score.get('score', None) if score is not None: try: score = float(score) if score >= 1: html_params['correct'] = True elif score > 0: html_params['partial'] = math.floor(score * 100) else: html_params['incorrect'] = True except Exception: raise ValueError('invalid score' + score) if display == 'inline': html_params['inline'] = True elif display == 'block': html_params['block'] = True else: raise ValueError('method of display "%s" is not valid (must be "inline" or "block")' % display) with open('pl-symbolic-input.mustache', 'r', encoding='utf-8') as f: html = chevron.render(f, html_params).strip() elif data['panel'] == 'answer': a_tru = data['correct_answers'].get(name, None) if a_tru is not None: if isinstance(a_tru, str): # this is so instructors can specify the true answer simply as a string a_tru = phs.convert_string_to_sympy(a_tru, variables, allow_complex=allow_complex) else: a_tru = phs.json_to_sympy(a_tru, allow_complex=allow_complex) a_tru = a_tru.subs(sympy.I, sympy.Symbol(imaginary_unit)) html_params = { 'answer': True, 'label': label, 'a_tru': sympy.latex(a_tru) } with open('pl-symbolic-input.mustache', 'r', encoding='utf-8') as f: html = chevron.render(f, html_params).strip() else: html = '' else: raise Exception('Invalid panel type: %s' % data['panel']) return html
def parse(element_html, data): element = lxml.html.fragment_fromstring(element_html) name = pl.get_string_attrib(element, 'answers-name') variables = get_variables_list(pl.get_string_attrib(element, 'variables', None)) allow_complex = pl.get_boolean_attrib(element, 'allow-complex', False) imaginary_unit = pl.get_string_attrib(element, 'imaginary-unit-for-display', 'i') # Get submitted answer or return parse_error if it does not exist a_sub = data['submitted_answers'].get(name, None) if not a_sub: data['format_errors'][name] = 'No submitted answer.' data['submitted_answers'][name] = None return # Parse the submitted answer and put the result in a string try: # Replace '^' with '**' wherever it appears. In MATLAB, either can be used # for exponentiation. In python, only the latter can be used. a_sub = a_sub.replace('^', '**') # Strip whitespace a_sub = a_sub.strip() # Convert safely to sympy a_sub_parsed = phs.convert_string_to_sympy(a_sub, variables, allow_complex=allow_complex) # If complex numbers are not allowed, raise error if expression has the imaginary unit if (not allow_complex) and (a_sub_parsed.has(sympy.I)): a_sub_parsed = a_sub_parsed.subs(sympy.I, sympy.Symbol(imaginary_unit)) s = 'Your answer was simplified to this, which contains a complex number (denoted ${:s}$): $${:s}$$'.format(imaginary_unit, sympy.latex(a_sub_parsed)) data['format_errors'][name] = s data['submitted_answers'][name] = None return # Store result as json. a_sub_json = phs.sympy_to_json(a_sub_parsed, allow_complex=allow_complex) except phs.HasFloatError as err: s = 'Your answer contains the floating-point number ' + str(err.n) + '. ' s += 'All numbers must be expressed as integers (or ratios of integers). ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None return except phs.HasComplexError as err: s = 'Your answer contains the complex number ' + str(err.n) + '. ' s += 'All numbers must be expressed as integers (or ratios of integers). ' if allow_complex: s += 'To include a complex number in your expression, write it as the product of an integer with the imaginary unit <code>i</code> or <code>j</code>. ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None return except phs.HasInvalidExpressionError as err: s = 'Your answer has an invalid expression. ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None return except phs.HasInvalidFunctionError as err: s = 'Your answer calls an invalid function "' + err.text + '". ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None return except phs.HasInvalidVariableError as err: s = 'Your answer refers to an invalid variable "' + err.text + '". ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None return except phs.HasParseError as err: s = 'Your answer has a syntax error. ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None return except phs.HasEscapeError as err: s = 'Your answer must not contain the character "\\". ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None return except phs.HasCommentError as err: s = 'Your answer must not contain the character "#". ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None return except Exception as err: data['format_errors'][name] = 'Invalid format.' data['submitted_answers'][name] = None return # Make sure we can parse the json again try: # Convert safely to sympy phs.json_to_sympy(a_sub_json, allow_complex=allow_complex) # Finally, store the result data['submitted_answers'][name] = a_sub_json except Exception as err: s = 'Your answer was simplified to this, which contains an invalid expression: $${:s}$$'.format(sympy.latex(a_sub_parsed)) data['format_errors'][name] = s data['submitted_answers'][name] = None
def render(element_html, data): element = lxml.html.fragment_fromstring(element_html) name = pl.get_string_attrib(element, 'answers-name') label = pl.get_string_attrib(element, 'label', LABEL_DEFAULT) variables_string = pl.get_string_attrib(element, 'variables', VARIABLES_DEFAULT) variables = get_variables_list(variables_string) display = pl.get_string_attrib(element, 'display', DISPLAY_DEFAULT) allow_complex = pl.get_boolean_attrib(element, 'allow-complex', ALLOW_COMPLEX_DEFAULT) imaginary_unit = pl.get_string_attrib(element, 'imaginary-unit-for-display', IMAGINARY_UNIT_FOR_DISPLAY_DEFAULT) size = pl.get_integer_attrib(element, 'size', SIZE_DEFAULT) operators = [ 'cos', 'sin', 'tan', 'exp', 'log', 'sqrt', '( )', '+', '-', '*', '/', '^', '**' ] constants = ['pi', 'e'] if data['panel'] == 'question': editable = data['editable'] raw_submitted_answer = data['raw_submitted_answers'].get(name, None) info_params = { 'format': True, 'variables': variables, 'operators': operators, 'constants': constants, 'allow_complex': allow_complex, } with open('pl-symbolic-input.mustache', 'r', encoding='utf-8') as f: info = chevron.render(f, info_params).strip() with open('pl-symbolic-input.mustache', 'r', encoding='utf-8') as f: info_params.pop('format', None) info_params['shortformat'] = True shortinfo = chevron.render(f, info_params).strip() html_params = { 'question': True, 'name': name, 'label': label, 'editable': editable, 'info': info, 'shortinfo': shortinfo, 'size': size, 'show_info': pl.get_boolean_attrib(element, 'show-help-text', SHOW_HELP_TEXT_DEFAULT), 'uuid': pl.get_uuid(), 'allow_complex': allow_complex, 'show_placeholder': size >= PLACEHOLDER_TEXT_THRESHOLD } partial_score = data['partial_scores'].get(name, {'score': None}) score = partial_score.get('score', None) if score is not None: try: score = float(score) if score >= 1: html_params['correct'] = True elif score > 0: html_params['partial'] = math.floor(score * 100) else: html_params['incorrect'] = True except Exception: raise ValueError('invalid score' + score) if display == 'inline': html_params['inline'] = True elif display == 'block': html_params['block'] = True else: raise ValueError( 'method of display "%s" is not valid (must be "inline" or "block")' % display) if raw_submitted_answer is not None: html_params['raw_submitted_answer'] = escape(raw_submitted_answer) with open('pl-symbolic-input.mustache', 'r', encoding='utf-8') as f: html = chevron.render(f, html_params).strip() elif data['panel'] == 'submission': parse_error = data['format_errors'].get(name, None) html_params = { 'submission': True, 'label': label, 'parse_error': parse_error, 'uuid': pl.get_uuid() } if parse_error is None and name in data['submitted_answers']: a_sub = data['submitted_answers'][name] if isinstance(a_sub, str): # this is for backward-compatibility a_sub = phs.convert_string_to_sympy( a_sub, variables, allow_complex=allow_complex) else: a_sub = phs.json_to_sympy(a_sub, allow_complex=allow_complex) a_sub = a_sub.subs(sympy.I, sympy.Symbol(imaginary_unit)) html_params['a_sub'] = sympy.latex(a_sub) elif name not in data['submitted_answers']: html_params['missing_input'] = True html_params['parse_error'] = None else: # Use the existing format text in the invalid popup. info_params = { 'format': True, 'variables': variables, 'operators': operators, 'constants': constants, 'allow_complex': allow_complex, } with open('pl-symbolic-input.mustache', 'r', encoding='utf-8') as f: info = chevron.render(f, info_params).strip() # Render invalid popup raw_submitted_answer = data['raw_submitted_answers'].get( name, None) with open('pl-symbolic-input.mustache', 'r', encoding='utf-8') as f: parse_error += chevron.render(f, { 'format_error': True, 'format_string': info }).strip() html_params['parse_error'] = parse_error if raw_submitted_answer is not None: html_params['raw_submitted_answer'] = pl.escape_unicode_string( raw_submitted_answer) partial_score = data['partial_scores'].get(name, {'score': None}) score = partial_score.get('score', None) if score is not None: try: score = float(score) if score >= 1: html_params['correct'] = True elif score > 0: html_params['partial'] = math.floor(score * 100) else: html_params['incorrect'] = True except Exception: raise ValueError('invalid score' + score) if display == 'inline': html_params['inline'] = True elif display == 'block': html_params['block'] = True else: raise ValueError( 'method of display "%s" is not valid (must be "inline" or "block")' % display) html_params['error'] = html_params['parse_error'] or html_params.get( 'missing_input', False) with open('pl-symbolic-input.mustache', 'r', encoding='utf-8') as f: html = chevron.render(f, html_params).strip() elif data['panel'] == 'answer': a_tru = data['correct_answers'].get(name, None) if a_tru is not None: if isinstance(a_tru, str): # this is so instructors can specify the true answer simply as a string a_tru = phs.convert_string_to_sympy( a_tru, variables, allow_complex=allow_complex) else: a_tru = phs.json_to_sympy(a_tru, allow_complex=allow_complex) a_tru = a_tru.subs(sympy.I, sympy.Symbol(imaginary_unit)) html_params = { 'answer': True, 'label': label, 'a_tru': sympy.latex(a_tru) } with open('pl-symbolic-input.mustache', 'r', encoding='utf-8') as f: html = chevron.render(f, html_params).strip() else: html = '' else: raise Exception('Invalid panel type: %s' % data['panel']) return html
def parse(element_html, data): element = lxml.html.fragment_fromstring(element_html) name = pl.get_string_attrib(element, 'answers-name') variables = get_variables_list(pl.get_string_attrib(element, 'variables', None)) allow_complex = pl.get_boolean_attrib(element, 'allow-complex', False) imaginary_unit = pl.get_string_attrib(element, 'imaginary-unit-for-display', 'i') # Get submitted answer or return parse_error if it does not exist a_sub = data['submitted_answers'].get(name, None) if not a_sub: data['format_errors'][name] = 'No submitted answer.' data['submitted_answers'][name] = None return # Parse the submitted answer and put the result in a string try: # Replace '^' with '**' wherever it appears. In MATLAB, either can be used # for exponentiation. In python, only the latter can be used. a_sub = a_sub.replace('^', '**') # Strip whitespace a_sub = a_sub.strip() # Convert safely to sympy a_sub_parsed = phs.convert_string_to_sympy(a_sub, variables, allow_complex=allow_complex) # If complex numbers are not allowed, raise error if expression has the imaginary unit if (not allow_complex) and (a_sub_parsed.has(sympy.I)): a_sub_parsed = a_sub_parsed.subs(sympy.I, sympy.Symbol(imaginary_unit)) s = 'Your answer was simplified to this, which contains a complex number (denoted ${:s}$): $${:s}$$'.format(imaginary_unit, sympy.latex(a_sub_parsed)) data['format_errors'][name] = s data['submitted_answers'][name] = None return # Store result as json. a_sub_json = phs.sympy_to_json(a_sub_parsed, allow_complex=allow_complex) except phs.HasFloatError as err: s = 'Your answer contains the floating-point number ' + str(err.n) + '. ' s += 'All numbers must be expressed as integers (or ratios of integers). ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None return except phs.HasComplexError as err: s = 'Your answer contains the complex number ' + str(err.n) + '. ' s += 'All numbers must be expressed as integers (or ratios of integers). ' if allow_complex: s += 'To include a complex number in your expression, write it as the product of an integer with the imaginary unit <code>i</code> or <code>j</code>. ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None return except phs.HasInvalidExpressionError as err: s = 'Your answer has an invalid expression. ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None return except phs.HasInvalidFunctionError as err: s = 'Your answer calls an invalid function "' + err.text + '". ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None return except phs.HasInvalidVariableError as err: s = 'Your answer refers to an invalid variable "' + err.text + '". ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None return except phs.HasParseError as err: s = 'Your answer has a syntax error. ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None return except phs.HasEscapeError as err: s = 'Your answer must not contain the character "\\". ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None return except phs.HasCommentError as err: s = 'Your answer must not contain the character "#". ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None return except Exception: data['format_errors'][name] = 'Invalid format.' data['submitted_answers'][name] = None return # Make sure we can parse the json again try: # Convert safely to sympy phs.json_to_sympy(a_sub_json, allow_complex=allow_complex) # Finally, store the result data['submitted_answers'][name] = a_sub_json except Exception: s = 'Your answer was simplified to this, which contains an invalid expression: $${:s}$$'.format(sympy.latex(a_sub_parsed)) data['format_errors'][name] = s data['submitted_answers'][name] = None
def from_json(v): """from_json(v) If v has the format {'_type':..., '_value':...} as would have been created using to_json(...), then it is replaced: '_type': 'complex' -> complex '_type': 'ndarray' -> non-complex ndarray '_type': 'complex_ndarray' -> complex ndarray '_type': 'sympy' -> sympy.Expr '_type': 'sympy_matrix' -> sympy.Matrix If v encodes an ndarray and has the field '_dtype', this function recovers its dtype. This function does not try to recover information like the assumptions on variables in a sympy expression. If v does not have the format {'_type':..., '_value':...}, then it is returned without change. """ if isinstance(v, dict): if '_type' in v: if v['_type'] == 'complex': if ('_value' in v) and ('real' in v['_value']) and ('imag' in v['_value']): return complex(v['_value']['real'], v['_value']['imag']) else: raise Exception('variable of type complex should have value with real and imaginary pair') elif v['_type'] == 'ndarray': if ('_value' in v): if ('_dtype' in v): return np.array(v['_value']).astype(v['_dtype']) else: return np.array(v['_value']) else: raise Exception('variable of type ndarray should have value') elif v['_type'] == 'complex_ndarray': if ('_value' in v) and ('real' in v['_value']) and ('imag' in v['_value']): if ('_dtype' in v): return (np.array(v['_value']['real']) + np.array(v['_value']['imag']) * 1j).astype(v['_dtype']) else: return np.array(v['_value']['real']) + np.array(v['_value']['imag']) * 1j else: raise Exception('variable of type complex_ndarray should have value with real and imaginary pair') elif v['_type'] == 'sympy': return json_to_sympy(v) elif v['_type'] == 'sympy_matrix': if ('_value' in v) and ('_variables' in v) and ('_shape' in v): value = v['_value'] variables = v['_variables'] shape = v['_shape'] M = sympy.Matrix.zeros(shape[0], shape[1]) for i in range(0, shape[0]): for j in range(0, shape[1]): M[i, j] = convert_string_to_sympy(value[i][j], variables) return M else: raise Exception('variable of type sympy_matrix should have value, variables, and shape') else: raise Exception('variable has unknown type {:s}'.format(v['_type'])) return v