Source code for quchip.engine.partitioned

"""Partition-aware dispatch for :func:`quchip.engine.simulate`.

This module only orchestrates: decide, split, run one pipeline for each
component, combine.
"""
# Chip-structural logic is in `quchip.chip.partition`.

from __future__ import annotations

from collections.abc import Mapping
from dataclasses import replace
from typing import Any
from quchip.engine.ir import StateStorage
from quchip.engine.sampling import AutomaticTimeGrid


def _uses_field_boundary(drive_ops: list, e_ops: dict | None) -> bool:
    """Whether a solve needs the unsplit PortNetwork reference plane."""
    from quchip.engine.ir import CoherentOp
    from quchip.observables import is_output_field

    if any(isinstance(operation, CoherentOp) for operation in drive_ops):
        return True
    if not e_ops:
        return False
    return any(is_output_field(value) for value in e_ops.values())


def _scheduled_coupling_supports(chip: Any, drive_ops: list) -> tuple[tuple[str, ...], ...]:
    """Return coupling endpoints activated only by this solve's drives."""
    supports: list[tuple[str, ...]] = []
    for operation in drive_ops:
        coupling = chip.coupling_map.get(operation.target_label)
        if coupling is None:
            continue
        support = (coupling.device_a_label, coupling.device_b_label)
        if support not in supports:
            supports.append(support)
    return tuple(supports)


[docs] def maybe_simulate_partitioned( chip: Any, drive_ops: list, tlist: Any, *, solver: str | None, options: dict | None, run_args: dict | None, e_ops: dict | None, initial_state: Any | None, approximation: Any | None, states: StateStorage | None = None, dissipation: bool = True, context: Any, ) -> Any | None: """Solve each component when the chip splits. ``None`` declines to the joint path. ``context`` is the joint solve's prepared context, whose resolved model decides the split. """ from quchip.cutoff import active_cutoff # The global excitation budget couples devices that no term couples. if active_cutoff(chip) is not None: return None if initial_state is not None and not isinstance(initial_state, Mapping): return None # Field inputs and outputs are defined at the complete network reference # plane. Component solves remain exact for internal observables, but the # current result combiner does not yet reconstruct a split field boundary; # keep these requests on the ordinary joint path. if _uses_field_boundary(drive_ops, e_ops): return None from quchip.chip.partition import partition_chip resolved = context._base_result part = partition_chip( chip, resolved=resolved, clone_trivial=False, extra_supports=_scheduled_coupling_supports(chip, drive_ops), ) if part.is_trivial: return None from quchip.chip.partition import split_drive_ops, split_e_ops, split_state_mapping from quchip.engine import build_problem, solve_problem from quchip.results.partitioned import PartitionedSimulationResult per_ops = split_drive_ops(part, chip, drive_ops) per_eops, key_plan = split_e_ops(part, e_ops) per_state = ( split_state_mapping(part, initial_state) if initial_state is not None else [None] * len(part) ) automatic = isinstance(tlist, AutomaticTimeGrid) times = tlist.bounds if automatic else tlist problems = [ build_problem(comp.chip, ops_i, times, solver=solver, options=options, run_args=run_args, e_ops=eops_i or None, initial_state=state_i, approximation=approximation, states=states, dissipation=dissipation) for comp, ops_i, eops_i, state_i in zip(part.components, per_ops, per_eops, per_state) ] if automatic: # All components need one grid for products of simultaneous observables. from quchip.engine.sampling import automatic_tlist common_times = automatic_tlist(problems, combine=True) problems = [replace(problem, tlist=common_times) for problem in problems] results = [solve_problem(problem) for problem in problems] return PartitionedSimulationResult(results, part, key_plan)