Ejemplo n.º 1
0
    def apply_to(self, expression: Expression) -> List[Expression]:
        if not expression.is_integral():
            return False

        integral_info = IntegralInfo(expression.sympy_expr.function, parse_expr('x'))
        subs_rule = substitution_rule(integral_info)

        if subs_rule is None:
            # Can not be applied by parts
            return []

        u = subs_rule.u_func
        du = Derivative(u, subs_rule.symbol).doit()
        variables = [
            ExpressionVariable('u', Expression(u)),
            ExpressionVariable('du', Expression(du)),
        ]

        equivalent_expression = subs_rule.substep.context.xreplace({subs_rule.u_var: parse_expr('u')})
        equivalent_expression = equivalent_expression * subs_rule.constant


        result = Expression(f'Integral({str(equivalent_expression)}, u)', variables, is_latex=False)

        return [
            result
        ]
Ejemplo n.º 2
0
    def test_get_children(self):
        exp = Expression("x + x^2")
        children = exp.get_children()
        self.assertEqual(2, len(children))

        self.assertTrue(Expression("x") in children)
        self.assertTrue(Expression("x^2") in children)
 def test_subtract_should_apply(self):
     exp = Expression('\\frac{d(x - x^3)}{dx}')
     expected_result = [
         Expression('\\frac{d(x)}{dx} + \\frac{d(-x^3)}{dx}'),
     ]
     result = theorem_sum_of_derivatives.apply_to(exp)
     self.assertTrue(equivalent_solutions(result, expected_result))
    def apply_to(self, expression: Expression) -> List[Expression]:
        if not expression.is_integral():
            return False

        integral_info = IntegralInfo(expression.sympy_expr.function,
                                     parse_expr('x'))
        by_parts_rule = parts_rule(integral_info)

        if by_parts_rule is None:
            # Can not be applied by parts
            return []

        u = by_parts_rule.u
        dv = by_parts_rule.dv
        v = Integral(dv, by_parts_rule.symbol).doit(
        )  # TODO Lucas: Buscar si hay una manera menos cochina de hacer esto
        variables = [
            ExpressionVariable('u(x)', Expression(u)),
            ExpressionVariable('v(x)', Expression(v)),
        ]

        equivalent_expression = Expression(
            '\\int (u(x) * \\frac{d(v(x))}{dx}) dx', variables)

        #main_expression == Expression('x * cos(x) - \\int (\\frac{d(x)}{dx} * cos(x)) dx')
        #main_expression = Expression('x * cos(x) - \\int (\\frac{d(x)}{dx} * cos(x)) dx', variables)
        # TODO: investigar dx

        #Expression('\\int u * \\frac{d(v)}{dx}', variables)
        # \\int(x * sen(x)) dx + \\int(x * cos(x)) dx
        # \\int(x * sen(x)) dx + POR PARTES(\\int(x * cos(x)) dx)
        # POR PARTES(\\int(x * sen(x)) dx) + \\int(x * cos(x)) dx

        return [equivalent_expression]
Ejemplo n.º 5
0
    def apply_to(self, expression: Expression) -> List[Expression]:
        from_side = self.left
        to_side = self.right

        # Get the subtrees of the expression that have the same root as from side.
        # by level means that we also get the level of that subtree to know if the
        # subtree could match from_side
        subtrees = expression.get_subtrees_with_root_func_by_level(from_side)
        from_side_depth = from_side.get_depth()
        expression_depth = expression.get_depth()
        results = []
        for subtree in subtrees:
            sub_expression = subtree['expression']
            level = subtree['level']
            # Example Derivative(x) have depth 2 and Derivative(f(x)+g(x)) have depth 3
            # So, if the depth of the subtree is less than the from_side of the theorem
            # it can't be applied
            if level <= expression_depth - from_side_depth:
                application_possibilities = self._apply_to(sub_expression, from_side, to_side)
                for possibility in application_possibilities:
                    if sub_expression != expression:
                        # Example:
                        # expression cos(x) + Derivative(2*x)
                        # sub_expression = Derivative(2*x)
                        # possibility = 2 * Derivative(x)
                        # replace sub_expression with possibility
                        # result = cos(x) + 2 * Derivative(x)
                        result = expression.get_copy()
                        result.replace(sub_expression,
                                   possibility)
                    else:
                        result = possibility

                    results += [result]
        return results
