Source code for qbraid.interface.random.random

# Copyright (C) 2024 qBraid
#
# This file is part of the qBraid-SDK
#
# The qBraid-SDK is free software released under the GNU General Public License v3
# or later. You can redistribute and/or modify it under the terms of the GPL v3.
# See the LICENSE file in the project root or <https://www.gnu.org/licenses/gpl-3.0.html>.
#
# THERE IS NO WARRANTY for the qBraid-SDK, as per Section 15 of the GPL v3.

"""
Module for generate random quantum circuits used for testing

"""
from __future__ import annotations

from typing import TYPE_CHECKING, Optional

import numpy as np

from qbraid._logging import logger
from qbraid.exceptions import QbraidError
from qbraid.programs.exceptions import PackageValueError
from qbraid.programs.registry import QPROGRAM_ALIASES
from qbraid.transpiler.converter import transpile
from qbraid.transpiler.graph import ConversionGraph

if TYPE_CHECKING:
    import qbraid.programs


[docs] def random_circuit( package: str, num_qubits: Optional[int] = None, depth: Optional[int] = None, graph: Optional[ConversionGraph] = None, **kwargs, ) -> qbraid.programs.QPROGRAM: """Generate random circuit of arbitrary size and form. Args: package (str): qBraid supported software package num_qubits (int, optional): Number of quantum wires. If not provided, set randomly in range [1,4]. depth (int, optional): Layers of operations (i.e. critical path length) If not provided, set randomly in range [1,4]. graph (ConversionGraph, optional): Conversion graph to use for transpilation **kwargs: Additional keyword arguments to pass to the random circuit generator Raises: PackageValueError: if ``package`` is not supported ValueError: when no conversion path exists for the specified package QbraidError: when random circuit generation fails for the specified package Returns: qbraid.programs.QPROGRAM: randomly generated quantum circuit/program """ def validate_and_assign(value: Optional[int], name: str): if value is None: return np.random.randint(1, 4) if not isinstance(value, int) or value <= 0: raise ValueError(f"Invalid random circuit option. '{name}' must be a positive integer.") return value if package not in QPROGRAM_ALIASES: raise PackageValueError(f"Package '{package}' is not supported.") generator_funcs = { "qasm3": "qbraid.interface.random.qasm3_random._qasm3_random", "qiskit": "qbraid.interface.random.qiskit_random._qiskit_random", "cirq": "qbraid.interface.random.cirq_random._cirq_random", } graph = graph or ConversionGraph() valid_generators = [gen for gen in list(generator_funcs.keys()) if graph.has_path(gen, package)] if not valid_generators: raise ValueError( f"No registered generator that can create a random circuit for '{package}'." ) num_qubits = validate_and_assign(num_qubits, "num_qubits") depth = validate_and_assign(depth, "depth") sorted_generators = graph.get_sorted_closest_sources(package, valid_generators) for src_pkg in sorted_generators: func_path = generator_funcs[src_pkg] try: module_name, func_name = func_path.rsplit(".", 1) module = __import__(module_name, fromlist=[func_name]) rand_circuit_func = getattr(module, func_name) rand_circuit = rand_circuit_func(num_qubits, depth, **kwargs) return transpile(rand_circuit, package) except Exception as err: # pylint: disable=broad-exception-caught logger.info("Failed to generate circuit with %s: %s", src_pkg, err) continue raise QbraidError(f"Failed to generate random circuit for program type '{package}'.")
[docs] def random_unitary_matrix(dim: int) -> np.ndarray: """Create a random (complex) unitary matrix of order `dim` Args: dim: integer square matrix dimension Returns: random unitary matrix of shape dim x dim """ # Create a random complex matrix of size dim x dim matrix = np.random.randn(dim, dim) + 1j * np.random.randn(dim, dim) # Use the QR decomposition to get a random unitary matrix unitary, _ = np.linalg.qr(matrix) return unitary