From 09394edc5b65b9428a0c1a9b6b2cd387068956fd Mon Sep 17 00:00:00 2001 From: SaashaJoshi Date: Fri, 3 Nov 2023 23:55:37 -0700 Subject: [PATCH 1/7] add init file for gate module --- .../models/tensor_network_circuits/__init__.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/quantum_image_processing/models/tensor_network_circuits/__init__.py b/quantum_image_processing/models/tensor_network_circuits/__init__.py index e69de29..6b8a71d 100644 --- a/quantum_image_processing/models/tensor_network_circuits/__init__.py +++ b/quantum_image_processing/models/tensor_network_circuits/__init__.py @@ -0,0 +1,7 @@ +from .ttn import TTN +from .mera import MERA + +__all__ = [ + "TTN", + "MERA", +] \ No newline at end of file From 887b29223efd3d2276b4fbb7b51082e00c347b30 Mon Sep 17 00:00:00 2001 From: SaashaJoshi Date: Fri, 3 Nov 2023 23:56:57 -0700 Subject: [PATCH 2/7] add doc strings to ttn --- .../models/tensor_network_circuits/ttn.py | 106 +++++++++++------- 1 file changed, 68 insertions(+), 38 deletions(-) diff --git a/quantum_image_processing/models/tensor_network_circuits/ttn.py b/quantum_image_processing/models/tensor_network_circuits/ttn.py index 9660950..f148cdb 100644 --- a/quantum_image_processing/models/tensor_network_circuits/ttn.py +++ b/quantum_image_processing/models/tensor_network_circuits/ttn.py @@ -1,65 +1,64 @@ +"""Tree Tensor Network (TTN)""" from __future__ import annotations from typing import Callable import numpy as np -from qiskit import QuantumCircuit from qiskit.circuit import QuantumCircuit, QuantumRegister, ParameterVector from quantum_image_processing.gates.two_qubit_unitary import TwoQubitUnitary class TTN: """ - Implements a Tree Tensor Network (TTN) as given by - Grant et al. (2018). + Implements a Tree Tensor Network (TTN) structure class with + alternative unitary qubit parameterization. - The model architecture only consists of a hierarchical - TTN model. It cannot be classified as a QCNN since - there is no distinction between conv and pooling layers. + References: + [1] Grant et al. (2018). """ - def __init__(self, img_dim): + def __init__(self, img_dim: int): + """ + Initializes the TTN class with given input variables. + + Args: + img_dim (int): product of dimensions of the input data. + For example, + for a 2x2 image, img_dim = 4. + """ self.img_dim = img_dim def ttn_simple(self, complex_structure: bool = True) -> QuantumCircuit: """ - Rotations here can be either real or complex. - - For real rotations only RY gates are used since - the gate has no complex rotations involved. - For complex rotations, a combination of RZ and RY - gates are used. + Implements a TTN network with simple alternative + parameterization as given in [1]. - I HAVE NO IDEA WHY I CHOSE THESE. THE SELECTION - OF UNITARY GATES IS COMPLETELY VOLUNTARY. + Args: + complex_structure (default=True): boolean marker + for real or complex gate parameterization. - PennyLane implements a TTN template with only RX gates. - - :return: + Returns: + QuantumCircuit: quantum circuit with unitary gates + represented by simple parameterization. """ param_vector = ParameterVector("theta", 2 * self.img_dim - 1) param_vector_copy = param_vector return self.ttn_backbone( - TwoQubitUnitary().simple_parameterization, param_vector_copy, complex_structure + TwoQubitUnitary().simple_parameterization, + param_vector_copy, + complex_structure, ) def ttn_general(self, complex_structure: bool = True) -> QuantumCircuit: """ - Two qubit gates built from referencing a paper by - Vatan et al. (2004). - - As stated in the paper: - "A general two-qubit quantum computation, up to a global phase, - can be constructed using at most 3 CNOT gates and 15 elementary - one-qubit gates from the family {Ry , Rz}." - and - - Theorem 3. Every two-qubit quantum gate in SO(4) (i.e. real gate) - can be realized by a circuit consisting of 12 elementary - one-qubit gates and 2 CNOT gates. - - Theorem 4. Every two-qubit quantum gate in O(4) with determinant - equal to −1 can be realized by a circuit consisting of 12 elementary - gates and 2 CNOT gates and one SWAP gate - :return: + Implements a TTN network with general alternative + parameterization as given in [1]. + + Args: + complex_structure (default=True): boolean marker + for real or complex gate parameterization. + + Returns: + QuantumCircuit: quantum circuit with unitary gates + represented by general parameterization. """ # Check number of params here. if complex_structure: @@ -70,12 +69,24 @@ def ttn_general(self, complex_structure: bool = True) -> QuantumCircuit: param_vector_copy = param_vector return self.ttn_backbone( - TwoQubitUnitary().simple_parameterization, param_vector_copy, complex_structure + TwoQubitUnitary().simple_parameterization, + param_vector_copy, + complex_structure, ) - def ttn_with_aux(self): + def ttn_with_aux(self, complex_structure: bool = True): """ TODO: Find the implementation procedure for this. + Implements a TTN network with alternative parameterization + that requires an auxiliary qubit, as given in [1]. + + Args: + complex_structure (default=True): boolean marker for + real or complex gate parameterization. + + Returns: + QuantumCircuit: quantum circuit with unitary gates + represented by general parameterization. """ def ttn_backbone( @@ -84,6 +95,25 @@ def ttn_backbone( param_vector_copy: ParameterVector, complex_structure: bool = True, ) -> QuantumCircuit: + """ + Lays out the TTN structure by progressively building layers + of unitary gates with their alternative parameterization. + + Args: + gate_structure (Callable): a callable function that implements + either one of the three available unitary gate parameterization - + simple, general or auxiliary. + + param_vector_copy (ParameterVector): copy of the parameter + vector list. + + complex_structure (default=True): boolean marker for + real or complex gate parameterization. + + Returns: + QuantumCircuit: quantum circuit with unitary gates + represented by general parameterization. + """ ttn_qr = QuantumRegister(size=self.img_dim) ttn_circ = QuantumCircuit(ttn_qr) From a288d23f8cafe38a126893dcffbfbdf9a439b77b Mon Sep 17 00:00:00 2001 From: SaashaJoshi Date: Sun, 5 Nov 2023 21:17:34 -0800 Subject: [PATCH 3/7] lint edits --- .../data_encoder/__init__.py | 9 +++ .../data_encoder/amplitude_encoder.py | 2 - .../data_encoder/angle_encoder.py | 1 + .../image_representations/__init__.py | 4 ++ .../image_representations/frqi.py | 70 +++++++++---------- .../image_representations/neqr.py | 70 +++++++++---------- .../data_loader/__init__.py | 9 +++ quantum_image_processing/gates/__init__.py | 2 +- .../gates/two_qubit_unitary.py | 1 + quantum_image_processing/models/__init__.py | 5 ++ .../models/neural_networks/__init__.py | 5 ++ .../neural_networks/convolutional/__init__.py | 4 ++ .../generative_adversarial/__init__.py | 4 ++ .../models/neural_networks/neural_network.py | 0 .../tensor_network_circuits/__init__.py | 6 +- .../models/tensor_network_circuits/mera.py | 17 ++++- .../variational_classifiers/__init__.py | 5 ++ requirements.txt | 9 ++- 18 files changed, 139 insertions(+), 84 deletions(-) create mode 100644 quantum_image_processing/models/neural_networks/neural_network.py diff --git a/quantum_image_processing/data_encoder/__init__.py b/quantum_image_processing/data_encoder/__init__.py index e69de29..9b71862 100644 --- a/quantum_image_processing/data_encoder/__init__.py +++ b/quantum_image_processing/data_encoder/__init__.py @@ -0,0 +1,9 @@ +""" +Data Encoders (module: quantum_image_processing.data_encoder) +""" + +from .angle_encoder import angle_encoding + +__all__ = [ + "angle_encoding", +] diff --git a/quantum_image_processing/data_encoder/amplitude_encoder.py b/quantum_image_processing/data_encoder/amplitude_encoder.py index 4348f98..e69de29 100644 --- a/quantum_image_processing/data_encoder/amplitude_encoder.py +++ b/quantum_image_processing/data_encoder/amplitude_encoder.py @@ -1,2 +0,0 @@ -def amplitude_encoding(): - pass diff --git a/quantum_image_processing/data_encoder/angle_encoder.py b/quantum_image_processing/data_encoder/angle_encoder.py index fc48d9f..5a78222 100644 --- a/quantum_image_processing/data_encoder/angle_encoder.py +++ b/quantum_image_processing/data_encoder/angle_encoder.py @@ -1,3 +1,4 @@ +"""Angle Encoder""" from qiskit.circuit import QuantumCircuit, ParameterVector diff --git a/quantum_image_processing/data_encoder/image_representations/__init__.py b/quantum_image_processing/data_encoder/image_representations/__init__.py index bf3f9f3..dd2857b 100644 --- a/quantum_image_processing/data_encoder/image_representations/__init__.py +++ b/quantum_image_processing/data_encoder/image_representations/__init__.py @@ -1,3 +1,7 @@ +""" +Quantum Image Representations (module: quantum_image_processing.data_encoder.image_representations) +""" + from .frqi import FRQI from .neqr import NEQR diff --git a/quantum_image_processing/data_encoder/image_representations/frqi.py b/quantum_image_processing/data_encoder/image_representations/frqi.py index 45085e6..814a0f4 100644 --- a/quantum_image_processing/data_encoder/image_representations/frqi.py +++ b/quantum_image_processing/data_encoder/image_representations/frqi.py @@ -1,9 +1,7 @@ from __future__ import annotations import math import numpy as np -from qiskit import Aer, execute -from qiskit.circuit import QuantumCircuit, QuantumRegister, ClassicalRegister -from qiskit.visualization import plot_histogram +from qiskit.circuit import QuantumCircuit, QuantumRegister class FRQI: @@ -51,20 +49,20 @@ def _color_info(self, pixel_pos: int) -> QuantumCircuit: return circ - # TODO: Delete this function from here. Make a separate file. - def _measure_circ(self, circ: QuantumCircuit) -> QuantumCircuit: - # Append measurement gates to the circuit - qr = QuantumRegister(self.feature_dim + 1) - cr = ClassicalRegister(self.feature_dim + 1) - - meas_circ = QuantumCircuit(qr, cr) - meas_circ.measure( - list(range(self.feature_dim + 1)), - list(range(self.feature_dim + 1)), - ) - meas_circ = meas_circ.compose(circ, range(self.feature_dim + 1), front=True) - - return meas_circ + # # TODO: Delete this function from here. Make a separate file. + # def _measure_circ(self, circ: QuantumCircuit) -> QuantumCircuit: + # # Append measurement gates to the circuit + # qr = QuantumRegister(self.feature_dim + 1) + # cr = ClassicalRegister(self.feature_dim + 1) + # + # meas_circ = QuantumCircuit(qr, cr) + # meas_circ.measure( + # list(range(self.feature_dim + 1)), + # list(range(self.feature_dim + 1)), + # ) + # meas_circ = meas_circ.compose(circ, range(self.feature_dim + 1), front=True) + # + # return meas_circ def frqi(self, measure=True) -> QuantumCircuit: """Builds the FRQI image representation on a circuit. @@ -103,28 +101,28 @@ def frqi(self, measure=True) -> QuantumCircuit: ) circ.barrier() - if measure: - circ = self._measure_circ(circ) + # if measure: + # circ = self._measure_circ(circ) return circ - # TODO: Remove the following function from this file. - @staticmethod - def get_simulator_result( - circ: QuantumCircuit, - backend: str = "qasm_simulator", - shots: int = 1024, - plot_counts=True, - ): - backend = Aer.get_backend(backend) - job = execute(circ, backend=backend, shots=shots) - results = job.result() - counts = results.get_counts() - - if plot_counts: - plot_histogram(counts) - - return counts + # # TODO: Remove the following function from this file. + # @staticmethod + # def get_simulator_result( + # circ: QuantumCircuit, + # backend: str = "qasm_simulator", + # shots: int = 1024, + # plot_counts=True, + # ): + # backend = Aer.get_backend(backend) + # job = execute(circ, backend=backend, shots=shots) + # results = job.result() + # counts = results.get_counts() + # + # if plot_counts: + # plot_histogram(counts) + # + # return counts def qic(self): pass diff --git a/quantum_image_processing/data_encoder/image_representations/neqr.py b/quantum_image_processing/data_encoder/image_representations/neqr.py index d4767f6..2449825 100644 --- a/quantum_image_processing/data_encoder/image_representations/neqr.py +++ b/quantum_image_processing/data_encoder/image_representations/neqr.py @@ -1,9 +1,7 @@ from __future__ import annotations import math import numpy as np -from qiskit import Aer, execute -from qiskit.circuit import QuantumCircuit, QuantumRegister, ClassicalRegister -from qiskit.visualization import plot_histogram +from qiskit.circuit import QuantumCircuit, QuantumRegister class NEQR: @@ -46,21 +44,21 @@ def _color_info(self, pixel_pos: int) -> QuantumCircuit: return circ - def _measure_circ(self, circ: QuantumCircuit) -> QuantumCircuit: - # Append measurement gates to the circuit - qr = QuantumRegister(self.feature_dim + self.q) - cr = ClassicalRegister(self.feature_dim + self.q) - - meas_circ = QuantumCircuit(qr, cr) - meas_circ.measure( - list(range(self.feature_dim + self.q)), - list(range(self.feature_dim + self.q)), - ) - meas_circ = meas_circ.compose( - circ, range(self.feature_dim + self.q), front=True - ) - - return meas_circ + # def _measure_circ(self, circ: QuantumCircuit) -> QuantumCircuit: + # # Append measurement gates to the circuit + # qr = QuantumRegister(self.feature_dim + self.q) + # cr = ClassicalRegister(self.feature_dim + self.q) + # + # meas_circ = QuantumCircuit(qr, cr) + # meas_circ.measure( + # list(range(self.feature_dim + self.q)), + # list(range(self.feature_dim + self.q)), + # ) + # meas_circ = meas_circ.compose( + # circ, range(self.feature_dim + self.q), front=True + # ) + # + # return meas_circ def image_encoding(self, measure=True) -> QuantumCircuit: qr = QuantumRegister(self.feature_dim + self.q) @@ -91,27 +89,27 @@ def image_encoding(self, measure=True) -> QuantumCircuit: range(self.feature_dim), ) - if measure: - circ = self._measure_circ(circ) + # if measure: + # circ = self._measure_circ(circ) return circ - @staticmethod - def get_simulator_result( - circ: QuantumCircuit, - backend: str = "qasm_simulator", - shots: int = 1024, - plot_counts=True, - ) -> list: - backend = Aer.get_backend(backend) - job = execute(circ, backend=backend, shots=shots) - results = job.result() - counts = results.get_counts() - - if plot_counts: - plot_histogram(counts) - - return counts + # @staticmethod + # def get_simulator_result( + # circ: QuantumCircuit, + # backend: str = "qasm_simulator", + # shots: int = 1024, + # plot_counts=True, + # ) -> list: + # backend = Aer.get_backend(backend) + # job = execute(circ, backend=backend, shots=shots) + # results = job.result() + # counts = results.get_counts() + # + # if plot_counts: + # plot_histogram(counts) + # + # return counts def qic(self): pass diff --git a/quantum_image_processing/data_loader/__init__.py b/quantum_image_processing/data_loader/__init__.py index e69de29..5173f8d 100644 --- a/quantum_image_processing/data_loader/__init__.py +++ b/quantum_image_processing/data_loader/__init__.py @@ -0,0 +1,9 @@ +""" +Data Loader (module: quantum_image_processing.data_loader) +""" + +from .mnist_data_loader import load_mnist_data + +__all__ = [ + "load_mnist_data", +] diff --git a/quantum_image_processing/gates/__init__.py b/quantum_image_processing/gates/__init__.py index 715ee96..caa0d62 100644 --- a/quantum_image_processing/gates/__init__.py +++ b/quantum_image_processing/gates/__init__.py @@ -1,6 +1,6 @@ """ Gate implementations, including unitary gates and their alternative parameterization. -(mod: quantum_image_processing.gates) +(module: quantum_image_processing.gates) """ from .unitary_block import Unitary diff --git a/quantum_image_processing/gates/two_qubit_unitary.py b/quantum_image_processing/gates/two_qubit_unitary.py index 7a6e6a2..2768b03 100644 --- a/quantum_image_processing/gates/two_qubit_unitary.py +++ b/quantum_image_processing/gates/two_qubit_unitary.py @@ -9,6 +9,7 @@ class TwoQubitUnitary(Unitary): """ Implements two qubit unitary with alternative parameterizations. """ + def simple_parameterization( self, circuit: QuantumCircuit, diff --git a/quantum_image_processing/models/__init__.py b/quantum_image_processing/models/__init__.py index e69de29..7476b45 100644 --- a/quantum_image_processing/models/__init__.py +++ b/quantum_image_processing/models/__init__.py @@ -0,0 +1,5 @@ +""" +Quantum algorithms and models, including neural networks, tensor network +quantum circuits, variational classifiers, and more. +(module: quantum_image_processing.models) +""" diff --git a/quantum_image_processing/models/neural_networks/__init__.py b/quantum_image_processing/models/neural_networks/__init__.py index e69de29..5684eab 100644 --- a/quantum_image_processing/models/neural_networks/__init__.py +++ b/quantum_image_processing/models/neural_networks/__init__.py @@ -0,0 +1,5 @@ +""" +Quantum Neural Networks, including convolutional and +generative adversarial neural networks +(module: quantum_image_processing.models.neural_networks) +""" diff --git a/quantum_image_processing/models/neural_networks/convolutional/__init__.py b/quantum_image_processing/models/neural_networks/convolutional/__init__.py index e69de29..3a088a4 100644 --- a/quantum_image_processing/models/neural_networks/convolutional/__init__.py +++ b/quantum_image_processing/models/neural_networks/convolutional/__init__.py @@ -0,0 +1,4 @@ +""" +Convolutional Neural Networks +(module: quantum_image_processing.models.neural_networks.convolutional) +""" diff --git a/quantum_image_processing/models/neural_networks/generative_adversarial/__init__.py b/quantum_image_processing/models/neural_networks/generative_adversarial/__init__.py index e69de29..14913a6 100644 --- a/quantum_image_processing/models/neural_networks/generative_adversarial/__init__.py +++ b/quantum_image_processing/models/neural_networks/generative_adversarial/__init__.py @@ -0,0 +1,4 @@ +""" +Generative Adversarial Neural Networks +(module: quantum_image_processing.models.neural_networks.generative_adversarial) +""" diff --git a/quantum_image_processing/models/neural_networks/neural_network.py b/quantum_image_processing/models/neural_networks/neural_network.py new file mode 100644 index 0000000..e69de29 diff --git a/quantum_image_processing/models/tensor_network_circuits/__init__.py b/quantum_image_processing/models/tensor_network_circuits/__init__.py index 6b8a71d..25b1d20 100644 --- a/quantum_image_processing/models/tensor_network_circuits/__init__.py +++ b/quantum_image_processing/models/tensor_network_circuits/__init__.py @@ -1,7 +1,11 @@ +""" +Tensor Network Quantum Circuits (module: quantum_image_processing.models.tensor_network_circuits) +""" + from .ttn import TTN from .mera import MERA __all__ = [ "TTN", "MERA", -] \ No newline at end of file +] diff --git a/quantum_image_processing/models/tensor_network_circuits/mera.py b/quantum_image_processing/models/tensor_network_circuits/mera.py index 78e2b2a..a1662b0 100644 --- a/quantum_image_processing/models/tensor_network_circuits/mera.py +++ b/quantum_image_processing/models/tensor_network_circuits/mera.py @@ -26,7 +26,11 @@ def mera_simple(self, complex_structure: bool = True) -> QuantumCircuit: int(self.img_dim / 2 * (self.img_dim / 2 + 1)) + 3, ) param_vector_copy = param_vector - return self.mera_backbone(TwoQubitUnitary().simple_parameterization, param_vector_copy, complex_structure) + return self.mera_backbone( + TwoQubitUnitary().simple_parameterization, + param_vector_copy, + complex_structure, + ) # Check number of params here. def mera_general(self, complex_structure: bool = True) -> QuantumCircuit: @@ -36,10 +40,17 @@ def mera_general(self, complex_structure: bool = True) -> QuantumCircuit: else: param_vector = ParameterVector("theta", 10 * self.img_dim - 1) param_vector_copy = param_vector - return self.mera_backbone(TwoQubitUnitary().general_parameterization, param_vector_copy, complex_structure) + return self.mera_backbone( + TwoQubitUnitary().general_parameterization, + param_vector_copy, + complex_structure, + ) def mera_backbone( - self, gate_structure: Callable, param_vector_copy: ParameterVector, complex_structure: bool = True + self, + gate_structure: Callable, + param_vector_copy: ParameterVector, + complex_structure: bool = True, ) -> QuantumCircuit: mera_qr = QuantumRegister(size=self.img_dim) mera_circ = QuantumCircuit(mera_qr) diff --git a/quantum_image_processing/models/variational_classifiers/__init__.py b/quantum_image_processing/models/variational_classifiers/__init__.py index e69de29..b29a49f 100644 --- a/quantum_image_processing/models/variational_classifiers/__init__.py +++ b/quantum_image_processing/models/variational_classifiers/__init__.py @@ -0,0 +1,5 @@ +""" +Quantum Variational Classifiers, including kernel estimator, and +data re-uploader. +(module: quantum_image_processing.models.variational_classifiers) +""" diff --git a/requirements.txt b/requirements.txt index 8bb428b..4d13e0f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,4 @@ -matplotlib~=3.6.2 -qiskit~=0.39.4 -torchvision~=0.14.1 -torch~=1.13.1 -numpy~=1.24.1 \ No newline at end of file +matplotlib==3.7.3 +qiskit==0.45.0 +qiskit_terra==0.45.0 +torchvision==0.16.0 \ No newline at end of file From 0863a0297bd4cf3675c895cbc1759bfaac44968e Mon Sep 17 00:00:00 2001 From: SaashaJoshi Date: Thu, 16 Nov 2023 18:44:27 -0800 Subject: [PATCH 4/7] pip install requirements.txt to solve linting error --- .github/workflows/pylint.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml index c9c962e..5c66d6a 100644 --- a/.github/workflows/pylint.yml +++ b/.github/workflows/pylint.yml @@ -18,6 +18,7 @@ jobs: run: | python -m pip install --upgrade pip pip install pylint + pip install -r requirements.txt - name: Analysing the code with pylint run: | pylint $(git ls-files '*.py') From 08e52f804a1653329c78eaad0df4f45909f21bc0 Mon Sep 17 00:00:00 2001 From: SaashaJoshi Date: Thu, 16 Nov 2023 19:01:16 -0800 Subject: [PATCH 5/7] add doc strings for mera --- .../models/tensor_network_circuits/mera.py | 66 ++++++++++++++++--- 1 file changed, 56 insertions(+), 10 deletions(-) diff --git a/quantum_image_processing/models/tensor_network_circuits/mera.py b/quantum_image_processing/models/tensor_network_circuits/mera.py index a1662b0..d5ad1e1 100644 --- a/quantum_image_processing/models/tensor_network_circuits/mera.py +++ b/quantum_image_processing/models/tensor_network_circuits/mera.py @@ -1,26 +1,42 @@ -import numpy as np +"""Multiscale Entanglement Renormalization Ansatz (MERA) Tensor Network""" from typing import Callable +import numpy as np from qiskit.circuit import QuantumCircuit, QuantumRegister, ParameterVector from quantum_image_processing.gates.two_qubit_unitary import TwoQubitUnitary -# Can TTN be an ABC for MERA? Good thought! class MERA: """ - Implements QCNN structure by Cong et al. (2019), replicating - the architecture described by MERA - Multiscale Entanglement - Renormalization Ansatz, given by Vidal et al. (2008). - - The decomposition of MERA architecture takes from the paper - by Grant et al. (2018). - - NOTE: Remember QCNN and MERA have opposite directions!! + Implements a Multiscale Entanglement Renormalization Ansatz + (MERA) tensor network structure as given by [2]. + + References: + [1] E. Grant et al., “Hierarchical quantum classifiers,” + npj Quantum Information, vol. 4, no. 1, Dec. 2018, + doi: https://doi.org/10.1038/s41534-018-0116-9. + + [2] G. Vidal, “Class of Quantum Many-Body States That + Can Be Efficiently Simulated,” Physical Review Letters, + vol. 101, no. 11, Sep. 2008, + doi: https://doi.org/10.1103/physrevlett.101.110501. """ def __init__(self, img_dim): self.img_dim = img_dim def mera_simple(self, complex_structure: bool = True) -> QuantumCircuit: + """ + Builds a MERA circuit with a simple unitary gate + parameterization. + + Args: + complex_structure (bool): If True, builds the MERA + structure with complex unitary gates (e.g. RY, etc.) + + Returns: + circuit (QuantumCircuit): Returns the MERA circuit + generated with the help of the input arguments. + """ param_vector = ParameterVector( "theta", int(self.img_dim / 2 * (self.img_dim / 2 + 1)) + 3, @@ -34,6 +50,18 @@ def mera_simple(self, complex_structure: bool = True) -> QuantumCircuit: # Check number of params here. def mera_general(self, complex_structure: bool = True) -> QuantumCircuit: + """ + Builds a MERA circuit with a general unitary gate + parameterization. Refer [1]. + + Args: + complex_structure (bool): If True, builds the MERA + structure with complex unitary gates (e.g. RY, etc.) + + Returns: + circuit (QuantumCircuit): Returns the MERA circuit + generated with the help of the input arguments. + """ if complex_structure: param_vector = ParameterVector("theta", 20 * self.img_dim - 1) param_vector_copy = param_vector @@ -52,6 +80,24 @@ def mera_backbone( param_vector_copy: ParameterVector, complex_structure: bool = True, ) -> QuantumCircuit: + """ + Lays out the backbone structure of a MERA circuit onto + which the unitary gates are applied. + + Args: + gate_structure (Callable): calls the function with + the required unitary gate parameterization structure. + + param_vector_copy (ParameterVector): list of unitary + gate parameters to be used in the circuit. + + complex_structure (bool): If True, builds the MERA + structure with complex unitary gates (e.g. RY, etc.) + + Returns: + circuit (QuantumCircuit): Returns the MERA circuit + generated with the help of the input arguments. + """ mera_qr = QuantumRegister(size=self.img_dim) mera_circ = QuantumCircuit(mera_qr) From 913ed5671b99f4f5d94d23c8f197855c5a08398a Mon Sep 17 00:00:00 2001 From: SaashaJoshi Date: Thu, 16 Nov 2023 19:07:10 -0800 Subject: [PATCH 6/7] update reference in ttn --- .../models/tensor_network_circuits/ttn.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/quantum_image_processing/models/tensor_network_circuits/ttn.py b/quantum_image_processing/models/tensor_network_circuits/ttn.py index f148cdb..cf50a41 100644 --- a/quantum_image_processing/models/tensor_network_circuits/ttn.py +++ b/quantum_image_processing/models/tensor_network_circuits/ttn.py @@ -12,7 +12,9 @@ class TTN: alternative unitary qubit parameterization. References: - [1] Grant et al. (2018). + [1] E. Grant et al., “Hierarchical quantum classifiers,” + npj Quantum Information, vol. 4, no. 1, Dec. 2018, + doi: https://doi.org/10.1038/s41534-018-0116-9. """ def __init__(self, img_dim: int): From b6de7fba6173b3c17411b949045cb73139d5916a Mon Sep 17 00:00:00 2001 From: SaashaJoshi Date: Thu, 16 Nov 2023 19:32:11 -0800 Subject: [PATCH 7/7] update doc-strings for gate module --- .../gates/two_qubit_unitary.py | 59 +++++++++++++++++++ .../gates/unitary_block.py | 52 ++++++++++++++++ 2 files changed, 111 insertions(+) diff --git a/quantum_image_processing/gates/two_qubit_unitary.py b/quantum_image_processing/gates/two_qubit_unitary.py index 2768b03..8aa5153 100644 --- a/quantum_image_processing/gates/two_qubit_unitary.py +++ b/quantum_image_processing/gates/two_qubit_unitary.py @@ -1,3 +1,4 @@ +"""Two-Qubit Unitary Gate class""" from __future__ import annotations import numpy as np @@ -49,6 +50,26 @@ def auxiliary_parameterization( def _real_simple_block( circuit: QuantumCircuit, qubits: list, parameter_vector: ParameterVector ) -> tuple[QuantumCircuit, ParameterVector]: + """ + Builds a two-qubit unitary gate with simple parameterization, + consisting of real two single-unitary gates followed by a CNOT + gate as given in the following paper. + + References: + [1] E. Grant et al., “Hierarchical quantum classifiers,” + npj Quantum Information, vol. 4, no. 1, Dec. 2018, + doi: https://doi.org/10.1038/s41534-018-0116-9. + + Args: + circuit (QuantumCircuit): Circuit on which two-qubit + unitary gate needs to be applied. + + qubits (list): list of qubits on which the gates need to + be applied. + + parameter_vector (ParameterVector): list of parameters + of the unitary gates. + """ block = circuit block.ry(parameter_vector[0], qubits[0]) block.ry(parameter_vector[1], qubits[1]) @@ -62,6 +83,25 @@ def _real_simple_block( def _real_general_block( circuit: QuantumCircuit, qubits: list, parameter_vector: ParameterVector ) -> tuple[QuantumCircuit, ParameterVector]: + """ + Builds a two-qubit unitary gate with a general parameterization, + consisting of real gates only, as given in the following reference paper. + + Reference: + [1] F. Vatan and C. Williams, “Optimal quantum circuits for + general two-qubit gates,” Physical Review A, vol. 69, no. 3, + Mar. 2004, doi: https://doi.org/10.1103/physreva.69.032315. + + Args: + circuit (QuantumCircuit): Circuit on which two-qubit + unitary gate needs to be applied. + + qubits (list): list of qubits on which the gates need to + be applied. + + parameter_vector (ParameterVector): list of parameters + of the unitary gates. + """ block = circuit block.rz(np.pi / 2, qubits[0]) @@ -90,6 +130,25 @@ def _real_general_block( def _complex_general_block( circuit: QuantumCircuit, qubits: list, parameter_vector: ParameterVector ) -> tuple[QuantumCircuit, ParameterVector]: + """ + Builds a two-qubit unitary gate with a general parameterization, + consisting of complex gates, as given in the following reference paper. + + Reference: + [1] F. Vatan and C. Williams, “Optimal quantum circuits for + general two-qubit gates,” Physical Review A, vol. 69, no. 3, + Mar. 2004, doi: https://doi.org/10.1103/physreva.69.032315. + + Args: + circuit (QuantumCircuit): Circuit on which two-qubit + unitary gate needs to be applied. + + qubits (list): list of qubits on which the gates need to + be applied. + + parameter_vector (ParameterVector): list of parameters + of the unitary gates. + """ block = circuit block.rz(parameter_vector[0], qubits[0]) block.ry(parameter_vector[1], qubits[0]) diff --git a/quantum_image_processing/gates/unitary_block.py b/quantum_image_processing/gates/unitary_block.py index a8fc26d..b564b05 100644 --- a/quantum_image_processing/gates/unitary_block.py +++ b/quantum_image_processing/gates/unitary_block.py @@ -1,3 +1,4 @@ +"""Unitary Gate class""" from __future__ import annotations from abc import ABC, abstractmethod from qiskit.circuit import QuantumCircuit, ParameterVector @@ -20,6 +21,23 @@ def simple_parameterization( parameter_vector: ParameterVector, complex_structure: bool = False, ): + """ + Used to build a two-qubit unitary gate with real or complex + simple parameterization. + + Args: + circuit (QuantumCircuit): Circuit on which two-qubit + unitary gate needs to be applied. + + qubits (list): list of qubits on which the gates need to + be applied. + + parameter_vector (ParameterVector): list of parameters + of the unitary gates. + + complex_structure (bool): If True, builds the unitary gate + parameterization with complex unitary gates (e.g. RY, etc.) + """ return NotImplementedError @abstractmethod @@ -30,6 +48,23 @@ def general_parameterization( parameter_vector: ParameterVector, complex_structure: bool = True, ): + """ + Used to build a two-qubit unitary gate with real or complex + general parameterization. + + Args: + circuit (QuantumCircuit): Circuit on which two-qubit + unitary gate needs to be applied. + + qubits (list): list of qubits on which the gates need to + be applied. + + parameter_vector (ParameterVector): list of parameters + of the unitary gates. + + complex_structure (bool): If True, builds the unitary gate + parameterization with complex unitary gates (e.g. RY, etc.) + """ return NotImplementedError @abstractmethod @@ -40,4 +75,21 @@ def auxiliary_parameterization( parameter_vector: ParameterVector, complex_structure: bool = True, ): + """ + Used to build a two-qubit unitary gate parameterization + with the help of an auxiliary qubit. + + Args: + circuit (QuantumCircuit): Circuit on which two-qubit + unitary gate needs to be applied. + + qubits (list): list of qubits on which the gates need to + be applied. + + parameter_vector (ParameterVector): list of parameters + of the unitary gates. + + complex_structure (bool): If True, builds the unitary gate + parameterization with complex unitary gates (e.g. RY, etc.) + """ return NotImplementedError