Ejemplo n.º 6
0
    def apply_to_children(self, expression: Expression, from_side: Expression, to_side: Expression) -> List[Expression]:
        application_possibilities = []

        template = from_side

        already_tried = set()

        # try applying to groups of children
        # for example in x + y + z
        # try with: x + y ; x + z : y + z
        if expression.can_group_children():
            logger.info("Trying to apply: " + self.name +
                        " to a group children: " + str(expression))
            for size in range(2, expression.children_amount() + 1):
                children_of_size_n_possibilities = expression.get_child_with_size_possibilities(
                    size)
                for child_of_size_n in children_of_size_n_possibilities:
                    if str(child_of_size_n) not in already_tried:
                        analysis = self.analyzer.analyze(
                            template, self.conditions, child_of_size_n)
                        if analysis.expression_match_template:
                            application_possibilities.append(TheoremApplication(
                                child_of_size_n, self.transform_side(to_side, analysis.equalities)))
                        already_tried.add(str(child_of_size_n))
        return application_possibilities
Ejemplo n.º 7
0
 def test_apply_reverse_to(self):
     theorem = self.derivative_sum_theorem
     expression = Expression("x^3 + \\frac{d(x)}{dx} + \\frac{d(x^2)}{dx}")
     possibilities = theorem.apply_reverse_to(expression)
     expected = Expression("\\frac{d(x + x^2)}{dx} + x^3")
     print(possibilities)
     self.assertTrue(is_present(expected, possibilities))
Ejemplo n.º 8
0
 def test_subtract_should_apply(self):
     exp = Expression('\\int(x - x^3)dx')
     expected_result = [
         Expression('(\\int(x)dx) + (\\int(-x^3)dx)'),
     ]
     result = theorem.apply_to(exp)
     self.assertTrue(equivalent_solutions(result, expected_result))
    def solve_exercise_with_solution_tree(self, exercise: SolvedExercise):
        # get solution tree
        data = {
            'problem_input': exercise.steps[0],
        }
        response = self.client.post(path='/results/solution-tree',
                                    data=data,
                                    format='json')

        tree_str = json.loads(response.content)

        resolve_data = {
            'problem_input': exercise.steps[0],
            'math_tree': tree_str,
            'type': 'derivative',
        }

        # all steps should be valid
        for i in range(1, len(exercise.non_result_steps)):
            previous_steps = []
            previous_steps += exercise.non_result_steps[:i]
            previous_steps.pop()

            current_step = exercise.non_result_steps[i]
            resolve_data['step_list'] = previous_steps
            resolve_data['current_expression'] = current_step

            response = self.client.post(path='/resolve',
                                        data=resolve_data,
                                        format='json')

            result = json.loads(response.content)

            if result['exerciseStatus'] == 'resolved':
                print(
                    Expression(
                        current_step['expression']).to_expression_string() +
                    ' - ' + json.dumps(current_step['variables']))
            if result['exerciseStatus'] == 'invalid':
                print(
                    Expression(
                        current_step['expression']).to_expression_string() +
                    ' - ' + json.dumps(current_step['variables']))

            self.assertEquals(response.status_code, status.HTTP_200_OK)
            self.assertEquals(result['exerciseStatus'], 'valid')

        # the result should be resolved
        resolve_data['step_list'] = exercise.steps
        resolve_data['current_expression'] = exercise.steps[-1]

        response = self.client.post(path='/resolve',
                                    data=resolve_data,
                                    format='json')

        result = json.loads(response.content)
        self.assertEquals(response.status_code, status.HTTP_200_OK)
        self.assertEquals(result['exerciseStatus'], 'resolved')
 def test_sum_of_three_should_return_all_possibilities(self):
     exp = Expression('\\frac{d(x + x^2 + x^3)}{dx}')
     expected_result = [
         Expression('\\frac{d(x + x^2)}{dx} + \\frac{d( x^3)}{dx}'),
         Expression('\\frac{d(x)}{dx} + \\frac{d(x^2 + x^3)}{dx}'),
         Expression('\\frac{d(x + x^3)}{dx} + \\frac{d(x^2)}{dx}')
     ]
     result = theorem_sum_of_derivatives.apply_to(exp)
     self.assertTrue(equivalent_solutions(result, expected_result))
Ejemplo n.º 11
0
 def apply_to(self, expression: Expression) -> List[Expression]:
     if expression.to_expression_string(
     ) == 'Integral(u(x)*Derivative(v(x), x), x)':
         return [
             Expression(
                 'u(x) * v(x) - \\int (\\frac{d(u(x))}{dx} * v(x)) dx',
                 expression.variables)
         ]
     return []
