| | 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_) |
| |
|
| | @property |
| | def real(self): return self |
| |
|
| | @property |
| | def imag(self): return self.ctx.zero |
| |
|
| | def conjugate(self): return self |
| |
|
| | @property |
| | def a(self): |
| | a, b = self._mpi_ |
| | return self.ctx.make_mpf((a, a)) |
| |
|
| | @property |
| | def b(self): |
| | a, b = self._mpi_ |
| | return self.ctx.make_mpf((b, b)) |
| |
|
| | @property |
| | def mid(self): |
| | ctx = self.ctx |
| | v = mpi_mid(self._mpi_, ctx.prec) |
| | return ctx.make_mpf((v, v)) |
| |
|
| | @property |
| | def delta(self): |
| | ctx = self.ctx |
| | v = mpi_delta(self._mpi_, ctx.prec) |
| | return ctx.make_mpf((v,v)) |
| |
|
| | @property |
| | 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)) |
| |
|
| | @property |
| | def a(self): |
| | (a, b), (c,d) = self._mpci_ |
| | return self.ctx.make_mpf((a, a)) |
| |
|
| | @property |
| | def b(self): |
| | (a, b), (c,d) = self._mpci_ |
| | return self.ctx.make_mpf((b, b)) |
| |
|
| | @property |
| | def c(self): |
| | (a, b), (c,d) = self._mpci_ |
| | return self.ctx.make_mpf((c, c)) |
| |
|
| | @property |
| | def d(self): |
| | (a, b), (c,d) = self._mpci_ |
| | return self.ctx.make_mpf((d, d)) |
| |
|
| | @property |
| | def real(s): |
| | return s.ctx.make_mpf(s._mpci_[0]) |
| |
|
| | @property |
| | 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 |
| |
|
| | @classmethod |
| | 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) |
| | |
| | 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 k > maxterms: |
| | raise ctx.NoConvergence |
| |
|
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | try: |
| | import numbers |
| | numbers.Complex.register(ivmpc) |
| | numbers.Real.register(ivmpf) |
| | except ImportError: |
| | pass |
| |
|