75 lines
2.0 KiB
Python
75 lines
2.0 KiB
Python
from packaging.version import Version, parse
|
|
|
|
import numpy as np
|
|
import scipy
|
|
|
|
SP_VERSION = parse(scipy.__version__)
|
|
SP_LT_15 = SP_VERSION < Version("1.4.99")
|
|
SCIPY_GT_14 = not SP_LT_15
|
|
SP_LT_16 = SP_VERSION < Version("1.5.99")
|
|
SP_LT_17 = SP_VERSION < Version("1.6.99")
|
|
SP_LT_19 = SP_VERSION < Version("1.8.99")
|
|
|
|
|
|
def _next_regular(target):
|
|
"""
|
|
Find the next regular number greater than or equal to target.
|
|
Regular numbers are composites of the prime factors 2, 3, and 5.
|
|
Also known as 5-smooth numbers or Hamming numbers, these are the optimal
|
|
size for inputs to FFTPACK.
|
|
|
|
Target must be a positive integer.
|
|
"""
|
|
if target <= 6:
|
|
return target
|
|
|
|
# Quickly check if it's already a power of 2
|
|
if not (target & (target - 1)):
|
|
return target
|
|
|
|
match = float("inf") # Anything found will be smaller
|
|
p5 = 1
|
|
while p5 < target:
|
|
p35 = p5
|
|
while p35 < target:
|
|
# Ceiling integer division, avoiding conversion to float
|
|
# (quotient = ceil(target / p35))
|
|
quotient = -(-target // p35)
|
|
# Quickly find next power of 2 >= quotient
|
|
p2 = 2 ** ((quotient - 1).bit_length())
|
|
|
|
N = p2 * p35
|
|
if N == target:
|
|
return N
|
|
elif N < match:
|
|
match = N
|
|
p35 *= 3
|
|
if p35 == target:
|
|
return p35
|
|
if p35 < match:
|
|
match = p35
|
|
p5 *= 5
|
|
if p5 == target:
|
|
return p5
|
|
if p5 < match:
|
|
match = p5
|
|
return match
|
|
|
|
|
|
def _valarray(shape, value=np.nan, typecode=None):
|
|
"""Return an array of all value."""
|
|
|
|
out = np.ones(shape, dtype=bool) * value
|
|
if typecode is not None:
|
|
out = out.astype(typecode)
|
|
if not isinstance(out, np.ndarray):
|
|
out = np.asarray(out)
|
|
return out
|
|
|
|
|
|
if SP_LT_16:
|
|
# copied from scipy, added to scipy in 1.6.0
|
|
from ._scipy_multivariate_t import multivariate_t # noqa: F401
|
|
else:
|
|
from scipy.stats import multivariate_t # noqa: F401
|