From 8882745c7f7f674febf2804679a3b1e536696f47 Mon Sep 17 00:00:00 2001 From: GenericP3rson Date: Sun, 30 Jul 2023 12:33:37 -0500 Subject: [PATCH 01/11] nlocal circuit --- torchquantum/layer/nlocal.py | 101 +++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 torchquantum/layer/nlocal.py diff --git a/torchquantum/layer/nlocal.py b/torchquantum/layer/nlocal.py new file mode 100644 index 00000000..a0b8d44f --- /dev/null +++ b/torchquantum/layer/nlocal.py @@ -0,0 +1,101 @@ +""" +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 torchquantum as tq +import torchquantum.layers as layers + + +class NLocal(layers.LayerTemplate0): + """Layer Template for a NLocal Class + + Args: + rotation_ops (list): gates for the rotation layer as a list of torchquantum operations + entanglement_ops (list): gates for the entanglement layer as a list of torchquantum operations + arch (dict): circuit architecture in a dictionary format + rotation_layer (torchquantum.QuantumModule): type of rotation layer in a torchquantum.QuantumModule format + entanglement_layer (torchquantum.QuantumModule): type of entanglement layer in a torchquantum.QuantumModule format + rotation_layer_params (dict): additional parameters for the rotation layer in a dictionary format + entanglement_layer_params (dict): additional parameters for the entanglement layer in a dictionary format + skip_final_rotation_layer (bool): whether or not to add the final rotation layer as a boolean + """ + + def __init__( + self, + rotation_ops: list, + entanglement_ops: list, + arch: dict = None, + rotation_layer: tq.QuantumModule = tq.layers.Op1QAllLayer, + entanglement_layer: tq.QuantumModule = tq.layers.Op2QAllLayer, + rotation_layer_params: dict = {}, + entanglement_layer_params: dict = {}, + skip_final_rotation_layer: bool = False, + ): + # rotation block options + self.rotation_ops = rotation_ops + self.rotation_layer = rotation_layer + self.rotation_layer_params = rotation_layer_params + + # entanglement block options + self.entanglement_ops = entanglement_ops + self.entanglement_layer = entanglement_layer + self.entanglement_layer_params = entanglement_layer_params + + # extra parameters + self.skip_final_rotation_layer = skip_final_rotation_layer + layers.LayerTemplate0.__init__(self, arch) + + def build_layers(self): + layers_all = tq.QuantumModuleList() + + # repeat for each rep + for _ in range(self.n_blocks): + # add rotation blocks to the qubits + for rot in self.rotation_ops: + layers_all.append( + self.rotation_layer( + op=rot, n_wires=self.n_wires, *self.rotation_layer_params + ) + ) + + # add entanglement blocks to everything + for entanglement in self.entanglement_ops: + layers_all.append( + self.entanglement_layer( + op=entanglement, + n_wires=self.n_wires, + *self.entanglement_layer_params + ) + ) + + # add final rotation layer + if not self.skip_final_rotation_layer: + for rot in self.rotation_ops: + layers_all.append( + self.rotation_layer( + op=rot, n_wires=self.n_wires, *self.rotation_layer_params + ) + ) + + # return QuantumModuleList + return layers_all From 566cf189f3e1d926702fc8404c0aee3ee1038325 Mon Sep 17 00:00:00 2001 From: GenericP3rson Date: Sun, 30 Jul 2023 19:32:45 -0500 Subject: [PATCH 02/11] unpacking params correction and function reformatting --- torchquantum/layer/nlocal.py | 61 +++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 22 deletions(-) diff --git a/torchquantum/layer/nlocal.py b/torchquantum/layer/nlocal.py index a0b8d44f..bf39324c 100644 --- a/torchquantum/layer/nlocal.py +++ b/torchquantum/layer/nlocal.py @@ -37,6 +37,7 @@ class NLocal(layers.LayerTemplate0): entanglement_layer (torchquantum.QuantumModule): type of entanglement layer in a torchquantum.QuantumModule format rotation_layer_params (dict): additional parameters for the rotation layer in a dictionary format entanglement_layer_params (dict): additional parameters for the entanglement layer in a dictionary format + initial_circuit (torchquantum.QuantumModule): initial gates or layer in a QuantumModule format skip_final_rotation_layer (bool): whether or not to add the final rotation layer as a boolean """ @@ -49,6 +50,7 @@ def __init__( entanglement_layer: tq.QuantumModule = tq.layers.Op2QAllLayer, rotation_layer_params: dict = {}, entanglement_layer_params: dict = {}, + initial_circuit: tq.QuantumModule = None, skip_final_rotation_layer: bool = False, ): # rotation block options @@ -62,40 +64,55 @@ def __init__( self.entanglement_layer_params = entanglement_layer_params # extra parameters + self.initial_circuit = initial_circuit self.skip_final_rotation_layer = skip_final_rotation_layer - layers.LayerTemplate0.__init__(self, arch) + + # initialize the LayerTemplate0 + super().__init__(arch) + + def build_rotation_block(self): + """Build rotation block""" + rotation_layers = [] + for rot in self.rotation_ops: + rotation_layers.append( + self.rotation_layer( + op=rot, n_wires=self.n_wires, **self.rotation_layer_params + ) + ) + return rotation_layers + + def build_entanglement_block(self): + """Build entanglement block""" + entanglement_layers = [] + for entanglement in self.entanglement_ops: + entanglement_layers.append( + self.entanglement_layer( + op=entanglement, + n_wires=self.n_wires, + **self.entanglement_layer_params + ) + ) + return entanglement_layers def build_layers(self): + """Build nlocal circuit""" layers_all = tq.QuantumModuleList() + # add the initial circuit + if self.initial_circuit is not None: + layers_all.append(self.initial_circuit) + # repeat for each rep for _ in range(self.n_blocks): # add rotation blocks to the qubits - for rot in self.rotation_ops: - layers_all.append( - self.rotation_layer( - op=rot, n_wires=self.n_wires, *self.rotation_layer_params - ) - ) + layers_all.extend(self.build_rotation_block()) - # add entanglement blocks to everything - for entanglement in self.entanglement_ops: - layers_all.append( - self.entanglement_layer( - op=entanglement, - n_wires=self.n_wires, - *self.entanglement_layer_params - ) - ) + # add entanglement blocks to the qubits + layers_all.extend(self.build_entanglement_block()) # add final rotation layer if not self.skip_final_rotation_layer: - for rot in self.rotation_ops: - layers_all.append( - self.rotation_layer( - op=rot, n_wires=self.n_wires, *self.rotation_layer_params - ) - ) + layers_all.extend(self.build_rotation_block()) # return QuantumModuleList return layers_all From 4a96e60be213a8b204426f6ad0c4c46a26ee9f9f Mon Sep 17 00:00:00 2001 From: GenericP3rson Date: Sun, 30 Jul 2023 21:51:15 -0500 Subject: [PATCH 03/11] adding TwoLocal --- torchquantum/layer/nlocal.py | 65 ++++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/torchquantum/layer/nlocal.py b/torchquantum/layer/nlocal.py index bf39324c..3bad4c29 100644 --- a/torchquantum/layer/nlocal.py +++ b/torchquantum/layer/nlocal.py @@ -35,6 +35,7 @@ class NLocal(layers.LayerTemplate0): arch (dict): circuit architecture in a dictionary format rotation_layer (torchquantum.QuantumModule): type of rotation layer in a torchquantum.QuantumModule format entanglement_layer (torchquantum.QuantumModule): type of entanglement layer in a torchquantum.QuantumModule format + reps (int): number of reptitions of the rotation and entanglement layers in a integer format rotation_layer_params (dict): additional parameters for the rotation layer in a dictionary format entanglement_layer_params (dict): additional parameters for the entanglement layer in a dictionary format initial_circuit (torchquantum.QuantumModule): initial gates or layer in a QuantumModule format @@ -48,6 +49,7 @@ def __init__( arch: dict = None, rotation_layer: tq.QuantumModule = tq.layers.Op1QAllLayer, entanglement_layer: tq.QuantumModule = tq.layers.Op2QAllLayer, + reps: int = 1, rotation_layer_params: dict = {}, entanglement_layer_params: dict = {}, initial_circuit: tq.QuantumModule = None, @@ -66,6 +68,7 @@ def __init__( # extra parameters self.initial_circuit = initial_circuit self.skip_final_rotation_layer = skip_final_rotation_layer + self.reps = reps # initialize the LayerTemplate0 super().__init__(arch) @@ -89,7 +92,7 @@ def build_entanglement_block(self): self.entanglement_layer( op=entanglement, n_wires=self.n_wires, - **self.entanglement_layer_params + **self.entanglement_layer_params, ) ) return entanglement_layers @@ -103,7 +106,7 @@ def build_layers(self): layers_all.append(self.initial_circuit) # repeat for each rep - for _ in range(self.n_blocks): + for _ in range(self.reps): # add rotation blocks to the qubits layers_all.extend(self.build_rotation_block()) @@ -116,3 +119,61 @@ def build_layers(self): # return QuantumModuleList return layers_all + + +class TwoLocal(NLocal): + """Layer Template for a TwoLocal Class + + Args: + rotation_ops (list): gates for the rotation layer as a list of torchquantum operations + entanglement_ops (list): gates for the entanglement layer as a list of torchquantum operations + arch (dict): circuit architecture in a dictionary format + rotation_layer (torchquantum.QuantumModule): type of rotation layer in a torchquantum.QuantumModule format + entanglement_layer (str): type of entanglement layer in a string ("linear", "reverse_linear", "circular", "full") or tq.QuantumModule format + reps (int): number of reptitions of the rotation and entanglement layers in a integer format + entanglement_layer_params (dict): additional parameters for the entanglement layer in a dictionary forma + initial_circuit (torchquantum.QuantumModule): initial gates or layer in a QuantumModule formatt + skip_final_rotation_layer (bool): whether or not to add the final rotation layer as a boolean + """ + + def __init__( + self, + rotation_ops: list, + entanglement_ops: list, + arch: dict = None, + rotation_layer: tq.QuantumModule = tq.layers.Op1QAllLayer, + entanglement_layer: str = "linear", + reps: int = 1, + entanglement_layer_params: dict = {}, + initial_circuit: tq.QuantumModule = None, + skip_final_rotation_layer: bool = False, + ): + # if passed as string, determine entanglement type + if type(entanglement_layer) == str: + match entanglement_layer: + case "linear": + entanglement_layer = tq.layers.Op2QAllLayer + case "reverse_linear": + entanglement_layer = tq.layers.Op2QAllLayer + entanglement_layer_params = {"wire_reverse": True} + case "circular": + entanglement_layer = tq.layers.Op2QAllLayer + entanglement_layer_params = {"circular": True} + case "full": + entanglement_layer = tq.layers.Op2QDenseLayer + case _: + raise NotImplemented + + # initialize + super().__init__( + arch=arch, + rotation_ops=rotation_ops, + rotation_layer=rotation_layer, + rotation_layer_params={"has_params": True, "trainable": True}, + entanglement_ops=entanglement_ops, + entanglement_layer=entanglement_layer, + entanglement_layer_params=entanglement_layer_params, + initial_circuit=initial_circuit, + reps=reps, + skip_final_rotation_layer=skip_final_rotation_layer, + ) From 617acbb3f712cccb71b830d43e6732f63a1addcd Mon Sep 17 00:00:00 2001 From: GenericP3rson Date: Sun, 30 Jul 2023 21:58:17 -0500 Subject: [PATCH 04/11] added excitationpreserving --- torchquantum/layer/nlocal.py | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/torchquantum/layer/nlocal.py b/torchquantum/layer/nlocal.py index 3bad4c29..73171da9 100644 --- a/torchquantum/layer/nlocal.py +++ b/torchquantum/layer/nlocal.py @@ -162,7 +162,7 @@ def __init__( case "full": entanglement_layer = tq.layers.Op2QDenseLayer case _: - raise NotImplemented + raise NotImplementedError # initialize super().__init__( @@ -177,3 +177,32 @@ def __init__( reps=reps, skip_final_rotation_layer=skip_final_rotation_layer, ) + + +class ExcitationPreserving(TwoLocal): + """Layer Template for a ExcitationPreserving circuit + + Args: + arch (dict): circuit architecture in a dictionary format + entanglement_layer (str): type of entanglement layer in a string ("linear", "reverse_linear", "circular", "full") or tq.QuantumModule format + reps (int): number of reptitions of the rotation and entanglement layers in a integer format + skip_final_rotation_layer (bool): whether or not to add the final rotation layer as a boolean + """ + + def __init__( + self, + arch: dict = None, + entanglement_layer: str = "full", + reps: int = 3, + skip_final_rotation_layer: bool = False, + ): + # construct circuit with rotation layers of RZ and entanglement with RXX and RYY + super().__init__( + arch=arch, + rotation_ops=[tq.RZ], + entanglement_ops=[tq.RXX, tq.RYY], + entanglement_layer=entanglement_layer, + entanglement_layer_params={"has_params": True, "trainable": True}, + reps=reps, + skip_final_rotation_layer=skip_final_rotation_layer, + ) From a58a0d560f49b6f55e93cdcabcd8453f8ecc6b02 Mon Sep 17 00:00:00 2001 From: GenericP3rson Date: Sun, 30 Jul 2023 22:04:54 -0500 Subject: [PATCH 05/11] removed match python 3.10 dependency --- torchquantum/layer/nlocal.py | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/torchquantum/layer/nlocal.py b/torchquantum/layer/nlocal.py index 73171da9..04e490bb 100644 --- a/torchquantum/layer/nlocal.py +++ b/torchquantum/layer/nlocal.py @@ -149,20 +149,16 @@ def __init__( skip_final_rotation_layer: bool = False, ): # if passed as string, determine entanglement type - if type(entanglement_layer) == str: - match entanglement_layer: - case "linear": - entanglement_layer = tq.layers.Op2QAllLayer - case "reverse_linear": - entanglement_layer = tq.layers.Op2QAllLayer - entanglement_layer_params = {"wire_reverse": True} - case "circular": - entanglement_layer = tq.layers.Op2QAllLayer - entanglement_layer_params = {"circular": True} - case "full": - entanglement_layer = tq.layers.Op2QDenseLayer - case _: - raise NotImplementedError + if entanglement_layer == "linear": + entanglement_layer = tq.layers.Op2QAllLayer + elif entanglement_layer == "reverse_linear": + entanglement_layer = tq.layers.Op2QAllLayer + entanglement_layer_params = {"wire_reverse": True} + elif entanglement_layer == "circular": + entanglement_layer = tq.layers.Op2QAllLayer + entanglement_layer_params = {"circular": True} + elif entanglement_layer == "full": + entanglement_layer = tq.layers.Op2QDenseLayer # initialize super().__init__( From 3be6d58e075bc48bed1673096e997562d160ae94 Mon Sep 17 00:00:00 2001 From: GenericP3rson Date: Tue, 1 Aug 2023 11:56:22 -0500 Subject: [PATCH 06/11] added EfficientSU2 --- torchquantum/layer/nlocal.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/torchquantum/layer/nlocal.py b/torchquantum/layer/nlocal.py index 04e490bb..27e6a76e 100644 --- a/torchquantum/layer/nlocal.py +++ b/torchquantum/layer/nlocal.py @@ -202,3 +202,31 @@ def __init__( reps=reps, skip_final_rotation_layer=skip_final_rotation_layer, ) + + +class EfficientSU2(TwoLocal): + """Layer Template for a EfficientSU2 circuit + + Args: + arch (dict): circuit architecture in a dictionary format + entanglement_layer (str): type of entanglement layer in a string ("linear", "reverse_linear", "circular", "full") or tq.QuantumModule format + reps (int): number of reptitions of the rotation and entanglement layers in a integer format + skip_final_rotation_layer (bool): whether or not to add the final rotation layer as a boolean + """ + + def __init__( + self, + arch: dict = None, + entanglement_layer: str = "reverse_linear", + reps: int = 3, + skip_final_rotation_layer: bool = False, + ): + # construct circuit with rotation layers of RY and RZ and entanglement with CX + super().__init__( + arch=arch, + rotation_ops=[tq.RY, tq.RZ], + entanglement_ops=[tq.CNOT], + entanglement_layer=entanglement_layer, + reps=reps, + skip_final_rotation_layer=skip_final_rotation_layer, + ) From 4cb1ec72b29d2542dbe7a373f6ec879e4983da11 Mon Sep 17 00:00:00 2001 From: GenericP3rson Date: Tue, 1 Aug 2023 11:59:40 -0500 Subject: [PATCH 07/11] added RealAmplitudes --- torchquantum/layer/nlocal.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/torchquantum/layer/nlocal.py b/torchquantum/layer/nlocal.py index 27e6a76e..f4289004 100644 --- a/torchquantum/layer/nlocal.py +++ b/torchquantum/layer/nlocal.py @@ -230,3 +230,24 @@ def __init__( reps=reps, skip_final_rotation_layer=skip_final_rotation_layer, ) + + +class RealAmplitudes(TwoLocal): + """Layer Template for a RealAmplitudes circuit + + Args: + arch (dict): circuit architecture in a dictionary format + entanglement_layer (str): type of entanglement layer in a string ("linear", "reverse_linear", "circular", "full") or tq.QuantumModule format + reps (int): number of reptitions of the rotation and entanglement layers in a integer format + skip_final_rotation_layer (bool): whether or not to add the final rotation layer as a boolean + """ + def __init__(self, arch: dict = None, entanglement_layer: str="reverse_linear", reps: int=3, skip_final_rotation_layer: bool=False): + # construct circuit with rotation layers of RY and entanglement with CX + super().__init__( + arch=arch, + rotation_ops = [tq.RY], + entanglement_ops = [tq.CNOT], + entanglement_layer = entanglement_layer, + reps=reps, + skip_final_rotation_layer = skip_final_rotation_layer, + ) From f4f7316653c7f03b77a8f5dd62a566043f9ac1f4 Mon Sep 17 00:00:00 2001 From: GenericP3rson Date: Tue, 1 Aug 2023 12:00:15 -0500 Subject: [PATCH 08/11] updates to pass lint test --- torchquantum/layer/nlocal.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/torchquantum/layer/nlocal.py b/torchquantum/layer/nlocal.py index f4289004..26cefa50 100644 --- a/torchquantum/layer/nlocal.py +++ b/torchquantum/layer/nlocal.py @@ -241,13 +241,20 @@ class RealAmplitudes(TwoLocal): reps (int): number of reptitions of the rotation and entanglement layers in a integer format skip_final_rotation_layer (bool): whether or not to add the final rotation layer as a boolean """ - def __init__(self, arch: dict = None, entanglement_layer: str="reverse_linear", reps: int=3, skip_final_rotation_layer: bool=False): + + def __init__( + self, + arch: dict = None, + entanglement_layer: str = "reverse_linear", + reps: int = 3, + skip_final_rotation_layer: bool = False, + ): # construct circuit with rotation layers of RY and entanglement with CX super().__init__( arch=arch, - rotation_ops = [tq.RY], - entanglement_ops = [tq.CNOT], - entanglement_layer = entanglement_layer, + rotation_ops=[tq.RY], + entanglement_ops=[tq.CNOT], + entanglement_layer=entanglement_layer, reps=reps, - skip_final_rotation_layer = skip_final_rotation_layer, + skip_final_rotation_layer=skip_final_rotation_layer, ) From b361c48c25cc047f8680b99c8f34ed043cdcd9f6 Mon Sep 17 00:00:00 2001 From: GenericP3rson Date: Tue, 1 Aug 2023 12:03:02 -0500 Subject: [PATCH 09/11] adding the updated __init__ --- torchquantum/layer/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/torchquantum/layer/__init__.py b/torchquantum/layer/__init__.py index 4117c8b9..a6c99385 100644 --- a/torchquantum/layer/__init__.py +++ b/torchquantum/layer/__init__.py @@ -23,3 +23,4 @@ """ from .layers import * +from .nlocal import * From 60779d041c433c8c0b1c611c80a8300361d8682b Mon Sep 17 00:00:00 2001 From: GenericP3rson Date: Tue, 1 Aug 2023 18:04:22 -0500 Subject: [PATCH 10/11] slight restructure of nlocal --- torchquantum/layer/nlocal.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/torchquantum/layer/nlocal.py b/torchquantum/layer/nlocal.py index 26cefa50..0a2d02cc 100644 --- a/torchquantum/layer/nlocal.py +++ b/torchquantum/layer/nlocal.py @@ -73,6 +73,10 @@ def __init__( # initialize the LayerTemplate0 super().__init__(arch) + def build_initial_layer(self): + """Build the initial layer""" + return self.initial_circuit + def build_rotation_block(self): """Build rotation block""" rotation_layers = [] @@ -102,8 +106,9 @@ def build_layers(self): layers_all = tq.QuantumModuleList() # add the initial circuit - if self.initial_circuit is not None: - layers_all.append(self.initial_circuit) + initial_circuit = self.build_initial_layer() + if initial_circuit is not None: + layers_all.append(initial_circuit) # repeat for each rep for _ in range(self.reps): From 41729651b15802d779df083a82cae41f2a6e017f Mon Sep 17 00:00:00 2001 From: GenericP3rson Date: Thu, 3 Aug 2023 21:43:29 -0300 Subject: [PATCH 11/11] added support for PauliTwoDesign --- torchquantum/layer/layers.py | 41 +++++++++++++++++ torchquantum/layer/nlocal.py | 89 ++++++++++++++++++++++++++++++------ 2 files changed, 115 insertions(+), 15 deletions(-) diff --git a/torchquantum/layer/layers.py b/torchquantum/layer/layers.py index 0e409ced..cf72b3a7 100644 --- a/torchquantum/layer/layers.py +++ b/torchquantum/layer/layers.py @@ -41,6 +41,7 @@ "RandomLayer", "RandomLayerAllTypes", "Op1QAllLayer", + "RandomOp1All", "Op2QAllLayer", "Op2QButterflyLayer", "Op2QDenseLayer", @@ -146,6 +147,46 @@ def forward(self, q_device: tq.QuantumDevice): self.op(q_device, wires=[self.n_gate - 1, 0]) +class RandomOp1All(tq.QuantumModule): + def __init__( + self, n_wires: int, op_types=(tq.RX, tq.RY, tq.RZ), op_ratios=None, seed=None + ): + """Layer adding a random gate to all wires + + Params: + n_wires (int): number of wires/gates in integer format + op_types (Iterable): single-wire gates to select from in iterable format + op_ratios (Iterable): probabilities to select each gate option in iterable format + seed (int): random seed in integer format + """ + super().__init__() + self.n_wires = n_wires + self.op_types = op_types + self.op_ratios = op_ratios + self.seed = seed + self.gate_all = nn.ModuleList() + if seed is not None: + np.random.seed(seed) + self.build_random_layer() + + def build_random_layer(self): + for k in range(self.n_wires): + op = np.random.choice(self.op_types, p=self.op_ratios) + self.gate_all.append(op()) + + @tq.static_support + def forward(self, q_device: tq.QuantumDevice, x): + # op 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, ( + f"Number of gates ({self.n_wires}) is different from number " + f"of wires ({q_device.n_wires})!" + ) + + for k in range(self.n_wires): + self.gate_all[k](q_device, wires=k, params=x[:, k]) + + class RandomLayer(tq.QuantumModule): def __init__( self, diff --git a/torchquantum/layer/nlocal.py b/torchquantum/layer/nlocal.py index 0a2d02cc..1a3c8803 100644 --- a/torchquantum/layer/nlocal.py +++ b/torchquantum/layer/nlocal.py @@ -22,11 +22,27 @@ SOFTWARE. """ -import torchquantum as tq -import torchquantum.layers as layers - -class NLocal(layers.LayerTemplate0): +import torch +import torchquantum as tq +from torchquantum.layer.layers import ( + LayerTemplate0, + Op1QAllLayer, + Op2QAllLayer, + RandomOp1All, +) + +__all__ = [ + "NLocal", + "TwoLocal", + "ExcitationPreserving", + "EfficientSU2", + "RealAmplitudes", + "PauliTwoDesign", +] + + +class NLocal(LayerTemplate0): """Layer Template for a NLocal Class Args: @@ -44,11 +60,11 @@ class NLocal(layers.LayerTemplate0): def __init__( self, - rotation_ops: list, - entanglement_ops: list, + rotation_ops: list = None, + entanglement_ops: list = None, arch: dict = None, - rotation_layer: tq.QuantumModule = tq.layers.Op1QAllLayer, - entanglement_layer: tq.QuantumModule = tq.layers.Op2QAllLayer, + rotation_layer: tq.QuantumModule = Op1QAllLayer, + entanglement_layer: tq.QuantumModule = Op2QAllLayer, reps: int = 1, rotation_layer_params: dict = {}, entanglement_layer_params: dict = {}, @@ -143,10 +159,10 @@ class TwoLocal(NLocal): def __init__( self, - rotation_ops: list, - entanglement_ops: list, + rotation_ops: list = None, + entanglement_ops: list = None, arch: dict = None, - rotation_layer: tq.QuantumModule = tq.layers.Op1QAllLayer, + rotation_layer: tq.QuantumModule = Op1QAllLayer, entanglement_layer: str = "linear", reps: int = 1, entanglement_layer_params: dict = {}, @@ -155,15 +171,15 @@ def __init__( ): # if passed as string, determine entanglement type if entanglement_layer == "linear": - entanglement_layer = tq.layers.Op2QAllLayer + entanglement_layer = Op2QAllLayer elif entanglement_layer == "reverse_linear": - entanglement_layer = tq.layers.Op2QAllLayer + entanglement_layer = Op2QAllLayer entanglement_layer_params = {"wire_reverse": True} elif entanglement_layer == "circular": - entanglement_layer = tq.layers.Op2QAllLayer + entanglement_layer = Op2QAllLayer entanglement_layer_params = {"circular": True} elif entanglement_layer == "full": - entanglement_layer = tq.layers.Op2QDenseLayer + entanglement_layer = Op2QDenseLayer # initialize super().__init__( @@ -263,3 +279,46 @@ def __init__( reps=reps, skip_final_rotation_layer=skip_final_rotation_layer, ) + + +class PauliTwoDesign(TwoLocal): + """Layer Template for a PauliTwoDesign circuit + + Args: + arch (dict): circuit architecture in a dictionary format + entanglement_layer (str): type of entanglement layer in a string ("linear", "reverse_linear", "circular", "full") or tq.QuantumModule format + reps (int): number of reptitions of the rotation and entanglement layers in a integer format + skip_final_rotation_layer (bool): whether or not to add the final rotation layer as a boolean + """ + + def __init__( + self, + arch: dict = None, + entanglement_layer: str = "reverse_linear", + reps: int = 3, + skip_final_rotation_layer: bool = False, + seed: int = 0, + ): + # set seed + self.seed = seed + # construct circuit with entanglement with CX + super().__init__( + arch=arch, + entanglement_ops=[tq.CNOT], + entanglement_layer=entanglement_layer, + reps=reps, + skip_final_rotation_layer=skip_final_rotation_layer, + ) + + def build_initial_layer(self): + # add an initial layer of ry with rotation pi/4 + return tq.QuantumModule.from_op_history( + [ + {"name": "ry", "wires": wire, "params": torch.pi / 4} + for wire in range(self.arch["n_wires"]) + ] + ) + + def build_rotation_block(self): + # make a random layer of rotations + return [RandomOp1All(n_wires=self.n_wires, seed=self.seed)]