Sequential Quantum Gate Decomposer  v1.9.6
Powerful decomposition of general unitarias into one- and two-qubit gates gates
noisy_circuit.cpp
Go to the documentation of this file.
1 /*
2 Copyright 2025 SQUANDER Contributors
3 
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7 
8  http://www.apache.org/licenses/LICENSE-2.0
9 
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16 
17 #include "noisy_circuit.h"
18 #include "gate_operation.h"
19 #include "noise_operation.h"
20 
21 // Include gate headers
22 #include "CH.h"
23 #include "CNOT.h"
24 #include "CP.h"
25 #include "CRX.h"
26 #include "CRY.h"
27 #include "CRZ.h"
28 #include "CZ.h"
29 #include "H.h"
30 #include "RX.h"
31 #include "RY.h"
32 #include "RZ.h"
33 #include "S.h"
34 #include "SDG.h"
35 #include "SX.h"
36 #include "T.h"
37 #include "Tdg.h"
38 #include "U1.h"
39 #include "U2.h"
40 #include "U3.h"
41 #include "X.h"
42 #include "Y.h"
43 #include "Z.h"
44 
45 namespace squander {
46 namespace density {
47 
48 // ================================================================
49 // Constructors & Destructor
50 // ================================================================
51 
52 NoisyCircuit::NoisyCircuit(int qbit_num) : qbit_num_(qbit_num) {
53  if (qbit_num < 1) {
54  throw std::invalid_argument("NoisyCircuit: qbit_num must be >= 1");
55  }
56 }
57 
58 NoisyCircuit::~NoisyCircuit() = default;
59 
60 // ================================================================
61 // Move Semantics
62 // ================================================================
63 
65  : qbit_num_(other.qbit_num_), operations_(std::move(other.operations_)),
66  param_starts_(std::move(other.param_starts_)),
67  total_params_(other.total_params_) {
68  other.qbit_num_ = 0;
69  other.total_params_ = 0;
70 }
71 
73  if (this != &other) {
74  qbit_num_ = other.qbit_num_;
75  operations_ = std::move(other.operations_);
76  param_starts_ = std::move(other.param_starts_);
77  total_params_ = other.total_params_;
78  other.qbit_num_ = 0;
79  other.total_params_ = 0;
80  }
81  return *this;
82 }
83 
84 // ================================================================
85 // Internal Helpers
86 // ================================================================
87 
88 void NoisyCircuit::add_operation(std::unique_ptr<IDensityOperation> op) {
89  param_starts_.push_back(total_params_);
90  total_params_ += op->get_parameter_num();
91  operations_.push_back(std::move(op));
92 }
93 
95  add_operation(std::unique_ptr<GateOperation>(new GateOperation(gate, true)));
96 }
97 
98 // ================================================================
99 // Single-Qubit Constant Gates
100 // ================================================================
101 
102 void NoisyCircuit::add_H(int target) {
103  add_gate_internal(new H(qbit_num_, target));
104 }
105 
106 void NoisyCircuit::add_X(int target) {
107  add_gate_internal(new X(qbit_num_, target));
108 }
109 
110 void NoisyCircuit::add_Y(int target) {
111  add_gate_internal(new Y(qbit_num_, target));
112 }
113 
114 void NoisyCircuit::add_Z(int target) {
115  add_gate_internal(new Z(qbit_num_, target));
116 }
117 
118 void NoisyCircuit::add_S(int target) {
119  add_gate_internal(new S(qbit_num_, target));
120 }
121 
122 void NoisyCircuit::add_Sdg(int target) {
123  add_gate_internal(new SDG(qbit_num_, target));
124 }
125 
126 void NoisyCircuit::add_T(int target) {
127  add_gate_internal(new T(qbit_num_, target));
128 }
129 
130 void NoisyCircuit::add_Tdg(int target) {
131  add_gate_internal(new Tdg(qbit_num_, target));
132 }
133 
134 void NoisyCircuit::add_SX(int target) {
135  add_gate_internal(new SX(qbit_num_, target));
136 }
137 
138 // ================================================================
139 // Single-Qubit Parametric Gates
140 // ================================================================
141 
142 void NoisyCircuit::add_RX(int target) {
143  add_gate_internal(new RX(qbit_num_, target));
144 }
145 
146 void NoisyCircuit::add_RY(int target) {
147  add_gate_internal(new RY(qbit_num_, target));
148 }
149 
150 void NoisyCircuit::add_RZ(int target) {
151  add_gate_internal(new RZ(qbit_num_, target));
152 }
153 
154 void NoisyCircuit::add_U1(int target) {
155  add_gate_internal(new U1(qbit_num_, target));
156 }
157 
158 void NoisyCircuit::add_U2(int target) {
159  add_gate_internal(new U2(qbit_num_, target));
160 }
161 
162 void NoisyCircuit::add_U3(int target) {
163  add_gate_internal(new U3(qbit_num_, target));
164 }
165 
166 // ================================================================
167 // Two-Qubit Constant Gates
168 // ================================================================
169 
170 void NoisyCircuit::add_CNOT(int target, int control) {
171  add_gate_internal(new CNOT(qbit_num_, target, control));
172 }
173 
174 void NoisyCircuit::add_CZ(int target, int control) {
175  add_gate_internal(new CZ(qbit_num_, target, control));
176 }
177 
178 void NoisyCircuit::add_CH(int target, int control) {
179  add_gate_internal(new CH(qbit_num_, target, control));
180 }
181 
182 // ================================================================
183 // Two-Qubit Parametric Gates
184 // ================================================================
185 
186 void NoisyCircuit::add_CRY(int target, int control) {
187  add_gate_internal(new CRY(qbit_num_, target, control));
188 }
189 
190 void NoisyCircuit::add_CRZ(int target, int control) {
191  add_gate_internal(new CRZ(qbit_num_, target, control));
192 }
193 
194 void NoisyCircuit::add_CRX(int target, int control) {
195  add_gate_internal(new CRX(qbit_num_, target, control));
196 }
197 
198 void NoisyCircuit::add_CP(int target, int control) {
199  add_gate_internal(new CP(qbit_num_, target, control));
200 }
201 
202 // ================================================================
203 // Noise Channels
204 // ================================================================
205 
207  add_operation(std::unique_ptr<DepolarizingOp>(new DepolarizingOp(qbit_num)));
208 }
209 
210 void NoisyCircuit::add_depolarizing(int qbit_num, double error_rate) {
211  add_operation(std::unique_ptr<DepolarizingOp>(
212  new DepolarizingOp(qbit_num, error_rate)));
213 }
214 
217  std::unique_ptr<LocalDepolarizingOp>(new LocalDepolarizingOp(target)));
218 }
219 
220 void NoisyCircuit::add_local_depolarizing(int target, double error_rate) {
221  add_operation(std::unique_ptr<LocalDepolarizingOp>(
222  new LocalDepolarizingOp(target, error_rate)));
223 }
224 
227  std::unique_ptr<AmplitudeDampingOp>(new AmplitudeDampingOp(target)));
228 }
229 
230 void NoisyCircuit::add_amplitude_damping(int target, double gamma) {
231  add_operation(std::unique_ptr<AmplitudeDampingOp>(
232  new AmplitudeDampingOp(target, gamma)));
233 }
234 
236  add_operation(std::unique_ptr<PhaseDampingOp>(new PhaseDampingOp(target)));
237 }
238 
239 void NoisyCircuit::add_phase_damping(int target, double lambda) {
241  std::unique_ptr<PhaseDampingOp>(new PhaseDampingOp(target, lambda)));
242 }
243 
244 // ================================================================
245 // Circuit Execution
246 // ================================================================
247 
248 void NoisyCircuit::apply_to(const double *params, int param_count,
249  DensityMatrix &rho) {
250  if (rho.get_qbit_num() != qbit_num_) {
251  throw std::runtime_error("NoisyCircuit::apply_to: qubit number mismatch");
252  }
253 
254  if (param_count < total_params_) {
255  throw std::runtime_error(
256  "NoisyCircuit::apply_to: not enough parameters. Expected " +
257  std::to_string(total_params_) + ", got " + std::to_string(param_count));
258  }
259 
260  // Apply each operation in sequence
261  for (size_t i = 0; i < operations_.size(); i++) {
262  auto &op = operations_[i];
263  int start = param_starts_[i];
264  int count = op->get_parameter_num();
265 
266  const double *op_params = (count > 0) ? (params + start) : nullptr;
267  op->apply_to_density(op_params, count, rho);
268  }
269 }
270 
272  DensityMatrix &rho) {
273  apply_to(params.data, params.rows * params.cols, rho);
274 }
275 
276 // ================================================================
277 // Inspection
278 // ================================================================
279 
280 std::vector<NoisyCircuit::OperationInfo>
282  std::vector<OperationInfo> info;
283  info.reserve(operations_.size());
284 
285  for (size_t i = 0; i < operations_.size(); i++) {
286  OperationInfo oi;
287  oi.name = operations_[i]->get_name();
288  oi.is_unitary = operations_[i]->is_unitary();
289  oi.param_count = operations_[i]->get_parameter_num();
290  oi.param_start = param_starts_[i];
291  info.push_back(oi);
292  }
293 
294  return info;
295 }
296 
297 } // namespace density
298 } // namespace squander
Copyright (C) Miklos Maroti, 2021 SPDX-License-Identifier: Apache-2.0.
Definition: U3.h:19
Definition: X.h:11
Header file for a class representing a CP gate.
void add_CZ(int target, int control)
void add_RZ(int target)
1 parameter
Definition: U2.h:11
Header file for a class representing a controlled Z rotation gate.
Definition: S.h:11
void add_CRZ(int target, int control)
1 parameter
A class representing a controlled RX gate.
Definition: CRX.h:35
A class representing a CP gate.
Definition: CP.h:35
void add_CNOT(int target, int control)
void add_local_depolarizing(int target)
Add parametric local single-qubit depolarizing noise (1 parameter)
NoisyCircuit & operator=(const NoisyCircuit &)=delete
void add_U2(int target)
2 parameters
void add_phase_damping(int target)
Add parametric phase damping noise (1 parameter)
Header file for a class representing a controlled rotation gate around the Y axis.
void apply_to(const double *params, int param_count, DensityMatrix &rho)
Apply entire circuit to density matrix.
void add_U1(int target)
1 parameter
scalar * data
pointer to the stored data
Definition: matrix_base.hpp:48
Header file for a class representing a CH operation.
Header file for a class representing a controlled X rotation gate.
Definition: Tdg.h:11
std::vector< OperationInfo > get_operation_info() const
Get information about all operations.
Definition: U1.h:11
void add_CP(int target, int control)
1 parameter
void add_U3(int target)
3 parameters
A class representing a CZ operation.
Definition: CZ.h:36
Header file for a class representing a CNOT operation.
Definition: Z.h:11
Definition: RZ.h:11
A class representing a CRY gate.
Definition: CRY.h:37
int rows
The number of rows.
Definition: matrix_base.hpp:42
A class representing a CH operation.
Definition: CH.h:36
int cols
The number of columns.
Definition: matrix_base.hpp:44
NoisyCircuit(int qbit_num)
Create empty circuit for n qubits.
Amplitude damping channel (T1 relaxation): |1⟩ → |0⟩ decay.
std::vector< std::unique_ptr< IDensityOperation > > operations_
void add_depolarizing(int qbit_num)
Add parametric depolarizing noise channel (1 parameter)
void add_CRY(int target, int control)
1 parameter
Wraps an existing Gate for density matrix operations.
Quantum density matrix ρ for mixed-state representation.
Phase damping channel (T2 dephasing): loss of coherence.
Header file for a class representing a CZ operation.
A class representing a CNOT operation.
Definition: CNOT.h:35
int get_qbit_num() const
Get number of qubits.
std::vector< int > param_starts_
Depolarizing noise channel: ρ → (1-p)ρ + p·I/2^n.
void add_RY(int target)
1 parameter
Information about a circuit operation.
Definition: Y.h:11
void add_CH(int target, int control)
Definition: RY.h:11
A class representing a controlled RZ gate.
Definition: CRZ.h:35
Base class for the representation of general gate operations.
Definition: Gate.h:86
void add_RX(int target)
1 parameter
Local single-qubit depolarizing channel on one target qubit.
void add_operation(std::unique_ptr< IDensityOperation > op)
void add_CRX(int target, int control)
1 parameter
Definition: SX.h:11
Definition: T.h:11
Quantum circuit with noise for density matrix simulation.
Definition: noisy_circuit.h:57
Definition: RX.h:11
void add_amplitude_damping(int target)
Add parametric amplitude damping noise (1 parameter)
Definition: SDG.h:11