Skip to content

Dependencies

dependencies

Conservative input dependencies from retained compiler IR, without derivatives.

BlockStructure(name, size, state_axis_positions, parameter_axis_positions) dataclass

Immutable snapshot of one existing compiler-checked block-axis proof.

Scalar parameters are implicitly broadcast. Shaped parameter positions and their time-axis convention retain the existing BlockAxisInfo meaning. No second separability analysis is performed by the export.

DependencyRows(output_names, output_shapes, input_names, rows, time_dependent) dataclass

Conservative input-column indices for each named output group.

Each RHS output is one expanded scalar state derivative. Each observable output is one complete named scalar or array; its row unions dependencies across all cells. Parameter columns identify runtime input buffers, not expanded scalar parameter coordinates. A listed edge may have zero numerical derivative; an absent edge excludes a current-input read in this scope.

edge_count property

Number of retained conservative edges.

to_dict()

Return detached primitive JSON fields.

Returns:

Type Description
dict[str, object]

Output shapes, ordered inputs, row indices and time flags.

Source code in src/op_system/dependencies.py
56
57
58
59
60
61
62
63
64
65
66
67
68
def to_dict(self) -> dict[str, object]:
    """Return detached primitive JSON fields.

    Returns:
        Output shapes, ordered inputs, row indices and time flags.
    """
    return {
        "output_names": list(self.output_names),
        "output_shapes": [list(shape) for shape in self.output_shapes],
        "input_names": list(self.input_names),
        "rows": [list(row) for row in self.rows],
        "time_dependent": list(self.time_dependent),
    }

DependencyStructure(model, status, reasons, state, parameters, observable_state, observable_parameters, parameter_axes, block_axes, limits) dataclass

Bounded compiler dependency report with source and coverage identity.

Unsupported coverage has None patterns, distinct from supported empty rows. Observations/priors/noise and numerical operators belong to their consuming contracts. This report supplies no statistical-factorization or rank proof.

to_json()

Serialize a deterministic primitive report with the existing model ID.

Returns:

Type Description
str

Schema-1 report text. Saved evidence still requires independently

str

expected source identity and a caller-owned loading contract.

Source code in src/op_system/dependencies.py
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
def to_json(self) -> str:
    """Serialize a deterministic primitive report with the existing model ID.

    Returns:
        Schema-1 report text. Saved evidence still requires independently
        expected source identity and a caller-owned loading contract.
    """
    return json.dumps(
        {
            "format": "op-system-dependencies",
            "schema_version": 1,
            "model": json.loads(self.model.to_json()),
            "coordinates": "natural_compiled_state",
            "status": self.status,
            "reasons": self.reasons,
            "state": None if self.state is None else self.state.to_dict(),
            "parameters": None
            if self.parameters is None
            else self.parameters.to_dict(),
            "observable_state": None
            if self.observable_state is None
            else self.observable_state.to_dict(),
            "observable_parameters": None
            if self.observable_parameters is None
            else self.observable_parameters.to_dict(),
            "parameter_axes": self.parameter_axes,
            "block_axes": [
                {
                    "name": block.name,
                    "size": block.size,
                    "state_axis_positions": block.state_axis_positions,
                    "parameter_axis_positions": block.parameter_axis_positions,
                }
                for block in self.block_axes
            ],
            "limits": dict(
                zip(("states", "edges", "ir_nodes"), self.limits, strict=True)
            ),
        },
        sort_keys=True,
        separators=(",", ":"),
        allow_nan=False,
    )

dependency_structure(compiled, *, max_states=4096, max_edges=262144, max_nodes=1000000)

Export input-read structure without creating numerical derivative matrices.

Expanded state rows reuse retained typed IR and the existing state-selector analysis. Observable rows union all cells in each named output, including explicit reduction axes. Listed edges conservatively survive cancellation and zero runtime coefficients. Only existing checked block axes are copied.

Parameters:

Name Type Description Default
compiled CompiledRhs

Unmodified compiler-produced artifact with retained source IR.

required
max_states int

Positive expanded-state limit, checked before traversal.

4096
max_edges int

Positive limit across all four output/input families.

262144
max_nodes int

Positive traversal-node limit after alias/reduction expansion.

1000000

Returns:

