Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
ca3b8d5
First version of exporting to open qasm
clausia Nov 23, 2020
9c31e79
Optional third party libraries
clausia Nov 23, 2020
145e796
Import/export OpenQASM code and import/export to pyzx package for ZX-…
clausia Jan 2, 2021
733a26b
Merge branch 'devel' into add-pyzx-and-qasm
clausia Jan 4, 2021
85cd14d
improve comment
clausia Jan 6, 2021
058e6f6
Better equivalences for CH and Y that includes the power parameter
clausia Jan 8, 2021
45296ce
fix comments in compiler.py
clausia Jan 8, 2021
15d0841
dd matrix representation of U gate
clausia Jan 8, 2021
290ced0
More tests for gates u1,u2,u3,U
clausia Jan 8, 2021
7009185
Improve qubits property in QGateImpl
clausia Jan 11, 2021
23b8ab7
correct gates equivalent to CH
clausia Jan 12, 2021
28f069b
Tests for import/export OpenQASM code
clausia Jan 13, 2021
66626fd
Correct order for U gate equivalent circuit and improvement in tests …
clausia Jan 14, 2021
d178f26
Error (and fix) because changes in _gates_impl.py regarding _qubits a…
clausia Jan 14, 2021
0c55263
Tests for import/export OpenQASM code
clausia Jan 14, 2021
4d14b97
Remove temporal comment
clausia Jan 14, 2021
99d10b4
Avoid some warnings
clausia Jan 14, 2021
9aa17b3
Tests for convert from/to pyzx
clausia Jan 15, 2021
599777c
Test if a circuit reduced within pyzx remains the same when returned …
clausia Jan 15, 2021
ff68b80
Skip pyzx tests if pyzx package is not installed
clausia Jan 15, 2021
7b41f99
Improve tests for new compile functions (ry, y, ch)
clausia Jan 15, 2021
344c22c
Merge branch 'devel' into add-pyzx-and-qasm
clausia Jan 15, 2021
a8f4769
Variables are not needed when importing OpqnQASM code
clausia Jan 15, 2021
209ddf1
Merge branch 'devel' into add-pyzx-and-qasm
clausia Jan 20, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@ qulacs # default simulator, remove if the installation gives you trouble
#pyquil # you need to install the forest-sdk
#qulacs-gpu
#qibo <= 0.1.1

#optional third party libraries
#pyzx
2 changes: 2 additions & 0 deletions src/tequila/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
INSTALLED_SAMPLERS, \
INSTALLED_SIMULATORS, SUPPORTED_BACKENDS, INSTALLED_BACKENDS, show_available_simulators
from tequila.wavefunction import QubitWaveFunction
from tequila.circuit.qasm import export_open_qasm, import_open_qasm, import_open_qasm_from_file
from tequila.circuit.pyzx import convert_to_pyzx, convert_from_pyzx
import tequila.quantumchemistry as chemistry # shortcut
from tequila.quantumchemistry import Molecule, MoleculeFromOpenFermion

Expand Down
20 changes: 7 additions & 13 deletions src/tequila/circuit/_gates_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,16 @@ def control(self):

@property
def qubits(self):
return self._qubits
# Set the active qubits
if self.control:
qubits = self.target + self.control
else:
qubits = self.target
return sorted(tuple(set(qubits)))

@property
def max_qubit(self):
return self._max_qubit
return self.compute_max_qubit()

def extract_variables(self):
return []
Expand All @@ -47,13 +52,6 @@ def __init__(self, name, target: UnionList, control: UnionList = None):
self._target = tuple(list_assignment(target))
self._control = tuple(list_assignment(control))
self.finalize()
# Set the active qubits
if self.control:
self._qubits = self.target + self.control
else:
self._qubits = self.target
self._qubits = sorted(tuple(set(self._qubits)))
self._max_qubit = self.compute_max_qubit()

def copy(self):
return copy.deepcopy(self)
Expand Down Expand Up @@ -134,12 +132,8 @@ def __eq__(self, other):
def map_qubits(self, qubit_map: dict):
mapped = copy.deepcopy(self)
mapped._target = tuple([qubit_map[i] for i in self.target])
qubits = mapped._target
if self.control is not None:
mapped._control = tuple([qubit_map[i] for i in self.control])
qubits += mapped._control
mapped._qubits = sorted(tuple(set(qubits)))
mapped._max_qubit = mapped.compute_max_qubit()
if hasattr(self, "generator"):
mapped.generator = self.generator.map_qubits(qubit_map=qubit_map)
if hasattr(self, "generators"):
Expand Down
95 changes: 93 additions & 2 deletions src/tequila/circuit/compiler.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from tequila import TequilaException
from tequila.circuit.circuit import QCircuit
from tequila.circuit.gates import Rx, Ry, H, X, Rz, ExpPauli, CNOT, Phase, T, Z, Y
from tequila.circuit.gates import Rx, Ry, H, X, Rz, ExpPauli, CNOT, Phase, T, Z, Y, S, CX
from tequila.circuit._gates_impl import RotationGateImpl, PhaseGateImpl, QGateImpl, \
ExponentialPauliGateImpl, TrotterizedGateImpl, PowerGateImpl
from tequila.utils import to_float
Expand Down Expand Up @@ -54,7 +54,10 @@ def __init__(self,
controlled_rotation=False,
swap=False,
cc_max=False,
gradient_mode=False
gradient_mode=False,
ry_gate=False,
y_gate=False,
ch_gate=False
):

