File size: 1,452 Bytes
9f8cf99
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
from __future__ import annotations

import numpy as np
from numpy.typing import ArrayLike, NDArray

from .noise import apply_kraus_1q_density_matrix


def kraus_1q_from_qiskit(error: object) -> NDArray[np.complex128]:
    """
    Extract 1-qubit Kraus operators from a Qiskit object.

    Works for many Qiskit quantum channels and Aer noise errors via `qiskit.quantum_info.Kraus`.
    Returns a complex ndarray of shape (k, 2, 2).
    """
    try:
        from qiskit.quantum_info import Kraus  # type: ignore
    except Exception as e:  # pragma: no cover
        raise ImportError(
            "Qiskit is not installed. Install with `pip install qhybrid-kernels[qiskit]`."
        ) from e

    k = Kraus(error)
    data = np.asarray(k.data, dtype=np.complex128)

    # Qiskit may return shape (k, 2, 2) or (2, 2) for a single Kraus op
    if data.shape == (2, 2):
        data = data[None, :, :]

    if data.ndim != 3 or data.shape[1:] != (2, 2):
        raise ValueError(f"Expected Kraus ops of shape (k,2,2); got {data.shape}")

    return data


def apply_qiskit_kraus_1q_to_density_matrix(
    rho: ArrayLike,
    n_qubits: int,
    target_qubit: int,
    error: object,
) -> NDArray[np.complex128]:
    """
    Convenience wrapper:
      - convert Qiskit error/channel to Kraus
      - call the Rust kernel
    """
    kraus_ops = kraus_1q_from_qiskit(error)
    return apply_kraus_1q_density_matrix(rho, n_qubits, target_qubit, kraus_ops)