From 440a27b72d88dbfe0c089488adae3ada5653a8a0 Mon Sep 17 00:00:00 2001 From: Manideep3969 Date: Thu, 20 Aug 2026 11:44:00 +0530 Subject: [PATCH] fix(#48): _simulate_values now uses cost model fidelity and warns users _simulate_values used a hardcoded base_fidelity=0.85 instead of the cost model's fidelity estimate, producing arbitrary results without any warning to users. Fix: Store the circuit in execute() and use cost_model.estimate_fidelity to get actual circuit fidelity. Fall back to 0.85 only if no circuit is available. Emit UserWarning when simulated values are used. --- src/qc_compiler/mitigation.py | 28 +++++++++++++++++++--- tests/test_mitigation.py | 45 ++++++++++++++++++++++++++++++----- 2 files changed, 64 insertions(+), 9 deletions(-) diff --git a/src/qc_compiler/mitigation.py b/src/qc_compiler/mitigation.py index feb3de5..c0c5f90 100644 --- a/src/qc_compiler/mitigation.py +++ b/src/qc_compiler/mitigation.py @@ -262,6 +262,8 @@ def execute( """ resolved_method = "zne" if plan.method == "adaptive" else plan.method + self._last_circuit = circuit + if resolved_method == "zne": return self._extrapolate_zne(plan, raw_values) elif resolved_method == "pec": @@ -605,7 +607,8 @@ def _simulate_values(self, plan: MitigationPlan) -> list[float]: """Simulate noisy expectation values from cost model. Uses the cost model's fidelity estimate to generate - plausible noisy values at each noise scale. + plausible noisy values at each noise scale. If no circuit + is available, falls back to a default fidelity estimate. Args: plan: The mitigation plan. @@ -613,10 +616,29 @@ def _simulate_values(self, plan: MitigationPlan) -> list[float]: Returns: List of simulated expectation values. """ - base_fidelity = 0.85 + import warnings + + warnings.warn( + "No raw values provided; using cost model to simulate " + "expectation values. Results are approximate and should " + "not be relied upon for accuracy.", + UserWarning, + stacklevel=2, + ) + + if ( + hasattr(self, "_last_circuit") + and self._last_circuit is not None + ): + base_fidelity = self.cost_model.estimate_fidelity( + self._last_circuit + ).total_fidelity + else: + base_fidelity = 0.85 + values = [] for scale in plan.noise_scales: - noisy = base_fidelity ** scale + noisy = base_fidelity**scale values.append(float(noisy)) return values diff --git a/tests/test_mitigation.py b/tests/test_mitigation.py index 2d33f10..c08edc2 100644 --- a/tests/test_mitigation.py +++ b/tests/test_mitigation.py @@ -432,11 +432,7 @@ def test_zne_result_is_not_placeholder(self): qc.h(0) qc.cx(0, 1) plan = mitigation.create_plan(qc, method="zne") - import warnings - - with warnings.catch_warnings(): - warnings.simplefilter("error") - result = mitigation.execute(qc, plan) + result = mitigation.execute(qc, plan, raw_values=[0.9, 0.8, 0.7]) assert result.placeholder is False assert result.method == "zne" assert plan.subcircuit_sensitivity is not None @@ -470,4 +466,41 @@ def test_adaptive_uses_zne_noise_scales(self): qc.cx(0, 1) plan_adaptive = mitigation.create_plan(qc, method="adaptive") plan_zne = mitigation.create_plan(qc, method="zne") - assert plan_adaptive.noise_scales == plan_zne.noise_scales \ No newline at end of file + assert plan_adaptive.noise_scales == plan_zne.noise_scales + + +class TestSimulateValues: + """Regression tests for _simulate_values using cost model (issue #48).""" + + def test_simulate_values_warns_when_no_raw_values(self): + mitigation = AdaptiveErrorMitigation(CostModel()) + qc = QuantumCircuit(2) + qc.h(0) + qc.cx(0, 1) + plan = mitigation.create_plan(qc, method="zne") + with pytest.warns(UserWarning, match="No raw values provided"): + mitigation.execute(qc, plan, raw_values=None) + + def test_simulate_values_uses_cost_model_fidelity(self): + mitigation = AdaptiveErrorMitigation(CostModel()) + qc = QuantumCircuit(2) + qc.h(0) + qc.cx(0, 1) + plan = mitigation.create_plan(qc, method="zne") + with pytest.warns(UserWarning, match="No raw values provided"): + result = mitigation.execute(qc, plan) + assert result.raw_values is not None + assert len(result.raw_values) > 0 + + def test_simulate_values_no_warning_with_raw_values(self): + mitigation = AdaptiveErrorMitigation(CostModel()) + qc = QuantumCircuit(2) + qc.h(0) + qc.cx(0, 1) + plan = mitigation.create_plan(qc, method="zne") + import warnings + + with warnings.catch_warnings(): + warnings.simplefilter("error") + result = mitigation.execute(qc, plan, raw_values=[0.9, 0.8]) + assert result.placeholder is False \ No newline at end of file