mixle.engines package¶
Public compute-engine registry and precision front door for Mixle kernels.
This namespace exposes the NumPy, Torch, JAX, symbolic, and precision-aware engine utilities used by backend-neutral scoring, estimation, and data-transfer paths.
- class ComputeEngine[source]
Bases:
ABCSmall array-backend interface for numpy/torch/etc.
Engines own arithmetic policy: array library, device, dtype, and optional compilation. Distribution and kernel code should depend only on this surface when it wants backend-neutral arrays.
- is_concrete(x)[source]
Return whether
xholds real values now, so host-side inspection of it is meaningful.Every eager backend answers True. A tracing backend (JAX under
jit) answers False for a traced value: its contents are not available in Python, soto_numpyraises and any control flow branching on them is impossible by construction. Shared code that wants to run an optional host-side diagnostic – scanning for NaN rows to name them in an exception, say – asks first and skips the diagnostic while tracing; the engine math itself is unaffected either way.
- constant(value)[source]
Return
valuein this engine’s scalar representation (identity for numeric engines).
- property accumulator_dtype: Any
High-precision dtype for sufficient-statistic reductions, or
Nonewhen not applicable.Numeric engines override this with their float64 accumulator so a reduced-precision fit does not drift on large N (see
NumpyEngine/TorchEngine). The base returnsNone: meaning “no separate accumulator dtype”, which is the correct policy for engines that never drive the numeric accumulate path (e.g. the symbolic engine, where reductions are exact expression trees).Noneis also a validdtype=argument tosum(NumPy’s default).
- property precision: str
Return the engine dtype policy as a stable user-facing name.
- with_precision(precision)[source]
Return an equivalent engine with a different floating-point policy.
- Parameters:
precision (Any)
- Return type:
ComputeEngine
- abstractmethod asarray(x, dtype=None)[source]
Convert
xinto this engine’s array/tensor representation.
- abstractmethod zeros(shape, dtype=None)[source]
Allocate a zero-filled array on this engine.
- abstractmethod empty(shape, dtype=None)[source]
Allocate an uninitialized array on this engine.
- abstractmethod arange(*args, **kwargs)[source]
Return an evenly spaced one-dimensional array on this engine.
- abstractmethod to_numpy(x)[source]
Move an engine array back to a NumPy/host representation.
- abstractmethod stack(arrays, axis=0)[source]
Stack a sequence of arrays along
axis.
- abstractmethod concatenate(arrays, axis=0)[source]
Join a sequence of arrays along an existing
axis.
- requires_grad(x)[source]
Return whether
xparticipates in this engine’s autograd graph.
- compile(fn)[source]
Optionally compile
fn; engines without a compiler return it unchanged.
- replicate(x)[source]
Return
xin the engine’s replicated placement, when applicable.
- class NumpyEngine(dtype=None, prefer_fused=False)[source]
Bases:
ComputeEngineHost NumPy/SciPy engine used by the default local execution path.
- Parameters:
dtype (Any)
prefer_fused (bool)
- property accumulator_dtype: Any
High-precision dtype for sufficient-statistic reductions (always float64).
Reductions that aggregate over observations (the sum/index-add forming sufficient statistics) accumulate in this dtype even when scoring runs in reduced precision, so a float32 fit does not drift on large N (e.g. catastrophic cancellation in a variance).
- with_precision(precision)[source]
Return a NumPy engine using
precisionfor floating arrays.- Parameters:
precision (Any)
- Return type:
NumpyEngine
- asarray(x, dtype=None)[source]
Convert
xto a NumPy ndarray under the engine dtype policy.
- zeros(shape, dtype=None)[source]
Allocate a NumPy zero array using the configured float dtype.
- empty(shape, dtype=None)[source]
Allocate an uninitialized NumPy array using the configured float dtype.
- arange(*args, **kwargs)[source]
Return
np.arangewith float ranges honoring the precision policy.
- stack(arrays, axis=0)[source]
Stack arrays with
np.stackalong the requested axis.
- concatenate(arrays, axis=0)[source]
Join arrays with
np.concatenatealong the requested axis.
- log = <ufunc 'log'>
- exp = <ufunc 'exp'>
- sqrt = <ufunc 'sqrt'>
- abs = <ufunc 'absolute'>
- static where(condition, [x, y, ]/)
Return elements chosen from x or y depending on condition.
Note
When only condition is provided, this function is a shorthand for
np.asarray(condition).nonzero(). Using nonzero directly should be preferred, as it behaves correctly for subclasses. The rest of this documentation covers only the case where all three arguments are provided.- Parameters:
condition (array_like, bool) – Where True, yield x, otherwise yield y.
x (array_like) – Values from which to choose. x, y and condition need to be broadcastable to some shape.
y (array_like) – Values from which to choose. x, y and condition need to be broadcastable to some shape.
- Returns:
out – An array with elements from x where condition is True, and elements from y elsewhere.
- Return type:
ndarray
See also
choosenonzeroThe function that is called when x and y are omitted
Notes
If all the arrays are 1-D, where is equivalent to:
[xv if c else yv for c, xv, yv in zip(condition, x, y)]
Examples
>>> import numpy as np >>> a = np.arange(10) >>> a array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) >>> np.where(a < 5, a, 10*a) array([ 0, 1, 2, 3, 4, 50, 60, 70, 80, 90])
This can be used on multidimensional arrays too:
>>> np.where([[True, False], [True, True]], ... [[1, 2], [3, 4]], ... [[9, 8], [7, 6]]) array([[1, 8], [3, 4]])
The shapes of x, y, and the condition are broadcast together:
>>> x, y = np.ogrid[:3, :4] >>> np.where(x < y, x, 10 + y) # both x and 10+y are broadcast array([[10, 0, 0, 0], [10, 11, 1, 1], [10, 11, 12, 2]])
>>> a = np.array([[0, 1, 2], ... [0, 2, 4], ... [0, 3, 6]]) >>> np.where(a < 4, a, -1) # -1 is broadcast array([[ 0, 1, 2], [ 0, 2, -1], [ 0, 3, -1]])
- maximum = <ufunc 'maximum'>
- static clip(a, a_min=np._NoValue, a_max=np._NoValue, out=None, *, min=np._NoValue, max=np._NoValue, **kwargs)
Clip (limit) the values in an array.
Given an interval, values outside the interval are clipped to the interval edges. For example, if an interval of
[0, 1]is specified, values smaller than 0 become 0, and values larger than 1 become 1.Equivalent to but faster than
np.minimum(a_max, np.maximum(a, a_min)).No check is performed to ensure
a_min < a_max.- Parameters:
a (array_like) – Array containing elements to clip.
a_min (array_like or None) – Minimum and maximum value. If
None, clipping is not performed on the corresponding edge. If botha_minanda_maxareNone, the elements of the returned array stay the same. Both are broadcasted againsta.a_max (array_like or None) – Minimum and maximum value. If
None, clipping is not performed on the corresponding edge. If botha_minanda_maxareNone, the elements of the returned array stay the same. Both are broadcasted againsta.out (ndarray, optional) – The results will be placed in this array. It may be the input array for in-place clipping. out must be of the right shape to hold the output. Its type is preserved.
min (array_like or None) –
Array API compatible alternatives for
a_minanda_maxarguments. Eithera_minanda_maxorminandmaxcan be passed at the same time. Default:None.Added in version 2.1.0.
max (array_like or None) –
Array API compatible alternatives for
a_minanda_maxarguments. Eithera_minanda_maxorminandmaxcan be passed at the same time. Default:None.Added in version 2.1.0.
**kwargs – For other keyword-only arguments, see the ufunc docs.
- Returns:
clipped_array – An array with the elements of a, but where values < a_min are replaced with a_min, and those > a_max with a_max.
- Return type:
ndarray
See also
Notes
When a_min is greater than a_max, clip returns an array in which all values are equal to a_max, as shown in the second example.
Examples
>>> import numpy as np >>> a = np.arange(10) >>> a array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) >>> np.clip(a, 1, 8) array([1, 1, 2, 3, 4, 5, 6, 7, 8, 8]) >>> np.clip(a, 8, 1) array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1]) >>> np.clip(a, 3, 6, out=a) array([3, 3, 3, 3, 4, 5, 6, 6, 6, 6]) >>> a array([3, 3, 3, 3, 4, 5, 6, 6, 6, 6]) >>> a = np.arange(10) >>> a array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) >>> np.clip(a, [3, 4, 1, 1, 1, 4, 4, 4, 4, 4], 8) array([3, 4, 2, 3, 4, 5, 6, 7, 8, 8])
- floor = <ufunc 'floor'>
- isnan = <ufunc 'isnan'>
- isinf = <ufunc 'isinf'>
- sum(a, *args, dtype=None, **kwargs)[source]
Reduce with
np.sum, accumulating floats inaccumulator_dtypeby default.A float32
np.sumdrifts on large N; when the caller passes no explicitdtypewe promote floating inputs to the engine’s high-precision accumulator (float64) so correctness no longer relies on every caller threadingdtype=accumulator_dtype. Integer inputs and explicit-dtype calls keep NumPy’s default behavior.
- static max(a, axis=None, out=None, keepdims=np._NoValue, initial=np._NoValue, where=np._NoValue)
Return the maximum of an array or maximum along an axis.
- Parameters:
a (array_like) – Input data.
axis (None or int or tuple of ints, optional) – Axis or axes along which to operate. By default, flattened input is used. If this is a tuple of ints, the maximum is selected over multiple axes, instead of a single axis or all the axes as before.
out (ndarray, optional) – Alternative output array in which to place the result. Must be of the same shape and buffer length as the expected output. See Output type determination for more details.
keepdims (bool, optional) –
If this is set to True, the axes which are reduced are left in the result as dimensions with size one. With this option, the result will broadcast correctly against the input array.
If the default value is passed, then keepdims will not be passed through to the
maxmethod of sub-classes of ndarray, however any non-default value will be. If the sub-class’ method does not implement keepdims any exceptions will be raised.initial (scalar, optional) – The minimum value of an output element. Must be present to allow computation on empty slice. See ~numpy.ufunc.reduce for details.
where (array_like of bool, optional) – Elements to compare for the maximum. See ~numpy.ufunc.reduce for details.
- Returns:
max – Maximum of a. If axis is None, the result is a scalar value. If axis is an int, the result is an array of dimension
a.ndim - 1. If axis is a tuple, the result is an array of dimensiona.ndim - len(axis).- Return type:
ndarray or scalar
See also
aminThe minimum value of an array along a given axis, propagating any NaNs.
nanmaxThe maximum value of an array along a given axis, ignoring any NaNs.
maximumElement-wise maximum of two arrays, propagating any NaNs.
fmaxElement-wise maximum of two arrays, ignoring any NaNs.
argmaxReturn the indices of the maximum values.
nanmin,minimum,fminNotes
NaN values are propagated, that is if at least one item is NaN, the corresponding max value will be NaN as well. To ignore NaN values (MATLAB behavior), please use nanmax.
Don’t use ~numpy.max for element-wise comparison of 2 arrays; when
a.shape[0]is 2,maximum(a[0], a[1])is faster thanmax(a, axis=0).Examples
>>> import numpy as np >>> a = np.arange(4).reshape((2,2)) >>> a array([[0, 1], [2, 3]]) >>> np.max(a) # Maximum of the flattened array 3 >>> np.max(a, axis=0) # Maxima along the first axis array([2, 3]) >>> np.max(a, axis=1) # Maxima along the second axis array([1, 3]) >>> np.max(a, where=[False, True], initial=-1, axis=0) array([-1, 3]) >>> b = np.arange(5, dtype=float) >>> b[2] = np.nan >>> np.max(b) np.float64(nan) >>> np.max(b, where=~np.isnan(b), initial=-1) 4.0 >>> np.nanmax(b) 4.0
You can use an initial value to compute the maximum of an empty slice, or to initialize it to a different value:
>>> np.max([[-50], [10]], axis=-1, initial=0) array([ 0, 10])
Notice that the initial value is used as one of the elements for which the maximum is determined, unlike for the default argument Python’s max function, which is only used for empty iterables.
>>> np.max([5], initial=6) 6 >>> max([5], default=6) 5
- static dot(a, b, out=None)
Dot product of two arrays. Specifically,
If both a and b are 1-D arrays, it is inner product of vectors (without complex conjugation).
If both a and b are 2-D arrays, it is matrix multiplication, but using
matmul()ora @ bis preferred.If either a or b is 0-D (scalar), it is equivalent to
multiply()and usingnumpy.multiply(a, b)ora * bis preferred.If a is an N-D array and b is a 1-D array, it is a sum product over the last axis of a and b.
If a is an N-D array and b is an M-D array (where
M>=2), it is a sum product over the last axis of a and the second-to-last axis of b:dot(a, b)[i,j,k,m] = sum(a[i,j,:] * b[k,:,m])
It uses an optimized BLAS library when possible (see numpy.linalg).
- Parameters:
a (array_like) – First argument.
b (array_like) – Second argument.
out (ndarray, optional) – Output argument. This must have the exact kind that would be returned if it was not used. In particular, it must have the right type, must be C-contiguous, and its dtype must be the dtype that would be returned for dot(a,b). This is a performance feature. Therefore, if these conditions are not met, an exception is raised, instead of attempting to be flexible.
- Returns:
output – Returns the dot product of a and b. If a and b are both scalars or both 1-D arrays then a scalar is returned; otherwise an array is returned. If out is given, then it is returned.
- Return type:
ndarray
- Raises:
ValueError – If the last dimension of a is not the same size as the second-to-last dimension of b.
See also
vdotComplex-conjugating dot product.
vecdotVector dot product of two arrays.
tensordotSum products over arbitrary axes.
einsumEinstein summation convention.
matmul‘@’ operator as method with out parameter.
linalg.multi_dotChained dot product.
Examples
>>> import numpy as np >>> np.dot(3, 4) 12
Neither argument is complex-conjugated:
>>> np.dot([2j, 3j], [2j, 3j]) (-13+0j)
For 2-D arrays it is the matrix product:
>>> a = [[1, 0], [0, 1]] >>> b = [[4, 1], [2, 2]] >>> np.dot(a, b) array([[4, 1], [2, 2]])
>>> a = np.arange(3*4*5*6).reshape((3,4,5,6)) >>> b = np.arange(3*4*5*6)[::-1].reshape((5,4,6,3)) >>> np.dot(a, b)[2,3,2,1,2,2] 499128 >>> sum(a[2,3,2,:] * b[1,2,:,2]) 499128
- matmul = <ufunc 'matmul'>
- static cumsum(a, axis=None, dtype=None, out=None)
Return the cumulative sum of the elements along a given axis.
- Parameters:
a (array_like) – Input array.
axis (int, optional) – Axis along which the cumulative sum is computed. The default (None) is to compute the cumsum over the flattened array.
dtype (dtype, optional) – Type of the returned array and of the accumulator in which the elements are summed. If dtype is not specified, it defaults to the dtype of a, unless a has an integer dtype with a precision less than that of the default platform integer. In that case, the default platform integer is used.
out (ndarray, optional) – Alternative output array in which to place the result. It must have the same shape and buffer length as the expected output but the type will be cast if necessary. See Output type determination for more details.
- Returns:
cumsum_along_axis – A new array holding the result is returned unless out is specified, in which case a reference to out is returned. The result has the same size as a, and the same shape as a if axis is not None or a is a 1-d array.
- Return type:
ndarray.
See also
cumulative_sumArray API compatible alternative for
cumsum.sumSum array elements.
trapezoidIntegration of array values using composite trapezoidal rule.
diffCalculate the n-th discrete difference along given axis.
Notes
Arithmetic is modular when using integer types, and no error is raised on overflow.
cumsum(a)[-1]may not be equal tosum(a)for floating-point values sincesummay use a pairwise summation routine, reducing the roundoff-error. See sum for more information.Examples
>>> import numpy as np >>> a = np.array([[1,2,3], [4,5,6]]) >>> a array([[1, 2, 3], [4, 5, 6]]) >>> np.cumsum(a) array([ 1, 3, 6, 10, 15, 21]) >>> np.cumsum(a, dtype=float) # specifies type of output value(s) array([ 1., 3., 6., 10., 15., 21.])
>>> np.cumsum(a,axis=0) # sum over rows for each of the 3 columns array([[1, 2, 3], [5, 7, 9]]) >>> np.cumsum(a,axis=1) # sum over columns for each of the 2 rows array([[ 1, 3, 6], [ 4, 9, 15]])
cumsum(b)[-1]may not be equal tosum(b)>>> b = np.array([1, 2e-9, 3e-9] * 1000000) >>> b.cumsum()[-1] 1000000.0050045159 >>> b.sum() 1000000.0050000029
- static logsumexp(a, axis=None, b=None, keepdims=False, return_sign=False)
Compute the log of the sum of exponentials of input elements.
- Parameters:
a (array_like) – Input array.
axis (None or int or tuple of ints, optional) –
Axis or axes over which the sum is taken. By default axis is None, and all elements are summed.
Added in version 0.11.0.
b (array-like, optional) –
Scaling factor for exp(a) must be of the same shape as a or broadcastable to a. These values may be negative in order to implement subtraction.
Added in version 0.12.0.
keepdims (bool, optional) –
If this is set to True, the axes which are reduced are left in the result as dimensions with size one. With this option, the result will broadcast correctly against the original array.
Added in version 0.15.0.
return_sign (bool, optional) –
If this is set to True, the result will be a pair containing sign information; if False, results that are negative will be returned as NaN. Default is False (no sign information).
Added in version 0.16.0.
- Returns:
res (ndarray) – The result,
np.log(np.sum(np.exp(a)))calculated in a numerically more stable way. If b is given thennp.log(np.sum(b*np.exp(a)))is returned. Ifreturn_signis True,rescontains the log of the absolute value of the argument.sgn (ndarray) – If
return_signis True, this will be an array of floating-point numbers matching res containing +1, 0, -1 (for real-valued inputs) or a complex phase (for complex inputs). This gives the sign of the argument of the logarithm inres. Ifreturn_signis False, only one result is returned.
See also
Notes
NumPy has a logaddexp function which is very similar to logsumexp, but only handles two arguments. logaddexp.reduce is similar to this function, but may be less stable.
The logarithm is a multivalued function: for each \(x\) there is an infinite number of \(z\) such that \(exp(z) = x\). The convention is to return the \(z\) whose imaginary part lies in \((-pi, pi]\).
Array API Standard Support
logsumexp has experimental support for Python Array API Standard compatible backends in addition to NumPy. Please consider testing these features by setting an environment variable
SCIPY_ARRAY_API=1and providing CuPy, PyTorch, JAX, or Dask arrays as array arguments. The following combinations of backend and device (or other capability) are supported.Library
CPU
GPU
NumPy
✅
n/a
CuPy
n/a
✅
PyTorch
✅
✅
JAX
✅
✅
Dask
✅
n/a
See Support for the array API standard for more information.
Examples
>>> import numpy as np >>> from scipy.special import logsumexp >>> a = np.arange(10) >>> logsumexp(a) 9.4586297444267107 >>> np.log(np.sum(np.exp(a))) 9.4586297444267107
With weights
>>> a = np.arange(10) >>> b = np.arange(10, 0, -1) >>> logsumexp(a, b=b) 9.9170178533034665 >>> np.log(np.sum(b*np.exp(a))) 9.9170178533034647
Returning a sign flag
>>> logsumexp([1,2],b=[1,-1],return_sign=True) (1.5413248546129181, -1.0)
Notice that logsumexp does not directly support masked arrays. To use it on a masked array, convert the mask into zero weights:
>>> a = np.ma.array([np.log(2), 2, np.log(3)], ... mask=[False, True, False]) >>> b = (~a.mask).astype(int) >>> logsumexp(a.data, b=b), np.log(5) 1.6094379124341005, 1.6094379124341005
- static bincount(x, /, weights=None, minlength=0)
Count number of occurrences of each value in array of non-negative ints.
The number of bins (of size 1) is one larger than the largest value in x. If minlength is specified, there will be at least this number of bins in the output array (though it will be longer if necessary, depending on the contents of x). Each bin gives the number of occurrences of its index value in x. If weights is specified the input array is weighted by it, i.e. if a value
nis found at positioni,out[n] += weight[i]instead ofout[n] += 1.- Parameters:
x (array_like, 1 dimension, nonnegative ints) – Input array.
weights (array_like, optional) – Weights, array of the same shape as x.
minlength (int, optional) – A minimum number of bins for the output array.
- Returns:
out – The result of binning the input array. The length of out is equal to
np.amax(x)+1.- Return type:
ndarray of ints
- Raises:
ValueError – If the input is not 1-dimensional, or contains elements with negative values, or if minlength is negative.
TypeError – If the type of the input is float or complex.
See also
histogram,digitize,uniqueExamples
>>> import numpy as np >>> np.bincount(np.arange(5)) array([1, 1, 1, 1, 1]) >>> np.bincount(np.array([0, 1, 1, 3, 2, 1, 7])) array([1, 3, 1, 1, 0, 0, 0, 1])
>>> x = np.array([0, 1, 1, 3, 2, 1, 7, 23]) >>> np.bincount(x).size == np.amax(x)+1 True
The input array needs to be of integer dtype, otherwise a TypeError is raised:
>>> np.bincount(np.arange(5, dtype=float)) Traceback (most recent call last): ... TypeError: Cannot cast array data from dtype('float64') to dtype('int64') according to the rule 'safe'
A possible use of
bincountis to perform sums over variable-size chunks of an array, using theweightskeyword.>>> w = np.array([0.3, 0.5, 0.2, 0.7, 1., -0.6]) # weights >>> x = np.array([0, 1, 1, 2, 2, 2]) >>> np.bincount(x, weights=w) array([ 0.3, 0.7, 1.1])
- static unique(ar, return_index=False, return_inverse=False, return_counts=False, axis=None, *, equal_nan=True, sorted=True)
Find the unique elements of an array.
Returns the sorted unique elements of an array. There are three optional outputs in addition to the unique elements:
the indices of the input array that give the unique values
the indices of the unique array that reconstruct the input array
the number of times each unique value comes up in the input array
- Parameters:
ar (array_like) – Input array. Unless axis is specified, this will be flattened if it is not already 1-D.
return_index (bool, optional) – If True, also return the indices of ar (along the specified axis, if provided, or in the flattened array) that result in the unique array.
return_inverse (bool, optional) – If True, also return the indices of the unique array (for the specified axis, if provided) that can be used to reconstruct ar.
return_counts (bool, optional) – If True, also return the number of times each unique item appears in ar.
axis (int or None, optional) – The axis to operate on. If None, ar will be flattened. If an integer, the subarrays indexed by the given axis will be flattened and treated as the elements of a 1-D array with the dimension of the given axis, see the notes for more details. Object arrays or structured arrays that contain objects are not supported if the axis kwarg is used. The default is None.
equal_nan (bool, optional) –
If True, collapses multiple NaN values in the return array into one.
Added in version 1.24.
sorted (bool, optional) –
If True, the unique elements are sorted. Elements may be sorted in practice even if
sorted=False, but this could change without notice.Added in version 2.3.
- Returns:
unique (ndarray) – The sorted unique values.
unique_indices (ndarray, optional) – The indices of the first occurrences of the unique values in the original array. Only provided if return_index is True.
unique_inverse (ndarray, optional) – The indices to reconstruct the original array from the unique array. Only provided if return_inverse is True.
unique_counts (ndarray, optional) – The number of times each of the unique values comes up in the original array. Only provided if return_counts is True.
See also
repeatRepeat elements of an array.
sortReturn a sorted copy of an array.
Notes
When an axis is specified the subarrays indexed by the axis are sorted. This is done by making the specified axis the first dimension of the array (move the axis to the first dimension to keep the order of the other axes) and then flattening the subarrays in C order. The flattened subarrays are then viewed as a structured type with each element given a label, with the effect that we end up with a 1-D array of structured types that can be treated in the same way as any other 1-D array. The result is that the flattened subarrays are sorted in lexicographic order starting with the first element.
Changed in version 1.21: Like np.sort, NaN will sort to the end of the values. For complex arrays all NaN values are considered equivalent (no matter whether the NaN is in the real or imaginary part). As the representant for the returned array the smallest one in the lexicographical order is chosen - see np.sort for how the lexicographical order is defined for complex arrays.
Changed in version 2.0: For multi-dimensional inputs,
unique_inverseis reshaped such that the input can be reconstructed usingnp.take(unique, unique_inverse, axis=axis). The result is now not 1-dimensional whenaxis=None.Note that in NumPy 2.0.0 a higher dimensional array was returned also when
axiswas notNone. This was reverted, butinverse.reshape(-1)can be used to ensure compatibility with both versions.Examples
>>> import numpy as np >>> np.unique([1, 1, 2, 2, 3, 3]) array([1, 2, 3]) >>> a = np.array([[1, 1], [2, 3]]) >>> np.unique(a) array([1, 2, 3])
Return the unique rows of a 2D array
>>> a = np.array([[1, 0, 0], [1, 0, 0], [2, 3, 4]]) >>> np.unique(a, axis=0) array([[1, 0, 0], [2, 3, 4]])
Return the indices of the original array that give the unique values:
>>> a = np.array(['a', 'b', 'b', 'c', 'a']) >>> u, indices = np.unique(a, return_index=True) >>> u array(['a', 'b', 'c'], dtype='<U1') >>> indices array([0, 1, 3]) >>> a[indices] array(['a', 'b', 'c'], dtype='<U1')
Reconstruct the input array from the unique values and inverse:
>>> a = np.array([1, 2, 6, 4, 2, 3, 2]) >>> u, indices = np.unique(a, return_inverse=True) >>> u array([1, 2, 3, 4, 6]) >>> indices array([0, 1, 4, 3, 1, 2, 1]) >>> u[indices] array([1, 2, 6, 4, 2, 3, 2])
Reconstruct the input values from the unique values and counts:
>>> a = np.array([1, 2, 6, 4, 2, 3, 2]) >>> values, counts = np.unique(a, return_counts=True) >>> values array([1, 2, 3, 4, 6]) >>> counts array([1, 3, 1, 1, 1]) >>> np.repeat(values, counts) array([1, 2, 2, 2, 3, 4, 6]) # original order not preserved
- static searchsorted(a, v, side='left', sorter=None)
Find indices where elements should be inserted to maintain order.
Find the indices into a sorted array a such that, if the corresponding elements in v were inserted before the indices, the order of a would be preserved.
Assuming that a is sorted:
side
returned index i satisfies
left
a[i-1] < v <= a[i]right
a[i-1] <= v < a[i]- Parameters:
a (1-D array_like) – Input array. If sorter is None, then it must be sorted in ascending order, otherwise sorter must be an array of indices that sort it.
v (array_like) – Values to insert into a.
side ({'left', 'right'}, optional) – If ‘left’, the index of the first suitable location found is given. If ‘right’, return the last such index. If there is no suitable index, return either 0 or N (where N is the length of a).
sorter (1-D array_like, optional) – Optional array of integer indices that sort array a into ascending order. They are typically the result of argsort.
- Returns:
indices – Array of insertion points with the same shape as v, or an integer if v is a scalar.
- Return type:
int or array of ints
See also
sortReturn a sorted copy of an array.
histogramProduce histogram from 1-D data.
Notes
Binary search is used to find the required insertion points.
As of NumPy 1.4.0 searchsorted works with real/complex arrays containing nan values. The enhanced sort order is documented in sort.
This function uses the same algorithm as the builtin python bisect.bisect_left (
side='left') and bisect.bisect_right (side='right') functions, which is also vectorized in the v argument.Examples
>>> import numpy as np >>> np.searchsorted([11,12,13,14,15], 13) 2 >>> np.searchsorted([11,12,13,14,15], 13, side='right') 3 >>> np.searchsorted([11,12,13,14,15], [-10, 20, 12, 13]) array([0, 5, 1, 2])
When sorter is used, the returned indices refer to the sorted array of a and not a itself:
>>> a = np.array([40, 10, 20, 30]) >>> sorter = np.argsort(a) >>> sorter array([1, 2, 3, 0]) # Indices that would sort the array 'a' >>> result = np.searchsorted(a, 25, sorter=sorter) >>> result 2 >>> a[sorter[result]] 30 # The element at index 2 of the sorted array is 30.
- gammaln = <ufunc 'gammaln'>
- digamma = <ufunc 'psi'>
- betaln = <ufunc 'betaln'>
- erf = <ufunc 'erf'>
- cos = <ufunc 'cos'>
- sin = <ufunc 'sin'>
- arctan2 = <ufunc 'arctan2'>
- i0e = <ufunc 'i0e'>
- erfcx = <ufunc 'erfcx'>
- class SymbolicEngine[source]
Bases:
ComputeEngineSmall symbolic expression engine over scalar nodes and object arrays.
- with_precision(precision)[source]
Return this engine unchanged: symbolic expressions carry no float precision policy.
The numeric engines swap their float dtype here, but symbolic nodes are exact expression trees with no reduced-precision representation, so precision adjustment is a no-op rather than an error – this lets backend-neutral code call
with_precisionuniformly across engines.- Parameters:
precision (Any)
- Return type:
SymbolicEngine
- constant(value)[source]
Return
valueas a symbolic constant node.- Parameters:
value (Any)
- Return type:
SymbolicExpression
- symbol(name)[source]
Return a named symbolic expression variable.
- Parameters:
name (str)
- Return type:
SymbolicExpression
- asarray(x, dtype=None)[source]
Convert scalars/arrays/strings into symbolic expression objects.
- zeros(shape, dtype=None)[source]
Return an object array filled with symbolic zero constants.
- empty(shape, dtype=None)[source]
Return an uninitialized object array for symbolic expressions.
- arange(*args, **kwargs)[source]
Return symbolic constants corresponding to
np.arangevalues.
- to_numpy(x)[source]
Return
xas a NumPy object array without numeric evaluation.
- evaluate(x, values)[source]
Evaluate a scalar expression or object-array expression tree.
- symbols(x)[source]
Return sorted symbolic variable names referenced by
x.
- op_counts(x)[source]
Return aggregate operation counts over a scalar or array expression.
- diagnostics(x)[source]
Return a compact diagnostic summary for generated-kernel inspection.
- stack(arrays, axis=0)[source]
Stack symbolic arrays with NumPy object-array semantics.
- concatenate(arrays, axis=0)[source]
Join symbolic arrays with NumPy object-array semantics.
- static sum(x, axis=None, dtype=None, keepdims=False, initial=None, where=None)[source]
Return a symbolic sum reduction over
axis, matching NumPy’ssumcontract.keepdims,initial, andwhereare implemented exactly asnp.sumdefines them: reduced axes are kept as size-1 dimensions,initialseeds each reduction group (the additive identity 0.0 when omitted), andwhereexcludes masked-out elements by substituting the additive identity in their place before folding.dtypehas no symbolic analogue – an expression node carries no numeric storage to cast – so a non-Nonevalue is rejected rather than silently ignored (matching the “reject unsupported arguments” half of the declared reduction contract, since honoring it is not meaningful here).
- static logsumexp(x, axis=None, keepdims=False)[source]
Return a symbolic log-sum-exp reduction over
axis, matching SciPy’slogsumexp.keepdimsis implemented exactly asscipy.special.logsumexpdefines it. SciPy’s ownlogsumexp(whichNumpyEngine.logsumexpforwards to directly) has nodtype/initial/whereparameter either, so there is no declared behavior to honor for them here; passing them raises the sameTypeErrorSciPy’s own function would, for the same reason (an unexpected keyword argument). An all--infinput (every term has zero probability in log-space) correctly evaluates to-inf, notNaN– see_logsumexp_values(). An empty reduction is likewise defined as-inf(the identity: the log of a sum of zero terms), matching SciPy.
- static max(x, axis=None, keepdims=False, initial=None, where=None)[source]
Return a symbolic max reduction over
axis, matching NumPy’smaxcontract.keepdimsandinitialare implemented exactly asnp.maxdefines them (np.maxitself has nodtypeparameter, so none is declared here either). Max has no universal identity element, so – exactly likenp.max– passingwherewithout also passinginitialis rejected rather than silently reducing an under-specified group. An empty reduction with noinitialraises (there is nothing to seed it with), matchingnp.max; withinitialit returnsinitial.
- static where(cond, x, y)[source]
Return a symbolic elementwise conditional expression.
- static maximum(x, y)[source]
Return a symbolic elementwise maximum expression.
- static less(x, y)[source]
Return a symbolic less-than comparison.
- static less_equal(x, y)[source]
Return a symbolic less-than-or-equal comparison.
- static greater(x, y)[source]
Return a symbolic greater-than comparison.
- static greater_equal(x, y)[source]
Return a symbolic greater-than-or-equal comparison.
- static equal(x, y)[source]
Return a symbolic equality comparison.
- static not_equal(x, y)[source]
Return a symbolic inequality comparison.
- static logical_and(x, y)[source]
Return a symbolic elementwise logical-and expression.
- static logical_or(x, y)[source]
Return a symbolic elementwise logical-or expression.
- static logical_not(x)[source]
Return a symbolic elementwise logical-not expression.
- static clip(x, a_min=None, a_max=None)[source]
Return a symbolic clipped expression.
- static cumsum(x, axis=None, dtype=None, out=None)[source]
Return a symbolic cumulative sum over
axis, matching NumPy’scumsumcontract.axisbehaves exactly asnp.cumsumdefines it (Noneflattens first).dtypehas no symbolic analogue – an expression node carries no numeric storage to cast into, the same reasonsum()rejects it – andoutcannot be honored either, because the result is a freshly built object array of expression nodes rather than a buffer that can be written into. Both are therefore rejected rather than silently discarded (MXR-080-1567: the previous implementation was a lambda that swalloweddtype,out, and any other argument into unused*args/**kwargsand passed onlyaxisthrough, so a caller asking for a float32 accumulation or an output buffer got neither and no signal). An unexpected keyword now raisesTypeErrorfrom ordinary signature binding, as the other engines’cumsumdoes.
- index_add(out, index, values)[source]
Return a symbolic index-add operation node.
- static to_sympy(x)[source]
Lower a symbolic expression (or object array) to a sympy expression.
- static to_sage(x)[source]
Lower a symbolic expression (or object array) to a sage expression.
- class SymbolicExpression(op, args=())[source]
Bases:
objectA compact immutable symbolic expression tree.
- static symbol(name)[source]
Create a named symbolic variable node.
- Parameters:
name (str)
- Return type:
SymbolicExpression
- static constant(value)[source]
Create a symbolic constant node.
- Parameters:
value (Any)
- Return type:
SymbolicExpression
- static call(op, *args)[source]
Create an operation node with symbolic arguments.
- evaluate(values)[source]
Evaluate the expression with a mapping from symbol names to values.
A
wherenode with a SCALAR condition evaluates only the selected branch (MXR-080-1565); see_evaluate_where(). Every other node evaluates all of its arguments.
- symbols()[source]
Return sorted symbolic variable names referenced by this expression.
- class TorchEngine(device=None, dtype=None, compile=False, mesh=None, shard=None)[source]
Bases:
ComputeEngineTorch tensor engine for device placement, autograd, and optional DTensor sharding.
- property accumulator_dtype: Any
High-precision dtype for sufficient-statistic reductions (float64, or float32 on MPS).
Reductions that aggregate over observations accumulate in float64 even when scoring runs in reduced precision, so a float32 fit does not drift on large N. MPS has no float64, so there the accumulator falls back to float32 (its max precision) — fits on very large N may drift slightly.
- with_precision(precision)[source]
Return a Torch engine with the same placement and a new dtype policy.
- Parameters:
precision (Any)
- Return type:
TorchEngine
- asarray(x, dtype=None)[source]
Convert
xto a Torch tensor or DTensor on the configured device.Contract: float inputs are force-cast to the engine’s float dtype (e.g. a float32 numpy array becomes the engine’s float64) unless
dtypeis given; this differs from numpy’sasarray, which preserves the input dtype. Complex NumPy input is rejected whendtypeis not given explicitly: the dtype inference below has no complex-precision policy of its own, and letting it fall through to the generic non-floating/non-Boolean case would silently discard the imaginary component and collapse the real part to an integer. Pass an explicitdtype=torch.complex64/torch.complex128for a genuine complex tensor.
- zeros(shape, dtype=None)[source]
Allocate a zero tensor with this engine’s dtype/device/placement.
- empty(shape, dtype=None)[source]
Allocate an uninitialized tensor with this engine’s dtype/device/placement.
- arange(*args, **kwargs)[source]
Return
torch.arangeon the configured device.
- to_numpy(x)[source]
Gather/detach a Torch tensor or DTensor to a host NumPy array.
- stack(arrays, axis=0)[source]
Stack tensors with
torch.stackunder the engine’s dtype and device policy.Elements route through
asarray()first. Leaf scorers legitimately hand back float64 NumPy arrays; stacking them raw produced a float64 tensor that later met float32 engine tensors – invisible on CPU, but a hard “mat1 double, mat2 float” error inside the HMM forward pass on the first real CUDA execution (rented RTX 3060, 2026-08-04). The engine’s dtype policy has to apply at every ingestion point, not only the explicit asarray calls.
- concatenate(arrays, axis=0)[source]
Join tensors with
torch.catunder the same ingestion policy asstack().
- replicate(x)[source]
Return
xreplicated across the configured DeviceMesh.
- place_component_axis(x, axis=0)[source]
Place a stacked component parameter tensor on
Shard(axis).TorchEngine(mesh=..., shard='components')is the model-parallel configuration from the compute-engine design. Encoded data remains replicated, while homogeneous stacked-kernel parameter tensors are sharded along their component dimension. With no mesh, or with no component sharding requested, this is justasarray.
- requires_grad(x)[source]
Return whether
xis a Torch tensor/DTensor requiring gradients.
- compile(fn)[source]
Compile
fnwithtorch.compilewhen enabled and available.
- sum(x, *args, **kwargs)[source]
Return
torch.sumaccepting eitheraxisordim.Promotes a floating input to
accumulator_dtypewhen the caller doesn’t pass an explicitdtype=– mirroringNumpyEngine.sum(). Without this,torch.sumaccumulates in the input tensor’s own dtype by default, so a float32-precision fit on this engine would silently drift on large N (the exact catastrophic-cancellation riskaccumulator_dtypeexists to guard against) while the numpy engine, which already promotes, stayed accurate.
- static max(x, *args, **kwargs)[source]
Return
torch.maxaccepting eitheraxisordim(incl. a tuple of axes).
- matmul(x, y)[source]
Matrix-multiply under the engine’s dtype policy.
Both operands route through
asarray(). Mixed float32/float64 operands reached this point through paths that never crossed an explicit ingestion call, and torch.matmul promotes on CPU but hard-errors on CUDA (“mat1 double, mat2 float”) – found and probed on the first real CUDA execution of the HMM forward pass (rented RTX 3060, 2026-08-04: mat1 float64 [100, 2] against mat2 float32 [2, 2]). The engine’s declared dtype IS the policy for floating operands, so applying it here is a correctness boundary, not a cast of convenience.
- static cumsum(x, *args, **kwargs)[source]
Return
torch.cumsumacceptingaxis/dimand defaulting to a flattened scan.
- static logsumexp(x, *args, **kwargs)[source]
Return
torch.logsumexpaccepting eitheraxisordim.torch < 2.5 registers no DTensor sharding strategy for
logsumexp, so reducing over a sharded axis (the mixture E-step’s log-partition over component-sharded scores) raisesNotImplementedError. Fall back to redistributing the DTensor to replicated first – the reduction then runs locally and is correct on any torch version. torch >= 2.5 has the strategy and takes the fast native path unchanged; non-DTensor inputs re-raise the original error.
- hmm_forward_ll(log_emit, log_w, log_a, mask)[source]
Fused log-space forward: per-sequence emission log-likelihood (freeze-alpha padding).
- hmm_forward_backward(log_emit, log_w, log_a, mask, weights=None)[source]
Fused log-space Baum-Welch recurrences, exactly mirroring the generic engine-op version: alpha freezes across padded steps, beta carries, gamma is mask-SELECTED (NaN-safe for empty sequences), xi is computed for all transitions at once, and per-sequence
weightsscale gamma / xi / pi. Returns(ll, gamma, xi_sum, pi).
- index_add(out, index, values)[source]
Add
valuesintooutalong axis 0 using Torchindex_add.Contract: return-value-only –
torch.Tensor.index_add(no trailing underscore) does not mutateoutin place, unlike numpy’sadd.at; callers must use the returned tensor.
- class JaxEngine(device=None, dtype=None, compile=False)[source]
Bases:
ComputeEngineJAX array engine: XLA-compiled ops, float64, optional
jax.jitcompilation, GPU/TPU via JAX.- property accumulator_dtype: Any
High-precision dtype for sufficient-statistic reductions (float64, or float32 when the ambient
jax_enable_x64is off – see the module docstring; JAX would silently truncate a float64 accumulator request to float32 there anyway, so this avoids claiming a precision the runtime cannot actually give).
- with_precision(precision)[source]
Return a JAX engine with the same placement and a new dtype policy.
- Parameters:
precision (Any)
- Return type:
JaxEngine
- asarray(x, dtype=None)[source]
Convert
xto a JAX array on this engine’s device. Float inputs are force-cast to the engine dtype (float64 by default) unlessdtypeis given – matching the Torch engine’s contract, not NumPy’s.Complex input is rejected when
dtypeis not given explicitly (MXR-080-1560), exactly asmixle.engines.torch_engine.TorchEngine.asarray()does: this engine’s dtype policy has no complex-precision concept, so the generic non-floating/non-Boolean fallback (jnp.int64) would silently discard the imaginary component and collapse the real part to an integer. Passdtype=jnp.complex64/jnp.complex128for a genuine complex array.
- zeros(shape, dtype=None)[source]
Allocate a zero array with this engine’s dtype, placed on this engine’s device.
- empty(shape, dtype=None)[source]
Allocate an array on this engine’s device (JAX has no uninitialized
empty; zeros is the safe equivalent).
- arange(*args, **kwargs)[source]
Return
jnp.arangeplaced on this engine’s device; float arguments select the engine float dtype.
- is_concrete(x)[source]
False while
xis a jit tracer: its values do not exist yet, so to_numpy would raise.
- to_numpy(x)[source]
Move a JAX array back to a host NumPy array.
- stack(arrays, axis=0)[source]
Stack arrays with
jnp.stack, placed on this engine’s device.
- concatenate(arrays, axis=0)[source]
Join arrays with
jnp.concatenateon this engine’s device.
- requires_grad(x)[source]
Always False: JAX autograd is functional (
jax.grad), not tensor-tagged.
- compile(fn)[source]
Compile
fnwithjax.jitwhen enabled.
- index_add(out, index, values)[source]
Add
valuesintooutalong axis 0 via the functional.at[idx].addupdate, placed on this engine’s device.Contract: return-value-only – JAX arrays are immutable, so this returns a new array; callers must use the return value (the same contract the Torch engine documents).
- auto_precision(data=None, *, engine=None, sample_size=512)[source]
Recommend
'float32'or'float64'from the data and the target hardware.float32 only helps on a GPU Torch engine (on CPU/NumPy it is a no-op or slower), and even there only when the data is well conditioned for single precision. Sufficient-statistic accumulation is already float64-safe (see
ComputeEngine.accumulator_dtype), so this guards the remaining risk – the ~7 significant digits of float32 scoring – by inspecting the data’s magnitude and dynamic range. Returns'float64'whenever a numeric sample is unavailable, non-finite, or looks risky.- Parameters:
- Returns:
'float32'or'float64'.- Return type:
- engine_of(x, default=NUMPY_ENGINE)[source]
Return the ComputeEngine associated with an array or encoded payload.
Nested encodings are scanned recursively. Mixing arrays whose engines disagree on backend, device, mesh/placement, or an explicitly-chosen dtype policy is an error, because silent host/device/precision mixing is almost always a performance or correctness bug (see
_engines_compatible()).- Parameters:
x (Any)
default (ComputeEngine)
- Return type:
ComputeEngine
- engine_with_precision(engine, precision)[source]
Return
engineadjusted to the requested floating precision.
- is_symbolic_payload(x)[source]
Return True for a symbolic node or a NumPy object array of ALL-symbolic nodes.
Every element of an object array is checked, not just the first: classifying the whole array from a single element lets a mixed-ownership payload – some elements genuine
SymbolicExpressionnodes, others unrelated plain objects – be misrouted based on whichever kind happens to occupy index 0 (numeric-first routes the symbolic elements through NumPy, which was never built to handle them; symbolic-first routes the unrelated elements through the symbolic engine instead). Mixed ownership is rejected outright rather than silently guessed at from one element.Scans left to right and stops at the first element whose kind disagrees with the first element’s, so a genuinely uniform array (the overwhelmingly common case) still only pays for a single early-exit scan, while a mixed one is still caught regardless of which kind happens to sit at index 0.
- normalize_numpy_dtype(precision)[source]
Normalize a precision specifier to a NumPy floating dtype.
- normalize_torch_dtype(precision, torch_module)[source]
Normalize a precision specifier to a Torch floating dtype.
- precision_name(precision)[source]
Return a readable canonical precision name.
- register_array_type(array_type, engine, *, override=False)[source]
Register an array/tensor type with its owning engine.
Existing ownership cannot be replaced unless
override=Trueis explicit. Registeringobjectis forbidden because it would capture every otherwise-unregistered Python value process-wide.
- to_latex(expr)[source]
Return a LaTeX string for
exprvia sympy.
- to_numpy(x)[source]
Convert an engine array/tensor payload to NumPy at an explicit boundary.
A dict, list, or tuple that contains an engine-owned value is converted leaf by leaf, preserving container structure and resolving each leaf’s own owning engine independently. Resolving a single engine for the whole container up front and handing it the container as-is – the previous behavior – fails to stack a ragged list of Torch tensors, leaves dictionary values unconverted, and can hand a device tensor to
np.asarraywithout transferring it to host memory first. Plain nested data with no engine-owned value is still handed to the resolved engine as one unit, unchanged.
- to_sage(expr)[source]
Convert a
SymbolicExpression(or object array of them) to sage.Mirrors
to_sympy()againstsage.all. RaisesImportErrorif sage is unavailable, andNotImplementedErrorfor non-symbolic kernels.
- to_sympy(expr)[source]
Convert a
SymbolicExpression(or object array of them) to sympy.Scalar nodes become a sympy expression; object arrays map elementwise into a NumPy object array of sympy expressions (shape preserved). Genuinely non-symbolic kernels (
bincount/unique/searchsorted/index_add) raiseNotImplementedError. RaisesImportErrorif sympy is unavailable.
- class DoubleDouble(hi, lo=0.0)[source]
Bases:
objectAn (almost) ~106-bit float as two non-overlapping
float64arrayshi + lo.Scalars or numpy arrays; operations broadcast. The invariant is
|lo| <= 0.5 * ulp(hi). A component may be+infor-inf– exactly representable infloat64, carried withlo == 0– but never NaN, and never an overflow of finite operands.- Parameters:
hi (Any)
lo (Any)
- dd_sum(x)[source]
Accurate sum of a
float64array in double-double precision – vectorized, no Python loop over elements.Pairwise tree reduction with an error-free
two_sum()combine at every node:O(n)work inO(log n)vectorized passes, accumulating the rounding error into thelocomponent. The result is correct to ~106 bits even for catastrophically cancelling inputs thatfloat64sums get wrong.An infinite term short-circuits to the IEEE answer (
-inffor a zero-probability log-density) instead of raising; NaN, and+infmixed with-inf, still fail closed – see_infinite_sum().- Parameters:
x (Any)
- Return type:
DoubleDouble
- dd_dot(a, b)[source]
Accurate dot product
sum(a_i * b_i)in double-double precision.Uses the compiled hardware-FMA kernel when available (one
fmaper element, ~3x faster than the pure-numpy Veltkamp-split path, and exactly as accurate – each product’s error is exact either way, though the two paths accumulate in different orders, sequential versus pairwise tree, so their results agree to double-double precision rather than bit for bit). Otherwise each product is split error-free by_product_and_residual()and the products + errors are summed bydd_sum(). Defeats the cancellation that wrecks a naivefloat64dot.Every check that decides whether an input is acceptable is made once, before dispatch, so the two implementations cannot drift apart on what they accept: equal length (see
_require_equal_length(),ValueError), finite operands (ValueError), and a result that is representable at all (OverflowError). A single product that underflows to zero is not one of them: it contributes less than one smallest-subnormal to the sum, so it is summed as the zero it rounds to rather than failing the whole reduction –dd_dot([1e-200, 1.0], [1e-200, 1.0])is1.0, which is the right answer, not an error. (two_prod()on its own still fails closed there, because a lone product has nothing to be negligible against.)
- class FloatFormat(mantissa_bits, exp_bits=11)[source]
Bases:
NumericFormatRound-to-nearest MANTISSA rounding at
mantissa_bits, nominally styled after an IEEE-ish fpN split (seefp()).quantizerounds each value’s significand tomantissa_bitsexplicit bits (round-to-nearest); the exponent passes through UNCHANGED, with no range limit.exp_bitstherefore only feedsname/bits_per_value(the advertised bit budget an allocation pass compares against) – it is NOT enforced: there is no overflow/underflow, no saturation or flush-to-zero, no subnormals, and no NaN/Inf bit-pattern encoding. This is a deliberate scope choice, not an oversight: an unbounded exponent is what makesmax_rel_errora genuine bound for any finite magnitude (see that property’s docstring), so a caller can read the round trip as a pure mantissa-rounding measurement independent of range.A consequence: this codec does NOT faithfully emulate a real bounded fpN storage format. A real 8-bit float cannot represent
1e100at all, butFloatFormat.fp(8).round_trip([1e100])rounds1e100’s mantissa to 3 bits and returns a value that is still ~1e100 in magnitude – by design, per the above, not a bug. Do not usefp(8)/fp(16)/etc. where actual overflow/underflow/saturation behavior matters; they measure mantissa-rounding error only.- classmethod fp(total_bits)[source]
Build a format whose
mantissa_bits/exp_bitsfollow an IEEE-like split oftotal_bits(n = 1..1024+). Only the resultingmantissa_bitsaffectsquantize’s numeric behavior –exp_bitsis bit-budget bookkeeping only (see the class docstring); this does NOT build a range-limited fpN codec.- Parameters:
total_bits (int)
- Return type:
FloatFormat
- property max_rel_error: float
Return the worst-case relative rounding error – a universal bound, true for every finite input regardless of magnitude (the exponent is never range-limited; see the class docstring).
- quantize(x)[source]
Round values to this mantissa precision; the exponent passes through exactly, unclamped.
- class FixedPointFormat(frac_bits, int_bits=31)[source]
Bases:
NumericFormatFixed-point: store
round(x * 2**frac_bits)as an integer; real compression + a hard error bound.int_bitssets the representable magnitude[-2**int_bits, 2**int_bits); out-of-range clamps.in_range_max_abs_error == 2**-(frac_bits+1)bounds round-to-nearest only for values inside that range. The universalmax_abs_erroris infinite because saturation error is unbounded. Storage is a plainint32/int64– there is no arbitrary-width packed storage – so the declared total width1 + int_bits + frac_bitscannot exceed 64 bits; wider requests raise at construction instead of silently overflowing the int64 cast (and falsifyingmax_abs_error).- property max_abs_error: float
Return the universal error bound; saturation makes it unbounded.
- property in_range_max_abs_error: float
Return the half-step error bound for inputs inside the representable range.
- quantize(x)[source]
Encode values as clipped scaled integers.
- class CodebookFormat(codebook)[source]
Bases:
NumericFormatScalar vector-quantization: store an index into a learned codebook;
log2(K)bits per value.The genuine pure-numpy compression codec – quantize gathers the nearest code (an unsigned index array), dequantize gathers the code values back. Fit the codebook to data with
fit().The codebook must be finite and nonempty (validated at construction,
ValueErrorotherwise). Duplicate entries are allowed: a repeated code costs a wasted, unreachable index but does not break nearest-code assignment or decoding (both entries decode to the same, correct value), andfit()’s Lloyd iteration can legitimately converge two cluster means onto the same value on degenerate/skewed data – rejecting that outcome would be pure loss, not a correctness fix.- Parameters:
codebook (Any)
- classmethod fit(data, n_codes, iters=25, seed=0)[source]
Learn
n_codescodes by 1-D k-means (Lloyd) ondata; codes are the cluster means.Raises
ValueErrorifn_codesoritersis not a positive integer.
- quantize(x)[source]
Map values to nearest codebook indices.
- dequantize(q)[source]
Map codebook indices back to representative values.
- compress(x)[source]
Quantize
xand pack the indices to bytes: returns(packed_uint8, count).For
K <= 256codes the indices are sub-byte or byte-exact andpack_bits()bit-packs them (e.g. 16 codes -> 4-bit indices -> 2 values/byte -> 16x vs float64). Larger codebooks need 16- or 32-bit indices, which are not sub-byte-packable – those are stored byte-aligned (little-endian), still returned as a flatuint8array.
- class Interval(lo, hi)[source]
Bases:
objectA guaranteed enclosure
[lo, hi]of a value (scalar or numpy array), outward-rounded.- Parameters:
lo (Any)
hi (Any)
- classmethod exact(x)[source]
A degenerate interval
[x, x]for an exactly-represented value.- Parameters:
x (Any)
- Return type:
Interval
- classmethod from_quantized(original, fmt)[source]
Enclose
originalusing the quantized format’s error bound.max_rel_erroris a duck-typed, self-reported claim: nothing here enforces that an implementer’s static bound actually holds for every valuefmtmight quantize, only that it is offered as one. A format that flushes underflowing values to exactly zero, or saturates on overflow, would still report a fixedmax_rel_errorwhile its true error at those magnitudes no longer scales with it – the analytic pad below would then be too narrow, silently returning an interval that does not actually encloseoriginal(FloatFormatavoids this today by staying mantissa-only with an unbounded exponent, so itsmax_rel_errorgenuinely is universal – see that class’s docstring – but nothing here depends on every format that will ever be passed in honoring that same discipline). Guard against a format that breaks the assumption by cross-checking the analytic pad against the error actually measured onoriginal– already in hand, it is quantized right here – and padding by whichever is WIDER. This needs nothing new fromfmtbeyondround_trip, which every caller already requires, and is a no-op whenevermax_rel_errorgenuinely does bound this data (the analytic pad is then always >= the measured one, by construction).
- width()[source]
The guaranteed error bound:
hi - lo(outward-rounded).A degenerate point exactly at
+/-inf(lo == hi == +/-inf, legal per the constructor) has zero width by definition – but IEEE-754 computesinf - inf == NaNfor it, which would otherwise leak a NaN out of this function with no constructor downstream to catch it. Special-case that one pattern directly; every other case (including an ordinary, non- degenerate unbounded interval like[0, inf], whose width is correctlyinf) is unaffected.- Return type:
- midpoint()[source]
Return interval midpoints.
Same
inf - infgap aswidth(): a degenerate point at+/-infis its own midpoint by definition, computed directly rather than via the subtraction that would otherwise produce NaN.- Return type:
- sum_error_bound(x)[source]
Return a certified bound on the float64 error of
sum(x).The standard a-priori bound
|fl(sum) - sum| <= gamma_{n-1} * sum|x_i|withgamma_k = k*u / (1 - k*u)andu = 2**-53. It is sound for any summation order. A bound that is large relative to|sum x|means the sum is ill-conditioned (cancellation) and warrants the double-doublemixle.engines.extended.dd_sum(); a tight one means float64 already suffices and no extra compute is justified.
- float64_sum_is_accurate(x, target_rel_error=1e-12)[source]
Return whether float64 summation is accurate to
target_rel_error.Reads the certified bound relative to the magnitude of the result – precision allocation in one call.
- class AffineForm(center, terms=None)[source]
Bases:
objectcenter + sum_i coeff_i * eps_iover shared noise symbolseps_i in [-1, 1].- classmethod constant(x)[source]
Create an affine form with no uncertainty terms.
- Parameters:
x (Any)
- Return type:
AffineForm
- classmethod uncertain(x, radius=0.0)[source]
An input known only to within +/-
radius– one fresh noise symbol of that radius.
- radius()[source]
Half-width =
sum_i |coeff_i|(one outward ULP of slop for the f64 summation).- Return type:
- contains(value)[source]
Return a boolean mask for values contained in the affine enclosure.
- allocate_precision(center_magnitude, op_count, target_abs_error)[source]
Suggest the lowest-cost dtype whose endpoint-magnitude error heuristic is under target.
The estimate
op_count*u*center_magnitudedoes not observe intermediate values or an operation graph and is therefore only a planning heuristic. It must never be used as an accuracy certificate.Raises
ValueErrorunlesscenter_magnitudeandop_countare both finite and nonnegative andtarget_abs_erroris finite and strictly positive. Before this validation existed, a negativeop_countflipped the estimated error negative, which spuriously satisfies every dtype’s budget comparison and misselectsfloat16– the least precise dtype – regardless of how large the magnitude or how tight the target; a negativetarget_abs_errormade every dtype’s comparison fail and fell through to silently returningqdeven though no dtype can certify a negative bound (impossible by definition); and a NaN/Inf value anywhere in the formula rode comparison-with-NaN-is-always-False (or Inf’s unpredictable propagation) into whatever the fallthrough dtype happened to be, not a principled decision.
- accurate_sum(x, target_rel_error=1e-12)[source]
Sum
xtotarget_rel_errorrelative accuracy using the lowest-cost sufficient backend.Returns a
SumResultcertifying the accuracy actually achieved. Escalates from float64 to double-double to arbitrary precision only when the certified error bound says the lower-cost backend cannot meet the budget – so the common well-conditioned case never leaves vectorized float64 – and fails closed (status="insufficient") rather than silently returning a value that does not meettarget_rel_errorwhen no backend available in this process can certify it.Raises
ValueErroriftarget_rel_erroris not a positive, finite number.
- cast(x, precision)[source]
Cast
xonto the spectrum: a native dtype name,"dd"/"fp<bits>", or an integer bit width."dd","fp128", and the integer128are the same request (DoubleDouble);"fp96"and the integer96are likewise the same request (both resolve to 96 total bits via_precision_bits()) and route to the identical representation via_cast_by_bits(), regardless of which spelling the caller used. A nonpositive bit width (e.g."fp0",-5) raisesValueErrorrather than reaching format construction. Anything else (e.g."float64",np.float32) is handed straight tonumpy.dtype().Returns a numpy array (native / simulated low-bit), a
DoubleDouble, or an MPFR object array – see_cast_by_bits()for the exact tiering.
- sum_certificate(x)[source]
Report the certified float64 summation error and the condition number, without choosing a backend.
Submodules¶
- mixle.engines.affine module
- mixle.engines.arithmetic module
- mixle.engines.base module
- mixle.engines.bitpacked module
- mixle.engines.build_kernels module
- mixle.engines.error_tracing module
- mixle.engines.extended module
- mixle.engines.formats module
- mixle.engines.heterogeneous module
- mixle.engines.highprec module
- mixle.engines.jax_engine module
- mixle.engines.lns module
- mixle.engines.lns_nn module
- mixle.engines.numpy_engine module
- mixle.engines.packing module
- mixle.engines.precision module
- mixle.engines.qlut module
- mixle.engines.spectrum module
- mixle.engines.symbolic_engine module
- mixle.engines.symbolic_export module
- mixle.engines.torch_engine module