Пример #1
0
    def _piecewise_symbolic_integral(cache, integrand, x, y=None):
        """
        Computes the symbolic integral of 'x' of a piecewise polynomial 'integrand'.
        The result might be a sympy expression or a numerical value.

        Parameters
        ----------
        integrand : list
            A list of (lower bound, upper bound, polynomial)
        x : object
            A string/sympy expression representing the integration variable
        """
        cache_hit = [0, 0] if (cache is not None) else None

        res = 0
        for l, u, p in integrand:
            symx = symvar(x)
            symy = symvar(y) if y else symvar("aux_y")
            syml = Poly(to_sympy(l), symy, domain="QQ")
            symu = Poly(to_sympy(u), symy, domain="QQ")

            if type(p) != Poly:
                symp = Poly(to_sympy(p), symx, domain="QQ")
            else:
                symp = Poly(p.as_expr(), symx, symy, domain="QQ")

            #print("integrating", symp.as_expr(), f"in d{symx} with bounds", [syml.as_expr(), symu.as_expr()])
            if cache is not None:  # for cache = True
                """ hierarchical cache, where we cache:
                 - the anti-derivatives for integrands, retrieved by:
                       (None, None, integrand key)
                 - the partial integration term, retrieved by:
                       (lower bound key, None, integrand key)
                       (None, upper bound key, integrand key)
                 - the whole integration, retrieved by:
                       (lower bound key, upper bound key, integrand key)
                """
                # cache keys for bounds
                k_lower = MP2WMI.sympy_to_tuple(syml)
                k_upper = MP2WMI.sympy_to_tuple(symu)
                k_poly = MP2WMI.sympy_to_tuple(
                    symp)  # cache key for integrand polynomial
                k_full = (k_lower, k_upper, k_poly)

                #print("========= KEYS =========")
                #print("lower:", syml.as_expr(), "-->", k_lower)
                #print("upper:", symu.as_expr(), "-->", k_upper)
                #print("poly:", symp.as_expr(), "-->", k_poly)
                #print("========================")
                if k_full in cache:
                    # retrieve the whole integration
                    cache_hit[True] += 1
                    symintegral = MP2WMI.tuple_to_sympy(
                        cache[k_full], symx, symy)
                    symintegral = symintegral.subs(symintegral.gens[0], symy)

                else:
                    # retrieve partial integration terms
                    terms = [None, None]
                    k_part_l = (k_lower, k_poly)
                    k_part_u = (k_upper, k_poly)
                    if k_part_l in cache:
                        partial_l = MP2WMI.tuple_to_sympy(
                            cache[k_part_l], symx, symy)
                        terms[0] = partial_l.subs(partial_l.gens[0], symy)

                    if k_part_u in cache:
                        partial_u = MP2WMI.tuple_to_sympy(
                            cache[k_part_u], symx, symy)
                        terms[1] = partial_u.subs(partial_u.gens[0], symy)

                    if None not in terms:
                        cache_hit[True] += 1
                    else:
                        # retrieve anti-derivative
                        k_anti = (k_poly, )
                        if k_anti in cache:
                            cache_hit[True] += 1
                            antidrv = MP2WMI.tuple_to_sympy(
                                cache[k_anti], symx, symy)

                        else:
                            cache_hit[False] += 1
                            antidrv = symp.integrate(symx)
                            cache[k_anti] = MP2WMI.sympy_to_tuple(antidrv)

                        # cache partial integration terms
                        if terms[0] is None:
                            terms[0] = Poly(antidrv.as_expr(),
                                            symx,
                                            domain=f'QQ[{symy}]').eval(
                                                {symx: syml.as_expr()})
                            terms[0] = Poly(terms[0].as_expr(),
                                            symx,
                                            symy,
                                            domain="QQ")
                            cache[k_part_l] = MP2WMI.sympy_to_tuple(terms[0])

                        if terms[1] is None:
                            terms[1] = Poly(antidrv.as_expr(),
                                            symx,
                                            domain=f'QQ[{symy}]').eval(
                                                {symx: symu.as_expr()})
                            terms[1] = Poly(terms[1].as_expr(),
                                            symx,
                                            symy,
                                            domain="QQ")
                            cache[k_part_u] = MP2WMI.sympy_to_tuple(terms[1])

                    #print("subs: (", terms[1].as_expr(), ") - (", terms[0].as_expr(), ")")
                    symintegral = terms[1] - terms[0]
                    if not isinstance(symintegral, Poly):
                        symintegral = Poly(symintegral,
                                           symx,
                                           symy,
                                           domain='QQ')
                    cache[k_full] = MP2WMI.sympy_to_tuple(symintegral)

            else:  # for cache = False
                antidrv = symp.integrate(symx)
                lower = Poly(antidrv.as_expr(), symx,
                             domain=f'QQ[{symy}]').eval({symx: syml.as_expr()})
                lower = Poly(lower.as_expr(), symx, symy, domain="QQ")
                upper = Poly(antidrv.as_expr(), symx,
                             domain=f'QQ[{symy}]').eval({symx: symu.as_expr()})
                upper = Poly(upper.as_expr(), symx, symy, domain="QQ")
                symintegral = upper - lower

            res += symintegral
            #print("integral:", symintegral.as_expr())
            #print()

        #print("RESULT:", res)
        #print("**************************************************")
        return res, cache_hit
