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

Refactored QAOA to use circuit



We can, in fact, completely remove QAOA as an algorithm (use VQE on the circuit)

Keeping it for now since we can enhance QAOA to handle MAX-CUT, QUBO in the future.
Signed-off-by: Nguyen, Thien Minh's avatarThien Nguyen <nguyentm@ornl.gov>
parent e688fe92
......@@ -53,43 +53,17 @@ bool QAOA::initialize(const HeterogeneousMap& parameters)
initializeOk = false;
}
// (5) Reference Hamiltonian: optional.
// Default is X0 + X1 + ...
// i.e. the X-basis where |+>|+>... is the ground state.
m_refHam.clear();
if (parameters.keyExists<std::vector<std::string>>("ref-ham"))
{
m_refHam = parameters.get<std::vector<std::string>>("ref-ham");
}
if (initializeOk)
{
m_costHamObs = parameters.getPointerLike<Observable>("observable");
// Add cost Hamiltonian terms to the list of terms for gamma exp
m_costHam.clear();
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 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)
{
const auto length = endPosition - startPosition + 1;
pauliTermStr.replace(startPosition, length, s.str());
}
m_costHam.emplace_back(pauliTermStr);
}
m_qpu = parameters.getPointerLike<Accelerator>("accelerator");
m_optimizer = parameters.getPointerLike<Optimizer>("optimizer");
// Optional ref-hamiltonian
m_refHamObs = nullptr;
if (parameters.pointerLikeExists<Observable>("ref-ham"))
{
m_refHamObs = parameters.getPointerLike<Observable>("ref-ham");
}
}
return initializeOk;
......@@ -100,64 +74,17 @@ const std::vector<std::string> QAOA::requiredParameters() const
return { "accelerator", "optimizer", "observable" };
}
std::shared_ptr<CompositeInstruction> QAOA::constructParameterizedKernel(const std::shared_ptr<AcceleratorBuffer>& in_buffer) const
{
auto gateRegistry = xacc::getService<xacc::IRProvider>("quantum");
const auto nbQubits = in_buffer->size();
auto qaoaKernel = gateRegistry->createComposite("qaoaKernel");
// Hadamard layer
for (size_t i = 0; i < nbQubits; ++i)
{
qaoaKernel->addInstruction(gateRegistry->createInstruction("H", { i }));
}
// Trotter layers (parameterized): mixing b/w cost and drive (reference) Hamiltonian
int betaParamCounter = 0;
int gammaParamCounter = 0;
for (size_t i = 0; i < m_nbSteps; ++i)
{
for (const auto& term : m_costHam)
{
auto expCirc = std::dynamic_pointer_cast<xacc::quantum::Circuit>(xacc::getService<Instruction>("exp_i_theta"));
const std::string paramName = "gamma" + std::to_string(gammaParamCounter++);
expCirc->addVariable(paramName);
expCirc->expand({ std::make_pair("pauli", term) });
qaoaKernel->addVariable(paramName);
qaoaKernel->addInstructions(expCirc->getInstructions());
}
// Beta params:
// If no drive/reference Hamiltonian is given,
// then assume the default X0 + X1 + ...
std::vector<std::string> refHamTerms(m_refHam);
if (refHamTerms.empty())
{
for (size_t qId = 0; qId < nbQubits; ++qId)
{
refHamTerms.emplace_back("X" + std::to_string(qId));
}
}
for (const auto& term : refHamTerms)
{
auto expCirc = std::dynamic_pointer_cast<xacc::quantum::Circuit>(xacc::getService<Instruction>("exp_i_theta"));
const std::string paramName = "beta" + std::to_string(betaParamCounter++);
expCirc->addVariable(paramName);
expCirc->expand({ std::make_pair("pauli", term) });
qaoaKernel->addVariable(paramName);
qaoaKernel->addInstructions(expCirc->getInstructions());
}
}
return qaoaKernel;
}
void QAOA::execute(const std::shared_ptr<AcceleratorBuffer> buffer) const
{
const int nbQubits = buffer->size();
auto kernel = constructParameterizedKernel(buffer);
auto kernel = std::dynamic_pointer_cast<CompositeInstruction>(xacc::getService<Instruction>("qaoa"));
kernel->expand({
std::make_pair("nbQubits", nbQubits),
std::make_pair("nbSteps", m_nbSteps),
std::make_pair("cost-ham", m_costHamObs),
std::make_pair("ref-ham", m_refHamObs),
});
// Observe the cost Hamiltonian:
auto kernels = m_costHamObs->observe(kernel);
......@@ -248,7 +175,12 @@ void QAOA::execute(const std::shared_ptr<AcceleratorBuffer> buffer) const
std::vector<double> QAOA::execute(const std::shared_ptr<AcceleratorBuffer> buffer, const std::vector<double>& x)
{
const int nbQubits = buffer->size();
auto kernel = constructParameterizedKernel(buffer);
auto kernel = std::dynamic_pointer_cast<CompositeInstruction>(xacc::getService<Instruction>("qaoa"));
kernel->expand({
std::make_pair("nbQubits", nbQubits),
std::make_pair("nbSteps", m_nbSteps),
std::make_pair("cost-ham", m_costHamObs)
});
// Observe the cost Hamiltonian:
auto kernels = m_costHamObs->observe(kernel);
......
......@@ -26,14 +26,9 @@ public:
const std::string name() const override { return "QAOA"; }
const std::string description() const override { return ""; }
DEFINE_ALGORITHM_CLONE(QAOA)
private:
std::shared_ptr<CompositeInstruction> constructParameterizedKernel(const std::shared_ptr<AcceleratorBuffer>& in_buffer) const;
private:
std::vector<std::string> m_refHam;
std::vector<std::string> m_costHam;
Observable* m_costHamObs;
Observable* m_refHamObs;
Accelerator* m_qpu;
Optimizer* m_optimizer;
int m_nbSteps;
......
......@@ -16,12 +16,95 @@ namespace xacc {
namespace circuits {
bool QAOA::expand(const xacc::HeterogeneousMap& runtimeOptions)
{
return false;
if (!runtimeOptions.keyExists<int>("nbQubits"))
{
std::cout << "'nbQubits' is required.\n";
return false;
}
if (!runtimeOptions.keyExists<int>("nbSteps"))
{
std::cout << "'nbSteps' is required.\n";
return false;
}
if (!runtimeOptions.pointerLikeExists<xacc::Observable>("cost-ham"))
{
std::cout << "'cost-ham' is required.\n";
return false;
}
m_nbQubits = runtimeOptions.get<int>("nbQubits");
m_nbSteps = runtimeOptions.get<int>("nbSteps");
auto costHam = runtimeOptions.getPointerLike<xacc::Observable>("cost-ham");
xacc::Observable* refHam = nullptr;
if (runtimeOptions.pointerLikeExists<xacc::Observable>("ref-ham"))
{
refHam = runtimeOptions.getPointerLike<xacc::Observable>("ref-ham");
}
parseObservables(costHam, refHam);
// Expand to a parametric kernel
auto kernel = constructParameterizedKernel();
clear();
for (int instId = 0; instId < kernel->nInstructions(); ++instId)
{
addInstruction(kernel->getInstruction(instId)->clone());
}
return true;
}
const std::vector<std::string> QAOA::requiredKeys()
{
return {};
// Keys for conventional circuit expand
// Mixer Hamiltonian is optional.
return { "nbQubits", "nbSteps", "cost-ham" };
}
void QAOA::parseObservables(Observable* costHam, Observable* refHam)
{
m_costHam.clear();
m_refHam.clear();
const auto pauliTermToString = [](const std::shared_ptr<xacc::Observable>& in_term){
std::string pauliTermStr = in_term->toString();
std::stringstream s;
s.precision(12);
s << std::fixed << in_term->coefficient();
// Find the parenthesis
const auto startPosition = pauliTermStr.find("(");
const auto endPosition = pauliTermStr.find(")");
if (startPosition != std::string::npos && endPosition != std::string::npos)
{
const auto length = endPosition - startPosition + 1;
pauliTermStr.replace(startPosition, length, s.str());
}
return pauliTermStr;
};
for (const auto& term : costHam->getNonIdentitySubTerms())
{
m_costHam.emplace_back(pauliTermToString(term));
}
// Default X mixer
if (!refHam)
{
for (size_t qId = 0; qId < m_nbQubits; ++qId)
{
m_refHam.emplace_back("X" + std::to_string(qId));
}
}
else
{
// Ref-Ham was provided:
for (const auto& term : refHam->getNonIdentitySubTerms())
{
m_refHam.emplace_back(pauliTermToString(term));
}
}
}
std::shared_ptr<CompositeInstruction> QAOA::constructParameterizedKernel() const
......@@ -77,7 +160,7 @@ std::shared_ptr<CompositeInstruction> QAOA::constructParameterizedKernel() const
return qaoaKernel;
}
// Runtime arguments (e.g. QCOR)
void QAOA::applyRuntimeArguments()
{
// Apply runtime arguments: i.e. resolve all parameters to concrete values
......@@ -86,54 +169,9 @@ void QAOA::applyRuntimeArguments()
const std::vector<double> gammaVec = arguments[2]->runtimeValue.get<std::vector<double>>(INTERNAL_ARGUMENT_VALUE_KEY);
auto costHam = arguments[3]->runtimeValue.getPointerLike<xacc::Observable>(INTERNAL_ARGUMENT_VALUE_KEY);
auto refHam = arguments[4]->runtimeValue.getPointerLike<xacc::Observable>(INTERNAL_ARGUMENT_VALUE_KEY);
// std::cout << "Number of qubits: " << m_nbQubits << "\n";
// std::cout << "Beta length: " << betaVec.size() << "\n";
// std::cout << "Gamma length: " << gammaVec.size() << "\n";
// std::cout << "Cost Ham: \n " << costHam->toString() << "\n";
// std::cout << "Ref Ham: \n " << refHam->toString() << "\n";
// Number of QAOA steps
m_nbSteps = betaVec.size()/m_nbQubits;
// std::cout << "Number steps (p): " << m_nbSteps << "\n";
m_costHam.clear();
for (const auto& term : costHam->getNonIdentitySubTerms())
{
std::string pauliTermStr = term->toString();
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)
{
const auto length = endPosition - startPosition + 1;
pauliTermStr.replace(startPosition, length, s.str());
}
m_costHam.emplace_back(pauliTermStr);
}
m_refHam.clear();
for (const auto& term : refHam->getNonIdentitySubTerms())
{
std::string pauliTermStr = term->toString();
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)
{
const auto length = endPosition - startPosition + 1;
pauliTermStr.replace(startPosition, length, s.str());
}
m_refHam.emplace_back(pauliTermStr);
}
parseObservables(costHam, refHam);
const int nbGammasPerStep = m_costHam.size();
const int nbBetasPerStep = m_refHam.size();
// Parametric kernel
......
......@@ -36,6 +36,7 @@ public:
private:
std::shared_ptr<CompositeInstruction> constructParameterizedKernel() const;
void parseObservables(Observable* costHam, Observable* refHam);
private:
size_t m_nbQubits;
size_t m_nbSteps;
......
Markdown is supported
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