Commit c4d48630 authored by Mccaskey, Alex's avatar Mccaskey, Alex
Browse files

add circuit optimizer input to qite quasimo workflow, add demo example for c++ and python

parent 695ba19d
Loading
Loading
Loading
Loading
Loading
+35 −0
Original line number Diff line number Diff line
#include "qcor_qsim.hpp"

__qpu__ void state_prep(qreg q) { X(q[0]); }

int main(int argc, char** argv) {
  set_verbose(true);
  using namespace QuaSiMo;

  // Create the qsearch IR Transformation
  auto qsearch_optimizer = createTransformation("qsearch");

  // Create the Hamiltonian
  auto observable = -2.1433 * X(0) * X(1) - 2.1433 * Y(0) * Y(1) +
                    .21829 * Z(0) - 6.125 * Z(1) + 5.907;

  // We'll run with 5 steps and .1 step size
  const int nbSteps = 5;
  const double stepSize = 0.1;

  // Create the model (2 qubits, 0 variational params in above state_prep)
  // and QITE workflow
  auto problemModel = ModelFactory::createModel(state_prep, &observable, 2, 0);
  auto workflow =
      getWorkflow("qite", {{"steps", nbSteps},
                           {"step-size", stepSize},
                           {"circuit-optimizer", qsearch_optimizer}});

  // Execute
  auto result = workflow->execute(problemModel);

  // Get the energy and final circuit
  const auto energy = result.get<double>("energy");
  auto finalCircuit = result.getPointerLike<CompositeInstruction>("circuit");
  printf("\n%s\nEnergy=%f\n", finalCircuit->toString().c_str(), energy);
}
 No newline at end of file
+8 −3
Original line number Diff line number Diff line
#include "partial_tomography.hpp"

#include "qsim_utils.hpp"
#include "xacc.hpp"

@@ -10,7 +11,11 @@ double PartialTomoObjFuncEval::evaluate(
      xacc::as_shared_ptr(target_operator), state_prep);
  // Run the pass manager (optimization + placement)
  executePassManager(subKernels);
  auto tmp_buffer = qalloc(state_prep->nPhysicalBits());
  // Set qreg size to the bigger of target_operator bits or state prep physical bits
  auto tmp_buffer =
      qalloc(target_operator->nBits() > state_prep->nPhysicalBits()
                 ? target_operator->nBits()
                 : state_prep->nPhysicalBits());
  xacc::internal_compiler::execute(tmp_buffer.results(), subKernels);
  const double energy = tmp_buffer.weighted_sum(target_operator);
  return energy;
+63 −34
Original line number Diff line number Diff line
#include "qite.hpp"

#include "qsim_utils.hpp"
#include "xacc.hpp"
#include "xacc_service.hpp"
#include "qsim_utils.hpp"

namespace {
// Helper to generate all permutation of Pauli observables:
@@ -51,12 +52,28 @@ bool QiteWorkflow::initialize(const HeterogeneousMap &params) {
    std::cout << "'step-size' is required.\n";
    initializeOk = false;
  }

  if (params.keyExists<std::shared_ptr<xacc::IRTransformation>>(
          "circuit-optimizer")) {
    extra_circuit_optimizers.push_back(
        params.get<std::shared_ptr<xacc::IRTransformation>>(
            "circuit-optimizer"));
  } else if (params.keyExists<
                 std::vector<std::shared_ptr<xacc::IRTransformation>>>(
                 "circuit-optimizers")) {
    auto opts =
        params.get<std::vector<std::shared_ptr<xacc::IRTransformation>>>(
            "circuit-optimizers");
    extra_circuit_optimizers.insert(extra_circuit_optimizers.end(),
                                    opts.begin(), opts.end());
  }

  config_params = params;
  return initializeOk;
}

