def calculate_answer(s, domain): """Calculates a string using sympy. :param s: String to be calculated :param domain: The domain of the variables. :return: A latex version of the calculated string. """ try: domain = json.loads(domain) except ValueError: pass try: if not is_number(s): # Small optimization s = remove_unnecessary(s) s = str(latex_to_sympy(s)) s = s.replace('*)', ')*') s = s.replace('?)@', ')?@') s = parse_expr(s, transformations=standard_transformations + (convert_xor, implicit_multiplication_application,), global_dict=None, evaluate=False) s = latex(sympify(str(s))) # Sometimes sympify returns the value 'zoo' else: if domain != '': s = round_answer(domain, float(s)) except Exception as e: print('exception in calculate answer') print(e) return str(s)
def test_template(template): """Tests if the creation of a template ends up with a valid template. Returns 1/0 for success/failure.""" got_trough_test = 0 # 1 if template got through test, and 0 if not. # Make numbers, check condition, check calculations random_domain = template.random_domain # Efficiency note: it might be faster to pass the domain list, instead of getting them from template every time. answer = template.answer question = template.question_text solution = template.solution conditions = template.conditions conditions = remove_unnecessary(conditions) variable_dict = generate_valid_numbers(question, random_domain, "", False) inserted_conditions = string_replace(conditions, variable_dict) if len(conditions) > 1: conditions_pass = sympify(latex_to_sympy(inserted_conditions)) else: conditions_pass = True if conditions_pass: answer = string_replace(answer, variable_dict) solution = string_replace(solution, variable_dict) try: answer = parse_answer(answer, random_domain) parse_solution(solution, random_domain) # Checks if solution can be parsed got_trough_test = 1 except Exception: pass if answer == 'error': got_trough_test = 0 return got_trough_test
def check_answer(user_answer, answer, template_type, margin_for_error=0): """Checks if the answer the user gave is correct. :param user_answer: A list containing the answer(s) the user gave. :param answer: A list containing the answer(s) to the template. :param template_type: A string detailing how the template is presented. :return: Boolean of whether the answer is correct """ if (margin_for_error is None) or (margin_for_error == ''): margin_for_error = '0' if template_type != 'normal': # Reverse iteration to avoid index out of bounds when elements get deleted. for s in range(len(answer)-1, -1, -1): try: if s == '': del user_answer[s] elif parse_using_sympy_simplify(latex_to_sympy('(' + user_answer[s] + ') - ' + str(margin_for_error)) + ' <= ' + latex_to_sympy(answer[s]) + ' <= ' + latex_to_sympy('(' + user_answer[s] + ') + '+ str(margin_for_error))): del user_answer[s] except TypeError or SyntaxError: if parse_using_sympy_simplify(latex_to_sympy(answer[s]) + ' == ' + latex_to_sympy(user_answer[s])): del user_answer[s] break else: for s in answer: for us in user_answer: print('testing') print(margin_for_error) if margin_for_error != 0: try: if parse_using_sympy_simplify(latex_to_sympy('(' + us + ') - ' + margin_for_error) + ' <= ' + latex_to_sympy(s) + ' <= ' + latex_to_sympy('(' + us + ') + '+ margin_for_error)): user_answer.remove(us) break except TypeError: if parse_using_sympy_simplify(latex_to_sympy(s) + ' == ' + latex_to_sympy(us)): user_answer.remove(us) break elif parse_using_sympy_simplify(latex_to_sympy(s) + ' == ' + latex_to_sympy(us)): user_answer.remove(us) break if user_answer == []: # Can not be written as user_answer is [], even though pep says otherwise. right_answer = True else: right_answer = False return right_answer
def parenthesis_remover(s): """removes parenthesises from expressions and checks if the expression is still valid.""" s = s.replace(')(', ')*(') s = s.replace('§', '+paragraftegn+') s = s.replace('(+', '(') s = s.replace('(+', '(') pairs = find_pairs(s, '(', ')') removable = [] for pair in pairs: temp_s = remove_all_from_list(s, pair) try: # Note: +0 is added so the string never ends with + (which would stop sympy) if parse_using_sympy(latex_to_sympy(temp_s) + '+0' + '==' + latex_to_sympy(s) + '+0'): removable.append(pair[0]) removable.append(pair[1]) except Exception as e: print('exception in parenthesis remover:') print(e) print(s) print('^ string that failed. end of exception.') s = remove_all_from_list(s, removable) #s = replace_key_with_value(s, replace_dict) s = s.replace('+parenthesisleft+', '(') s = s.replace('+parenthesisright+', ')') s = s.replace('+erlik+', '=') s = s.replace('+paragraftegn+', '§') s = s.replace('+-', '-') s = s.replace('--', '+') s = s.replace('- -', '+') s = s.replace('+ -', '-') s = s.replace('§+', '§') s = s.replace('=+', '=') s = s.replace('^{+', '^{') s = s.replace('(+', '(') return s
def check_conditions(conditions, variable_dict, domain_dict, domain_list): """A function that checks if the generated variables pass the conditions and generates new ones until they do. :param conditions: The conditions of the template. :param variable_dict: List of variables. :param domain_dict: the domain of the variables. :param domain_list: a dict with the domain list. :return: List of variables that pass the conditions of the given template. """ conditions = remove_unnecessary(conditions) # Check conditions --> if false: change a variable -> check conditions inserted_conditions = string_replace(conditions, variable_dict) while not parse_expr(latex_to_sympy(inserted_conditions), transformations=standard_transformations + (convert_xor, implicit_multiplication_application,), global_dict=None, evaluate=True): variable_to_change = choice(list(variable_dict.keys())) # Chose a random key from variable_dict if domain_list[variable_to_change]: variable_dict[variable_to_change] = make_number_from_list(domain_dict[variable_to_change]) else: variable_dict[variable_to_change] = new_random_value(variable_to_change, domain_dict) inserted_conditions = string_replace(conditions, variable_dict) return variable_dict
def make_number_from_list(domain): return sympify(latex_to_sympy(choice(domain)))