Source code for pyphi.serialize.schema

"""msgspec schema types for serializing PyPhi results.

Each serializable type has one frozen ``msgspec.Struct`` carrying a unique
string ``tag``. ``Schema`` is the tagged union of all of them; msgspec uses the
tag to validate and dispatch on decode. Adding a type means adding its Struct
here and registering its converter in :mod:`pyphi.serialize.convert`.
"""

from typing import Any

import msgspec


[docs] class DirectionSchema(msgspec.Struct, frozen=True, tag="direction"): name: str
# --- Simple value types -------------------------------------------------------
[docs] class DistanceResultSchema(msgspec.Struct, frozen=True, tag="distance_result"): value: float aux: dict[str, Any] = msgspec.field(default_factory=dict)
# A φ value is either a native float or a distance result with auxiliary data; # the Struct tag distinguishes the latter, so a bare number decodes as a float. PhiSchema = float | DistanceResultSchema
[docs] class NodeLabelsSchema(msgspec.Struct, frozen=True, tag="node_labels"): labels: tuple[str, ...] node_indices: tuple[int, ...]
[docs] class NoNodeLabelsSchema(msgspec.Struct, frozen=True, tag="no_node_labels"): """Marker for an object whose ``node_labels`` was ``None`` at encode time. Within a document, a stored ``None`` means "inherit the document's label frame"; this marker records that the object genuinely carried no labels, so decode does not attach the frame to it. """
# A stored per-object ``node_labels``: the labels themselves, the explicit # no-labels marker, or ``None`` meaning "inherit the document frame". NodeLabelsField = NodeLabelsSchema | NoNodeLabelsSchema | None
[docs] class StateSpecificationSchema(msgspec.Struct, frozen=True, tag="state_specification"): direction: DirectionSchema purview: tuple[int, ...] state: tuple[int, ...] intrinsic_information: PhiSchema repertoire: bytes unconstrained_repertoire: bytes # Tri-state: None = ties never computed; () = computed, no peers (the # tie family is just this specification); otherwise the peer tuple. tie_peers: tuple["StateSpecificationSchema", ...] | None = () runner_up_state: tuple[int, ...] | None = None runner_up_intrinsic_information: PhiSchema | None = None node_labels: NodeLabelsField = None
[docs] class SystemStateSpecificationSchema( msgspec.Struct, frozen=True, tag="system_state_specification" ): cause: StateSpecificationSchema effect: StateSpecificationSchema
StateSpecSchema = StateSpecificationSchema | SystemStateSpecificationSchema # --- Partitions and edge cuts -------------------------------------------------
[docs] class PartSchema(msgspec.Struct, frozen=True, tag="part"): mechanism: tuple[int, ...] purview: tuple[int, ...] node_labels: NodeLabelsField = None
[docs] class NullCutSchema(msgspec.Struct, frozen=True, tag="null_cut"): indices: tuple[int, ...] node_labels: NodeLabelsField = None
[docs] class DirectedBipartitionSchema(msgspec.Struct, frozen=True, tag="directed_bipartition"): direction: DirectionSchema from_nodes: tuple[int, ...] to_nodes: tuple[int, ...] node_labels: NodeLabelsField = None
[docs] class JointPartitionSchema(msgspec.Struct, frozen=True, tag="joint_partition"): parts: tuple[PartSchema, ...] node_labels: NodeLabelsField = None
[docs] class JointBipartitionSchema(msgspec.Struct, frozen=True, tag="joint_bipartition"): part0: PartSchema part1: PartSchema node_labels: NodeLabelsField = None
[docs] class JointTripartitionSchema(msgspec.Struct, frozen=True, tag="joint_tripartition"): parts: tuple[PartSchema, ...] node_labels: NodeLabelsField = None
JointPartitionSchemas = ( JointPartitionSchema | JointBipartitionSchema | JointTripartitionSchema )
[docs] class DirectedJointPartitionSchema( msgspec.Struct, frozen=True, tag="directed_joint_partition" ): direction: DirectionSchema partition: JointPartitionSchemas node_labels: NodeLabelsField = None
[docs] class EdgeCutSchema(msgspec.Struct, frozen=True, tag="edge_cut"): node_indices: tuple[int, ...] cut_matrix: bytes node_labels: NodeLabelsField
[docs] class TotalCutSchema(msgspec.Struct, frozen=True, tag="total_cut"): node_indices: tuple[int, ...] node_labels: NodeLabelsField
[docs] class DirectedSetPartitionSchema( msgspec.Struct, frozen=True, tag="directed_set_partition" ): node_indices: tuple[int, ...] cut_matrix: bytes set_partition: tuple[tuple[int, ...], ...] node_labels: NodeLabelsField
# Any concrete partition / edge cut (the building-block Part is separate). PartitionSchema = ( NullCutSchema | DirectedBipartitionSchema | DirectedJointPartitionSchema | EdgeCutSchema | TotalCutSchema | DirectedSetPartitionSchema | JointPartitionSchema | JointBipartitionSchema | JointTripartitionSchema ) # --- RIA and MICE -------------------------------------------------------------
[docs] class RIASchema(msgspec.Struct, frozen=True, tag="ria"): phi: PhiSchema direction: DirectionSchema mechanism: tuple[int, ...] mechanism_state: tuple[int, ...] | None purview: tuple[int, ...] purview_state: tuple[int, ...] | None partition: PartitionSchema repertoire: bytes | None partitioned_repertoire: bytes | None specified_state: StateSpecificationSchema | None node_labels: NodeLabelsField partition_tie_peers: tuple["RIASchema", ...] = () state_tie_peers: tuple["RIASchema", ...] = () partition_margin: PhiSchema | None = None signed_phi: PhiSchema | None = None selectivity: float | None = None reasons: tuple[str, ...] | None = None signed_normalized_phi: float | None = None
[docs] class MICESchema(msgspec.Struct, frozen=True, tag="mice"): ria: RIASchema purview_margin: PhiSchema | None = None purview_tie_peers: tuple["MICEAnySchema", ...] | None = None # Whether the MICE is itself a member of its purview-tie tuple (a # state- or partition-tie MICE carries the winner's tuple without # being a member). Defaults True for payloads written before the field # existed. purview_tie_member: bool = True
[docs] class MICECauseSchema(msgspec.Struct, frozen=True, tag="mice_cause"): ria: RIASchema purview_margin: PhiSchema | None = None purview_tie_peers: tuple["MICEAnySchema", ...] | None = None purview_tie_member: bool = True
[docs] class MICEEffectSchema(msgspec.Struct, frozen=True, tag="mice_effect"): ria: RIASchema purview_margin: PhiSchema | None = None purview_tie_peers: tuple["MICEAnySchema", ...] | None = None purview_tie_member: bool = True
MICEAnySchema = MICESchema | MICECauseSchema | MICEEffectSchema # --- Distinctions -------------------------------------------------------------
[docs] class DistinctionSchema(msgspec.Struct, frozen=True, tag="distinction"): mechanism: tuple[int, ...] | None cause: MICEAnySchema effect: MICEAnySchema
# IIT 3.0 terminology calls a distinction a "concept". ConceptSchema = DistinctionSchema
[docs] class DistinctionsSchema(msgspec.Struct, frozen=True, tag="distinctions"): concepts: tuple[DistinctionSchema, ...]
[docs] class UnresolvedDistinctionsSchema( msgspec.Struct, frozen=True, tag="unresolved_distinctions" ): concepts: tuple[DistinctionSchema, ...]
[docs] class ResolvedDistinctionsSchema( msgspec.Struct, frozen=True, tag="resolved_distinctions" ): concepts: tuple[DistinctionSchema, ...]
DistinctionsAnySchema = ( DistinctionsSchema | UnresolvedDistinctionsSchema | ResolvedDistinctionsSchema ) # --- Provenance, excluded candidates, and SIAs --------------------------------
[docs] class ProvenanceSchema(msgspec.Struct, frozen=True, tag="provenance"): pyphi_version: str git_sha: str | None git_dirty: bool | None timestamp: str python_version: str numpy_version: str scipy_version: str platform: str wall_time: float | None = None seed: int | None = None note: str | None = None estimator: dict | None = None
[docs] class MacroUnitSchema(msgspec.Struct, frozen=True, tag="macro_unit"): constituents: tuple["MacroUnitSchema | int", ...] update_grain: int mapping: tuple[int, ...] background_apportionment: tuple[int, ...] = ()
[docs] class ExcludedCandidateSchema(msgspec.Struct, frozen=True, tag="excluded_candidate"): node_indices: tuple[int, ...] phi: float | None units: tuple[MacroUnitSchema, ...] | None = None ii_ceiling: float | None = None gated: bool = False
[docs] class RunnerUpSchema(msgspec.Struct, frozen=True, tag="runner_up"): partition: PartitionSchema phi: PhiSchema normalized_phi: PhiSchema | None = None
[docs] class IIT3SIASchema(msgspec.Struct, frozen=True, tag="iit3_sia"): phi: PhiSchema | None distinctions: DistinctionsAnySchema | None partitioned_distinctions: DistinctionsAnySchema | None partition: PartitionSchema | None node_indices: tuple[int, ...] | None node_labels: NodeLabelsField current_state: tuple[int, ...] | None tie_peers: tuple["IIT3SIASchema", ...] = () runner_up: RunnerUpSchema | None = None reasons: tuple[str, ...] | None = None config: dict[str, Any] | None = None provenance: ProvenanceSchema | None = None
# Direction-keyed phi dict (e.g. intrinsic_differentiation) as ordered pairs. DirectionPhiPairs = tuple[tuple[DirectionSchema, PhiSchema], ...]
[docs] class IIT4SIASchema(msgspec.Struct, frozen=True, tag="iit4_sia"): phi: PhiSchema partition: PartitionSchema normalized_phi: PhiSchema cause: RIASchema | None effect: RIASchema | None system_state: SystemStateSpecificationSchema | None current_state: tuple[int, ...] | None node_indices: tuple[int, ...] | None node_labels: NodeLabelsField intrinsic_differentiation: DirectionPhiPairs | None reasons: tuple[str, ...] | None signed_phi: PhiSchema | None signed_normalized_phi: PhiSchema | None config: dict[str, Any] | None provenance: ProvenanceSchema | None tie_peers: tuple["IIT4SIASchema", ...] = () partition_margin: PhiSchema | None = None runner_up: RunnerUpSchema | None = None
[docs] class NullIIT4SIASchema(IIT4SIASchema, frozen=True, tag="null_iit4_sia"): pass
SIASchema = IIT3SIASchema | IIT4SIASchema | NullIIT4SIASchema # --- Relations (standalone) --------------------------------------------------- # A standalone relation embeds its member distinctions in full. Inside a # CauseEffectStructure the distinctions are stored once and relations reference # them by index (see the normalized CES schema below).
[docs] class RelationSchema(msgspec.Struct, frozen=True, tag="relation"): distinctions: tuple[DistinctionSchema, ...]
[docs] class ConcreteRelationsSchema(msgspec.Struct, frozen=True, tag="concrete_relations"): relations: tuple[RelationSchema, ...]
[docs] class NullRelationsSchema(msgspec.Struct, frozen=True, tag="null_relations"): pass
[docs] class AnalyticalRelationsSchema(msgspec.Struct, frozen=True, tag="analytical_relations"): distinctions: DistinctionsAnySchema
RelationsSchema = ( ConcreteRelationsSchema | NullRelationsSchema | AnalyticalRelationsSchema ) # --- Normalized cause-effect structure ---------------------------------------- # Within a CES the distinctions are stored once in a table; each relation # references its members by their index into that table, removing the dominant # redundancy of embedding every distinction in every relation.
[docs] class RelationRefSchema(msgspec.Struct, frozen=True, tag="relation_ref"): distinction_indices: tuple[int, ...]
[docs] class ConcreteRelationsRefSchema( msgspec.Struct, frozen=True, tag="concrete_relations_ref" ): relations: tuple[RelationRefSchema, ...]
[docs] class NullRelationsRefSchema(msgspec.Struct, frozen=True, tag="null_relations_ref"): pass
[docs] class AnalyticalRelationsRefSchema( msgspec.Struct, frozen=True, tag="analytical_relations_ref" ): pass
RelationsRefSchema = ( ConcreteRelationsRefSchema | NullRelationsRefSchema | AnalyticalRelationsRefSchema )
[docs] class CESSchema(msgspec.Struct, frozen=True, tag="ces"): sia: SIASchema distinctions: DistinctionsAnySchema relations: RelationsRefSchema config: dict[str, Any] | None = None provenance: ProvenanceSchema | None = None
[docs] class NullCESSchema(CESSchema, frozen=True, tag="null_ces"): pass
# --- Substrate, system, transition --------------------------------------------
[docs] class SubstrateSchema(msgspec.Struct, frozen=True, tag="substrate"): """Alphabet-general substrate encoding. One conditional factor array per node plus the per-node state space, so substrates with any alphabet sizes round-trip. """ factors: tuple[bytes, ...] state_space: tuple[tuple[int | str, ...], ...] cm: bytes node_labels: NodeLabelsField factors_trimmed: tuple[bool, ...] | None = None
[docs] class SystemSchema(msgspec.Struct, frozen=True, tag="system"): substrate: SubstrateSchema state: tuple[int, ...] node_indices: tuple[int, ...] partition: PartitionSchema external_indices: tuple[int, ...] background_conditioning: str | None = None background_state: tuple[int, ...] | None = None
[docs] class TransitionSchema(msgspec.Struct, frozen=True, tag="transition"): substrate: SubstrateSchema before_state: tuple[int, ...] after_state: tuple[int, ...] cause_indices: tuple[int, ...] effect_indices: tuple[int, ...] partition: PartitionSchema noise_background: bool = False
[docs] class TransitionSystemSchema(msgspec.Struct, frozen=True, tag="transition_system"): substrate: SubstrateSchema before_state: tuple[int, ...] after_state: tuple[int, ...] cause_indices: tuple[int, ...] effect_indices: tuple[int, ...] direction: DirectionSchema partition: PartitionSchema noise_background: bool = False
# --- Actual causation ---------------------------------------------------------
[docs] class AcRIASchema(msgspec.Struct, frozen=True, tag="ac_ria"): # ``purview``, ``partition``, and the probabilities are None for the # null RIA of a reducible causal link. alpha: float state: tuple[int, ...] direction: DirectionSchema mechanism: tuple[int, ...] purview: tuple[int, ...] | None partition: PartitionSchema | None probability: float | None partitioned_probability: float | None partition_tie_peers: tuple["AcRIASchema", ...] = () node_labels: NodeLabelsField = None reasons: tuple[str, ...] | None = None
[docs] class CausalLinkSchema(msgspec.Struct, frozen=True, tag="causal_link"): ria: AcRIASchema extended_purview: tuple[tuple[int, ...], ...] | None purview_tie_peers: tuple[AcRIASchema, ...] = ()
[docs] class AccountSchema(msgspec.Struct, frozen=True, tag="account"): causal_links: tuple[CausalLinkSchema, ...]
[docs] class DirectedAccountSchema(msgspec.Struct, frozen=True, tag="directed_account"): causal_links: tuple[CausalLinkSchema, ...]
AccountAnySchema = AccountSchema | DirectedAccountSchema
[docs] class AcSIASchema(msgspec.Struct, frozen=True, tag="ac_sia"): alpha: float | None direction: DirectionSchema | None account: AccountAnySchema | None partitioned_account: AccountAnySchema | None partition: PartitionSchema | None before_state: tuple[int, ...] | None after_state: tuple[int, ...] | None size: int | None node_indices: tuple[int, ...] | None cause_indices: tuple[int, ...] | None effect_indices: tuple[int, ...] | None node_labels: NodeLabelsField reasons: tuple[str, ...] | None = None config: dict[str, Any] | None = None provenance: ProvenanceSchema | None = None tie_peers: tuple["AcSIASchema", ...] = ()
# --- Complex (embeds a substrate, hence after the substrate schema) -----------
[docs] class AnalysisSchema(msgspec.Struct, frozen=True, tag="analysis"): system: "SystemSchema | MacroSystemSchema" sia: SIASchema # IIT 4.0 wraps the distinctions in a Φ-structure; IIT 3.0's cause-effect # structure is the bare distinction sequence. ces: "CESSchema | NullCESSchema | DistinctionsAnySchema"
[docs] class ComplexSchema(msgspec.Struct, frozen=True, tag="complex"): sia: SIASchema substrate: SubstrateSchema is_maximal: bool excluded: tuple[ExcludedCandidateSchema, ...] units: tuple[MacroUnitSchema, ...] | None = None node_indices: tuple[int, ...] | None = None
# --- Macro systems and the grain search ---------------------------------------
[docs] class MacroSystemSchema(msgspec.Struct, frozen=True, tag="macro_system"): """A :class:`~pyphi.macro.system.MacroSystem`. Carries the System fields over the synthetic macro substrate plus the macro construction: the units, the micro universe and history, and the construction's cause TPM (stored as factors like a substrate, since it is not derivable from the macro substrate). """ substrate: SubstrateSchema state: tuple[int, ...] node_indices: tuple[int, ...] partition: PartitionSchema external_indices: tuple[int, ...] units: tuple[MacroUnitSchema, ...] micro_substrate: SubstrateSchema micro_history: tuple[tuple[int, ...], ...] cause_factors: tuple[bytes, ...] cause_factors_trimmed: tuple[bool, ...] cause_state_space: tuple[tuple[int | str, ...], ...] background_conditioning: str | None = None background_state: tuple[int, ...] | None = None
[docs] class EvaluationRecordSchema(msgspec.Struct, frozen=True, tag="evaluation_record"): system: MacroSystemSchema phi: float | None ii_ceiling: float | None = None gated: bool = False
[docs] class ComplexesResultSchema(msgspec.Struct, frozen=True, tag="complexes_result"): complexes: tuple[ComplexSchema, ...] records: tuple[EvaluationRecordSchema, ...] ties: tuple[tuple[MacroSystemSchema, ...], ...]
# --- Estimation-layer posteriors ----------------------------------------------
[docs] class CoverageReportSchema(msgspec.Struct, frozen=True, tag="coverage_report"): counts: bytes n_units: int
[docs] class SubstratePosteriorSchema(msgspec.Struct, frozen=True, tag="substrate_posterior"): alpha_on: bytes alpha_off: bytes regime: str prior: float coverage: CoverageReportSchema node_labels: tuple[str, ...] | None provenance: ProvenanceSchema
[docs] class PhiPosteriorSchema(msgspec.Struct, frozen=True, tag="phi_posterior"): samples: bytes complex_samples: tuple[tuple[int, ...], ...] state: tuple[int, ...] subset: tuple[int, ...] | None seed: int regime: str coverage: CoverageReportSchema provenance: ProvenanceSchema screen_margin: float | None = None screened: bool = False reference_margins: dict[str, float | None] | None = None
# --- Batch-run results --------------------------------------------------------
[docs] class DataFrameSchema(msgspec.Struct, frozen=True, tag="dataframe"): """A pandas DataFrame as embedded parquet. ``index_columns`` names the index levels reset to columns before the parquet write; ``tuple_columns`` names the object columns whose non-null cells are restored as tuples on decode (parquet represents them as lists). """ parquet: bytes index_columns: tuple[str, ...] = () tuple_columns: tuple[str, ...] = ()
[docs] class SweepResultSchema(msgspec.Struct, frozen=True, tag="sweep_result"): df: DataFrameSchema results: tuple["Schema | float", ...] skipped: tuple[tuple["str | int", str, tuple[int, ...], tuple[int, ...]], ...]
[docs] class CampaignTaskSchema(msgspec.Struct, frozen=True, tag="campaign_task"): task_id: int kind: str compute: "str | None" compute_ref: "str | None" config_overrides: dict[str, Any] cells: tuple[tuple["str | int", str | None, tuple[int, ...], tuple[int, ...]], ...] skip_uncomputable: bool
[docs] class CellOutputSchema(msgspec.Struct, frozen=True, tag="campaign_cell_output"): status: str result: "Schema | None" traceback: "str | None" aux: dict[str, Any] | None = None
[docs] class CampaignTaskOutputSchema(msgspec.Struct, frozen=True, tag="campaign_task_output"): task_id: int pyphi_version: str entries: tuple[CellOutputSchema, ...] metrics: dict[str, Any] | None = None
[docs] class AxisScopeSchema(msgspec.Struct, frozen=True, tag="axis_scope"): explicit: tuple[tuple[int, ...], ...] | None min_order: int | None max_order: int | None containing: tuple[int, ...] | None within: tuple[int, ...] | None
[docs] class CESScopeSchema(msgspec.Struct, frozen=True, tag="ces_scope"): mechanisms: AxisScopeSchema cause_purviews: AxisScopeSchema effect_purviews: AxisScopeSchema max_purview_order_by_mechanism_order: tuple[tuple[int, int], ...] | None = None
[docs] class ShardSpecSchema(msgspec.Struct, frozen=True, tag="shard_spec"): payload_kind: str mechanisms: tuple[tuple[int, ...], ...] mechanism: tuple[int, ...] | None direction: "str | None" purviews: tuple[tuple[int, ...], ...] purview: tuple[int, ...] | None stride: tuple[int, int] | None units: float memory_bytes: int = 0
[docs] class CESShardTaskSchema(msgspec.Struct, frozen=True, tag="campaign_ces_task"): task_id: int kind: str substrate_label: "str | int" state: tuple[int, ...] subset: tuple[int, ...] | None scope: CESScopeSchema config_overrides: dict[str, Any] formalism: str | None spec: ShardSpecSchema ordering: "str | None"
[docs] class SIAShardTaskSchema(msgspec.Struct, frozen=True, tag="campaign_sia_task"): task_id: int kind: str substrate_label: "str | int" state: tuple[int, ...] subset: tuple[int, ...] | None config_overrides: dict[str, Any] formalism: str | None stride: tuple[int, int]
[docs] class OptimizationResultSchema(msgspec.Struct, frozen=True, tag="optimization_result"): """An :func:`~pyphi.optimize.optimize` outcome. ``best_objective`` is stored as None exactly when the run had no reachable candidate (NaN on the domain object; JSON cannot carry NaN). """ best_params: bytes best_objective: float | None best_substrate: SubstrateSchema best_sia: SIASchema | None trajectory: DataFrameSchema bounds: tuple[tuple[float, float], ...] seed: int direction: str objective_name: str settings: dict[str, Any] config_snapshot: dict[str, Any] n_evaluations: int n_unreachable: int
# The tagged union grows one member per serializable type. Schema = ( DirectionSchema | DistanceResultSchema | NodeLabelsSchema | StateSpecificationSchema | SystemStateSpecificationSchema | PartSchema | NullCutSchema | DirectedBipartitionSchema | DirectedJointPartitionSchema | EdgeCutSchema | TotalCutSchema | DirectedSetPartitionSchema | JointPartitionSchema | JointBipartitionSchema | JointTripartitionSchema | RIASchema | MICESchema | MICECauseSchema | MICEEffectSchema | DistinctionSchema | DistinctionsSchema | UnresolvedDistinctionsSchema | ResolvedDistinctionsSchema | ProvenanceSchema | RunnerUpSchema | ExcludedCandidateSchema | MacroUnitSchema | IIT3SIASchema | IIT4SIASchema | NullIIT4SIASchema | RelationSchema | ConcreteRelationsSchema | NullRelationsSchema | AnalyticalRelationsSchema | CESSchema | NullCESSchema | SubstrateSchema | SystemSchema | TransitionSchema | TransitionSystemSchema | AcRIASchema | CausalLinkSchema | AccountSchema | DirectedAccountSchema | AcSIASchema | ComplexSchema | MacroSystemSchema | EvaluationRecordSchema | ComplexesResultSchema | AnalysisSchema | CoverageReportSchema | SubstratePosteriorSchema | PhiPosteriorSchema | SweepResultSchema | OptimizationResultSchema | CampaignTaskSchema | CellOutputSchema | CampaignTaskOutputSchema | AxisScopeSchema | CESScopeSchema | ShardSpecSchema | CESShardTaskSchema | SIAShardTaskSchema )