|
1 | 1 | # This code is part of a Qiskit project.
|
2 | 2 | #
|
3 |
| -# (C) Copyright IBM 2023, 2024. |
| 3 | +# (C) Copyright IBM 2023, 2025. |
4 | 4 | #
|
5 | 5 | # This code is licensed under the Apache License, Version 2.0. You may
|
6 | 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory
|
|
21 | 21 | from qiskit_machine_learning import QiskitMachineLearningError
|
22 | 22 |
|
23 | 23 | from ...utils import derive_num_qubits_feature_map_ansatz
|
| 24 | +from ...utils.deprecation import issue_deprecation_msg |
| 25 | + |
| 26 | + |
| 27 | +def qnn_circuit( |
| 28 | + num_qubits: int | None = None, |
| 29 | + feature_map: QuantumCircuit | None = None, |
| 30 | + ansatz: QuantumCircuit | None = None, |
| 31 | +): |
| 32 | + """ |
| 33 | + The qnn_circuit creates a QuantumCircuit that is a composition of a feature map |
| 34 | + and an ansatz circuit. Also returned are the feature map and ansatz parameters for |
| 35 | + use for inputs and weights as needed for a neural network, such as |
| 36 | + :class:`~qiskit-machine-learning.neural_networks.SamplerQNN`. |
| 37 | +
|
| 38 | + If only the number of qubits is provided the :meth:`~qiskit.circuit.library.real_amplitudes` |
| 39 | + ansatz and the :meth:`~qiskit.circuit.library.zz_feature_map` feature map are used. If the |
| 40 | + number of qubits is 1 the :meth:`~qiskit.circuit.library.z_feature_map` is used. If only a |
| 41 | + feature map is provided, the :meth:`~qiskit.circuit.library.real_amplitudes` ansatz with the |
| 42 | + corresponding number of qubits is used. If only an ansatz is provided the |
| 43 | + :meth:`~qiskit.circuit.library.zz_feature_map` with the corresponding number of qubits is used. |
| 44 | +
|
| 45 | + At least one parameter has to be provided. If a feature map and an ansatz is provided, the |
| 46 | + number of qubits must be the same. |
| 47 | +
|
| 48 | + Example: |
| 49 | +
|
| 50 | + .. code-block:: python |
| 51 | +
|
| 52 | + from qiskit_machine_learning.circuit.library import qnn_circuit |
| 53 | + qnn_qc, fm_params, anz_params = qnn_circuit(2) |
| 54 | + qnn_qc.draw(fold=60) |
| 55 | + # ┌───┐┌─────────────┐ » |
| 56 | + # q_0: ┤ H ├┤ P(2.0*x[0]) ├──■──» |
| 57 | + # ├───┤├─────────────┤┌─┴─┐» |
| 58 | + # q_1: ┤ H ├┤ P(2.0*x[1]) ├┤ X ├» |
| 59 | + # └───┘└─────────────┘└───┘» |
| 60 | + # « ┌───┐» |
| 61 | + # «q_0: ──────────────────────────────────■──┤ H ├» |
| 62 | + # « ┌──────────────────────────────┐┌─┴─┐├───┤» |
| 63 | + # «q_1: ┤ P(2.0*(x[0] - π)*(x[1] - π)) ├┤ X ├┤ H ├» |
| 64 | + # « └──────────────────────────────┘└───┘└───┘» |
| 65 | + # « ┌─────────────┐ » |
| 66 | + # «q_0: ┤ P(2.0*x[0]) ├──■──────────────────────────────────» |
| 67 | + # « ├─────────────┤┌─┴─┐┌──────────────────────────────┐» |
| 68 | + # «q_1: ┤ P(2.0*x[1]) ├┤ X ├┤ P(2.0*(x[0] - π)*(x[1] - π)) ├» |
| 69 | + # « └─────────────┘└───┘└──────────────────────────────┘» |
| 70 | + # « ┌──────────┐ ┌──────────┐ ┌──────────┐» |
| 71 | + # «q_0: ──■──┤ Ry(θ[0]) ├──■──┤ Ry(θ[2]) ├──■──┤ Ry(θ[4]) ├» |
| 72 | + # « ┌─┴─┐├──────────┤┌─┴─┐├──────────┤┌─┴─┐├──────────┤» |
| 73 | + # «q_1: ┤ X ├┤ Ry(θ[1]) ├┤ X ├┤ Ry(θ[3]) ├┤ X ├┤ Ry(θ[5]) ├» |
| 74 | + # « └───┘└──────────┘└───┘└──────────┘└───┘└──────────┘» |
| 75 | + # « ┌──────────┐ |
| 76 | + # «q_0: ──■──┤ Ry(θ[6]) ├ |
| 77 | + # « ┌─┴─┐├──────────┤ |
| 78 | + # «q_1: ┤ X ├┤ Ry(θ[7]) ├ |
| 79 | + # « └───┘└──────────┘ |
| 80 | + print(fm_params) |
| 81 | + # ParameterView([ParameterVectorElement(x[0]), ParameterVectorElement(x[1])]) |
| 82 | + print(anz_params) |
| 83 | + # ParameterView([ParameterVectorElement(θ[0]), ParameterVectorElement(θ[1]), |
| 84 | + # ParameterVectorElement(θ[2]), ParameterVectorElement(θ[3]), |
| 85 | + # ParameterVectorElement(θ[4]), ParameterVectorElement(θ[5]), |
| 86 | + # ParameterVectorElement(θ[6]), ParameterVectorElement(θ[7])]) |
| 87 | +
|
| 88 | + Although all arguments to qnn_circuit default to None at least one must be provided, |
| 89 | + to determine the number of qubits from. |
| 90 | +
|
| 91 | + If more than one is passed: |
| 92 | +
|
| 93 | + 1) If num_qubits is provided the feature map and/or ansatz circuits supplied must be the |
| 94 | + same number of qubits. |
| 95 | +
|
| 96 | + 2) If num_qubits is not provided the feature_map and ansatz must be set to the same number |
| 97 | + of qubits. |
| 98 | +
|
| 99 | + Args: |
| 100 | + num_qubits: Number of qubits, a positive integer. Optional if feature_map or ansatz is |
| 101 | + provided, otherwise required. If not provided num_qubits defaults from the |
| 102 | + sizes of feature_map and/or ansatz. |
| 103 | + feature_map: A feature map. Optional if num_qubits or ansatz is provided, otherwise |
| 104 | + required. If not provided defaults to |
| 105 | + :meth:`~qiskit.circuit.library.zz_feature_map` or |
| 106 | + :meth:`~qiskit.circuit.library.z_feature_map` if num_qubits is determined |
| 107 | + to be 1. |
| 108 | + ansatz: An ansatz. Optional if num_qubits or feature_map is provided, otherwise |
| 109 | + required. If not provided defaults to |
| 110 | + :meth:`~qiskit.circuit.library.real_amplitudes`. |
| 111 | +
|
| 112 | + Returns: |
| 113 | + The composed feature map and ansatz circuit, the feature map parameters and the |
| 114 | + ansatz parameters. |
| 115 | +
|
| 116 | + Raises: |
| 117 | + QiskitMachineLearningError: If a valid number of qubits cannot be derived from the \ |
| 118 | + provided input arguments. |
| 119 | + """ |
| 120 | + # Check if circuit is constructed with valid configuration and set properties accordingly. |
| 121 | + num_qubits, feature_map, ansatz = derive_num_qubits_feature_map_ansatz( |
| 122 | + num_qubits, feature_map, ansatz, use_methods=True |
| 123 | + ) |
| 124 | + qc = QuantumCircuit(num_qubits) |
| 125 | + qc.compose(feature_map, inplace=True) |
| 126 | + qc.compose(ansatz, inplace=True) |
| 127 | + return qc, feature_map.parameters, ansatz.parameters |
24 | 128 |
|
25 | 129 |
|
26 | 130 | class QNNCircuit(BlueprintCircuit):
|
27 | 131 | """
|
28 |
| - The QNN circuit is a blueprint circuit that wraps feature map and ansatz circuits. |
| 132 | + (DEPRECATED) The QNN circuit is a blueprint circuit that wraps feature map and ansatz circuits. |
29 | 133 | It can be used to simplify the composition of these two.
|
30 | 134 |
|
31 | 135 | If only the number of qubits is provided the :class:`~qiskit.circuit.library.RealAmplitudes`
|
@@ -119,6 +223,16 @@ def __init__(
|
119 | 223 | """
|
120 | 224 |
|
121 | 225 | super().__init__()
|
| 226 | + |
| 227 | + issue_deprecation_msg( |
| 228 | + msg="QNNCircuit, a BlueprintCircuit based class, is deprecated", |
| 229 | + version="0.9.0", |
| 230 | + remedy="Use qnn_circuit instead of QNNCircuit but note " |
| 231 | + "that later adjustment of the number of qubits, or updating " |
| 232 | + "the feature map and/or ansatz is not possible anymore.", |
| 233 | + period="4 months", |
| 234 | + ) |
| 235 | + |
122 | 236 | self._feature_map = feature_map
|
123 | 237 | self._ansatz = ansatz
|
124 | 238 | # Check if circuit is constructed with valid configuration and set properties accordingly.
|
|
0 commit comments