.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "examples/devices/example_004_beamsplitter.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_examples_devices_example_004_beamsplitter.py: Ideal Beam-Splitter Example =========================== This example demonstrates the use of the :class:`~symop.devices.models.beamsplitters.beamsplitter.BeamSplitter` model, we also make use of :class:`~symop.devices.models.sources.number_state_source.NumberStateSource` to generate the state. .. GENERATED FROM PYTHON SOURCE LINES 11-22 .. code-block:: Python from __future__ import annotations import numpy as np from symop.devices.models import BeamSplitter, NumberStateSource from symop.modes.labels import Path, Polarization from symop.modes.envelopes import GaussianEnvelope from symop.polynomial.state.ket import KetPolyState # Visualization Package import symop.viz as VI .. GENERATED FROM PYTHON SOURCE LINES 23-26 **Setup** Set up mode labels for sources and beamsplitter (50/50) .. GENERATED FROM PYTHON SOURCE LINES 26-41 .. code-block:: Python src_a = NumberStateSource( envelope=GaussianEnvelope(omega0=100.0, sigma=50.0, tau=0.0), polarization=Polarization.H(), n=1, ) src_b = NumberStateSource( envelope=GaussianEnvelope(omega0=100.0, sigma=50.0, tau=0.0), polarization=Polarization.H(), n=1, ) bs = BeamSplitter(theta=np.pi / 4, phi_r=0) .. GENERATED FROM PYTHON SOURCE LINES 42-45 **1) Generate the states** - Generate vacuum states for the sources to populate .. GENERATED FROM PYTHON SOURCE LINES 45-51 .. code-block:: Python vac = KetPolyState.vacuum() state_a = src_a(vac, ports={"out": Path("src_a_out")}).with_label("in_A") state_b = src_b(vac, ports={"out": Path("src_b_out")}).with_label("in_B") .. GENERATED FROM PYTHON SOURCE LINES 52-56 **2) Interfere the two states** - Join the states - Interfere them .. GENERATED FROM PYTHON SOURCE LINES 56-69 .. code-block:: Python state_joint = state_a.join(state_b).with_label("joint") state_interfered = bs( state_joint, ports={ "in0": Path("src_a_out"), "in1": Path("src_b_out"), "out0": Path("bs_out0"), "out1": Path("bs_out1"), }, ).with_label("interfered") .. GENERATED FROM PYTHON SOURCE LINES 70-71 **2a) Inspect the states** .. GENERATED FROM PYTHON SOURCE LINES 71-73 .. code-block:: Python VI.display_many(state_a, state_b, state_joint, state_interfered) .. raw:: html
2026-04-20T22:50:34.084733 image/svg+xml Matplotlib v3.10.8, https://matplotlib.org/
2026-04-20T22:50:34.098339 image/svg+xml Matplotlib v3.10.8, https://matplotlib.org/
2026-04-20T22:50:34.113643 image/svg+xml Matplotlib v3.10.8, https://matplotlib.org/
2026-04-20T22:50:34.141655 image/svg+xml Matplotlib v3.10.8, https://matplotlib.org/


.. GENERATED FROM PYTHON SOURCE LINES 74-94 *Why does the output contain several terms?* The beamsplitter acts linearly on each input creation operator. Since the joint input state contains one photon in each input path, the output is obtained by expanding the product of two linear combinations of output-mode operators. This produces amplitudes for all possible two-photon output configurations: - both photons in output path 0, - one photon in each output path, - both photons in output path 1. These terms are amplitudes, not measurement probabilities. The actual detection statistics depend on the overlaps between the output modes. When the two inputs are fully indistinguishable (same envelope and same polarization), interference can cancel coincidence contributions and enhance bunching, as in the Hong-Ou-Mandel effect. .. GENERATED FROM PYTHON SOURCE LINES 96-101 **3) Interfering just one pulse with vacuum** Beam splitter can also work without the counterpart provided In the example below, we interfere the photon in path ``src_a_out`` with vacuum in the other port .. GENERATED FROM PYTHON SOURCE LINES 101-116 .. code-block:: Python state_interfered_single = bs( state_a, ports={ "in0": Path("src_a_out"), "in1": Path("any"), "out0": Path("bs_out0"), "out1": Path("bs_out1"), }, ).with_label("interfered_single") VI.display_many(state_a, state_interfered_single) .. raw:: html
2026-04-20T22:50:34.174835 image/svg+xml Matplotlib v3.10.8, https://matplotlib.org/
2026-04-20T22:50:34.193856 image/svg+xml Matplotlib v3.10.8, https://matplotlib.org/


.. GENERATED FROM PYTHON SOURCE LINES 117-121 **4) Interfere the two states** - Join the states - Interfere them .. GENERATED FROM PYTHON SOURCE LINES 121-135 .. code-block:: Python state_joint_dense = state_joint.to_density() state_interfered_dense = bs( state_joint_dense, ports={ "in0": Path("src_a_out"), "in1": Path("src_b_out"), "out0": Path("bs_out0"), "out1": Path("bs_out1"), }, ).with_label("interfered") VI.display_many(state_joint_dense, state_interfered_dense) .. raw:: html
2026-04-20T22:50:34.224167 image/svg+xml Matplotlib v3.10.8, https://matplotlib.org/
2026-04-20T22:50:34.356754 image/svg+xml Matplotlib v3.10.8, https://matplotlib.org/


.. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 0.435 seconds) .. _sphx_glr_download_examples_devices_example_004_beamsplitter.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: example_004_beamsplitter.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: example_004_beamsplitter.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: example_004_beamsplitter.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_