Aggregation

ResultAggregator groups raw execution results — without ever losing them. The pattern is always:

raw results -> aggregation -> derived analysis (never raw results -> replace with summary).

Usage

from microquantum import ResultAggregator
from microquantum.experiments.record import ExecutionRecord

result = [
    ExecutionRecord(execution_id="1", plan_name="sweep", backend="sim",
                    parameter_bindings={"theta": 0.0},
                    metadata={"sweep_name": "freq_sweep"}),
    ExecutionRecord(execution_id="2", plan_name="sweep", backend="sim",
                    parameter_bindings={"theta": 0.5},
                    metadata={"sweep_name": "freq_sweep"}),
    ExecutionRecord(execution_id="3", plan_name="sweep", backend="hw",
                    parameter_bindings={"theta": 1.0}, metadata={}),
]
agg = ResultAggregator(result)
print(agg.record_count)                     # 3

# group by dotted-path accessor (attribute or nested field)
by_backend = agg.group_by("backend")
by_status  = agg.group_by("status")
by_theta   = agg.group_by("parameter_bindings.theta")
counts     = agg.group_counts(by_theta)

# convenience groupings
agg.group_by_parameter("theta")
agg.group_by_backend()
agg.group_by_status()

Callables as accessors

A callable record -> value works too:

def key(record):
    return record.metadata.get("sweep_name", "fixed")

groups = agg.group_by(key)

Derived summaries

  • mean_expectation(groups, "Z") — mean of an expectation label per group (groups without the label are omitted).

  • parameter_expectations(parameter, "Z") / expectation_keys() — parameter-to-expectation surfaces.

  • to_dict(accessor="backend") / to_json(...) — JSON-safe output that keeps counts and per-group summaries.

Design guarantee

Raw records are kept as-is (agg.records is a read-only view of the original objects), so any group can be re-analysed with the full result data later.