Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
ORNL Quantum Computing Institute
xacc
Commits
8a203f61
Unverified
Commit
8a203f61
authored
May 28, 2020
by
Mccaskey, Alex
Committed by
GitHub
May 28, 2020
Browse files
Merge pull request #194 from tnguyen-ornl/tnguyen/qcor
Refactored QAOA circuit construction
parents
f3e9b32a
9202fe68
Changes
6
Hide whitespace changes
Inline
Side-by-side
quantum/gate/ir/Circuit.hpp
View file @
8a203f61
...
...
@@ -85,8 +85,9 @@ public:
:
circuitName
(
name
),
variables
(
vars
)
{}
Circuit
(
const
Circuit
&
other
)
:
circuitName
(
other
.
circuitName
),
variables
(
other
.
variables
),
instructions
(
other
.
instructions
),
parsingUtil
(
other
.
parsingUtil
)
{}
:
CompositeInstruction
(
other
),
circuitName
(
other
.
circuitName
),
variables
(
other
.
variables
),
instructions
(
other
.
instructions
),
parsingUtil
(
other
.
parsingUtil
)
{
}
const
std
::
string
name
()
const
override
{
return
circuitName
;
}
const
std
::
string
description
()
const
override
{
return
""
;
}
...
...
quantum/plugins/algorithms/qaoa/QAOAActivator.cpp
View file @
8a203f61
...
...
@@ -11,6 +11,7 @@
* Thien Nguyen - initial API and implementation
*******************************************************************************/
#include
"qaoa.hpp"
#include
"qaoa_circuit.hpp"
#include
"cppmicroservices/BundleActivator.h"
#include
"cppmicroservices/BundleContext.h"
...
...
@@ -35,6 +36,7 @@ public:
void
Start
(
BundleContext
context
)
{
auto
c
=
std
::
make_shared
<
xacc
::
algorithm
::
QAOA
>
();
context
.
RegisterService
<
xacc
::
Algorithm
>
(
c
);
context
.
RegisterService
<
xacc
::
Instruction
>
(
std
::
make_shared
<
xacc
::
circuits
::
QAOA
>
());
}
/**
...
...
quantum/plugins/algorithms/qaoa/qaoa.cpp
View file @
8a203f61
...
...
@@ -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,13 @@ 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
),
std
::
make_pair
(
"ref-ham"
,
m_refHamObs
)
});
// Observe the cost Hamiltonian:
auto
kernels
=
m_costHamObs
->
observe
(
kernel
);
...
...
quantum/plugins/algorithms/qaoa/qaoa.hpp
View file @
8a203f61
...
...
@@ -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
;
...
...
quantum/plugins/algorithms/qaoa/qaoa_circuit.cpp
0 → 100644
View file @
8a203f61
/*******************************************************************************
* Copyright (c) 2019 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
"qaoa_circuit.hpp"
#include
"PauliOperator.hpp"
namespace
{
// Null if not an Observable-like type
std
::
shared_ptr
<
xacc
::
Observable
>
getObservableRuntimeArg
(
const
xacc
::
HeterogeneousMap
&
in_runtimeArg
)
{
// Try base Observable pointer:
if
(
in_runtimeArg
.
pointerLikeExists
<
xacc
::
Observable
>
(
xacc
::
INTERNAL_ARGUMENT_VALUE_KEY
))
{
return
std
::
shared_ptr
<
xacc
::
Observable
>
(
in_runtimeArg
.
getPointerLike
<
xacc
::
quantum
::
PauliOperator
>
(
xacc
::
INTERNAL_ARGUMENT_VALUE_KEY
),
xacc
::
empty_delete
<
xacc
::
Observable
>
());
}
// Try concrete Pauli Observable
// Reference type
if
(
in_runtimeArg
.
keyExists
<
xacc
::
quantum
::
PauliOperator
>
(
xacc
::
INTERNAL_ARGUMENT_VALUE_KEY
))
{
// Just make a copy
return
std
::
make_shared
<
xacc
::
quantum
::
PauliOperator
>
(
in_runtimeArg
.
get
<
xacc
::
quantum
::
PauliOperator
>
(
xacc
::
INTERNAL_ARGUMENT_VALUE_KEY
));
}
// Pointer type
if
(
in_runtimeArg
.
pointerLikeExists
<
xacc
::
quantum
::
PauliOperator
>
(
xacc
::
INTERNAL_ARGUMENT_VALUE_KEY
))
{
// Make a copy
return
std
::
make_shared
<
xacc
::
quantum
::
PauliOperator
>
(
*
(
in_runtimeArg
.
getPointerLike
<
xacc
::
quantum
::
PauliOperator
>
(
xacc
::
INTERNAL_ARGUMENT_VALUE_KEY
)));
}
return
nullptr
;
}
}
namespace
xacc
{
namespace
circuits
{
bool
QAOA
::
expand
(
const
xacc
::
HeterogeneousMap
&
runtimeOptions
)
{
if
(
runtimeOptions
.
size
()
==
0
)
{
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
();
variables
=
kernel
->
getVariables
();
for
(
int
instId
=
0
;
instId
<
kernel
->
nInstructions
();
++
instId
)
{
addInstruction
(
kernel
->
getInstruction
(
instId
)
->
clone
());
}
return
true
;
}
const
std
::
vector
<
std
::
string
>
QAOA
::
requiredKeys
()
{
// 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
{
auto
gateRegistry
=
xacc
::
getService
<
xacc
::
IRProvider
>
(
"quantum"
);
auto
qaoaKernel
=
gateRegistry
->
createComposite
(
"qaoaKernel"
);
// Hadamard layer
for
(
size_t
i
=
0
;
i
<
m_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
<
m_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
());
}
}
// std::cout << "Kernel: \n" << qaoaKernel->toString() << "\n";
return
qaoaKernel
;
}
// Runtime arguments (e.g. QCOR)
void
QAOA
::
applyRuntimeArguments
()
{
// Apply runtime arguments: i.e. resolve all parameters to concrete values
m_nbQubits
=
arguments
[
1
]
->
runtimeValue
.
get
<
int
>
(
INTERNAL_ARGUMENT_VALUE_KEY
);
const
std
::
vector
<
double
>
betaVec
=
arguments
[
2
]
->
runtimeValue
.
get
<
std
::
vector
<
double
>>
(
INTERNAL_ARGUMENT_VALUE_KEY
);
const
std
::
vector
<
double
>
gammaVec
=
arguments
[
3
]
->
runtimeValue
.
get
<
std
::
vector
<
double
>>
(
INTERNAL_ARGUMENT_VALUE_KEY
);
auto
costHam
=
getObservableRuntimeArg
(
arguments
[
4
]
->
runtimeValue
);
auto
refHam
=
getObservableRuntimeArg
(
arguments
[
5
]
->
runtimeValue
);
// Cost Hamiltonian is required.
if
(
!
costHam
)
{
std
::
cout
<<
"No cost Hamiltonian observable was provided!
\n
"
;
return
;
}
// Number of QAOA steps
m_nbSteps
=
betaVec
.
size
()
/
m_nbQubits
;
parseObservables
(
costHam
.
get
(),
refHam
.
get
());
const
int
nbGammasPerStep
=
m_costHam
.
size
();
const
int
nbBetasPerStep
=
m_refHam
.
size
();
// Parametric kernel
auto
kernel
=
constructParameterizedKernel
();
std
::
vector
<
double
>
params
;
int
gammaCounter
=
0
;
int
betaCounter
=
0
;
// Combine gammas and betas into one vector to resolve/evaluate the circuit.
for
(
int
i
=
0
;
i
<
m_nbSteps
;
++
i
)
{
// Gamma first
for
(
int
j
=
0
;
j
<
nbGammasPerStep
;
++
j
)
{
params
.
emplace_back
(
gammaVec
[
gammaCounter
]);
gammaCounter
++
;
}
// then betas
for
(
int
j
=
0
;
j
<
nbBetasPerStep
;
++
j
)
{
params
.
emplace_back
(
betaVec
[
betaCounter
]);
betaCounter
++
;
}
}
// Evaluate the circuit:
auto
evaled
=
kernel
->
operator
()(
params
);
// std::cout << "Eval: \n" << evaled->toString() << "\n";
// Construct circuit (now all gates have been resolved).
clear
();
for
(
int
instId
=
0
;
instId
<
evaled
->
nInstructions
();
++
instId
)
{
addInstruction
(
evaled
->
getInstruction
(
instId
)
->
clone
());
}
}
}
// namespace circuits
}
// namespace xacc
quantum/plugins/algorithms/qaoa/qaoa_circuit.hpp
0 → 100644
View file @
8a203f61
/*******************************************************************************
* Copyright (c) 2019 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
*******************************************************************************/
#pragma once
#include
"Circuit.hpp"
#include
"IRProvider.hpp"
namespace
xacc
{
namespace
circuits
{
// Generate QAOA ansatz for VQE
class
QAOA
:
public
xacc
::
quantum
::
Circuit
{
public:
QAOA
()
:
Circuit
(
"qaoa"
)
{
// Default runtime arguments
arguments
.
push_back
(
std
::
make_shared
<
xacc
::
CompositeArgument
>
(
"qReg"
,
"qreg"
));
}
bool
expand
(
const
xacc
::
HeterogeneousMap
&
runtimeOptions
)
override
;
const
std
::
vector
<
std
::
string
>
requiredKeys
()
override
;
void
applyRuntimeArguments
()
override
;
DEFINE_CLONE
(
QAOA
);
private:
std
::
shared_ptr
<
CompositeInstruction
>
constructParameterizedKernel
()
const
;
void
parseObservables
(
Observable
*
costHam
,
Observable
*
refHam
);
private:
size_t
m_nbQubits
;
size_t
m_nbSteps
;
std
::
vector
<
std
::
string
>
m_refHam
;
std
::
vector
<
std
::
string
>
m_costHam
;
};
}
// namespace circuits
}
// namespace xacc
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment