974 lines
26 KiB
Python
974 lines
26 KiB
Python
"""Callback-free data contract for the whole-system numeric IR.
|
|
|
|
System IR v2 describes a compiled simulation model. It is intentionally a
|
|
pure, immutable data graph: Python functions, model objects, object addresses,
|
|
and run-local diagnostic state are not part of this module's wire contract.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass, fields, is_dataclass
|
|
from enum import StrEnum
|
|
from hashlib import sha256
|
|
import json
|
|
from math import isfinite
|
|
from struct import pack
|
|
from typing import ClassVar
|
|
from unicodedata import normalize
|
|
|
|
|
|
SYSTEM_NUMERIC_IR_SCHEMA_ID = "system-numeric-ir"
|
|
SYSTEM_NUMERIC_IR_SCHEMA_MAJOR = 2
|
|
SYSTEM_NUMERIC_IR_SCHEMA_MINOR = 0
|
|
SYSTEM_NUMERIC_IR_COMPILER_ID = "generic-fluid-system"
|
|
SYSTEM_NUMERIC_IR_COMPILER_VERSION = "2.0.0"
|
|
NATIVE_NUMERIC_ABI_VERSION = 1
|
|
|
|
|
|
class IRDType(StrEnum):
|
|
FLOAT64 = "float64"
|
|
INT32 = "int32"
|
|
|
|
|
|
class IRBufferKind(StrEnum):
|
|
TIME = "time"
|
|
STATE_INPUT = "state_input"
|
|
DERIVATIVE_OUTPUT = "derivative_output"
|
|
LOCAL_STATE = "local_state"
|
|
LOCAL_DERIVATIVE = "local_derivative"
|
|
ALGEBRAIC = "algebraic"
|
|
SIGNAL = "signal"
|
|
PARAMETER = "parameter"
|
|
CONSTANT = "constant"
|
|
MODE = "mode"
|
|
WORK_FLOAT = "work_float"
|
|
WORK_INT = "work_int"
|
|
EVENT_OUTPUT = "event_output"
|
|
JACOBIAN_VALUE = "jacobian_value"
|
|
RESULT_OUTPUT = "result_output"
|
|
RUNTIME_INPUT = "runtime_input"
|
|
|
|
|
|
class IRKernelPhase(StrEnum):
|
|
PRIMAL = "primal"
|
|
RESIDUAL = "residual"
|
|
DERIVATIVE = "derivative"
|
|
PROPERTY = "property"
|
|
EVENT = "event"
|
|
RESET = "reset"
|
|
JACOBIAN = "jacobian"
|
|
OUTPUT = "output"
|
|
|
|
|
|
class IRKernelAvailability(StrEnum):
|
|
NATIVE = "native"
|
|
REFERENCE_ONLY = "reference_only"
|
|
|
|
|
|
class IRPortKind(StrEnum):
|
|
PHYSICAL = "physical"
|
|
SIGNAL = "signal"
|
|
|
|
|
|
class IRPortNominalRole(StrEnum):
|
|
INLET = "inlet"
|
|
OUTLET = "outlet"
|
|
BIDIRECTIONAL = "bidirectional"
|
|
INPUT = "input"
|
|
OUTPUT = "output"
|
|
|
|
|
|
class IRPositiveFlowDirection(StrEnum):
|
|
INTO_COMPONENT = "intoComponent"
|
|
|
|
|
|
class IRVariableRole(StrEnum):
|
|
EFFORT = "effort"
|
|
FLOW = "flow"
|
|
STREAM = "stream"
|
|
SIGNAL = "signal"
|
|
|
|
|
|
class IRConnectionRule(StrEnum):
|
|
EQUAL = "equal"
|
|
SUM_TO_ZERO = "sumToZero"
|
|
STREAM_MIX = "streamMix"
|
|
DIRECTED = "directed"
|
|
|
|
|
|
class IREquationOwner(StrEnum):
|
|
COMPONENT = "component"
|
|
CONNECTION = "connection"
|
|
|
|
|
|
class IREquationRelation(StrEnum):
|
|
EQUAL = "equal"
|
|
SUM_TO_ZERO = "sumToZero"
|
|
CONSTITUTIVE = "constitutive"
|
|
STATE = "state"
|
|
|
|
|
|
class IRPressureFlowScopeKind(StrEnum):
|
|
NETWORK = "network"
|
|
PHYSICAL_ISLAND = "physical_island"
|
|
EQUATION_BLOCK = "equation_block"
|
|
|
|
|
|
class IRStageKind(StrEnum):
|
|
STATE_REDUCE = "state_reduce"
|
|
SIGNAL = "signal"
|
|
MECHANICAL_EQUIVALENCE = "mechanical_equivalence"
|
|
DYNAMIC_VOLUME = "dynamic_volume"
|
|
PROPERTY = "property"
|
|
PRESSURE_FLOW = "pressure_flow"
|
|
STREAM = "stream"
|
|
TEMPERATURE_REFERENCE = "temperature_reference"
|
|
THERMOFLUID_FIXED_POINT = "thermofluid_fixed_point"
|
|
MECHANICAL_ACCELERATION = "mechanical_acceleration"
|
|
DERIVATIVE_REDUCE = "derivative_reduce"
|
|
EVENT = "event"
|
|
JACOBIAN = "jacobian"
|
|
OUTPUT = "output"
|
|
RESET = "reset"
|
|
|
|
|
|
class IREntryPointKind(StrEnum):
|
|
RHS = "rhs"
|
|
EVENTS = "events"
|
|
JACOBIAN = "jacobian"
|
|
OUTPUTS = "outputs"
|
|
|
|
|
|
class IRBlockKind(StrEnum):
|
|
SEQUENCE = "sequence"
|
|
FIXED_POINT = "fixed_point"
|
|
STREAM_SCC = "stream_scc"
|
|
|
|
|
|
class IRStepKind(StrEnum):
|
|
STAGE = "stage"
|
|
BLOCK = "block"
|
|
|
|
|
|
class IRStateMapKind(StrEnum):
|
|
SCATTER = "scatter"
|
|
DERIVATIVE_GATHER = "derivative_gather"
|
|
|
|
|
|
class IREventDirection(StrEnum):
|
|
DECREASING = "decreasing"
|
|
ANY = "any"
|
|
INCREASING = "increasing"
|
|
|
|
|
|
class IRFailurePolicy(StrEnum):
|
|
FAIL = "fail"
|
|
RETRY_SMALLER_STEP = "retry_smaller_step"
|
|
|
|
|
|
class IRCacheKind(StrEnum):
|
|
PROPERTY = "property"
|
|
PRESSURE_FLOW = "pressure_flow"
|
|
STREAM = "stream"
|
|
JACOBIAN = "jacobian"
|
|
OUTPUT = "output"
|
|
|
|
|
|
class IRCapabilityLevel(StrEnum):
|
|
NATIVE = "native"
|
|
REFERENCE_ONLY = "reference_only"
|
|
UNSUPPORTED = "unsupported"
|
|
|
|
|
|
class IRDiagnosticSeverity(StrEnum):
|
|
INFO = "info"
|
|
WARNING = "warning"
|
|
ERROR = "error"
|
|
|
|
|
|
class IROpcode(StrEnum):
|
|
FILL = "fill"
|
|
COPY = "copy"
|
|
SCATTER = "scatter"
|
|
LINEAR_COMBINATION = "linear_combination"
|
|
STATE_MAP = "state_map"
|
|
KERNEL_CALL = "kernel_call"
|
|
EFFORT_BROADCAST = "effort_broadcast"
|
|
FLOW_ASSIGN = "flow_assign"
|
|
CHECK_FINITE = "check_finite"
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRSchemaVersion:
|
|
schema_id: str = SYSTEM_NUMERIC_IR_SCHEMA_ID
|
|
major: int = SYSTEM_NUMERIC_IR_SCHEMA_MAJOR
|
|
minor: int = SYSTEM_NUMERIC_IR_SCHEMA_MINOR
|
|
|
|
|
|
CURRENT_SYSTEM_IR_VERSION = IRSchemaVersion()
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRSlotRef:
|
|
buffer: IRBufferKind
|
|
index: int
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRBufferSpec:
|
|
kind: IRBufferKind
|
|
dtype: IRDType
|
|
size: int
|
|
initial_float_values: tuple[float, ...] = ()
|
|
initial_int_values: tuple[int, ...] = ()
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRValueSpec:
|
|
value_id: str
|
|
slot: IRSlotRef
|
|
semantic: str
|
|
role: str
|
|
quantity: str
|
|
unit: str
|
|
scale: float
|
|
lower_bound: float | None = None
|
|
upper_bound: float | None = None
|
|
owner_component_index: int | None = None
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRKernelPhaseSpec:
|
|
"""Phase capability tag; each call's ordered slot lists define its C-01 ABI.
|
|
|
|
Fixed component-kernel signatures deliberately belong to the C-02 contract.
|
|
Recording placeholder arities here would make the current reference-only
|
|
kernels look more strictly specified than they are.
|
|
"""
|
|
|
|
phase: IRKernelPhase
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRKernelSpec:
|
|
kernel_id: str
|
|
model_type: str
|
|
model_version: str
|
|
implementation_version: str
|
|
availability: IRKernelAvailability
|
|
unavailable_reason: str | None
|
|
phases: tuple[IRKernelPhaseSpec, ...]
|
|
parameter_count: int
|
|
state_count: int
|
|
mode_count: int
|
|
workspace_float_count: int
|
|
workspace_int_count: int
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRComponentInstance:
|
|
instance_id: str
|
|
kernel_index: int
|
|
parameter_slots: tuple[IRSlotRef, ...]
|
|
state_slots: tuple[IRSlotRef, ...]
|
|
derivative_slots: tuple[IRSlotRef, ...]
|
|
mode_slots: tuple[IRSlotRef, ...]
|
|
port_indices: tuple[int, ...]
|
|
port_slots: tuple[IRSlotRef, ...]
|
|
output_indices: tuple[int, ...]
|
|
workspace_float_slots: tuple[IRSlotRef, ...]
|
|
workspace_int_slots: tuple[IRSlotRef, ...]
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRPortVariable:
|
|
variable_id: str
|
|
name: str
|
|
role: IRVariableRole
|
|
connection_rule: IRConnectionRule
|
|
quantity: str
|
|
unit: str
|
|
result_visible: bool
|
|
slot: IRSlotRef
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRPortSpec:
|
|
port_id: str
|
|
component_index: int
|
|
name: str
|
|
kind: IRPortKind
|
|
domain: str
|
|
nominal_role: IRPortNominalRole
|
|
positive_flow_direction: IRPositiveFlowDirection | None
|
|
variables: tuple[IRPortVariable, ...]
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRConnectionVariable:
|
|
name: str
|
|
rule: IRConnectionRule
|
|
endpoint_a_slot: IRSlotRef
|
|
endpoint_b_slot: IRSlotRef
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRConnectionSpec:
|
|
connection_id: str
|
|
kind: IRPortKind
|
|
domain: str
|
|
endpoint_a_port_index: int
|
|
endpoint_b_port_index: int
|
|
variables: tuple[IRConnectionVariable, ...]
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRMediumSpec:
|
|
medium_id: str
|
|
name: str
|
|
implementation_id: str
|
|
implementation_version: str
|
|
parameter_slots: tuple[IRSlotRef, ...]
|
|
component_indices: tuple[int, ...]
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRCSRPattern:
|
|
row_count: int
|
|
column_count: int
|
|
row_pointers: tuple[int, ...]
|
|
column_indices: tuple[int, ...]
|
|
|
|
@property
|
|
def nonzero_count(self) -> int:
|
|
return len(self.column_indices)
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRCSRMatrix:
|
|
pattern: IRCSRPattern
|
|
values: tuple[float, ...]
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRStateReducer:
|
|
solver_state_count: int
|
|
local_state_slots: tuple[IRSlotRef, ...]
|
|
raw_derivative_slots: tuple[IRSlotRef, ...]
|
|
state_scatter: IRCSRMatrix
|
|
derivative_gather: IRCSRMatrix
|
|
initial_state: tuple[float, ...]
|
|
absolute_tolerances: tuple[float, ...]
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRFillOperation:
|
|
opcode: ClassVar[IROpcode] = IROpcode.FILL
|
|
target_slots: tuple[IRSlotRef, ...]
|
|
value: float
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRCopyOperation:
|
|
opcode: ClassVar[IROpcode] = IROpcode.COPY
|
|
source_slot: IRSlotRef
|
|
target_slot: IRSlotRef
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRScatterOperation:
|
|
opcode: ClassVar[IROpcode] = IROpcode.SCATTER
|
|
source_slot: IRSlotRef
|
|
target_slots: tuple[IRSlotRef, ...]
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRLinearCombinationOperation:
|
|
opcode: ClassVar[IROpcode] = IROpcode.LINEAR_COMBINATION
|
|
source_slots: tuple[IRSlotRef, ...]
|
|
weights: tuple[float, ...]
|
|
target_slot: IRSlotRef
|
|
bias: float = 0.0
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRStateMapOperation:
|
|
opcode: ClassVar[IROpcode] = IROpcode.STATE_MAP
|
|
map_kind: IRStateMapKind
|
|
source_slots: tuple[IRSlotRef, ...]
|
|
target_slots: tuple[IRSlotRef, ...]
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRKernelCallOperation:
|
|
opcode: ClassVar[IROpcode] = IROpcode.KERNEL_CALL
|
|
kernel_index: int
|
|
component_index: int | None
|
|
phase: IRKernelPhase
|
|
read_slots: tuple[IRSlotRef, ...]
|
|
write_slots: tuple[IRSlotRef, ...]
|
|
equation_indices: tuple[int, ...] = ()
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IREffortBroadcastOperation:
|
|
opcode: ClassVar[IROpcode] = IROpcode.EFFORT_BROADCAST
|
|
variable: str
|
|
anchor_slot: IRSlotRef
|
|
residual_slot: IRSlotRef
|
|
result_slot: IRSlotRef
|
|
scatter_slots: tuple[IRSlotRef, ...]
|
|
equation_id: str
|
|
lower_bound: float | None = None
|
|
upper_bound: float | None = None
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRFlowAssignmentOperation:
|
|
opcode: ClassVar[IROpcode] = IROpcode.FLOW_ASSIGN
|
|
value_slot: IRSlotRef
|
|
result_slot: IRSlotRef
|
|
scatter_slots: tuple[IRSlotRef, ...]
|
|
equation_id: str
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRCheckFiniteOperation:
|
|
opcode: ClassVar[IROpcode] = IROpcode.CHECK_FINITE
|
|
slots: tuple[IRSlotRef, ...]
|
|
error_code: str
|
|
|
|
|
|
IROperation = (
|
|
IRFillOperation
|
|
| IRCopyOperation
|
|
| IRScatterOperation
|
|
| IRLinearCombinationOperation
|
|
| IRStateMapOperation
|
|
| IRKernelCallOperation
|
|
| IREffortBroadcastOperation
|
|
| IRFlowAssignmentOperation
|
|
| IRCheckFiniteOperation
|
|
)
|
|
|
|
|
|
def operation_read_slots(operation: IROperation) -> tuple[IRSlotRef, ...]:
|
|
if isinstance(operation, IRFillOperation):
|
|
return ()
|
|
if isinstance(operation, (IRCopyOperation, IRScatterOperation)):
|
|
return (operation.source_slot,)
|
|
if isinstance(operation, (IRLinearCombinationOperation, IRStateMapOperation)):
|
|
return operation.source_slots
|
|
if isinstance(operation, IRKernelCallOperation):
|
|
return operation.read_slots
|
|
if isinstance(operation, IREffortBroadcastOperation):
|
|
return (operation.anchor_slot, operation.residual_slot)
|
|
if isinstance(operation, IRFlowAssignmentOperation):
|
|
return (operation.value_slot,)
|
|
if isinstance(operation, IRCheckFiniteOperation):
|
|
return operation.slots
|
|
raise TypeError(f"Unsupported IR operation: {type(operation).__name__}.")
|
|
|
|
|
|
def operation_write_slots(operation: IROperation) -> tuple[IRSlotRef, ...]:
|
|
if isinstance(operation, IRFillOperation):
|
|
return operation.target_slots
|
|
if isinstance(operation, IRCopyOperation):
|
|
return (operation.target_slot,)
|
|
if isinstance(operation, IRScatterOperation):
|
|
return operation.target_slots
|
|
if isinstance(operation, IRLinearCombinationOperation):
|
|
return (operation.target_slot,)
|
|
if isinstance(operation, IRStateMapOperation):
|
|
return operation.target_slots
|
|
if isinstance(operation, IRKernelCallOperation):
|
|
return operation.write_slots
|
|
if isinstance(operation, IREffortBroadcastOperation):
|
|
return (operation.result_slot, *operation.scatter_slots)
|
|
if isinstance(operation, IRFlowAssignmentOperation):
|
|
return (operation.result_slot, *operation.scatter_slots)
|
|
if isinstance(operation, IRCheckFiniteOperation):
|
|
return ()
|
|
raise TypeError(f"Unsupported IR operation: {type(operation).__name__}.")
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRStage:
|
|
stage_id: str
|
|
kind: IRStageKind
|
|
operations: tuple[IROperation, ...]
|
|
declared_read_slots: tuple[IRSlotRef, ...]
|
|
declared_write_slots: tuple[IRSlotRef, ...]
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRStepRef:
|
|
kind: IRStepKind
|
|
index: int
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRConvergenceSpec:
|
|
monitor_slots: tuple[IRSlotRef, ...]
|
|
absolute_tolerance: float
|
|
relative_tolerance: float
|
|
max_iterations: int
|
|
relaxation: float
|
|
rollback_slots: tuple[IRSlotRef, ...]
|
|
failure_policy: IRFailurePolicy
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRExecutionBlock:
|
|
block_id: str
|
|
kind: IRBlockKind
|
|
steps: tuple[IRStepRef, ...]
|
|
convergence: IRConvergenceSpec | None = None
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IREntryPoint:
|
|
kind: IREntryPointKind
|
|
steps: tuple[IRStepRef, ...]
|
|
input_slots: tuple[IRSlotRef, ...]
|
|
output_slots: tuple[IRSlotRef, ...]
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRCausalEffortStageRef:
|
|
variable: str
|
|
stage_index: int
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRCausalPlan:
|
|
plan_id: str
|
|
scope_component_indices: tuple[int, ...]
|
|
source_schema_version: int
|
|
source_structural_signature: str | None
|
|
fallback_reason: str | None
|
|
canonical_slots: tuple[IRSlotRef, ...]
|
|
compatibility_slots: tuple[IRSlotRef, ...]
|
|
reset_slots: tuple[IRSlotRef, ...]
|
|
external_effort_slots: tuple[IRSlotRef, ...]
|
|
effort_stages: tuple[IRCausalEffortStageRef, ...]
|
|
flow_stage_indices: tuple[int, ...]
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRAlgebraicUnknown:
|
|
unknown_id: str
|
|
component_index: int
|
|
port_index: int
|
|
variable: str
|
|
role: IRVariableRole
|
|
slot: IRSlotRef
|
|
scale: float
|
|
lower_bound: float | None = None
|
|
upper_bound: float | None = None
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRPressureFlowEquation:
|
|
equation_id: str
|
|
owner: IREquationOwner
|
|
owner_index: int
|
|
relation: IREquationRelation
|
|
role: IRVariableRole | None
|
|
variable_slots: tuple[IRSlotRef, ...]
|
|
residual_slot: IRSlotRef
|
|
scale: float
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRPressureFlowBlock:
|
|
block_id: str
|
|
unknown_indices: tuple[int, ...]
|
|
equation_indices: tuple[int, ...]
|
|
jacobian_pattern: IRCSRPattern
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRPressureFlowScope:
|
|
scope_id: str
|
|
kind: IRPressureFlowScopeKind
|
|
component_indices: tuple[int, ...]
|
|
unknown_indices: tuple[int, ...]
|
|
equation_indices: tuple[int, ...]
|
|
block_indices: tuple[int, ...]
|
|
causal_plan_index: int | None
|
|
residual_tolerance: float
|
|
max_evaluations: int
|
|
sparse_pattern_trusted: bool
|
|
sparse_fallback_reason: str | None
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRPressureFlowPlan:
|
|
unknowns: tuple[IRAlgebraicUnknown, ...]
|
|
equations: tuple[IRPressureFlowEquation, ...]
|
|
blocks: tuple[IRPressureFlowBlock, ...]
|
|
scopes: tuple[IRPressureFlowScope, ...]
|
|
global_scope_index: int
|
|
secondary_scope_indices: tuple[int, ...]
|
|
pressure_lower_bound: float
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRStreamSCC:
|
|
scc_id: str
|
|
node_slots: tuple[IRSlotRef, ...]
|
|
block_index: int
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRStreamEdge:
|
|
source_scc_index: int
|
|
target_scc_index: int
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRStreamPlan:
|
|
plan_id: str
|
|
node_slots: tuple[IRSlotRef, ...]
|
|
strongly_connected_components: tuple[IRStreamSCC, ...]
|
|
condensed_edges: tuple[IRStreamEdge, ...]
|
|
topological_scc_indices: tuple[int, ...]
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRThermofluidPlan:
|
|
physical_port_indices: tuple[int, ...]
|
|
global_component_indices: tuple[int, ...]
|
|
stream_plan_index: int
|
|
secondary_pressure_scope_indices: tuple[int, ...]
|
|
sensitive_component_indices: tuple[int, ...]
|
|
maximum_iterations: int
|
|
flow_relative_tolerance: float
|
|
uses_conservative_global_solver: bool
|
|
conservative_fallback_reason: str | None
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRTransactionPlan:
|
|
snapshot_slots: tuple[IRSlotRef, ...]
|
|
flow_slots: tuple[IRSlotRef, ...]
|
|
cache_component_indices: tuple[int, ...]
|
|
cache_attribute_ids: tuple[str, ...]
|
|
diagnostic_owner_ids: tuple[str, ...]
|
|
restores_on_recoverable_failure: bool
|
|
restores_on_fatal_failure: bool
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRModeValueSpec:
|
|
value: int
|
|
name: str
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRModeSpec:
|
|
mode_id: str
|
|
slot: IRSlotRef
|
|
owner_component_indices: tuple[int, ...]
|
|
values: tuple[IRModeValueSpec, ...]
|
|
initial_value: int
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRFiniteDifferenceColumn:
|
|
column_index: int
|
|
value_indices: tuple[int, ...]
|
|
relative_step: float
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRJacobianPlan:
|
|
pattern: IRCSRPattern
|
|
value_slots: tuple[IRSlotRef, ...]
|
|
color_groups: tuple[tuple[int, ...], ...]
|
|
fill_steps: tuple[IRStepRef, ...]
|
|
analytic_value_indices: tuple[int, ...]
|
|
local_finite_difference_columns: tuple[IRFiniteDifferenceColumn, ...]
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRModeGuard:
|
|
mode_slot: IRSlotRef
|
|
allowed_values: tuple[int, ...]
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IREventSpec:
|
|
event_id: str
|
|
event_kind: str
|
|
owner_component_indices: tuple[int, ...]
|
|
root_slot: IRSlotRef
|
|
direction: IREventDirection
|
|
terminal: bool
|
|
priority: int
|
|
mode_guards: tuple[IRModeGuard, ...]
|
|
reset_steps: tuple[IRStepRef, ...]
|
|
invalidated_caches: tuple[IRCacheKind, ...]
|
|
restarts_integrator: bool
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IROutputSpec:
|
|
output_id: str
|
|
component_index: int
|
|
scope: str
|
|
port_name: str | None
|
|
name: str
|
|
label: str
|
|
category: str
|
|
quantity: str
|
|
unit: str
|
|
order: int
|
|
source_slot: IRSlotRef
|
|
output_slot: IRSlotRef
|
|
scale: float = 1.0
|
|
offset: float = 0.0
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRComponentCapability:
|
|
component_index: int
|
|
level: IRCapabilityLevel
|
|
supported_phases: tuple[IRKernelPhase, ...]
|
|
missing_features: tuple[str, ...]
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRCapabilityIssue:
|
|
code: str
|
|
severity: IRDiagnosticSeverity
|
|
scope_id: str
|
|
message: str
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRCapabilityReport:
|
|
system_level: IRCapabilityLevel
|
|
components: tuple[IRComponentCapability, ...]
|
|
issues: tuple[IRCapabilityIssue, ...]
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class SystemIR:
|
|
version: IRSchemaVersion
|
|
model_id: str
|
|
model_version: str
|
|
compiler_id: str
|
|
compiler_version: str
|
|
numeric_dtype: IRDType
|
|
buffers: tuple[IRBufferSpec, ...]
|
|
values: tuple[IRValueSpec, ...]
|
|
kernels: tuple[IRKernelSpec, ...]
|
|
components: tuple[IRComponentInstance, ...]
|
|
mediums: tuple[IRMediumSpec, ...]
|
|
ports: tuple[IRPortSpec, ...]
|
|
connections: tuple[IRConnectionSpec, ...]
|
|
state_reducer: IRStateReducer
|
|
causal_plans: tuple[IRCausalPlan, ...]
|
|
pressure_flow: IRPressureFlowPlan
|
|
stream_plans: tuple[IRStreamPlan, ...]
|
|
thermofluid: IRThermofluidPlan
|
|
stages: tuple[IRStage, ...]
|
|
blocks: tuple[IRExecutionBlock, ...]
|
|
entry_points: tuple[IREntryPoint, ...]
|
|
transaction: IRTransactionPlan
|
|
modes: tuple[IRModeSpec, ...]
|
|
jacobian: IRJacobianPlan
|
|
events: tuple[IREventSpec, ...]
|
|
outputs: tuple[IROutputSpec, ...]
|
|
capabilities: IRCapabilityReport
|
|
required_features: tuple[str, ...] = ()
|
|
|
|
def canonical_json_bytes(self) -> bytes:
|
|
return canonical_json_bytes(self)
|
|
|
|
def calculate_structural_signature(self) -> str:
|
|
return sha256(self.canonical_json_bytes()).hexdigest()
|
|
|
|
@property
|
|
def structural_signature(self) -> str:
|
|
return self.calculate_structural_signature()
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IRNativeBuildIdentity:
|
|
abi_version: int
|
|
target_triple: str
|
|
compiler_id: str
|
|
compiler_version: str
|
|
compile_flags: tuple[str, ...]
|
|
floating_point_policy: str
|
|
kernel_library_signature: str
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class _IRNativeArtifactKeyInput:
|
|
program_signature: str
|
|
build: IRNativeBuildIdentity
|
|
|
|
|
|
_CANONICAL_TYPE_NAMES: tuple[tuple[type[object], str], ...] = (
|
|
(IRSchemaVersion, "schema_version"),
|
|
(IRSlotRef, "slot_ref"),
|
|
(IRBufferSpec, "buffer"),
|
|
(IRValueSpec, "value"),
|
|
(IRKernelPhaseSpec, "kernel_phase"),
|
|
(IRKernelSpec, "kernel"),
|
|
(IRComponentInstance, "component"),
|
|
(IRPortVariable, "port_variable"),
|
|
(IRPortSpec, "port"),
|
|
(IRConnectionVariable, "connection_variable"),
|
|
(IRConnectionSpec, "connection"),
|
|
(IRMediumSpec, "medium"),
|
|
(IRCSRPattern, "csr_pattern"),
|
|
(IRCSRMatrix, "csr_matrix"),
|
|
(IRStateReducer, "state_reducer"),
|
|
(IRFillOperation, "operation"),
|
|
(IRCopyOperation, "operation"),
|
|
(IRScatterOperation, "operation"),
|
|
(IRLinearCombinationOperation, "operation"),
|
|
(IRStateMapOperation, "operation"),
|
|
(IRKernelCallOperation, "operation"),
|
|
(IREffortBroadcastOperation, "operation"),
|
|
(IRFlowAssignmentOperation, "operation"),
|
|
(IRCheckFiniteOperation, "operation"),
|
|
(IRStage, "stage"),
|
|
(IRStepRef, "step_ref"),
|
|
(IRConvergenceSpec, "convergence"),
|
|
(IRExecutionBlock, "block"),
|
|
(IREntryPoint, "entry_point"),
|
|
(IRCausalEffortStageRef, "causal_effort_stage"),
|
|
(IRCausalPlan, "causal_plan"),
|
|
(IRAlgebraicUnknown, "algebraic_unknown"),
|
|
(IRPressureFlowEquation, "pressure_flow_equation"),
|
|
(IRPressureFlowBlock, "pressure_flow_block"),
|
|
(IRPressureFlowScope, "pressure_flow_scope"),
|
|
(IRPressureFlowPlan, "pressure_flow_plan"),
|
|
(IRStreamSCC, "stream_scc"),
|
|
(IRStreamEdge, "stream_edge"),
|
|
(IRStreamPlan, "stream_plan"),
|
|
(IRThermofluidPlan, "thermofluid_plan"),
|
|
(IRTransactionPlan, "transaction_plan"),
|
|
(IRModeValueSpec, "mode_value"),
|
|
(IRModeSpec, "mode"),
|
|
(IRFiniteDifferenceColumn, "finite_difference_column"),
|
|
(IRJacobianPlan, "jacobian_plan"),
|
|
(IRModeGuard, "mode_guard"),
|
|
(IREventSpec, "event"),
|
|
(IROutputSpec, "output"),
|
|
(IRComponentCapability, "component_capability"),
|
|
(IRCapabilityIssue, "capability_issue"),
|
|
(IRCapabilityReport, "capability_report"),
|
|
(SystemIR, "system_ir"),
|
|
(IRNativeBuildIdentity, "native_build"),
|
|
(_IRNativeArtifactKeyInput, "native_artifact_key_input"),
|
|
)
|
|
|
|
|
|
_OPERATION_TYPES = (
|
|
IRFillOperation,
|
|
IRCopyOperation,
|
|
IRScatterOperation,
|
|
IRLinearCombinationOperation,
|
|
IRStateMapOperation,
|
|
IRKernelCallOperation,
|
|
IREffortBroadcastOperation,
|
|
IRFlowAssignmentOperation,
|
|
IRCheckFiniteOperation,
|
|
)
|
|
|
|
|
|
def _canonical_type_name(value: object) -> str:
|
|
value_type = type(value)
|
|
for candidate, name in _CANONICAL_TYPE_NAMES:
|
|
if value_type is candidate:
|
|
return name
|
|
raise TypeError(f"Unsupported IR schema object: {value_type.__name__}.")
|
|
|
|
|
|
def _canonical_float(value: float) -> object:
|
|
numeric = float(value)
|
|
if not isfinite(numeric):
|
|
raise ValueError("Canonical IR JSON does not permit NaN or infinity.")
|
|
if numeric == 0.0:
|
|
numeric = 0.0
|
|
return {"$float64": pack(">d", numeric).hex()}
|
|
|
|
|
|
def _canonical_value(value: object) -> object:
|
|
if value is None or isinstance(value, bool):
|
|
return value
|
|
if isinstance(value, StrEnum):
|
|
return value.value
|
|
if isinstance(value, int):
|
|
return value
|
|
if isinstance(value, float):
|
|
return _canonical_float(value)
|
|
if isinstance(value, str):
|
|
return normalize("NFC", value)
|
|
if isinstance(value, tuple):
|
|
return [_canonical_value(item) for item in value]
|
|
if is_dataclass(value) and not isinstance(value, type):
|
|
payload: dict[str, object] = {"$type": _canonical_type_name(value)}
|
|
if isinstance(value, _OPERATION_TYPES):
|
|
payload["opcode"] = value.opcode.value
|
|
for item in fields(value):
|
|
payload[item.name] = _canonical_value(getattr(value, item.name))
|
|
return payload
|
|
raise TypeError(
|
|
"Canonical IR JSON accepts only schema dataclasses, tuples, enums, and "
|
|
f"scalar values; received {type(value).__name__}."
|
|
)
|
|
|
|
|
|
def canonical_json_bytes(value: object) -> bytes:
|
|
"""Return the exact platform-independent canonical JSON byte sequence."""
|
|
|
|
return json.dumps(
|
|
_canonical_value(value),
|
|
ensure_ascii=True,
|
|
allow_nan=False,
|
|
sort_keys=True,
|
|
separators=(",", ":"),
|
|
).encode("utf-8")
|
|
|
|
|
|
def native_artifact_key(
|
|
program: SystemIR,
|
|
build: IRNativeBuildIdentity,
|
|
) -> str:
|
|
"""Build cache key; target details never contaminate the program hash."""
|
|
|
|
if build.abi_version != NATIVE_NUMERIC_ABI_VERSION:
|
|
raise ValueError(
|
|
"Native build ABI does not match NATIVE_NUMERIC_ABI_VERSION."
|
|
)
|
|
for field_name, value in (
|
|
("target_triple", build.target_triple),
|
|
("compiler_id", build.compiler_id),
|
|
("compiler_version", build.compiler_version),
|
|
("floating_point_policy", build.floating_point_policy),
|
|
):
|
|
if not value:
|
|
raise ValueError(f"Native build {field_name} must not be empty.")
|
|
if any(not flag for flag in build.compile_flags):
|
|
raise ValueError("Native build flags must not contain empty entries.")
|
|
if (
|
|
len(build.kernel_library_signature) != 64
|
|
or any(
|
|
character not in "0123456789abcdef"
|
|
for character in build.kernel_library_signature
|
|
)
|
|
):
|
|
raise ValueError(
|
|
"Native kernel library signature must be lowercase SHA-256 hex."
|
|
)
|
|
payload = _IRNativeArtifactKeyInput(program.structural_signature, build)
|
|
return sha256(canonical_json_bytes(payload)).hexdigest()
|