def _kraus_ops_from_rates(
    flat_rates: tuple[float, ...], shape: tuple[int, int]
) -> Sequence[np.ndarray]:
    """Generate kraus operators from an array of rates.

    Args:
        flat_rates: A tuple of rates, flattened from a numpy array with:
            flat_rates = tuple(rates.reshape(-1))
            This format is necessary to support caching of inputs.
        shape: The shape of flat_rates prior to flattening.
    """
    rates = np.array(flat_rates).reshape(shape)
    num_op = np.diag(np.sqrt(np.diag(rates)))
    annihilation = np.sqrt(np.triu(rates, 1))
    creation = np.sqrt(np.triu(rates.T, 1)).T
    # Lindbladian with three Lindblad ops for the three processes
    # Note: 'time' parameter already specified implicitly through rates
    L = _lindbladian(annihilation) + _lindbladian(creation) + 2 * _lindbladian(num_op)
    superop = linalg.expm(L.real)
    return qis.superoperator_to_kraus(superop)
Generate kraus operators from an array of rates.

    Args:
        flat_rates: A tuple of rates, flattened from a numpy array with:
            flat_rates = tuple(rates.reshape(-1))
            This format is necessary to support caching of inputs.
        shape: The shape of flat_rates prior to flattening.
    
cirq-core/cirq/devices/thermal_noise_model.py