"""
Expand Down Expand Up @@ -93,6 +96,12 @@ def __init__(self,
whether or not to break down swap gates into CNOT gates.
cc_max:
whether or not to break down all controlled gates with 2 or more controls.
ry_gate:
whether or not to break down all rotational y gates
y_gate:
whether or not to break down all y gates
ch_gate:
whether or not to break down all controlled-H gates
"""
self.multitarget = multitarget
self.multicontrol = multicontrol
Expand All @@ -111,6 +120,9 @@ def __init__(self,
self.swap = swap
self.cc_max = cc_max
self.gradient_mode = gradient_mode
self.ry_gate = ry_gate
self.y_gate = y_gate
self.ch_gate = ch_gate

def __call__(self, objective: typing.Union[Objective, QCircuit, ExpectationValueImpl], variables=None, *args,
**kwargs):
Expand Down Expand Up @@ -280,6 +292,12 @@ def compile_circuit(self, abstract_circuit: QCircuit, variables=None, *args, **k
cg = compile_power_gate(gate=cg)
if self.phase:
cg = compile_phase(gate=cg)
if self.ch_gate:
cg = compile_ch(gate=cg)
if self.y_gate:
cg = compile_y(gate=cg)
if self.ry_gate:
cg = compile_ry(gate=cg, controlled_rotation=self.controlled_rotation)
if controlled:
if self.cc_max:
cg = compile_to_cc(gate=cg)
Expand Down Expand Up @@ -1297,3 +1315,76 @@ def compile_trotterized_gate(gate, compile_exponential_pauli: bool = False):
return compile_exponential_pauli_gate(result)
else:
return result


@compiler
def compile_ry(gate: RotationGateImpl, controlled_rotation: bool = False) -> QCircuit:
"""
Compile Ry gates into Rx and Rz.
Parameters
----------
gate:
the gate.
controlled_rotation:
determines if the decomposition of the controlled-Ry gate will be performed in compile_controlled_rotation,
if not, decomposition will be performed here

Returns
-------
QCircuit, the result of compilation.
"""
if gate.name.lower() == "ry":

if not (gate.is_controlled() and controlled_rotation):

return Rz(target=gate.target, control=None, angle=-numpy.pi / 2) \
+ Rx(target=gate.target, control=gate.control, angle=gate.parameter) \
+ Rz(target=gate.target, control=None, angle=numpy.pi / 2)

return QCircuit.wrap_gate(gate)


@compiler
def compile_y(gate) -> QCircuit:
"""
Compile Y gates into X and Rz.
Parameters
----------
gate:
the gate.

Returns
-------
QCircuit, the result of compilation.
"""
if gate.name.lower() == "y":

return Rz(target=gate.target, control=None, angle=-numpy.pi / 2) \
+ X(target=gate.target, control=gate.control, power=gate.parameter if gate.is_parametrized() else None) \
+ Rz(target=gate.target, control=None, angle=numpy.pi / 2)

else:
return QCircuit.wrap_gate(gate)


@compiler
def compile_ch(gate: QGateImpl) -> QCircuit:
"""
Compile CH gates into its equivalent:
CH = Ry(0.25pi) CZ Ry(-0.25pi)
Parameters
----------
gate:
the gate.

Returns
-------
QCircuit, the result of compilation.
"""
if gate.name.lower() == "h" and gate.is_controlled():

return Ry(target=gate.target, control=None, angle=-numpy.pi / 4) \
+ Z(target=gate.target, control=gate.control, power=gate.parameter if gate.is_parametrized() else None) \
+ Ry(target=gate.target, control=None, angle=numpy.pi / 4)
else:
return QCircuit.wrap_gate(gate)
171 changes: 171 additions & 0 deletions src/tequila/circuit/gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,177 @@ def CRz(control: int, target: int, angle: float) -> QCircuit:
return Rz(target=target, control=control, angle=angle)


def U(theta, phi, lambd, target: typing.Union[list, int], control: typing.Union[list, int] = None) -> QCircuit:
"""
Notes
----------
Convenient gate, one of the abstract gates defined by OpenQASM.

.. math::
U(\\theta, \\phi, \\lambda) = R_z(\\phi)R_x(-\\pi/2)R_z(\\theta)R_x(\\pi/2)R_z(\\lambda)
U(\\theta, \\phi, \\lambda) = \\begin{pmatrix}
e^{-i \\frac{\\phi}{2}} & 0 \\\\
0 & e^{i \\frac{\\phi}{2}}
\\end{pmatrix}
\\begin{pmatrix}
\\cos{-\\frac{\\pi}{4}} & -i \\sin{-\\frac{\\pi}{4}} \\\\
-i \\sin{-\\frac{\\pi}{4}} & \\cos{-\\frac{\\pi}{4}}
\\end{pmatrix}
\\begin{pmatrix}
e^{-i \\frac{\\theta}{2}} & 0 \\\\
0 & e^{i \\frac{\\theta}{2}}
\\end{pmatrix}
\\begin{pmatrix}
\\cos{\\frac{\\pi}{4}} & -i \\sin{\\frac{\\pi}{4}} \\\\
-i \\sin{\\frac{\\pi}{4}} & \\cos{\\frac{\\pi}{4}}
\\end{pmatrix}
\\begin{pmatrix}
e^{-i \\frac{\\lambda}{2}} & 0 \\\\
0 & e^{i \\frac{\\lambda}{2}}
\\end{pmatrix}

U(\\theta, \\phi, \\lambda) = \\begin{pmatrix}
\\cos{\\frac{\\theta}{2}} &
-e^{i \\lambda} \\sin{\\frac{\\theta}{2}} \\\\
e^{i \\phi} \\sin{\\frac{\\theta}{2}} &
e^{i (\\phi+\\lambda)} \\cos{\\frac{\\theta}{2}}
\\end{pmatrix}

Parameters
----------
theta
first parameter angle
phi
second parameter angle
lamnd
third parameter angle
target
int or list of int
control
int or list of int

Returns
-------
QCircuit object
"""

theta = assign_variable(theta)
phi = assign_variable(phi)
lambd = assign_variable(lambd)
pi_half = assign_variable(np.pi / 2)

return Rz(angle=lambd, target=target, control=control) + \
Rx(angle=pi_half, target=target, control=control) + \
Rz(angle=theta, target=target, control=control) + \
Rx(angle=-pi_half, target=target, control=control) + \
Rz(angle=phi, target=target, control=control)


def u1(lambd, target: typing.Union[list, int], control: typing.Union[list, int] = None) -> QCircuit:
"""
Notes
----------
Convenient gate, one of the abstract gates defined by Quantum Experience Standard Header.
Changes the phase of a carrier without applying any pulses.

.. math::
from OpenQASM 2.0 specification:
u1(\\lambda) \\sim U(0, 0, \\lambda) = R_z(\\lambda) = e^{-i\\frac{\\lambda}{2} \\sigma_{z}}
also is equal to:
u1(\\lambda) = \\begin{pmatrix} 1 & 0 \\\\ 0 & e^{i\\lambda} \\end{pmatrix}
which is the Tequila Phase gate:
u1(\\lambda) = Phase(\\lambda)

Parameters
----------
lambd
parameter angle
target
int or list of int
control
int or list of int

Returns
-------
QCircuit object
"""

return Phase(phi=lambd, target=target, control=control)


def u2(phi, lambd, target: typing.Union[list, int], control: typing.Union[list, int] = None) -> QCircuit:
"""
Notes
----------
Convenient gate, one of the abstract gates defined by Quantum Experience Standard Header.
Uses a single \\pi/2-pulse.

.. math::
u2(\\phi, \\lambda) = U(\\pi/2, \\phi, \\lambda) = R_z(\\phi + \\pi/2)R_x(\\pi/2)R_z(\\lambda - \\pi/2)

u2(\\phi, \\lambda) = \\frac{1}{\\sqrt{2}}
\\begin{pmatrix}
1 & -e^{i\\lambda} \\\\
e^{i\\phi} & e^{i(\\phi+\\lambda)}
\\end{pmatrix}

Parameters
----------
phi
first parameter angle
lambd
second parameter angle
target
int or list of int
control
int or list of int

Returns
-------
QCircuit object
"""

return U(theta=np.pi/2, phi=phi, lambd=lambd, target=target, control=control)


def u3(theta, phi, lambd, target: typing.Union[list, int], control: typing.Union[list, int] = None) -> QCircuit:
"""
Notes
----------
Convenient gate, one of the abstract gates defined by Quantum Experience Standard Header
The most general single-qubit gate.
Uses a pair of \\pi/2-pulses.

.. math::
u3(\\theta, \\phi, \\lambda) = U(\\theta, \\phi, \\lambda)
= \\begin{pmatrix}
\\cos{\\frac{\\5theta}{2}} &
-e^{i \\lambda} \\sin{\\frac{\\theta}{2}} \\\\
e^{i \\phi} \\sin{\\frac{\\theta}{2}} &
e^{i (\\phi+\\lambda)} \\cos{\\frac{\\theta}{2}}
\\end{pmatrix}

Parameters
----------
theta
first parameter angle
phi
second parameter angle
lambd
third parameter angle
target
int or list of int
control
int or list of int

Returns
-------
QCircuit object
"""

return U(theta=theta, phi=phi, lambd=lambd, target=target, control=control)


if __name__ == "__main__":
G = CRx(1, 0, 2.0)

Expand Down
Loading