Ejemplo n.º 12
0
 def test_sum_of_three_should_return_all_possibilities(self):
     exp = Expression('\\int(x + x^2 + x^3)dx')
     expected_result = [
         Expression('(\\int(x + x^2)dx) + (\\int( x^3)dx)'),
         Expression('(\\int(x)dx) + (\\int(x^2 + x^3)dx)'),
         Expression('(\\int(x + x^3)dx) + (\\int(x^2)dx)')
     ]
     result = theorem.apply_to(exp)
     self.assertTrue(equivalent_solutions(result, expected_result))
    def test_analyze_exp_with_user_def_func_diff_sizes(self):
        analyzer = TemplateMatchAnalyzer()
        template = Expression("f(x) + g(y)")
        expression = Expression("x + x^2 + y")
        analysis = MatchAnalysisReport(template, expression, True, [])
        result = analyzer.analyze_exp_with_user_def_func_diff_sizes(
            template, [], expression, analysis)

        self.assertTrue(result.expression_match_template)
Ejemplo n.º 14
0
    def solution_tree(self, expression: Expression) -> SolutionTreeNode:
        logger.info("get solution tree for: " + expression.to_string())
        theorems = []
        if expression.contains_derivative():
            theorems += DerivativeTheorems.get_all()
        if expression.contains_integral():
            theorems += IntegrateTheorems.get_all()

        return self.solution_tree_for(expression, theorems,
                                      Theorem('none', None, None, {}))
Ejemplo n.º 15
0
 def test_contains(self):
     all_steps_contained = True
     for i in range(0, len(exercise.steps)):
         step = exercise.steps[i]
         expression = Expression(step['expression'], step['variables'])
         all_steps_contained = all_steps_contained and tree.contains(
             expression)
         if not all_steps_contained:
             print('failed: ' + expression.to_string())
     self.assertTrue(all_steps_contained)
 def analyze_exp_with_user_def_func_eq_sizes(
         self, template: Expression, template_conditions: List,
         expression: Expression,
         analysis: MatchAnalysisReport) -> MatchAnalysisReport:
     if template.compare_func(expression):
         if template.is_commutative():
             return self.analyze_commutative_children_eq_len(
                 template.get_children(), template_conditions,
                 expression.get_children(), analysis)
         else:
             return self.analyze_children_non_commutative_eq_len(
                 template, template_conditions, expression, analysis)
 def analyze_children_non_commutative_eq_len(
         self, template: Expression, template_conditions: List,
         expression: Expression,
         analysis: MatchAnalysisReport) -> MatchAnalysisReport:
     result = analysis
     template_children = template.get_children()
     expression_children = expression.get_children()
     for i in range(0, len(template)):
         result = self.analyze_rec(template_children[i],
                                   template_conditions,
                                   expression_children[i], result)
     return result
 def test_parts_replacing_u_v_should_apply(self):
     exp = Expression('\\int (x * \\cos(x))')
     variables = [
         ExpressionVariable('u(x)', Expression("x")),
         ExpressionVariable('v(x)', Expression("sen(x)")),
     ]
     expected_result = [
         Expression('u(x) * v(x) - \\int (\\frac{d(u(x))}{dx} * v(x))',
                    variables),
         Expression('\\int u(x) * \\frac{d(v(x))}{dx}', variables)
     ]
     result = theorem.apply_to(exp)
     self.assertEqual(result, expected_result)
