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

Added a simple QAOA example



Signed-off-by: default avatarThien Nguyen <nguyentm@ornl.gov>
parent 0fb48177
Loading
Loading
Loading
Loading
+63 −0
Original line number Diff line number Diff line
#include "qcor.hpp"
#include <random>

// Use QAOA algorithm to solve a QUBO problem
// QUBO function:
// y = -5x1 - 3x2 - 8x3 - 6x4 + 4x1x2 + 8x1x3 + 2x2x3 + 10x3x4
// Adapted from https://docs.entropicalabs.io/qaoa/notebooks/6_solvingqubowithqaoa
// Instructions:
// Compile: qcor -o qaoa -qpu qpp qaoa_demo.cpp 
// Run: ./qaoa
int main(int argc, char **argv) {
  // Create corresponding QUBO Hamiltonian (cost Observable)
  auto observable = qcor::createObservable(
      "-5.0 - 0.5 Z0 - 1.0 Z2 + 0.5 Z3 + 1.0 Z0 Z1 + 2.0 Z0 Z2 + 0.5 Z1 Z2 + 2.5 Z2 Z3");
  
  // Allocate 4 qubits (number of variables)
  auto q = qalloc(4);
  
  // QAOA 'p' steps:
  const int nbSteps = 6;
  // We have 4 params for the mixer Hamiltonian terms (one for each qubit)
  // and 7 terms for the above cost Hamiltonian.
  // i.e. 11 params/step.
  const int nbParams = nbSteps*11;
  // We need to seed the 'nlopt' optimizer with random numbers
  // to prevent it from being stuck.
  std::vector<double> initialParams;
  std::random_device rd;  
  std::mt19937 gen(rd()); 
  std::uniform_real_distribution<> dis(-2.0, 2.0);
  // Init random parameters
  for (int i = 0; i < nbParams; ++i) {
    initialParams.emplace_back(dis(gen));
  } 
  
  // Create the Optimizer
  auto optimizer = qcor::createOptimizer("nlopt", xacc::HeterogeneousMap{ 
    std::make_pair("initial-parameters", initialParams),
      // Scale the number of iters by the number of params 
      // to guarantee convergence.
      std::make_pair("nlopt-maxeval", nbParams*100)
  });

  auto algorithm = qcor::createAlgorithm("QAOA", {
                        std::make_pair("optimizer", optimizer),
                        std::make_pair("observable", observable),
                        std::make_pair("accelerator", get_qpu()),
                        // number of time steps (p) param
                        std::make_pair("steps", nbSteps)
                      });

  // Call taskInitiate, kick off QAOA optimization run 
  // on the backend (Async call).
  auto handle = qcor::taskInitiate(algorithm, q);

  // Go do other work...

  // Query results when ready.
  auto results = qcor::sync(handle);

  // Print the optimal value.
  printf("<Min QUBO> = %f\n", results.opt_val);
}
+27 −0
Original line number Diff line number Diff line
@@ -55,6 +55,20 @@ std::shared_ptr<xacc::Observable> createObservable(const char *repr) {
  return xacc::quantum::getObservable("pauli", std::string(repr));
}

std::shared_ptr<xacc::Algorithm> createAlgorithm(const char *type, HeterogeneousMap &&options) {
  if (!xacc::isInitialized())
    xacc::internal_compiler::compiler_InitializeXACC();
  
  auto algorithm = xacc::getAlgorithm(type);
  const bool initOk = algorithm->initialize(options);

  if (!initOk) {
    std::cout << "Algorithm '" << type << "' initialization failed!\n";
  }

  return algorithm;
}

std::shared_ptr<xacc::CompositeInstruction> compile(const std::string &src) {
  return xacc::getCompiler("xasm")->compile(src)->getComposites()[0];
}
@@ -101,4 +115,17 @@ Handle taskInitiate(std::shared_ptr<ObjectiveFunction> objective,
  });
}

Handle taskInitiate(const std::shared_ptr<Algorithm>& algorithm,
                    xacc::internal_compiler::qreg& qubitReg) {
  return std::async(std::launch::async, [&]() -> ResultsBuffer {
    auto buffer = xacc::as_shared_ptr(qubitReg.results());
    algorithm->execute(buffer);
    ResultsBuffer rb;
    rb.q_buffer = qubitReg;
    rb.opt_params = (*buffer)["opt-params"].as<std::vector<double>>();
    rb.opt_val = (*buffer)["opt-val"].as<double>();
    return rb;
  });
}

} // namespace qcor
 No newline at end of file
+11 −0
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@
#include "CompositeInstruction.hpp"
#include "Observable.hpp"
#include "Optimizer.hpp"
#include "Algorithm.hpp"

#include "qalloc"
#include "xacc_internal_compiler.hpp"
@@ -21,6 +22,7 @@ using OptFunction = xacc::OptFunction;
using HeterogeneousMap = xacc::HeterogeneousMap;
using Observable = xacc::Observable;
using Optimizer = xacc::Optimizer;
using Algorithm = xacc::Algorithm;

class ResultsBuffer {
public:
@@ -233,6 +235,10 @@ createOptimizer(const char *type, HeterogeneousMap &&options = {});
// Create an observable from a string representation
std::shared_ptr<Observable> createObservable(const char *repr);

// Create the desired Algorithm
std::shared_ptr<Algorithm>
createAlgorithm(const char *type, HeterogeneousMap &&options = {});

std::shared_ptr<ObjectiveFunction> createObjectiveFunction(
    const char *obj_name, std::shared_ptr<xacc::CompositeInstruction> kernel,
    std::shared_ptr<Observable> observable, HeterogeneousMap &&options = {}) {
@@ -286,6 +292,11 @@ Handle taskInitiate(std::shared_ptr<ObjectiveFunction> objective,
      },
      nParameters);
}

// Execute an algorithm on the qubit register.
Handle taskInitiate(const std::shared_ptr<Algorithm>& algorithm,
                    xacc::internal_compiler::qreg& qubitReg);

} // namespace qcor

#endif