def _eval_evalf(self, prec): """Evaluate this complex root to the given precision. """ _prec, mp.prec = mp.prec, prec try: func = lambdify(self.poly.gen, self.expr) interval = self._get_interval() refined = False while True: if self.is_real: x0 = mpf(str(interval.center)) else: x0 = mpc(*map(str, interval.center)) try: root = findroot(func, x0) except ValueError: interval = interval.refine() refined = True continue else: if refined: self._set_interval(interval) break finally: mp.prec = _prec return Float._new(root.real._mpf_, prec) + I*Float._new(root.imag._mpf_, prec)
def _eval_evalf(self, prec): """Evaluate this complex root to the given precision. """ with workprec(prec): g = self.poly.gen if not g.is_Symbol: d = Dummy('x') func = lambdify(d, self.expr.subs(g, d)) else: func = lambdify(g, self.expr) interval = self._get_interval() if not self.is_real: # For complex intervals, we need to keep refining until the # imaginary interval is disjunct with other roots, that is, # until both ends get refined. ay = interval.ay by = interval.by while interval.ay == ay or interval.by == by: interval = interval.refine() while True: if self.is_real: x0 = mpf(str(interval.center)) else: x0 = mpc(*map(str, interval.center)) try: root = findroot(func, x0, verify=False) # If the (real or complex) root is not in the 'interval', # then keep refining the interval. This happens if findroot # accidentally finds a different root outside of this # interval because our initial estimate 'x0' was not close # enough. if self.is_real: a = mpf(str(interval.a)) b = mpf(str(interval.b)) if a == b: root = a break if not (a < root < b): raise ValueError("Root not in the interval.") else: ax = mpf(str(interval.ax)) bx = mpf(str(interval.bx)) ay = mpf(str(interval.ay)) by = mpf(str(interval.by)) if ax == bx and ay == by: root = ax + S.ImaginaryUnit * by break if not (ax < root.real < bx and ay < root.imag < by): raise ValueError("Root not in the interval.") except ValueError: interval = interval.refine() continue else: break return Float._new(root.real._mpf_, prec) + I * Float._new(root.imag._mpf_, prec)
def _eval_evalf(self, prec): """Evaluate this complex root to the given precision. """ with workprec(prec): g = self.poly.gen if not g.is_Symbol: d = Dummy('x') func = lambdify(d, self.expr.subs(g, d)) else: func = lambdify(g, self.expr) interval = self._get_interval() if not self.is_real: # For complex intervals, we need to keep refining until the # imaginary interval is disjunct with other roots, that is, # until both ends get refined. ay = interval.ay by = interval.by while interval.ay == ay or interval.by == by: interval = interval.refine() while True: if self.is_real: x0 = mpf(str(interval.center)) else: x0 = mpc(*map(str, interval.center)) try: root = findroot(func, x0, verify=False) # If the (real or complex) root is not in the 'interval', # then keep refining the interval. This happens if findroot # accidentally finds a different root outside of this # interval because our initial estimate 'x0' was not close # enough. if self.is_real: a = mpf(str(interval.a)) b = mpf(str(interval.b)) if a == b: root = a break if not (a < root < b): raise ValueError("Root not in the interval.") else: ax = mpf(str(interval.ax)) bx = mpf(str(interval.bx)) ay = mpf(str(interval.ay)) by = mpf(str(interval.by)) if ax == bx and ay == by: root = ax + S.ImaginaryUnit*by break if not (ax < root.real < bx and ay < root.imag < by): raise ValueError("Root not in the interval.") except ValueError: interval = interval.refine() continue else: break return Float._new(root.real._mpf_, prec) + I*Float._new(root.imag._mpf_, prec)
def _eval_evalf(self, prec): """Evaluate this complex root to the given precision. """ _prec, mp.prec = mp.prec, prec try: func = lambdify(self.poly.gen, self.expr) interval = self._get_interval() if not self.is_real: # For complex intervals, we need to keep refining until the # imaginary interval is disjunct with other roots, that is, # until both ends get refined. ay = interval.ay by = interval.by while interval.ay == ay or interval.by == by: interval = interval.refine() while True: if self.is_real: x0 = mpf(str(interval.center)) else: x0 = mpc(*map(str, interval.center)) try: root = findroot(func, x0) # If the (real or complex) root is not in the 'interval', # then keep refining the interval. This happens if findroot # accidentally finds a different root outside of this # interval because our initial estimate 'x0' was not close # enough. if self.is_real: a = mpf(str(interval.a)) b = mpf(str(interval.b)) # This is needed due to the bug #3364: a, b = min(a, b), max(a, b) if not (a < root < b): raise ValueError("Root not in the interval.") else: ax = mpf(str(interval.ax)) bx = mpf(str(interval.bx)) ay = mpf(str(interval.ay)) by = mpf(str(interval.by)) # This is needed due to the bug #3364: ax, bx = min(ax, bx), max(ax, bx) ay, by = min(ay, by), max(ay, by) if not (ax < root.real < bx and ay < root.imag < by): raise ValueError("Root not in the interval.") except ValueError: interval = interval.refine() continue else: break finally: mp.prec = _prec return Float._new(root.real._mpf_, prec) + I * Float._new(root.imag._mpf_, prec)
def _eval_evalf(self, prec): """Evaluate this complex root to the given precision. """ _prec, mp.prec = mp.prec, prec try: func = lambdify(self.poly.gen, self.expr) interval = self._get_interval() if not self.is_real: # For complex intervals, we need to keep refining until the # imaginary interval is disjunct with other roots, that is, # until both ends get refined. ay = interval.ay by = interval.by while interval.ay == ay or interval.by == by: interval = interval.refine() while True: if self.is_real: x0 = mpf(str(interval.center)) else: x0 = mpc(*map(str, interval.center)) try: root = findroot(func, x0) # If the (real or complex) root is not in the 'interval', # then keep refining the interval. This happens if findroot # accidentally finds a different root outside of this # interval because our initial estimate 'x0' was not close # enough. if self.is_real: a = mpf(str(interval.a)) b = mpf(str(interval.b)) # This is needed due to the bug #3364: a, b = min(a, b), max(a, b) if not (a < root < b): raise ValueError("Root not in the interval.") else: ax = mpf(str(interval.ax)) bx = mpf(str(interval.bx)) ay = mpf(str(interval.ay)) by = mpf(str(interval.by)) # This is needed due to the bug #3364: ax, bx = min(ax, bx), max(ax, bx) ay, by = min(ay, by), max(ay, by) if not (ax < root.real < bx and ay < root.imag < by): raise ValueError("Root not in the interval.") except ValueError: interval = interval.refine() continue else: break finally: mp.prec = _prec return Float._new(root.real._mpf_, prec) + I*Float._new(root.imag._mpf_, prec)
def _eval_evalf(self, prec): """Evaluate this complex root to the given precision. """ with workprec(prec): g = self.poly.gen if not g.is_Symbol: d = Dummy('x') func = lambdify(d, self.expr.subs(g, d)) else: func = lambdify(g, self.expr) interval = self._get_interval() if not self.is_real: # For complex intervals, we need to keep refining until the # imaginary interval is disjunct with other roots, that is, # until both ends get refined. ay = interval.ay by = interval.by while interval.ay == ay or interval.by == by: interval = interval.refine() while True: if self.is_real: a = mpf(str(interval.a)) b = mpf(str(interval.b)) if a == b: root = a break x0 = mpf(str(interval.center)) else: ax = mpf(str(interval.ax)) bx = mpf(str(interval.bx)) ay = mpf(str(interval.ay)) by = mpf(str(interval.by)) if ax == bx and ay == by: # the sign of the imaginary part will be assigned # according to the desired index using the fact that # roots are sorted with negative imag parts coming # before positive (and all imag roots coming after real # roots) deg = self.poly.degree() i = self.index # a positive attribute after creation if (deg - i) % 2: if ay < 0: ay = -ay else: if ay > 0: ay = -ay root = mpc(ax, ay) break x0 = mpc(*map(str, interval.center)) try: root = findroot(func, x0) # If the (real or complex) root is not in the 'interval', # then keep refining the interval. This happens if findroot # accidentally finds a different root outside of this # interval because our initial estimate 'x0' was not close # enough. It is also possible that the secant method will # get trapped by a max/min in the interval; the root # verification by findroot will raise a ValueError in this # case and the interval will then be tightened -- and # eventually the root will be found. # # It is also possible that findroot will not have any # successful iterations to process (in which case it # will fail to initialize a variable that is tested # after the iterations and raise an UnboundLocalError). if self.is_real: if (a <= root <= b): break elif (ax <= root.real <= bx and ay <= root.imag <= by): break except (UnboundLocalError, ValueError): pass interval = interval.refine() return (Float._new(root.real._mpf_, prec) + I*Float._new(root.imag._mpf_, prec))
def eval_approx(self, n): """Evaluate this complex root to the given precision. This uses secant method and root bounds are used to both generate an initial guess and to check that the root returned is valid. If ever the method converges outside the root bounds, the bounds will be made smaller and updated. """ prec = dps_to_prec(n) with workprec(prec): g = self.poly.gen if not g.is_Symbol: d = Dummy('x') if self.is_imaginary: d *= I func = lambdify(d, self.expr.subs(g, d)) else: expr = self.expr if self.is_imaginary: expr = self.expr.subs(g, I * g) func = lambdify(g, expr) interval = self._get_interval() while True: if self.is_real: a = mpf(str(interval.a)) b = mpf(str(interval.b)) if a == b: root = a break x0 = mpf(str(interval.center)) x1 = x0 + mpf(str(interval.dx)) / 4 elif self.is_imaginary: a = mpf(str(interval.ay)) b = mpf(str(interval.by)) if a == b: root = mpc(mpf('0'), a) break x0 = mpf(str(interval.center[1])) x1 = x0 + mpf(str(interval.dy)) / 4 else: ax = mpf(str(interval.ax)) bx = mpf(str(interval.bx)) ay = mpf(str(interval.ay)) by = mpf(str(interval.by)) if ax == bx and ay == by: root = mpc(ax, ay) break x0 = mpc(*map(str, interval.center)) x1 = x0 + mpc(*map(str, (interval.dx, interval.dy))) / 4 try: # without a tolerance, this will return when (to within # the given precision) x_i == x_{i-1} root = findroot(func, (x0, x1)) # If the (real or complex) root is not in the 'interval', # then keep refining the interval. This happens if findroot # accidentally finds a different root outside of this # interval because our initial estimate 'x0' was not close # enough. It is also possible that the secant method will # get trapped by a max/min in the interval; the root # verification by findroot will raise a ValueError in this # case and the interval will then be tightened -- and # eventually the root will be found. # # It is also possible that findroot will not have any # successful iterations to process (in which case it # will fail to initialize a variable that is tested # after the iterations and raise an UnboundLocalError). if self.is_real or self.is_imaginary: if not bool(root.imag) == self.is_real and (a <= root <= b): if self.is_imaginary: root = mpc(mpf('0'), root.real) break elif (ax <= root.real <= bx and ay <= root.imag <= by): break except (UnboundLocalError, ValueError): pass interval = interval.refine() # update the interval so we at least (for this precision or # less) don't have much work to do to recompute the root self._set_interval(interval) return (Float._new(root.real._mpf_, prec) + I * Float._new(root.imag._mpf_, prec))
def eval_approx(self, n): """Evaluate this complex root to the given precision. This uses secant method and root bounds are used to both generate an initial guess and to check that the root returned is valid. If ever the method converges outside the root bounds, the bounds will be made smaller and updated. """ prec = dps_to_prec(n) with workprec(prec): g = self.poly.gen if not g.is_Symbol: d = Dummy('x') if self.is_imaginary: d *= I func = lambdify(d, self.expr.subs(g, d)) else: expr = self.expr if self.is_imaginary: expr = self.expr.subs(g, I*g) func = lambdify(g, expr) interval = self._get_interval() while True: if self.is_real: a = mpf(str(interval.a)) b = mpf(str(interval.b)) if a == b: root = a break x0 = mpf(str(interval.center)) x1 = x0 + mpf(str(interval.dx))/4 elif self.is_imaginary: a = mpf(str(interval.ay)) b = mpf(str(interval.by)) if a == b: root = mpc(mpf('0'), a) break x0 = mpf(str(interval.center[1])) x1 = x0 + mpf(str(interval.dy))/4 else: ax = mpf(str(interval.ax)) bx = mpf(str(interval.bx)) ay = mpf(str(interval.ay)) by = mpf(str(interval.by)) if ax == bx and ay == by: root = mpc(ax, ay) break x0 = mpc(*map(str, interval.center)) x1 = x0 + mpc(*map(str, (interval.dx, interval.dy)))/4 try: # without a tolerance, this will return when (to within # the given precision) x_i == x_{i-1} root = findroot(func, (x0, x1)) # If the (real or complex) root is not in the 'interval', # then keep refining the interval. This happens if findroot # accidentally finds a different root outside of this # interval because our initial estimate 'x0' was not close # enough. It is also possible that the secant method will # get trapped by a max/min in the interval; the root # verification by findroot will raise a ValueError in this # case and the interval will then be tightened -- and # eventually the root will be found. # # It is also possible that findroot will not have any # successful iterations to process (in which case it # will fail to initialize a variable that is tested # after the iterations and raise an UnboundLocalError). if self.is_real or self.is_imaginary: if not bool(root.imag) == self.is_real and ( a <= root <= b): if self.is_imaginary: root = mpc(mpf('0'), root.real) break elif (ax <= root.real <= bx and ay <= root.imag <= by): break except (UnboundLocalError, ValueError): pass interval = interval.refine() # update the interval so we at least (for this precision or # less) don't have much work to do to recompute the root self._set_interval(interval) return (Float._new(root.real._mpf_, prec) + I*Float._new(root.imag._mpf_, prec))