Skip to content

Commit

Permalink
Add check_input option to UnitaryGate (Qiskit#10660)
Browse files Browse the repository at this point in the history
* Add skip_check option to UnitaryGate

This commit adds a new option to the unitary gate class's constructor,
skip_check, which is used to skip the checking on the input unitary.
When creating a unitary gates when you know the input is already unitary
checking that the input matrix is unitary is wasted CPU time. This new
option enables a user to assert the input is unitary and skip this
checking (at their own risk). The primary use case for this is the
consolidate blocks pass which is creating a large number of UnitaryGate
objects and matrix is always going to be unitary. This new flag is used
in ConsolidateBlocks to speed up the creation of gate objects.

* Rename argument check_input

* Fix rebase issues

* Update qiskit/circuit/library/generalized_gates/unitary.py
  • Loading branch information
mtreinish authored Oct 2, 2023
1 parent e24eee2 commit 81e28dc
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 14 deletions.
31 changes: 21 additions & 10 deletions qiskit/circuit/library/generalized_gates/unitary.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,22 @@ class UnitaryGate(Gate):
circuit.append(gate, [0, 1])
"""

def __init__(self, data: numpy.ndarray | Gate | BaseOperator, label: str | None = None) -> None:
"""
def __init__(
self,
data: numpy.ndarray | Gate | BaseOperator,
label: str | None = None,
check_input: bool = True,
) -> None:
"""Create a gate from a numeric unitary matrix.
Args:
data: Unitary operator.
label: Unitary name for backend [Default: None].
check_input: If set to ``False`` this asserts the input
is known to be unitary and the checking to validate this will
be skipped. This should only ever be used if you know the
input is unitary, setting this to ``False`` and passing in
a non-unitary matrix will result unexpected behavior and errors.
Raises:
ValueError: If input data is not an N-qubit unitary operator.
Expand All @@ -82,16 +93,16 @@ def __init__(self, data: numpy.ndarray | Gate | BaseOperator, label: str | None
# numpy matrix from `Operator.data`.
data = data.to_operator().data
# Convert to numpy array in case not already an array
data = numpy.array(data, dtype=complex)
# Check input is unitary
if not is_unitary_matrix(data):
raise ValueError("Input matrix is not unitary.")
# Check input is N-qubit matrix
data = numpy.asarray(data, dtype=complex)
input_dim, output_dim = data.shape
num_qubits = int(numpy.log2(input_dim))
if input_dim != output_dim or 2**num_qubits != input_dim:
raise ValueError("Input matrix is not an N-qubit operator.")

if check_input:
# Check input is unitary
if not is_unitary_matrix(data):
raise ValueError("Input matrix is not unitary.")
# Check input is N-qubit matrix
if input_dim != output_dim or 2**num_qubits != input_dim:
raise ValueError("Input matrix is not an N-qubit operator.")
# Store instruction params
super().__init__("unitary", num_qubits, [data], label=label)

Expand Down
8 changes: 4 additions & 4 deletions qiskit/transpiler/passes/optimization/consolidate_blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,10 @@ def run(self, dag):
qc.add_register(c)
for nd in block:
qc.append(nd.op, [q[block_index_map[i]] for i in nd.qargs])
unitary = UnitaryGate(Operator(qc))
unitary = UnitaryGate(Operator(qc), check_input=False)
else:
matrix = _block_to_matrix(block, block_index_map)
unitary = UnitaryGate(matrix)
unitary = UnitaryGate(matrix, check_input=False)

max_2q_depth = 20 # If depth > 20, there will be 1q gates to consolidate.
if ( # pylint: disable=too-many-boolean-expressions
Expand All @@ -151,7 +151,7 @@ def run(self, dag):
if any(gate in all_block_gates for gate in run):
continue
if len(run) == 1 and not self._check_not_in_basis(dag, run[0].name, run[0].qargs):
dag.substitute_node(run[0], UnitaryGate(run[0].op.to_matrix()))
dag.substitute_node(run[0], UnitaryGate(run[0].op.to_matrix(), check_input=False))
else:
qubit = run[0].qargs[0]
operator = run[0].op.to_matrix()
Expand All @@ -162,7 +162,7 @@ def run(self, dag):
operator = gate.op.to_matrix().dot(operator)
if already_in_block:
continue
unitary = UnitaryGate(operator)
unitary = UnitaryGate(operator, check_input=False)
if np.allclose(identity_1q, unitary.to_matrix()):
for node in run:
dag.remove_op_node(node)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
features:
- |
Added a new argument, ``check_input``, to the constructor for the
:class:`~.UnitaryGate` class. This flag is used to disable the default
initialization checks that input object represents a unitary matrix.
This can be used to speed up the creation of :class:`~.UnitaryGate`
objects if you know the input is already a unitary matrix. This new option
should only be used in these cases because if it's set to ``False`` and
the input is not unitary this will result in an invalid ``UnitaryGate``
object.

0 comments on commit 81e28dc

Please sign in to comment.