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
e9ed2672
Commit
e9ed2672
authored
May 22, 2020
by
Mccaskey, Alex
Browse files
Merge branch 'master' of
https://github.com/eclipse/xacc
parents
d9c7457a
f0b0b4ed
Pipeline
#103415
passed with stage
in 8 minutes and 18 seconds
Changes
16
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
docs/source/extensions.rst
View file @
e9ed2672
...
...
@@ -1089,6 +1089,137 @@ In Python:
print
(
'Min QUBO value = '
,
buffer
.
getInformation
(
'opt-val'
))
Quantum
Phase
Estimation
++++++++++++++++++++++++
The
``
QPE
``
algorithm
(
also
known
as
quantum
eigenvalue
estimation
algorithm
)
provides
an
implementation
of
Algorithm
that
estimates
the
phase
(
or
eigenvalue
)
of
an
eigenvector
of
a
unitary
operator
.
Here
the
unitary
operator
is
called
an
`
oracle
`
which
is
a
quantum
subroutine
that
acts
upon
a
set
of
qubits
and
returns
the
answer
as
a
phase
.
The
bits
precision
is
automatically
inferred
from
the
size
of
the
input
buffer
.
+------------------------+------------------------------------------------------------------------+------------------------------------------+
|
Algorithm
Parameter
|
Parameter
Description
|
type
|
+========================+========================================================================+==========================================+
|
oracle
|
The
circuit
represents
the
unitary
operator
.
|
pointer
-
like
CompositeInstruction
|
+------------------------+------------------------------------------------------------------------+------------------------------------------+
|
accelerator
|
The
backend
quantum
computer
to
use
.
|
pointer
-
like
Accelerator
|
+------------------------+------------------------------------------------------------------------+------------------------------------------+
|
state
-
preparation
|
The
circuit
to
prepare
the
eigen
state
.
|
pointer
-
like
CompositeInstruction
|
+------------------------+------------------------------------------------------------------------+------------------------------------------+
..
code
::
cpp
#
include
"xacc.hpp"
#
include
"xacc_service.hpp"
int
main
(
int
argc
,
char
**
argv
)
{
xacc
::
Initialize
(
argc
,
argv
);
//
Accelerator
:
auto
acc
=
xacc
::
getAccelerator
(
"qpp"
,
{
std
::
make_pair
(
"shots"
,
4096
)});
//
In
this
example
:
we
want
to
estimate
the
*
phase
*
of
an
arbitrary
'oracle'
//
i
.
e
.
Oracle
(|
State
>)
=
exp
(
i
*
Phase
)*|
State
>
//
and
we
need
to
estimate
that
Phase
.
//
Oracle
:
CPhase
(
theta
)
or
CU1
(
theta
)
which
is
defined
as
//
1
0
0
0
//
0
1
0
0
//
0
0
1
0
//
0
0
0
e
^(
i
*
theta
)
//
The
eigenstate
is
|
11
>;
i
.
e
.
CPhase
(
theta
)|
11
>
=
e
^(
i
*
theta
)|
11
>
//
Since
this
oracle
operates
on
2
qubits
,
we
need
to
add
more
qubits
to
the
buffer
.
//
The
more
qubits
we
have
,
the
more
accurate
the
estimate
.
//
Resolution
:=
2
^(
number
qubits
in
the
calculation
register
).
//
5
-
bit
precision
=>
7
qubits
in
total
auto
buffer
=
xacc
::
qalloc
(
7
);
auto
qpe
=
xacc
::
getService
<
xacc
::
Algorithm
>(
"QPE"
);
auto
compiler
=
xacc
::
getCompiler
(
"xasm"
);
//
Create
oracle
:
CPhase
gate
with
theta
=
2
pi
/
3
//
i
.
e
.
the
phase
value
to
estimate
is
1
/
3
~
0.33333
.
auto
gateRegistry
=
xacc
::
getService
<
xacc
::
IRProvider
>(
"quantum"
);
auto
oracle
=
gateRegistry
->
createComposite
(
"oracle"
);
oracle
->
addInstruction
(
gateRegistry
->
createInstruction
(
"CPhase"
,
{
0
,
1
},
{
2.0
*
M_PI
/
3.0
}));
//
Eigenstate
preparation
=
|
11
>
state
auto
statePrep
=
compiler
->
compile
(
R
"(__qpu__ void prep1(qbit q) {
X(q[0]);
X(q[1]);
})"
,
nullptr
)->
getComposite
(
"prep1"
);
//
Initialize
the
Quantum
Phase
Estimation
:
qpe
->
initialize
({
std
::
make_pair
(
"accelerator"
,
acc
),
std
::
make_pair
(
"oracle"
,
oracle
),
std
::
make_pair
(
"state-preparation"
,
statePrep
)
});
//
Run
the
algorithm
qpe
->
execute
(
buffer
);
//
Expected
result
:
//
The
factor
here
is
2
^
5
(
precision
)
=
32
//
we
expect
the
two
most
-
likely
bitstring
is
10
and
11
//
i
.
e
.
the
true
result
is
between
10
/
32
=
0.3125
and
11
/
32
=
0.34375
std
::
cout
<<
"Probability of the two most-likely bitstrings 10 (theta = 0.3125) and 11 (theta = 0.34375 ):
\n
"
;
std
::
cout
<<
"Probability of |11010> (11) = "
<<
buffer
->
computeMeasurementProbability
(
"11010"
)
<<
"
\n
"
;
std
::
cout
<<
"Probability of |01010> (10) = "
<<
buffer
->
computeMeasurementProbability
(
"01010"
)
<<
"
\n
"
;
xacc
::
Finalize
();
}
or
in
Python
..
code
::
python
import
xacc
,
sys
,
numpy
as
np
#
Get
access
to
the
desired
QPU
and
#
allocate
some
qubits
to
run
on
qpu
=
xacc
.
getAccelerator
(
'qpp'
,
{
'shots'
:
4096
})
#
In
this
example
:
we
want
to
estimate
the
*
phase
*
of
an
arbitrary
'oracle'
#
i
.
e
.
Oracle
(|
State
>)
=
exp
(
i
*
Phase
)*|
State
>
#
and
we
need
to
estimate
that
Phase
.
#
The
oracle
is
a
simple
T
gate
,
and
the
eigenstate
is
|
1
>
#
T
|
1
>
=
e
^(
i
*
pi
/
4
)|
1
>
#
The
phase
value
of
pi
/
4
=
2
pi
*
(
1
/
8
)
#
i
.
e
.
if
we
use
a
3
-
bit
register
for
estimation
,
#
we
will
get
the
correct
answer
of
1
deterministically
.
xacc
.
qasm
(
'''.compiler xasm
.circuit oracle
.qbit q
T(q[0]);
'''
)
oracle
=
xacc
.
getCompiled
(
'oracle'
)
#
We
need
to
prepare
the
eigenstate
|
1
>
xacc
.
qasm
(
'''.compiler xasm
.circuit prep
.qbit q
X(q[0]);
'''
)
statePrep
=
xacc
.
getCompiled
(
'prep'
)
#
We
need
4
qubits
(
3
-
bit
precision
)
buffer
=
xacc
.
qalloc
(
4
)
#
Create
the
QPE
algorithm
qpe
=
xacc
.
getAlgorithm
(
'QPE'
,
{
'accelerator'
:
qpu
,
'oracle'
:
oracle
,
'state-preparation'
:
statePrep
})
qpe
.
execute
(
buffer
)
#
We
should
only
get
the
bit
string
of
|
100
>
=
1
#
i
.
e
.
phase
value
of
1
/
2
^
3
=
1
/
8.
print
(
buffer
)
Accelerator
Decorators
----------------------
ROErrorDecorator
...
...
python/examples/quantum_phase_estimation.py
0 → 100644
View file @
e9ed2672
import
xacc
,
sys
,
numpy
as
np
# Get access to the desired QPU and
# allocate some qubits to run on
qpu
=
xacc
.
getAccelerator
(
'qpp'
,
{
'shots'
:
4096
})
# In this example: we want to estimate the *phase* of an arbitrary 'oracle'
# i.e. Oracle(|State>) = exp(i*Phase)*|State>
# and we need to estimate that Phase.
# The oracle is a simple T gate, and the eigenstate is |1>
# T|1> = e^(i*pi/4)|1>
# The phase value of pi/4 = 2pi * (1/8)
# i.e. if we use a 3-bit register for estimation,
# we will get the correct answer of 1 deterministically.
xacc
.
qasm
(
'''.compiler xasm
.circuit oracle
.qbit q
T(q[0]);
'''
)
oracle
=
xacc
.
getCompiled
(
'oracle'
)
# We need to prepare the eigenstate |1>
xacc
.
qasm
(
'''.compiler xasm
.circuit prep
.qbit q
X(q[0]);
'''
)
statePrep
=
xacc
.
getCompiled
(
'prep'
)
# We need 4 qubits (3-bit precision)
buffer
=
xacc
.
qalloc
(
4
)
# Create the QPE algorithm
qpe
=
xacc
.
getAlgorithm
(
'QPE'
,
{
'accelerator'
:
qpu
,
'oracle'
:
oracle
,
'state-preparation'
:
statePrep
})
qpe
.
execute
(
buffer
)
# We should only get the bit string of |100> = 1
# i.e. phase value of 1/2^3 = 1/8.
print
(
buffer
)
\ No newline at end of file
quantum/examples/qasm/CMakeLists.txt
View file @
e9ed2672
...
...
@@ -35,3 +35,6 @@ 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
)
add_executable
(
quantum_phase_estimation quantum_phase_estimation.cpp
)
target_link_libraries
(
quantum_phase_estimation PRIVATE xacc xacc-quantum-gate
)
quantum/examples/qasm/quantum_phase_estimation.cpp
0 → 100644
View file @
e9ed2672
/*******************************************************************************
* 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_service.hpp"
int
main
(
int
argc
,
char
**
argv
)
{
xacc
::
Initialize
(
argc
,
argv
);
// Accelerator:
auto
acc
=
xacc
::
getAccelerator
(
"qpp"
,
{
std
::
make_pair
(
"shots"
,
4096
)});
// In this example: we want to estimate the *phase* of an arbitrary 'oracle'
// i.e. Oracle(|State>) = exp(i*Phase)*|State>
// and we need to estimate that Phase.
// Oracle: CPhase(theta) or CU1(theta) which is defined as
// 1 0 0 0
// 0 1 0 0
// 0 0 1 0
// 0 0 0 e^(i*theta)
// The eigenstate is |11>; i.e. CPhase(theta)|11> = e^(i*theta)|11>
// Since this oracle operates on 2 qubits, we need to add more qubits to the buffer.
// The more qubits we have, the more accurate the estimate.
// Resolution := 2^(number qubits in the calculation register).
// 5-bit precision => 7 qubits in total
auto
buffer
=
xacc
::
qalloc
(
7
);
auto
qpe
=
xacc
::
getService
<
xacc
::
Algorithm
>
(
"QPE"
);
auto
compiler
=
xacc
::
getCompiler
(
"xasm"
);
// Create oracle: CPhase gate with theta = 2pi/3
// i.e. the phase value to estimate is 1/3 ~ 0.33333.
auto
gateRegistry
=
xacc
::
getService
<
xacc
::
IRProvider
>
(
"quantum"
);
auto
oracle
=
gateRegistry
->
createComposite
(
"oracle"
);
oracle
->
addInstruction
(
gateRegistry
->
createInstruction
(
"CPhase"
,
{
0
,
1
},
{
2.0
*
M_PI
/
3.0
}));
// Eigenstate preparation = |11> state
auto
statePrep
=
compiler
->
compile
(
R"(__qpu__ void prep1(qbit q) {
X(q[0]);
X(q[1]);
})"
,
nullptr
)
->
getComposite
(
"prep1"
);
// Initialize the Quantum Phase Estimation:
qpe
->
initialize
({
std
::
make_pair
(
"accelerator"
,
acc
),
std
::
make_pair
(
"oracle"
,
oracle
),
std
::
make_pair
(
"state-preparation"
,
statePrep
)
});
// Run the algorithm
qpe
->
execute
(
buffer
);
// Expected result:
// The factor here is 2^5 (precision) = 32
// we expect the two most-likely bitstring is 10 and 11
// i.e. the true result is between 10/32 = 0.3125 and 11/32 = 0.34375
std
::
cout
<<
"Probability of the two most-likely bitstrings 10 (theta = 0.3125) and 11 (theta = 0.34375 ):
\n
"
;
std
::
cout
<<
"Probability of |11010> (11) = "
<<
buffer
->
computeMeasurementProbability
(
"11010"
)
<<
"
\n
"
;
std
::
cout
<<
"Probability of |01010> (10) = "
<<
buffer
->
computeMeasurementProbability
(
"01010"
)
<<
"
\n
"
;
xacc
::
Finalize
();
}
\ No newline at end of file
quantum/plugins/algorithms/CMakeLists.txt
View file @
e9ed2672
...
...
@@ -16,6 +16,7 @@ add_subdirectory(ml)
add_subdirectory
(
rotoselect
)
add_subdirectory
(
qpt
)
add_subdirectory
(
qaoa
)
add_subdirectory
(
qpe
)
file
(
GLOB PYDECORATORS
${
CMAKE_CURRENT_SOURCE_DIR
}
/vqe/python/*.py
${
CMAKE_CURRENT_SOURCE_DIR
}
/ml/ddcl/python/*.py
)
...
...
quantum/plugins/algorithms/qpe/CMakeLists.txt
0 → 100644
View file @
e9ed2672
# *******************************************************************************
# 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 v.10 which accompany 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
# *******************************************************************************/
set
(
LIBRARY_NAME xacc-algorithm-qpe
)
file
(
GLOB SRC *.cpp
)
usfunctiongetresourcesource
(
TARGET
${
LIBRARY_NAME
}
OUT SRC
)
usfunctiongeneratebundleinit
(
TARGET
${
LIBRARY_NAME
}
OUT SRC
)
add_library
(
${
LIBRARY_NAME
}
SHARED
${
SRC
}
)
target_include_directories
(
${
LIBRARY_NAME
}
PUBLIC .
)
target_link_libraries
(
${
LIBRARY_NAME
}
PUBLIC xacc CppMicroServices xacc-quantum-gate
)
set
(
_bundle_name xacc_algorithm_qpe
)
set_target_properties
(
${
LIBRARY_NAME
}
PROPERTIES COMPILE_DEFINITIONS
US_BUNDLE_NAME=
${
_bundle_name
}
US_BUNDLE_NAME
${
_bundle_name
}
)
usfunctionembedresources
(
TARGET
${
LIBRARY_NAME
}
WORKING_DIRECTORY
${
CMAKE_CURRENT_SOURCE_DIR
}
FILES
manifest.json
)
if
(
APPLE
)
set_target_properties
(
${
LIBRARY_NAME
}
PROPERTIES INSTALL_RPATH
"@loader_path/../lib"
)
set_target_properties
(
${
LIBRARY_NAME
}
PROPERTIES LINK_FLAGS
"-undefined dynamic_lookup"
)
else
()
set_target_properties
(
${
LIBRARY_NAME
}
PROPERTIES INSTALL_RPATH
"$ORIGIN/../lib"
)
set_target_properties
(
${
LIBRARY_NAME
}
PROPERTIES LINK_FLAGS
"-shared"
)
endif
()
if
(
XACC_BUILD_TESTS
)
add_subdirectory
(
tests
)
endif
()
install
(
TARGETS
${
LIBRARY_NAME
}
DESTINATION
${
CMAKE_INSTALL_PREFIX
}
/plugins
)
quantum/plugins/algorithms/qpe/ControlledGateApplicator.cpp
0 → 100644
View file @
e9ed2672
/*******************************************************************************
* 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
"ControlledGateApplicator.hpp"
namespace
xacc
{
namespace
circuits
{
bool
ControlledU
::
expand
(
const
xacc
::
HeterogeneousMap
&
runtimeOptions
)
{
if
(
!
runtimeOptions
.
keyExists
<
int
>
(
"control-idx"
))
{
xacc
::
error
(
"'control-idx' is required."
);
return
false
;
}
const
auto
ctrlIdx
=
runtimeOptions
.
get
<
int
>
(
"control-idx"
);
if
(
!
runtimeOptions
.
pointerLikeExists
<
CompositeInstruction
>
(
"U"
))
{
xacc
::
error
(
"'U' composite is required."
);
return
false
;
}
auto
uComposite
=
std
::
shared_ptr
<
CompositeInstruction
>
(
runtimeOptions
.
getPointerLike
<
CompositeInstruction
>
(
"U"
),
xacc
::
empty_delete
<
CompositeInstruction
>
());
auto
ctrlU
=
applyControl
(
uComposite
,
ctrlIdx
);
for
(
int
instId
=
0
;
instId
<
ctrlU
->
nInstructions
();
++
instId
)
{
addInstruction
(
ctrlU
->
getInstruction
(
instId
)
->
clone
());
}
return
true
;
}
std
::
shared_ptr
<
xacc
::
CompositeInstruction
>
ControlledU
::
applyControl
(
const
std
::
shared_ptr
<
xacc
::
CompositeInstruction
>&
in_program
,
int
in_ctrlIdx
)
{
m_gateProvider
=
xacc
::
getService
<
xacc
::
IRProvider
>
(
"quantum"
);
m_composite
=
m_gateProvider
->
createComposite
(
"CTRL_"
+
in_program
->
name
()
+
"_"
+
std
::
to_string
(
in_ctrlIdx
));
m_ctrlIdx
=
in_ctrlIdx
;
InstructionIterator
it
(
in_program
);
while
(
it
.
hasNext
())
{
auto
nextInst
=
it
.
next
();
if
(
nextInst
->
isEnabled
())
{
nextInst
->
accept
(
this
);
}
}
return
m_composite
;
}
void
ControlledU
::
visit
(
Hadamard
&
h
)
{
if
(
h
.
bits
()[
0
]
==
m_ctrlIdx
)
{
xacc
::
error
(
"Control bit must be different from target qubit(s)."
);
}
else
{
const
auto
targetIdx
=
h
.
bits
()[
0
];
// CH
m_composite
->
addInstruction
(
m_gateProvider
->
createInstruction
(
"CH"
,
{
m_ctrlIdx
,
targetIdx
}));
}
}
void
ControlledU
::
visit
(
X
&
x
)
{
if
(
x
.
bits
()[
0
]
==
m_ctrlIdx
)
{
xacc
::
error
(
"Control bit must be different from target qubit(s)."
);
}
else
{
const
auto
targetIdx
=
x
.
bits
()[
0
];
// CNOT
m_composite
->
addInstruction
(
m_gateProvider
->
createInstruction
(
"CX"
,
{
m_ctrlIdx
,
targetIdx
}));
}
}
void
ControlledU
::
visit
(
Y
&
y
)
{
if
(
y
.
bits
()[
0
]
==
m_ctrlIdx
)
{
xacc
::
error
(
"Control bit must be different from target qubit(s)."
);
}
else
{
const
auto
targetIdx
=
y
.
bits
()[
0
];
// CY
m_composite
->
addInstruction
(
m_gateProvider
->
createInstruction
(
"CY"
,
{
m_ctrlIdx
,
targetIdx
}));
}
}
void
ControlledU
::
visit
(
Z
&
z
)
{
if
(
z
.
bits
()[
0
]
==
m_ctrlIdx
)
{
xacc
::
error
(
"Control bit must be different from target qubit(s)."
);
}
else
{
const
auto
targetIdx
=
z
.
bits
()[
0
];
// CZ
m_composite
->
addInstruction
(
m_gateProvider
->
createInstruction
(
"CZ"
,
{
m_ctrlIdx
,
targetIdx
}));
}
}
void
ControlledU
::
visit
(
CNOT
&
cnot
)
{
// CCNOT gate:
// We now have two control bits
const
auto
ctrlIdx1
=
cnot
.
bits
()[
0
];
const
auto
ctrlIdx2
=
m_ctrlIdx
;
// Target qubit
const
auto
targetIdx
=
cnot
.
bits
()[
1
];
m_composite
->
addInstruction
(
m_gateProvider
->
createInstruction
(
"H"
,
{
targetIdx
}));
m_composite
->
addInstruction
(
m_gateProvider
->
createInstruction
(
"CX"
,
{
ctrlIdx1
,
targetIdx
}));
m_composite
->
addInstruction
(
m_gateProvider
->
createInstruction
(
"Tdg"
,
{
targetIdx
}));
m_composite
->
addInstruction
(
m_gateProvider
->
createInstruction
(
"Tdg"
,
{
targetIdx
}));
m_composite
->
addInstruction
(
m_gateProvider
->
createInstruction
(
"CX"
,
{
ctrlIdx2
,
targetIdx
}));
m_composite
->
addInstruction
(
m_gateProvider
->
createInstruction
(
"T"
,
{
targetIdx
}));
m_composite
->
addInstruction
(
m_gateProvider
->
createInstruction
(
"CX"
,
{
ctrlIdx1
,
targetIdx
}));
m_composite
->
addInstruction
(
m_gateProvider
->
createInstruction
(
"Tdg"
,
{
targetIdx
}));
m_composite
->
addInstruction
(
m_gateProvider
->
createInstruction
(
"CX"
,
{
ctrlIdx2
,
targetIdx
}));
m_composite
->
addInstruction
(
m_gateProvider
->
createInstruction
(
"T"
,
{
ctrlIdx1
}));
m_composite
->
addInstruction
(
m_gateProvider
->
createInstruction
(
"T"
,
{
targetIdx
}));
m_composite
->
addInstruction
(
m_gateProvider
->
createInstruction
(
"H"
,
{
targetIdx
}));
m_composite
->
addInstruction
(
m_gateProvider
->
createInstruction
(
"CX"
,
{
ctrlIdx2
,
ctrlIdx1
}));
m_composite
->
addInstruction
(
m_gateProvider
->
createInstruction
(
"T"
,
{
ctrlIdx2
}));
m_composite
->
addInstruction
(
m_gateProvider
->
createInstruction
(
"Tdg"
,
{
ctrlIdx1
}));
m_composite
->
addInstruction
(
m_gateProvider
->
createInstruction
(
"CX"
,
{
ctrlIdx2
,
ctrlIdx1
}));
}
void
ControlledU
::
visit
(
Rx
&
rx
)
{
// CRn(theta) = Rn(theta/2) - CX - Rn(-theta/2) - CX
if
(
rx
.
bits
()[
0
]
==
m_ctrlIdx
)
{
xacc
::
error
(
"Control bit must be different from target qubit(s)."
);
}
else
{
const
auto
targetIdx
=
rx
.
bits
()[
0
];
const
auto
angle
=
InstructionParameterToDouble
(
rx
.
getParameter
(
0
));
m_composite
->
addInstruction
(
m_gateProvider
->
createInstruction
(
"Rx"
,
{
targetIdx
},
{
angle
/
2.0
}));
m_composite
->
addInstruction
(
m_gateProvider
->
createInstruction
(
"CX"
,
{
m_ctrlIdx
,
targetIdx
}));
m_composite
->
addInstruction
(
m_gateProvider
->
createInstruction
(
"Rx"
,
{
targetIdx
},
{
-
angle
/
2.0
}));
m_composite
->
addInstruction
(
m_gateProvider
->
createInstruction
(
"CX"
,
{
m_ctrlIdx
,
targetIdx
}));
}
}
void
ControlledU
::
visit
(
Ry
&
ry
)
{
// CRn(theta) = Rn(theta/2) - CX - Rn(-theta/2) - CX
if
(
ry
.
bits
()[
0
]
==
m_ctrlIdx
)
{
xacc
::
error
(
"Control bit must be different from target qubit(s)."
);
}
else
{
const
auto
targetIdx
=
ry
.
bits
()[
0
];
const
auto
angle
=
InstructionParameterToDouble
(
ry
.
getParameter
(
0
));
m_composite
->
addInstruction
(
m_gateProvider
->
createInstruction
(
"Ry"
,
{
targetIdx
},
{
angle
/
2.0
}));
m_composite
->
addInstruction
(
m_gateProvider
->
createInstruction
(
"CX"
,
{
m_ctrlIdx
,
targetIdx
}));
m_composite
->
addInstruction
(
m_gateProvider
->
createInstruction
(
"Ry"
,
{
targetIdx
},
{
-
angle
/
2.0
}));
m_composite
->
addInstruction
(
m_gateProvider
->
createInstruction
(
"CX"
,
{
m_ctrlIdx
,
targetIdx
}));
}
}
void
ControlledU
::
visit
(
Rz
&
rz
)
{
if
(
rz
.
bits
()[
0
]
==
m_ctrlIdx
)
{
xacc
::
error
(
"Control bit must be different from target qubit(s)."
);
}
else
{
const
auto
targetIdx
=
rz
.
bits
()[
0
];
const
auto
angle
=
InstructionParameterToDouble
(
rz
.
getParameter
(
0
));
// CRz
m_composite
->
addInstruction
(
m_gateProvider
->
createInstruction
(
"CRZ"
,
{
m_ctrlIdx
,
targetIdx
},
{
angle
}));
}
}
void
ControlledU
::
visit
(
S
&
s
)
{
// Ctrl-S = CPhase(pi/2)
const
auto
targetIdx
=
s
.
bits
()[
0
];
m_composite
->
addInstruction
(
m_gateProvider
->
createInstruction
(
"CPhase"
,
{
m_ctrlIdx
,
targetIdx
},
{
M_PI_2
}));
}
void
ControlledU
::
visit
(
Sdg
&
sdg
)
{
// Ctrl-Sdg = CPhase(-pi/2)
const
auto
targetIdx
=
sdg
.
bits
()[
0
];
m_composite
->
addInstruction
(
m_gateProvider
->
createInstruction
(
"CPhase"
,
{
m_ctrlIdx
,
targetIdx
},
{
-
M_PI_2
}));
}
void
ControlledU
::
visit
(
T
&
t
)
{
// Ctrl-T = CPhase(pi/4)
const
auto
targetIdx
=
t
.
bits
()[
0
];
m_composite
->
addInstruction
(
m_gateProvider
->
createInstruction
(
"CPhase"
,
{
m_ctrlIdx
,
targetIdx
},
{
M_PI_4
}));
}
void
ControlledU
::
visit
(
Tdg
&
tdg
)
{
// Ctrl-Tdg = CPhase(-pi/4)
const
auto
targetIdx
=
tdg
.
bits
()[
0
];
m_composite
->
addInstruction
(
m_gateProvider
->
createInstruction
(
"CPhase"
,
{
m_ctrlIdx
,
targetIdx
},
{
-
M_PI_4
}));
}
void
ControlledU
::
visit
(
Swap
&
s
)
{
// Fredkin gate: controlled-swap
// Decompose Swap gate into CNOT gates;
// then re-visit those CNOT gates (becoming CCNOT).
CNOT
c1
(
s
.
bits
()),
c2
(
s
.
bits
()[
1
],
s
.
bits
()[
0
]),
c3
(
s
.
bits
());
visit
(
c1
);
visit
(
c2
);
visit
(
c3
);
}
void
ControlledU
::
visit
(
U
&
u
)
{
// U(theta, phi, lambda) := Rz(phi)Ry(theta)Rz(lambda)
const
auto
theta
=
InstructionParameterToDouble
(
u
.
getParameter
(
0
));
const
auto
phi
=
InstructionParameterToDouble
(
u
.
getParameter
(
1
));
const
auto
lambda
=
InstructionParameterToDouble
(
u
.
getParameter
(
2
));
Ry
ry1
(
u
.
bits
()[
0
],
theta
);
Rz
rz1
(
u
.
bits
()[
0
],
lambda
);
Rz
rz2
(
u
.
bits
()[
0
],
phi
);
// Revisit these gates: Rn -> CRn
visit
(
rz1
);
visit
(
ry1
);
visit
(
rz2
);
}
void
ControlledU
::
visit
(
CY
&
cy
)
{
// controlled-Y = Sdg(target) - CX - S(target)
CNOT
c1
(
cy
.
bits
());