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

Code clean up and added an example



Signed-off-by: Nguyen, Thien Minh's avatarThien Nguyen <nguyentm@ornl.gov>
parent d9541363
......@@ -32,3 +32,6 @@ target_link_libraries(rotoselect PRIVATE xacc xacc-quantum-gate)
add_executable(nah_ucc3 nah_ucc3_psi4.cpp)
target_link_libraries(nah_ucc3 PRIVATE xacc xacc-quantum-gate)
add_executable(qaoa_qubo solve_qubo_with_qaoa.cpp)
target_link_libraries(qaoa_qubo PRIVATE xacc xacc-quantum-gate)
/*******************************************************************************
* Copyright (c) 2020 UT-Battelle, LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompanies this
* distribution. The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution
*License is available at https://eclipse.org/org/documents/edl-v10.php
*
* Contributors:
* Thien Nguyen - initial API and implementation
*******************************************************************************/
#include "xacc.hpp"
#include "xacc_observable.hpp"
#include "xacc_service.hpp"
#include <random>
// Use XACC built-in QAOA 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
int main(int argc, char **argv) {
xacc::Initialize(argc, argv);
// Use the Qpp simulator as the accelerator
auto acc = xacc::getAccelerator("qpp");
auto buffer = xacc::qalloc(4);
// The corresponding QUBO Hamiltonian is:
auto observable = xacc::quantum::getObservable(
"pauli",
std::string("-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"));
const int nbSteps = 12;
const int nbParams = nbSteps*11;
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));
}
auto optimizer = xacc::getOptimizer("nlopt",
xacc::HeterogeneousMap {
std::make_pair("initial-parameters", initialParams),
std::make_pair("nlopt-maxeval", 1000) });
auto qaoa = xacc::getService<xacc::Algorithm>("QAOA");
const bool initOk = qaoa->initialize({
std::make_pair("accelerator", acc),
std::make_pair("optimizer", optimizer),
std::make_pair("observable", observable),
// number of time steps (p) param
std::make_pair("steps", nbSteps)
});
qaoa->execute(buffer);
// Expected -11 (correct answer is 1001)
// y(1001) = -5x1 - 3x2 - 8x3 - 6x4 + 4x1x2 + 8x1x3 + 2x2x3 + 10x3x4
// = -11
std::cout << "Min QUBO: " << (*buffer)["opt-val"].as<double>() << "\n";
}
\ No newline at end of file
......@@ -46,28 +46,14 @@ bool QAOA::initialize(const HeterogeneousMap& parameters)
m_nbSteps = parameters.get<int>("steps");
}
// (4) Initial values for the beta parameters
m_betas.clear();
if (parameters.keyExists<std::vector<double>>("init-betas"))
{
m_betas = parameters.get<std::vector<double>>("init-betas");
}
// (5) Initial values for the gamma parameters
m_gammas.clear();
if (parameters.keyExists<std::vector<double>>("init-gammas"))
{
m_gammas = parameters.get<std::vector<double>>("init-gammas");
}
// (6) Cost Hamiltonian
// (4) Cost Hamiltonian
if (!parameters.pointerLikeExists<Observable>("observable"))
{
std::cout << "'observable' is required.\n";
initializeOk = false;
}
// (7) Reference Hamiltonian: optional.
// (5) Reference Hamiltonian: optional.
// Default is X0 + X1 + ...
// i.e. the X-basis where |+>|+>... is the ground state.
m_refHam.clear();
......@@ -84,15 +70,19 @@ bool QAOA::initialize(const HeterogeneousMap& parameters)
for (const auto& term : m_costHamObs->getNonIdentitySubTerms())
{
std::string pauliTermStr = term->toString();
// HACK: the Pauli parser doesn't like '-0', i.e. extra minus sign on 0
// hence, just remove it.
if (pauliTermStr.find("-0)") != std::string::npos)
// HACK: the Pauli parser doesn't like '-0', i.e. extra minus sign on integer (no decimal point)
// hence, just reformat it.
std::stringstream s;
s.precision(12);
s << std::fixed << term->coefficient();
// Find the parenthesis
const auto startPosition = pauliTermStr.find("(");
const auto endPosition = pauliTermStr.find(")");
if (startPosition != std::string::npos && endPosition != std::string::npos)
{
pauliTermStr.replace(pauliTermStr.find("-0)"), 3, "0)");
}
if (pauliTermStr.find("(-0,") != std::string::npos)
{
pauliTermStr.replace(pauliTermStr.find("(-0,"), 4, "(0,");
const auto length = endPosition - startPosition + 1;
pauliTermStr.replace(startPosition, length, s.str());
}
m_costHam.emplace_back(pauliTermStr);
......@@ -134,7 +124,6 @@ std::shared_ptr<CompositeInstruction> QAOA::constructParameterizedKernel(const s
const std::string paramName = "gamma" + std::to_string(gammaParamCounter++);
expCirc->addVariable(paramName);
expCirc->expand({ std::make_pair("pauli", term) });
//std::cout << "Term: '" << term << "': \n" << expCirc->toString() << "\n";
qaoaKernel->addVariable(paramName);
qaoaKernel->addInstructions(expCirc->getInstructions());
}
......@@ -157,7 +146,6 @@ std::shared_ptr<CompositeInstruction> QAOA::constructParameterizedKernel(const s
const std::string paramName = "beta" + std::to_string(betaParamCounter++);
expCirc->addVariable(paramName);
expCirc->expand({ std::make_pair("pauli", term) });
// std::cout << "Term: '" << term << "': \n" << expCirc->toString() << "\n";
qaoaKernel->addVariable(paramName);
qaoaKernel->addInstructions(expCirc->getInstructions());
}
......@@ -170,10 +158,10 @@ void QAOA::execute(const std::shared_ptr<AcceleratorBuffer> buffer) const
{
const int nbQubits = buffer->size();
auto kernel = constructParameterizedKernel(buffer);
// Observe the cost Hamiltonian:
auto kernels = m_costHamObs->observe(kernel);
int iterCount = 0;
// Construct the optimizer/minimizer:
OptFunction f(
[&, this](const std::vector<double>& x, std::vector<double>& dx) {
......@@ -233,12 +221,21 @@ void QAOA::execute(const std::shared_ptr<AcceleratorBuffer> buffer) const
buffer->appendChild(fsToExec[i]->name(), buffers[i]);
}
// std::stringstream ss;
// ss << "E(" << ( !x.empty() ? std::to_string(x[0]) : "");
// for (int i = 1; i < x.size(); i++)
// ss << "," << x[i];
// ss << ") = " << std::setprecision(12) << energy;
// std::cout << ss.str() << '\n';
std::stringstream ss;
iterCount++;
ss << "Iter " << iterCount << ": E(" << ( !x.empty() ? std::to_string(x[0]) : "");
for (int i = 1; i < x.size(); i++)
{
ss << "," << std::setprecision(3) << x[i];
if (i > 4)
{
// Don't print too many params
ss << ", ...";
break;
}
}
ss << ") = " << std::setprecision(12) << energy;
std::cout << ss.str() << '\n';
return energy;
},
kernel->nVariables());
......
......@@ -37,8 +37,6 @@ private:
Accelerator* m_qpu;
Optimizer* m_optimizer;
int m_nbSteps;
std::vector<double> m_gammas;
std::vector<double> m_betas;
};
} // namespace algorithm
} // namespace xacc
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment