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
qcor
Commits
09cc54bc
Commit
09cc54bc
authored
Sep 14, 2021
by
Nguyen, Thien Minh
Browse files
Handle clifford gates
Signed-off-by:
Thien Nguyen
<
nguyentm@ornl.gov
>
parent
c5e99b56
Changes
2
Hide whitespace changes
Inline
Side-by-side
lib/mirror_rb/mirror_circuit_rb.cpp
View file @
09cc54bc
...
...
@@ -36,9 +36,8 @@ createMirrorCircuit(std::shared_ptr<CompositeInstruction> in_circuit) {
std
::
vector
<
qcor
::
utils
::
PauliLabel
>
net_paulis
(
n
,
qcor
::
utils
::
PauliLabel
::
I
);
// Sympletic group for Pauli gates:
const
auto
srep_dict
=
qcor
::
utils
::
computeGateSymplecticRepresentations
({
"I"
,
"X"
,
"Y"
,
"Z"
});
// Sympletic group
const
auto
srep_dict
=
qcor
::
utils
::
computeGateSymplecticRepresentations
();
const
auto
pauliListToLayer
=
[](
const
std
::
vector
<
qcor
::
utils
::
PauliLabel
>
&
in_paulis
)
{
...
...
@@ -83,12 +82,14 @@ createMirrorCircuit(std::shared_ptr<CompositeInstruction> in_circuit) {
return
gateProvider
->
createInstruction
(
"U"
,
{
qubit
},
{
theta2
-
M_PI
,
theta3
-
3.0
*
M_PI
,
theta1
});
};
static
const
std
::
vector
<
std
::
string
>
SELF_ADJOINT_CLIFFORD_GATES
{
"H"
,
"X"
,
"Y"
,
"Z"
,
"CNOT"
,
"Swap"
};
const
auto
d
=
in_circuit
->
depth
();
for
(
int
layer
=
d
-
1
;
layer
>=
0
;
--
layer
)
{
auto
current_layers
=
getLayer
(
in_circuit
->
as_xacc
(),
layer
);
for
(
const
auto
&
gate
:
current_layers
)
{
// Only handle "U3" gate for now.
// TODO: convert all single-qubit gates to U3
// TODO: convert all single-qubit
rotation
gates to U3
if
(
gate
->
name
()
==
"U"
)
{
const
auto
u3_angles
=
decomposeU3Angle
(
gate
);
const
auto
[
theta1_inv
,
theta2_inv
,
theta3_inv
]
=
...
...
@@ -97,6 +98,10 @@ createMirrorCircuit(std::shared_ptr<CompositeInstruction> in_circuit) {
in_circuit
->
addInstruction
(
gateProvider
->
createInstruction
(
"U"
,
{
qubit
},
{
theta2_inv
-
M_PI
,
theta1_inv
-
3.0
*
M_PI
,
theta3_inv
}));
}
else
if
(
xacc
::
container
::
contains
(
SELF_ADJOINT_CLIFFORD_GATES
,
gate
->
name
()))
{
// Handle Clifford gates:
in_circuit
->
addInstruction
(
gate
->
clone
());
}
}
}
...
...
@@ -125,27 +130,45 @@ createMirrorCircuit(std::shared_ptr<CompositeInstruction> in_circuit) {
return
random_paulis
;
}(
n
);
const
auto
new_paulis_as_layer
=
pauliListToLayer
(
new_paulis
);
const
auto
current_net_paulis_as_layer
=
pauliListToLayer
(
net_paulis
);
const
auto
new_net_paulis_reps
=
qcor
::
utils
::
computeCircuitSymplecticRepresentations
(
{
new_paulis_as_layer
,
current_net_paulis_as_layer
},
n
,
srep_dict
);
// Update the tracking net
net_paulis
=
qcor
::
utils
::
find_pauli_labels
(
new_net_paulis_reps
.
second
);
{
std
::
stringstream
ss
;
ss
<<
"Net Pauli: "
;
for
(
const
auto
&
p
:
net_paulis
)
{
ss
<<
p
<<
" "
;
const
auto
gateToLayerInfo
=
[](
xacc
::
InstPtr
gate
,
int
nbQubits
)
{
qcor
::
utils
::
CliffordGateLayer_t
result
;
std
::
vector
<
int
>
operands
;
for
(
const
auto
&
bit
:
gate
->
bits
())
{
operands
.
emplace_back
(
bit
);
}
for
(
int
i
=
0
;
i
<
nbQubits
;
++
i
)
{
if
(
!
xacc
::
container
::
contains
(
operands
,
i
))
{
result
.
emplace_back
(
std
::
make_pair
(
"I"
,
std
::
vector
<
int
>
{
i
}));
}
}
xacc
::
info
(
ss
.
str
());
}
result
.
emplace_back
(
std
::
make_pair
(
gate
->
name
(),
operands
));
return
result
;
};
const
auto
current_net_paulis_as_layer
=
pauliListToLayer
(
net_paulis
);
for
(
const
auto
&
gate
:
current_layers
)
{
// Only handle "U3" gate for now.
// TODO: convert all single-qubit gates to U3
if
(
gate
->
name
()
==
"U"
)
{
const
auto
new_paulis_as_layer
=
pauliListToLayer
(
new_paulis
);
const
auto
new_net_paulis_reps
=
qcor
::
utils
::
computeCircuitSymplecticRepresentations
(
{
new_paulis_as_layer
,
current_net_paulis_as_layer
},
n
,
srep_dict
);
// Update the tracking net
net_paulis
=
qcor
::
utils
::
find_pauli_labels
(
new_net_paulis_reps
.
second
);
{
std
::
stringstream
ss
;
ss
<<
"Net Pauli: "
;
for
(
const
auto
&
p
:
net_paulis
)
{
ss
<<
p
<<
" "
;
}
xacc
::
info
(
ss
.
str
());
}
const
size_t
qubit
=
gate
->
bits
()[
0
];
const
auto
[
theta1
,
theta2
,
theta3
]
=
decomposeU3Angle
(
gate
);
// Compute the pseudo_inverse gate:
...
...
@@ -155,6 +178,27 @@ createMirrorCircuit(std::shared_ptr<CompositeInstruction> in_circuit) {
net_paulis
[
qubit
]);
mirrorCircuit
.
emplace_back
(
createU3GateFromAngle
(
qubit
,
theta1_new
,
theta2_new
,
theta3_new
));
}
else
if
(
xacc
::
container
::
contains
(
SELF_ADJOINT_CLIFFORD_GATES
,
gate
->
name
()))
{
mirrorCircuit
.
emplace_back
(
gate
->
clone
());
// we need to account for how the net pauli changes when it gets passed
// through the clifford layers
const
auto
new_net_paulis_reps
=
qcor
::
utils
::
computeCircuitSymplecticRepresentations
(
{
gateToLayerInfo
(
gate
,
n
),
current_net_paulis_as_layer
,
gateToLayerInfo
(
gate
,
n
)},
n
,
srep_dict
);
// Update the tracking net
net_paulis
=
qcor
::
utils
::
find_pauli_labels
(
new_net_paulis_reps
.
second
);
{
std
::
stringstream
ss
;
ss
<<
"Net Pauli: "
;
for
(
const
auto
&
p
:
net_paulis
)
{
ss
<<
p
<<
" "
;
}
xacc
::
info
(
ss
.
str
());
}
}
}
}
...
...
lib/mirror_rb/tests/MirrorCircuitTester.cpp
View file @
09cc54bc
...
...
@@ -90,6 +90,49 @@ TEST(MirrorCircuitTester, checkMultipleU3) {
EXPECT_EQ
(
allBitStrings
.
size
(),
4
);
}
TEST
(
MirrorCircuitTester
,
checkCliffordGates
)
{
auto
provider
=
xacc
::
getIRProvider
(
"quantum"
);
constexpr
int
NUM_TESTS
=
1000
;
auto
accelerator
=
xacc
::
getAccelerator
(
"qpp"
,
{{
"shots"
,
1024
}});
std
::
set
<
std
::
string
>
allBitStrings
;
for
(
int
i
=
0
;
i
<
NUM_TESTS
;
++
i
)
{
auto
circuit
=
provider
->
createComposite
(
std
::
string
(
"test"
)
+
std
::
to_string
(
i
));
const
double
theta1
=
random_angle
();
const
double
phi1
=
random_angle
();
const
double
lambda1
=
random_angle
();
circuit
->
addInstruction
(
provider
->
createInstruction
(
"U"
,
{
0
},
std
::
vector
<
xacc
::
InstructionParameter
>
{
theta1
,
phi1
,
lambda1
}));
const
double
theta2
=
random_angle
();
const
double
phi2
=
random_angle
();
const
double
lambda2
=
random_angle
();
circuit
->
addInstruction
(
provider
->
createInstruction
(
"U"
,
{
1
},
std
::
vector
<
xacc
::
InstructionParameter
>
{
theta2
,
phi2
,
lambda2
}));
circuit
->
addInstruction
(
provider
->
createInstruction
(
"CNOT"
,
{
0
,
1
}));
circuit
->
addInstruction
(
provider
->
createInstruction
(
"H"
,
{
0
}));
circuit
->
addInstruction
(
provider
->
createInstruction
(
"H"
,
{
1
}));
auto
[
mirror_cir
,
expected_result
]
=
qcor
::
createMirrorCircuit
(
std
::
make_shared
<
qcor
::
CompositeInstruction
>
(
circuit
));
const
std
::
string
expectedBitString
=
std
::
to_string
(
expected_result
[
0
])
+
std
::
to_string
(
expected_result
[
1
]);
std
::
cout
<<
"HOWDY:
\n
"
<<
mirror_cir
->
toString
()
<<
"
\n
"
;
std
::
cout
<<
"Expected bitstring: "
<<
expectedBitString
<<
"
\n
"
;
auto
mirror_circuit
=
provider
->
createComposite
(
"test_mirror"
);
mirror_circuit
->
addInstructions
(
mirror_cir
->
getInstructions
());
mirror_circuit
->
addInstruction
(
provider
->
createInstruction
(
"Measure"
,
{
0
}));
mirror_circuit
->
addInstruction
(
provider
->
createInstruction
(
"Measure"
,
{
1
}));
auto
mc_buffer
=
xacc
::
qalloc
(
2
);
accelerator
->
execute
(
mc_buffer
,
mirror_circuit
);
mc_buffer
->
print
();
EXPECT_EQ
(
mc_buffer
->
getMeasurementCounts
().
size
(),
1
);
EXPECT_EQ
(
mc_buffer
->
getMeasurementCounts
()[
expectedBitString
],
1024
);
allBitStrings
.
emplace
(
expectedBitString
);
}
// Cover both cases (randomized Pauli worked)
EXPECT_EQ
(
allBitStrings
.
size
(),
4
);
}
int
main
(
int
argc
,
char
**
argv
)
{
xacc
::
Initialize
();
::
testing
::
InitGoogleTest
(
&
argc
,
argv
);
...
...
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