Skip to content

SPSAIterationIR

from cascaqit import SPSAIterationIR

SPSAIterationIR

SPSAIterationIR(
    iteration_index: int,
    learning_rate: float,
    perturbation: float,
    center_parameters: Mapping[str, float],
    directions: tuple[SPSADirectionIR, ...],
    gradient_estimate: Mapping[str, float],
    gradient_standard_error: Mapping[str, float] | None,
    unprojected_parameters: Mapping[str, float],
    updated_parameters: Mapping[str, float],
    update_norm: float,
    projection_applied: bool,
    schema_version: str = ALGORITHM_SCHEMA_VERSION,
)

Store one SPSA update, usually from result.optimization_starts[i].spsa_iterations. learning_rate and perturbation are the actual gains for this iteration after applying their schedules. iteration_index starts at 0.

directions retains plus/minus parameters, repeated objective estimates and the gradient for each random direction. gradient_estimate averages those gradients. With one direction, gradient_standard_error is None. With at least two, it is the sample standard deviation across directions divided by the square root of their count, not a total for every source of error.

center_parameters, unprojected_parameters and updated_parameters retain the point before the update, after subtracting learning_rate times gradient, and after projection. update_norm is the actual Euclidean update norm. projection_applied can be triggered by perturbation points or the updated point, not just the final point.

Parameter mappings must share ordered keys and direction indices must be contiguous from 0. Construction and restoration recheck directional and mean gradients, standard errors and update norm. They do not call the backend to fill missing records.

from cascaqit import HamiltonianTerm, OptimizerConfig, PauliHamiltonian, PauliZ, VQE

vqe = VQE(PauliHamiltonian("z", (HamiltonianTerm("z", 1.0, PauliZ("q0")),),
                           logical_order=("q0",)))
result = vqe.run(optimizer=OptimizerConfig(method="SPSA", max_iterations=2, seed=7),
                 initial_parameters=(0.4, 0.2), final_shots=16)
from cascaqit import SPSAIterationIR

iteration = result.optimization_starts[0].spsa_iterations[0]
assert iteration.iteration_index == 0
assert len(iteration.directions) == 1
assert iteration.gradient_standard_error is None
assert SPSAIterationIR.from_dict(iteration.to_dict()).stable_hash() == iteration.stable_hash()

from_dict

from_dict(data: Mapping[str, Any]) -> SPSAIterationIR

Restore nested SPSADirectionIR records from a dictionary and validate derived values, returning SPSAIterationIR. Missing fields or inconsistent records raise. There is no from_json(); decode JSON text with json.loads() first.

to_dict

to_dict() -> dict[str, Any]

Return a JSON-compatible dictionary of the complete record, including nested objects. This saves existing data without rerunning the experiment.

to_json

to_json(*, indent: int | None = None) -> str

Return the complete record as a JSON string. indent controls formatting; no file is written.

stable_hash

stable_hash() -> str

Return the SHA-256 digest of the complete canonical JSON record for content comparison and provenance. It neither proves the experiment’s conclusion nor establishes physical equivalence.