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
9bafef37
Commit
9bafef37
authored
Apr 09, 2020
by
Mccaskey, Alex
Browse files
updates to IR v3 for qcor support
Signed-off-by:
Alex McCaskey
<
mccaskeyaj@ornl.gov
>
parent
68e2a3bf
Changes
31
Expand all
Hide whitespace changes
Inline
Side-by-side
quantum/gate/ir/Gate.cpp
View file @
9bafef37
...
...
@@ -27,7 +27,7 @@ Gate::Gate(std::string name, std::vector<std::size_t> qubts,
std
::
vector
<
InstructionParameter
>
params
)
:
gateName
(
name
),
qbits
(
qubts
),
parameters
(
params
)
{}
Gate
::
Gate
(
const
Gate
&
inst
)
:
gateName
(
inst
.
gateName
),
qbits
(
inst
.
qbits
),
parameters
(
inst
.
parameters
),
:
gateName
(
inst
.
gateName
),
qbits
(
inst
.
qbits
),
parameters
(
inst
.
parameters
),
arguments
(
inst
.
arguments
),
enabled
(
inst
.
enabled
)
{}
const
std
::
string
Gate
::
name
()
const
{
return
gateName
;
}
...
...
quantum/gate/ir/tests/GateTester.cpp
View file @
9bafef37
...
...
@@ -54,12 +54,11 @@ TEST(GateTester, checkIR3) {
EXPECT_THROW
(
circuit
->
updateRuntimeArguments
(
2.2
),
std
::
runtime_error
);
circuit
->
updateRuntimeArguments
(
2.2
,
3.3
,
4.4
);
circuit
->
applyRuntimeArguments
();
std
::
cout
<<
circuit
->
toString
()
<<
"
\n
"
;
circuit
->
updateRuntimeArguments
(
3.2
,
4.3
,
5.3
);
circuit
->
applyRuntimeArguments
();
std
::
cout
<<
circuit
->
toString
()
<<
"
\n
"
;
}
...
...
quantum/gate/utils/IRToGraphVisitor.cpp
View file @
9bafef37
...
...
@@ -30,7 +30,7 @@ void IRToGraphVisitor::addSingleQubitGate(Gate &inst) {
std
::
make_pair
(
"bits"
,
inst
.
bits
())};
graph
->
addVertex
(
newNode
);
graph
->
addEdge
(
lastNode
.
get
<
in
t
>
(
"id"
),
newNode
.
get
<
in
t
>
(
"id"
),
1
);
graph
->
addEdge
(
lastNode
.
get
<
std
::
size_
t
>
(
"id"
),
newNode
.
get
<
std
::
size_
t
>
(
"id"
),
1
);
qubitToLastNode
[
bit
]
=
newNode
;
}
...
...
@@ -39,8 +39,8 @@ void IRToGraphVisitor::addTwoQubitGate(Gate &inst) {
auto
srcbit
=
inst
.
bits
()[
0
];
auto
tgtbit
=
inst
.
bits
()[
1
];
auto
lastsrcnodeid
=
qubitToLastNode
[
srcbit
].
get
<
in
t
>
(
"id"
);
auto
lasttgtnodeid
=
qubitToLastNode
[
tgtbit
].
get
<
in
t
>
(
"id"
);
auto
lastsrcnodeid
=
qubitToLastNode
[
srcbit
].
get
<
std
::
size_
t
>
(
"id"
);
auto
lasttgtnodeid
=
qubitToLastNode
[
tgtbit
].
get
<
std
::
size_
t
>
(
"id"
);
id
++
;
CircuitNode
newNode
{
std
::
make_pair
(
"name"
,
inst
.
name
()),
...
...
@@ -60,7 +60,7 @@ IRToGraphVisitor::IRToGraphVisitor(const int nQubits) {
std
::
vector
<
std
::
size_t
>
allQbitIds
(
nQubits
);
std
::
iota
(
std
::
begin
(
allQbitIds
),
std
::
end
(
allQbitIds
),
0
);
CircuitNode
initNode
{
std
::
make_pair
(
"name"
,
std
::
string
(
"InitialState"
)),
std
::
make_pair
(
"id"
,
0
),
std
::
make_pair
(
"id"
,
id
),
std
::
make_pair
(
"bits"
,
allQbitIds
)};
for
(
int
i
=
0
;
i
<
nQubits
;
i
++
)
{
qubitToLastNode
[
i
]
=
initNode
;
...
...
@@ -75,7 +75,7 @@ std::shared_ptr<Graph> IRToGraphVisitor::getGraph() {
graph
->
addVertex
(
finalNode
);
for
(
auto
&
kv
:
qubitToLastNode
)
{
graph
->
addEdge
(
kv
.
second
.
get
<
in
t
>
(
"id"
),
finalNode
.
get
<
in
t
>
(
"id"
),
1.0
);
graph
->
addEdge
(
kv
.
second
.
get
<
std
::
size_
t
>
(
"id"
),
finalNode
.
get
<
std
::
size_
t
>
(
"id"
),
1.0
);
}
return
graph
;
...
...
quantum/gate/utils/IRToGraphVisitor.hpp
View file @
9bafef37
...
...
@@ -20,7 +20,7 @@
namespace
xacc
{
namespace
quantum
{
using
CircuitNode
=
HeterogeneousMap
;
//std::map<std::string, InstructionParameter>;
using
CircuitNode
=
HeterogeneousMap
;
class
IRToGraphVisitor
:
public
AllGateVisitor
{
...
...
@@ -29,7 +29,7 @@ protected:
std
::
map
<
int
,
CircuitNode
>
qubitToLastNode
;
in
t
id
=
0
;
std
::
size_
t
id
=
0
;
void
addSingleQubitGate
(
Gate
&
inst
);
void
addTwoQubitGate
(
Gate
&
inst
);
...
...
quantum/observable/pauli/PauliOperator.cpp
View file @
9bafef37
...
...
@@ -38,9 +38,7 @@ PauliOperator::PauliOperator(double c) {
terms
.
emplace
(
std
::
make_pair
(
"I"
,
c
));
}
PauliOperator
::
PauliOperator
(
std
::
string
fromStr
)
{
fromString
(
fromStr
);
}
PauliOperator
::
PauliOperator
(
std
::
string
fromStr
)
{
fromString
(
fromStr
);
}
PauliOperator
::
PauliOperator
(
std
::
complex
<
double
>
c
,
std
::
string
var
)
{
terms
.
emplace
(
std
::
piecewise_construct
,
std
::
forward_as_tuple
(
"I"
),
...
...
@@ -90,10 +88,17 @@ PauliOperator::PauliOperator(std::map<int, std::string> operators,
std
::
forward_as_tuple
(
coeff
,
var
,
operators
));
}
std
::
complex
<
double
>
PauliOperator
::
coefficient
()
{
if
(
terms
.
size
()
>
1
)
{
xacc
::
error
(
"Cannot call PauliOperator::coefficient on operator with more "
"than 1 term."
);
}
return
terms
.
begin
()
->
second
.
coeff
();
}
std
::
vector
<
std
::
shared_ptr
<
CompositeInstruction
>>
PauliOperator
::
observe
(
std
::
shared_ptr
<
CompositeInstruction
>
function
)
{
// Create a new GateQIR to hold the spin based terms
// Create a new GateQIR to hold the spin based terms
auto
gateRegistry
=
xacc
::
getService
<
IRProvider
>
(
"quantum"
);
std
::
vector
<
std
::
shared_ptr
<
CompositeInstruction
>>
observed
;
int
counter
=
0
;
...
...
@@ -104,8 +109,8 @@ PauliOperator::observe(std::shared_ptr<CompositeInstruction> function) {
Term
spinInst
=
inst
.
second
;
auto
gateFunction
=
gateRegistry
->
createComposite
(
inst
.
first
,
function
->
getVariables
());
auto
gateFunction
=
gateRegistry
->
createComposite
(
inst
.
first
,
function
->
getVariables
());
gateFunction
->
setCoefficient
(
spinInst
.
coeff
());
...
...
@@ -113,6 +118,10 @@ PauliOperator::observe(std::shared_ptr<CompositeInstruction> function) {
gateFunction
->
addInstruction
(
function
->
clone
());
}
for
(
auto
arg
:
function
->
getArguments
())
{
gateFunction
->
addArgument
(
arg
,
0
);
}
// Loop over all terms in the Spin Instruction
// and create instructions to run on the Gate QPU.
std
::
vector
<
std
::
shared_ptr
<
xacc
::
Instruction
>>
measurements
;
...
...
@@ -130,8 +139,8 @@ PauliOperator::observe(std::shared_ptr<CompositeInstruction> function) {
int
t
=
qbit
;
std
::
size_t
tt
=
t
;
auto
gateName
=
terms
[
i
].
second
;
auto
meas
=
gateRegistry
->
createInstruction
(
"Measure"
,
std
::
vector
<
std
::
size_t
>
{
tt
});
auto
meas
=
gateRegistry
->
createInstruction
(
"Measure"
,
std
::
vector
<
std
::
size_t
>
{
tt
});
xacc
::
InstructionParameter
classicalIdx
(
qbit
);
meas
->
setParameter
(
0
,
classicalIdx
);
measurements
.
push_back
(
meas
);
...
...
@@ -141,7 +150,8 @@ PauliOperator::observe(std::shared_ptr<CompositeInstruction> function) {
gateRegistry
->
createInstruction
(
"H"
,
std
::
vector
<
std
::
size_t
>
{
tt
});
gateFunction
->
addInstruction
(
hadamard
);
}
else
if
(
gateName
==
"Y"
)
{
auto
rx
=
gateRegistry
->
createInstruction
(
"Rx"
,
std
::
vector
<
std
::
size_t
>
{
tt
});
auto
rx
=
gateRegistry
->
createInstruction
(
"Rx"
,
std
::
vector
<
std
::
size_t
>
{
tt
});
InstructionParameter
p
(
pi
/
2.0
);
rx
->
setParameter
(
0
,
p
);
gateFunction
->
addInstruction
(
rx
);
...
...
@@ -278,8 +288,8 @@ std::vector<std::complex<double>> PauliOperator::toDenseMatrix(const int n) {
}
}
std
::
vector
<
std
::
complex
<
double
>>
retv
(
dim
*
dim
);
Eigen
::
MatrixXcd
::
Map
(
&
retv
.
data
()[
0
],
A
.
rows
(),
A
.
cols
())
=
A
;
std
::
vector
<
std
::
complex
<
double
>>
retv
(
dim
*
dim
);
Eigen
::
MatrixXcd
::
Map
(
&
retv
.
data
()[
0
],
A
.
rows
(),
A
.
cols
())
=
A
;
return
retv
;
}
...
...
@@ -360,7 +370,6 @@ void PauliOperator::fromString(const std::string str) {
clear
();
operator
+=
(
listener
.
getOperator
());
}
bool
PauliOperator
::
contains
(
PauliOperator
&
op
)
{
...
...
@@ -434,7 +443,8 @@ bool PauliOperator::operator==(const PauliOperator &v) noexcept {
bool
found
=
false
;
for
(
auto
&
vkv
:
v
.
terms
)
{
if
(
kv
.
second
.
operator
==
(
vkv
.
second
)
|
(
kv
.
second
.
id
()
==
"I"
&&
vkv
.
second
.
id
()
==
"I"
))
{
if
(
kv
.
second
.
operator
==
(
vkv
.
second
)
|
(
kv
.
second
.
id
()
==
"I"
&&
vkv
.
second
.
id
()
==
"I"
))
{
found
=
true
;
break
;
}
...
...
@@ -638,10 +648,9 @@ std::shared_ptr<IR> PauliOperator::toXACCIR() {
auto
tmp
=
gateRegistry
->
createComposite
(
"tmp"
);
auto
kernels
=
observe
(
tmp
);
auto
newIr
=
gateRegistry
->
createIR
();
for
(
auto
&
k
:
kernels
)
newIr
->
addComposite
(
k
);
for
(
auto
&
k
:
kernels
)
newIr
->
addComposite
(
k
);
return
newIr
;
}
int
PauliOperator
::
nQubits
()
{
...
...
quantum/observable/pauli/PauliOperator.hpp
View file @
9bafef37
...
...
@@ -12,7 +12,6 @@
*******************************************************************************/
#ifndef QUANTUM_UTILS_PAULIOPERATOR_HPP_
#define QUANTUM_UTILS_PAULIOPERATOR_HPP_
#include
<ios>
#include
<unordered_map>
#include
<complex>
#include
<map>
...
...
@@ -223,7 +222,8 @@ public:
};
class
PauliOperator
:
public
xacc
::
Observable
,
public
xacc
::
Cloneable
<
Observable
>
,
:
public
xacc
::
Observable
,
public
xacc
::
Cloneable
<
Observable
>
,
public
tao
::
operators
::
commutative_ring
<
PauliOperator
>
,
public
tao
::
operators
::
equality_comparable
<
PauliOperator
>
,
public
tao
::
operators
::
commutative_multipliable
<
PauliOperator
,
double
>
,
...
...
@@ -234,7 +234,7 @@ protected:
public:
std
::
shared_ptr
<
Observable
>
clone
()
override
{
return
std
::
make_shared
<
PauliOperator
>
();
return
std
::
make_shared
<
PauliOperator
>
();
}
std
::
unordered_map
<
std
::
string
,
Term
>::
iterator
begin
()
{
...
...
@@ -259,6 +259,39 @@ public:
std
::
vector
<
std
::
shared_ptr
<
CompositeInstruction
>>
observe
(
std
::
shared_ptr
<
CompositeInstruction
>
function
)
override
;
std
::
vector
<
std
::
shared_ptr
<
Observable
>>
getSubTerms
()
override
{
std
::
vector
<
std
::
shared_ptr
<
Observable
>>
ret
;
for
(
auto
&
term
:
getTerms
())
{
ret
.
emplace_back
(
new
PauliOperator
(
term
.
second
.
ops
(),
term
.
second
.
coeff
()));
}
return
ret
;
}
virtual
std
::
vector
<
std
::
shared_ptr
<
Observable
>>
getNonIdentitySubTerms
()
{
std
::
vector
<
std
::
shared_ptr
<
Observable
>>
ret
;
for
(
auto
&
term
:
getTerms
())
{
if
(
term
.
first
!=
"I"
)
{
ret
.
emplace_back
(
new
PauliOperator
(
term
.
second
.
ops
(),
term
.
second
.
coeff
()));
}
}
return
ret
;
}
virtual
std
::
shared_ptr
<
Observable
>
getIdentitySubTerm
()
{
for
(
auto
&
term
:
getTerms
())
{
if
(
term
.
first
==
"I"
)
{
return
std
::
make_shared
<
PauliOperator
>
(
term
.
second
.
ops
(),
term
.
second
.
coeff
());
}
}
return
nullptr
;
}
std
::
complex
<
double
>
coefficient
()
override
;
const
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
complex
<
double
>>>
computeActionOnKet
(
const
std
::
string
&
bitString
);
const
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
complex
<
double
>>>
...
...
@@ -302,7 +335,7 @@ public:
eval
(
const
std
::
map
<
std
::
string
,
std
::
complex
<
double
>>
varToValMap
);
bool
isClose
(
PauliOperator
&
other
);
int
nQubits
();
const
int
nBits
()
override
{
return
nQubits
();}
const
int
nBits
()
override
{
return
nQubits
();
}
PauliOperator
&
operator
+=
(
const
PauliOperator
&
v
)
noexcept
;
PauliOperator
&
operator
-=
(
const
PauliOperator
&
v
)
noexcept
;
...
...
@@ -311,18 +344,15 @@ public:
PauliOperator
&
operator
*=
(
const
double
v
)
noexcept
;
PauliOperator
&
operator
*=
(
const
std
::
complex
<
double
>
v
)
noexcept
;
const
std
::
string
name
()
const
override
{
return
"pauli"
;
}
const
std
::
string
description
()
const
override
{
return
""
;
}
void
fromOptions
(
const
HeterogeneousMap
&
options
)
override
{
return
;
}
const
std
::
string
name
()
const
override
{
return
"pauli"
;
}
const
std
::
string
description
()
const
override
{
return
""
;
}
void
fromOptions
(
const
HeterogeneousMap
&
options
)
override
{
return
;
}
};
}
// namespace quantum
template
const
quantum
::
PauliOperator
&
HeterogeneousMap
::
get
<
quantum
::
PauliOperator
>(
const
std
::
string
key
)
const
;
}
// namespace xacc
#endif
quantum/plugins/circuits/exp/exp.cpp
View file @
9bafef37
...
...
@@ -13,9 +13,11 @@
#include
"exp.hpp"
#include
"FermionOperator.hpp"
#include
"IRProvider.hpp"
#include
"Instruction.hpp"
#include
"ObservableTransform.hpp"
#include
"PauliOperator.hpp"
#include
"Utils.hpp"
#include
"xacc.hpp"
#include
"xacc_service.hpp"
#include
<memory>
...
...
@@ -140,11 +142,11 @@ bool Exp::expand(const HeterogeneousMap ¶meters) {
int
name_counter
=
1
;
std
::
string
name
=
"exp_tmp"
;
while
(
xacc
::
hasCompiled
(
name
))
{
name
+=
std
::
to_string
(
name_counter
);
name
+=
std
::
to_string
(
name_counter
);
}
xasm_src
=
"__qpu__ void "
+
name
+
"(qbit q, double "
+
paramLetter
+
") {
\n
"
+
xasm_src
+
"}"
;
xasm_src
=
"__qpu__ void "
+
name
+
"(qbit q, double "
+
paramLetter
+
") {
\n
"
+
xasm_src
+
"}"
;
auto
xasm
=
xacc
::
getCompiler
(
"xasm"
);
auto
tmp
=
xasm
->
compile
(
xasm_src
)
->
getComposites
()[
0
];
...
...
@@ -153,7 +155,145 @@ bool Exp::expand(const HeterogeneousMap ¶meters) {
addInstruction
(
inst
);
return
true
;
}
// namespace instructions
}
void
Exp
::
applyRuntimeArguments
()
{
// we expect first argument to be the variable name
// we expect the second argument to be the observable
std
::
string
variable_name
=
arguments
[
0
]
->
name
;
auto
x_val
=
arguments
[
0
]
->
runtimeValue
.
get
<
double
>
(
INTERNAL_ARGUMENT_VALUE_KEY
);
auto
observable
=
arguments
[
1
]
->
runtimeValue
.
getPointerLike
<
Observable
>
(
INTERNAL_ARGUMENT_VALUE_KEY
);
// Have to make sure this wasn't already expanded
if
(
nInstructions
()
==
0
)
{
std
::
unordered_map
<
std
::
string
,
xacc
::
quantum
::
Term
>
terms
;
if
(
dynamic_cast
<
FermionOperator
*>
(
observable
))
{
terms
=
std
::
dynamic_pointer_cast
<
PauliOperator
>
(
xacc
::
getService
<
ObservableTransform
>
(
"jw"
)
->
transform
(
xacc
::
as_shared_ptr
(
observable
)))
->
getTerms
();
}
else
{
terms
=
dynamic_cast
<
PauliOperator
*>
(
observable
)
->
getTerms
();
}
double
pi
=
xacc
::
constants
::
pi
;
auto
gateRegistry
=
xacc
::
getService
<
IRProvider
>
(
"quantum"
);
std
::
string
xasm_src
=
""
;
for
(
auto
inst
:
terms
)
{
Term
spinInst
=
inst
.
second
;
// Get the individual pauli terms
auto
termsMap
=
std
::
get
<
2
>
(
spinInst
);
std
::
vector
<
std
::
pair
<
int
,
std
::
string
>>
terms
;
for
(
auto
&
kv
:
termsMap
)
{
if
(
kv
.
second
!=
"I"
&&
!
kv
.
second
.
empty
())
{
terms
.
push_back
({
kv
.
first
,
kv
.
second
});
}
}
// The largest qubit index is on the last term
int
largestQbitIdx
=
terms
[
terms
.
size
()
-
1
].
first
;
std
::
vector
<
std
::
size_t
>
qidxs
;
std
::
stringstream
basis_front
,
basis_back
;
for
(
auto
&
term
:
terms
)
{
auto
qid
=
term
.
first
;
auto
pop
=
term
.
second
;
qidxs
.
push_back
(
qid
);
if
(
pop
==
"X"
)
{
basis_front
<<
"H(q["
<<
qid
<<
"]);
\n
"
;
basis_back
<<
"H(q["
<<
qid
<<
"]);
\n
"
;
}
else
if
(
pop
==
"Y"
)
{
basis_front
<<
"Rx(q["
<<
qid
<<
"], "
<<
1.57079362679
<<
");
\n
"
;
basis_back
<<
"Rx(q["
<<
qid
<<
"], "
<<
-
1.57079362679
<<
");
\n
"
;
}
}
// std::cout << "QIDS: " << qidxs << "\n";
Eigen
::
MatrixXi
cnot_pairs
(
2
,
qidxs
.
size
()
-
1
);
for
(
int
i
=
0
;
i
<
qidxs
.
size
()
-
1
;
i
++
)
{
cnot_pairs
(
0
,
i
)
=
qidxs
[
i
];
}
for
(
int
i
=
0
;
i
<
qidxs
.
size
()
-
1
;
i
++
)
{
cnot_pairs
(
1
,
i
)
=
qidxs
[
i
+
1
];
}
// std::cout << "HOWDY: \n" << cnot_pairs << "\n";
std
::
stringstream
cnot_front
,
cnot_back
;
for
(
int
i
=
0
;
i
<
qidxs
.
size
()
-
1
;
i
++
)
{
Eigen
::
VectorXi
pairs
=
cnot_pairs
.
col
(
i
);
auto
c
=
pairs
(
0
);
auto
t
=
pairs
(
1
);
cnot_front
<<
"CNOT(q["
<<
c
<<
"], q["
<<
t
<<
"]);
\n
"
;
}
for
(
int
i
=
qidxs
.
size
()
-
2
;
i
>=
0
;
i
--
)
{
Eigen
::
VectorXi
pairs
=
cnot_pairs
.
col
(
i
);
auto
c
=
pairs
(
0
);
auto
t
=
pairs
(
1
);
cnot_back
<<
"CNOT(q["
<<
c
<<
"], q["
<<
t
<<
"]);
\n
"
;
}
xasm_src
=
xasm_src
+
"
\n
"
+
basis_front
.
str
()
+
cnot_front
.
str
();
xasm_src
=
xasm_src
+
"Rz(q["
+
std
::
to_string
(
qidxs
[
qidxs
.
size
()
-
1
])
+
"], "
+
std
::
to_string
(
std
::
real
(
spinInst
.
coeff
()))
+
" * "
+
variable_name
+
");
\n
"
;
xasm_src
=
xasm_src
+
cnot_back
.
str
()
+
basis_back
.
str
();
}
int
name_counter
=
1
;
std
::
string
name
=
"exp_tmp"
;
while
(
xacc
::
hasCompiled
(
name
))
{
name
+=
std
::
to_string
(
name_counter
);
}
xasm_src
=
"__qpu__ void "
+
name
+
"(qbit q, double "
+
arguments
[
0
]
->
name
+
") {
\n
"
+
xasm_src
+
"}"
;
auto
xasm
=
xacc
::
getCompiler
(
"xasm"
);
auto
tmp
=
xasm
->
compile
(
xasm_src
)
->
getComposites
()[
0
];
for
(
auto
inst
:
tmp
->
getInstructions
())
addInstruction
(
inst
);
// store the Rz expressions
for
(
auto
&
i
:
instructions
)
{
if
(
i
->
name
()
==
"Rz"
)
{
rz_expressions
.
push_back
(
i
->
getParameter
(
0
).
toString
());
}
}
parsingUtil
=
xacc
::
getService
<
ExpressionParsingUtil
>
(
"exprtk"
);
}
int
counter
=
0
;
for
(
auto
&
i
:
instructions
)
{
if
(
i
->
name
()
==
"Rz"
)
{
double
x_val_ref
=
0.0
;
parsingUtil
->
evaluate
(
rz_expressions
[
counter
],
{
variable_name
},
{
x_val
},
x_val_ref
);
i
->
setParameter
(
0
,
x_val_ref
);
counter
++
;
}
}
}
}
// namespace circuits
}
// namespace xacc
\ No newline at end of file
quantum/plugins/circuits/exp/exp.hpp
View file @
9bafef37
...
...
@@ -14,12 +14,17 @@
#define XACC_GENERATORS_EXP_HPP_
#include
"Circuit.hpp"
#include
<expression_parsing_util.hpp>
namespace
xacc
{
namespace
circuits
{
class
Exp
:
public
xacc
::
quantum
::
Circuit
{
protected:
std
::
vector
<
std
::
string
>
rz_expressions
;
std
::
shared_ptr
<
ExpressionParsingUtil
>
parsingUtil
;
public:
Exp
()
:
Circuit
(
"exp_i_theta"
)
{}
void
applyRuntimeArguments
()
override
;
bool
expand
(
const
xacc
::
HeterogeneousMap
&
runtimeOptions
)
override
;
const
std
::
vector
<
std
::
string
>
requiredKeys
()
override
;
DEFINE_CLONE
(
Exp
);
...
...
quantum/plugins/optimizers/simple/CircuitOptimizer.cpp
View file @
9bafef37
...
...
@@ -138,9 +138,9 @@ void CircuitOptimizer::apply(std::shared_ptr<CompositeInstruction> gateFunction,
for
(
int
i
=
1
;
i
<
graphView
->
order
()
-
2
;
i
++
)
{
auto
node
=
graphView
->
getVertexProperties
(
i
);
if
(
node
.
getString
(
"name"
)
==
"CNOT"
&&
gateFunction
->
getInstruction
(
node
.
get
<
in
t
>
(
"id"
)
-
1
)
gateFunction
->
getInstruction
(
node
.
get
<
std
::
size_
t
>
(
"id"
)
-
1
)
->
isEnabled
())
{
auto
nAsVec
=
graphView
->
getNeighborList
(
node
.
get
<
in
t
>
(
"id"
));
auto
nAsVec
=
graphView
->
getNeighborList
(
node
.
get
<
std
::
size_
t
>
(
"id"
));
// std::vector<int> nAsVec(neighbors.begin(), neighbors.end());
// Note: There is an edge-case if the CNOT is last gate on a pair of qubit wires,
// i.e. both of its neighbors will be the final state node.
...
...
@@ -148,7 +148,7 @@ void CircuitOptimizer::apply(std::shared_ptr<CompositeInstruction> gateFunction,
if
(
nAsVec
[
0
]
==
nAsVec
[
1
]
&&
nAsVec
[
0
]
!=
graphView
->
order
()
-
1
)
{
// Check that the neighbor gate is indeed a CNOT gate, i.e. not a different 2-qubit gate.
if
(
gateFunction
->
getInstruction
(
nAsVec
[
0
]
-
1
)
->
name
()
==
"CNOT"
)
{
gateFunction
->
getInstruction
(
node
.
get
<
in
t
>
(
"id"
)
-
1
)
->
disable
();
gateFunction
->
getInstruction
(
node
.
get
<
std
::
size_
t
>
(
"id"
)
-
1
)
->
disable
();
gateFunction
->
getInstruction
(
nAsVec
[
0
]
-
1
)
->
disable
();
modified
=
true
;
break
;
...
...
@@ -170,13 +170,13 @@ void CircuitOptimizer::apply(std::shared_ptr<CompositeInstruction> gateFunction,
for
(
int
i
=
1
;
i
<
graphView
->
order
()
-
2
;
++
i
)
{
auto
node
=
graphView
->
getVertexProperties
(
i
);
auto
nAsVec
=
graphView
->
getNeighborList
(
node
.
get
<
in
t
>
(
"id"
));
auto
nAsVec
=
graphView
->
getNeighborList
(
node
.
get
<
std
::
size_
t
>
(
"id"
));
// std::vector<int> nAsVec(adj.begin(), adj.end());
if
(
nAsVec
.
size
()
==
1
)
{
auto
nextNode
=
graphView
->
getVertexProperties
(
nAsVec
[
0
]);
if
(
node
.
getString
(
"name"
)
==
"H"
&&
nextNode
.
getString
(
"name"
)
==
"H"
)
{
gateFunction
->
getInstruction
(
node
.
get
<
in
t
>
(
"id"
)
-
1
)
->
disable
();
gateFunction
->
getInstruction
(
node
.
get
<
std
::
size_
t
>
(
"id"
)
-
1
)
->
disable
();
gateFunction
->
getInstruction
(
nAsVec
[
0
]
-
1
)
->
disable
();
modified
=
true
;
break
;
...
...
@@ -199,7 +199,7 @@ void CircuitOptimizer::apply(std::shared_ptr<CompositeInstruction> gateFunction,
// neighbor
for
(
int
i
=
1
;
i
<
graphView
->
order
()
-
2
;
i
++
)
{
auto
node
=
graphView
->
getVertexProperties
(
i
);
auto
nAsVec
=
graphView
->
getNeighborList
(
node
.
get
<
in
t
>
(
"id"
));
auto
nAsVec
=
graphView
->
getNeighborList
(
node
.
get
<
std
::
size_
t
>
(
"id"
));
// if it has more than 1 neighbor, don't consider
if
(
nAsVec
.
size
()
==
1
)
{
auto
nextNode
=
graphView
->
getVertexProperties
(
nAsVec
[
0
]);
...
...
@@ -207,21 +207,21 @@ void CircuitOptimizer::apply(std::shared_ptr<CompositeInstruction> gateFunction,
isRotation
(
nextNode
.
getString
(
"name"
))
&&
node
.
getString
(
"name"
)
==
nextNode
.
getString
(
"name"
))
{
auto
val1
=
ipToDouble
(
gateFunction
->
getInstruction
(
node
.
get
<
in
t
>
(
"id"
)
-
1
)
ipToDouble
(
gateFunction
->
getInstruction
(
node
.
get
<
std
::
size_
t
>
(
"id"
)
-
1
)
->
getParameter
(
0
));
auto
val2
=
ipToDouble
(
gateFunction
->
getInstruction
(
nextNode
.
get
<
in
t
>
(
"id"
)
-
1
)
gateFunction
->
getInstruction
(
nextNode
.
get
<
std
::
size_
t
>
(
"id"
)
-
1
)
->
getParameter
(
0
));
if
(
std
::
fabs
(
val1
+
val2
)
<
1e-12
)
{
gateFunction
->
getInstruction
(
node
.
get
<
in
t
>
(
"id"
)
-
1
)
->
disable
();
gateFunction
->
getInstruction
(
nextNode
.
get
<
in
t
>
(
"id"
)
-
1
)
gateFunction
->
getInstruction
(
node
.
get
<
std
::
size_
t
>
(
"id"
)
-
1
)
->
disable
();
gateFunction
->
getInstruction
(
nextNode
.
get
<
std
::
size_
t
>
(
"id"
)
-
1
)
->
disable
();
}
else
{
InstructionParameter
tmp
(
val1
+
val2
);
gateFunction
->
getInstruction
(
node
.
get
<
in
t
>
(
"id"
)
-
1
)
gateFunction
->
getInstruction
(
node
.
get
<
std
::
size_
t
>
(
"id"
)
-
1
)
->
setParameter
(
0
,
tmp
);
gateFunction
->
getInstruction
(
nextNode
.
get
<
in
t
>
(
"id"
)
-
1
)
gateFunction
->
getInstruction
(
nextNode
.
get
<
std
::
size_
t
>
(
"id"
)
-
1
)
->
disable
();
}
modified
=
true
;
...
...
@@ -302,21 +302,21 @@ bool CircuitOptimizer::tryReduceHadamardGates(std::shared_ptr<CompositeInstructi
// Algorithm: we iterate the circuit until we hit an Hadamard gate,
// then check if the sequence is one of those in Figure 4 of https://arxiv.org/pdf/1710.07345.pdf
auto
graphView
=
io_program
->
toGraph
();
std
::
vector
<
in
t
>
hadamardNodeIds
;
std
::
vector
<
std
::
size_
t
>
hadamardNodeIds
;
// We collect all Hadamard nodes ahead of time for the iteration and matching
for
(
int
i
=
1
;
i
<
graphView
->
order
()
-
1
;
++
i
)
{
const
auto
node
=
graphView
->
getVertexProperties
(
i
);
if
(
node
.
getString
(
"name"
)
==
"H"
)
{
hadamardNodeIds
.
emplace_back
(
node
.
get
<
in
t
>
(
"id"
));
hadamardNodeIds
.
emplace_back
(
node
.
get
<
std
::
size_
t
>
(
"id"
));
}
}
std
::
vector
<
std
::
vector
<
in
t
>>
matchedReductionPatterns
;
std
::
vector
<
std
::
vector
<
std
::
size_
t
>>
matchedReductionPatterns
;
// Set of Hadamard node Ids that have already been matched against a pattern,
// hence no need to match any more to prevent double matching.
// The below matching is constructed to prioritize patterns that result in more
// gate count reduction, hence we want to keep track of which H gates have already been matched.
std
::
unordered_set
<
in
t
>
matchedHadamardNodeIds
;
std
::
unordered_set
<
std
::
size_
t
>
matchedHadamardNodeIds
;
for
(
const
auto
&
hadamardNode
:
hadamardNodeIds
)
{
if
(
container
::
contains
(
matchedHadamardNodeIds
,
hadamardNode
))
{
...
...
@@ -339,14 +339,14 @@ bool CircuitOptimizer::tryReduceHadamardGates(std::shared_ptr<CompositeInstructi
// |
// |