Ejemplo n.º 19
0
    def solve_exercise_with_solution_tree(self, exercise: SolvedExercise):
        # get solution tree
        theorems = load_theorems("test/jsons/integrate_theorems.json")
        data = {
            'problem_input': exercise.steps[0],
            'type': 'integrate',
            'theorems': theorems
        }
        response = self.client.post(path='/results/solution-tree',
                                    data=data,
                                    format='json')

        tree_str = json.loads(response.content)

        resolve_data = {
            'problem_input': exercise.steps[0],
            'math_tree': tree_str,
            'type': 'integrate',
            'theorems': theorems
        }

        # all steps should be valid
        for i in range(1, len(exercise.non_result_steps)):
            previous_steps = exercise.non_result_steps[:i]
            # remove problem_input
            previous_steps.pop()
            current_step = exercise.non_result_steps[i]
            resolve_data['step_list'] = json.dumps(previous_steps)
            resolve_data['current_expression'] = current_step
            response = self.client.post(path='/resolve',
                                        data=resolve_data,
                                        format='json')
            result = json.loads(response.content)
            if result['exerciseStatus'] == 'resolved':
                print(Expression(current_step).to_string())
            if result['exerciseStatus'] == 'invalid':
                print(Expression(current_step).to_string())
            self.assertEquals(response.status_code, status.HTTP_200_OK)
            self.assertEquals(result['exerciseStatus'], 'valid')

        # the result should be resolved
        resolve_data['step_list'] = json.dumps(exercise.steps)
        resolve_data['current_expression'] = exercise.steps[-1]

        response = self.client.post(path='/resolve',
                                    data=resolve_data,
                                    format='json')

        result = json.loads(response.content)
        self.assertEquals(response.status_code, status.HTTP_200_OK)
        self.assertEquals(result['exerciseStatus'], 'resolved')
Ejemplo n.º 20
0
 def test_get_operators_by_level_complex(self):
     exp = Expression(
         "cos(x+Derivative(e**x,x))  + Derivative(x + x**(2*x+3), x)",
         is_latex=False)
     operators = exp.get_operators_by_level()
     expected = {
         0: [Add],
         1: [cos, Derivative],
         2: [Add, Add],
         3: [Derivative, Pow],
         4: [Pow, Add],
         5: [Mul]
     }
     self.assertEquals(expected, operators)
Ejemplo n.º 21
0
def solve_derivative(request: Request):
    if request.method == 'POST':
        body = json.loads(request.body)
        expression = Expression(body['expression'])
        result = result_service.get_derivative_result(expression)
        logger.info('Returning the following response: {}'.format(result))
        return Response(result.to_latex(), status=status.HTTP_200_OK)
Ejemplo n.º 22
0
    def _apply_to(self, expression: Expression, from_side: Expression, to_side: Expression) -> List[Expression]:
        application_possibilities = []

        template = from_side

        # Apply to general structure
        logger.debug("Trying to apply: " + self.name +
                    " to the general structure: " + str(expression))
        analysis = self.analyzer.analyze(template, self.conditions, expression)
        if analysis.expression_match_template:
            application_possibilities.append(
                self.transform_side(to_side, analysis.equalities))

        # Apply to children
        logger.debug("Trying to apply: " + self.name +
                    " to expression CHILDREN: " + str(expression))
        children_transformations = self.apply_to_children(
            expression, from_side, to_side)
        for child_transformation in children_transformations:
            result = expression.get_copy()
            result.replace(child_transformation.before,
                           child_transformation.after)
            application_possibilities.append(result)

        return application_possibilities
Ejemplo n.º 23
0
    def there_is_a_chance_to_apply_to(self, expression: Expression):
        if not expression.is_integral():
            return False

        integral_info = IntegralInfo(expression.sympy_expr.function, parse_expr('x'))
        subs_rule = substitution_rule(integral_info)

        return True if subs_rule is not None else False
Ejemplo n.º 24
0
 def test_get_hints_initial_step_should_return_hints(self):
     initialStep = Expression(
         "Derivative(x*exp(x), x) + Derivative(x**2*sin(x), x)",
         is_latex=False)
     hints = tree.get_hints(initialStep)
     hints = list(set(map(lambda h: h.name, hints)))
     self.assertTrue('derivada del producto' in hints)
     self.assertTrue('resolver derivadas' in hints)
    def analyze_exp_with_user_def_func_diff_sizes(
            self, template: Expression, template_conditions: List,
            expression: Expression,
            analysis: MatchAnalysisReport) -> MatchAnalysisReport:

        if template.children_amount() >= expression.children_amount():
            return self.build_match_analysis_report(False, analysis, template,
                                                    template_conditions,
                                                    expression)

        possible_expression_children = expression.get_children_with_size(
            template.children_amount())

        for children in possible_expression_children:
            if template.is_commutative():
                new_analysis = self.analyze_commutative_children_eq_len(
                    template.get_children(), template_conditions, children,
                    analysis)
            else:
                new_analysis = self.analyze_children_non_commutative_eq_len(
                    template.get_children(), template_conditions, children,
                    analysis)
            if new_analysis.expression_match_template:
                return new_analysis

        return self.build_match_analysis_report(False, analysis, template,
                                                template_conditions,
                                                expression)
