Maestro 0.3.11
Unified interface for quantum circuit simulation
Loading...
Searching...
No Matches
MaestroExe.cpp
Go to the documentation of this file.
1#include <algorithm>
2#include <boost/program_options.hpp>
3#include <iostream>
4#include <optional>
5
6#include <fstream>
7#include <iostream>
8#include <stdio.h>
9#include <stdlib.h>
10
12#include "Simulator.hpp"
13
14static std::string _get_env_var(const char *envs)
15{
16 std::string val;
17
18#ifdef _WIN32
19 size_t sz;
20
21 getenv_s(&sz, NULL, 0, envs);
22 if (sz == 0 || sz > 49)
23 return val;
24
25 char buf[50];
26
27 getenv_s(&sz, buf, sz, envs);
28
29 buf[49] = 0;
30 val = buf;
31#else
32 const char *env = getenv(envs);
33 if (env)
34 val = env;
35#endif
36
37 return val;
38}
39
40// CLI selection uses the historical option numbers; the native enum omits
41// Aer entries in builds without Aer, so translate at the ABI boundary.
42static int BackendId(int option)
43{
44 using Backend = Simulators::SimulatorType;
45 switch (option)
46 {
47#ifndef NO_QISKIT_AER
48 case 0:
49 return static_cast<int>(Backend::kQiskitAer);
50 case 2:
51 return static_cast<int>(Backend::kCompositeQiskitAer);
52#endif
53 case 1:
54 return static_cast<int>(Backend::kQCSim);
55 case 3:
56 return static_cast<int>(Backend::kCompositeQCSim);
57 case 4:
58 return static_cast<int>(Backend::kGpuSim);
59 case 5:
60 return static_cast<int>(Backend::kQuestSim);
61 default:
62 throw std::invalid_argument("Requested backend is unavailable in this build");
63 }
64}
65
66// An absent gateFusion leaves the backend default in place.
67static std::string GetConfigJson(int num_shots, int maxBondDim, std::optional<bool> gateFusion)
68{
69 std::string config = "{\"shots\": ";
70
71 config += std::to_string(num_shots);
72
73 if (maxBondDim != 0)
74 config += ", \"matrix_product_state_max_bond_dimension\": " + std::to_string(maxBondDim);
75
76 if (gateFusion)
77 config += *gateFusion ? ", \"gate_fusion\": true" : ", \"gate_fusion\": false";
78
79 return config + "}";
80}
81
82int main(int argc, char **argv)
83{
84 try
85 {
86 std::ios_base::sync_with_stdio(false);
87 std::cin.tie(nullptr);
88
89 boost::program_options::options_description desc("Allowed options");
90 desc.add_options()("help,h", "Print a help description")("version,v", "Print version information")(
91 "nrqubits,n", boost::program_options::value<int>(), "Specify the number of qubits")("shots,s", boost::program_options::value<int>(),
92 "Specify the number of shots for execution")(
93 "gate-fusion", boost::program_options::value<bool>(),
94 "Force Maestro gate fusion on or off on supported simulators "
95 "(default: on, except for small CPU statevectors and density "
96 "matrices)")("mbd,m", boost::program_options::value<int>(), "Specify the max bond dimension for the MPS simulator")(
97 "simulator,r", boost::program_options::value<std::string>(),
98 "Simulator type, either aer, qcsim, composite_aer, composite_qcsim, "
99 "gpu "
100 "or quest")("type,t", boost::program_options::value<std::string>(),
101 "Simulation type, either statevector, mps, stabilizer, "
102 "tensor or pauli_propagation")("file,f", boost::program_options::value<std::string>(), "Provide a qasm file for execution")(
103 "output,o", boost::program_options::value<std::string>(), "Specify the json output file")("expectations,e",
104 "Compute expectation values of observables");
105
106 boost::program_options::positional_options_description pos_desc;
107 pos_desc.add("file", 1);
108 pos_desc.add("output", 1);
109
110 boost::program_options::variables_map vars;
111 try
112 {
113 boost::program_options::basic_command_line_parser<char> parser(argc, argv);
114 parser.positional(pos_desc);
115 parser.options(desc);
116
117 boost::program_options::store(parser.run(), vars);
118 boost::program_options::notify(vars);
119 }
120 catch (boost::program_options::error &e)
121 {
122 std::cerr << "ERROR: " << e.what() << "\n";
123 return 1;
124 }
125
126 if (vars.count("version"))
127 std::cout << "Version 1.0\n";
128
129 if (vars.count("help"))
130 std::cout << desc << "\n";
131
132 int nrQubits = 64;
133 int nrShots = 1;
134 int maxBondDim = 0;
135#ifdef NO_QISKIT_AER
136 int simulatorType = 1;
137#else
138 int simulatorType = 0;
139#endif
140 int simulationType = 0;
141
142 if (vars.count("nrqubits"))
143 {
144 nrQubits = vars["nrqubits"].as<int>();
145
146 const std::string qstr = _get_env_var("maestro_nrqubits");
147 if (!qstr.empty())
148 {
149 const int nrQubitsMax = std::stoi(qstr);
150 if (nrQubits > nrQubitsMax)
151 nrQubits = nrQubitsMax;
152 }
153 }
154 else
155 {
156 const std::string qstr = _get_env_var("maestro_nrqubits");
157 if (!qstr.empty())
158 nrQubits = std::stoi(qstr);
159 }
160
161 if (nrQubits <= 0)
162 {
163 std::cerr << "Invalid number of qubits" << std::endl;
164 return 2;
165 }
166
167 if (vars.count("shots"))
168 {
169 nrShots = vars["shots"].as<int>();
170
171 const std::string sstr = _get_env_var("maestro_shots");
172 if (!sstr.empty())
173 {
174 const int nrShotsMax = std::stoi(sstr);
175 if (nrShots > nrShotsMax)
176 nrShots = nrShotsMax;
177 }
178 }
179 else
180 {
181 const std::string sstr = _get_env_var("maestro_shots");
182 if (!sstr.empty())
183 nrShots = std::stoi(sstr);
184 }
185
186 if (nrShots <= 0)
187 nrShots = 1;
188
189 if (vars.count("mbd"))
190 {
191 maxBondDim = vars["mbd"].as<int>();
192
193 const std::string mbds = _get_env_var("maestro_max_bond_dim");
194 if (!mbds.empty())
195 {
196 const int mbdMax = std::stoi(mbds);
197 if (maxBondDim > mbdMax || (maxBondDim <= 0 && mbdMax > 0))
198 maxBondDim = mbdMax;
199 }
200 }
201 else
202 {
203 const std::string mbds = _get_env_var("maestro_max_bond_dim");
204 if (!mbds.empty())
205 maxBondDim = std::stoi(mbds);
206 }
207
208 if (maxBondDim < 0)
209 maxBondDim = 0;
210
211 std::string stype;
212 if (vars.count("simulator"))
213 stype = vars["simulator"].as<std::string>();
214 else
215 stype = _get_env_var("maestro_simulator_type");
216
217 if (!stype.empty())
218 {
219 std::transform(stype.begin(), stype.end(), stype.begin(), [](unsigned char chr) { return std::tolower(chr); });
220
221 if (stype == "aer")
222 simulatorType = 0;
223 else if (stype == "qcsim")
224 simulatorType = 1;
225 else if (stype == "composite_aer" || stype == "pblocks_aer")
226 simulatorType = 2;
227 else if (stype == "composite_qcsim" || stype == "pblocks_qcsim")
228 simulatorType = 3;
229 else if (stype == "gpu")
230 simulatorType = 4;
231 else if (stype == "quest")
232 simulatorType = 5;
233 else
234 simulatorType = 1000; // something big, so it won't be set
235 }
236
237 if (simulatorType != 2 && simulatorType != 3)
238 {
239 stype.clear();
240 if (vars.count("type"))
241 stype = vars["type"].as<std::string>();
242 else
243 stype = _get_env_var("maestro_simulation_type");
244
245 if (!stype.empty())
246 {
247 std::transform(stype.begin(), stype.end(), stype.begin(), [](unsigned char chr) { return std::tolower(chr); });
248
249 if (stype == "statevector" || stype == "sv")
250 simulationType = 0;
251 else if (stype == "mps" || stype == "matrix_product_state")
252 simulationType = 1;
253 else if (stype == "stabilizer" || stype == "clifford")
254 simulationType = 2;
255 else if (stype == "tensor" || stype == "tensor_network" || stype == "tn")
256 simulationType = 3;
257 else if (stype == "pauli_propagation" || stype == "pauli" || stype == "pprop")
258 simulationType = 4;
259 else
260 simulationType = 1000;
261 }
262 }
263 else
264 simulationType = 0; // statevector for composite
265
266 if (vars.count("file") == 0)
267 {
268 std::cerr << "No qasm file provided" << std::endl;
269 return 3;
270 }
271
272 const std::string qasmFileName = vars["file"].as<std::string>();
273 if (qasmFileName.empty())
274 {
275 std::cerr << "Invalid qasm file" << std::endl;
276 return 4;
277 }
278
279 std::ifstream file(qasmFileName);
280 if (!file.is_open())
281 {
282 std::cerr << "Couldn't read the qasm file" << std::endl;
283 return 5;
284 }
285
286 std::string qasmStr((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
287 if (qasmStr.empty())
288 {
289 std::cerr << "Empty qasm" << std::endl;
290 return 6;
291 }
292
293 bool computeExpectations = false;
294 if (vars.count("expectations"))
295 computeExpectations = true;
296 else
297 {
298 const std::string estr = _get_env_var("maestro_expectations");
299 if (!estr.empty())
300 computeExpectations = (std::stoi(estr) != 0);
301 }
302
303 // after getting all params and so on, execute:
304
305 SimpleSimulator simulator;
306 if (!simulator.Init(
307#if defined(_WIN32)
308 "maestro.dll"
309#else
310 "libmaestro.so"
311
312#endif
313 ))
314 {
315 std::cerr << "Couldn't load maestro library" << std::endl;
316 return 6;
317 }
318
319 simulator.CreateSimpleSimulator(nrQubits);
320
321 if (simulatorType < 2) // qcsim or aer
322 {
323 if (simulationType < 4 || (simulatorType == 1 && simulationType == 4)) // qcsim also supports pauli propagation
324 simulator.RemoveAllOptimizationSimulatorsAndAdd(BackendId(simulatorType), static_cast<int>(simulationType));
325 else
326 {
327 simulator.RemoveAllOptimizationSimulatorsAndAdd(BackendId(simulatorType), 0);
328 simulator.AddOptimizationSimulator(BackendId(simulatorType), 1);
329 simulator.AddOptimizationSimulator(BackendId(simulatorType), 2);
330 }
331 }
332 else if (simulatorType < 4) // composite, ignore exec type and set statevector
333 {
334 simulator.RemoveAllOptimizationSimulatorsAndAdd(BackendId(simulatorType), 0);
335 }
336 else if (simulatorType == 4) // gpu
337 {
338 if (simulationType < 2 || simulationType == 3 || simulationType == 4) // statevector or mps, or tensor or pauli propagation
339 simulator.RemoveAllOptimizationSimulatorsAndAdd(BackendId(simulatorType), static_cast<int>(simulationType));
340 else // other types are not supported yet on gpu, set statevector
341 simulator.RemoveAllOptimizationSimulatorsAndAdd(BackendId(simulatorType), 0);
342 }
343 else if (simulatorType == 5) // quest, only supports statevector for now
344 {
345 simulator.RemoveAllOptimizationSimulatorsAndAdd(BackendId(simulatorType), 0);
346 }
347
348 static std::string configStr =
349 GetConfigJson(nrShots, maxBondDim, vars.count("gate-fusion") ? std::optional<bool>(vars["gate-fusion"].as<bool>()) : std::nullopt);
350
351 std::string result;
352 if (!qasmStr.empty())
353 {
354 if (computeExpectations)
355 {
356 std::string obsFileName = qasmFileName;
357 size_t lastDot = obsFileName.find_last_of(".");
358 if (lastDot != std::string::npos)
359 {
360 obsFileName = obsFileName.substr(0, lastDot);
361 }
362 obsFileName += ".obs";
363
364 std::ifstream obsFile(obsFileName);
365 if (obsFile.is_open())
366 {
367 std::string obsStr((std::istreambuf_iterator<char>(obsFile)), std::istreambuf_iterator<char>());
368 obsStr.erase(std::remove(obsStr.begin(), obsStr.end(), '\n'), obsStr.end());
369 obsStr.erase(std::remove(obsStr.begin(), obsStr.end(), '\r'), obsStr.end());
370 if (!obsStr.empty())
371 {
372 char *res = simulator.SimpleEstimate(qasmStr.c_str(), obsStr.c_str(), configStr.c_str());
373 if (res)
374 {
375 result = res;
376 simulator.FreeResult(res);
377 }
378 }
379 else
380 {
381 std::cerr << "Empty .obs file" << std::endl;
382 }
383 }
384 else
385 {
386 std::cerr << "Couldn't read the .obs file: " << obsFileName << std::endl;
387 }
388 }
389 else
390 {
391 char *res = simulator.SimpleExecute(qasmStr.c_str(), configStr.c_str());
392 if (res)
393 {
394 result = res;
395 simulator.FreeResult(res);
396 }
397 }
398 }
399
400 // depending on params, write it on stdout or in a file
401
402 if (vars.count("output"))
403 {
404 const std::string fileName = vars["output"].as<std::string>();
405 if (!fileName.empty())
406 {
407 std::ofstream outFile(fileName);
408 outFile << result;
409 }
410 }
411 else
412 std::cout << result << std::endl;
413 }
414 catch (std::exception &e)
415 {
416 std::cerr << "ERROR: " << e.what() << std::endl;
417 return 7;
418 }
419 catch (...)
420 {
421 std::cerr << "Exception of unknown type!" << std::endl;
422 return 8;
423 }
424
425 return 0;
426}
int main(int argc, char **argv)
static int BackendId(int option)
static std::string _get_env_var(const char *envs)
static std::string GetConfigJson(int num_shots, int maxBondDim, std::optional< bool > gateFusion)
bool AddOptimizationSimulator(int simType, int simExecType)
Definition Simulator.hpp:47
char * SimpleEstimate(const char *jsonCircuit, const char *observableStr, const char *jsonConfig)
Definition Simulator.hpp:60
unsigned long int CreateSimpleSimulator(int nrQubits) override
Definition Simulator.hpp:29
char * SimpleExecute(const char *jsonCircuit, const char *jsonConfig)
Definition Simulator.hpp:55
void FreeResult(char *result) override
Definition Simulator.hpp:65
bool Init(const char *libName) noexcept override
Definition Simulator.hpp:21
bool RemoveAllOptimizationSimulatorsAndAdd(int simType, int simExecType)
Definition Simulator.hpp:39
SimulatorType
The type of simulator.
Definition State.h:79