QuantumSimulationResult
QiteWorkflow::execute(const QuantumSimulationModel &model) {
QuantumSimulationResult QiteWorkflow::execute(
    const QuantumSimulationModel &model) {
  const auto nbSteps = config_params.get<int>("steps");
  const auto stepSize = config_params.get<double>("step-size");
  auto qite = xacc::getService<xacc::Algorithm>("qite");
@@ -73,9 +90,9 @@ QiteWorkflow::execute(const QuantumSimulationModel &model) {
  std::vector<double> energyAtStep;

  auto constructPropagateCircuit =
      [](const std::vector<std::shared_ptr<Observable>> &in_Aops,
         const std::shared_ptr<KernelFunctor> &in_statePrep, double in_stepSize)
      -> std::shared_ptr<CompositeInstruction> {
      [this, &acc](const std::vector<std::shared_ptr<Observable>> &in_Aops,
             const std::shared_ptr<KernelFunctor> &in_statePrep,
             double in_stepSize) -> std::shared_ptr<CompositeInstruction> {
    auto gateRegistry = xacc::getService<xacc::IRProvider>("quantum");
    auto propagateKernel = gateRegistry->createComposite("statePropCircuit");

@@ -93,11 +110,17 @@ QiteWorkflow::execute(const QuantumSimulationModel &model) {
      // i.e. regular evolution which approximates the imaginary time evolution.
      for (const auto &term : aObs->getNonIdentitySubTerms()) {
        auto method = xacc::getService<AnsatzGenerator>("trotter");
        auto trotterCir = method->create_ansatz(term.get(), {{"dt", 0.5 * in_stepSize}}).circuit;
        auto trotterCir =
            method->create_ansatz(term.get(), {{"dt", 0.5 * in_stepSize}})
                .circuit;
        propagateKernel->addInstructions(trotterCir->getInstructions());
      }
    }

    for (auto &opt : extra_circuit_optimizers) {
      opt->apply(propagateKernel, acc, config_params);
    }

    // std::cout << "Progagated kernel:\n" << propagateKernel->toString() <<
    // "\n";
    return propagateKernel;
@@ -106,7 +129,8 @@ QiteWorkflow::execute(const QuantumSimulationModel &model) {
  // Cost function (observable) evaluator
  auto calcCurrentEnergy = [&]() {
    // Trotter kernel up to this point
    auto propagateKernel = constructPropagateCircuit(approxOps, model.user_defined_ansatz, stepSize);
    auto propagateKernel = constructPropagateCircuit(
        approxOps, model.user_defined_ansatz, stepSize);
    evaluator = getEvaluator(model.observable, config_params);
    return evaluator->evaluate(propagateKernel);
  };
@@ -114,7 +138,8 @@ QiteWorkflow::execute(const QuantumSimulationModel &model) {
  // Initial energy
  energyAtStep.emplace_back(calcCurrentEnergy());
  const auto pauliOps = generatePauliPermutation(nbQubits);
  const auto evaluateTomographyAtStep = [&](const std::shared_ptr<CompositeInstruction>& in_kernel) {
  const auto evaluateTomographyAtStep =
      [&](const std::shared_ptr<CompositeInstruction> &in_kernel) {
        // Observe the kernels using the various Pauli
        // operators to calculate S and b.
        std::vector<double> sigmaExpectation(pauliOps.size());
@@ -126,7 +151,8 @@ QiteWorkflow::execute(const QuantumSimulationModel &model) {
          tomoObservable->fromString(pauliObsStr);
          assert(tomoObservable->getSubTerms().size() == 1);
          assert(tomoObservable->getNonIdentitySubTerms().size() == 1);
      auto temp_evaluator = getEvaluator(tomoObservable.get(), config_params);
          auto temp_evaluator =
              getEvaluator(tomoObservable.get(), config_params);
          sigmaExpectation[i] = temp_evaluator->evaluate(in_kernel);
        }
        return sigmaExpectation;
@@ -135,13 +161,16 @@ QiteWorkflow::execute(const QuantumSimulationModel &model) {
  // Main QITE time-stepping loop:
  for (int i = 0; i < nbSteps; ++i) {
    // Propagates the state via Trotter steps:
    auto kernel = constructPropagateCircuit(approxOps, model.user_defined_ansatz, stepSize);
    const std::vector<double> sigmaExpectation = evaluateTomographyAtStep(kernel);
    auto kernel = constructPropagateCircuit(
        approxOps, model.user_defined_ansatz, stepSize);
    const std::vector<double> sigmaExpectation =
        evaluateTomographyAtStep(kernel);
    auto tmp_buffer = qalloc(nbQubits);
    auto normVal = qite->calculate(
        "approximate-ops", xacc::as_shared_ptr(tmp_buffer.results()),
        {{"pauli-ops", pauliOps}, {"pauli-ops-exp-val", sigmaExpectation}});
    const std::string AopsStr = tmp_buffer.results()->getInformation("Aops-str").as<std::string>();
    const std::string AopsStr =
        tmp_buffer.results()->getInformation("Aops-str").as<std::string>();
    auto new_approx_ops = createObservable(AopsStr);
    approxOps.emplace_back(new_approx_ops);
    energyAtStep.emplace_back(calcCurrentEnergy());
+3 −0
Original line number Diff line number Diff line
@@ -4,6 +4,9 @@
namespace qcor {
namespace QuaSiMo {
class QiteWorkflow : public QuantumSimulationWorkflow {
protected:
  std::vector<std::shared_ptr<xacc::IRTransformation>> extra_circuit_optimizers;
  
public:
  virtual bool initialize(const HeterogeneousMap &params) override;
  virtual QuantumSimulationResult
+34 −4
Original line number Diff line number Diff line
#include <gtest/gtest.h>

#include "qcor.hpp"
#include "qcor_qsim.hpp"
#include "xacc.hpp"
#include <gtest/gtest.h>

TEST(QiteWorkflowTester, checkSimple) {
  using namespace qcor;
@@ -10,8 +11,8 @@ TEST(QiteWorkflowTester, checkSimple) {
  const int nbSteps = 25;
  const double stepSize = 0.1;
  auto problemModel = QuaSiMo::ModelFactory::createModel(&observable);
  auto workflow =
      QuaSiMo::getWorkflow("qite", {{"steps", nbSteps}, {"step-size", stepSize}});
  auto workflow = QuaSiMo::getWorkflow(
      "qite", {{"steps", nbSteps}, {"step-size", stepSize}});
  auto result = workflow->execute(problemModel);
  const auto energy = result.get<double>("energy");
  const auto energyAtStep = result.get<std::vector<double>>("exp-vals");
@@ -20,10 +21,39 @@ TEST(QiteWorkflowTester, checkSimple) {
  }
  // Minimal Energy = -1
  EXPECT_NEAR(energy, -1.0, 1e-2);
  auto finalCircuit = result.getPointerLike<xacc::CompositeInstruction>("circuit");
  auto finalCircuit =
      result.getPointerLike<xacc::CompositeInstruction>("circuit");
  std::cout << "HOWDY:\n" << finalCircuit->toString() << "\n";
}

// TEST(QiteWorkflowTester, checkDeuteronH2) {
//   using namespace qcor;
//   xacc::set_verbose(true);

//   auto compiler = xacc::getCompiler("xasm");
//   auto ir = compiler->compile(R"(__qpu__ void f(qbit q) { X(q[0]); })", nullptr);
//   auto x = ir->getComposite("f");

//   auto observable = -2.1433 * X(0) * X(1) - 2.1433 * Y(0) * Y(1) +
//                     .21829 * Z(0) - 6.125 * Z(1) + 5.907;
//   xacc::internal_compiler::qpu = xacc::getAccelerator("qpp");
//   const int nbSteps = 5;
//   const double stepSize = 0.1;
//   auto problemModel = QuaSiMo::ModelFactory::createModel(x, &observable);
//   auto workflow = QuaSiMo::getWorkflow(
//       "qite", {{"steps", nbSteps}, {"step-size", stepSize}, {"circuit-optimizer", xacc::getIRTransformation("qsearch")}});
//   auto result = workflow->execute(problemModel);
//   const auto energy = result.get<double>("energy");
//   const auto energyAtStep = result.get<std::vector<double>>("exp-vals");
//   for (const auto &val : energyAtStep) {
//     std::cout << val << "\n";
//   }
//   // Minimal Energy = -1
//   // EXPECT_NEAR(energy, -1.0, 1e-2);
//   // auto finalCircuit =
//   // result.getPointerLike<xacc::CompositeInstruction>("circuit"); std::cout <<
//   // "HOWDY:\n" << finalCircuit->toString() << "\n";
// }
int main(int argc, char **argv) {
  xacc::Initialize();
  ::testing::InitGoogleTest(&argc, argv);
Loading