Loading lib/mirror_rb/mirror_circuit_rb.cpp +53 −1 Original line number Diff line number Diff line Loading @@ -157,8 +157,60 @@ getLayer(std::shared_ptr<xacc::CompositeInstruction> circuit, int layerId) { } // namespace namespace qcor { std::pair<bool, xacc::HeterogeneousMap> MirrorCircuitValidator::validate( std::shared_ptr<xacc::Accelerator> qpu, std::shared_ptr<qcor::CompositeInstruction> program, xacc::HeterogeneousMap options) { // Some default values int n_trials = 1000; // 10% error allowed... (away from the expected bitstring) double eps = 0.1; int n_shots = 1024; if (options.keyExists<int>("trials")) { n_trials = options.get<int>("trials"); } if (options.keyExists<double>("epsilon")) { eps = options.get<double>("epsilon"); } qpu->updateConfiguration({{"shots", n_shots}}); std::vector<double> trial_success_probs; auto provider = xacc::getIRProvider("quantum"); for (int i = 0; i < n_trials; ++i) { auto [mirror_circuit, expected_result] = qcor::MirrorCircuitValidator::createMirrorCircuit(program); const std::string expectedBitString = [&]() { std::string bitStr; for (const auto &bit : expected_result) { bitStr += std::to_string(bit); } return bitStr; }(); for (size_t qId = 0; qId < mirror_circuit->nPhysicalBits(); ++qId) { mirror_circuit->addInstruction( provider->createInstruction("Measure", {qId})); } auto mc_buffer = xacc::qalloc(mirror_circuit->nPhysicalBits()); qpu->execute(mc_buffer, mirror_circuit->as_xacc()); // mc_buffer->print(); const auto bitStrProb = mc_buffer->computeMeasurementProbability(expectedBitString); trial_success_probs.emplace_back(bitStrProb); } xacc::HeterogeneousMap data; data.insert("trial-success-probabilities", trial_success_probs); const bool pass_fail_result = std::all_of(trial_success_probs.begin(), trial_success_probs.end(), [&eps](double val) { return val > 1.0 - eps; }); return std::make_pair(pass_fail_result, data); } std::pair<std::shared_ptr<CompositeInstruction>, std::vector<bool>> createMirrorCircuit(std::shared_ptr<CompositeInstruction> in_circuit) { MirrorCircuitValidator::createMirrorCircuit(std::shared_ptr<CompositeInstruction> in_circuit) { std::vector<std::shared_ptr<xacc::Instruction>> mirrorCircuit; auto gateProvider = xacc::getService<xacc::IRProvider>("quantum"); Loading lib/mirror_rb/mirror_circuit_rb.hpp +13 −5 Original line number Diff line number Diff line Loading @@ -3,11 +3,19 @@ #include <vector> #include <string> #include <utility> #include "qrt.hpp" // !Temporary: we'll figure out an interface for this later: namespace qcor { class CompositeInstruction; class MirrorCircuitValidator : public BackendValidator { public: virtual const std::string name() const override { return "mirror-rb"; } virtual const std::string description() const override { return ""; } virtual std::pair<bool, xacc::HeterogeneousMap> validate(std::shared_ptr<xacc::Accelerator> qpu, std::shared_ptr<qcor::CompositeInstruction> program, xacc::HeterogeneousMap options) override; // Return the 'mirrored' circuit along with the expected result. std::pair<std::shared_ptr<CompositeInstruction>, std::vector<bool>> static std::pair<std::shared_ptr<CompositeInstruction>, std::vector<bool>> createMirrorCircuit(std::shared_ptr<CompositeInstruction> in_circuit); }; } // namespace qcor lib/mirror_rb/tests/MirrorCircuitTester.cpp +7 −7 Original line number Diff line number Diff line Loading @@ -25,7 +25,7 @@ TEST(MirrorCircuitTester, checkU3Inverse) { const double lambda = random_angle(); circuit->addInstruction(provider->createInstruction( "U", {0}, std::vector<xacc::InstructionParameter>{theta, phi, lambda})); auto [mirror_cir, expected_result] = qcor::createMirrorCircuit( auto [mirror_cir, expected_result] = qcor::MirrorCircuitValidator::createMirrorCircuit( std::make_shared<qcor::CompositeInstruction>(circuit)); EXPECT_EQ(expected_result.size(), 1); EXPECT_EQ(mirror_cir->nInstructions(), 2); Loading Loading @@ -66,7 +66,7 @@ TEST(MirrorCircuitTester, checkMultipleU3) { const double lambda2 = random_angle(); circuit->addInstruction(provider->createInstruction( "U", {1}, std::vector<xacc::InstructionParameter>{theta2, phi2, lambda2})); auto [mirror_cir, expected_result] = qcor::createMirrorCircuit( auto [mirror_cir, expected_result] = qcor::MirrorCircuitValidator::createMirrorCircuit( std::make_shared<qcor::CompositeInstruction>(circuit)); EXPECT_EQ(expected_result.size(), 2); EXPECT_EQ(mirror_cir->nInstructions(), 4); Loading Loading @@ -112,7 +112,7 @@ TEST(MirrorCircuitTester, checkCliffordGates) { circuit->addInstruction(provider->createInstruction("CNOT", {0, 1})); circuit->addInstruction(provider->createInstruction("H", {0})); circuit->addInstruction(provider->createInstruction("H", {1})); auto [mirror_cir, expected_result] = qcor::createMirrorCircuit( auto [mirror_cir, expected_result] = qcor::MirrorCircuitValidator::createMirrorCircuit( std::make_shared<qcor::CompositeInstruction>(circuit)); const std::string expectedBitString = std::to_string(expected_result[0]) + std::to_string(expected_result[1]); Loading Loading @@ -145,17 +145,17 @@ TEST(MirrorCircuitTester, checkDeuteron) { circuit->addInstruction(provider->createInstruction( "Ry", {1}, std::vector<xacc::InstructionParameter>{random_angle()})); circuit->addInstruction(provider->createInstruction("CNOT", {1, 0})); auto [mirror_cir, expected_result] = qcor::createMirrorCircuit( auto [mirror_cir, expected_result] = qcor::MirrorCircuitValidator::createMirrorCircuit( std::make_shared<qcor::CompositeInstruction>(circuit)); std::cout << "Expected: " << expected_result[0] << expected_result[1] << "\n"; std::cout << "HOWDY: \n" << mirror_cir->toString() << "\n"; // std::cout << "Expected: " << expected_result[0] << expected_result[1] << "\n"; // std::cout << "HOWDY: \n" << mirror_cir->toString() << "\n"; auto mirror_circuit = provider->createComposite("test_mirror"); mirror_circuit->addInstructions(mirror_cir->getInstructions()); mirror_circuit->addInstruction(provider->createInstruction("Measure", {0})); mirror_circuit->addInstruction(provider->createInstruction("Measure", {1})); auto mc_buffer = xacc::qalloc(2); accelerator->execute(mc_buffer, mirror_circuit); mc_buffer->print(); // mc_buffer->print(); const std::string expectedBitString = std::to_string(expected_result[0]) + std::to_string(expected_result[1]); EXPECT_EQ(mc_buffer->getMeasurementCounts().size(), 1); Loading runtime/qrt/qrt.cpp +12 −1 Original line number Diff line number Diff line Loading @@ -89,6 +89,17 @@ std::string get_native_code(std::shared_ptr<qcor::CompositeInstruction> program, xacc::HeterogeneousMap options) { return get_qpu()->getNativeCode(program->as_xacc(), options); } std::pair<bool, xacc::HeterogeneousMap> validate_backend_execution(std::shared_ptr<qcor::CompositeInstruction> program, xacc::HeterogeneousMap options) { // FWIW, we only have this method... static const std::string DEFAULT_METHOD = "mirror-rb"; auto validate_program = program ? program : ::quantum::qrt_impl->get_current_program(); auto validator = xacc::getService<qcor::BackendValidator>(DEFAULT_METHOD); return validator->validate(get_qpu(), validate_program, options); } } // namespace internal_compiler } // namespace xacc namespace quantum { Loading runtime/qrt/qrt.hpp +18 −0 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ namespace qcor { using namespace xacc::internal_compiler; namespace xacc { class Accelerator; class AcceleratorBuffer; // class CompositeInstruction; class Instruction; Loading Loading @@ -256,6 +257,13 @@ void execute_pass_manager( std::shared_ptr<qcor::CompositeInstruction> optional_composite = nullptr); std::string get_native_code(std::shared_ptr<qcor::CompositeInstruction> program, xacc::HeterogeneousMap options); // Hook to validate backend execution of a circuit // e.g., via circuit mirror technique // returns a pass/fail bool along with a untyped result data. // options data may include method-specific configurations. std::pair<bool, xacc::HeterogeneousMap> validate_backend_execution( std::shared_ptr<qcor::CompositeInstruction> program = nullptr, xacc::HeterogeneousMap options = {}); } // namespace internal_compiler } // namespace xacc namespace qcor { Loading @@ -280,5 +288,15 @@ protected: std::vector<xacc::internal_compiler::qubit *> m_allocatedQubits; std::shared_ptr<xacc::AcceleratorBuffer> m_buffer; }; // An abstract interface for backend validator class BackendValidator : public xacc::Identifiable { public: // This interface is WIP: we just make it as generic as possible. virtual std::pair<bool, xacc::HeterogeneousMap> validate(std::shared_ptr<xacc::Accelerator> qpu, std::shared_ptr<qcor::CompositeInstruction> program, xacc::HeterogeneousMap options = {}) = 0; }; } // namespace qcor #endif No newline at end of file Loading
lib/mirror_rb/mirror_circuit_rb.cpp +53 −1 Original line number Diff line number Diff line Loading @@ -157,8 +157,60 @@ getLayer(std::shared_ptr<xacc::CompositeInstruction> circuit, int layerId) { } // namespace namespace qcor { std::pair<bool, xacc::HeterogeneousMap> MirrorCircuitValidator::validate( std::shared_ptr<xacc::Accelerator> qpu, std::shared_ptr<qcor::CompositeInstruction> program, xacc::HeterogeneousMap options) { // Some default values int n_trials = 1000; // 10% error allowed... (away from the expected bitstring) double eps = 0.1; int n_shots = 1024; if (options.keyExists<int>("trials")) { n_trials = options.get<int>("trials"); } if (options.keyExists<double>("epsilon")) { eps = options.get<double>("epsilon"); } qpu->updateConfiguration({{"shots", n_shots}}); std::vector<double> trial_success_probs; auto provider = xacc::getIRProvider("quantum"); for (int i = 0; i < n_trials; ++i) { auto [mirror_circuit, expected_result] = qcor::MirrorCircuitValidator::createMirrorCircuit(program); const std::string expectedBitString = [&]() { std::string bitStr; for (const auto &bit : expected_result) { bitStr += std::to_string(bit); } return bitStr; }(); for (size_t qId = 0; qId < mirror_circuit->nPhysicalBits(); ++qId) { mirror_circuit->addInstruction( provider->createInstruction("Measure", {qId})); } auto mc_buffer = xacc::qalloc(mirror_circuit->nPhysicalBits()); qpu->execute(mc_buffer, mirror_circuit->as_xacc()); // mc_buffer->print(); const auto bitStrProb = mc_buffer->computeMeasurementProbability(expectedBitString); trial_success_probs.emplace_back(bitStrProb); } xacc::HeterogeneousMap data; data.insert("trial-success-probabilities", trial_success_probs); const bool pass_fail_result = std::all_of(trial_success_probs.begin(), trial_success_probs.end(), [&eps](double val) { return val > 1.0 - eps; }); return std::make_pair(pass_fail_result, data); } std::pair<std::shared_ptr<CompositeInstruction>, std::vector<bool>> createMirrorCircuit(std::shared_ptr<CompositeInstruction> in_circuit) { MirrorCircuitValidator::createMirrorCircuit(std::shared_ptr<CompositeInstruction> in_circuit) { std::vector<std::shared_ptr<xacc::Instruction>> mirrorCircuit; auto gateProvider = xacc::getService<xacc::IRProvider>("quantum"); Loading
lib/mirror_rb/mirror_circuit_rb.hpp +13 −5 Original line number Diff line number Diff line Loading @@ -3,11 +3,19 @@ #include <vector> #include <string> #include <utility> #include "qrt.hpp" // !Temporary: we'll figure out an interface for this later: namespace qcor { class CompositeInstruction; class MirrorCircuitValidator : public BackendValidator { public: virtual const std::string name() const override { return "mirror-rb"; } virtual const std::string description() const override { return ""; } virtual std::pair<bool, xacc::HeterogeneousMap> validate(std::shared_ptr<xacc::Accelerator> qpu, std::shared_ptr<qcor::CompositeInstruction> program, xacc::HeterogeneousMap options) override; // Return the 'mirrored' circuit along with the expected result. std::pair<std::shared_ptr<CompositeInstruction>, std::vector<bool>> static std::pair<std::shared_ptr<CompositeInstruction>, std::vector<bool>> createMirrorCircuit(std::shared_ptr<CompositeInstruction> in_circuit); }; } // namespace qcor
lib/mirror_rb/tests/MirrorCircuitTester.cpp +7 −7 Original line number Diff line number Diff line Loading @@ -25,7 +25,7 @@ TEST(MirrorCircuitTester, checkU3Inverse) { const double lambda = random_angle(); circuit->addInstruction(provider->createInstruction( "U", {0}, std::vector<xacc::InstructionParameter>{theta, phi, lambda})); auto [mirror_cir, expected_result] = qcor::createMirrorCircuit( auto [mirror_cir, expected_result] = qcor::MirrorCircuitValidator::createMirrorCircuit( std::make_shared<qcor::CompositeInstruction>(circuit)); EXPECT_EQ(expected_result.size(), 1); EXPECT_EQ(mirror_cir->nInstructions(), 2); Loading Loading @@ -66,7 +66,7 @@ TEST(MirrorCircuitTester, checkMultipleU3) { const double lambda2 = random_angle(); circuit->addInstruction(provider->createInstruction( "U", {1}, std::vector<xacc::InstructionParameter>{theta2, phi2, lambda2})); auto [mirror_cir, expected_result] = qcor::createMirrorCircuit( auto [mirror_cir, expected_result] = qcor::MirrorCircuitValidator::createMirrorCircuit( std::make_shared<qcor::CompositeInstruction>(circuit)); EXPECT_EQ(expected_result.size(), 2); EXPECT_EQ(mirror_cir->nInstructions(), 4); Loading Loading @@ -112,7 +112,7 @@ TEST(MirrorCircuitTester, checkCliffordGates) { circuit->addInstruction(provider->createInstruction("CNOT", {0, 1})); circuit->addInstruction(provider->createInstruction("H", {0})); circuit->addInstruction(provider->createInstruction("H", {1})); auto [mirror_cir, expected_result] = qcor::createMirrorCircuit( auto [mirror_cir, expected_result] = qcor::MirrorCircuitValidator::createMirrorCircuit( std::make_shared<qcor::CompositeInstruction>(circuit)); const std::string expectedBitString = std::to_string(expected_result[0]) + std::to_string(expected_result[1]); Loading Loading @@ -145,17 +145,17 @@ TEST(MirrorCircuitTester, checkDeuteron) { circuit->addInstruction(provider->createInstruction( "Ry", {1}, std::vector<xacc::InstructionParameter>{random_angle()})); circuit->addInstruction(provider->createInstruction("CNOT", {1, 0})); auto [mirror_cir, expected_result] = qcor::createMirrorCircuit( auto [mirror_cir, expected_result] = qcor::MirrorCircuitValidator::createMirrorCircuit( std::make_shared<qcor::CompositeInstruction>(circuit)); std::cout << "Expected: " << expected_result[0] << expected_result[1] << "\n"; std::cout << "HOWDY: \n" << mirror_cir->toString() << "\n"; // std::cout << "Expected: " << expected_result[0] << expected_result[1] << "\n"; // std::cout << "HOWDY: \n" << mirror_cir->toString() << "\n"; auto mirror_circuit = provider->createComposite("test_mirror"); mirror_circuit->addInstructions(mirror_cir->getInstructions()); mirror_circuit->addInstruction(provider->createInstruction("Measure", {0})); mirror_circuit->addInstruction(provider->createInstruction("Measure", {1})); auto mc_buffer = xacc::qalloc(2); accelerator->execute(mc_buffer, mirror_circuit); mc_buffer->print(); // mc_buffer->print(); const std::string expectedBitString = std::to_string(expected_result[0]) + std::to_string(expected_result[1]); EXPECT_EQ(mc_buffer->getMeasurementCounts().size(), 1); Loading
runtime/qrt/qrt.cpp +12 −1 Original line number Diff line number Diff line Loading @@ -89,6 +89,17 @@ std::string get_native_code(std::shared_ptr<qcor::CompositeInstruction> program, xacc::HeterogeneousMap options) { return get_qpu()->getNativeCode(program->as_xacc(), options); } std::pair<bool, xacc::HeterogeneousMap> validate_backend_execution(std::shared_ptr<qcor::CompositeInstruction> program, xacc::HeterogeneousMap options) { // FWIW, we only have this method... static const std::string DEFAULT_METHOD = "mirror-rb"; auto validate_program = program ? program : ::quantum::qrt_impl->get_current_program(); auto validator = xacc::getService<qcor::BackendValidator>(DEFAULT_METHOD); return validator->validate(get_qpu(), validate_program, options); } } // namespace internal_compiler } // namespace xacc namespace quantum { Loading
runtime/qrt/qrt.hpp +18 −0 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ namespace qcor { using namespace xacc::internal_compiler; namespace xacc { class Accelerator; class AcceleratorBuffer; // class CompositeInstruction; class Instruction; Loading Loading @@ -256,6 +257,13 @@ void execute_pass_manager( std::shared_ptr<qcor::CompositeInstruction> optional_composite = nullptr); std::string get_native_code(std::shared_ptr<qcor::CompositeInstruction> program, xacc::HeterogeneousMap options); // Hook to validate backend execution of a circuit // e.g., via circuit mirror technique // returns a pass/fail bool along with a untyped result data. // options data may include method-specific configurations. std::pair<bool, xacc::HeterogeneousMap> validate_backend_execution( std::shared_ptr<qcor::CompositeInstruction> program = nullptr, xacc::HeterogeneousMap options = {}); } // namespace internal_compiler } // namespace xacc namespace qcor { Loading @@ -280,5 +288,15 @@ protected: std::vector<xacc::internal_compiler::qubit *> m_allocatedQubits; std::shared_ptr<xacc::AcceleratorBuffer> m_buffer; }; // An abstract interface for backend validator class BackendValidator : public xacc::Identifiable { public: // This interface is WIP: we just make it as generic as possible. virtual std::pair<bool, xacc::HeterogeneousMap> validate(std::shared_ptr<xacc::Accelerator> qpu, std::shared_ptr<qcor::CompositeInstruction> program, xacc::HeterogeneousMap options = {}) = 0; }; } // namespace qcor #endif No newline at end of file