Diagram#
- class discopy.quantum.optics.Diagram(dom, cod, boxes, offsets, layers=None)[source]#
Bases:
DiagramLinear optical network seen as a diagram of beam splitters, phase shifters and Mach-Zender interferometers.
Example
>>> BS >> BS optics.Diagram(dom=PRO(2), cod=PRO(2), boxes=[BS, BS], offsets=[0, 0])
- property array#
The array corresponding to the diagram. Builds a block diagonal matrix for each layer and then multiplies them in sequence.
Example
>>> np.shape(to_matrix(BS).array) (2, 2) >>> np.shape(to_matrix(BS >> BS).array) (2, 2) >>> np.shape(to_matrix(BS @ BS @ BS).array) (6, 6) >>> assert np.allclose( ... to_matrix(MZI(0, 0)).array, np.array([[0, 1], [1, 0]])) >>> assert np.allclose(to_matrix(MZI(0, 0) >> MZI(0, 0)).array, ... to_matrix(Id(2)).array)
- amp(x, y, permanent=<function npperm>)[source]#
Evaluates the amplitude of an optics.Diagram on input x and output y, when sending indistinguishable photons.
- Parameters:
x (List[int]) – Input vector of occupation numbers
y (List[int]) – Output vector of occupation numbers
permanent (callable, optional) – Use another function for computing the permanent or set permanent = np.determinant to compute fermionic statistics
Example
>>> network = MZI(0.2, 0.4) @ MZI(0.2, 0.4) >> Id(1) @ MZI(0.2, 0.4) @ Id(1) >>> amplitude = network.amp([1, 0, 0, 1], [1, 0, 1, 0]) >>> probability = np.abs(amplitude) ** 2 >>> assert probability > 0.05
- eval(n_photons, permanent=<function npperm>)[source]#
Evaluates the matrix acting on the Fock space given number of photons.
- Parameters:
n_photons (int) – Number of photons
permanent (callable, optional) – Use another function for computing the permanent (e.g. from thewalrus)
Example
>>> for i, _ in enumerate(occupation_numbers(3, 2)): assert np.isclose( ... sum(np.absolute(MZI(0.2, 0.4).eval(3)[i])**2), 1) >>> network = MZI(0.2, 0.4) @ Id(1) >> Id(1) @ MZI(0.2, 0.4) >>> for i, _ in enumerate(occupation_numbers(2, 3)): assert np.isclose( ... sum(np.absolute(network.eval(2)[i])**2), 1)
- indist_prob(x, y, permanent=<function npperm>)[source]#
Evaluates the probability for indistinguishable bosons by taking the born rule of the amplitude.
- Parameters:
x (List[int]) – Input vector of occupation numbers
y (List[int]) – Output vector of occupation numbers
permanent (callable, optional) – Use another function for computing the permanent (e.g. from thewalrus)
Example
>>> box = MZI(0.2, 0.6) >>> assert np.isclose(sum([box.indist_prob([3, 0], y) ... for y in occupation_numbers(3, 2)]), 1) >>> network = box @ box @ box >> Id(1) @ box @ box @ Id(1) >>> assert np.isclose(sum([network.indist_prob([0, 1, 0, 1, 1, 1], y) ... for y in occupation_numbers(4, 6)]), 1)
- dist_prob(x, y, permanent=<function npperm>)[source]#
Evaluates probability of an optics.Diagram for input x and output y, when sending distinguishable particles.
- Parameters:
x (List[int]) – Input vector of occupation numbers
y (List[int]) – Output vector of occupation numbers
permanent (callable, optional) – Use another function for computing the permanent (e.g. from thewalrus)
Example
>>> box = MZI(1.2, 0.6) >>> assert np.isclose(sum([box.dist_prob([3, 0], y) ... for y in occupation_numbers(3, 2)]), 1) >>> network = box @ box @ box >> Id(1) @ box @ box @ Id(1) >>> assert np.isclose(sum([network.dist_prob([0, 1, 0, 1, 1, 1], y) ... for y in occupation_numbers(4, 6)]), 1)
- pdist_prob(x, y, S, permanent=<function npperm>)[source]#
Calculates the probabilities for partially distinguishable photons.
- Parameters:
x (List[int]) – Input vector of occupation numbers
y (List[int]) – Output vector of occupation numbers
S (np.array) – Symmetric matrix of mutual distinguishabilities of shape (n_photons, n_photons)
permanent (callable, optional) – Use another function for computing the permanent
Example
Check the Hong-Ou-Mandel effect:
>>> BS = BBS(0) >>> x = [1, 1] >>> S = np.eye(2) >>> assert np.isclose(BS.pdist_prob(x, x, S), 0.5) >>> S = np.ones((2, 2)) >>> assert np.isclose(BS.pdist_prob(x, x, S), 0) >>> S = lambda p: np.array([[1, p], [p, 1]]) >>> for p in [0.1*x for x in range(11)]: ... assert np.isclose(BS.pdist_prob(x, x, S(p)), 0.5 * (1 - p **2))
- cl_distribution(x)[source]#
Computes the distribution of classical light in the outputs given an input distribution x.
- Parameters:
x (List[float]) – Input vector of positive reals (intensities), expected to sum to 1. If the vector is not normalised the output will have the same normalisation factor.
Example
>>> TBS(0.25).cl_distribution([2/3, 1/3]) array([0.5, 0.5]) >>> assert np.allclose(TBS(0.25).cl_distribution([2/3, 1/3]), ... TBS(0.25).cl_distribution([1/5, 4/5])) >>> BS = TBS(0.25) >>> d = BS @ BS >> Id(1) @ BS @ Id(1) >>> d.cl_distribution([0, 1/2, 1/2, 0]) array([0.25, 0.25, 0.25, 0.25])
- indist_prob_ub(x, y)[source]#
Evaluates probability of an optics.Diagram for input x and output y, when sending distinguishable particles, excluding bunching output probabilities.
- Parameters:
x (List[int]) – Input vector of occupation numbers
y (List[int]) – Output vector of occupation numbers
Example
>>> BS = TBS(0.25) >>> d = BS @ BS >> Id(1) @ BS @ Id(1) >>> unbunch = [s for s in occupation_numbers(2, 4) if set(s)=={0,1}] >>> assert np.isclose(sum([d.indist_prob_ub([1, 1, 0, 0], y) ... for y in unbunch]), 1)