File size: 3,332 Bytes
d2486ac
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
"""
Mitigation (ZNE) panel -- Phase 3 of the dashboard refactor.

Visualizes run_mitigation_sweep's result: how fidelity degrades across
noise scales, how the zero-noise-extrapolated estimate compares to the
raw noisy sample and the ideal circuit, and -- when predictive healing is
enabled -- makes the delta_preemp correction visible instead of leaving
it a silent internal number.
"""

import numpy as np
import matplotlib.pyplot as plt

from .plot_theme import C, MONO, _ax_style, _badge


def build_panel_mitigation(mitigation_res: dict, base_res: dict) -> plt.Figure:
    """mitigation_res: run_mitigation_sweep's return dict.
    base_res: the plain run_simulation() result at the base noise scale
    (only used for n_qubits/dominant-state formatting fallback -- the
    sweep's own prob_per_scale[0] is the actual base-noise sample)."""
    fig, (ax_fid, ax_prob) = plt.subplots(2, 1, figsize=(16, 12), facecolor=C['bg'])

    noise_factors = mitigation_res['noise_factors']
    fidelity_per_scale = mitigation_res['fidelity_per_scale']
    fidelity_zne = mitigation_res['fidelity_zne']

    # ROW 1 — fidelity per noise scale, with ZNE-corrected / ideal reference lines
    _ax_style(ax_fid, 'Zero-Noise Extrapolation — Fidelity vs Noise Scale',
              'Noise scale factor (× base p)', 'Fidelity')
    x = np.arange(len(noise_factors))
    ax_fid.bar(x, fidelity_per_scale, color=C['noise'], alpha=0.75, width=0.5,
               label='raw noisy (measured)')
    ax_fid.set_xticks(x)
    ax_fid.set_xticklabels([f'{f:g}×' for f in noise_factors])
    ax_fid.axhline(1.0, color=C['accent'], lw=1.0, ls='--', alpha=0.7,
                   label='ideal (F=1)')
    ax_fid.axhline(fidelity_zne, color=C['title'], lw=1.4, ls='-', alpha=0.9,
                   label='ZNE-corrected')
    ax_fid.legend(loc='lower left', fontsize=8, framealpha=0.15,
                  labelcolor=C['label'])
    ax_fid.set_ylim(0.0, max(1.05, fidelity_zne * 1.1, max(fidelity_per_scale) * 1.1))

    healing_txt = (
        f"healing: ON (Δpre_emp={mitigation_res['delta_preemp']:.4f})"
        if mitigation_res['healing_enabled'] else "healing: off (plain ZNE)"
    )
    _badge(ax_fid, f"F_ZNE={fidelity_zne:.6f}  ·  {healing_txt}", C['title'])

    # ROW 2 — top-K basis-state probability overlay: ideal / raw noisy (base
    # scale) / ZNE-corrected (same dim_vis truncation idea as build_panel_mosaico)
    prob_ideal = np.asarray(mitigation_res['prob_ideal'])
    prob_noisy_base = np.asarray(mitigation_res['prob_per_scale'][0])
    prob_zne = np.asarray(mitigation_res['prob_zne'])
    dim_vis = min(1024, len(prob_ideal))

    _ax_style(ax_prob, 'Probability Distribution — Ideal vs Raw vs ZNE-corrected',
              '|n⟩ computational basis (truncated)', 'P(|n⟩)')
    xs = np.arange(dim_vis)
    ax_prob.plot(xs, prob_ideal[:dim_vis], color=C['accent'], lw=1.2, alpha=0.85,
                 label='ideal')
    ax_prob.plot(xs, prob_noisy_base[:dim_vis], color=C['noise'], lw=1.0, alpha=0.6,
                 label='raw noisy (1×)')
    ax_prob.plot(xs, prob_zne[:dim_vis], color=C['title'], lw=1.2, alpha=0.9,
                 ls='--', label='ZNE-corrected')
    ax_prob.legend(loc='upper right', fontsize=8, framealpha=0.15,
                   labelcolor=C['label'])

    fig.tight_layout()
    return fig