Type Description
DependencyStructure

Immutable rows and block snapshots, or explicit unsupported coverage

DependencyStructure

with None rows for operators, history, gauge-fixed execution or state

DependencyStructure

selections outside the existing selector-analysis contract.

Raises:

Type Description
ValueError

Source/layout or limits are invalid, or a limit is exceeded.

Source code in src/op_system/dependencies.py
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
def dependency_structure(
    compiled: CompiledRhs,
    *,
    max_states: int = 4096,
    max_edges: int = 262_144,
    max_nodes: int = 1_000_000,
) -> DependencyStructure:
    """Export input-read structure without creating numerical derivative matrices.

    Expanded state rows reuse retained typed IR and the existing state-selector
    analysis. Observable rows union all cells in each named output, including
    explicit reduction axes. Listed edges conservatively survive cancellation
    and zero runtime coefficients. Only existing checked block axes are copied.

    Args:
        compiled: Unmodified compiler-produced artifact with retained source IR.
        max_states: Positive expanded-state limit, checked before traversal.
        max_edges: Positive limit across all four output/input families.
        max_nodes: Positive traversal-node limit after alias/reduction expansion.

    Returns:
        Immutable rows and block snapshots, or explicit unsupported coverage
        with None rows for operators, history, gauge-fixed execution or state
        selections outside the existing selector-analysis contract.

    Raises:
        ValueError: Source/layout or limits are invalid, or a limit is exceeded.
    """
    limits = (max_states, max_edges, max_nodes)
    if any(type(value) is not int or value < 1 for value in limits):
        msg = "Dependency limits must be positive integers, not booleans"
        raise ValueError(msg)
    rhs = compiled._rhs  # ruff: ignore[private-member-access]
    if rhs is None or rhs.state_names != compiled.state_names:
        msg = "Dependency export requires matching retained compiler source/layout"
        raise ValueError(msg)
    if len(compiled.state_names) > max_states:
        msg = "Dependency expanded-state limit exceeded"
        raise ValueError(msg)
    model = StructuralModelIdentity.from_compiled(compiled)
    axes: dict[str, tuple[str, ...]] = dict.fromkeys(compiled.param_names, ())
    axes.update(dict(rhs.shaped_params))
    axes.update(dict(rhs.time_varying_params))
    for observable in rhs.observables_ir:
        axes.update(dict(observable.parameter_axes))
    blocks = tuple(
        BlockStructure(
            info.name,
            info.size,
            tuple(sorted(info.state_axis_pos.items())),
            tuple(sorted(info.param_axis_pos.items())),
        )
        for info in compiled.block_axes
    )
    reasons = tuple(
        name
        for name, present in (
            ("numerical_operators", bool(compiled.operators)),
            ("history", bool(compiled.history_requirements)),
            ("gauge_fixed_execution", compiled.gauge_fix is not None),
        )
        if present
    )
    if reasons:
        return DependencyStructure(
            model,
            "unsupported",
            reasons,
            None,
            None,
            None,
            None,
            tuple(axes.items()),
            blocks,
            limits,
        )
    collector = _Collector(rhs, compiled.state_names, tuple(axes), max_edges, max_nodes)
    if len(rhs.equations_ir) != len(compiled.state_names):
        msg = "Dependency export requires complete expanded equation IR"
        raise ValueError(msg)
    try:
        state, parameters = _patterns(
            collector,
            rhs.equations_ir,
            compiled.state_names,
            ((),) * len(compiled.state_names),
        )
        observable_state, observable_parameters = _patterns(
            collector,
            tuple(observable.expression for observable in rhs.observables_ir),
            tuple(observable.definition.name for observable in rhs.observables_ir),
            tuple(
                compiled.observables[observable.definition.name].output_shape
                for observable in rhs.observables_ir
            ),
        )
    except NotInferableError as error:
        return DependencyStructure(
            model,
            "unsupported",
            (f"state_selection:{error}",),
            None,
            None,
            None,
            None,
            tuple(axes.items()),
            blocks,
            limits,
        )
    return DependencyStructure(
        model,
        "reported",
        (),
        state,
        parameters,
        observable_state,
        observable_parameters,
        tuple(axes.items()),
        blocks,
        limits,
    )