Ejemplo n.º 26
0
    def parse_compare_expressions_data(
            self, request_data: dict) -> (Expression, Expression):
        self.logger.info(
            "Parsing validate not in history request data: {}".format(
                request_data))
        try:
            expression_one_str = request_data['expression_one']
            expression_two_str = request_data['expression_two']

            expression_one = Expression(expression_one_str)
            expression_two = Expression(expression_two_str)

            return (expression_one, expression_two)

        except Exception as e:
            self.logger.error(
                "Error while parsing validate result input: {}".format(e))
            raise ValidateMapperException(e)
Ejemplo n.º 27
0
    def there_is_a_chance_to_apply_to(self, expression: Expression):
        contains_u = False
        contains_du = False
        for variable in expression.variables:
            if variable.tag == 'u':
                contains_u = True
            if variable.tag == 'du':
                contains_du = True

        return not expression.contains_integral() and contains_du and contains_u
Ejemplo n.º 28
0
def resolve(request: Request):
    if request.method == 'POST':
        body = json.loads(request.body)

        problem_input = Expression(body['problem_input']['expression'],
                                   body['problem_input']['variables'])
        solution_tree = solutionTreeMapper.parse(body['math_tree'])

        step_list = []
        for step in body['step_list']:
            # TODO: I will find a more more pythonable to do that
            step_expr = step['expression']
            variables = step['variables']
            step_vars = list(
                map(
                    lambda variable: ExpressionVariable(
                        variable['tag'],
                        Expression(variable['expression']['expression'])),
                    variables if variables is not None else []))

            step_list.append(Expression(step_expr, step_vars))

        # Current expression
        body_variables = body['current_expression']['variables']
        variables = list(
            map(
                lambda variable: ExpressionVariable(
                    variable['tag'],
                    Expression(variable['expression']['expression'])),
                body_variables if body_variables is not None else []))
        current_expression = Expression(
            body['current_expression']['expression'], variables)

        (result, hints) = result_service.resolve(problem_input, solution_tree,
                                                 step_list, current_expression)

        logger.info('Returning the following response: {} {}'.format(
            result, json.dumps(hints)))

        response_data = {'exerciseStatus': result, 'hints': hints}
        return Response(response_data,
                        status=status.HTTP_200_OK,
                        content_type='application/json')
Ejemplo n.º 29
0
    def is_a_valid_next_step(self, old_expression: Expression,
                             new_expression: Expression,
                             theorems: List[Theorem]) -> bool:
        logger.info("Starting transition validation")

        logger.info("Checking if a theorem can be applied")
        theorems_that_apply = self.theorems_service.possible_theorems_for(
            old_expression, theorems)

        logger.info("THEOREMS THAT APPLY:")
        logger.info(theorems_that_apply)

        for theorem in theorems_that_apply:
            theo_applied = theorem.apply_to(old_expression)
            for possibility in theo_applied:
                if possibility != None and possibility.simplify(
                ) == new_expression.simplify():
                    logger.info("Theorem can be applied")
                    return True

            theo_applied_reverse = theorem.apply_reverse_to(new_expression)
            for possibility in theo_applied_reverse:
                if possibility != None and possibility.simplify(
                ) == old_expression.simplify():
                    logger.info("Theorem can be applied")
                    return True

        # try with derivatives
        logger.info("Try with derivatives")
        if old_expression.solve_derivatives().simplify(
        ) == new_expression.simplify():
            logger.info("Derivatives were applied")
            return True

        only_one_derivative = old_expression.derivatives_solving_possibilities(
        )
        for derivative_applied in only_one_derivative:
            if derivative_applied.simplify() == new_expression.simplify():
                return True

        # try simplifying the expression
        logger.info("Try simplifying")
        old_simplifications = old_expression.get_simplifications()
        for simplification in old_simplifications:
            new_simplifications = new_expression.get_simplifications()
            if simplification in new_simplifications:
                logger.info("Simplifications were applied")
                return True

        logger.info("Invalid next step: " + str(new_expression) +
                    " - Old expression: " + str(old_expression))
        return False
Ejemplo n.º 30
0
    def parse_expression(json_expression):
        main_expression = json_expression['expression']
        json_variables = json_expression['variables']
        variables = list(
            map(
                lambda variable: ExpressionVariable(
                    variable['tag'],
                    SolutionTreeMapper.parse_expression(variable['expression'])
                ), json_variables))

        return Expression(main_expression, variables, is_latex=False)