/
base_operator.py
145 lines (120 loc) · 4.84 KB
/
base_operator.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# This code is part of Qiskit.
#
# (C) Copyright IBM 2017, 2019.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.
"""
Abstract BaseOperator class.
"""
from __future__ import annotations
import copy
from abc import ABC
from qiskit.exceptions import QiskitError
from qiskit.quantum_info.operators.op_shape import OpShape
from .mixins import GroupMixin
class BaseOperator(GroupMixin, ABC):
"""Abstract operator base class."""
def __init__(
self,
input_dims: tuple | int | None = None,
output_dims: tuple | int | None = None,
num_qubits: int | None = None,
shape: tuple | None = None,
op_shape: OpShape | None = None,
):
"""Initialize a BaseOperator shape
Args:
input_dims (tuple or int or None): Optional, input dimensions.
output_dims (tuple or int or None): Optional, output dimensions.
num_qubits (int): Optional, the number of qubits of the operator.
shape (tuple): Optional, matrix shape for automatically determining
qubit dimensions.
op_shape (OpShape): Optional, an OpShape object for operator dimensions.
.. note::
If `op_shape`` is specified it will take precedence over other
kwargs.
"""
self._qargs = None
if op_shape:
self._op_shape = op_shape
else:
self._op_shape = OpShape.auto(
shape=shape, dims_l=output_dims, dims_r=input_dims, num_qubits=num_qubits
)
# Set higher priority than Numpy array and matrix classes
__array_priority__ = 20
def __call__(self, *qargs):
"""Return a shallow copy with qargs attribute set"""
if len(qargs) == 1 and isinstance(qargs[0], (tuple, list)):
qargs = qargs[0]
n_qargs = len(qargs)
if n_qargs not in self._op_shape.num_qargs:
raise QiskitError(
"qargs does not match the number of operator qargs "
f"({n_qargs} not in {self._op_shape.num_qargs})"
)
ret = copy.copy(self)
ret._qargs = tuple(qargs)
return ret
def __eq__(self, other):
return isinstance(other, type(self)) and self._op_shape == other._op_shape
@property
def qargs(self):
"""Return the qargs for the operator."""
return self._qargs
@property
def dim(self):
"""Return tuple (input_shape, output_shape)."""
return self._op_shape._dim_r, self._op_shape._dim_l
@property
def num_qubits(self):
"""Return the number of qubits if a N-qubit operator or None otherwise."""
return self._op_shape.num_qubits
@property
def _input_dim(self):
"""Return the total input dimension."""
return self._op_shape._dim_r
@property
def _output_dim(self):
"""Return the total input dimension."""
return self._op_shape._dim_l
def reshape(
self,
input_dims: None | tuple | int = None,
output_dims: None | tuple | int = None,
num_qubits: None | int = None,
) -> BaseOperator:
"""Return a shallow copy with reshaped input and output subsystem dimensions.
Args:
input_dims (None or tuple): new subsystem input dimensions.
If None the original input dims will be preserved [Default: None].
output_dims (None or tuple): new subsystem output dimensions.
If None the original output dims will be preserved [Default: None].
num_qubits (None or int): reshape to an N-qubit operator [Default: None].
Returns:
BaseOperator: returns self with reshaped input and output dimensions.
Raises:
QiskitError: if combined size of all subsystem input dimension or
subsystem output dimensions is not constant.
"""
new_shape = OpShape.auto(
dims_l=output_dims, dims_r=input_dims, num_qubits=num_qubits, shape=self._op_shape.shape
)
ret = copy.copy(self)
ret._op_shape = new_shape
return ret
def input_dims(self, qargs=None):
"""Return tuple of input dimension for specified subsystems."""
return self._op_shape.dims_r(qargs)
def output_dims(self, qargs=None):
"""Return tuple of output dimension for specified subsystems."""
return self._op_shape.dims_l(qargs)
def copy(self):
"""Make a deep copy of current operator."""
return copy.deepcopy(self)