def test_evaluate_where_possible_simple(self): two_plus_two = Operation(OperationType.PLUS(), [Variable(2.0), Variable(2.0)]) expression = Operation(OperationType.DIVIDE(), [Variable('x'), two_plus_two]) verify(str(expression.evaluate_where_possible()), self.reporter)
def test_complex_operation(self): two = Operation(OperationType.POSITIVE(), [Variable(2)]) negative_x = Operation(OperationType.NEGATIVE(), [Variable('x')]) op = Operation(OperationType.TIMES(), [two, negative_x]) verify(str(op), self.reporter)
def test_evaluation_simple(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)]) self.assertTrue(two_plus_two_divided_by_four.is_evaluatable()) self.assertAlmostEqual(two_plus_two_divided_by_four.evaluate(), 1)
def test_evaluation_trivial(self): two = Operation(OperationType.POSITIVE(), [Variable('2')]) self.assertTrue(two.is_evaluatable()) self.assertAlmostEqual(two.evaluate(), 2) x = Operation(OperationType.POSITIVE(), [Variable('x')]) self.assertFalse(x.is_evaluatable())
def test_equation(self): two = Operation(OperationType.POSITIVE(), [Variable(2)]) negative_x = Operation(OperationType.NEGATIVE(), [Variable('x')]) lhs = Operation(OperationType.TIMES(), [two, negative_x]) rhs = Variable(3.1415) eq = Equation(lhs, rhs) verify(str(eq), self.reporter)
def test_equation_cancellation(self): lhs = Parser(Tokenizer.tokenize('x * 4')).parse() rhs = Parser(Tokenizer.tokenize('y')).parse() equation = Equation(lhs, rhs) multiplication_cancellation = EquationCancellation( OperationType.TIMES(), OperationType.DIVIDE()) self.assertTrue(multiplication_cancellation.is_applicable_to(equation)) result = multiplication_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 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 __init__(self, token): assert isinstance(token, Token) if token.token_type in self.token_map.keys(): self._operation_type = self.token_map[token.token_type] else: self._operation_type = OperationType.VARIABLE(token.value)
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
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)
class PrefixParselet: token_map = { TokenType.PLUS : OperationType.POSITIVE(), TokenType.MINUS : OperationType.NEGATIVE() } def __init__(self, token): assert isinstance(token, Token) if token.token_type in self.token_map.keys(): self._operation_type = self.token_map[token.token_type] else: self._operation_type = OperationType.VARIABLE(token.value) def parse(self, parser): assert isinstance(parser, Parser) if self._operation_type in self.token_map.values(): right = parser.parse(precedence=10) # All prefixes should be evaluated before infixes return Operation(self._operation_type, [right]) else: return Operation(self._operation_type)
def transform(self, expression, pattern=None): assert isinstance(expression, Operation) if pattern is None: assert isinstance(pattern, SubstitutionPattern) for k in pattern.keys(): if type(pattern[k]) == str: pattern[k] = Operation(OperationType.VARIABLE(pattern[k])) substituted_start = self.try_transform(expression, pattern) substituted_end = self._substitute(self._end, pattern) return substituted_end
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_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)
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_simple_operation(self): simple_op = Operation(OperationType.PLUS(), [Variable(2), Variable(2)]) verify(str(simple_op), self.reporter)