Spaces:
Paused
Paused
| import operator | |
| from . import libmp | |
| from .libmp.backend import basestring | |
| from .libmp import ( | |
| int_types, MPZ_ONE, | |
| prec_to_dps, dps_to_prec, repr_dps, | |
| round_floor, round_ceiling, | |
| fzero, finf, fninf, fnan, | |
| mpf_le, mpf_neg, | |
| from_int, from_float, from_str, from_rational, | |
| mpi_mid, mpi_delta, mpi_str, | |
| mpi_abs, mpi_pos, mpi_neg, mpi_add, mpi_sub, | |
| mpi_mul, mpi_div, mpi_pow_int, mpi_pow, | |
| mpi_from_str, | |
| mpci_pos, mpci_neg, mpci_add, mpci_sub, mpci_mul, mpci_div, mpci_pow, | |
| mpci_abs, mpci_pow, mpci_exp, mpci_log, | |
| ComplexResult, | |
| mpf_hash, mpc_hash) | |
| from .matrices.matrices import _matrix | |
| mpi_zero = (fzero, fzero) | |
| from .ctx_base import StandardBaseContext | |
| new = object.__new__ | |
| def convert_mpf_(x, prec, rounding): | |
| if hasattr(x, "_mpf_"): return x._mpf_ | |
| if isinstance(x, int_types): return from_int(x, prec, rounding) | |
| if isinstance(x, float): return from_float(x, prec, rounding) | |
| if isinstance(x, basestring): return from_str(x, prec, rounding) | |
| raise NotImplementedError | |
| class ivmpf(object): | |
| """ | |
| Interval arithmetic class. Precision is controlled by iv.prec. | |
| """ | |
| def __new__(cls, x=0): | |
| return cls.ctx.convert(x) | |
| def cast(self, cls, f_convert): | |
| a, b = self._mpi_ | |
| if a == b: | |
| return cls(f_convert(a)) | |
| raise ValueError | |
| def __int__(self): | |
| return self.cast(int, libmp.to_int) | |
| def __float__(self): | |
| return self.cast(float, libmp.to_float) | |
| def __complex__(self): | |
| return self.cast(complex, libmp.to_float) | |
| def __hash__(self): | |
| a, b = self._mpi_ | |
| if a == b: | |
| return mpf_hash(a) | |
| else: | |
| return hash(self._mpi_) | |
| def real(self): return self | |
| def imag(self): return self.ctx.zero | |
| def conjugate(self): return self | |
| def a(self): | |
| a, b = self._mpi_ | |
| return self.ctx.make_mpf((a, a)) | |
| def b(self): | |
| a, b = self._mpi_ | |
| return self.ctx.make_mpf((b, b)) | |
| def mid(self): | |
| ctx = self.ctx | |
| v = mpi_mid(self._mpi_, ctx.prec) | |
| return ctx.make_mpf((v, v)) | |
| def delta(self): | |
| ctx = self.ctx | |
| v = mpi_delta(self._mpi_, ctx.prec) | |
| return ctx.make_mpf((v,v)) | |
| def _mpci_(self): | |
| return self._mpi_, mpi_zero | |
| def _compare(*args): | |
| raise TypeError("no ordering relation is defined for intervals") | |
| __gt__ = _compare | |
| __le__ = _compare | |
| __gt__ = _compare | |
| __ge__ = _compare | |
| def __contains__(self, t): | |
| t = self.ctx.mpf(t) | |
| return (self.a <= t.a) and (t.b <= self.b) | |
| def __str__(self): | |
| return mpi_str(self._mpi_, self.ctx.prec) | |
| def __repr__(self): | |
| if self.ctx.pretty: | |
| return str(self) | |
| a, b = self._mpi_ | |
| n = repr_dps(self.ctx.prec) | |
| a = libmp.to_str(a, n) | |
| b = libmp.to_str(b, n) | |
| return "mpi(%r, %r)" % (a, b) | |
| def _compare(s, t, cmpfun): | |
| if not hasattr(t, "_mpi_"): | |
| try: | |
| t = s.ctx.convert(t) | |
| except: | |
| return NotImplemented | |
| return cmpfun(s._mpi_, t._mpi_) | |
| def __eq__(s, t): return s._compare(t, libmp.mpi_eq) | |
| def __ne__(s, t): return s._compare(t, libmp.mpi_ne) | |
| def __lt__(s, t): return s._compare(t, libmp.mpi_lt) | |
| def __le__(s, t): return s._compare(t, libmp.mpi_le) | |
| def __gt__(s, t): return s._compare(t, libmp.mpi_gt) | |
| def __ge__(s, t): return s._compare(t, libmp.mpi_ge) | |
| def __abs__(self): | |
| return self.ctx.make_mpf(mpi_abs(self._mpi_, self.ctx.prec)) | |
| def __pos__(self): | |
| return self.ctx.make_mpf(mpi_pos(self._mpi_, self.ctx.prec)) | |
| def __neg__(self): | |
| return self.ctx.make_mpf(mpi_neg(self._mpi_, self.ctx.prec)) | |
| def ae(s, t, rel_eps=None, abs_eps=None): | |
| return s.ctx.almosteq(s, t, rel_eps, abs_eps) | |
| class ivmpc(object): | |
| def __new__(cls, re=0, im=0): | |
| re = cls.ctx.convert(re) | |
| im = cls.ctx.convert(im) | |
| y = new(cls) | |
| y._mpci_ = re._mpi_, im._mpi_ | |
| return y | |
| def __hash__(self): | |
| (a, b), (c,d) = self._mpci_ | |
| if a == b and c == d: | |
| return mpc_hash((a, c)) | |
| else: | |
| return hash(self._mpci_) | |
| def __repr__(s): | |
| if s.ctx.pretty: | |
| return str(s) | |
| return "iv.mpc(%s, %s)" % (repr(s.real), repr(s.imag)) | |
| def __str__(s): | |
| return "(%s + %s*j)" % (str(s.real), str(s.imag)) | |
| def a(self): | |
| (a, b), (c,d) = self._mpci_ | |
| return self.ctx.make_mpf((a, a)) | |
| def b(self): | |
| (a, b), (c,d) = self._mpci_ | |
| return self.ctx.make_mpf((b, b)) | |
| def c(self): | |
| (a, b), (c,d) = self._mpci_ | |
| return self.ctx.make_mpf((c, c)) | |
| def d(self): | |
| (a, b), (c,d) = self._mpci_ | |
| return self.ctx.make_mpf((d, d)) | |
| def real(s): | |
| return s.ctx.make_mpf(s._mpci_[0]) | |
| def imag(s): | |
| return s.ctx.make_mpf(s._mpci_[1]) | |
| def conjugate(s): | |
| a, b = s._mpci_ | |
| return s.ctx.make_mpc((a, mpf_neg(b))) | |
| def overlap(s, t): | |
| t = s.ctx.convert(t) | |
| real_overlap = (s.a <= t.a <= s.b) or (s.a <= t.b <= s.b) or (t.a <= s.a <= t.b) or (t.a <= s.b <= t.b) | |
| imag_overlap = (s.c <= t.c <= s.d) or (s.c <= t.d <= s.d) or (t.c <= s.c <= t.d) or (t.c <= s.d <= t.d) | |
| return real_overlap and imag_overlap | |
| def __contains__(s, t): | |
| t = s.ctx.convert(t) | |
| return t.real in s.real and t.imag in s.imag | |
| def _compare(s, t, ne=False): | |
| if not isinstance(t, s.ctx._types): | |
| try: | |
| t = s.ctx.convert(t) | |
| except: | |
| return NotImplemented | |
| if hasattr(t, '_mpi_'): | |
| tval = t._mpi_, mpi_zero | |
| elif hasattr(t, '_mpci_'): | |
| tval = t._mpci_ | |
| if ne: | |
| return s._mpci_ != tval | |
| return s._mpci_ == tval | |
| def __eq__(s, t): return s._compare(t) | |
| def __ne__(s, t): return s._compare(t, True) | |
| def __lt__(s, t): raise TypeError("complex intervals cannot be ordered") | |
| __le__ = __gt__ = __ge__ = __lt__ | |
| def __neg__(s): return s.ctx.make_mpc(mpci_neg(s._mpci_, s.ctx.prec)) | |
| def __pos__(s): return s.ctx.make_mpc(mpci_pos(s._mpci_, s.ctx.prec)) | |
| def __abs__(s): return s.ctx.make_mpf(mpci_abs(s._mpci_, s.ctx.prec)) | |
| def ae(s, t, rel_eps=None, abs_eps=None): | |
| return s.ctx.almosteq(s, t, rel_eps, abs_eps) | |
| def _binary_op(f_real, f_complex): | |
| def g_complex(ctx, sval, tval): | |
| return ctx.make_mpc(f_complex(sval, tval, ctx.prec)) | |
| def g_real(ctx, sval, tval): | |
| try: | |
| return ctx.make_mpf(f_real(sval, tval, ctx.prec)) | |
| except ComplexResult: | |
| sval = (sval, mpi_zero) | |
| tval = (tval, mpi_zero) | |
| return g_complex(ctx, sval, tval) | |
| def lop_real(s, t): | |
| if isinstance(t, _matrix): return NotImplemented | |
| ctx = s.ctx | |
| if not isinstance(t, ctx._types): t = ctx.convert(t) | |
| if hasattr(t, "_mpi_"): return g_real(ctx, s._mpi_, t._mpi_) | |
| if hasattr(t, "_mpci_"): return g_complex(ctx, (s._mpi_, mpi_zero), t._mpci_) | |
| return NotImplemented | |
| def rop_real(s, t): | |
| ctx = s.ctx | |
| if not isinstance(t, ctx._types): t = ctx.convert(t) | |
| if hasattr(t, "_mpi_"): return g_real(ctx, t._mpi_, s._mpi_) | |
| if hasattr(t, "_mpci_"): return g_complex(ctx, t._mpci_, (s._mpi_, mpi_zero)) | |
| return NotImplemented | |
| def lop_complex(s, t): | |
| if isinstance(t, _matrix): return NotImplemented | |
| ctx = s.ctx | |
| if not isinstance(t, s.ctx._types): | |
| try: | |
| t = s.ctx.convert(t) | |
| except (ValueError, TypeError): | |
| return NotImplemented | |
| return g_complex(ctx, s._mpci_, t._mpci_) | |
| def rop_complex(s, t): | |
| ctx = s.ctx | |
| if not isinstance(t, s.ctx._types): | |
| t = s.ctx.convert(t) | |
| return g_complex(ctx, t._mpci_, s._mpci_) | |
| return lop_real, rop_real, lop_complex, rop_complex | |
| ivmpf.__add__, ivmpf.__radd__, ivmpc.__add__, ivmpc.__radd__ = _binary_op(mpi_add, mpci_add) | |
| ivmpf.__sub__, ivmpf.__rsub__, ivmpc.__sub__, ivmpc.__rsub__ = _binary_op(mpi_sub, mpci_sub) | |
| ivmpf.__mul__, ivmpf.__rmul__, ivmpc.__mul__, ivmpc.__rmul__ = _binary_op(mpi_mul, mpci_mul) | |
| ivmpf.__div__, ivmpf.__rdiv__, ivmpc.__div__, ivmpc.__rdiv__ = _binary_op(mpi_div, mpci_div) | |
| ivmpf.__pow__, ivmpf.__rpow__, ivmpc.__pow__, ivmpc.__rpow__ = _binary_op(mpi_pow, mpci_pow) | |
| ivmpf.__truediv__ = ivmpf.__div__; ivmpf.__rtruediv__ = ivmpf.__rdiv__ | |
| ivmpc.__truediv__ = ivmpc.__div__; ivmpc.__rtruediv__ = ivmpc.__rdiv__ | |
| class ivmpf_constant(ivmpf): | |
| def __new__(cls, f): | |
| self = new(cls) | |
| self._f = f | |
| return self | |
| def _get_mpi_(self): | |
| prec = self.ctx._prec[0] | |
| a = self._f(prec, round_floor) | |
| b = self._f(prec, round_ceiling) | |
| return a, b | |
| _mpi_ = property(_get_mpi_) | |
| class MPIntervalContext(StandardBaseContext): | |
| def __init__(ctx): | |
| ctx.mpf = type('ivmpf', (ivmpf,), {}) | |
| ctx.mpc = type('ivmpc', (ivmpc,), {}) | |
| ctx._types = (ctx.mpf, ctx.mpc) | |
| ctx._constant = type('ivmpf_constant', (ivmpf_constant,), {}) | |
| ctx._prec = [53] | |
| ctx._set_prec(53) | |
| ctx._constant._ctxdata = ctx.mpf._ctxdata = ctx.mpc._ctxdata = [ctx.mpf, new, ctx._prec] | |
| ctx._constant.ctx = ctx.mpf.ctx = ctx.mpc.ctx = ctx | |
| ctx.pretty = False | |
| StandardBaseContext.__init__(ctx) | |
| ctx._init_builtins() | |
| def _mpi(ctx, a, b=None): | |
| if b is None: | |
| return ctx.mpf(a) | |
| return ctx.mpf((a,b)) | |
| def _init_builtins(ctx): | |
| ctx.one = ctx.mpf(1) | |
| ctx.zero = ctx.mpf(0) | |
| ctx.inf = ctx.mpf('inf') | |
| ctx.ninf = -ctx.inf | |
| ctx.nan = ctx.mpf('nan') | |
| ctx.j = ctx.mpc(0,1) | |
| ctx.exp = ctx._wrap_mpi_function(libmp.mpi_exp, libmp.mpci_exp) | |
| ctx.sqrt = ctx._wrap_mpi_function(libmp.mpi_sqrt) | |
| ctx.ln = ctx._wrap_mpi_function(libmp.mpi_log, libmp.mpci_log) | |
| ctx.cos = ctx._wrap_mpi_function(libmp.mpi_cos, libmp.mpci_cos) | |
| ctx.sin = ctx._wrap_mpi_function(libmp.mpi_sin, libmp.mpci_sin) | |
| ctx.tan = ctx._wrap_mpi_function(libmp.mpi_tan) | |
| ctx.gamma = ctx._wrap_mpi_function(libmp.mpi_gamma, libmp.mpci_gamma) | |
| ctx.loggamma = ctx._wrap_mpi_function(libmp.mpi_loggamma, libmp.mpci_loggamma) | |
| ctx.rgamma = ctx._wrap_mpi_function(libmp.mpi_rgamma, libmp.mpci_rgamma) | |
| ctx.factorial = ctx._wrap_mpi_function(libmp.mpi_factorial, libmp.mpci_factorial) | |
| ctx.fac = ctx.factorial | |
| ctx.eps = ctx._constant(lambda prec, rnd: (0, MPZ_ONE, 1-prec, 1)) | |
| ctx.pi = ctx._constant(libmp.mpf_pi) | |
| ctx.e = ctx._constant(libmp.mpf_e) | |
| ctx.ln2 = ctx._constant(libmp.mpf_ln2) | |
| ctx.ln10 = ctx._constant(libmp.mpf_ln10) | |
| ctx.phi = ctx._constant(libmp.mpf_phi) | |
| ctx.euler = ctx._constant(libmp.mpf_euler) | |
| ctx.catalan = ctx._constant(libmp.mpf_catalan) | |
| ctx.glaisher = ctx._constant(libmp.mpf_glaisher) | |
| ctx.khinchin = ctx._constant(libmp.mpf_khinchin) | |
| ctx.twinprime = ctx._constant(libmp.mpf_twinprime) | |
| def _wrap_mpi_function(ctx, f_real, f_complex=None): | |
| def g(x, **kwargs): | |
| if kwargs: | |
| prec = kwargs.get('prec', ctx._prec[0]) | |
| else: | |
| prec = ctx._prec[0] | |
| x = ctx.convert(x) | |
| if hasattr(x, "_mpi_"): | |
| return ctx.make_mpf(f_real(x._mpi_, prec)) | |
| if hasattr(x, "_mpci_"): | |
| return ctx.make_mpc(f_complex(x._mpci_, prec)) | |
| raise ValueError | |
| return g | |
| def _wrap_specfun(cls, name, f, wrap): | |
| if wrap: | |
| def f_wrapped(ctx, *args, **kwargs): | |
| convert = ctx.convert | |
| args = [convert(a) for a in args] | |
| prec = ctx.prec | |
| try: | |
| ctx.prec += 10 | |
| retval = f(ctx, *args, **kwargs) | |
| finally: | |
| ctx.prec = prec | |
| return +retval | |
| else: | |
| f_wrapped = f | |
| setattr(cls, name, f_wrapped) | |
| def _set_prec(ctx, n): | |
| ctx._prec[0] = max(1, int(n)) | |
| ctx._dps = prec_to_dps(n) | |
| def _set_dps(ctx, n): | |
| ctx._prec[0] = dps_to_prec(n) | |
| ctx._dps = max(1, int(n)) | |
| prec = property(lambda ctx: ctx._prec[0], _set_prec) | |
| dps = property(lambda ctx: ctx._dps, _set_dps) | |
| def make_mpf(ctx, v): | |
| a = new(ctx.mpf) | |
| a._mpi_ = v | |
| return a | |
| def make_mpc(ctx, v): | |
| a = new(ctx.mpc) | |
| a._mpci_ = v | |
| return a | |
| def _mpq(ctx, pq): | |
| p, q = pq | |
| a = libmp.from_rational(p, q, ctx.prec, round_floor) | |
| b = libmp.from_rational(p, q, ctx.prec, round_ceiling) | |
| return ctx.make_mpf((a, b)) | |
| def convert(ctx, x): | |
| if isinstance(x, (ctx.mpf, ctx.mpc)): | |
| return x | |
| if isinstance(x, ctx._constant): | |
| return +x | |
| if isinstance(x, complex) or hasattr(x, "_mpc_"): | |
| re = ctx.convert(x.real) | |
| im = ctx.convert(x.imag) | |
| return ctx.mpc(re,im) | |
| if isinstance(x, basestring): | |
| v = mpi_from_str(x, ctx.prec) | |
| return ctx.make_mpf(v) | |
| if hasattr(x, "_mpi_"): | |
| a, b = x._mpi_ | |
| else: | |
| try: | |
| a, b = x | |
| except (TypeError, ValueError): | |
| a = b = x | |
| if hasattr(a, "_mpi_"): | |
| a = a._mpi_[0] | |
| else: | |
| a = convert_mpf_(a, ctx.prec, round_floor) | |
| if hasattr(b, "_mpi_"): | |
| b = b._mpi_[1] | |
| else: | |
| b = convert_mpf_(b, ctx.prec, round_ceiling) | |
| if a == fnan or b == fnan: | |
| a = fninf | |
| b = finf | |
| assert mpf_le(a, b), "endpoints must be properly ordered" | |
| return ctx.make_mpf((a, b)) | |
| def nstr(ctx, x, n=5, **kwargs): | |
| x = ctx.convert(x) | |
| if hasattr(x, "_mpi_"): | |
| return libmp.mpi_to_str(x._mpi_, n, **kwargs) | |
| if hasattr(x, "_mpci_"): | |
| re = libmp.mpi_to_str(x._mpci_[0], n, **kwargs) | |
| im = libmp.mpi_to_str(x._mpci_[1], n, **kwargs) | |
| return "(%s + %s*j)" % (re, im) | |
| def mag(ctx, x): | |
| x = ctx.convert(x) | |
| if isinstance(x, ctx.mpc): | |
| return max(ctx.mag(x.real), ctx.mag(x.imag)) + 1 | |
| a, b = libmp.mpi_abs(x._mpi_) | |
| sign, man, exp, bc = b | |
| if man: | |
| return exp+bc | |
| if b == fzero: | |
| return ctx.ninf | |
| if b == fnan: | |
| return ctx.nan | |
| return ctx.inf | |
| def isnan(ctx, x): | |
| return False | |
| def isinf(ctx, x): | |
| return x == ctx.inf | |
| def isint(ctx, x): | |
| x = ctx.convert(x) | |
| a, b = x._mpi_ | |
| if a == b: | |
| sign, man, exp, bc = a | |
| if man: | |
| return exp >= 0 | |
| return a == fzero | |
| return None | |
| def ldexp(ctx, x, n): | |
| a, b = ctx.convert(x)._mpi_ | |
| a = libmp.mpf_shift(a, n) | |
| b = libmp.mpf_shift(b, n) | |
| return ctx.make_mpf((a,b)) | |
| def absmin(ctx, x): | |
| return abs(ctx.convert(x)).a | |
| def absmax(ctx, x): | |
| return abs(ctx.convert(x)).b | |
| def atan2(ctx, y, x): | |
| y = ctx.convert(y)._mpi_ | |
| x = ctx.convert(x)._mpi_ | |
| return ctx.make_mpf(libmp.mpi_atan2(y,x,ctx.prec)) | |
| def _convert_param(ctx, x): | |
| if isinstance(x, libmp.int_types): | |
| return x, 'Z' | |
| if isinstance(x, tuple): | |
| p, q = x | |
| return (ctx.mpf(p) / ctx.mpf(q), 'R') | |
| x = ctx.convert(x) | |
| if isinstance(x, ctx.mpf): | |
| return x, 'R' | |
| if isinstance(x, ctx.mpc): | |
| return x, 'C' | |
| raise ValueError | |
| def _is_real_type(ctx, z): | |
| return isinstance(z, ctx.mpf) or isinstance(z, int_types) | |
| def _is_complex_type(ctx, z): | |
| return isinstance(z, ctx.mpc) | |
| def hypsum(ctx, p, q, types, coeffs, z, maxterms=6000, **kwargs): | |
| coeffs = list(coeffs) | |
| num = range(p) | |
| den = range(p,p+q) | |
| #tol = ctx.eps | |
| s = t = ctx.one | |
| k = 0 | |
| while 1: | |
| for i in num: t *= (coeffs[i]+k) | |
| for i in den: t /= (coeffs[i]+k) | |
| k += 1; t /= k; t *= z; s += t | |
| if t == 0: | |
| return s | |
| #if abs(t) < tol: | |
| # return s | |
| if k > maxterms: | |
| raise ctx.NoConvergence | |
| # Register with "numbers" ABC | |
| # We do not subclass, hence we do not use the @abstractmethod checks. While | |
| # this is less invasive it may turn out that we do not actually support | |
| # parts of the expected interfaces. See | |
| # http://docs.python.org/2/library/numbers.html for list of abstract | |
| # methods. | |
| try: | |
| import numbers | |
| numbers.Complex.register(ivmpc) | |
| numbers.Real.register(ivmpf) | |
| except ImportError: | |
| pass | |