Skip to content

Half, Fold, Pulse & UnFold

These arti.nn modules are independently usable PyTorch layers. They are unrelated to membrane visibility routing: Half changes feature amplitudes, while the membrane assigns token visibility domains.

For input x, Half computes a salience deficit from abs(x) and scales each value by base ** deficit. With defaults, values whose magnitude is at least 1 pass unchanged; weaker values fade smoothly. Shape and dtype are preserved and the module has no trainable parameters.

import torch
import arti.nn as ann
x = torch.randn(4, 128, 64) # any shape
y = ann.Half(threshold=1.0, base=0.5, scale=1.0)(x)
assert y.shape == x.shape

stochastic=True samples survival only in training mode; evaluation remains deterministic. This is an activation, not the half-transparent membrane.

fold = ann.Fold(k=16, dim=64)
x = torch.randn(4, 128, 64) # [B, N, D]
mask = torch.ones(4, 128, dtype=torch.bool) # [B, N]
q = torch.rand(4, 128) # [B, N], values clamped to [0, 1]
z = fold(x, q=q, mask=mask)
assert z.shape == (4, 16, 64) # [B, K, D]

mask answers whether a slot is valid; q guides salience. Keep them separate. The default soft mode uses differentiable assignments. topk sparsifies the input candidates per output slot. mode="attention" requires a static dim divisible by heads.

pulse = ann.Pulse(k=8, dim=64, hidden_dim=128)
workspace, info = pulse(x, q=q, mask=mask, return_info=True)
assert workspace.shape == (4, 8, 64)

Pulse is the public alias of LearnedPulse. It applies a learned fragment projection, optional Half, then Fold. q_topk prunes by external guidance before projection; fold_topk controls Fold sparsity. refine=True requires dim and adds a residual MLP or gated refinement.

x [B,N,D] + q/mask [B,N]
→ optional q_topk
→ learned fragment projection
→ Half (unless use_half=False)
→ Fold assignments over N fragments
→ workspace [B,K,D]
→ optional residual refinement

Pulse treats dimension N as an unordered-overcomplete fragment address space and always returns K slots. Therefore compatible fragment sets can be concatenated along N before one shared Pulse. concat_visual_fields is the audited helper:

field = ann.VisualField(patch_size=(4, 4))
left = field(glyph, window=(0, 0, 16, 48), field_id=0.0)
right = field(glyph, window=(0, 48, 16, 48), field_id=1.0)
visual = ann.concat_visual_fields(left, right)
assert visual.fragments.shape[1] == left.fragments.shape[1] + right.fragments.shape[1]
workspace = ann.Pulse(k=8, dim=visual.fragments.shape[-1])(
visual.fragments, mask=visual.mask
)

This is valid only when fields share batch size, source geometry, fragment width, positional policy, device, and dtype. Pixels are neither blended nor resized; absolute bounds and field_id remain in each fragment. Plain torch.cat is unsafe when feature schemas differ, positions are missing or use incompatible frames, or one mask is dropped. Concatenating on D is a different model contract and does not mean “more input slots.”

Concatenating compatible raw fragments before one Pulse and fusing several already-formed Pulse workspaces are different operations. ARTI introduced the Alpha FusionPulse in 1.6.0 and retains it in 1.7.0 for the second case:

compatible raw fragments → one Pulse → [B,K,D]
several compact Pulse workspaces → FusionPulse → one [B,K,D]

Whole-view, regional, and detail evidence can use separate Pulse capacities before a joint survival-and-fusion stage. Source count and slot counts may vary between calls, while FusionPulse keeps downstream K fixed.

UnFold queries new values and lays them out together with every original input instance. Since 1.6.0, target_length lets one configured maximum capacity serve different call-level lengths. It preserves original instance values, but it is not the inverse of Fold and cannot restore discarded information.

  • Half, Fold, Pulse, and UnFold are supported 1.x APIs in ARTI 1.7.0.
  • FusionPulse is Alpha in 1.7.0; its tensor contract is documented, while structural-loss defaults remain evolving.
  • Empty input sequences and incompatible shapes raise errors; Fold(k) always requires k > 0.
  • Randomly initialized outputs have no task semantics. Train the containing model or load task weights.
  • ARTI Web export currently accepts soft Fold paths; attention Fold is not a portable Web export promise.