Пример #1
0
 def _update_approx(self, center, rad, prec, derivatives):
     ini, path = self._path_to(center, prec)
     eps = RBF.one() >> prec
     # keep="all" won't do anything until _path_to returns better paths
     ctx = ancont.Context(self.dop, path, eps, keep="all")
     pairs = ancont.analytic_continuation(ctx, ini=ini)
     for (vert, val) in pairs:
         known = self._inivecs.get(vert)
         if known is None or known[0].accuracy() < val[0][0].accuracy():
             self._inivecs[vert] = [c[0] for c in val]
     logger.info(
         "computing new polynomial approximations: "
         "ini=%s, path=%s, rad=%s, eps=%s, ord=%s", ini, path, rad, eps,
         derivatives)
     polys = polapprox.doit(self.dop,
                            ini=ini,
                            path=path,
                            rad=rad,
                            eps=eps,
                            derivatives=derivatives,
                            x_is_real=True,
                            economization=polapprox.chebyshev_economization)
     logger.info("...done")
     approx = self._polys.get(center, [])
     new_approx = []
     for ord, pol in enumerate(polys):
         if ord >= len(approx) or approx[ord].prec < prec:
             new_approx.append(RealPolApprox(pol, prec))
         else:
             new_approx.append(approx[ord])
     self._update_approx_hook(center, rad, polys)
     self._polys[center] = new_approx
     return polys
Пример #2
0
 def _disk(self, pt):
     assert pt.is_real()
     # Since approximation disks satisfy 2·rad ≤ dist(center, sing), any
     # approximation disk containing pt must have rad ≤ dist(pt, sing)
     max_rad = pt.dist_to_sing().min(self.max_rad)
     # What we want is the largest such disk containing pt
     expo = ZZ(max_rad.log(2).upper().ceil()) - 1  # rad = 2^expo
     logger.log(logging.DEBUG - 2, "max_rad = %s, expo = %s", max_rad, expo)
     while True:
         approx_pt = pt.approx_abs_real(-expo)
         mantissa = (approx_pt.squash() >> expo).floor()
         if ZZ(mantissa) % 2 == 0:
             mantissa += 1
         center = mantissa << expo
         dist = Point(center, pt.dop).dist_to_sing()
         rad = RBF.one() << expo
         logger.log(
             logging.DEBUG - 2,
             "candidate disk: approx_pt = %s, mantissa = %s, "
             "center = %s, dist = %s, rad = %s", approx_pt, mantissa,
             center, dist, rad)
         if safe_ge(dist >> 1, rad):
             break
         expo -= 1
     logger.debug("disk for %s: center=%s, rad=%s", pt, center, rad)
     # pt may be a ball with nonzero radius: check that it is contained in
     # our candidate disk
     log = RBF.zero() if 0 in approx_pt else approx_pt.abs().log(2)
     F = RealBallField(ZZ((expo - log).max(0).upper().ceil()) + 10)
     dist_to_center = (F(approx_pt) - F(center)).abs()
     if not safe_le(dist_to_center, rad):
         assert not safe_gt((approx_pt.squash() - center).squash(), rad)
         logger.info("check that |%s - %s| < %s failed", approx_pt, center,
                     rad)
         return None, None
     # exactify center so that subsequent computations are not limited by the
     # precision of its parent
     center = QQ(center)
     return center, rad
Пример #3
0
    def approx(self, pt, prec=None, post_transform=None):
        r"""
        TESTS::

            sage: from ore_algebra import *
            sage: from ore_algebra.analytic.function import DFiniteFunction
            sage: DiffOps, x, Dx = DifferentialOperators()

            sage: h = DFiniteFunction(Dx^3-1, [0, 0, 1])
            sage: h.approx(0, post_transform=Dx^2)
            [2.0000000000000...]

            sage: f = DFiniteFunction((x^2 + 1)*Dx^2 + 2*x*Dx, [0, 1], max_prec=20)
            sage: f.approx(1/3, prec=10)
            [0.32...]
            sage: f.approx(1/3, prec=40)
            [0.321750554396...]
            sage: f.approx(1/3, prec=10, post_transform=Dx)
            [0.9...]
            sage: f.approx(1/3, prec=40, post_transform=Dx)
            [0.900000000000...]
            sage: f.approx(1/3, prec=10, post_transform=Dx^2)
            [-0.54...]
            sage: f.approx(1/3, prec=40, post_transform=Dx^2)
            [-0.540000000000...]

        """
        pt = Point(pt, self.dop)
        if prec is None:
            prec = _guess_prec(pt)
        if post_transform is None:
            post_transform = self.dop.parent().one()
        derivatives = min(post_transform.order() + 1, self._max_derivatives)
        post_transform = normalize_post_transform(self.dop, post_transform)
        if prec >= self.max_prec or not pt.is_real():
            logger.info(
                "performing high-prec evaluation "
                "(pt=%s, prec=%s, post_transform=%s)", pt, prec,
                post_transform)
            ini, path = self._path_to(pt)
            eps = RBF.one() >> prec
            return self.dop.numerical_solution(ini,
                                               path,
                                               eps,
                                               post_transform=post_transform)
        center, rad = self._disk(pt)
        if center is None:
            # raise NotImplementedError
            logger.info("falling back on generic evaluator")
            ini, path = self._path_to(pt)
            eps = RBF.one() >> prec
            return self.dop.numerical_solution(ini,
                                               path,
                                               eps,
                                               post_transform=post_transform)
        approx = self._polys.get(center, [])
        Balls = RealBallField(prec)
        # due to the way the polynomials are recomputed, the precisions attached
        # to the successive derivatives are nonincreasing
        if (len(approx) < derivatives or approx[derivatives - 1].prec < prec):
            polys = self._update_approx(center, rad, prec, derivatives)
        else:
            polys = [a.pol for a in approx]
        bpt = Balls(pt.value)
        reduced_pt = bpt - Balls(center)
        val = sum(
            ZZ(j).factorial() * coeff(bpt) * polys[j](reduced_pt)
            for j, coeff in enumerate(post_transform))
        return val
Пример #4
0
 def _rad(self, center):
     return RBF.one() << QQ(center).valuation(2)