Coverage for /usr/lib/python3/dist-packages/sympy/polys/domains/mpelements.py: 52%
121 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
1"""Real and complex elements. """
4from sympy.polys.domains.domainelement import DomainElement
5from sympy.utilities import public
7from mpmath.ctx_mp_python import PythonMPContext, _mpf, _mpc, _constant
8from mpmath.libmp import (MPZ_ONE, fzero, fone, finf, fninf, fnan,
9 round_nearest, mpf_mul, repr_dps, int_types,
10 from_int, from_float, from_str, to_rational)
11from mpmath.rational import mpq
14@public
15class RealElement(_mpf, DomainElement):
16 """An element of a real domain. """
18 __slots__ = ('__mpf__',)
20 def _set_mpf(self, val):
21 self.__mpf__ = val
23 _mpf_ = property(lambda self: self.__mpf__, _set_mpf)
25 def parent(self):
26 return self.context._parent
28@public
29class ComplexElement(_mpc, DomainElement):
30 """An element of a complex domain. """
32 __slots__ = ('__mpc__',)
34 def _set_mpc(self, val):
35 self.__mpc__ = val
37 _mpc_ = property(lambda self: self.__mpc__, _set_mpc)
39 def parent(self):
40 return self.context._parent
42new = object.__new__
44@public
45class MPContext(PythonMPContext):
47 def __init__(ctx, prec=53, dps=None, tol=None, real=False):
48 ctx._prec_rounding = [prec, round_nearest]
50 if dps is None:
51 ctx._set_prec(prec)
52 else:
53 ctx._set_dps(dps)
55 ctx.mpf = RealElement
56 ctx.mpc = ComplexElement
57 ctx.mpf._ctxdata = [ctx.mpf, new, ctx._prec_rounding]
58 ctx.mpc._ctxdata = [ctx.mpc, new, ctx._prec_rounding]
60 if real:
61 ctx.mpf.context = ctx
62 else:
63 ctx.mpc.context = ctx
65 ctx.constant = _constant
66 ctx.constant._ctxdata = [ctx.mpf, new, ctx._prec_rounding]
67 ctx.constant.context = ctx
69 ctx.types = [ctx.mpf, ctx.mpc, ctx.constant]
70 ctx.trap_complex = True
71 ctx.pretty = True
73 if tol is None:
74 ctx.tol = ctx._make_tol()
75 elif tol is False:
76 ctx.tol = fzero
77 else:
78 ctx.tol = ctx._convert_tol(tol)
80 ctx.tolerance = ctx.make_mpf(ctx.tol)
82 if not ctx.tolerance:
83 ctx.max_denom = 1000000
84 else:
85 ctx.max_denom = int(1/ctx.tolerance)
87 ctx.zero = ctx.make_mpf(fzero)
88 ctx.one = ctx.make_mpf(fone)
89 ctx.j = ctx.make_mpc((fzero, fone))
90 ctx.inf = ctx.make_mpf(finf)
91 ctx.ninf = ctx.make_mpf(fninf)
92 ctx.nan = ctx.make_mpf(fnan)
94 def _make_tol(ctx):
95 hundred = (0, 25, 2, 5)
96 eps = (0, MPZ_ONE, 1-ctx.prec, 1)
97 return mpf_mul(hundred, eps)
99 def make_tol(ctx):
100 return ctx.make_mpf(ctx._make_tol())
102 def _convert_tol(ctx, tol):
103 if isinstance(tol, int_types):
104 return from_int(tol)
105 if isinstance(tol, float):
106 return from_float(tol)
107 if hasattr(tol, "_mpf_"):
108 return tol._mpf_
109 prec, rounding = ctx._prec_rounding
110 if isinstance(tol, str):
111 return from_str(tol, prec, rounding)
112 raise ValueError("expected a real number, got %s" % tol)
114 def _convert_fallback(ctx, x, strings):
115 raise TypeError("cannot create mpf from " + repr(x))
117 @property
118 def _repr_digits(ctx):
119 return repr_dps(ctx._prec)
121 @property
122 def _str_digits(ctx):
123 return ctx._dps
125 def to_rational(ctx, s, limit=True):
126 p, q = to_rational(s._mpf_)
128 if not limit or q <= ctx.max_denom:
129 return p, q
131 p0, q0, p1, q1 = 0, 1, 1, 0
132 n, d = p, q
134 while True:
135 a = n//d
136 q2 = q0 + a*q1
137 if q2 > ctx.max_denom:
138 break
139 p0, q0, p1, q1 = p1, q1, p0 + a*p1, q2
140 n, d = d, n - a*d
142 k = (ctx.max_denom - q0)//q1
144 number = mpq(p, q)
145 bound1 = mpq(p0 + k*p1, q0 + k*q1)
146 bound2 = mpq(p1, q1)
148 if not bound2 or not bound1:
149 return p, q
150 elif abs(bound2 - number) <= abs(bound1 - number):
151 return bound2._mpq_
152 else:
153 return bound1._mpq_
155 def almosteq(ctx, s, t, rel_eps=None, abs_eps=None):
156 t = ctx.convert(t)
157 if abs_eps is None and rel_eps is None:
158 rel_eps = abs_eps = ctx.tolerance or ctx.make_tol()
159 if abs_eps is None:
160 abs_eps = ctx.convert(rel_eps)
161 elif rel_eps is None:
162 rel_eps = ctx.convert(abs_eps)
163 diff = abs(s-t)
164 if diff <= abs_eps:
165 return True
166 abss = abs(s)
167 abst = abs(t)
168 if abss < abst:
169 err = diff/abst
170 else:
171 err = diff/abss
172 return err <= rel_eps