Example #1
0
def test_pmatch_exponentials():
    pat = pm.pat_construct("e^(b)", {"b": "rem"})
    pmatch_res, _ = pm.pmatch(pat, p.parse("e^(x)"))
    assert pmatch_res == {"b": p.parse("x")}
Example #2
0
def test_pmatch_exp_with_terms():
    pat = pm.pat_construct("x^(a*y)", {"a": "const"})
    pmatch_res, _ = pm.pmatch(pat, p.parse("x^(3*y)"))
    assert pmatch_res == {"a": 3}
Example #3
0
def test_pmatch_exp_x_with_coeff():
    pat = pm.pat_construct("b*x^a", {"a": "const", "b": "const"})
    xyz = p.parse("10*x^3")
    pmatch_res, _ = pm.pmatch(pat, xyz)
    assert pmatch_res == {"a": 3, "b": 10}
Example #4
0
def test_x_once_coeff():
    """Tests pattern matching with input a*x"""
    # Generate the pattern
    pat = pm.pat_construct("a*x", {"a": "const"})
    pmatch_res, _ = pm.pmatch(pat, p.parse("2*x"))
    assert pmatch_res == {"a": 2}
Example #5
0
def test_recursion_return_part():
    pat = pm.pat_construct("b*x+c",
                           {"b": "const", "c": "const"})
    pmatch_res, pmatch_res_2 = pm.pmatch(pat, p.parse("x"))
    assert pmatch_res_2 == p.parse("x")
Example #6
0
def test_pmatch_exp():
    pat = pm.pat_construct("e^a", {"a": "const"})
    pmatch_res, _ = pm.pmatch(pat, p.parse("e^3"))
    assert pmatch_res == {"a": 3}
Example #7
0
def test_pmatch_polyn_one_zero():
    pat = pm.pat_construct("a*x^2+b*x+c", {"a": "const", "b": "const", "c": "const"})
    pmatch_res, _ = pm.pmatch(pat, p.parse("2*x^2+1"))
    assert pmatch_res == {"a": 2, "c": 1}
Example #8
0
def test_pmatch_fn_args_rem():
    pat = pm.pat_construct("ln(a)", {"a": "rem"})
    pmatch_res, _ = pm.pmatch(pat, p.parse("ln(x+y)"))
    assert pmatch_res == {"a": p.parse("x+y")}
Example #9
0
def test_pmatch_coeff_sin():
    pat = pm.pat_construct("a*sin(b)", {"a": "coeff", "b": "rem"})
    pmatch_res, _ = pm.pmatch(pat, p.parse("x*sin(x^2)"))
    assert pmatch_res == {"a": p.parse("x"), "b": p.parse("x^2")}
Example #10
0
def test_pmatch_non_match(coeff):
    """Tests pattern matching with input a*x+y"""
    # Generate the pattern
    pat = pm.pat_construct("a*x", {"a": "const"})
    pmatch_res, _ = pm.pmatch(pat, p.parse("{}*x+y".format(coeff)))
    assert pmatch_res == {}
Example #11
0
def test_pmatch_coeff_with_const():
    pat = pm.pat_construct("a*b*y/z", {"a": "const", "b":"coeff"})
    pmatch_res, _ = pm.pmatch(pat, p.parse("5*sin(x)*y/z"))
    assert pmatch_res == {"b": p.parse("sin(x)"), "a": 5}
Example #12
0
def test_pmatch_coeff():
    pat = pm.pat_construct("a*x", {"a": "coeff"})
    pmatch_res, _ = pm.pmatch(pat, p.parse("x^2*y*z"))
    assert pmatch_res == {"a": p.parse("x*y*z")}
Example #13
0
def test_pmatch_fn_args_with_pow_non_match():
    pat = pm.pat_construct("ln(a*x)^2", {"a": "const"})
    pmatch_res, _ = pm.pmatch(pat, p.parse("ln(x)"))
    assert pmatch_res == {}
Example #14
0
def test_pmatch_remaining():
    pat = pm.pat_construct("x^a + b", {"a": "const", "b": "rem"})
    pmatch_res, _ = pm.pmatch(pat, p.parse("x^3 + y*x"))
    assert pmatch_res == {"a": 3, "b": p.parse("y*x")}
Example #15
0
def test_pmatch_linear_sin_arg():
    pat = pm.pat_construct("a*sin(b*x+c)",
                           {"a": "const", "b": "const", "c": "const"})
    pmatch_res, _ = pm.pmatch(pat, p.parse("2*sin(3*x+10)"))
    assert pmatch_res == {"a": 2, "b": 3, "c": 10}
