Maestro 0.3.11
Unified interface for quantum circuit simulation
Loading...
Searching...
No Matches
Remapper.h
Go to the documentation of this file.
1
14
15#pragma once
16
17#ifndef _REMAPPER_H_
18#define _REMAPPER_H_
19
20#include "../Circuit/Circuit.h"
23#include "../Network/Network.h"
24
25namespace Distribution
26{
27
39
48template <typename Time = Types::time_type> class IRemapper : public std::enable_shared_from_this<IRemapper<Time>>
49{
50 public:
57 virtual ~IRemapper() = default;
58
69 virtual std::shared_ptr<Circuits::Circuit<Time>> Remap(const std::shared_ptr<Network::INetwork<Time>> &network,
70 const std::shared_ptr<Circuits::Circuit<Time>> &circuit) = 0;
71
81 virtual unsigned int GetNumberOfOperationsForDistribution() const = 0;
82
90 virtual unsigned int GetNumberOfDistributions() const = 0;
91
99 std::shared_ptr<IRemapper<Time>> getptr()
100 {
101 return std::enable_shared_from_this<IRemapper<Time>>::shared_from_this();
102 }
103
111 virtual RemapperType GetType() const = 0;
112
125 static bool IsNonLocalOperation(const std::shared_ptr<Circuits::IOperation<Time>> &op, const std::shared_ptr<Network::INetwork<Time>> &network)
126 {
127 if (op->NeedsEntanglementForDistribution())
128 {
129 auto qubits = op->AffectedQubits();
130
131 if (qubits.size() >= 2) // there should be no 3 qubit gates at this point, though
132 {
133 const size_t ctrlQubit = qubits[0];
134 const size_t targetQubit = qubits[1];
135
136 if (!network->AreQubitsOnSameHost(ctrlQubit, targetQubit))
137 return true;
138 }
139 }
140
141 return false;
142 }
143
161 virtual std::shared_ptr<Circuits::Circuit<Time>> SplitCompositeOperations(const std::shared_ptr<Network::INetwork<Time>> &network,
162 const std::shared_ptr<Circuits::Circuit<Time>> &distCirc) const
163 {
164 // Measurement, RandomGen, ConditionalMeasurement, ConditionalRandomGen,
165 // Reset... might involve qubits/classical bits that are on different hosts
166 // - split them so they could be executed in any order independently on top
167 // of that, conditional gates might need classical bits from different
168 // hosts, handle that as well in the future such classical bits transfers
169 // might be simulated using 'resources' involving queues or something like
170 // that to simulate the classical network
171
172 std::shared_ptr<Circuits::Circuit<Time>> newDistributedCircuit = std::make_shared<Circuits::Circuit<Time>>();
173
174 for (const auto &op : distCirc->GetOperations())
175 {
176 // the measurement, conditional measurement and reset are split based on
177 // the qubits they operate on the others based on the classical bits
178 // involved
179
180 switch (op->GetType())
181 {
183 std::unordered_map<size_t, std::vector<std::pair<Types::qubit_t, size_t>>> bits;
184 const auto qbits = op->AffectedQubits();
185 const auto cbits = op->AffectedBits();
186 const auto measurement = std::static_pointer_cast<Circuits::MeasurementOperation<Time>>(op);
187 std::unordered_map<size_t, std::vector<Circuits::ReadoutRates>> rates;
188
189 for (size_t q = 0; q < qbits.size(); ++q)
190 {
191 const size_t host = network->GetHostIdForAnyQubit(qbits[q]);
192 bits[host].push_back({qbits[q], cbits[q]});
193 if (measurement->HasReadout())
194 rates[host].push_back(measurement->GetReadout()[q]);
195 }
196
197 for (const auto &hostQubits : bits)
198 {
199 auto split = std::make_shared<Circuits::MeasurementOperation<Time>>(hostQubits.second);
200 if (measurement->HasReadout())
201 split->SetReadout(std::move(rates[hostQubits.first]));
202 newDistributedCircuit->AddOperation(split);
203 }
204 }
205 break;
207 std::unordered_map<size_t, std::vector<std::pair<Types::qubit_t, size_t>>> bits;
208 auto condOp = std::static_pointer_cast<Circuits::ConditionalMeasurement<Time>>(op);
209
210 const auto qbits = condOp->GetOperation()->AffectedQubits();
211 const auto cbits = condOp->GetOperation()->AffectedBits();
212 const auto measurement = std::static_pointer_cast<Circuits::MeasurementOperation<Time>>(condOp->GetOperation());
213 std::unordered_map<size_t, std::vector<Circuits::ReadoutRates>> rates;
214
215 for (size_t q = 0; q < qbits.size(); ++q)
216 {
217 const size_t host = network->GetHostIdForAnyQubit(qbits[q]);
218 bits[host].push_back({qbits[q], cbits[q]});
219 if (measurement->HasReadout())
220 rates[host].push_back(measurement->GetReadout()[q]);
221 }
222
223 for (const auto &hostQubits : bits)
224 {
225 auto measOp = std::make_shared<Circuits::MeasurementOperation<Time>>(hostQubits.second);
226 if (measurement->HasReadout())
227 measOp->SetReadout(std::move(rates[hostQubits.first]));
228 newDistributedCircuit->AddOperation(
229 std::make_shared<Circuits::ConditionalMeasurement<Time>>(measOp,
230 condOp->GetCondition())); // condition stays the same
231 }
232 }
233 break;
235 std::unordered_map<size_t, Types::qubits_vector> bits;
236 const auto qbits = op->AffectedQubits();
237 const auto reset = std::static_pointer_cast<Circuits::Reset<Time>>(op);
238 const auto &resetTargets = reset->GetResetTargets();
239 std::unordered_map<size_t, std::vector<bool>> targets;
240
241 for (size_t q = 0; q < qbits.size(); ++q)
242 {
243 const size_t host = network->GetHostIdForAnyQubit(qbits[q]);
244 bits[host].emplace_back(qbits[q]);
245 if (!resetTargets.empty())
246 targets[host].push_back(q < resetTargets.size() && resetTargets[q]);
247 }
248
249 for (const auto &hostQubits : bits)
250 newDistributedCircuit->AddOperation(
251 std::make_shared<Circuits::Reset<Time>>(hostQubits.second, reset->GetDelay(), targets[hostQubits.first]));
252 }
253 break;
255 std::unordered_map<size_t, std::vector<size_t>> bits;
256 const std::vector<size_t> cbits = op->AffectedBits();
257
258 for (const size_t c : cbits)
259 {
260 const size_t host = network->GetHostIdForClassicalBit(c);
261 bits[host].emplace_back(c);
262 }
263
264 for (const auto &hostQubits : bits)
265 newDistributedCircuit->AddOperation(std::make_shared<Circuits::Random<Time>>(hostQubits.second));
266 }
267 break;
269 std::unordered_map<size_t, std::vector<size_t>> bits;
270 // split by operation (as in random gen), not by condition, that
271 // should stay whole and be dealt with accordingly if classical
272 // network simulation details are to be done
273 auto condOp = std::static_pointer_cast<Circuits::ConditionalRandomGen<Time>>(op);
274 const std::vector<size_t> cbits = condOp->GetOperation()->AffectedBits();
275
276 for (const size_t c : cbits)
277 {
278 const size_t host = network->GetHostIdForClassicalBit(c);
279 bits[host].emplace_back(c);
280 }
281
282 for (const auto &hostQubits : bits)
283 {
284 auto randomOp = std::make_shared<Circuits::Random<Time>>(hostQubits.second);
285 newDistributedCircuit->AddOperation(
286 std::make_shared<Circuits::ConditionalRandomGen<Time>>(randomOp,
287 condOp->GetCondition())); // condition stays the same
288 }
289 }
290 break;
291 default:
292 newDistributedCircuit->AddOperation(op);
293 break;
294 }
295 }
296
297 return newDistributedCircuit;
298 }
299};
300
301} // namespace Distribution
302
303#endif // !_REMAPPER_H_
Circuit class for holding the sequence of operations.
Definition Circuit.h:51
A conditional measurement.
A conditional random generator.
The operation interface.
Definition Operations.h:402
Random operation.
Definition RandomOp.h:35
Reset operation class.
Definition Reset.h:34
Remapper abstract class.
Definition Remapper.h:49
virtual ~IRemapper()=default
Default virtual destructor.
static bool IsNonLocalOperation(const std::shared_ptr< Circuits::IOperation< Time > > &op, const std::shared_ptr< Network::INetwork< Time > > &network)
Checks if an operation is non local.
Definition Remapper.h:125
std::shared_ptr< IRemapper< Time > > getptr()
Get a shared pointer to this object.
Definition Remapper.h:99
virtual unsigned int GetNumberOfDistributions() const =0
Get the number of distribution circuits for the last remapped circuit.
virtual std::shared_ptr< Circuits::Circuit< Time > > Remap(const std::shared_ptr< Network::INetwork< Time > > &network, const std::shared_ptr< Circuits::Circuit< Time > > &circuit)=0
Remap the circuit.
virtual unsigned int GetNumberOfOperationsForDistribution() const =0
Get the number of operations for distribution.
virtual RemapperType GetType() const =0
Returns the type of the remapper.
virtual std::shared_ptr< Circuits::Circuit< Time > > SplitCompositeOperations(const std::shared_ptr< Network::INetwork< Time > > &network, const std::shared_ptr< Circuits::Circuit< Time > > &distCirc) const
Split composite operations.
Definition Remapper.h:161
The network interface.
Definition Network.h:60
@ kRandomGen
random classical bit generator, result in 'OperationState'
Definition Operations.h:32
@ kConditionalRandomGen
conditional random generator, similar with random gen, but conditioned on something from 'OperationSt...
Definition Operations.h:38
@ 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
@ kReset
reset, no result in 'state', just apply measurement, then apply not on all qubits that were measured ...
Definition Operations.h:41
RemapperType
The type of remapper to use.
Definition Remapper.h:33
@ kLayersRemapper
Remapper that uses intermediate layers for conversion.
Definition Remapper.h:34
@ kGreedyDirectRemapper
Remapper that uses a greedy algorithm for conversion, avoiding conversion to intermediate layers.
Definition Remapper.h:35