def test_single_variable_solver_handles_distribution(self): equation = Parser.parse_equation('p * -25 + (1 - p) * 5 = 0') result = Solver.single_variable(equation, 'p', print_out=True, max_iterations=20) verify(str(result), self.reporter)
def test_single_variable_solver_handles_same_variable(self): equation = Parser.parse_equation('x + x = 3') result = Solver.single_variable(equation, 'x', print_out=True, max_iterations=5) self.assertEqual(str(result), 'x = 1.5')
def test_single_variable_solver_handles_same_variable_complex(self): equation = Parser.parse_equation('2*x - 7 = 4*x + 5') result = Solver.single_variable(equation, 'x', print_out=True, max_iterations=20) self.assertEqual(str(result), 'x = -6.0')
def test_single_variable_solver_evaluates(self): equation = Parser.parse_equation('0 = 0.5*a + 3*4') result = Solver.single_variable(equation, 'a', print_out=True, max_iterations=5) verify(str(result), self.reporter)
def test_all_equation_substitutions_addition_by_same(self): equation = Parser.parse_equation('3.0 = (x)+(x)') substitution = ExpressionSubstitution(Parser.parse_expression('a + a'), Parser.parse_expression('2*a')) transformation = Transformation.apply_all_substitution_transformations( substitution) result = transformation.apply(equation) verify(str(result), self.reporter)
def test_all_equation_substitutions_simple(self): equation = Parser.parse_equation('y = (x)-(x)') substitution = ExpressionSubstitution(Parser.parse_expression('a - a'), Parser.parse_expression('0')) transformation = Transformation.apply_all_substitution_transformations( substitution) result = transformation.apply(equation) verify(str(result), self.reporter)
def solve_equation(input): assert type(input) == str if Parser.is_equation(input): equation = Parser.parse_equation(input) variables = equation.get_variables() if len(variables) != 1: raise InputException( 'Equation should have exactly 1 variable but instead has {}: {}' .format(str(len(variables)), variables)) result = Solver.single_variable(equation, variables[0]) else: expression = Parser.parse_expression(input) variables = expression.get_variables() if len(variables) != 0: raise InputException( 'Expression should have no variables but instead has the following: {}' .format(variables)) result = expression.evaluate() print(result)
def test_single_variable_solver_simple(self): equation = Parser.parse_equation('y*0.5 - 2*x = 9') result = Solver.single_variable(equation, 'y', print_out=True) verify(str(result), self.reporter)
def test_single_variable_solver_flip(self): equation = Parser.parse_equation('-3.1415 = p') result = Solver.single_variable(equation, 'p') verify(str(result), self.reporter)
def single_variable(equation, variable, print_out=False, max_iterations=1000): assert isinstance(equation, Equation) if type(variable) == str: variable = Variable(variable) assert isinstance(variable, Variable) assert type(print_out) == bool assert type(max_iterations) == int assert variable.symbol in equation.get_variables() expected_result = Operation(variable) condition = lambda x: ( (Operation.areEqual(x.lhs, expected_result) and variable.symbol not in x.rhs.get_variables())\ or x is None ) distributions = [ ExpressionSubstitution(Parser.parse_expression('a * (b + c)'), Parser.parse_expression('a * b + a * c')), ExpressionSubstitution(Parser.parse_expression('(a + b) * c'), Parser.parse_expression('a * c + b * c')), ExpressionSubstitution(Parser.parse_expression('(a + b) / c'), Parser.parse_expression('a / c + b / c')), ExpressionSubstitution(Parser.parse_expression('a * (b - c)'), Parser.parse_expression('a * b - a * c')), ExpressionSubstitution(Parser.parse_expression('(a - b) * c'), Parser.parse_expression('a * c - b * c')), ExpressionSubstitution(Parser.parse_expression('(a - b) / c'), Parser.parse_expression('a / c - b / c')), ] distributions = [ Transformation.apply_all_substitution_transformations(x) for x in distributions ] distribute = SolverStep( Transformation.each_transformation(distributions, False)) pre_solve = SolverStep( Transformation.collect_like_terms_transformation()) equation = distribute.execute_step(equation) equation = pre_solve.execute_step(equation) branches = [equation] executed_branches = set() iterations = 0 no_regrets_transformations = [ Transformation.apply_all_substitution_transformations(x)\ for x in Solver.no_regrets_substitutions ] solve_step = SolverStep(Transformation.evaluation_transformation(), terminate_on_repeat=True) solve_step_2 = SolverStep( Transformation.each_transformation(no_regrets_transformations, False)) solve_step_3 = SolverStep(Transformation.flip_transformation(variable)) solve_step_4 = SolverStep.cancellations() solve_step.next_step = solve_step_2 solve_step_2.next_step = solve_step_3 solve_step_3.next_step = solve_step_4 solve_step_4.next_step = solve_step while iterations < max_iterations: if len(branches) == 0: raise SolverException('Exhausted possible transformations.') branch = branches[0] branches = branches[1:] if print_out: print('Executing branch: {}'.format(str(branch))) result = solve_step.execute_until(branch, condition, print_out=print_out) if condition(result): final_execute_step = SolverStep( Transformation.evaluation_transformation()) return final_execute_step.execute_step(result) else: executed_branches.add(str(branch)) executed_branches.add( str(result)) # Executed already since steps terminated new_branches = dict() # We don't care about the outputs of flips or cancellations new_branch_strings = solve_step_3.previous_inputs - executed_branches for string in new_branch_strings: new_branches[string] = Parser.parse_equation(string) solve_step.clear_history() solve_step_2.clear_history() solve_step_3.clear_history() solve_step_4.clear_history() for substitution in Solver.substitutions: left_substitution_result = [ x[1] for x in substitution.get_all_substitutions(branch.lhs) ] right_substitution_result = [ x[1] for x in substitution.get_all_substitutions(branch.rhs) ] equations = [ Equation(x, branch.rhs) for x in left_substitution_result ] equations += [ Equation(branch.lhs, x) for x in right_substitution_result ] pairs = [(str(x), x) for x in equations if str(x) not in executed_branches] for k, v in pairs: new_branches[k] = v if print_out: print("New branches from {}:\n{}\n".format( str(branch), '\n'.join(new_branches.keys()))) branches += new_branches.values() branches.sort(key=lambda x: len(str(x))) iterations += 1 raise SolverException( 'Could not solve equation for a single variable. Final result: {}' .format(str(equation)))