def post_select_generaldyne(self, covmat, modes, vals): r"""Simulates a general-dyne measurement on a set of modes with a specified measurement outcome. Args: covmat (array): covariance matrix of the generaldyne measurement modes (list): modes to be measured vals (array): measurement outcome to postselect Raises: ValueError: if the dimension of covmat does not match the number of quadratures associated with modes ValueError: if any of the modes are not in the list of active modes """ if covmat.shape != (2 * len(modes), 2 * len(modes)): raise ValueError( "The size of the covariance matrix does not match the indices provided." ) for i in modes: if self.active[i] is None: raise ValueError( "Cannot apply measurement, mode does not exist") expind = np.concatenate((2 * np.array(modes), 2 * np.array(modes) + 1)) mp = self.get_covmat() A, B, C = ops.chop_in_blocks_multi(mp, expind) V = A - B @ np.linalg.inv(C + covmat) @ B.transpose(0, 2, 1) self.covs = ops.reassemble_multi(V, expind) r = self.get_mean() (va, vc) = ops.chop_in_blocks_vector_multi(r, expind) va = va + np.einsum("...ij,...j", B @ np.linalg.inv(C + covmat), (vals - vc)) self.means = ops.reassemble_vector_multi(va, expind) # Reweight each peak based on how likely a given peak was to have # contributed to the observed outcome reweights_exp_arg = np.einsum("...j,...jk,...k", (vals - vc), np.linalg.inv(C + covmat), (vals - vc)) reweights = np.exp(-0.5 * reweights_exp_arg) / (np.sqrt( np.linalg.det(2 * np.pi * (C + covmat)))) self.weights *= reweights self.weights /= np.sum(self.weights) self.means = self.means[abs(self.weights) > 0] self.covs = self.covs[abs(self.weights) > 0] self.weights = self.weights[abs(self.weights) > 0]
def test_reassemble_multi(self, id_to_delete): r"""Checks that ops.reassemble_multi generates the correct output""" # Create matrix A = np.random.rand(2, 2) reps = np.random.randint(1, 10) Atile = np.tile(A, [reps, 1, 1]) # Create indices m = ops.reassemble_multi(Atile, id_to_delete) dim = len(A) + len(id_to_delete) id_to_keep = list(set(range(dim)) - set(id_to_delete)) id_to_keep.sort() assert m.shape == (reps, dim, dim) A2, B2, C2 = ops.chop_in_blocks_multi(m, id_to_keep) assert np.allclose(C2, Atile) assert np.allclose(B2, 0) assert np.allclose(A2, np.tile(np.eye(len(id_to_delete)), [reps, 1, 1]))
def test_chop_in_blocks_multi(self, reps): r"""Checks that ops.chop_in_block_multi partitions arrays of matrices correctly""" # Create submatrices A = np.random.rand(2, 2) B = np.random.rand(2, 3) C = np.random.rand(3, 3) # Repeat them in an array Atile = np.tile(A, [reps, 1, 1]) Btile = np.tile(B, [reps, 1, 1]) Ctile = np.tile(C, [reps, 1, 1]) # Make a new block matrix out of them and repeat it m = np.block([[A, B], [B.T, C]]) m = np.tile(m, [reps, 1, 1]) # Choose to delete the indices corresponding to C id_to_delete = np.arange(2, 5, dtype=int) A2, B2, C2 = ops.chop_in_blocks_multi(m, id_to_delete) assert np.allclose(A2, Atile) assert np.allclose(B2, Btile) assert np.allclose(C2, Ctile)
def measure_threshold(self, modes): r"""Performs photon number measurement on the given modes""" if len(modes) == 1: if self.active[modes[0]] is None: raise ValueError( "Cannot apply measurement, mode does not exist") Idmat = self.hbar * np.eye(2) / 2 vacuum_fidelity = np.abs(self.fidelity_vacuum(modes)) measurement = np.random.choice( (0, 1), p=[vacuum_fidelity, 1 - vacuum_fidelity]) samples = measurement # If there are no more modes to measure simply set everything to vacuum if len(modes) == len(self.active): for mode in modes: self.loss(0, mode) # If there are other active modes simply update based on measurement else: mode_ind = np.concatenate( (2 * np.array(modes), 2 * np.array(modes) + 1)) sigma_A, sigma_AB, sigma_B = ops.chop_in_blocks_multi( self.covs, mode_ind) sigma_A_prime = sigma_A - sigma_AB @ np.linalg.inv( sigma_B + Idmat) @ sigma_AB.transpose(0, 2, 1) r_A, r_B = ops.chop_in_blocks_vector_multi( self.means, mode_ind) r_A_prime = r_A - np.einsum( "...ij,...j", sigma_AB @ np.linalg.inv(sigma_B + Idmat), r_B) reweights_exp_arg = np.einsum("...j,...jk,...k", -r_B, np.linalg.inv(sigma_B + Idmat), -r_B) reweights = np.exp(-0.5 * reweights_exp_arg) / (np.sqrt( np.linalg.det(2 * np.pi * (sigma_B + Idmat)))) if measurement == 1: self.means = np.append( ops.reassemble_vector_multi(r_A, mode_ind), ops.reassemble_vector_multi(r_A_prime, mode_ind), axis=0, ) self.covs = np.append( ops.reassemble_multi(sigma_A, mode_ind), ops.reassemble_multi(sigma_A_prime, mode_ind), axis=0, ) self.weights = np.append( self.weights / (1 - vacuum_fidelity), self.weights * (reweights * 2 * np.pi * self.hbar / (vacuum_fidelity - 1)), axis=0, ) else: self.post_select_heterodyne(modes[0], 0) self.loss(0, modes[0]) return samples raise ValueError( "Measure Threshold can only be applied to one mode at a time")