import numpy as np
from scipy.ndimage import gaussian_filter
from qutip import Qobj, rand_dm
import tensorflow as tf
import warnings
##### State preparation noise sources #####
[docs]
def mixed_state_noise(density_matrix: Qobj, noise_level: float=0.1) -> np.ndarray:
"""
Adds noise to a density matrix by mixing it with a random density matrix.
Parameters
----------
density_matrix : np.ndarray
Density matrix to which noise will be added.
noise_level : float
Proportion of noise to add to the density matrix. Must be between 0 and 1. Defaults to 0.1.
Returns
-------
np.ndarray
Density matrix with noise added.
"""
if type(density_matrix) == np.ndarray:
density_matrix = Qobj(density_matrix)
elif type(density_matrix) == tf.Tensor:
density_matrix = Qobj(density_matrix.numpy())
elif type(density_matrix) != Qobj:
raise ValueError("unrecognised data type for density_matrix.")
if noise_level < 0 or noise_level > 1:
raise ValueError("noise_level must be between 0 and 1.")
return (1 - noise_level) * density_matrix + noise_level * rand_dm(density_matrix.shape[0])
[docs]
def gaussian_convolution(Q_function: np.ndarray, variance: float) -> np.ndarray:
"""
Convolves a Q-function image with a Gaussian kernel.
Parameters
----------
Q_function : np.ndarray
Q-function image to be convolved.
variance : float
Variance of the Gaussian kernel.
Returns
-------
np.ndarray
Q-function image after convolution.
"""
return gaussian_filter(Q_function, sigma=variance)
##### Experimental measurement and data noise sources #####
[docs]
def additive_gaussian_noise(image: np.ndarray, mean: float, std: float) -> np.ndarray:
"""
Adds Gaussian noise to the image by sampling from a Gaussian distribution with the given mean and standard deviation. This type of noise arises from finite measurements and discrete binning of continuous data.
Parameters
----------
image : np.ndarray
Image to which noise will be added.
mean : float
Mean of the Gaussian distribution.
std : float
Standard deviation of the Gaussian distribution.
Returns
-------
np.ndarray
Image with Gaussian noise added.
"""
noise = np.random.normal(mean, std, image.shape)
image = image + noise
image[image < 0] = 0
return image
[docs]
def salt_and_pepper_noise(image: np.ndarray, pepper_p: float, salt_p: float=0.0, prob=None) -> np.ndarray:
"""
Adds salt-and-pepper noise to the image - set a proportion of pixels to 0.
Parameters
----------
image : np.ndarray
Image to which noise will be added.
pepper_p : float
Proportion of pixels to set to 0.
salt_p : float
Proportion of pixels to set to 1. Defaults to 0.0.
Returns
-------
np.ndarray
Image with salt-and-pepper noise added.
"""
if not pepper_p and pepper_p != 0:
if prob:
pepper_p = prob
warnings.warn("prob is deprecated and will be removed in a future version. Please use salt_p and pepper_p instead.", DeprecationWarning, stacklevel=2)
else:
raise ValueError("pepper_p must be specified.")
noise1 = np.random.rand(*image.shape)
image[noise1 < salt_p] = 1
noise2 = np.random.rand(*image.shape)
image[noise2 < pepper_p] = 0
return image
##### Combined noise #####
[docs]
def apply_measurement_noise(image: np.ndarray, affine_theta: float, affine_x: float, affine_y: float, additive_Gaussian_stddev: float, pepper_p: float, salt_p: float=0.0, salt_and_pepper_prob=None) -> np.ndarray:
"""
Applies all types of measurement noise to the image, using the given parameters.
Parameters
----------
image : np.ndarray
Image to which noise will be added.
affine_theta : float
Maximum rotation angle in degrees.
affine_x : float
Maximum translation in the x direction.
affine_y : float
Maximum translation in the y direction.
additive_Gaussian_stddev : float
Standard deviation of the Gaussian distribution from which additive noise is sampled.
salt_p : float
Proportion of pixels to set to 1. Defaults to 0.
pepper_p : float
Proportion of pixels to set to 0.
Returns
-------
np.ndarray
Image with all types of noise added.
"""
if not pepper_p and pepper_p != 0:
if salt_and_pepper_prob:
pepper_p = salt_and_pepper_prob
warnings.warn("prob is deprecated and will be removed in a future version. Please use salt_p and pepper_p instead.", DeprecationWarning, stacklevel=2)
else:
raise ValueError("pepper_p must be specified.")
return salt_and_pepper_noise(
additive_gaussian_noise(
affine_transformation(image,
affine_theta,
affine_x,
affine_y),
np.mean(image),
additive_Gaussian_stddev),
pepper_p, salt_p)