def cancellations(): cancels = [ EquationCancellation(OperationType.PLUS(), OperationType.MINUS()), EquationCancellation(OperationType.MINUS(), OperationType.PLUS()), EquationCancellation(OperationType.TIMES(), OperationType.DIVIDE()), EquationCancellation(OperationType.DIVIDE(), OperationType.TIMES()) ] transformations = [x.as_transformation() for x in cancels] return SolverStep(transformations)
def test_equation_cancellation_with_negative(self): lhs = Parser(Tokenizer.tokenize('x + -4')).parse() rhs = Parser(Tokenizer.tokenize('y')).parse() equation = Equation(lhs, rhs) addition_cancellation = EquationCancellation(OperationType.PLUS(), OperationType.MINUS()) self.assertTrue(addition_cancellation.is_applicable_to(equation)) result = addition_cancellation.apply(equation) verify(str(result), self.reporter)
def test_equation_cancellation_is_applicable(self): lhs = Parser(Tokenizer.tokenize('x + 4')).parse() rhs = Parser(Tokenizer.tokenize('y')).parse() equation = Equation(lhs, rhs) addition_cancellation = EquationCancellation(OperationType.PLUS(), OperationType.MINUS()) self.assertTrue(addition_cancellation.is_applicable_to(equation)) flipped = equation.flip() self.assertFalse(addition_cancellation.is_applicable_to(flipped))
def apply_function(equation): if equation.lhs.operation_type.arity == 0: equation = equation.flip() if (equation.rhs.operation_type.arity == 0) and (equation.rhs.operation_type.symbol == '0'): homogenized = equation.lhs else: homogenized = Operation(OperationType.MINUS(), [equation.lhs, equation.rhs]) collected = CollectedTerms.try_parse_expression(homogenized) if collected is None: return equation collected = collected.as_expression return Equation(collected, Operation(Variable(0)))
def test_complex_single_solution_solve(self): lhs = Parser(Tokenizer.tokenize('x * 4 - 18')).parse() rhs = Parser(Tokenizer.tokenize('2')).parse() equation = Equation(lhs, rhs) cancellations = [ EquationCancellation(OperationType.PLUS(), OperationType.MINUS()), EquationCancellation(OperationType.MINUS(), OperationType.PLUS()), EquationCancellation(OperationType.TIMES(), OperationType.DIVIDE()), EquationCancellation(OperationType.DIVIDE(), OperationType.TIMES()) ] transformations = list( map(lambda x: x.as_transformation(), cancellations)) step = SolverStep(transformations) step.next_step = step condition = lambda x: str(x.lhs) == 'x' result = step.execute_until(equation, condition) verify(str(result), self.reporter)
def test_evaluate_where_possible_complex(self): two_plus_two = Operation(OperationType.PLUS(), [Variable(2.0), Variable(2.0)]) two_plus_two_divided_by_four = Operation( OperationType.DIVIDE(), [two_plus_two, Variable(4)]) three_minus_x = Operation(OperationType.MINUS(), [Variable(3.0), Variable('x')]) seven_plus_five = Operation(OperationType.PLUS(), [Variable(7), Variable(5)]) three_minus_x_over_seven_plus_five = Operation( OperationType.DIVIDE(), [three_minus_x, seven_plus_five]) expression = Operation( OperationType.TIMES(), [two_plus_two_divided_by_four, three_minus_x_over_seven_plus_five]) verify(str(expression.evaluate_where_possible()), self.reporter)
class InfixParselet: token_map = { TokenType.PLUS: OperationType.PLUS(), TokenType.MINUS: OperationType.MINUS(), TokenType.TIMES: OperationType.TIMES(), TokenType.DIVIDES: OperationType.DIVIDE(), TokenType.EXPONENTIATES: OperationType.EXPONENTIATE() } # Enforce order of operations # If precedence <= max_priority, parser will parse only the next substatement # If priority > max_priority, parser will parse everything to the right precedence_map = { TokenType.EXPONENTIATES: 3, TokenType.TIMES: 2, TokenType.DIVIDES: 2, TokenType.PLUS: 1, TokenType.MINUS: 1 } def __init__(self, token): assert isinstance(token, Token) assert token.token_type in self.token_map.keys() self._operation_type = self.token_map[token.token_type] self.precedence = self.precedence_map[token.token_type] def parse(self, parser, left): assert isinstance(parser, Parser) assert isinstance(left, Operation) right = parser.parse(self.precedence) return Operation(self._operation_type, [left, right]) @staticmethod def get_next_precedence(parser): assert isinstance(parser, Parser) token = parser.peek() if token.token_type in InfixParselet.precedence_map.keys(): return InfixParselet.precedence_map[token.token_type] else: return 0