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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147 | def apply_denoising(qc: QuantumCircuit, pos_regs, intensity_reg, outcome=None):
"""
Apply the hierarchical consistency denoiser to an MHRQI circuit.
Args:
qc: QuantumCircuit (initialized and uploaded with data)
pos_regs: position registers
intensity_reg: intensity register
outcome: outcome register (must be provided if denoising is applied)
Returns:
tuple: (modified QuantumCircuit, denoise-only QuantumCircuit)
"""
denoise_qc = QuantumCircuit(*qc.qregs)
num_levels = len(pos_regs) // 2
# ========================================
# Ancilla allocation
# ========================================
work_qubits = []
for r in denoise_qc.qregs:
if r.name == "work":
work_qubits = list(r)
break
if len(work_qubits) < 2 or outcome is None:
logging.warning("Insufficient ancillas for denoising")
return qc, denoise_qc
parent_avg_ancilla = work_qubits[0]
consistency_ancilla = work_qubits[1]
outcome_qubit = outcome[0]
intensity_qubits = list(intensity_reg)
# ==========================================
# CHECK FINEST LEVEL VS PARENT
# ==========================================
finest_level = num_levels - 1
if finest_level == 0:
denoise_qc.x(outcome_qubit)
qc.compose(denoise_qc, inplace=True)
return qc, denoise_qc
qy_fine = pos_regs[2 * finest_level][0]
qx_fine = pos_regs[2 * finest_level + 1][0]
# === Sibling superposition ===
denoise_qc.h(qy_fine)
denoise_qc.h(qx_fine)
# === Parent average encoding ===
intensity_msb = intensity_qubits[-1]
intensity_msb_1 = intensity_qubits[-2] if len(intensity_qubits) > 1 else intensity_msb
intensity_msb_2 = intensity_qubits[-3] if len(intensity_qubits) > 2 else intensity_msb_1
intensity_msb_3 = intensity_qubits[-4] if len(intensity_qubits) > 3 else intensity_msb_2
# Flip MSB bits before rotation
denoise_qc.x(intensity_msb)
denoise_qc.x(intensity_msb_1)
denoise_qc.x(intensity_msb_2)
denoise_qc.x(intensity_msb_3)
# Rotate ancilla proportionally to intensity bits
denoise_qc.cry(np.pi / 16, intensity_msb, parent_avg_ancilla)
denoise_qc.cry(np.pi / 8, intensity_msb_1, parent_avg_ancilla)
denoise_qc.cry(np.pi / 4, intensity_msb_2, parent_avg_ancilla)
denoise_qc.cry(np.pi / 2, intensity_msb_3, parent_avg_ancilla)
# Unflip MSB bits
denoise_qc.x(intensity_msb)
denoise_qc.x(intensity_msb_1)
denoise_qc.x(intensity_msb_2)
denoise_qc.x(intensity_msb_3)
# === Uncompute sibling superposition ===
denoise_qc.h(qx_fine)
denoise_qc.h(qy_fine)
# === Compare pixel to parent average ===
# XNOR logic: consistent if MSB matches parent average
denoise_qc.x(parent_avg_ancilla)
denoise_qc.ccx(intensity_msb, parent_avg_ancilla, consistency_ancilla)
denoise_qc.x(parent_avg_ancilla)
denoise_qc.x(intensity_msb)
denoise_qc.ccx(intensity_msb, parent_avg_ancilla, consistency_ancilla)
denoise_qc.x(parent_avg_ancilla)
denoise_qc.x(intensity_msb)
# === Set outcome ===
denoise_qc.x(consistency_ancilla)
denoise_qc.cx(consistency_ancilla, outcome_qubit)
# === Uncompute ===
denoise_qc.x(intensity_msb)
denoise_qc.x(parent_avg_ancilla)
denoise_qc.ccx(intensity_msb, parent_avg_ancilla, consistency_ancilla)
denoise_qc.x(parent_avg_ancilla)
denoise_qc.x(intensity_msb)
denoise_qc.ccx(intensity_msb, parent_avg_ancilla, consistency_ancilla)
# Uncompute parent average encoding
denoise_qc.h(qy_fine)
denoise_qc.h(qx_fine)
denoise_qc.x(intensity_msb)
denoise_qc.x(intensity_msb_1)
denoise_qc.x(intensity_msb_2)
denoise_qc.x(intensity_msb_3)
denoise_qc.cry(-np.pi / 16, intensity_msb, parent_avg_ancilla)
denoise_qc.cry(-np.pi / 8, intensity_msb_1, parent_avg_ancilla)
denoise_qc.cry(-np.pi / 4, intensity_msb_2, parent_avg_ancilla)
denoise_qc.cry(-np.pi / 2, intensity_msb_3, parent_avg_ancilla)
denoise_qc.x(intensity_msb)
denoise_qc.x(intensity_msb_1)
denoise_qc.x(intensity_msb_2)
denoise_qc.x(intensity_msb_3)
denoise_qc.h(qx_fine)
denoise_qc.h(qy_fine)
qc.compose(denoise_qc, inplace=True)
return qc, denoise_qc
|