Maestro 0.3.11
Unified interface for quantum circuit simulation
Loading...
Searching...
No Matches
QcsimPauliPropagator.h
Go to the documentation of this file.
1
11
12#pragma once
13
14#ifndef _QCSIM_PAULI_PROPAGATOR_H
15#define _QCSIM_PAULI_PROPAGATOR_H 1
16
18#include "PauliPropagator.h"
19
20namespace Simulators
21{
22
23class QcsimPauliPropagator : public QC::PauliPropagator
24{
25 public:
26 void ApplyP(int qubit, double lambda)
27 {
28 ApplyRZ(qubit, lambda);
29 }
30
31 void ApplyT(int qubit)
32 {
33 ApplyRZ(qubit, M_PI_4);
34 }
35
36 void ApplyTDG(int qubit)
37 {
38 ApplyRZ(qubit, -M_PI_4);
39 }
40
41 // U and controlled gates are inherited from QCSim's native packed API.
42 // Each is one recorded operation, so approximation intervals count full gates.
43
44 std::unique_ptr<QcsimPauliPropagator> Clone() const
45 {
46 auto clone = std::make_unique<QcsimPauliPropagator>();
47 clone->SetNrQubits(GetNrQubits());
48 clone->SetPauliWeightThreshold(GetPauliWeightThreshold());
49 clone->SetBatchSize(GetBatchSize());
50 clone->SetBatchSizeForSum(GetBatchSizeForSum());
51 clone->SetCoefficientThreshold(GetCoefficientThreshold());
52 clone->SetParallelThreshold(GetParallelThreshold());
53 clone->SetParallelThresholdForSum(GetParallelThresholdForSum());
54 clone->SetStepsBetweenDeduplication(StepsBetweenDeduplication());
55 clone->SetStepsBetweenTrims(StepsBetweenTrims());
56
57 clone->ShareOperationsFrom(*this);
58
59 clone->SetSavePosition(GetSavePosition());
60
61 clone->SetSamplingCacheMaxNodes(GetSamplingCacheMaxNodes());
62 if (IsParallelEnabled())
63 clone->EnableParallel(GetThreadCount());
64
65 return clone;
66 }
67
68 static double GetSamplingCost(const std::shared_ptr<Circuits::Circuit<>> &circuit, size_t nrQubitsSampled, size_t samples)
69 {
70 if (nrQubitsSampled == 0)
71 return 0.0;
72 return samples * GetCost(circuit) * exp2(nrQubitsSampled - 1);
73 }
74
75 static double GetCost(const std::shared_ptr<Circuits::Circuit<>> &circuit)
76 {
77 if (!circuit)
78 return 0.0;
79
80 // Conservative branching estimates, not elapsed time: commuting inputs and
81 // deduplication often reduce the actual expansion.
82 double cost = 0.0;
83 double doublingCost = 1;
84
85 // go backwards, the same way as the propagator does, to get the cost of the
86 // operations in the circuit
87
88 for (int pos = static_cast<int>(circuit->size()) - 1; pos >= 0; --pos)
89 {
90 const std::shared_ptr<Circuits::IOperation<>> &op = (*circuit)[pos];
91 cost += GetOpCost(circuit, op, pos) * doublingCost;
92 doublingCost *= GetOpMultiplication(op);
93 }
94
95 // summing up all pauli strings expectations
96 cost += doublingCost;
97
98 return cost;
99 }
100
101 private:
102 static double GetOpCost(const std::shared_ptr<Circuits::Circuit<>> &circuit, const std::shared_ptr<Circuits::IOperation<>> &op, int pos)
103 {
104 if (!circuit || !op || pos < 0 || pos >= static_cast<int>(circuit->size()))
105 return 0.;
106
107 if (op->GetType() != Circuits::OperationType::kGate)
108 {
109 if (op->GetType() == Circuits::OperationType::kMeasurement)
110 {
111 // measurement costs a pauli string propagated down the circuit from the
112 // point of measurement... but then it adds a projector in the circuit
113 // in its place, which means a doubling at that point for subsequent
114 // propagations
115 if (pos == 0)
116 return 1.;
117
118 const auto &prevOp = (*circuit)[pos - 1];
119 return 1. + GetOpCost(circuit, prevOp, pos - 1);
120 }
121 else if (op->GetType() == Circuits::OperationType::kReset)
122 {
123 // a measurement followed by a conditional X gate, assume X half of the
124 // times
125 if (pos == 0)
126 return 1.5;
127 const auto &prevOp = (*circuit)[pos - 1];
128 return 1.5 + GetOpCost(circuit, prevOp, pos - 1);
129 }
130 else if (op->GetType() == Circuits::OperationType::kConditionalGate)
131 {
132 const auto conditionalGate = std::static_pointer_cast<Circuits::ConditionalGate<>>(op);
133 return GetOpCost(circuit, conditionalGate->GetOperation(), pos);
134 }
135 else if (op->GetType() == Circuits::OperationType::kConditionalMeasurement)
136 {
137 const auto conditionalMeasurement = std::static_pointer_cast<Circuits::ConditionalMeasurement<>>(op);
138 return GetOpCost(circuit, conditionalMeasurement->GetOperation(), pos);
139 }
140 return 0.;
141 }
142
143 const auto gate = std::static_pointer_cast<Circuits::IQuantumGate<>>(op);
144
145 switch (gate->GetGateType())
146 {
147 // cliffords
149 [[fallthrough]];
151 [[fallthrough]];
153 return 0.5; // just a sign flip
155 return 1.;
157 return 3.5;
159 return 1.;
161 return 1.5;
163 return 4.;
165 return 3.;
167 return 1.;
169 return 3.5;
171 return 3.;
173 return 3.;
174
175 // non-cliffords
176 // the ones below just rotations, they split in two operators
178 [[fallthrough]];
180 [[fallthrough]];
182 [[fallthrough]];
184 [[fallthrough]];
186 [[fallthrough]];
188 return 2.;
189
191 return 3.; // at most three Pauli outputs
192
194 return 4.;
196 return 4.;
198 [[fallthrough]];
200 return 4.;
202 return 4.;
204 return 4.;
206 return 4.;
207
209 return 8.;
210
212 return 4.;
214 return 4.;
215
216 default:
217 return 1.;
218 }
219
220 return 1.;
221 }
222
223 static double GetOpMultiplication(const std::shared_ptr<Circuits::IOperation<>> &op)
224 {
225 if (!op)
226 return 1.;
227
228 if (op->GetType() != Circuits::OperationType::kGate)
229 {
230 if (op->GetType() == Circuits::OperationType::kMeasurement)
231 {
232 return 2.;
233 }
234 else if (op->GetType() == Circuits::OperationType::kReset)
235 {
236 return 2.;
237 }
238 else if (op->GetType() == Circuits::OperationType::kConditionalGate)
239 {
240 const auto conditionalGate = std::static_pointer_cast<Circuits::ConditionalGate<>>(op);
241 return GetOpMultiplication(conditionalGate->GetOperation());
242 }
243 else if (op->GetType() == Circuits::OperationType::kConditionalMeasurement)
244 {
245 return 2.; // actually it depends on the measurement result
246 }
247 return 1.;
248 }
249
250 const auto gate = std::static_pointer_cast<Circuits::IQuantumGate<>>(op);
251 switch (gate->GetGateType())
252 {
253 // all cliffords retun 1, as they do not increase the number of pauli
254 // strings to propagate
256 [[fallthrough]];
258 [[fallthrough]];
260 [[fallthrough]];
262 [[fallthrough]];
264 [[fallthrough]];
266 [[fallthrough]];
268 [[fallthrough]];
270 [[fallthrough]];
272 [[fallthrough]];
274 [[fallthrough]];
276 [[fallthrough]];
278 [[fallthrough]];
280 return 1.;
281
283 [[fallthrough]];
285 [[fallthrough]];
287 [[fallthrough]];
289 [[fallthrough]];
291 [[fallthrough]];
293 return 2.; // just duplication of the pauli string... I guess this
294 // would be proportional with the number of qubits, but
295 // let's just put a constant for now
296
298 return 3.; // at most three Pauli outputs
299
301 [[fallthrough]];
303 [[fallthrough]];
305 [[fallthrough]];
307 [[fallthrough]];
309 return 4.; // maximum outputs of the native local action
310
312 [[fallthrough]];
314 return 4.;
315
317 return 8.; // includes a nonzero controlled global phase
318
319 // Native three-qubit actions have at most four outputs.
321 return 4.;
323 return 4.;
324
325 default:
326 return 1.;
327 }
328 return 1.;
329 }
330};
331
332} // namespace Simulators
333
334#endif // _QCSIM_PAULI_PROPAGATOR_H
Circuit class for holding the sequence of operations.
Definition Circuit.h:51
The operation interface.
Definition Operations.h:402
std::unique_ptr< QcsimPauliPropagator > Clone() const
static double GetSamplingCost(const std::shared_ptr< Circuits::Circuit<> > &circuit, size_t nrQubitsSampled, size_t samples)
static double GetCost(const std::shared_ptr< Circuits::Circuit<> > &circuit)
void ApplyP(int qubit, double lambda)
@ kConditionalGate
conditional gate, similar with gate, but conditioned on something from 'OperationState'
Definition Operations.h:33
@ kConditionalMeasurement
conditional measurement, similar with measurement, but conditioned on something from 'OperationState'
Definition Operations.h:35
@ kMeasurement
measurement, result in 'OperationState'
Definition Operations.h:31
@ kGate
the usual quantum gate, result stays in simulator's state
Definition Operations.h:30
@ kReset
reset, no result in 'state', just apply measurement, then apply not on all qubits that were measured ...
Definition Operations.h:41
Bounded online routing based on current physical bond dimensions.