@@ -40,27 +40,52 @@ HybridSchrodingerFeynmanSimulator<Config>::getNDecisions(qc::Qubit splitQubit) {
40
40
if (op->getType () == qc::Barrier) {
41
41
continue ;
42
42
}
43
- if (op->isStandardOperation ()) {
44
- bool targetInLowerSlice = false ;
45
- bool targetInUpperSlice = false ;
46
- bool controlInLowerSlice = false ;
47
- bool controlInUpperSlice = false ;
48
- for (const auto & target : op->getTargets ()) {
49
- targetInLowerSlice = targetInLowerSlice || target < splitQubit;
50
- targetInUpperSlice = targetInUpperSlice || target >= splitQubit;
43
+
44
+ assert (op->isStandardOperation ());
45
+
46
+ bool targetInLowerSlice = false ;
47
+ bool targetInUpperSlice = false ;
48
+ bool controlInLowerSlice = false ;
49
+ size_t nControlsInLowerSlice = 0 ;
50
+ bool controlInUpperSlice = false ;
51
+ size_t nControlsInUpperSlice = 0 ;
52
+ for (const auto & target : op->getTargets ()) {
53
+ targetInLowerSlice = targetInLowerSlice || target < splitQubit;
54
+ targetInUpperSlice = targetInUpperSlice || target >= splitQubit;
55
+ }
56
+ for (const auto & control : op->getControls ()) {
57
+ if (control.qubit < splitQubit) {
58
+ controlInLowerSlice = true ;
59
+ nControlsInLowerSlice++;
60
+ } else {
61
+ controlInUpperSlice = true ;
62
+ nControlsInUpperSlice++;
51
63
}
52
- for (const auto & control : op->getControls ()) {
53
- controlInLowerSlice = controlInLowerSlice || control.qubit < splitQubit;
54
- controlInUpperSlice =
55
- controlInUpperSlice || control.qubit >= splitQubit;
64
+ }
65
+
66
+ if (targetInLowerSlice && targetInUpperSlice) {
67
+ throw std::invalid_argument (
68
+ " Multiple targets spread across the cut through the circuit are not "
69
+ " supported at the moment as this would require actually computing "
70
+ " the Schmidt decomposition of the gate being cut." );
71
+ }
72
+
73
+ if (targetInLowerSlice && controlInUpperSlice) {
74
+ if (nControlsInUpperSlice > 1 ) {
75
+ throw std::invalid_argument (
76
+ " Multiple controls in the control part of the gate being cut are "
77
+ " not supported at the moment as this would require actually "
78
+ " computing the Schmidt decomposition of the gate being cut." );
56
79
}
57
- if ((targetInLowerSlice && controlInUpperSlice) ||
58
- (targetInUpperSlice && controlInLowerSlice)) {
59
- ndecisions++;
80
+ ++ndecisions;
81
+ } else if (targetInUpperSlice && controlInLowerSlice) {
82
+ if (nControlsInLowerSlice > 1 ) {
83
+ throw std::invalid_argument (
84
+ " Multiple controls in the control part of the gate being cut are "
85
+ " not supported at the moment as this would require actually "
86
+ " computing the Schmidt decomposition of the gate being cut." );
60
87
}
61
- } else {
62
- throw std::invalid_argument (
63
- " Only StandardOperations are supported for now." );
88
+ ++ndecisions;
64
89
}
65
90
}
66
91
return ndecisions;
@@ -77,11 +102,10 @@ qc::VectorDD HybridSchrodingerFeynmanSimulator<Config>::simulateSlicing(
77
102
controls);
78
103
79
104
for (const auto & op : *CircuitSimulator<Config>::qc) {
80
- if (op->isUnitary ()) {
81
- [[maybe_unused]] auto l = lower.apply (sliceDD, op);
82
- [[maybe_unused]] auto u = upper.apply (sliceDD, op);
83
- assert (l == u);
84
- }
105
+ assert (op->isUnitary ());
106
+ [[maybe_unused]] auto l = lower.apply (sliceDD, op);
107
+ [[maybe_unused]] auto u = upper.apply (sliceDD, op);
108
+ assert (l == u);
85
109
sliceDD->garbageCollect ();
86
110
}
87
111
@@ -97,76 +121,67 @@ bool HybridSchrodingerFeynmanSimulator<Config>::Slice::apply(
97
121
std::unique_ptr<dd::Package<Config>>& sliceDD,
98
122
const std::unique_ptr<qc::Operation>& op) {
99
123
bool isSplitOp = false ;
100
- if (dynamic_cast <qc::StandardOperation*>(op.get ()) !=
101
- nullptr ) { // TODO change control and target if wrong direction
102
- qc::Targets opTargets{};
103
- qc::Controls opControls{};
104
-
105
- // check targets
106
- bool targetInSplit = false ;
107
- bool targetInOtherSplit = false ;
108
- for (const auto & target : op->getTargets ()) {
109
- if (start <= target && target <= end) {
110
- opTargets.push_back (target);
111
- targetInSplit = true ;
112
- } else {
113
- targetInOtherSplit = true ;
114
- }
115
- }
116
-
117
- if (targetInSplit && targetInOtherSplit && !op->getControls ().empty ()) {
118
- throw std::invalid_argument (" Multiple Targets that are in different "
119
- " slices are not supported at the moment" );
124
+ assert (op->isStandardOperation ());
125
+ qc::Targets opTargets{};
126
+ qc::Controls opControls{};
127
+
128
+ // check targets
129
+ bool targetInSplit = false ;
130
+ bool targetInOtherSplit = false ;
131
+ for (const auto & target : op->getTargets ()) {
132
+ if (start <= target && target <= end) {
133
+ opTargets.emplace_back (target);
134
+ targetInSplit = true ;
135
+ } else {
136
+ targetInOtherSplit = true ;
120
137
}
138
+ }
121
139
122
- // check controls
123
- for (const auto & control : op->getControls ()) {
124
- if (start <= control.qubit && control.qubit <= end) {
125
- opControls.emplace (control.qubit , control.type );
126
- } else { // other controls are set to the corresponding value
127
- if (targetInSplit) {
128
- isSplitOp = true ;
129
- const bool nextControl = getNextControl ();
130
- if ((control.type == qc::Control::Type::Pos &&
131
- !nextControl) || // break if control is not activated
132
- (control.type == qc::Control::Type::Neg && nextControl)) {
133
- nDecisionsExecuted++;
134
- return true ;
135
- }
140
+ // Ensured in the getNDecisions function
141
+ assert (!(targetInSplit && targetInOtherSplit));
142
+
143
+ // check controls
144
+ for (const auto & control : op->getControls ()) {
145
+ if (start <= control.qubit && control.qubit <= end) {
146
+ opControls.emplace (control);
147
+ } else { // other controls are set to the corresponding value
148
+ if (targetInSplit) {
149
+ isSplitOp = true ;
150
+ const bool nextControl = getNextControl ();
151
+ // break if control is not activated
152
+ if ((control.type == qc::Control::Type::Pos && !nextControl) ||
153
+ (control.type == qc::Control::Type::Neg && nextControl)) {
154
+ nDecisionsExecuted++;
155
+ return true ;
136
156
}
137
157
}
138
158
}
159
+ }
139
160
140
- if (targetInOtherSplit && !opControls.empty ()) { // control slice for split
141
- if (opControls.size () > 1 ) {
142
- throw std::invalid_argument (
143
- " Multiple controls in control slice of operation are not supported "
144
- " at the moment" );
145
- }
161
+ if (targetInOtherSplit && !opControls.empty ()) { // control slice for split
162
+ // Ensured in the getNDecisions function
163
+ assert (opControls.size () == 1 );
146
164
147
- isSplitOp = true ;
148
- const bool control = getNextControl ();
149
- for (const auto & c : opControls) {
150
- auto tmp = edge;
151
- edge = sliceDD->deleteEdge (
152
- edge, static_cast <dd::Qubit>(c.qubit ),
153
- control != (c.type == qc::Control::Type::Neg) ? 0 : 1 );
154
- // TODO incref and decref could be integrated in delete edge
155
- sliceDD->incRef (edge);
156
- sliceDD->decRef (tmp);
157
- }
158
- } else if (targetInSplit) { // target slice for split or operation in split
159
- const auto & param = op->getParameter ();
160
- qc::StandardOperation newOp (opControls, opTargets, op->getType (), param);
165
+ isSplitOp = true ;
166
+ const bool control = getNextControl ();
167
+ for (const auto & c : opControls) {
161
168
auto tmp = edge;
162
- edge = sliceDD->multiply (dd::getDD (&newOp, *sliceDD), edge);
169
+ edge = sliceDD->deleteEdge (
170
+ edge, static_cast <dd::Qubit>(c.qubit ),
171
+ control != (c.type == qc::Control::Type::Neg) ? 0 : 1 );
172
+ // TODO incref and decref could be integrated in delete edge
163
173
sliceDD->incRef (edge);
164
174
sliceDD->decRef (tmp);
165
175
}
166
- } else {
167
- throw std::invalid_argument (
168
- " Only StandardOperations are supported for now." );
176
+ } else if (targetInSplit) { // target slice for split or operation in split
177
+ const auto & param = op->getParameter ();
178
+ qc::StandardOperation newOp (opControls, opTargets, op->getType (), param);
179
+ auto tmp = edge;
180
+ edge = sliceDD->multiply (dd::getDD (&newOp, *sliceDD), edge);
181
+ sliceDD->incRef (edge);
182
+ sliceDD->decRef (tmp);
169
183
}
184
+
170
185
if (isSplitOp) {
171
186
nDecisionsExecuted++;
172
187
}
@@ -176,6 +191,20 @@ bool HybridSchrodingerFeynmanSimulator<Config>::Slice::apply(
176
191
template <class Config >
177
192
std::map<std::string, std::size_t >
178
193
HybridSchrodingerFeynmanSimulator<Config>::simulate(std::size_t shots) {
194
+ if (CircuitSimulator<Config>::qc->isDynamic ()) {
195
+ throw std::invalid_argument (
196
+ " Dynamic quantum circuits containing mid-circuit measurements, resets, "
197
+ " or classical control flow are not supported by this simulator." );
198
+ }
199
+
200
+ for (const auto & op : *CircuitSimulator<Config>::qc) {
201
+ if (!op->isStandardOperation ()) {
202
+ throw std::invalid_argument (" This simulator only supports regular gates "
203
+ " (`StandardOperation`). \" " +
204
+ op->getName () + " \" is not supported." );
205
+ }
206
+ }
207
+
179
208
auto nqubits = CircuitSimulator<Config>::getNumberOfQubits ();
180
209
auto splitQubit = static_cast <qc::Qubit>(nqubits / 2 );
181
210
if (mode == Mode::DD) {
0 commit comments