-
Notifications
You must be signed in to change notification settings - Fork 26
/
noise_aware.cpp
150 lines (120 loc) · 6.98 KB
/
noise_aware.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#include "DeterministicNoiseSimulator.hpp"
#include "StochasticNoiseSimulator.hpp"
#include "cxxopts.hpp"
#include "nlohmann/json.hpp"
#include <chrono>
#include <iomanip>
#include <iostream>
#include <memory>
#include <string>
namespace nl = nlohmann;
int main(int argc, char** argv) { // NOLINT(bugprone-exception-escape)
cxxopts::Options options("MQT DDSIM", "see for more information https://www.cda.cit.tum.de/");
// clang-format off
options.add_options()
("h,help", "produce help message")
("seed", "seed for random number generator (default zero is possibly directly used as seed!)", cxxopts::value<std::size_t>()->default_value("0"))
("pm", "print measurements")
("ps", "print simulation stats (applied gates, sim. time, and maximal size of the DD)")
("verbose", "Causes some simulators to print additional information to STDERR")
("simulate_file", "simulate a quantum circuit given by file (detection by the file extension)", cxxopts::value<std::string>())
("step_fidelity", "target fidelity for each approximation run (>=1 = disable approximation)", cxxopts::value<double>()->default_value("1.0"))
("steps", "number of approximation steps", cxxopts::value<unsigned int>()->default_value("1"))
// Parameters for noise aware simulation
("noise_effects", "Noise effects (A (=amplitude damping),D (=depolarization),P (=phase flip)) in the form of a character string describing the noise effects", cxxopts::value<std::string>()->default_value("APD"))
("noise_prob", "Probability for applying noise.", cxxopts::value<double>()->default_value("0.001"))
("noise_prob_t1", "Probability for applying amplitude damping noise (default:2 x noise_prob)", cxxopts::value<double>())
("noise_prob_multi", "Noise factor for multi qubit operations", cxxopts::value<double>()->default_value("2"))
("use_density_matrix_simulator", "Set this flag to use the density matrix simulator. Per default the stochastic simulator is used")
("shots", "Specify the number of shots that shall be generated", cxxopts::value<std::size_t>()->default_value("0"))
; // end arguments list
// clang-format on
auto vm = options.parse(argc, argv);
if (vm.count("help") > 0) {
std::cout << options.help();
std::exit(0);
}
std::unique_ptr<qc::QuantumComputation> quantumComputation;
if (vm.count("simulate_file") > 0) {
const std::string fname = vm["simulate_file"].as<std::string>();
quantumComputation = std::make_unique<qc::QuantumComputation>(fname);
} else {
std::cerr << "Did not find anything to simulate. See help below.\n"
<< options.help() << "\n";
std::exit(1);
}
if (quantumComputation && quantumComputation->getNqubits() > 100) {
std::clog << "[WARNING] Quantum computation contains quite many qubits. You're jumping into the deep end.\n";
}
std::optional<double> noiseProbT1{};
if (vm.count("noise_prob_t1") > 0) {
noiseProbT1 = vm["noise_prob_t1"].as<double>();
}
if (vm.count("use_density_matrix_simulator") == 0) {
const auto approxSteps = vm["steps"].as<unsigned int>();
const auto stepFidelity = vm["step_fidelity"].as<double>();
const ApproximationInfo approxInfo{stepFidelity, approxSteps, ApproximationInfo::FidelityDriven};
// Using stochastic simulator
auto ddsim = std::make_unique<StochasticNoiseSimulator>(std::move(quantumComputation),
approxInfo,
vm["seed"].as<std::size_t>(),
vm["noise_effects"].as<std::string>(),
vm["noise_prob"].as<double>(),
noiseProbT1,
vm["noise_prob_multi"].as<double>());
auto t1 = std::chrono::steady_clock::now();
const auto measurementResults = ddsim->simulate(vm["shots"].as<size_t>());
auto t2 = std::chrono::steady_clock::now();
const std::chrono::duration<float> durationSimulation = t2 - t1;
nl::json outputObj;
if (vm.count("ps") > 0) {
outputObj["statistics"] = {
{"simulation_time", durationSimulation.count()},
{"benchmark", ddsim->getName()},
{"n_qubits", +ddsim->getNumberOfQubits()},
{"applied_gates", ddsim->getNumberOfOps()},
{"seed", ddsim->getSeed()},
};
for (const auto& [key, value]: ddsim->additionalStatistics()) {
outputObj["statistics"][key] = value;
}
}
if (vm.count("pm") > 0) {
outputObj["measurement_results"] = measurementResults;
}
std::cout << std::setw(2) << outputObj << "\n";
} else if (vm.count("use_density_matrix_simulator") > 0) {
// Using deterministic simulator
auto ddsim = std::make_unique<DeterministicNoiseSimulator>(std::move(quantumComputation),
ApproximationInfo{},
vm["seed"].as<std::size_t>(),
vm["noise_effects"].as<std::string>(),
vm["noise_prob"].as<double>(),
noiseProbT1,
vm["noise_prob_multi"].as<double>());
auto t1 = std::chrono::steady_clock::now();
const auto measurementResults = ddsim->simulate(vm["shots"].as<size_t>());
auto t2 = std::chrono::steady_clock::now();
const std::chrono::duration<float> durationSimulation = t2 - t1;
nl::json outputObj;
if (vm.count("ps") > 0) {
outputObj["statistics"] = {
{"simulation_time", durationSimulation.count()},
{"benchmark", ddsim->getName()},
{"n_qubits", ddsim->getNumberOfQubits()},
{"applied_gates", ddsim->getNumberOfOps()},
{"max_matrix_nodes", ddsim->getMaxMatrixNodeCount()},
{"active_matrix_nodes", ddsim->getMatrixActiveNodeCount()},
{"seed", ddsim->getSeed()},
{"active_nodes", ddsim->getActiveNodeCount()},
};
for (const auto& item: ddsim->additionalStatistics()) {
outputObj["statistics"][item.first] = item.second;
}
}
if (vm.count("pm") > 0) {
outputObj["measurement_results"] = measurementResults;
}
std::cout << std::setw(2) << outputObj << "\n";
}
}