def pattern_uint64_width(ord): """ Return number of 64-bit words occupied by a pattern of order `ord`. Depending on the order, the numerical representation of an ordinal pattern requires a certain number of bits. This function rounds the bit width up to the next-greatest multiple of a 64-bit machine word. Parameters ---------- ord : int Pattern order between 2 and 255. Returns ------- width : int An integer between 1 and 27. """ if not is_scalar_int(ord): raise TypeError("order must be a scalar integer") if ord < 2 or ord > 255: raise ValueError("order must be between 2 and 255") n_pats = _factorial(ord) n_bits = _log(n_pats, 2) n_words = _ceil(n_bits / 64) return int(n_words)
def check_lookup_table(tab, ord): """ Raise an error if `tab` is not a valid lookup table. Parameters ---------- tab : possibly a duck Python object to be tested. ord : int Pattern order between 2 and 10. """ if not is_scalar_int(ord): raise TypeError("ord must be a scalar integer") if ord < 2 or ord > 10: raise ValueError("ord must be between 2 and 10") if not isinstance(tab, _np.ndarray): raise TypeError("tab must be an ndarray") if not tab.dtype == _np.uint64: raise TypeError("tab must have dtype uint64") if not tab.flags["CA"]: raise TypeError("tab must be contiguous and word-aligned") if not tab.shape == (_factorial(ord), ord): raise ValueError("tab must have shape ord! x ord") # Invalid codes may cause segmentation fault. if (tab >= tab.shape[0]).any(): raise ValueError("tab contains invalid pattern codes")
def create_lookup_table(ord): """ Return pattern table to be used with the 'lookup' algorithm. The pattern order must be an integer greater than 1. Because the table size increases super-exponentially with the pattern order, only orders `ord` < 11 are accepted. (A lookup table for `ord` == 11 would occupy more than 3 GiB of memory). Parameters ---------- ord : int Pattern order between 2 and 10. Returns ------- table : ndarray of uint64 A lookup table containing factorial(ord) * ord pattern codes. Each code is a value between 0 and factorial(ord) - 1. """ if not _utils.is_scalar_int(ord): raise TypeError("order must be a scalar integer") if ord < 2 or ord > 10: raise ValueError("order must be between 2 and 10") table = _np.empty((_factorial(ord), ord), dtype=_np.uint64) ret = _lib.ordpat_create_lookup_table(table, table.size, ord) if not ret == 0: _raise_api_error(ret) return table
def pattern_word_size(ord): """ Return word size of an ordinal pattern of order ord. Depending on the order, the numerical representation of an ordinal pattern requires a certain number of bits. This function rounds the bit width up to the next-greatest machine word. Parameters ---------- ord : int Pattern order between 2 and 20. Returns ------- width : int Either 8, 16, 32 or 64. """ if not is_scalar_int(ord): raise TypeError("order must be a scalar integer") if ord < 2 or ord > 20: raise ValueError("order must be between 2 and 20") n_pats = _factorial(ord) n_bits = _log(n_pats, 2) exp = _ceil(_log(n_bits, 2)) return int(max(8, 2**exp))
def fact(n): if _is_pointZero(n): if 0 <= n <= 64: return _factorial(n) elif n < 0: raise MathError('<font color=red>fact()</font> ' +\ translate('MathErrors', _errors['nv'])) else: raise MathError('<font color=red>fact()</font> ' +\ translate('MathErrors', _errors['fac64'])) else: raise MathError('<font color=red>fact()</font> ' +\ translate('MathErrors', _errors['oiv']))
def get_states_number(start, end, length): curr_l = (start - end) // 2 + 1 curr_s = (start + end + 1) // 2 nom = 1 for _ in range(length): nom *= curr_l * curr_s curr_l -= 1 curr_s -= 1 denom = _factorial(length) denom *= denom result = nom // denom return result
def multinomial_coefficient(tup): """ Multinomial coefficient for a tuple of objects. No sorting (and no checks!). :Parameters: - `tup`: tuple :Returns: integer :Example: >>> multinomial_coefficient((1,2)) 2 >>> multinomial_coefficient((1,1,2)) 3 >>> multinomial_coefficient((1,2,1)) # no sorting 6 >>> multinomial_coefficient((1,1,1)) 1 """ if tuple(tup) == (): return 1 numer = _factorial(len(tup)) denom = 1 count = 1 tup = list(tup) prev = tup.pop(0) for i in tup: if i == prev: count += 1 else: denom *= _factorial(count) prev = i count = 1 denom *= _factorial(count) return int(numer/denom)
def create_lookup_table(ord): """ Return pattern table to be used with the 'lookup' algorithm. The pattern order must be an integer greater than 1. Because the table size increases super-exponentially with the pattern order, only orders `ord` < 11 are accepted. (A lookup table for `ord` == 11 would occupy more than 3 GiB of memory). Parameters ---------- ord : int Pattern order between 2 and 10. Returns ------- table : ndarray of uint64 A lookup table containing factorial(ord) * ord pattern codes. Each code is a value between 0 and factorial(ord) - 1. """ if not _utils.is_scalar_int(ord): raise TypeError("order must be a scalar integer") if ord < 2 or ord > 10: raise ValueError("order must be between 2 and 10") pat = 2 * _utils.pattern_table(ord - 1) pat = pat.repeat(ord, 0) val = _np.arange(2.0 * ord - 1, 0, -2) val = val.reshape((ord, 1)) val = _np.tile(val, (_factorial(ord - 1), 1)) pat = _np.concatenate((pat, val), axis=1) tab = encode_vectorised(pat, ord, 1, trustme=True) tab = tab.reshape((-1, ord)) tab = _np.tile(tab, (ord, 1)) return tab
def _comb(n,k): return _factorial(n) / (_factorial(n-k) * _factorial(k))
def _comb(n, k): # NB: Python 3.8 has math.comb() return _factorial(n) // _factorial(k) // _factorial(n - k)
def p020(number): return sum(map(int, str(_factorial(number))))
def encode_vectorised(x, ord, lag, axis=-1, trustme=False): """ Extract and encode ordinal patterns using the 'vectorised' algorithm. Parameters ---------- x : array_like Time series data to be encoded. Can be multi-dimensional, and must be convertible to an ndarray of data type 'double'. ord : int Order of the encoding, an integer between 2 and 20. lag : int Time lag used for creating embedding vectors. Must be a positive integer. axis : int, optional The axis of the input data along which the extraction shall be performed. By default, the last axis is used. trustme : bool, optional If set to True, the function arguments are not validated before processing. This will speed up the calculation. Returns ------- pat : ndarray of uint64 Each value represents an ordinal pattern. The shape of the `pat` array is equal to the input array `x`, except for the axis on which the encoding is performed. For this axis, it holds that ``pat.shape[axis] == x.shape[axis] - (ord - 1) * lag``. """ if not trustme: x = _utils.prepare_input_data(x, ord, lag, axis) if ord > 20: raise ValueError("vectorised algorithm does not support ord > 20") _scope['x'] = _np.moveaxis(x, axis, 0) if (_scope['order'] != ord) or (_scope['lag'] != lag): cmd = "" for idx in range(1, ord + 1): fwd = (idx - 1) * lag rev = (ord - idx) * lag cmd += "x{0} = x[{1}:{2}]\n".format(idx, fwd, -rev or None) cmd += "\ny = " word_size = _utils.pattern_word_size(ord) for i in range(1, ord): cmd += "{0} * (".format(_factorial(ord - i)) cmd += "(x{0} > x{1})".format(i, i + 1) cmd += ".astype(_np.uint8)" for j in range(i + 2, ord + 1): cmd += " + (x{0} > x{1})".format(i, j) cmd += ").astype(_np.uint{0})".format(word_size) if i == ord - 1: cmd += "\n" else: cmd += " + \\\n" + " " * 4 _scope['cmd'] = compile(cmd, "<string>", "exec") _scope['order'] = ord _scope['lag'] = lag exec(_scope['cmd'], None, _scope) pat = _scope['y'] pat = _np.moveaxis(pat, 0, axis) return pat.astype(_np.uint64)
def encode_overlap(x, ord, lag, trustme=False): """ Extract and encode ordinal patterns using the 'overlap' algorithm. Parameters ---------- x : array_like Time series data to be encoded. Can be multi-dimensional, and must be convertible to an ndarray of data type 'double'. The input array is flattened prior to encoding. ord : int Order of the encoding, an integer between 2 and 20. lag : int Time lag used for creating embedding vectors. Must be a positive integer. trustme : bool, optional If set to True, the function arguments are not validated before processing. This will speed up the calculation. Returns ------- pat : ndarray of uint64 One-dimensional array, with each value representing an ordinal pattern. It holds that ``pat.size == x.size - (ord - 1) * lag``. """ if not trustme: x = _utils.prepare_input_data(x, ord, lag) if ord > 20: raise ValueError("overlap algorithm does not support ord > 20") n_rel = ord - 1 # number of order relations n_pat = x.size - n_rel * lag # sequence length pat = _np.zeros(n_pat, dtype=_np.uint64) ranks = _np.zeros([lag, n_rel], dtype=_np.uint8) radix = [_factorial(r) for r in range(n_rel, 0, -1)] radix = _np.array(radix, dtype=_np.uint64) for k in range(0, lag): for i in range(0, n_rel - 1): for j in range(i + 1, n_rel): ranks[k, i + 1] += x[k + i * lag] > x[k + j * lag] i = 0 for k in range(0, n_pat): ranks[i] = _np.roll(ranks[i], -1) ranks[i, -1] = 0 updates = x[k:k + n_rel * lag:lag] > x[k + n_rel * lag] ranks[i] += updates pat[k] = _np.matmul(radix, ranks[i]) i = (i + 1) % lag return pat
def _comb(n, k): return _factorial(n) / (_factorial(n - k) * _factorial(k))