Skip to content

Commit

Permalink
fix: remove deprecated as_unitary method (#738)
Browse files Browse the repository at this point in the history
  • Loading branch information
AbeCoull authored Oct 24, 2023
1 parent b89d394 commit 8ba0b4a
Show file tree
Hide file tree
Showing 3 changed files with 1 addition and 532 deletions.
49 changes: 1 addition & 48 deletions src/braket/circuits/circuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

from __future__ import annotations

import warnings
from collections.abc import Callable, Iterable
from numbers import Number
from typing import Any, Optional, TypeVar, Union
Expand Down Expand Up @@ -51,7 +50,7 @@
QubitReferenceType,
SerializationProperties,
)
from braket.circuits.unitary_calculation import calculate_unitary, calculate_unitary_big_endian
from braket.circuits.unitary_calculation import calculate_unitary_big_endian
from braket.default_simulator.openqasm.interpreter import Interpreter
from braket.ir.jaqcd import Program as JaqcdProgram
from braket.ir.openqasm import Program as OpenQasmProgram
Expand Down Expand Up @@ -1391,52 +1390,6 @@ def _add_fixed_argument_calibrations(
)
return additional_calibrations

def as_unitary(self) -> np.ndarray:
r"""
Returns the unitary matrix representation, in little endian format, of the entire circuit.
*Note*: The performance of this method degrades with qubit count. It might be slow for
qubit count > 10.
Returns:
ndarray: A numpy array with shape (2^qubit_count, 2^qubit_count) representing the
circuit as a unitary. *Note*: For an empty circuit, an empty numpy array is
returned (`array([], dtype=complex128)`)
Warnings:
This method has been deprecated, please use to_unitary() instead.
The unitary returned by this method is *little-endian*; the first qubit in the circuit
is the _least_ significant. For example, a circuit `Circuit().h(0).x(1)` will yield the
unitary :math:`X(1) \otimes H(0)`.
Raises:
TypeError: If circuit is not composed only of `Gate` instances,
i.e. a circuit with `Noise` operators will raise this error.
Examples:
>>> circ = Circuit().h(0).cnot(0, 1)
>>> circ.as_unitary()
array([[ 0.70710678+0.j, 0.70710678+0.j, 0. +0.j,
0. +0.j],
[ 0. +0.j, 0. +0.j, 0.70710678+0.j,
-0.70710678+0.j],
[ 0. +0.j, 0. +0.j, 0.70710678+0.j,
0.70710678+0.j],
[ 0.70710678+0.j, -0.70710678+0.j, 0. +0.j,
0. +0.j]])
"""
warnings.warn(
"Matrix returned will have qubits in little-endian order; "
"This method has been deprecated. Please use to_unitary() instead.",
category=DeprecationWarning,
)

qubits = self.qubits
if not qubits:
return np.zeros(0, dtype=complex)
qubit_count = max(qubits) + 1

return calculate_unitary(qubit_count, self.instructions)

def to_unitary(self) -> np.ndarray:
"""
Returns the unitary matrix representation of the entire circuit.
Expand Down
71 changes: 0 additions & 71 deletions src/braket/circuits/unitary_calculation.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,77 +23,6 @@
from braket.registers.qubit_set import QubitSet


def _einsum_subscripts(targets: QubitSet, qubit_count: int) -> str:
target_count = len(targets)

gate_left_indexes = list(range(target_count))
un_left_indexes = list(range(target_count, target_count + qubit_count))
un_right_indexes = list(range(target_count + qubit_count, target_count + 2 * qubit_count))

gate_right_indexes = [un_left_indexes[-1 - target] for target in targets]

result_left_indexes = un_left_indexes.copy()
for pos, target in enumerate(targets):
result_left_indexes[-1 - target] = gate_left_indexes[pos]

return (
gate_left_indexes + gate_right_indexes,
un_left_indexes + un_right_indexes,
result_left_indexes + un_right_indexes,
)


def calculate_unitary(qubit_count: int, instructions: Iterable[Instruction]) -> np.ndarray:
"""
Returns the unitary matrix representation for all the `instructions` with a given
`qubit_count`.
*Note*: The performance of this method degrades with qubit count. It might be slow for
qubit count > 10.
Args:
qubit_count (int): Total number of qubits, enough for all the `instructions`.
instructions (Iterable[Instruction]): The instructions for which the unitary matrix
will be calculated.
Returns:
np.ndarray: A numpy array with shape (2^qubit_count, 2^qubit_count) representing the
`instructions` as a unitary.
Raises:
TypeError: If `instructions` is not composed only of `Gate` instances,
i.e. a circuit with `Noise` operators will raise this error.
Any `CompilerDirective` instructions will be ignored, as these should
not affect the unitary representation of the circuit.
"""
unitary = np.eye(2**qubit_count, dtype=complex)
un_tensor = np.reshape(unitary, qubit_count * [2, 2])

for instr in instructions:
if isinstance(instr.operator, CompilerDirective):
continue

if not isinstance(instr.operator, Gate):
raise TypeError("Only Gate operators are supported to build the unitary")

matrix = instr.operator.to_matrix()
targets = instr.target

gate_indexes, un_indexes, result_indexes = _einsum_subscripts(targets, qubit_count)
gate_matrix = np.reshape(matrix, len(targets) * [2, 2])

un_tensor = np.einsum(
gate_matrix,
gate_indexes,
un_tensor,
un_indexes,
result_indexes,
dtype=complex,
casting="no",
)

return np.reshape(un_tensor, 2 * [2**qubit_count])


def calculate_unitary_big_endian(
instructions: Iterable[Instruction], qubits: QubitSet
) -> np.ndarray:
Expand Down
Loading

0 comments on commit 8ba0b4a

Please sign in to comment.