diff --git a/README.md b/README.md index 9105e0f8..d905eb03 100644 --- a/README.md +++ b/README.md @@ -7,15 +7,19 @@

- - MIT License - Documentation + + MIT License + + Chat @ Slack + + Chat @ Discord + Forum diff --git a/docs/source/api_layers.rst b/docs/source/api_layers.rst new file mode 100644 index 00000000..18a6753c --- /dev/null +++ b/docs/source/api_layers.rst @@ -0,0 +1,29 @@ +torchquantum.layers +====================== + +.. currentmodule:: torchquantum.layer + +Layers +--------- +.. autosummary:: + :toctree: generated + :template: classtemplate_controlflow.rst + + + QuantumModuleFromOps + TrainableOpAll + ClassicalInOpAll + FixedOpAll + TwoQAll + RandomLayer + RandomLayerAllTypes + Op1QAllLayer + RandomOp1All + Op2QAllLayer + Op2QButterflyLayer + Op2QDenseLayer + CXLayer + CXCXCXLayer + SWAPSWAPLayer + RXYZCXLayer0 + QFTLayer diff --git a/docs/source/api_operators.rst b/docs/source/api_operators.rst index f8c607d3..7933fd01 100644 --- a/docs/source/api_operators.rst +++ b/docs/source/api_operators.rst @@ -1,7 +1,7 @@ torchquantum.operators ====================== -.. currentmodule:: torchquantum.operators +.. currentmodule:: torchquantum.operator Classes --------- diff --git a/docs/source/index.rst b/docs/source/index.rst index a1a4f08a..24f29897 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -5,6 +5,7 @@ api_torchquantum api_functional api_operators + api_layers .. toctree:: :maxdepth: 1 diff --git a/examples/gradient_pruning/q_models.py b/examples/gradient_pruning/q_models.py index 1073ac72..133993ef 100644 --- a/examples/gradient_pruning/q_models.py +++ b/examples/gradient_pruning/q_models.py @@ -154,7 +154,7 @@ def shift_and_run( node.shift_this_step[idx] = True elif self.pruning_method == "perlayer_pruning": node.shift_this_step[:] = False - idxs = torch.range(0, self.n_params - 1, dtype=int).view( + idxs = torch.arange(0, self.n_params, dtype=int).view( self.n_qubits, self.n_layers ) sampled_colums = self.colums @@ -164,7 +164,7 @@ def shift_and_run( self.colums %= self.n_layers elif self.pruning_method == "perqubit_pruning": node.shift_this_step[:] = False - idxs = torch.range(0, self.n_params - 1, dtype=int).view( + idxs = torch.arange(0, self.n_params, dtype=int).view( self.n_qubits, self.n_layers ) sampled_rows = self.rows diff --git a/examples/index.rst b/examples/index.rst index e36da434..c9bd9c24 100644 --- a/examples/index.rst +++ b/examples/index.rst @@ -8,4 +8,6 @@ TorchQuantum Examples param_shift_onchip_training/param_shift_onchip_training.ipynb quantum_kernel_method/quantum_kernel_method.ipynb quanvolution/quanvolution.ipynb - superdense_coding/superdense_coding_torchquantum.ipynb \ No newline at end of file + superdense_coding/superdense_coding_torchquantum.ipynb + qubit_rotation/TQ_Qubit_Rotation_Tutorial.ipynb + diff --git a/examples/superdense_coding/superdense_coding_torchquantum.ipynb b/examples/superdense_coding/superdense_coding_torchquantum.ipynb index 3f53e91c..e4128624 100644 --- a/examples/superdense_coding/superdense_coding_torchquantum.ipynb +++ b/examples/superdense_coding/superdense_coding_torchquantum.ipynb @@ -502,7 +502,7 @@ "id": "nFC9-bqHbG2I" }, "source": [ - "# References:\n", + "## References:\n", "\n", "[1] Bennett, C.H., Brassard, G., Crépeau, C., Jozsa, R., Peres, A. and Wootters, W.K., 1993. Teleporting an unknown quantum state via dual classical and Einstein-Podolsky-Rosen channels. Physical review letters, 70(13), p.1895.\n", "\n", diff --git a/test/layers/test_rotgate.py b/test/layers/test_rotgate.py new file mode 100644 index 00000000..c69d5569 --- /dev/null +++ b/test/layers/test_rotgate.py @@ -0,0 +1,55 @@ +import torchquantum as tq +import qiskit +from qiskit import Aer, execute + +from torchquantum.util import ( + switch_little_big_endian_matrix, + find_global_phase, +) + +from qiskit.circuit.library import GR, GRX, GRY, GRZ +import numpy as np + +all_pairs = [ + {"qiskit": GR, "tq": tq.layer.GlobalR, "params": 2}, + {"qiskit": GRX, "tq": tq.layer.GlobalRX, "params": 1}, + {"qiskit": GRY, "tq": tq.layer.GlobalRY, "params": 1}, + {"qiskit": GRZ, "tq": tq.layer.GlobalRZ, "params": 1}, +] + +ITERATIONS = 10 + +# test each pair +for pair in all_pairs: + # test 2-5 wires + for num_wires in range(2, 5): + # try multiple random parameters + for _ in range(ITERATIONS): + # generate random parameters + params = [ + np.random.uniform(-2 * np.pi, 2 * np.pi) for _ in range(pair["params"]) + ] + + # create the qiskit circuit + qiskit_circuit = pair["qiskit"](num_wires, *params) + + # get the unitary from qiskit + backend = Aer.get_backend("unitary_simulator") + result = execute(qiskit_circuit, backend).result() + unitary_qiskit = result.get_unitary(qiskit_circuit) + + # create tq circuit + qdev = tq.QuantumDevice(num_wires) + tq_circuit = pair["tq"](num_wires, *params) + tq_circuit(qdev) + + # get the unitary from tq + unitary_tq = tq_circuit.get_unitary(qdev) + unitary_tq = switch_little_big_endian_matrix(unitary_tq.data.numpy()) + + # phase? + phase = find_global_phase(unitary_tq, unitary_qiskit, 1e-4) + + assert np.allclose( + unitary_tq * phase, unitary_qiskit, atol=1e-6 + ), f"{pair} not equal with {params=}!" diff --git a/torchquantum/layer/__init__.py b/torchquantum/layer/__init__.py index a6c99385..ce5540cb 100644 --- a/torchquantum/layer/__init__.py +++ b/torchquantum/layer/__init__.py @@ -24,3 +24,4 @@ from .layers import * from .nlocal import * +from .general import * diff --git a/torchquantum/layer/general.py b/torchquantum/layer/general.py new file mode 100644 index 00000000..9857220a --- /dev/null +++ b/torchquantum/layer/general.py @@ -0,0 +1,104 @@ +""" +MIT License + +Copyright (c) 2020-present TorchQuantum Authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" + + +import torch +import torchquantum as tq +from torchquantum.layer.layers import ( + LayerTemplate0, + Op1QAllLayer, + Op2QAllLayer, + RandomOp1All, +) + +__all__ = [ + "GlobalR", + "GlobalRX", + "GlobalRY", + "GlobalRZ", +] + + +class GlobalR(tq.QuantumModule): + """Layer Template for a Global R General Gate""" + + def __init__( + self, + n_wires: int = 0, + theta: float = 0, + phi: float = 0, + ): + """Create the layer""" + super().__init__() + self.n_wires = n_wires + self.params = torch.tensor([[theta, phi]]) + + @tq.static_support + def forward(self, q_device, x=None): + for k in range(self.n_wires): + tq.R()(q_device, wires=k, params=self.params) + + +class GlobalRX(GlobalR): + """Layer Template for a Global RX General Gate""" + + def __init__( + self, + n_wires: int = 0, + theta: float = 0, + ): + """Create the layer""" + super().__init__(n_wires, theta, phi=0) + + +class GlobalRY(GlobalR): + """Layer Template for a Global RY General Gate""" + + def __init__( + self, + n_wires: int = 0, + theta: float = 0, + ): + """Create the layer""" + super().__init__(n_wires, theta, phi=torch.pi / 2) + +class GlobalRZ(tq.QuantumModule): + """Layer Template for a Global RZ General Gate""" + + def __init__( + self, + n_wires: int = 0, + phi: float = 0, + ): + """Create the layer""" + super().__init__() + self.n_wires = n_wires + self.params = torch.tensor([[phi]]) + + @tq.static_support + def forward(self, q_device, x=None): + for k in range(self.n_wires): + tq.RZ()(q_device, wires=k, params=self.params) + + diff --git a/torchquantum/layer/layers.py b/torchquantum/layer/layers.py index 9d4e5f61..7882240b 100644 --- a/torchquantum/layer/layers.py +++ b/torchquantum/layer/layers.py @@ -54,16 +54,22 @@ "U3CU3Layer0", "QFTLayer", "SethLayer0", + "EntangleLinear", + "EntanglePairwise", + "EntangleFull", + "EntangleCircular", + "EntanglementLayer", ] class QuantumModuleFromOps(tq.QuantumModule): """Initializes a QuantumModuleFromOps instance. - Args: - ops (List[tq.Operation]): List of quantum operations. + Args: + ops (List[tq.Operation]): List of quantum operations. + + """ - """ def __init__(self, ops): super().__init__() self.ops = tq.QuantumModuleList(ops) @@ -72,13 +78,13 @@ def __init__(self, ops): def forward(self, q_device: tq.QuantumDevice): """Performs the forward pass of the quantum module. - Args: - q_device (tq.QuantumDevice): Quantum device to apply the operations on. + Args: + q_device (tq.QuantumDevice): Quantum device to apply the operations on. - Returns: - None + Returns: + None - """ + """ self.q_device = q_device for op in self.ops: op(q_device) @@ -113,18 +119,19 @@ def forward(self, q_device: tq.QuantumDevice): class ClassicalInOpAll(tq.QuantumModule): """ - Quantum module that applies the same quantum operation to all wires of a quantum device, - where the parameters of the operation are obtained from a classical input. + Quantum module that applies the same quantum operation to all wires of a quantum device, + where the parameters of the operation are obtained from a classical input. - Args: - n_gate (int): Number of gates. - op (tq.Operator): Quantum operation to be applied. + Args: + n_gate (int): Number of gates. + op (tq.Operator): Quantum operation to be applied. - Attributes: - n_gate (int): Number of gates. - gate_all (nn.ModuleList): List of quantum operations. + Attributes: + n_gate (int): Number of gates. + gate_all (nn.ModuleList): List of quantum operations. + + """ - """ def __init__(self, n_gate: int, op: tq.Operator): super().__init__() self.n_gate = n_gate @@ -135,19 +142,19 @@ def __init__(self, n_gate: int, op: tq.Operator): @tq.static_support def forward(self, q_device: tq.QuantumDevice, x): """ - Performs the forward pass of the classical input quantum operation module. + Performs the forward pass of the classical input quantum operation module. - Args: - q_device (tq.QuantumDevice): Quantum device to apply the operations on. - x (torch.Tensor): Classical input of shape (batch_size, n_gate). + Args: + q_device (tq.QuantumDevice): Quantum device to apply the operations on. + x (torch.Tensor): Classical input of shape (batch_size, n_gate). - Returns: - None + Returns: + None - Raises: - AssertionError: If the number of gates is different from the number of wires in the device. + Raises: + AssertionError: If the number of gates is different from the number of wires in the device. - """ + """ # rx on all wires, assert the number of gate is the same as the number # of wires in the device. assert self.n_gate == q_device.n_wires, ( @@ -161,17 +168,18 @@ def forward(self, q_device: tq.QuantumDevice, x): class FixedOpAll(tq.QuantumModule): """ - Quantum module that applies the same fixed quantum operation to all wires of a quantum device. + Quantum module that applies the same fixed quantum operation to all wires of a quantum device. + + Args: + n_gate (int): Number of gates. + op (tq.Operator): Quantum operation to be applied. - Args: - n_gate (int): Number of gates. - op (tq.Operator): Quantum operation to be applied. + Attributes: + n_gate (int): Number of gates. + gate_all (nn.ModuleList): List of quantum operations. - Attributes: - n_gate (int): Number of gates. - gate_all (nn.ModuleList): List of quantum operations. + """ - """ def __init__(self, n_gate: int, op: tq.Operator): super().__init__() self.n_gate = n_gate @@ -182,18 +190,18 @@ def __init__(self, n_gate: int, op: tq.Operator): @tq.static_support def forward(self, q_device: tq.QuantumDevice): """ - Performs the forward pass of the fixed quantum operation module. + Performs the forward pass of the fixed quantum operation module. - Args: - q_device (tq.QuantumDevice): Quantum device to apply the operations on. + Args: + q_device (tq.QuantumDevice): Quantum device to apply the operations on. - Returns: - None + Returns: + None - Raises: - AssertionError: If the number of gates is different from the number of wires in the device. + Raises: + AssertionError: If the number of gates is different from the number of wires in the device. - """ + """ # rx on all wires, assert the number of gate is the same as the number # of wires in the device. assert self.n_gate == q_device.n_wires, ( @@ -207,17 +215,18 @@ def forward(self, q_device: tq.QuantumDevice): class TwoQAll(tq.QuantumModule): """ - Quantum module that applies a two-qubit quantum operation to adjacent pairs of wires in a quantum device. + Quantum module that applies a two-qubit quantum operation to adjacent pairs of wires in a quantum device. - Args: - n_gate (int): Number of adjacent pairs of wires. - op (tq.Operator): Two-qubit quantum operation to be applied. + Args: + n_gate (int): Number of adjacent pairs of wires. + op (tq.Operator): Two-qubit quantum operation to be applied. - Attributes: - n_gate (int): Number of adjacent pairs of wires. - op (tq.Operator): Two-qubit quantum operation. + Attributes: + n_gate (int): Number of adjacent pairs of wires. + op (tq.Operator): Two-qubit quantum operation. + + """ - """ def __init__(self, n_gate: int, op: tq.Operator): super().__init__() self.n_gate = n_gate @@ -272,28 +281,29 @@ def forward(self, q_device: tq.QuantumDevice, x): class RandomLayer(tq.QuantumModule): """ - Quantum module that represents a random layer of quantum operations applied to specified wires. + Quantum module that represents a random layer of quantum operations applied to specified wires. + + Args: + wires (int or Iterable[int]): Indices of the wires the operations are applied to. + n_ops (int): Number of random operations in the layer. + n_params (int): Number of parameters for each random operation. + op_ratios (list or float): Ratios determining the relative frequencies of different operation types. + op_types (tuple or tq.Operator): Types of random operations to be included in the layer. + seed (int): Seed for random number generation. + qiskit_compatible (bool): Flag indicating whether the layer should be compatible with Qiskit. + + Attributes: + n_ops (int): Number of random operations in the layer. + n_params (int): Number of parameters for each random operation. + wires (list): Indices of the wires the operations are applied to. + n_wires (int): Number of wires. + op_types (list): Types of random operations included in the layer. + op_ratios (numpy.array): Ratios determining the relative frequencies of different operation types. + seed (int): Seed for random number generation. + op_list (tq.QuantumModuleList): List of random operations in the layer. - Args: - wires (int or Iterable[int]): Indices of the wires the operations are applied to. - n_ops (int): Number of random operations in the layer. - n_params (int): Number of parameters for each random operation. - op_ratios (list or float): Ratios determining the relative frequencies of different operation types. - op_types (tuple or tq.Operator): Types of random operations to be included in the layer. - seed (int): Seed for random number generation. - qiskit_compatible (bool): Flag indicating whether the layer should be compatible with Qiskit. - - Attributes: - n_ops (int): Number of random operations in the layer. - n_params (int): Number of parameters for each random operation. - wires (list): Indices of the wires the operations are applied to. - n_wires (int): Number of wires. - op_types (list): Types of random operations included in the layer. - op_ratios (numpy.array): Ratios determining the relative frequencies of different operation types. - seed (int): Seed for random number generation. - op_list (tq.QuantumModuleList): List of random operations in the layer. + """ - """ def __init__( self, wires, @@ -344,15 +354,15 @@ def __init__( def rebuild_random_layer_from_op_list(self, n_ops_in, wires_in, op_list_in): """ - Rebuilds a random layer from the given operation list. - This method is used for loading a random layer from a checkpoint. + Rebuilds a random layer from the given operation list. + This method is used for loading a random layer from a checkpoint. - Args: - n_ops_in (int): Number of operations in the layer. - wires_in (list): Indices of the wires the operations are applied to. - op_list_in (list): List of operations in the layer. + Args: + n_ops_in (int): Number of operations in the layer. + wires_in (list): Indices of the wires the operations are applied to. + op_list_in (list): List of operations in the layer. - """ + """ self.n_ops = n_ops_in self.wires = wires_in @@ -423,20 +433,21 @@ def forward(self, q_device: tq.QuantumDevice): class RandomLayerAllTypes(RandomLayer): """ - Random layer with a wide range of quantum gate types. + Random layer with a wide range of quantum gate types. + + This class extends the `RandomLayer` class to include a variety of quantum gate types as options for the random layer. - This class extends the `RandomLayer` class to include a variety of quantum gate types as options for the random layer. + Args: + wires (int or list): Indices of the wires the operations are applied to. + n_ops (int): Number of operations in the layer. + n_params (int): Number of parameters for each operation. + op_ratios (list): Ratios for selecting different types of operations. + op_types (tuple): Types of operations to include in the layer. + seed (int): Seed for the random number generator. + qiskit_compatible (bool): Flag indicating whether the layer should be Qiskit-compatible. - Args: - wires (int or list): Indices of the wires the operations are applied to. - n_ops (int): Number of operations in the layer. - n_params (int): Number of parameters for each operation. - op_ratios (list): Ratios for selecting different types of operations. - op_types (tuple): Types of operations to include in the layer. - seed (int): Seed for the random number generator. - qiskit_compatible (bool): Flag indicating whether the layer should be Qiskit-compatible. + """ - """ def __init__( self, wires, @@ -491,14 +502,15 @@ def __init__( class SimpleQLayer(tq.QuantumModule): """ - Simple quantum layer consisting of three parameterized gates applied to specific wires. + Simple quantum layer consisting of three parameterized gates applied to specific wires. + + This class represents a simple quantum layer with three parameterized gates: RX, RY, and RZ. The gates are applied to specific wires in the quantum device. - This class represents a simple quantum layer with three parameterized gates: RX, RY, and RZ. The gates are applied to specific wires in the quantum device. + Args: + n_wires (int): Number of wires in the quantum device. - Args: - n_wires (int): Number of wires in the quantum device. + """ - """ def __init__(self, n_wires): super().__init__() self.n_wires = n_wires @@ -518,14 +530,15 @@ def forward(self, q_dev): class CXLayer(tq.QuantumModule): """ - Quantum layer with a controlled-X (CX) gate applied to two specified wires. + Quantum layer with a controlled-X (CX) gate applied to two specified wires. - This class represents a quantum layer with a controlled-X (CX) gate applied to two specified wires in the quantum device. + This class represents a quantum layer with a controlled-X (CX) gate applied to two specified wires in the quantum device. - Args: - n_wires (int): Number of wires in the quantum device. + Args: + n_wires (int): Number of wires in the quantum device. + + """ - """ def __init__(self, n_wires): super().__init__() self.n_wires = n_wires @@ -538,14 +551,15 @@ def forward(self, q_dev): class CXCXCXLayer(tq.QuantumModule): """ - Quantum layer with a sequence of CX gates applied to three specified wires. + Quantum layer with a sequence of CX gates applied to three specified wires. - This class represents a quantum layer with a sequence of CX gates applied to three specified wires in the quantum device. + This class represents a quantum layer with a sequence of CX gates applied to three specified wires in the quantum device. - Args: - n_wires (int): Number of wires in the quantum device. + Args: + n_wires (int): Number of wires in the quantum device. + + """ - """ def __init__(self, n_wires): super().__init__() self.n_wires = n_wires @@ -560,14 +574,15 @@ def forward(self, q_dev): class SWAPSWAPLayer(tq.QuantumModule): """ - Quantum layer with a sequence of SWAP gates applied to two specified pairs of wires. + Quantum layer with a sequence of SWAP gates applied to two specified pairs of wires. - This class represents a quantum layer with a sequence of SWAP gates applied to two specified pairs of wires in the quantum device. + This class represents a quantum layer with a sequence of SWAP gates applied to two specified pairs of wires in the quantum device. - Args: - n_wires (int): Number of wires in the quantum device. + Args: + n_wires (int): Number of wires in the quantum device. + + """ - """ def __init__(self, n_wires): super().__init__() self.n_wires = n_wires @@ -581,17 +596,18 @@ def forward(self, q_dev): class Op1QAllLayer(tq.QuantumModule): """ - Quantum layer applying the same single-qubit operation to all wires. + Quantum layer applying the same single-qubit operation to all wires. - This class represents a quantum layer that applies the same single-qubit operation to all wires in the quantum device. + This class represents a quantum layer that applies the same single-qubit operation to all wires in the quantum device. - Args: - op (tq.Operator): Single-qubit operation to be applied. - n_wires (int): Number of wires in the quantum device. - has_params (bool, optional): Flag indicating if the operation has parameters. Defaults to False. - trainable (bool, optional): Flag indicating if the operation is trainable. Defaults to False. + Args: + op (tq.Operator): Single-qubit operation to be applied. + n_wires (int): Number of wires in the quantum device. + has_params (bool, optional): Flag indicating if the operation has parameters. Defaults to False. + trainable (bool, optional): Flag indicating if the operation is trainable. Defaults to False. + + """ - """ def __init__(self, op, n_wires: int, has_params=False, trainable=False): super().__init__() self.n_wires = n_wires @@ -608,21 +624,22 @@ def forward(self, q_device): class Op2QAllLayer(tq.QuantumModule): """ - Quantum layer applying the same two-qubit operation to all pairs of adjacent wires. - This class represents a quantum layer that applies the same two-qubit operation to all pairs of adjacent wires - in the quantum device. The pairs of wires can be determined in a circular or non-circular pattern based on the - specified jump. - - Args: - op (tq.Operator): Two-qubit operation to be applied. - n_wires (int): Number of wires in the quantum device. - has_params (bool, optional): Flag indicating if the operation has parameters. Defaults to False. - trainable (bool, optional): Flag indicating if the operation is trainable. Defaults to False. - wire_reverse (bool, optional): Flag indicating if the order of wires in each pair should be reversed. Defaults to False. - jump (int, optional): Number of positions to jump between adjacent pairs of wires. Defaults to 1. - circular (bool, optional): Flag indicating if the pattern should be circular. Defaults to False. + Quantum layer applying the same two-qubit operation to all pairs of adjacent wires. + This class represents a quantum layer that applies the same two-qubit operation to all pairs of adjacent wires + in the quantum device. The pairs of wires can be determined in a circular or non-circular pattern based on the + specified jump. + + Args: + op (tq.Operator): Two-qubit operation to be applied. + n_wires (int): Number of wires in the quantum device. + has_params (bool, optional): Flag indicating if the operation has parameters. Defaults to False. + trainable (bool, optional): Flag indicating if the operation is trainable. Defaults to False. + wire_reverse (bool, optional): Flag indicating if the order of wires in each pair should be reversed. Defaults to False. + jump (int, optional): Number of positions to jump between adjacent pairs of wires. Defaults to 1. + circular (bool, optional): Flag indicating if the pattern should be circular. Defaults to False. """ + """pattern: circular = False jump = 1: [0, 1], [1, 2], [2, 3], [3, 4], [4, 5] @@ -677,20 +694,21 @@ def forward(self, q_device): class Op2QFit32Layer(tq.QuantumModule): """ - Quantum layer applying the same two-qubit operation to all pairs of adjacent wires, fitting to 32 operations. + Quantum layer applying the same two-qubit operation to all pairs of adjacent wires, fitting to 32 operations. - This class represents a quantum layer that applies the same two-qubit operation to all pairs of adjacent wires in the quantum device. The pairs of wires can be determined in a circular or non-circular pattern based on the specified jump. The layer is designed to fit to 32 operations by repeating the same operation pattern multiple times. + This class represents a quantum layer that applies the same two-qubit operation to all pairs of adjacent wires in the quantum device. The pairs of wires can be determined in a circular or non-circular pattern based on the specified jump. The layer is designed to fit to 32 operations by repeating the same operation pattern multiple times. - Args: - op (tq.Operator): Two-qubit operation to be applied. - n_wires (int): Number of wires in the quantum device. - has_params (bool, optional): Flag indicating if the operation has parameters. Defaults to False. - trainable (bool, optional): Flag indicating if the operation is trainable. Defaults to False. - wire_reverse (bool, optional): Flag indicating if the order of wires in each pair should be reversed. Defaults to False. - jump (int, optional): Number of positions to jump between adjacent pairs of wires. Defaults to 1. - circular (bool, optional): Flag indicating if the pattern should be circular. Defaults to False. + Args: + op (tq.Operator): Two-qubit operation to be applied. + n_wires (int): Number of wires in the quantum device. + has_params (bool, optional): Flag indicating if the operation has parameters. Defaults to False. + trainable (bool, optional): Flag indicating if the operation is trainable. Defaults to False. + wire_reverse (bool, optional): Flag indicating if the order of wires in each pair should be reversed. Defaults to False. + jump (int, optional): Number of positions to jump between adjacent pairs of wires. Defaults to 1. + circular (bool, optional): Flag indicating if the pattern should be circular. Defaults to False. + + """ - """ def __init__( self, op, @@ -730,18 +748,19 @@ def forward(self, q_device): class Op2QButterflyLayer(tq.QuantumModule): """ - Quantum layer applying the same two-qubit operation in a butterfly pattern. + Quantum layer applying the same two-qubit operation in a butterfly pattern. - This class represents a quantum layer that applies the same two-qubit operation in a butterfly pattern. The butterfly pattern connects the first and last wire, the second and second-to-last wire, and so on, until the center wire(s) in the case of an odd number of wires. + This class represents a quantum layer that applies the same two-qubit operation in a butterfly pattern. The butterfly pattern connects the first and last wire, the second and second-to-last wire, and so on, until the center wire(s) in the case of an odd number of wires. - Args: - op (tq.Operator): Two-qubit operation to be applied. - n_wires (int): Number of wires in the quantum device. - has_params (bool, optional): Flag indicating if the operation has parameters. Defaults to False. - trainable (bool, optional): Flag indicating if the operation is trainable. Defaults to False. - wire_reverse (bool, optional): Flag indicating if the order of wires in each pair should be reversed. Defaults to False. + Args: + op (tq.Operator): Two-qubit operation to be applied. + n_wires (int): Number of wires in the quantum device. + has_params (bool, optional): Flag indicating if the operation has parameters. Defaults to False. + trainable (bool, optional): Flag indicating if the operation is trainable. Defaults to False. + wire_reverse (bool, optional): Flag indicating if the order of wires in each pair should be reversed. Defaults to False. + + """ - """ """pattern: [0, 5], [1, 4], [2, 3]""" def __init__( @@ -766,20 +785,21 @@ def forward(self, q_device): self.ops_all[k](q_device, wires=wires) -class Op2QDenseLayer(tq.QuantumModule): +class EntangleFull(tq.QuantumModule): """ - Quantum layer applying the same two-qubit operation in a dense pattern. + Quantum layer applying the same two-qubit operation in a dense pattern. + + This class represents a quantum layer that applies the same two-qubit operation in a dense pattern. The dense pattern connects every pair of wires, ensuring that each wire is connected to every other wire exactly once. - This class represents a quantum layer that applies the same two-qubit operation in a dense pattern. The dense pattern connects every pair of wires, ensuring that each wire is connected to every other wire exactly once. + Args: + op (tq.Operator): Two-qubit operation to be applied. + n_wires (int): Number of wires in the quantum device. + has_params (bool, optional): Flag indicating if the operation has parameters. Defaults to False. + trainable (bool, optional): Flag indicating if the operation is trainable. Defaults to False. + wire_reverse (bool, optional): Flag indicating if the order of wires in each pair should be reversed. Defaults to False. - Args: - op (tq.Operator): Two-qubit operation to be applied. - n_wires (int): Number of wires in the quantum device. - has_params (bool, optional): Flag indicating if the operation has parameters. Defaults to False. - trainable (bool, optional): Flag indicating if the operation is trainable. Defaults to False. - wire_reverse (bool, optional): Flag indicating if the order of wires in each pair should be reversed. Defaults to False. + """ - """ """pattern: [0, 1], [0, 2], [0, 3], [0, 4], [0, 5] [1, 2], [1, 3], [1, 4], [1, 5] @@ -813,25 +833,30 @@ def forward(self, q_device): k += 1 +# Adding an alias to the previous name +Op2QDenseLayer = EntangleFull + + class LayerTemplate0(tq.QuantumModule): """ - A template for a custom quantum layer. + A template for a custom quantum layer. - Args: - arch (dict, optional): The architecture configuration for the layer. Defaults to None. + Args: + arch (dict, optional): The architecture configuration for the layer. Defaults to None. - Attributes: - n_wires (int): The number of wires in the layer. - arch (dict): The architecture configuration for the layer. - n_blocks (int): The number of blocks in the layer. (Optional) - n_layers_per_block (int): The number of layers per block. (Optional) - layers_all (tq.QuantumModuleList): The list of layers in the template. + Attributes: + n_wires (int): The number of wires in the layer. + arch (dict): The architecture configuration for the layer. + n_blocks (int): The number of blocks in the layer. (Optional) + n_layers_per_block (int): The number of layers per block. (Optional) + layers_all (tq.QuantumModuleList): The list of layers in the template. - Methods: - build_layers: Abstract method to build the layers of the template. - forward: Applies the quantum layer to the given quantum device. + Methods: + build_layers: Abstract method to build the layers of the template. + forward: Applies the quantum layer to the given quantum device. + + """ - """ def __init__(self, arch: dict = None): super().__init__() self.n_wires = arch["n_wires"] @@ -854,25 +879,24 @@ def forward(self, q_device: tq.QuantumDevice): class U3CU3Layer0(LayerTemplate0): """ - Layer template with U3 and CU3 blocks. + Layer template with U3 and CU3 blocks. - This layer template consists of U3 and CU3 blocks repeated for the specified number of blocks. + This layer template consists of U3 and CU3 blocks repeated for the specified number of blocks. - Args: - arch (dict, optional): The architecture configuration for the layer. Defaults to None. - - Attributes: - n_wires (int): The number of wires in the layer. - arch (dict): The architecture configuration for the layer. - n_blocks (int): The number of blocks in the layer. - layers_all (tq.QuantumModuleList): The list of layers in the template. + Args: + arch (dict, optional): The architecture configuration for the layer. Defaults to None. - Methods: - build_layers: Builds the U3 and CU3 layers for the template. - forward: Applies the quantum layer to the given quantum device. + Attributes: + n_wires (int): The number of wires in the layer. + arch (dict): The architecture configuration for the layer. + n_blocks (int): The number of blocks in the layer. + layers_all (tq.QuantumModuleList): The list of layers in the template. - """ + Methods: + build_layers: Builds the U3 and CU3 layers for the template. + forward: Applies the quantum layer to the given quantum device. + """ def build_layers(self): layers_all = tq.QuantumModuleList() @@ -897,25 +921,24 @@ def build_layers(self): class CU3Layer0(LayerTemplate0): """ - Layer template with CU3 blocks. - - This layer template consists of CU3 blocks repeated for the specified number of blocks. + Layer template with CU3 blocks. - Args: - arch (dict, optional): The architecture configuration for the layer. Defaults to None. + This layer template consists of CU3 blocks repeated for the specified number of blocks. - Attributes: - n_wires (int): The number of wires in the layer. - arch (dict): The architecture configuration for the layer. - n_blocks (int): The number of blocks in the layer. - layers_all (tq.QuantumModuleList): The list of layers in the template. + Args: + arch (dict, optional): The architecture configuration for the layer. Defaults to None. - Methods: - build_layers: Builds the CU3 layers for the template. - forward: Applies the quantum layer to the given quantum device. + Attributes: + n_wires (int): The number of wires in the layer. + arch (dict): The architecture configuration for the layer. + n_blocks (int): The number of blocks in the layer. + layers_all (tq.QuantumModuleList): The list of layers in the template. - """ + Methods: + build_layers: Builds the CU3 layers for the template. + forward: Applies the quantum layer to the given quantum device. + """ def build_layers(self): layers_all = tq.QuantumModuleList() @@ -935,25 +958,24 @@ def build_layers(self): class CXRZSXLayer0(LayerTemplate0): """ - Layer template with CXRZSX blocks. + Layer template with CXRZSX blocks. - This layer template consists of CXRZSX blocks, which include RZ, CNOT, and SX gates, repeated for the specified number of blocks. + This layer template consists of CXRZSX blocks, which include RZ, CNOT, and SX gates, repeated for the specified number of blocks. - Args: - arch (dict, optional): The architecture configuration for the layer. Defaults to None. + Args: + arch (dict, optional): The architecture configuration for the layer. Defaults to None. - Attributes: - n_wires (int): The number of wires in the layer. - arch (dict): The architecture configuration for the layer. - n_blocks (int): The number of blocks in the layer. - layers_all (tq.QuantumModuleList): The list of layers in the template. + Attributes: + n_wires (int): The number of wires in the layer. + arch (dict): The architecture configuration for the layer. + n_blocks (int): The number of blocks in the layer. + layers_all (tq.QuantumModuleList): The list of layers in the template. - Methods: - build_layers: Builds the CXRZSX layers for the template. - forward: Applies the quantum layer to the given quantum device. - - """ + Methods: + build_layers: Builds the CXRZSX layers for the template. + forward: Applies the quantum layer to the given quantum device. + """ def build_layers(self): layers_all = tq.QuantumModuleList() @@ -987,24 +1009,25 @@ def build_layers(self): class SethLayer0(LayerTemplate0): """ - Layer template with Seth blocks. + Layer template with Seth blocks. - This layer template consists of Seth blocks, which include RZZ and RY gates, repeated for the specified number of blocks. + This layer template consists of Seth blocks, which include RZZ and RY gates, repeated for the specified number of blocks. - Args: - arch (dict, optional): The architecture configuration for the layer. Defaults to None. + Args: + arch (dict, optional): The architecture configuration for the layer. Defaults to None. - Attributes: - n_wires (int): The number of wires in the layer. - arch (dict): The architecture configuration for the layer. - n_blocks (int): The number of blocks in the layer. - layers_all (tq.QuantumModuleList): The list of layers in the template. + Attributes: + n_wires (int): The number of wires in the layer. + arch (dict): The architecture configuration for the layer. + n_blocks (int): The number of blocks in the layer. + layers_all (tq.QuantumModuleList): The list of layers in the template. - Methods: - build_layers: Builds the Seth layers for the template. - forward: Applies the quantum layer to the given quantum device. + Methods: + build_layers: Builds the Seth layers for the template. + forward: Applies the quantum layer to the given quantum device. + + """ - """ def build_layers(self): layers_all = tq.QuantumModuleList() for k in range(self.arch["n_blocks"]): @@ -1028,24 +1051,25 @@ def build_layers(self): class SethLayer1(LayerTemplate0): """ - Layer template with extended Seth blocks. + Layer template with extended Seth blocks. + + This layer template consists of extended Seth blocks, which include RZZ and RY gates repeated twice for each block. - This layer template consists of extended Seth blocks, which include RZZ and RY gates repeated twice for each block. + Args: + arch (dict, optional): The architecture configuration for the layer. Defaults to None. - Args: - arch (dict, optional): The architecture configuration for the layer. Defaults to None. + Attributes: + n_wires (int): The number of wires in the layer. + arch (dict): The architecture configuration for the layer. + n_blocks (int): The number of blocks in the layer. + layers_all (tq.QuantumModuleList): The list of layers in the template. - Attributes: - n_wires (int): The number of wires in the layer. - arch (dict): The architecture configuration for the layer. - n_blocks (int): The number of blocks in the layer. - layers_all (tq.QuantumModuleList): The list of layers in the template. + Methods: + build_layers: Builds the extended Seth layers for the template. + forward: Applies the quantum layer to the given quantum device. - Methods: - build_layers: Builds the extended Seth layers for the template. - forward: Applies the quantum layer to the given quantum device. + """ - """ def build_layers(self): layers_all = tq.QuantumModuleList() for k in range(self.arch["n_blocks"]): @@ -1079,24 +1103,25 @@ def build_layers(self): class SethLayer2(LayerTemplate0): """ - Layer template with Seth blocks using Op2QFit32Layer. + Layer template with Seth blocks using Op2QFit32Layer. - This layer template consists of Seth blocks using the Op2QFit32Layer, which includes RZZ gates and supports 32 wires. + This layer template consists of Seth blocks using the Op2QFit32Layer, which includes RZZ gates and supports 32 wires. - Args: - arch (dict, optional): The architecture configuration for the layer. Defaults to None. + Args: + arch (dict, optional): The architecture configuration for the layer. Defaults to None. - Attributes: - n_wires (int): The number of wires in the layer. - arch (dict): The architecture configuration for the layer. - n_blocks (int): The number of blocks in the layer. - layers_all (tq.QuantumModuleList): The list of layers in the template. + Attributes: + n_wires (int): The number of wires in the layer. + arch (dict): The architecture configuration for the layer. + n_blocks (int): The number of blocks in the layer. + layers_all (tq.QuantumModuleList): The list of layers in the template. - Methods: - build_layers: Builds the Seth layers with Op2QFit32Layer for the template. - forward: Applies the quantum layer to the given quantum device. + Methods: + build_layers: Builds the Seth layers with Op2QFit32Layer for the template. + forward: Applies the quantum layer to the given quantum device. + + """ - """ def build_layers(self): layers_all = tq.QuantumModuleList() for k in range(self.arch["n_blocks"]): @@ -1115,24 +1140,25 @@ def build_layers(self): class RZZLayer0(LayerTemplate0): """ - Layer template with RZZ blocks. + Layer template with RZZ blocks. - This layer template consists of RZZ blocks using the Op2QAllLayer. + This layer template consists of RZZ blocks using the Op2QAllLayer. - Args: - arch (dict, optional): The architecture configuration for the layer. Defaults to None. + Args: + arch (dict, optional): The architecture configuration for the layer. Defaults to None. - Attributes: - n_wires (int): The number of wires in the layer. - arch (dict): The architecture configuration for the layer. - n_blocks (int): The number of blocks in the layer. - layers_all (tq.QuantumModuleList): The list of layers in the template. + Attributes: + n_wires (int): The number of wires in the layer. + arch (dict): The architecture configuration for the layer. + n_blocks (int): The number of blocks in the layer. + layers_all (tq.QuantumModuleList): The list of layers in the template. - Methods: - build_layers: Builds the RZZ layers with Op2QAllLayer for the template. - forward: Applies the quantum layer to the given quantum device. + Methods: + build_layers: Builds the RZZ layers with Op2QAllLayer for the template. + forward: Applies the quantum layer to the given quantum device. + + """ - """ def build_layers(self): layers_all = tq.QuantumModuleList() for k in range(self.arch["n_blocks"]): @@ -1151,24 +1177,25 @@ def build_layers(self): class BarrenLayer0(LayerTemplate0): """ - Layer template with Barren blocks. + Layer template with Barren blocks. - This layer template consists of Barren blocks using the Op1QAllLayer and Op2QAllLayer. + This layer template consists of Barren blocks using the Op1QAllLayer and Op2QAllLayer. - Args: - arch (dict, optional): The architecture configuration for the layer. Defaults to None. + Args: + arch (dict, optional): The architecture configuration for the layer. Defaults to None. - Attributes: - n_wires (int): The number of wires in the layer. - arch (dict): The architecture configuration for the layer. - n_blocks (int): The number of blocks in the layer. - layers_all (tq.QuantumModuleList): The list of layers in the template. + Attributes: + n_wires (int): The number of wires in the layer. + arch (dict): The architecture configuration for the layer. + n_blocks (int): The number of blocks in the layer. + layers_all (tq.QuantumModuleList): The list of layers in the template. - Methods: - build_layers: Builds the Barren layers with Op1QAllLayer and Op2QAllLayer for the template. - forward: Applies the quantum layer to the given quantum device. + Methods: + build_layers: Builds the Barren layers with Op1QAllLayer and Op2QAllLayer for the template. + forward: Applies the quantum layer to the given quantum device. + + """ - """ def build_layers(self): layers_all = tq.QuantumModuleList() layers_all.append( @@ -1199,24 +1226,25 @@ def build_layers(self): class FarhiLayer0(LayerTemplate0): """ - Layer template with Farhi blocks. + Layer template with Farhi blocks. - This layer template consists of Farhi blocks using the Op2QAllLayer. + This layer template consists of Farhi blocks using the Op2QAllLayer. - Args: - arch (dict, optional): The architecture configuration for the layer. Defaults to None. + Args: + arch (dict, optional): The architecture configuration for the layer. Defaults to None. - Attributes: - n_wires (int): The number of wires in the layer. - arch (dict): The architecture configuration for the layer. - n_blocks (int): The number of blocks in the layer. - layers_all (tq.QuantumModuleList): The list of layers in the template. + Attributes: + n_wires (int): The number of wires in the layer. + arch (dict): The architecture configuration for the layer. + n_blocks (int): The number of blocks in the layer. + layers_all (tq.QuantumModuleList): The list of layers in the template. - Methods: - build_layers: Builds the Farhi layers with Op2QAllLayer for the template. - forward: Applies the quantum layer to the given quantum device. + Methods: + build_layers: Builds the Farhi layers with Op2QAllLayer for the template. + forward: Applies the quantum layer to the given quantum device. + + """ - """ def build_layers(self): layers_all = tq.QuantumModuleList() for k in range(self.arch["n_blocks"]): @@ -1245,24 +1273,25 @@ def build_layers(self): class MaxwellLayer0(LayerTemplate0): """ - Layer template with Maxwell blocks. + Layer template with Maxwell blocks. + + This layer template consists of Maxwell blocks using the Op1QAllLayer and Op2QAllLayer modules. - This layer template consists of Maxwell blocks using the Op1QAllLayer and Op2QAllLayer modules. + Args: + arch (dict, optional): The architecture configuration for the layer. Defaults to None. - Args: - arch (dict, optional): The architecture configuration for the layer. Defaults to None. + Attributes: + n_wires (int): The number of wires in the layer. + arch (dict): The architecture configuration for the layer. + n_blocks (int): The number of blocks in the layer. + layers_all (tq.QuantumModuleList): The list of layers in the template. - Attributes: - n_wires (int): The number of wires in the layer. - arch (dict): The architecture configuration for the layer. - n_blocks (int): The number of blocks in the layer. - layers_all (tq.QuantumModuleList): The list of layers in the template. + Methods: + build_layers: Builds the Maxwell layers with Op1QAllLayer and Op2QAllLayer for the template. + forward: Applies the quantum layer to the given quantum device. - Methods: - build_layers: Builds the Maxwell layers with Op1QAllLayer and Op2QAllLayer for the template. - forward: Applies the quantum layer to the given quantum device. + """ - """ def build_layers(self): layers_all = tq.QuantumModuleList() for k in range(self.arch["n_blocks"]): @@ -1317,24 +1346,25 @@ def build_layers(self): class RYRYCXLayer0(LayerTemplate0): """ - Layer template with RYRYCX blocks. + Layer template with RYRYCX blocks. + + This layer template consists of RYRYCX blocks using the Op1QAllLayer and CXLayer modules. - This layer template consists of RYRYCX blocks using the Op1QAllLayer and CXLayer modules. + Args: + arch (dict, optional): The architecture configuration for the layer. Defaults to None. - Args: - arch (dict, optional): The architecture configuration for the layer. Defaults to None. + Attributes: + n_wires (int): The number of wires in the layer. + arch (dict): The architecture configuration for the layer. + n_blocks (int): The number of blocks in the layer. + layers_all (tq.QuantumModuleList): The list of layers in the template. - Attributes: - n_wires (int): The number of wires in the layer. - arch (dict): The architecture configuration for the layer. - n_blocks (int): The number of blocks in the layer. - layers_all (tq.QuantumModuleList): The list of layers in the template. + Methods: + build_layers: Builds the RYRYCX layers with Op1QAllLayer and CXLayer for the template. + forward: Applies the quantum layer to the given quantum device. - Methods: - build_layers: Builds the RYRYCX layers with Op1QAllLayer and CXLayer for the template. - forward: Applies the quantum layer to the given quantum device. + """ - """ def build_layers(self): layers_all = tq.QuantumModuleList() for k in range(self.arch["n_blocks"]): @@ -1349,23 +1379,23 @@ def build_layers(self): class RYRYRYCXCXCXLayer0(LayerTemplate0): """ - Layer template with RYRYRYCXCXCX blocks. + Layer template with RYRYRYCXCXCX blocks. - This layer template consists of RYRYRYCXCXCX blocks using the RYRYCXCXLayer module. + This layer template consists of RYRYRYCXCXCX blocks using the RYRYCXCXLayer module. - Args: - arch (dict, optional): The architecture configuration for the layer. Defaults to None. + Args: + arch (dict, optional): The architecture configuration for the layer. Defaults to None. - Attributes: - n_wires (int): The number of wires in the layer. - arch (dict): The architecture configuration for the layer. - n_blocks (int): The number of blocks in the layer. - layers_all (tq.QuantumModuleList): The list of layers in the template. + Attributes: + n_wires (int): The number of wires in the layer. + arch (dict): The architecture configuration for the layer. + n_blocks (int): The number of blocks in the layer. + layers_all (tq.QuantumModuleList): The list of layers in the template. - Methods: - build_layers: Builds the RYRYRYCXCXCX layers with RYRYCXCXLayer for the template. + Methods: + build_layers: Builds the RYRYRYCXCXCX layers with RYRYCXCXLayer for the template. - """ + """ def build_layers(self): layers_all = tq.QuantumModuleList() @@ -1381,24 +1411,25 @@ def build_layers(self): class RYRYRYLayer0(LayerTemplate0): """ - Layer template with RYRYRYCXCXCX blocks. + Layer template with RYRYRYCXCXCX blocks. - This layer template consists of RYRYRYCXCXCX blocks using the Op1QAllLayer and CXCXCXLayer modules. + This layer template consists of RYRYRYCXCXCX blocks using the Op1QAllLayer and CXCXCXLayer modules. - Args: - arch (dict, optional): The architecture configuration for the layer. Defaults to None. + Args: + arch (dict, optional): The architecture configuration for the layer. Defaults to None. - Attributes: - n_wires (int): The number of wires in the layer. - arch (dict): The architecture configuration for the layer. - n_blocks (int): The number of blocks in the layer. - layers_all (tq.QuantumModuleList): The list of layers in the template. + Attributes: + n_wires (int): The number of wires in the layer. + arch (dict): The architecture configuration for the layer. + n_blocks (int): The number of blocks in the layer. + layers_all (tq.QuantumModuleList): The list of layers in the template. - Methods: - build_layers: Builds the RYRYRYCXCXCX layers with Op1QAllLayer and CXCXCXLayer for the template. + Methods: + build_layers: Builds the RYRYRYCXCXCX layers with Op1QAllLayer and CXCXCXLayer for the template. - """ + """ + def build_layers(self): layers_all = tq.QuantumModuleList() for k in range(self.arch["n_blocks"]): @@ -1412,24 +1443,25 @@ def build_layers(self): class RYRYRYSWAPSWAPLayer0(LayerTemplate0): """ - Layer template with RYRYRYSWAPSWAP blocks. + Layer template with RYRYRYSWAPSWAP blocks. - This layer template consists of RYRYRYSWAPSWAP blocks using the Op1QAllLayer and SWAPSWAPLayer modules. + This layer template consists of RYRYRYSWAPSWAP blocks using the Op1QAllLayer and SWAPSWAPLayer modules. - Args: - arch (dict, optional): The architecture configuration for the layer. Defaults to None. + Args: + arch (dict, optional): The architecture configuration for the layer. Defaults to None. - Attributes: - n_wires (int): The number of wires in the layer. - arch (dict): The architecture configuration for the layer. - n_blocks (int): The number of blocks in the layer. - layers_all (tq.QuantumModuleList): The list of layers in the template. + Attributes: + n_wires (int): The number of wires in the layer. + arch (dict): The architecture configuration for the layer. + n_blocks (int): The number of blocks in the layer. + layers_all (tq.QuantumModuleList): The list of layers in the template. - Methods: - build_layers: Builds the RYRYRYSWAPSWAP layers with Op1QAllLayer and SWAPSWAPLayer for the template. + Methods: + build_layers: Builds the RYRYRYSWAPSWAP layers with Op1QAllLayer and SWAPSWAPLayer for the template. - """ + """ + def build_layers(self): layers_all = tq.QuantumModuleList() for k in range(self.arch["n_blocks"]): @@ -1444,23 +1476,23 @@ def build_layers(self): class SWAPSWAPLayer0(LayerTemplate0): """ - Layer template with SWAPSWAP blocks. + Layer template with SWAPSWAP blocks. - This layer template consists of SWAPSWAP blocks using the SWAPSWAPLayer module. + This layer template consists of SWAPSWAP blocks using the SWAPSWAPLayer module. - Args: - arch (dict, optional): The architecture configuration for the layer. Defaults to None. + Args: + arch (dict, optional): The architecture configuration for the layer. Defaults to None. - Attributes: - n_wires (int): The number of wires in the layer. - arch (dict): The architecture configuration for the layer. - n_blocks (int): The number of blocks in the layer. - layers_all (tq.QuantumModuleList): The list of layers in the template. + Attributes: + n_wires (int): The number of wires in the layer. + arch (dict): The architecture configuration for the layer. + n_blocks (int): The number of blocks in the layer. + layers_all (tq.QuantumModuleList): The list of layers in the template. - Methods: - build_layers: Builds the SWAPSWAP layers with SWAPSWAPLayer for the template. + Methods: + build_layers: Builds the SWAPSWAP layers with SWAPSWAPLayer for the template. - """ + """ def build_layers(self): layers_all = tq.QuantumModuleList() @@ -1471,23 +1503,24 @@ def build_layers(self): class RXYZCXLayer0(LayerTemplate0): """ - Layer template with RXYZCX blocks. + Layer template with RXYZCX blocks. - This layer template consists of RXYZCX blocks using the RXYZCXLayer module. + This layer template consists of RXYZCX blocks using the RXYZCXLayer module. - Args: - arch (dict, optional): The architecture configuration for the layer. Defaults to None. + Args: + arch (dict, optional): The architecture configuration for the layer. Defaults to None. - Attributes: - n_wires (int): The number of wires in the layer. - arch (dict): The architecture configuration for the layer. - n_blocks (int): The number of blocks in the layer. - layers_all (tq.QuantumModuleList): The list of layers in the template. + Attributes: + n_wires (int): The number of wires in the layer. + arch (dict): The architecture configuration for the layer. + n_blocks (int): The number of blocks in the layer. + layers_all (tq.QuantumModuleList): The list of layers in the template. - Methods: - build_layers: Builds the RXYZCX layers with RXYZCXLayer for the template. + Methods: + build_layers: Builds the RXYZCX layers with RXYZCXLayer for the template. + + """ - """ def build_layers(self): layers_all = tq.QuantumModuleList() for k in range(self.arch["n_blocks"]): @@ -1619,6 +1652,190 @@ def forward(self, q_device: tq.QuantumDevice): self.gates_all(q_device) +class EntangleLinear(Op2QAllLayer): + """ + Quantum layer applying the same two-qubit operation to all pairs of adjacent wires. + This class represents a quantum layer that applies the same two-qubit operation to all pairs of adjacent wires + in the quantum device. + + Args: + op (tq.Operator): Two-qubit operation to be applied. + n_wires (int): Number of wires in the quantum device. + has_params (bool, optional): Flag indicating if the operation has parameters. Defaults to False. + trainable (bool, optional): Flag indicating if the operation is trainable. Defaults to False. + wire_reverse (bool, optional): Flag indicating if the order of wires in each pair should be reversed. Defaults to False. + """ + + """pattern: [0, 1], [1, 2], [2, 3], [3, 4], [4, 5] + """ + + def __init__( + self, + op, + n_wires: int, + has_params=False, + trainable=False, + wire_reverse=False, + ): + super().__init__( + op=op, + n_wires=n_wires, + has_params=has_params, + trainable=trainable, + wire_reverse=wire_reverse, + jump=1, + circular=False, + ) + + +class EntangleCircular(Op2QAllLayer): + """ + Quantum layer applying the same two-qubit operation to all pairs of adjacent wires in a circular manner. + This class represents a quantum layer that applies the same two-qubit operation to all pairs of adjacent wires + in the quantum device with a wrap-around + + Args: + op (tq.Operator): Two-qubit operation to be applied. + n_wires (int): Number of wires in the quantum device. + has_params (bool, optional): Flag indicating if the operation has parameters. Defaults to False. + trainable (bool, optional): Flag indicating if the operation is trainable. Defaults to False. + wire_reverse (bool, optional): Flag indicating if the order of wires in each pair should be reversed. Defaults to False. + jump (int, optional): Number of positions to jump between adjacent pairs of wires. Defaults to 1. + circular (bool, optional): Flag indicating if the pattern should be circular. Defaults to False. + + """ + + """pattern: [0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 0] + """ + + def __init__( + self, + op, + n_wires: int, + has_params=False, + trainable=False, + wire_reverse=False, + ): + super().__init__( + op=op, + n_wires=n_wires, + has_params=has_params, + trainable=trainable, + wire_reverse=wire_reverse, + jump=1, + circular=True, + ) + + +class EntanglePairwise(tq.QuantumModule): + """ + Quantum layer applying the same two-qubit operation in a pair-wise pattern + + This class represents a quantum layer that applies the same two-qubit operation in a pairwise pattern. The pairwise pattern first entangles all qubits i with i+1 for even i then all qubits i with i+1 for odd i. + + Args: + op (tq.Operator): Two-qubit operation to be applied. + n_wires (int): Number of wires in the quantum device. + has_params (bool, optional): Flag indicating if the operation has parameters. Defaults to False. + trainable (bool, optional): Flag indicating if the operation is trainable. Defaults to False. + wire_reverse (bool, optional): Flag indicating if the order of wires in each pair should be reversed. Defaults to False. + + """ + + """pattern: + [0, 1], [2, 3], [4, 5] + [1, 2], [3, 4] + """ + + def __init__( + self, op, n_wires: int, has_params=False, trainable=False, wire_reverse=False + ): + super().__init__() + self.n_wires = n_wires + self.op = op + self.ops_all = tq.QuantumModuleList() + + # reverse the wires, for example from [1, 2] to [2, 1] + self.wire_reverse = wire_reverse + + for k in range(self.n_wires - 1): + self.ops_all.append(op(has_params=has_params, trainable=trainable)) + + def forward(self, q_device): + k = 0 + + # entangle qubit i with i+1 for all even values of i + for i in range(self.n_wires - 1): + if i % 2 == 0: + wires = [i, i + 1] + if self.wire_reverse: + wires.reverse() + self.ops_all[k](q_device, wires=wires) + k += 1 + + # entangle qubit i with i+1 for all odd values of i + for i in range(1, self.n_wires - 1): + if i % 2 == 1: + wires = [i, i + 1] + if self.wire_reverse: + wires.reverse() + self.ops_all[k](q_device, wires=wires) + k += 1 + + +class EntanglementLayer(tq.QuantumModule): + """ + Quantum layer applying a specified two-qubit entanglement type to all qubits. The entanglement types include full, linear, pairwise, and circular. + + Args: + op (tq.Operator): Two-qubit operation to be applied. + n_wires (int): Number of wires in the quantum device. + entanglement (str): Type of entanglement from ["full", "linear", "pairwise", "circular"] + has_params (bool, optional): Flag indicating if the operation has parameters. Defaults to False. + trainable (bool, optional): Flag indicating if the operation is trainable. Defaults to False. + wire_reverse (bool, optional): Flag indicating if the order of wires in each pair should be reversed. Defaults to False. + jump (int, optional): Number of positions to jump between adjacent pairs of wires. Defaults to 1. + circular (bool, optional): Flag indicating if the pattern should be circular. Defaults to False. + + """ + + def __init__( + self, + op, + n_wires: int, + entanglement: str, + has_params=False, + trainable=False, + wire_reverse=False, + ): + super().__init__() + + entanglement_to_class = { + "full": EntangleFull, + "linear": EntangleLinear, + "pairwise": EntanglePairwise, + "circular": EntangleCircular, + } + + self.entanglement_class = entanglement_to_class.get(entanglement, None) + + assert ( + self.entanglement_class is not None + ), f"invalid entanglement type {entanglement}" + + self.entanglement_class.__init__( + op=op, + n_wires=n_wires, + has_params=has_params, + trainable=trainable, + wire_reverse=wire_reverse, + ) + + @tq.static_support + def forward(self, q_device): + self.entanglement_class.forward(q_device) + + layer_name_dict = { "u3cu3_0": U3CU3Layer0, "cu3_0": CU3Layer0, diff --git a/torchquantum/plugin/qiskit/qiskit_plugin.py b/torchquantum/plugin/qiskit/qiskit_plugin.py index 9dca0649..bca3a7d2 100644 --- a/torchquantum/plugin/qiskit/qiskit_plugin.py +++ b/torchquantum/plugin/qiskit/qiskit_plugin.py @@ -682,7 +682,10 @@ def qiskit2tq_Operator(circ: QuantumCircuit): try: p2v_orig = circ._layout.final_layout.get_physical_bits().copy() except: - p2v_orig = circ._layout.get_physical_bits().copy() + try: + p2v_orig = circ._layout.get_physical_bits().copy() + except: + p2v_orig = circ._layout.initial_layout.get_physical_bits().copy() p2v = {} for p, v in p2v_orig.items(): if v.register.name == "q": diff --git a/torchquantum/plugin/qiskit/qiskit_unitary_gate.py b/torchquantum/plugin/qiskit/qiskit_unitary_gate.py index d2b93577..6e520b96 100644 --- a/torchquantum/plugin/qiskit/qiskit_unitary_gate.py +++ b/torchquantum/plugin/qiskit/qiskit_unitary_gate.py @@ -23,7 +23,6 @@ from qiskit.circuit.exceptions import CircuitError from qiskit.circuit._utils import _compute_control_matrix from qiskit.circuit.library.standard_gates import U3Gate -from qiskit.extensions.quantum_initializer import isometry from qiskit.quantum_info.operators.predicates import matrix_equal from qiskit.quantum_info.operators.predicates import is_unitary_matrix from qiskit.quantum_info.synthesis.one_qubit_decompose import OneQubitEulerDecomposer @@ -117,7 +116,7 @@ def _define(self): else: q = QuantumRegister(self.num_qubits, "q") qc = QuantumCircuit(q, name=self.name) - qc.append(isometry.Isometry(self.to_matrix(), 0, 0), qargs=q[:]) + qc.append(qiskit.circuit.library.Isometry(self.to_matrix(), 0, 0), qargs=q[:]) self.definition = qc def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): @@ -139,7 +138,7 @@ def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): cmat = _compute_control_matrix( self.to_matrix(), num_ctrl_qubits, ctrl_state=None ) - iso = isometry.Isometry(cmat, 0, 0) + iso = qiskit.circuit.library.Isometry(cmat, 0, 0) cunitary = ControlledGate( "c-unitary", num_qubits=self.num_qubits + num_ctrl_qubits, diff --git a/torchquantum/pulse/utils.py b/torchquantum/pulse/utils.py index e80465c2..eb0c7b82 100644 --- a/torchquantum/pulse/utils.py +++ b/torchquantum/pulse/utils.py @@ -40,7 +40,7 @@ def InitialState(n_qubit = 1, state = [0]): def InitialDensity(n_qubit = 1, state = [0]): initial_state = InitialState(n_qubit, state) - initial_density = torch.ger(initial_state, torch.conj(initial_state)) + initial_density = torch.outer(initial_state, torch.conj(initial_state)) return initial_density def H_2q_example(pulse, dt):