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

Work on sycamore demo



Update QCOR decompose_unitary to respect the underlying qubits of the register.
i.e., we can now decompose unitary matrices to gates acting on a subset of the master register.

Signed-off-by: default avatarThien Nguyen <nguyentm@ornl.gov>
parent b71f2259
Loading
Loading
Loading
Loading
+41 −0
Original line number Diff line number Diff line
// Fermionic Simulation gate:
// FSimGate(θ, φ) = 
// [[1, 0, 0, 0],
//  [0, a, b, 0],
//  [0, b, a, 0],
//  [0, 0, 0, c]]
// where:
// a = cos(theta)
// b = -i·sin(theta)
// c = exp(-i·phi)
__qpu__ void FSimGate(qubit q0, qubit q1, double theta, double phi) {
  std::vector<qubit> qubits{q0, q1};
  qreg q(qubits);
  auto a = std::cos(theta);
  auto b = std::complex<double>{ 0.0, -std::sin(theta)};
  auto c = std::exp(std::complex<double>{ 0.0, -phi});
  // Use QCOR unitaty decomposition (KAK)
  decompose {
    // Create the unitary matrix
    UnitaryMatrix fsim_mat = UnitaryMatrix::Identity(4, 4);
    fsim_mat(1, 1) = a;
    fsim_mat(1, 2) = b;
    fsim_mat(2, 1) = b;
    fsim_mat(2, 2) = a;
    fsim_mat(3, 3) = c;
  }(q, kak);
}


// TODO: Sycamore experiment...
__qpu__ void sycamore(qreg q) {
  FSimGate(q[1], q[4], 1.5157741664070026, 0.5567125777724111);
  FSimGate(q[3], q[7], 1.5177580142210796, 0.49481085782254924);
}

int main() {
  auto q = qalloc(53);
  sycamore::print_kernel(q);
}

+2 −0
Original line number Diff line number Diff line
@@ -185,6 +185,8 @@ std::string run_token_collector(
          {0,
           [&](const std::string arg) {
             code_ss << "auto decompose_buffer_name = " << arg << ".name();\n";
             // Cache the decompose buffer as well
             code_ss << "auto decompose_buffer = " << arg << ";\n";
           }},
          {1,
           [&](const std::string arg) {
+2 −2
Original line number Diff line number Diff line
@@ -95,11 +95,11 @@ void UnitaryTokenCollector::collect(clang::Preprocessor &PP,
  if (optimizer_provided) {
    ss << "auto decomposed_program = "
          "__internal__::decompose_unitary(decompose_algo_name, "
       << var_name << ", decompose_buffer_name, decompose_optimizer);\n";
       << var_name << ", decompose_buffer, decompose_optimizer);\n";
  } else {
    ss << "auto decomposed_program = "
          "__internal__::decompose_unitary(decompose_algo_name, "
       << var_name << ", decompose_buffer_name);\n";
       << var_name << ", decompose_buffer);\n";
  }
  // Add the qfast decomp and hook up to the qrt program.

+16 −3
Original line number Diff line number Diff line
@@ -68,7 +68,7 @@ std::shared_ptr<qcor::IRProvider> get_provider() {

std::shared_ptr<qcor::CompositeInstruction> decompose_unitary(
    const std::string algorithm, UnitaryMatrix &mat,
    const std::string buffer_name) {
    qreg& buffer) {
  std::string local_algorithm = algorithm;
  if (local_algorithm == "z_y_z") local_algorithm = "z-y-z";

@@ -84,12 +84,19 @@ std::shared_ptr<qcor::CompositeInstruction> decompose_unitary(
    xacc::error("Could not decompose unitary with " + local_algorithm);
  }

  // Map the decomposed circuit to the qubits in the register.
  std::vector<std::size_t> bitMap;
  for (int i = 0; i < buffer.size(); ++i) {
    bitMap.emplace_back(buffer[i].second);
  }
  for (auto inst : decomposed->getInstructions()) {
    std::vector<std::string> buffer_names;
    for (int i = 0; i < inst->nRequiredBits(); i++) {
      const std::string buffer_name = buffer[inst->bits()[i]].first;
      buffer_names.push_back(buffer_name);
    }
    inst->setBufferNames(buffer_names);
    inst->mapBits(bitMap);
  }

  return decomposed;
@@ -97,10 +104,14 @@ std::shared_ptr<qcor::CompositeInstruction> decompose_unitary(

std::shared_ptr<qcor::CompositeInstruction> decompose_unitary(
    const std::string algorithm, UnitaryMatrix &mat,
    const std::string buffer_name, std::shared_ptr<xacc::Optimizer> optimizer) {
    qreg& buffer, std::shared_ptr<xacc::Optimizer> optimizer) {
  auto tmp = xacc::getService<xacc::Instruction>(algorithm);
  auto decomposed = std::dynamic_pointer_cast<CompositeInstruction>(tmp);

  // Map the decomposed circuit to the qubits in the register.
  std::vector<std::size_t> bitMap;
  for (int i = 0; i < buffer.size(); ++i) {
    bitMap.emplace_back(buffer[i].second);
  }
  // default Adam
  const bool expandOk = decomposed->expand(
      {std::make_pair("unitary", mat), std::make_pair("optimizer", optimizer)});
@@ -112,9 +123,11 @@ std::shared_ptr<qcor::CompositeInstruction> decompose_unitary(
  for (auto inst : decomposed->getInstructions()) {
    std::vector<std::string> buffer_names;
    for (int i = 0; i < inst->nRequiredBits(); i++) {
      const std::string buffer_name = buffer[inst->bits()[i]].first;
      buffer_names.push_back(buffer_name);
    }
    inst->setBufferNames(buffer_names);
    inst->mapBits(bitMap);
  }

  return decomposed;
+6 −6
Original line number Diff line number Diff line
@@ -204,15 +204,15 @@ std::shared_ptr<qcor::IRProvider> get_provider();

// Decompose the given unitary matrix with the specified decomposition
// algorithm.
std::shared_ptr<qcor::CompositeInstruction> decompose_unitary(
    const std::string algorithm, UnitaryMatrix &mat,
    const std::string buffer_name);
std::shared_ptr<qcor::CompositeInstruction>
decompose_unitary(const std::string algorithm, UnitaryMatrix &mat,
                  qreg &buffer);

// Decompose the given unitary matrix with the specified decomposition algorithm
// and optimizer
std::shared_ptr<qcor::CompositeInstruction> decompose_unitary(
    const std::string algorithm, UnitaryMatrix &mat,
    const std::string buffer_name, std::shared_ptr<xacc::Optimizer> optimizer);
std::shared_ptr<qcor::CompositeInstruction>
decompose_unitary(const std::string algorithm, UnitaryMatrix &mat, qreg &buffer,
                  std::shared_ptr<xacc::Optimizer> optimizer);

// Utility for calling a Functor via mapping a tuple of Args to
// a sequence of Args...