Пример #2
0
    def piecewise_symbolic_integral(self, integrand, x, y=None):
        """
        Computes the symbolic integral of 'x' of a piecewise polynomial 'integrand'.
        The result might be a sympy expression or a numerical value.

        Parameters
        ----------
        integrand : list
            A list of (lower bound, upper bound, polynomial)
        x : object
            A string/sympy expression representing the integration variable
        """
        res = 0
        #logger.debug(f"\t\t\t\tpiecewise_symbolic_integral")
        #logger.debug(f"\t\t\t\tlen(integrand): {len(integrand)} --- y: {y}")
        for l, u, p in integrand:
            symx = symvar(x)
            symy = symvar(y) if y else symvar("aux_y")

            syml = Poly(to_sympy(l), symy, domain="QQ")
            symu = Poly(to_sympy(u), symy, domain="QQ")
            #logger.debug(f"\t\t\t\t\tl: {l} --- u: {u} --- p: {p}")
            if type(p) != Poly:
                symp = Poly(to_sympy(p), symx, domain="QQ")
            else:
                symp = Poly(p.as_expr(), symx, domain=f"QQ[{symy}]") if y else p

            if self.cache is not None:  # for cache = True
                """ hierarchical cache, where we cache:
                 - the anti-derivatives for integrands, retrieved by the same
                       integrand key
                 - the partial integration term, retrieved by the same
                       (integrand key, lower / upper bound key) pair
                 - the whole integration, retrieved by the same
                       (integrand key, lower bound key, upper bound key) pair
                """
                bds_ks = [MPWMI.cache_key(syml)[0],
                          MPWMI.cache_key(symu)[0]]  # cache keys for bounds
                bds = [syml.as_expr(),
                       symu.as_expr()]
                p_ks = MPWMI.cache_key(symp)  # cache key for integrand polynomial
                trm_ks = [(bds_ks[0], p_ks[0]),
                          (bds_ks[1], p_ks[0])]
                if (bds_ks[0], bds_ks[1], p_ks[0]) in self.cache:
                    # retrieve the whole integration
                    self.cache_hit[True] += 1
                    symintegral = self.cache[(bds_ks[0], bds_ks[1], p_ks[0])]
                    symintegral = symintegral.subs(symintegral.gens[0], symy)
                else:
                    terms = []
                    for tk in trm_ks:  # retrieve partial integration terms
                        if tk in self.cache:
                            trm = self.cache[tk]
                            trm = trm.subs(trm.gens[0], symy)
                            terms.append(trm)
                        else:
                            terms.append(None)

                    if None not in terms:
                        self.cache_hit[True] += 1
                    else:
                        if p_ks[0] in self.cache:  # retrieve anti-derivative
                            self.cache_hit[True] += 1
                            antidrv = self.cache[p_ks[0]]
                            antidrv_expr = antidrv.as_expr().subs(antidrv.gens[0], symx)
                            antidrv = Poly(antidrv_expr, symx,
                                           domain=f"QQ[{symy}]") if y \
                                else Poly(antidrv_expr, symx, domain="QQ")
                        else:
                            self.cache_hit[False] += 1
                            antidrv = symp.integrate(symx)
                            for k in p_ks:  # cache anti-derivative
                                self.cache[k] = antidrv

                        for i in range(len(terms)):
                            if terms[i] is not None:
                                continue
                            terms[i] = antidrv.eval({symx: bds[i]})
                            terms[i] = Poly(terms[i].as_expr(), symy, domain="QQ")
                            for k in p_ks:  # cache partial integration terms
                                self.cache[(bds_ks[i], k)] = terms[i]

                    symintegral = terms[1] - terms[0]
                    for k in p_ks:  # cache the whole integration
                        self.cache[(bds_ks[0], bds_ks[1], k)] = symintegral

            else:  # for cache = False
                antidrv = symp.integrate(symx)
                symintegral = antidrv.eval({symx: symu.as_expr()}) - \
                              antidrv.eval({symx: syml.as_expr()})

            res += symintegral
            #logger.debug(f"\t\t\t\t\tsymintegral: {symintegral}")
        return res