Array Module (qiskit_dynamics.array)#

Warning

The array and dispatch submodules of Qiskit Dynamics have been deprecated as of version 0.5.0. The use of the Array class is no longer required to work with different array libraries in Qiskit Dynamics, and is broken in some cases. Refer to the user guide entry on using different array libraries with Qiskit Dynamics. Users can now work directly with the supported array type of their choice, without the need to wrap them to enable dispatching. The array and dispatch submodules will be removed in version 0.6.0.

This module contains an Array class that wraps N-dimensional array objects from different libraries. It enables working with different array libraries through a common NumPy-based interface, along with other functionality for writing array-library agnostic code.

Array Class#

The Array class provides a NumPy compatible wrapper to supported Python array libraries. NumPy functions applied to an Array class instance will be dispatched to the corresponding function for the current Array backend, if a compatible function has been specified in the qiskit_dynamics.dispatch system.

The following array libraries have built in support for the qiskit_dynamics.dispatch module:

Basic Usage#

When using the default numpy backend Array, objects can be used interchangably with numpy.ndarray. When numpy functions are applied to an Array object the return type will be an Array instead of an numpy.ndarray.

from qiskit_dynamics.array import Array
import numpy as np

# Initialize an Array
a = Array(np.arange(10))

# Apply numpy ufuncs
np.cos(a) + 1j * np.sin(a)
Array([ 1.        +0.j        ,  0.54030231+0.84147098j,
       -0.41614684+0.90929743j, -0.9899925 +0.14112001j,
       -0.65364362-0.7568025j ,  0.28366219-0.95892427j,
        0.96017029-0.2794155j ,  0.75390225+0.6569866j ,
       -0.14550003+0.98935825j, -0.91113026+0.41211849j], backend='numpy')

For the JAX Array backend, only Numpy functions that have a corresponding function in the jax library that have been registered with the dispatch module can be applied to the functions. Trying to apply an unsupported numpy function to these arrays will raise an exception.

Default Backend#

When initializing a new Array, the backend kwarg is used to specify which array backend to use. This will convert the input data to an array of this backend if required. If backend=None, the default backend will be used. The initial default backend is always set to "numpy".

The current default backend can be viewed by using the class method Array.default_backend(). A different default backend can be set for all Array() instances by using the Array.set_default_backend() class method.

Attributes and Methods#

The Array class exposes the same methods and attributes of the wrapped array class and adds two additional attributes:

  • data which returns the wrapped array object

  • backend which returns the backend string of the wrapped array.

All other attributes and methods of the wrapped array are accessible through this class, but with any array return types wrapped into Array objects. For example:

# Call an numpy.ndarray method
a.reshape((2, 5))
Array([[0, 1, 2, 3, 4],
       [5, 6, 7, 8, 9]], backend='numpy')

Array Initialization#

An Array object can be initialized as Array(data) from any data that is:

  1. An array object of one of the supported backends.

  2. An object that can be used to initialize the backend array.

  3. An object of a class that defines a __qiskit_array__ method with the following signature:

    def __qiskit_array__(self,
                         dtype: Optional[any] = None,
                         backend: Optional[str]=None) -> Array:
        # conversion from class to Array
    

The Array.__init__() method has optional kwargs:

  • dtype (any): Equivalent to the numpy.array dtype kwarg. For other array backends, the specified dtype must be supported. If not specified, the dtype will be inferred from the input data.

  • order (str): Equivalent to the numpy.array order kwarg. For other array backends, the specified order value must be supported.

  • backend (str): The array backend to use. If not specified this will be inferred from the input data type if it is a backend array instance, otherwise it will be the default_backend().

Using Arrays with other Libraries#

The Array class is intended to be used with array functions in Python libraries that work with any of the supported Array backends.

Wrapping Functions#

Functions from other libraries can be wrapped to work with Array objects using the wrap() function as

from qiskit_dynamics.array import Array, wrap

# Some 3rd-party library
import library

# Wrap library function f
f = wrap(library.f)

# Apply f to an Array
a = Array([0, 1, 2, 4])
b = f(a)

The wrapped function will automatically unwrap any Array args and kwargs for calling the wrapped function. If the result of the function is a backend array or an instance of a class that defines a __qiskit_array__ method, the wrapped function will return this as an Array object. Similarly, if the result is a tuple this conversion will be applied to each element of the tuple where appropriate.

Wrapping Decorators#

The wrap() function can also be used to wrap function decorators by setting the decorator=True kwarg.

For example, to wrap autograd and jit decorators from the JAX library to work with Array functions, we can do the following

import jax

jit = wrap(jax.jit, decorator=True)
grad = wrap(jax.grad, decorator=True)
value_and_grad = wrap(jax.value_and_grad, decorator=True)

f = jit(obj)
g = grad(obj)
h = value_and_grad(obj)

Array Class#

Array(data[, dtype, order, backend])

Qiskit array class.

Array Functions#

wrap(func[, wrap_return, wrap_args, decorator])

Wrap an array backend function to work with Arrays.