Example #16
0
    def eval(self):
        """
        Evaluates the integral. This will be done symbol by symbol, so for
        instance 2*x^2 + sin(x) will be done by integrating 2x^2 then sin(x)
        :return: Numeric object
        """
        logger.debug("Attempting to integrate {}".format(self.arg))
        parser = caspy.parsing.parser.Parser()
        tot = caspy.numeric.numeric.Numeric(0, "number")
        integrated_values = []
        for i, sym in enumerate(self.arg.val):
            # Simplify symbol, this get's rid of issues caused by terms
            # like x^0
            sym.simplify()
            if sym.is_exclusive_numeric():
                # Integrate constant term
                frac_val = sym.sym_frac_eval()
                frac_val_num = caspy.numeric.numeric.Numeric(
                    frac_val, "number")
                wrt_term = caspy.numeric.numeric.Numeric(self.wrt, "sym")
                tot += wrt_term * frac_val_num
                integrated_values.append(i)
                # Go onto next term
                continue

            if not sym.has_variable_in(self.wrt):
                # Integrate term that doesn't contain the variable we're
                # integrating with respect to
                sym_numeric_obj = caspy.numeric.numeric.Numeric(sym, "sym_obj")
                wrt_term = caspy.numeric.numeric.Numeric(self.wrt, "sym")
                tot += sym_numeric_obj * wrt_term
                integrated_values.append(i)
                continue

            # Try matching x^n
            pmatch_res = pm.pmatch_sym("a*{}^n".format(self.wrt), {
                "n": "const",
                "a": "const"
            }, sym, self.parser)
            if pmatch_res != {}:
                logger.debug(
                    "Integrating polynomial term {}, pmatch result {}".format(
                        sym, pmatch_res))
                if pmatch_res["n"] == -1:
                    term_val = self.parser.parse("{} * ln({})".format(
                        copy(pmatch_res["a"]), self.wrt))
                else:
                    # TODO maybe refactor Fraction class so it doesn't return self
                    # so we don't need to do a ridiculous amount of copying like this
                    term_val = self.parser.parse("{} * {} ^ ({})".format(
                        copy(pmatch_res["a"]) / (copy(pmatch_res["n"]) + 1),
                        self.wrt,
                        copy(pmatch_res["n"]) + 1))
                tot += term_val
                integrated_values.append(i)
                # Go onto next term
                continue

            # Try integrating exponential terms
            pmatch_res = pm.pmatch_sym("A1 * e^(A2)".format(self.wrt), {
                "A1": "const",
                "A2": "rem"
            }, sym, self.parser)
            if pmatch_res != {}:
                logger.debug(
                    "Integrating exponential term, pmatch result {}".format(
                        pmatch_res))
                # Currently pattern matching doesn't quite work correctly with matching
                # things like e^(a*x+b) so we will have to pattern match the A2 term
                exp_pow = expand.Expand(pmatch_res["A2"]).eval()
                pat = pm.pat_construct("B1 * {} + B2".format(self.wrt), {
                    "B1": "const",
                    "B2": "rem"
                })
                pmatch_res_pow, _ = pm.pmatch(pat, exp_pow)
                logger.debug("Power pmatch result {}".format(pmatch_res_pow))
                if "B1" in pmatch_res_pow.keys():
                    failed_int = False
                    if "B2" in pmatch_res_pow.keys():
                        if self.wrt in pmatch_res_pow["B2"].get_variables_in():
                            logger.debug(
                                "Failed integration of exponential term")
                            failed_int = True
                    if not failed_int:
                        term_val = caspy.numeric.numeric.Numeric(
                            copy(pmatch_res["A1"]) /
                            copy(pmatch_res_pow["B1"]))
                        term_val.val[0].val.append(
                            ["e", deepcopy(pmatch_res["A2"])])
                        tot += term_val
                        integrated_values.append(i)
                        continue
            # Try integrating exponential terms with u sub
            pmatch_res = pm.pmatch_sym("B1*e^(A1)", {
                "A1": "rem",
                "B1": "coeff"
            }, sym, self.parser)
            if pmatch_res != {}:
                logger.debug(
                    "Integrating e^(...) object with u sub, pmatch_res {}".
                    format(pmatch_res))
                numeric_wrapper = caspy.numeric.numeric.Numeric(
                    deepcopy(sym), "sym_obj")
                u_subbed = self.u_sub_int(pmatch_res["A1"], numeric_wrapper)
                if u_subbed is not None:
                    logger.warning("U sub integral worked")
                    tot += u_subbed
                    integrated_values.append(i)
                    continue

            # Try matching simple sin terms like sin(ax+b)
            pmatch_res = pm.pmatch_sym("a*sin(b*{}+c)".format(self.wrt), {
                "a": "const",
                "b": "const",
                "c": "const"
            }, sym, self.parser)
            if pmatch_res != {}:
                logger.debug("Integrating simple linear sin term")
                term_val = self.parser.parse("{} * cos({}*{}+{})".format(
                    copy(pmatch_res["a"]) * (-1) / copy(pmatch_res["b"]),
                    pmatch_res["b"], self.wrt, pmatch_res.get("c", 0)))
                tot += term_val
                integrated_values.append(i)
                continue

            # Try matching simple sin terms like cos(ax+b)
            pmatch_res = pm.pmatch_sym("a*cos(b*{}+c)".format(self.wrt), {
                "a": "const",
                "b": "const",
                "c": "const"
            }, sym, self.parser)
            if pmatch_res != {}:
                logger.debug("Integrating simple linear cos term")
                term_val = self.parser.parse("{} * sin({}*{}+{})".format(
                    copy(pmatch_res["a"]) / copy(pmatch_res["b"]),
                    pmatch_res["b"], self.wrt, pmatch_res.get("c", 0)))
                tot += term_val
                integrated_values.append(i)
                continue

            # Try integrating sin(___) term with a 'u' substitution
            pmatch_res = pm.pmatch_sym("b*sin(a)", {
                "a": "rem",
                "b": "coeff"
            }, sym, self.parser)
            if pmatch_res != {}:
                logger.debug(
                    "Integrating sin object with u sub, pmatch_res {}".format(
                        pmatch_res))
                numeric_wrapper = caspy.numeric.numeric.Numeric(
                    deepcopy(sym), "sym_obj")
                u_subbed = self.u_sub_int(pmatch_res["a"], numeric_wrapper)
                if u_subbed is not None:
                    logger.warning("U sub integral worked")
                    tot += u_subbed
                    integrated_values.append(i)
                    continue

            # Try integrating cos(___) term with a 'u' substitution
            pmatch_res = pm.pmatch_sym("b*cos(a)", {
                "a": "rem",
                "b": "coeff"
            }, sym, self.parser)
            if pmatch_res != {}:
                logger.debug(
                    "Integrating cos object with u sub, pmatch_res {}".format(
                        pmatch_res))
                numeric_wrapper = caspy.numeric.numeric.Numeric(
                    deepcopy(sym), "sym_obj")
                u_subbed = self.u_sub_int(pmatch_res["a"], numeric_wrapper)
                if u_subbed is not None:
                    logger.warning("U sub integral worked")
                    tot += u_subbed
                    integrated_values.append(i)
                    continue

            if self.root_integral and not self.dont_expand:
                # Try expanding the symbol then integrating
                sym_numeric = caspy.numeric.numeric.Numeric(
                    deepcopy(sym), "sym_obj")
                expand_obj = expand.Expand(sym_numeric)
                expanded = expand_obj.eval()
                logger.info("Expanded val: {}".format(
                    ln.latex_numeric_str(expanded)))
                integ_exp = Integrate(expanded, self.wrt, True, True)
                new_integral = integ_exp.eval()
                if integ_exp.fully_integrated:
                    integrated_values.append(i)
                    tot += new_integral
                    continue
                else:
                    logger.info("Failed expanded int {}".format(
                        ln.latex_numeric_str(new_integral)))

            if not self.root_integral:
                continue
            # Try integrating by parts
            int_done_by_parts = False
            for (a, b) in group_list_into_all_poss_pairs(deepcopy(sym.val)):
                # Make symbols for a and b\
                a_sym = caspy.numeric.symbol.Symbol(1, Fraction(1, 1))
                a_sym.val = a
                a_num = caspy.numeric.numeric.Numeric(a_sym, "sym_obj")
                b_sym = caspy.numeric.symbol.Symbol(1, Fraction(1, 1))
                b_sym.val = b
                b_num = caspy.numeric.numeric.Numeric(b_sym, "sym_obj")
                logger.debug("PRE Int by parts u_prime {} v {}".format(
                    ln.latex_numeric_str(a_num), ln.latex_numeric_str(b_num)))
                by_parts_ab = self.int_by_parts(a_num, b_num)
                if by_parts_ab is not None:
                    logger.debug("Int by parts u_prime {} v {}".format(
                        ln.latex_numeric_str(a_num),
                        ln.latex_numeric_str(b_num)))
                    tot += by_parts_ab
                    integrated_values.append(i)
                    int_done_by_parts = True
                else:
                    by_part_ba = self.int_by_parts(b_num, a_num)
                    if by_part_ba is not None:
                        logger.debug("Int by parts2 u_prime {} v {}".format(
                            ln.latex_numeric_str(b_num),
                            ln.latex_numeric_str(a_num)))
                        tot += by_part_ba
                        integrated_values.append(i)
                        int_done_by_parts = True

                if int_done_by_parts:
                    break
                else:
                    logger.debug("One round of int by parts failed")

            if int_done_by_parts:
                continue

        new_val = []
        # Remove integrated values from the arg property
        for j, term_val in enumerate(self.arg.val):
            if j not in integrated_values:
                new_val.append(term_val)

        if new_val == []:
            # All terms have been integrated
            self.fully_integrated = True
            return tot
        else:
            # Make a numeric object to store the non integrated terms
            new_val_numeric_obj = caspy.numeric.numeric.Numeric(1, "number")
            new_val_numeric_obj.val = new_val
            self.arg = new_val_numeric_obj
            # Return integrated terms and other terms in an integral
            remaining_int = super().eval()
            return remaining_int + tot
Example #17
0
def test_pmatch_fn_args():
    pat = pm.pat_construct("ln(a*x)", {"a": "const"})
    pmatch_res, _ = pm.pmatch(pat, p.parse("ln(3*x)"))
    assert pmatch_res == {"a": 3}