Measurements¶
All the built-in measurement instructions in Piquasso. Measurement instructions should be placed at the end of the Piquasso program.
Note
When multiple shots are specified and the evolution of the choses simulated state is possible, the measurement outcome corresponding to the last shot is used to evolve the state.
- class ParticleNumberMeasurement
Particle number measurement.
A non-Gaussian projective measurement with the probability density given by
\[p(n) = \operatorname{Tr} \left [ \rho | n \rangle \langle n | \right ]\]The generated samples are non-negative integer values corresponding to the detected photon number.
Note
When used with
GaussianState, the state is not evolved, since that would be non-Gaussian.
- class ThresholdMeasurement
Threshold measurement.
Similar to
ParticleNumberMeasurement, but only measuring whether or not the measured mode contains any photon.The generated samples contain \(0\) or \(1\), where \(0\) corresponds to no photon being detected, and \(1\) corresponds to detection of at least one photon.
- class GeneraldyneMeasurement(detection_covariance: ndarray)
General-dyne measurement.
The probability density is given by
\[p(r_m) = \frac{ \exp \left ( (r_m - r)^T \frac{1}{\sigma + \sigma_m} (r_m - r) \right ) }{ \pi^d \sqrt{ \operatorname{det} (\sigma + \sigma_m) } },\]where \(r_m \in \mathbb{C}^d\), \(\sigma\) is the covariance matrix of the current state, \(r \in \mathbb{C}^d\) is the first moment of the current state, and \(\sigma_m\) is the covariance corresponding to a non-displaced Gaussian state characterizing the general-dyne detection. Notably, the heterodyne detection would correspond to a non-displaced Gaussian state with covariance \(\sigma_m = I_{d \times d}\).
- Parameters:
detection_covariance (numpy.ndarray) – A \(2\times2\) symplectic matrix corresponding to a purely quadratic Hamiltonian.
- Raises:
InvalidParameter – When the detection covariance does not satisfy the Robertson-Schrödinger uncertainty relation.
- class HomodyneMeasurement(phi: float = 0.0, z: float = 0.0001)
Homodyne measurement.
Corresponds to measurement of the quadrature operator
\[\hat{x}_{\phi} = \cos \phi \hat{x} + \sin \phi \hat{p}\]with outcome probability density given by
\[p(x_{\phi}) = \langle x_{\phi} | \rho | x_{\phi} \rangle,\]where \(x_{\phi}\) correspond to the eigenvalues of \(\hat{x}_{\phi}\).
In optical setups, the measurement is performed by mixing the state \(\rho\) with a strong coherent state \(| \alpha \rangle\), where \(\alpha >> 1\), then subtracting the detected intensities of the two outputs. The mixing is performed with a 50:50 beamsplitter.
- class HeterodyneMeasurement
Heterodyne measurement.
The probability density is given by
\[p(x_{\phi}) = \frac{1}{\pi} \operatorname{Tr} ( \rho | \alpha \rangle \langle \alpha | ).\]In optical setups, the measurement is performed by mixing the state \(\rho\) with a vacuum state \(| 0 \rangle\), then subtracting the detected intensities of the two outputs. The mixing is performed with a 50:50 beamsplitter.
- class PostSelectPhotons(postselect_modes: Tuple[int, ...], photon_counts: Tuple[int, ...])
Post-selection on detected photon numbers.
Example usage:
with pq.Program() as program: pq.Q(all) | pq.StateVector([0, 1, 0]) * np.sqrt(0.2) pq.Q(all) | pq.StateVector([1, 1, 0]) * np.sqrt(0.3) pq.Q(all) | pq.StateVector([2, 1, 0]) * np.sqrt(0.5) pq.Q(0) | pq.Phaseshifter(np.pi) pq.Q(1, 2) | pq.Beamsplitter(np.pi / 8) pq.Q(0, 1) | pq.Beamsplitter(1.1437) pq.Q(1, 2) | pq.Beamsplitter(-np.pi / 8) pq.Q(all) | pq.PostSelectPhotons( postselect_modes=(1, 2), photon_counts=(1, 0) ) simulator = pq.PureFockSimulator(d=3, config=pq.Config(cutoff=4)) state = simulator.execute(program).state
Note
The resulting state is not normalized. To normalize it, use
normalize(). Moreover, it is a state over the remaining modes, i.e., if k modes are post-selected, then the resulting state will be defined on a system with k modes less.
- class ImperfectPostSelectPhotons(postselect_modes: Tuple[int, ...], photon_counts: Tuple[int, ...], detector_efficiency_matrix: ndarray)
Post-selection on detected photon numbers.
Example usage:
P = np.array( [ [1.0, 0.1, 0.2], [0.0, 0.9, 0.2], [0.0, 0.0, 0.6], ], ) with pq.Program() as program: pq.Q(all) | pq.StateVector([0, 1, 0]) * np.sqrt(0.2) pq.Q(all) | pq.StateVector([1, 1, 0]) * np.sqrt(0.3) pq.Q(all) | pq.StateVector([2, 1, 0]) * np.sqrt(0.5) pq.Q(0) | pq.Phaseshifter(np.pi) pq.Q(1, 2) | pq.Beamsplitter(np.pi / 8) pq.Q(0, 1) | pq.Beamsplitter(1.1437) pq.Q(1, 2) | pq.Beamsplitter(-np.pi / 8) pq.Q(all) | pq.ImperfectPostSelectPhotons( postselect_modes=(1, 2), photon_counts=(1, 0), detector_efficiency_matrix=P, ) simulator = pq.PureFockSimulator(d=3, config=pq.Config(cutoff=4)) state = simulator.execute(program).state
The detector efficiency matrix \(P\) is defined elementwise as
\[P_{n m} = p(\text{detected photon count } = n| \text{actual photon count } = m)\]Note
The resulting state is not normalized. To normalize it, use
normalize(). Moreover, it is a state over the remaining modes, i.e., if k modes are post-selected, then the resulting state will be defined on a system with k modes less._summary_