TensorPlay
Reference guides
latest (dev)
Copy
View Markdown

Latest development documentation · Updated 2026-10-08

foreach operations

foreach operations lift an ordinary tensor operation over a whole list of tensors in one call. tensorplay._foreach_add(tensors, other) is semantically equivalent to a Python loop applying tensorplay.add at each list position — but it runs as one multi-tensor kernel when the backend and the operands allow it, and it is the primitive the built-in optimizers are built on: applying an update to every parameter of a model is exactly a foreach operation.

import tensorplay as tp

xs = [tp.ones(3) * 1, tp.ones(3) * 2, tp.ones(3) * 3]
ys = [tp.ones(3)] * 3

# out-of-place: returns a new list, inputs untouched
print([t.tolist() for t in tp._foreach_add(xs, ys)])
# [[2.0, 2.0, 2.0], [3.0, 3.0, 3.0], [4.0, 4.0, 4.0]]

# in-place: the trailing underscore, like the scalar-op convention
tp._foreach_mul_(xs, 2.0)
print([t.tolist() for t in xs])
# [[2.0, 2.0, 2.0], [4.0, 4.0, 4.0], [6.0, 6.0, 6.0]]

# reductions lift too
print([n.item() for n in tp._foreach_norm(xs)])
# [3.464..., 6.928..., 10.392...]

Naming and coverage

The functions live directly on the tensorplay namespace with a _foreach_ prefix: tensorplay._foreach_add, tensorplay._foreach_mul_, tensorplay._foreach_norm, and about ninety more, covering the unary math functions (_foreach_abs, _foreach_acos, _foreach_ceil, …), the binary arithmetic (_foreach_add, _foreach_sub, _foreach_div, _foreach_clamp_min, …) in both out-of-place and in-place spellings, plus list-level utilities (_foreach_clone, _foreach_copy_, _foreach_norm, _foreach_zero_), matrix multiply over lists (_foreach_mm), and the fused optimizer kernels (_foreach_adam, _foreach_sgd).

Operand forms

The second operand of a binary foreach op can be:

  • a TensorList of the same length — position-wise, each pair together;

  • a single Tensor — shared across every position;

  • a Scalar or list of Scalars — the elementwise-constant form.

tp._foreach_add(xs, ys)            # TensorList / TensorList
tp._foreach_add(xs, ys[0])         # TensorList / Tensor (shared)
tp._foreach_add(xs, 2.0)           # TensorList / Scalar
tp._foreach_add(xs, [1.0, 2.0, 3.0])   # TensorList / list of Scalars

Tensor lists must be non-empty, and corresponding tensor/scalar lists must match in length. On CUDA the fused multi-tensor path additionally requires tensors on the same device with compatible dtypes and layouts; where a list does not qualify, results stay correct — only the single-kernel speedup is lost.

When to reach for them

Hand-written training code rarely needs them — the optimizers already use the fused forms internally. Direct use pays off when you maintain parallel lists of tensors outside an optimizer: applying the same elementwise fixup to a list of buffers, zeroing a list of gradients, or computing per-tensor statistics in one call.

On this page

Ask DeepWiki