1 """Provides algorithms from number theory.
4 from ..core
import init_module
6 init_module
.import_lowlevel_operations()
8 from .numbers
import mpq
, div
11 __all__
= ['gcd', 'lcm', 'factorial',
12 'integer_digits', 'real_digits',
13 'multinomial_coefficients', 'f2q']
15 __docformat__
= "restructuredtext en"
17 def factorial(n
, memo
=[1, 1]):
18 """Return n factorial (for integers n >= 0 only)."""
20 raise ValueError("expected non-negative integer, got %r" % (n
)) #pragma NO COVER
33 """Calculate the greatest common divisor (GCD) of the arguments."""
36 if L
== 1: return args
[0]
42 return gcd(gcd(args
[0], args
[1]), *args
[2:])
45 """Calculate the least common multiple (LCM) of the arguments."""
48 if L
== 1: return args
[0]
49 if L
== 2: return div(args
[0], gcd(*args
))*args
[1]
50 return lcm(lcm(args
[0], args
[1]), *args
[2:])
52 # TODO: this could use the faster implementation in mpmath
53 def integer_digits(n
, base
=10):
54 """Return a list of the digits of abs(n) in the given base."""
56 assert isinstance(n
, (int, long))
62 n
, digit
= divmod(n
, base
)
66 # TODO: this could (also?) be implemented as an endless generator
67 def real_digits(x
, base
=10, truncation
=10):
68 """Return ``(L, d)`` where L is a list of digits of ``abs(x)`` in
69 the given base and ``d`` is the (signed) distance from the leading
70 digit to the radix point.
72 For example, 1234.56 becomes ``([1, 2, 3, 4, 5, 6], 4)`` and 0.001
73 becomes ``([1], -2)``. If, during the generation of fractional
74 digits, the length reaches `truncation` digits, the iteration is
77 assert isinstance(x
, (int, long, mpq
))
85 integer
, fraction
= divmod(x
, 1)
86 L
= integer_digits(integer
, base
)
90 for i
in xrange(truncation
- len(L
)):
97 def binomial_coefficients(n
):
98 """Return a dictionary containing pairs {(k1,k2) : C_kn} where
99 C_kn are binomial coefficients and n=k1+k2.
108 >>> sorted(binomial_coefficients(3).items())
109 [((0, 3), 1), ((1, 2), 3), ((2, 1), 3), ((3, 0), 1)]
111 Notice the coefficients above are the same as below:
112 x**3 + 3*x**2*y + 3*x*y**2 + y^3
115 d
= {(0, n
):1, (n
, 0):1}
117 for k
in xrange(1, n
//2+1):
119 d
[k
, n
-k
] = d
[n
-k
, k
] = a
122 def binomial_coefficients_list(n
):
123 """Return a list of binomial coefficients as rows of the Pascal's
128 for k
in xrange(1, n
//2+1):
133 def multinomial_coefficients(m
, n
, _tuple
=tuple, _zip
=zip):
134 """Return a dictionary containing pairs ``{(k1,k2,..,km) : C_kn}``
135 where ``C_kn`` are multinomial coefficients such that
141 _tuple, _zip -- hacks for speed; don't set these as a user.
147 >>> sorted(multinomial_coefficients(2,5).items())
148 [((0, 5), 1), ((1, 4), 5), ((2, 3), 10), ((3, 2), 10), ((4, 1), 5), ((5, 0), 1)]
150 Notice that these are the coefficients of ``(x+y)**5``:
151 x**5 + 5*x**4*y + 10*x**3*y**2 + 10*x**2*y**3 + 5*x*y**4 + y**5
153 >>> sorted(multinomial_coefficients(3,2).items())
154 [((0, 0, 2), 1), ((0, 1, 1), 2), ((0, 2, 0), 1), ((1, 0, 1), 2), ((1, 1, 0), 2), ((2, 0, 0), 1)]
158 The algorithm we implement for computing the multinomial coefficients
159 is based on the following result:
161 Consider a polynomial and its ``n``-th exponent::
163 P(x) = sum_{i=0}^m p_i x^k
164 P(x)^n = sum_{k=0}^{m n} a(n,k) x^k
166 We compute the coefficients ``a(n,k)`` using the
167 J.C.P. Miller Pure Recurrence [see D.E.Knuth, Seminumerical
168 Algorithms, The art of Computer Programming v.2, Addison
169 Wesley, Reading, 1981;]::
171 a(n,k) = 1/(k p_0) sum_{i=1}^m p_i ((n+1)i-k) a(n,k-i),
173 where ``a(n,0) = p_0^n``.
178 return binomial_coefficients(n
)
179 symbols
= [(0,)*i
+ (1,) + (0,)*(m
-i
-1) for i
in range(m
)]
181 p0
= [_tuple([aa
-bb
for aa
,bb
in _zip(s
,s0
)]) for s
in symbols
]
182 r
= {_tuple([aa
*n
for aa
in s0
]):1}
185 l
= [0] * (n
*(m
-1)+1)
187 for k
in xrange(1, n
*(m
-1)+1):
190 for i
in xrange(1, min(m
,k
+1)):
195 for t2
, c2
in l
[k
-i
]:
196 tt
= _tuple([aa
+bb
for aa
,bb
in _zip(t2
,t
)])
198 dict_add_item(None, d
, tt
, cc
)
199 r1
= [(t
, c
//k
) for (t
, c
) in d
.iteritems()]
205 """abs(x-y)/((abs(x)+abs(y))/2)"""
206 return abs(x
-y
)/((abs(x
)+abs(y
))/2)
208 def f2q(f
, minerr
=None):
210 Find (almost) the best rational representation of a float that has
213 The algorithm is based on Stern-Brocot representation of
214 irrational/rational numbers and its relation to continuants [1].
217 [1] "Concrete Mathematics" by Graham, Knuth, and Patashnik. Addison-Wesley. 1989
219 if mpmath
.libmp
.BACKEND
=='gmpy':
220 tmpz
= type(mpmath
.libmp
.MPZ_ZERO
)
222 r
= mpmath
.libmp
.gmpy
.f2q(f
)
224 r
= mpmath
.libmp
.gmpy
.f2q(f
, minerr
)
225 if isinstance (r
, tmpz
):
227 n
,d
= int(r
.numer ()), int(r
.denom ())
233 if f
<0: return -f2q(-f
,minerr
)
234 al
= f
# Initialize Eq.(6.142) [1]
236 minerr
= 1/mpf(2**al
.context
.prec
) # min number for the given precision
238 minerr
= 1/mpf(2**-minerr
)
239 a
= mpmath
.floor(al
) # a = floor(al) # Initialize Eq.(6.142) [1]
240 r1
=[0,0,1] # r1[1:] is 1st row of Eq.(6.138) [1]
241 r2
=[0,1,a
] # r2[1:] is 2nd row of Eq.(6.138) [1]
244 al
= 1/(al
-a
) # Eq.(6.142) [1]
245 a
= mpmath
.floor(al
) # a = floor(al) # Eq.(6.142) [1]
248 r1
[2] = r1
[1]*a
+r1
[0] # use Eq.(6.127) [1]
251 r2
[2] = r2
[1]*a
+r2
[0] # use Eq.(6.127) [1]
252 newerr
= reldiff(f
,r2
[2]/r1
[2])
254 n
, d
= (int(r2
[1]),int(r1
[1]))
258 n
, d
= (int(r2
[2]),int(r1
[2]))
263 #from .combinatorics import multinomial_coefficients