# SPDX-License-Identifier: Apache-2.0 """MiniMax H3 packed-sequence materialization for FL2VA and Ref2VA tasks. Layout: [text L | imgvid_cond C | audio A(=t*2ch) | video_target V | pad P]. Builder rules: - placeholder ids; block-derived pos infos/masks/cu_seqlens/document_id - img_position_ids fp64 grid: text rows (row_idx,0,0); video/cond t counter continues text_len with temporal interp spans (frame_rescale 5/3 x frame_per_token (1,4,4,4,4)); each spatial sqrt_area axis uses evenly spaced coordinates excluding the right endpoint, then scales them by INTERP; audio channel-major blocks pinned to the w-grid extremes. """ from __future__ import annotations from collections.abc import Mapping, Sequence import numpy as np import torch MINIMAX_H3_FL2VA_KEYFRAME_SIGNATURES: tuple[tuple[int, ...], ...] = ( (0,), (-1,), (0, -1), ) MINIMAX_H3_TEXT_ID = -5 MINIMAX_H3_IMGVID_COND_ID = -11 MINIMAX_H3_AUDIO_REF_COND_ID = -17 MINIMAX_H3_AUDIO_FIRST_ID = -15 MINIMAX_H3_AUDIO_ID = -14 MINIMAX_H3_VIDEO_FIRST_ID = -3 MINIMAX_H3_VIDEO_ID = -2 MINIMAX_H3_VIDEO_LAST_ID = -4 MINIMAX_H3_PAD_ID = -1 _INTERP = 32 _T_GROUP = 5 _FRAME_PER_TOKEN = (1, 4, 4, 4, 4) _FRAME_RESCALE = 5.0 / 3.0 _SEQ_ALIGN = 64 # MiniMax H3 packs video latents with a fixed [1, 2, 2] (t, h, w) patch. _PATCH_T = 1 _PATCH_H = 2 _PATCH_W = 2 def _keyframe_cond_frame_indices( *, include_keyframe_cond: bool, keyframe_frame_indices: list[int] | tuple[int, ...] | None, ) -> list[int]: if not include_keyframe_cond: if keyframe_frame_indices is not None: raise ValueError("keyframe_frame_indices must be omitted when keyframe cond is not included") return [] if keyframe_frame_indices is None: raise ValueError("strict fl2va packed layout requires keyframe_frame_indices") if any(isinstance(value, bool) or not isinstance(value, int) for value in keyframe_frame_indices): raise ValueError("strict fl2va packed layout requires integer keyframe_frame_indices") out = list(keyframe_frame_indices) if tuple(out) not in MINIMAX_H3_FL2VA_KEYFRAME_SIGNATURES: raise ValueError( "strict fl2va packed layout requires keyframe_frame_indices in " f"{MINIMAX_H3_FL2VA_KEYFRAME_SIGNATURES!r}, got {out!r}" ) return out def _resolve_keyframe_frame_indices( frame_indices: Sequence[int], *, frame_count: int | None, ) -> list[int]: if frame_indices and frame_count is None: raise ValueError("frame_count is required when keyframe_frame_indices are provided") if frame_count is None: return [] if frame_count <= 0: raise ValueError("frame_count must be positive") seen: dict[int, int] = {} resolved: list[int] = [] for block_index, semantic_index in enumerate(frame_indices): if semantic_index == -1: resolved_index = frame_count - 1 elif 0 <= semantic_index < frame_count: resolved_index = semantic_index else: raise ValueError(f"keyframe frame index {semantic_index} must be -1 or in [0, {frame_count})") previous = seen.get(resolved_index) if previous is not None: raise ValueError( f"keyframe frame index at block {block_index} resolves to " f"{resolved_index}, already bound by block {previous}" ) seen[resolved_index] = block_index resolved.append(resolved_index) return resolved def _temporal_position_span(temporal_length: int) -> float: """Temporal position span for patch_t=1, in fp64. NOTE: intentionally NOT merged with ``_video_t_span``. This variant sums via numpy (pairwise summation), matching the fl2va anchor computation, while ``_video_t_span`` sums sequentially, matching the ref2va t-origin accumulation. The two orders diverge in the last ulp from n=16 onward, so each path must keep its own summation order. """ spans = np.ones(int(temporal_length), dtype=np.float64) * _FRAME_RESCALE for token_index in range(_T_GROUP): spans[token_index::_T_GROUP] *= _FRAME_PER_TOKEN[token_index] return float(spans.sum()) def minimax_h3_packed_sequence( *, text_len: int, latent_t: int, latent_h: int, latent_w: int, audio_t: int, audio_channel: int = 2, include_keyframe_cond: bool, keyframe_frame_indices: list[int] | tuple[int, ...] | None = None, frame_count: int | None = None, ) -> dict[str, torch.Tensor]: """Build the packed-sequence structural fields for one CFG branch. The used length is padded up to a multiple of 64. """ ph, pw = latent_h // _PATCH_H, latent_w // _PATCH_W frame_rows = ph * pw cond_frame_indices = _keyframe_cond_frame_indices( include_keyframe_cond=include_keyframe_cond, keyframe_frame_indices=keyframe_frame_indices, ) resolved_cond_frame_indices = _resolve_keyframe_frame_indices( cond_frame_indices, frame_count=frame_count, ) cond_rows = len(cond_frame_indices) * frame_rows video_rows = latent_t * frame_rows audio_rows = audio_t * audio_channel used = text_len + cond_rows + audio_rows + video_rows seq_len = ((used + _SEQ_ALIGN - 1) // _SEQ_ALIGN) * _SEQ_ALIGN text_sl = slice(0, text_len) cond_sl = slice(text_len, text_len + cond_rows) audio_sl = slice(cond_sl.stop, cond_sl.stop + audio_rows) video_sl = slice(audio_sl.stop, audio_sl.stop + video_rows) pad_sl = slice(video_sl.stop, seq_len) input_ids = torch.full((seq_len,), MINIMAX_H3_PAD_ID, dtype=torch.int64) input_ids[text_sl] = MINIMAX_H3_TEXT_ID if cond_rows: input_ids[cond_sl] = MINIMAX_H3_IMGVID_COND_ID input_ids[audio_sl] = MINIMAX_H3_AUDIO_ID input_ids[audio_sl.start] = MINIMAX_H3_AUDIO_FIRST_ID input_ids[video_sl] = MINIMAX_H3_VIDEO_ID input_ids[video_sl.start] = MINIMAX_H3_VIDEO_FIRST_ID input_ids[video_sl.stop - 1] = MINIMAX_H3_VIDEO_LAST_ID image_mask = torch.zeros(seq_len, dtype=torch.bool) image_mask[cond_sl] = True image_mask[video_sl] = True audio_mask = torch.zeros(seq_len, dtype=torch.bool) audio_mask[audio_sl] = True img_pos = torch.cat( [ torch.arange(cond_sl.start, cond_sl.stop), torch.arange(video_sl.start, video_sl.stop), ] ) update_mask = torch.zeros(img_pos.shape[0], dtype=torch.bool) update_mask[cond_rows:] = True audio_pos = torch.arange(audio_sl.start, audio_sl.stop) text_pos = torch.arange(0, text_len) g = torch.zeros(seq_len, 3, dtype=torch.float64) g[text_sl, 0] = torch.arange(text_len, dtype=torch.float64) t_grid = _video_t_grid(latent_t, float(text_len)) sqrt_area = np.sqrt(latent_h * latent_w) h_grid = _axis_from_sqrt_area(latent_h, _PATCH_H, sqrt_area) w_grid = _axis_from_sqrt_area(latent_w, _PATCH_W, sqrt_area) hh, ww = torch.meshgrid(h_grid, w_grid, indexing="ij") frame = torch.stack([hh.reshape(-1), ww.reshape(-1)], dim=-1) video_g = torch.empty(latent_t, frame_rows, 3, dtype=torch.float64) video_g[:, :, 0] = t_grid[:, None] video_g[:, :, 1:] = frame[None] for block_index, pixel_index in enumerate(resolved_cond_frame_indices): sl = slice( cond_sl.start + block_index * frame_rows, cond_sl.start + (block_index + 1) * frame_rows, ) if pixel_index == 0: cond_t = float(text_len) elif frame_count is not None and pixel_index == frame_count - 1: cond_t = float(text_len) + _temporal_position_span(latent_t) - _FRAME_RESCALE else: raise ValueError( f"fl2va packed layout only supports first/last keyframe anchors, got resolved frame index {pixel_index}" ) g[sl, 0] = cond_t g[sl, 1:] = frame g[video_sl] = video_g.reshape(-1, 3) audio_t_grid = float(text_len) + torch.arange(audio_t, dtype=torch.float64) g[audio_sl, 0] = audio_t_grid.repeat(audio_channel) g[audio_sl, 2] = torch.cat( [ torch.full((audio_t,), float(w_grid[0]), dtype=torch.float64), torch.full((audio_rows - audio_t,), float(w_grid[-1]), dtype=torch.float64), ] ) token_tags = torch.full((seq_len,), -1, dtype=torch.long) # PADDING token_tags[text_sl] = 1 # TEXT (fl2va image-segment override happens upstream) token_tags[audio_sl] = 2 # AUDIO token_tags[img_pos] = 0 # VIDEO cu = torch.tensor([0, used, seq_len], dtype=torch.int32) doc = torch.zeros(seq_len, dtype=torch.int32) doc[pad_sl] = 1 return { "seq_len": torch.tensor(seq_len), "input_ids": input_ids, "image_mask": image_mask, "audio_mask": audio_mask, "img_pos": img_pos, "audio_pos": audio_pos, "text_pos": text_pos, "update_mask": update_mask, "img_position_ids": g, "token_tags": token_tags, "cu_seqlens": cu, "document_id": doc, # Extent of the video segment within the packed sequence. "latent_grid": torch.tensor([latent_t, ph, pw], dtype=torch.int64), "video_row_start": torch.tensor(video_sl.start, dtype=torch.int64), } def _positive_int( block: Mapping[str, object], key: str, path: str, *, allow_zero: bool = False, ) -> int: value = block.get(key) if isinstance(value, bool) or not isinstance(value, int): raise ValueError(f"{path}.{key} must be an integer") if value < 0 or (value == 0 and not allow_zero): predicate = "non-negative" if allow_zero else "positive" raise ValueError(f"{path}.{key} must be {predicate}") return int(value) def _axis_from_sqrt_area(dim: int, patch: int, sqrt_area: float) -> torch.Tensor: ratio = dim / sqrt_area left = (1.0 - ratio) * 1.0 / 2.0 right = left + ratio * 1.0 grid = np.linspace(left, right, dim // patch, endpoint=False) * _INTERP return torch.from_numpy(grid).to(torch.float64) def _video_t_grid(n: int, origin: float) -> torch.Tensor: spans = torch.tensor( [_FRAME_RESCALE * _FRAME_PER_TOKEN[k % _T_GROUP] for k in range(n)], dtype=torch.float64, ) return origin + torch.cat([torch.zeros(1, dtype=torch.float64), spans[:-1].cumsum(0)]) def _video_t_span(n: int) -> float: # Sequential fp64 summation on purpose — see _temporal_position_span for # why the two span implementations must not be unified. return sum(_FRAME_RESCALE * _FRAME_PER_TOKEN[k % _T_GROUP] for k in range(n)) def _range_for_slice(sl: slice) -> torch.Tensor: return torch.arange(sl.start, sl.stop, dtype=torch.long) def _cat_ranges(parts: list[torch.Tensor]) -> torch.Tensor: if parts: return torch.cat(parts) return torch.empty(0, dtype=torch.long) def minimax_h3_packed_sequence_ref2va_blocks( *, text_len: int, latent_t: int, latent_h: int, latent_w: int, audio_t: int, ref_blocks: Sequence[Mapping[str, object]], audio_channel: int = 2, seq_len: int | None = None, ) -> dict[str, torch.Tensor]: """General ref2va-family packed layout. ``ref_blocks`` are consumed in request/plan order: - ``{"kind": "image", "latent_h": H, "latent_w": W}`` - ``{"kind": "audio", "ref_audio_t": T}`` - ``{"kind": "video"|"video_audio", "ref_audio_t": T, "latent_t": RT, "latent_h": RH, "latent_w": RW}`` Video-bearing blocks pack their audio rows immediately before their video rows; both share the same temporal origin and advance by the longer of the audio and video spans. Standalone audio advances the target origin by its own T, and image blocks advance it by one integer slot. """ if not isinstance(ref_blocks, Sequence) or isinstance(ref_blocks, (str, bytes)): raise ValueError("ref_blocks must be a sequence") parsed: list[dict[str, object]] = [] ref_visual_rows = 0 ref_audio_rows = 0 for index, raw in enumerate(ref_blocks): path = f"ref_blocks[{index}]" if not isinstance(raw, Mapping): raise ValueError(f"{path} must be an object") kind = raw.get("kind", raw.get("type")) if not isinstance(kind, str) or not kind: raise ValueError(f"{path}.kind must be a non-empty string") if kind == "image": rh = _positive_int(raw, "latent_h", path) rw = _positive_int(raw, "latent_w", path) rows = (rh // _PATCH_H) * (rw // _PATCH_W) item = {"kind": kind, "latent_h": rh, "latent_w": rw, "rows": rows} ref_visual_rows += rows elif kind == "audio": rt = _positive_int(raw, "ref_audio_t", path, allow_zero=True) rows = rt * audio_channel item = {"kind": kind, "ref_audio_t": rt, "audio_rows": rows} ref_audio_rows += rows elif kind in ("video", "video_audio"): rt = _positive_int(raw, "ref_audio_t", path, allow_zero=True) vt = _positive_int(raw, "latent_t", path) vh = _positive_int(raw, "latent_h", path) vw = _positive_int(raw, "latent_w", path) frame_rows = (vh // _PATCH_H) * (vw // _PATCH_W) audio_rows = rt * audio_channel video_rows = vt * frame_rows item = { "kind": kind, "ref_audio_t": rt, "latent_t": vt, "latent_h": vh, "latent_w": vw, "frame_rows": frame_rows, "audio_rows": audio_rows, "video_rows": video_rows, } ref_audio_rows += audio_rows ref_visual_rows += video_rows else: raise ValueError(f"{path}.kind unsupported for ref2va: {kind!r}") parsed.append(item) ph, pw = latent_h // _PATCH_H, latent_w // _PATCH_W frame_rows = ph * pw video_rows = latent_t * frame_rows audio_rows = audio_t * audio_channel ref_rows = ref_visual_rows + ref_audio_rows used = text_len + ref_rows + audio_rows + video_rows if seq_len is None: seq_len = ((used + _SEQ_ALIGN - 1) // _SEQ_ALIGN) * _SEQ_ALIGN if seq_len < used: raise ValueError(f"seq_len {seq_len} < used rows {used}") text_sl = slice(0, text_len) cursor = text_len block_slices: list[dict[str, object]] = [] for item in parsed: kind = str(item["kind"]) if kind == "image": rows = int(item["rows"]) visual_sl = slice(cursor, cursor + rows) cursor = visual_sl.stop block_slices.append({**item, "visual_sl": visual_sl}) elif kind == "audio": rows = int(item["audio_rows"]) audio_sl = slice(cursor, cursor + rows) cursor = audio_sl.stop block_slices.append({**item, "audio_sl": audio_sl}) else: a_rows = int(item["audio_rows"]) v_rows = int(item["video_rows"]) audio_sl = slice(cursor, cursor + a_rows) visual_sl = slice(audio_sl.stop, audio_sl.stop + v_rows) cursor = visual_sl.stop block_slices.append({**item, "audio_sl": audio_sl, "visual_sl": visual_sl}) audio_sl = slice(cursor, cursor + audio_rows) video_sl = slice(audio_sl.stop, audio_sl.stop + video_rows) pad_sl = slice(video_sl.stop, seq_len) input_ids = torch.full((seq_len,), MINIMAX_H3_PAD_ID, dtype=torch.int64) input_ids[text_sl] = MINIMAX_H3_TEXT_ID image_mask = torch.zeros(seq_len, dtype=torch.bool) audio_mask = torch.zeros(seq_len, dtype=torch.bool) ref_img_pos_parts: list[torch.Tensor] = [] ref_audio_pos_parts: list[torch.Tensor] = [] g = torch.zeros(seq_len, 3, dtype=torch.float64) g[text_sl, 0] = torch.arange(text_len, dtype=torch.float64) target_area = np.sqrt(latent_h * latent_w) h_grid = _axis_from_sqrt_area(latent_h, _PATCH_H, target_area) w_grid = _axis_from_sqrt_area(latent_w, _PATCH_W, target_area) hh, ww = torch.meshgrid(h_grid, w_grid, indexing="ij") target_frame = torch.stack([hh.reshape(-1), ww.reshape(-1)], dim=-1) t_cursor = float(text_len) for item in block_slices: kind = str(item["kind"]) if kind == "image": visual_sl = item["visual_sl"] assert isinstance(visual_sl, slice) input_ids[visual_sl] = MINIMAX_H3_IMGVID_COND_ID image_mask[visual_sl] = True ref_img_pos_parts.append(_range_for_slice(visual_sl)) rh = int(item["latent_h"]) rw = int(item["latent_w"]) area = np.sqrt(rh * rw) ref_hh, ref_ww = torch.meshgrid( _axis_from_sqrt_area(rh, _PATCH_H, area), _axis_from_sqrt_area(rw, _PATCH_W, area), indexing="ij", ) g[visual_sl, 0] = t_cursor g[visual_sl, 1] = ref_hh.reshape(-1) g[visual_sl, 2] = ref_ww.reshape(-1) t_cursor += 1.0 elif kind == "audio": audio_ref_sl = item["audio_sl"] assert isinstance(audio_ref_sl, slice) ref_t = int(item["ref_audio_t"]) input_ids[audio_ref_sl] = MINIMAX_H3_AUDIO_REF_COND_ID audio_mask[audio_ref_sl] = True ref_audio_pos_parts.append(_range_for_slice(audio_ref_sl)) ref_t_grid = t_cursor + torch.arange(ref_t, dtype=torch.float64) g[audio_ref_sl, 0] = ref_t_grid.repeat(audio_channel) if ref_t: g[audio_ref_sl, 2] = torch.cat( [ torch.full((ref_t,), float(w_grid[0]), dtype=torch.float64), torch.full( (int(item["audio_rows"]) - ref_t,), float(w_grid[-1]), dtype=torch.float64, ), ] ) t_cursor += float(ref_t) else: audio_ref_sl = item["audio_sl"] visual_sl = item["visual_sl"] assert isinstance(audio_ref_sl, slice) assert isinstance(visual_sl, slice) ref_t = int(item["ref_audio_t"]) vt = int(item["latent_t"]) vh = int(item["latent_h"]) vw = int(item["latent_w"]) input_ids[audio_ref_sl] = MINIMAX_H3_AUDIO_REF_COND_ID input_ids[visual_sl] = MINIMAX_H3_IMGVID_COND_ID audio_mask[audio_ref_sl] = True image_mask[visual_sl] = True ref_audio_pos_parts.append(_range_for_slice(audio_ref_sl)) ref_img_pos_parts.append(_range_for_slice(visual_sl)) ref_area = np.sqrt(vh * vw) rv_h_grid = _axis_from_sqrt_area(vh, _PATCH_H, ref_area) rv_w_grid = _axis_from_sqrt_area(vw, _PATCH_W, ref_area) rv_hh, rv_ww = torch.meshgrid(rv_h_grid, rv_w_grid, indexing="ij") ref_t_grid = t_cursor + torch.arange(ref_t, dtype=torch.float64) g[audio_ref_sl, 0] = ref_t_grid.repeat(audio_channel) if ref_t: g[audio_ref_sl, 2] = torch.cat( [ torch.full((ref_t,), float(rv_w_grid[0]), dtype=torch.float64), torch.full( (int(item["audio_rows"]) - ref_t,), float(rv_w_grid[-1]), dtype=torch.float64, ), ] ) rv_frame = torch.stack([rv_hh.reshape(-1), rv_ww.reshape(-1)], dim=-1) rv_g = torch.empty(vt, int(item["frame_rows"]), 3, dtype=torch.float64) rv_g[:, :, 0] = _video_t_grid(vt, t_cursor)[:, None] rv_g[:, :, 1:] = rv_frame[None] g[visual_sl] = rv_g.reshape(-1, 3) t_cursor += max(float(ref_t), _video_t_span(vt)) input_ids[audio_sl] = MINIMAX_H3_AUDIO_ID input_ids[audio_sl.start] = MINIMAX_H3_AUDIO_FIRST_ID input_ids[video_sl] = MINIMAX_H3_VIDEO_ID input_ids[video_sl.start] = MINIMAX_H3_VIDEO_FIRST_ID input_ids[video_sl.stop - 1] = MINIMAX_H3_VIDEO_LAST_ID audio_mask[audio_sl] = True image_mask[video_sl] = True audio_t_grid = t_cursor + torch.arange(audio_t, dtype=torch.float64) g[audio_sl, 0] = audio_t_grid.repeat(audio_channel) g[audio_sl, 2] = torch.cat( [ torch.full((audio_t,), float(w_grid[0]), dtype=torch.float64), torch.full((audio_rows - audio_t,), float(w_grid[-1]), dtype=torch.float64), ] ) video_g = torch.empty(latent_t, frame_rows, 3, dtype=torch.float64) video_g[:, :, 0] = _video_t_grid(latent_t, t_cursor)[:, None] video_g[:, :, 1:] = target_frame[None] g[video_sl] = video_g.reshape(-1, 3) target_img_pos = _range_for_slice(video_sl) target_audio_pos = _range_for_slice(audio_sl) img_pos = _cat_ranges(ref_img_pos_parts + [target_img_pos]) audio_pos = _cat_ranges(ref_audio_pos_parts + [target_audio_pos]) update_mask = torch.zeros(img_pos.shape[0], dtype=torch.bool) update_mask[ref_visual_rows:] = True audio_update_mask = torch.zeros(audio_pos.shape[0], dtype=torch.bool) audio_update_mask[ref_audio_rows:] = True text_pos = torch.arange(0, text_len) token_tags = torch.full((seq_len,), -1, dtype=torch.long) # PADDING token_tags[text_sl] = 1 # TEXT if ref_audio_rows: token_tags[_cat_ranges(ref_audio_pos_parts)] = 2 # AUDIO (reference) token_tags[audio_sl] = 2 # AUDIO (target) token_tags[img_pos] = 0 # VIDEO (refs + target) cu = torch.tensor([0, used, seq_len], dtype=torch.int32) doc = torch.zeros(seq_len, dtype=torch.int32) doc[pad_sl] = 1 return { "seq_len": torch.tensor(seq_len), "input_ids": input_ids, "image_mask": image_mask, "audio_mask": audio_mask, "img_pos": img_pos, "audio_pos": audio_pos, "text_pos": text_pos, "update_mask": update_mask, "audio_update_mask": audio_update_mask, "img_position_ids": g, "token_tags": token_tags, "cu_seqlens": cu, "document_id": doc, # Extent of the video segment within the packed sequence. "latent_grid": torch.tensor([latent_t, ph, pw], dtype=torch.int64), "video_row_start": torch.tensor(video_sl.start, dtype=torch.int64), } __all__ = [ "MINIMAX_H3_AUDIO_FIRST_ID", "MINIMAX_H3_AUDIO_ID", "MINIMAX_H3_AUDIO_REF_COND_ID", "MINIMAX_H3_IMGVID_COND_ID", "MINIMAX_H3_PAD_ID", "MINIMAX_H3_TEXT_ID", "MINIMAX_H3_VIDEO_FIRST_ID", "MINIMAX_H3_VIDEO_ID", "MINIMAX_H3_VIDEO_LAST_ID", "minimax_h3_packed_sequence", "minimax_h3_packed_sequence_ref2va_blocks", ]