tensor_utils¶
Broadcasting, reshaping and interpolation helpers for batched tensors.
Algan’s animation state is uniformly shaped [time, mob, ...], and almost
every operation has to line up operands that disagree about how many batch
dimensions they carry. This module is the vocabulary for doing that:
broadcast* for aligning operands, unsqueeze_* / add_dummy_dims_* for
inserting axes on either side, squish / unsquish for flattening and
restoring axis pairs, and cast_to_tensor for accepting the Python lists,
floats and tuples a user naturally writes.
interpolate is the blend used when materializing an animated attribute
between two recorded states.
These are internal helpers and deliberately excluded from
from algan import *, whose names are chosen not to collide with a user’s own.
Functions
- cast_to_direction(name, x)[source]¶
Cast a user-supplied 3-D vector argument to a
[1, N, 3]tensor.Like
cast_to_tensor(), but rejects anything whose last dimension is not 3. A bare scalar casts to shape[1, 1, 1], which broadcasts across all three axes rather than failing, so without thismob.move(1)moves diagonally to(1, 1, 1)instead of telling the user it wanted a vector.- Parameters:
name – The user-facing parameter name, used in the error message.
x – The value to cast.
- Raises:
AlganConfigurationError – If
xis not a 3-D vector.
- cast_to_tensor(x)[source]¶
Converts scalars or lists of scalars into tensors, and combines lists of tensors into a single tensor. All other input types are returned unchanged. Returned tensors are always of shape [1,N,D] where D is dimension and N is the number of tensors combined.
- concat_dicts(kwargs)[source]¶
Concatenates a list of dicts sharing the same keys, the resulting dictionary has the same keys and concatenated values.
- reject_non_finite(name, value, given=None)[source]¶
Raise if
valueholds a NaN or an infinity.A NaN reaching an animatable attribute is not caught anywhere downstream: it propagates through the basis, the projection and the rasterizer, and the symptom is a black frame (or a mob that silently disappears) with nothing in it pointing back at the line that wrote it. Checked once, where the value is authored, rather than per replayed frame.
- Parameters:
name – The user-facing parameter or attribute name, used in the message.
value – The already-cast tensor to check. Non-tensors pass through.
given – What the user actually wrote, when it reads better than the tensor.
- Return type:
The value, unchanged, so this can wrap a cast.
- Raises:
AlganConfigurationError – If any element is NaN or infinite.
- reject_outside_unit_interval(name, value, given=None)[source]¶
Raise if
valuefalls outside the closed unit interval[0, 1].For the attributes documented as fractions – opacity above all – where a value outside the interval has no meaning the renderer could honour. It is not clamped silently:
opacity=1.5andopacity=-0.2are authoring mistakes, and the frame they produce looks like a bug in Algan rather than a bug in the script.Only for values that are set. A value that is scaled stays unchecked on purpose, on the same reasoning that leaves
scale(0)and a negative scale legal: a multiply is a transform, and the interval is a property of what the attribute means, not of every arithmetic step towards it.Non-finite values are rejected first, by
reject_non_finite(), so a NaN reports as a NaN rather than as an out-of-range value.- Parameters:
name – The user-facing parameter or attribute name, used in the message.
value – The value to check. A tensor is checked element-wise; a Python number is checked directly, so the plain
set_opacity(1.5)spelling is caught as well as the tensor one. Anything else passes through.given – What the user actually wrote, when it reads better than the tensor.
- Return type:
The value, unchanged, so this can wrap a cast.
- Raises:
AlganConfigurationError – If any element is NaN, infinite, below 0 or above 1.
- robust_concat(xs)[source]¶
Concatenates multiple tensors together while broadcasting as necessary to ensure shapes match.
- squish(x, start=0, end=1)[source]¶
Flatten dimensions
startthroughend(inclusive) ofxinto one.E.g.
squish(x, 1, 2)reshapes[A, B, C, D]to[A, B*C, D]. The inverse ofunsquish().- Parameters:
start (int)
end (int)
- texture_u8_provenance(texture)[source]¶
Whether a
[..., 5]color texture is exactly 8-bit with zero glow.True iff every channel value is exactly
k / 255for an integerkin[0, 255](the valuesget_image()produces from an 8-bit file) AND the glow channel (index 3) is identically zero. Proved by the round trip itself –round(x * 255) / 255 == xelementwise in f32 – so a map this accepts quantizes to u8 and back bit-identically, which is the admission rule for texture_u8_storage’s packed color-map layout.Checked ONCE at authoring (the
color_texturesetter, a mesh constructor) rather than at the merge: the merge runs on the prefetch worker, where an elementwise probe’s device sync waits out the whole queued chunk. NaNs fail the round trip, so they fail the check.
- unsquish(x, dim=0, factor=None)[source]¶
Split dimension
dimofxinto two dimensions.factorsets the size of the second new dimension (dimbecomes[size/factor, factor]); a negativefactorsets the size of the first instead ([-factor, size/-factor]);Nonesplits into a square ([sqrt(size), sqrt(size)]). The inverse ofsquish().- Parameters:
dim (int)
factor (int | None)