Commit ef7e3a54 authored by Nguyen, Thien Minh's avatar Nguyen, Thien Minh
Browse files

Added a runtime hook to connect use the mirror circuit validation



Signed-off-by: default avatarThien Nguyen <nguyentm@ornl.gov>
parent fd2bca29
Loading
Loading
Loading
Loading
+53 −1
Original line number Diff line number Diff line
@@ -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");

+13 −5
Original line number Diff line number Diff line
@@ -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
+7 −7
Original line number Diff line number Diff line
@@ -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);
@@ -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);
@@ -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]);
@@ -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);
+12 −1
Original line number Diff line number Diff line
@@ -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 {
+18 −0
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@ namespace qcor {
using namespace xacc::internal_compiler;

namespace xacc {
class Accelerator;
class AcceleratorBuffer;
// class CompositeInstruction;
class Instruction;
@@ -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 {
@@ -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