# Linear optical network with correlated photon measurement \<n\_i n\_j\>

**URL:** <https://discuss.pennylane.ai/t/linear-optical-network-with-correlated-photon-measurement-n-i-n-j/9122>\
**Category:** PennyLane Help\
**Created:** [November 25, 2025, 10:37am UTC](https://discuss.pennylane.ai/t/linear-optical-network-with-correlated-photon-measurement-n-i-n-j/9122 "2025-11-25T10:37:27Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![Daniel\_Wang](https://yyz2.discourse-cdn.com/flex012/user_avatar/discuss.pennylane.ai/daniel_wang/32/2058_2.png) [@Daniel\_Wang](https://discuss.pennylane.ai/u/Daniel_Wang)\
**Post date:** [November 25, 2025, 10:37am UTC](https://discuss.pennylane.ai/t/linear-optical-network-with-correlated-photon-measurement-n-i-n-j/9122/1 "2025-11-25T10:37:27Z")

</div>

Hello,

I am doing some code tests in pennylane:

```auto
# photonic_pennylane_pytorch.py

import torch

import torch.nn as nn

import torch.optim as optim

import pennylane as qml

import numpy as np

dev3 = qml.device(“default.gaussian”, wires=2)

@qml.qnode(dev3)
def measure_n_coherent(alpha, phi):
  qml.Squeezing(alpha, phi, wires = 0)
  
  return qml.expval(qml.NumberOperator(0))

coherent_expval = measure_n_coherent(1, np.pi / 3)

print(“Expected number of photons: {}”.format(coherent_expval))

```

The above code measures the expected photon numbers in wire 0, i.e. \<n\_0\>. I want to know if it is possible to measure \<n\_0 n\_1\> in this code or other libraries such as strawberryfields. I want to use it for some machine learning models, so the gradient should flow properly.

Thank you very much. I look forward to your help.

---

<div class="post-metadata">

**Author:** ![CatalinaAlbornoz](https://yyz2.discourse-cdn.com/flex012/user_avatar/discuss.pennylane.ai/catalinaalbornoz/32/1196_2.png) [@CatalinaAlbornoz](https://discuss.pennylane.ai/u/CatalinaAlbornoz)\
**Post date:** [November 26, 2025, 1:33am UTC](https://discuss.pennylane.ai/t/linear-optical-network-with-correlated-photon-measurement-n-i-n-j/9122/2 "2025-11-26T01:33:11Z")

</div>

Hi @Daniel_Wang, welcome back to the Forum!

I don’t think your current code would allow you to measure what you need.

The PennyLane [demo on photonic quantum computing](https://pennylane.ai/qml/demos/tutorial_photonics) may guide you on ways to make different kinds of measurements. For example the section on [measuring quadratures](https://pennylane.ai/qml/demos/tutorial_photonics#measuring-quadratures) shows you how to simulate a homodyne measurement. Note that here we use several qnodes, each with one measurement, since `default.gaussian` doesn’t support multiple measurements nor products of measurements.

I’m not entirely sure whether this is differentiable and compatible with Torch, but I think it should be. Just make sure not to use both NumPy and Torch since this is a common source for errors.

Let me know if this works for you!

---

<div class="post-metadata">

**Author:** ![Daniel\_Wang](https://yyz2.discourse-cdn.com/flex012/user_avatar/discuss.pennylane.ai/daniel_wang/32/2058_2.png) [@Daniel\_Wang](https://discuss.pennylane.ai/u/Daniel_Wang)\
**Post date:** [November 26, 2025, 3:09pm UTC](https://discuss.pennylane.ai/t/linear-optical-network-with-correlated-photon-measurement-n-i-n-j/9122/3 "2025-11-26T15:09:35Z")

</div>

Thanks for your clarification. If default.gaussian does not work itself, what device should I use then? I went through the mentioned demo, it does not include what I want. Could you guide me into how to measure products of the number operators? A brief code would be best.

Thank you very much!

---

<div class="post-metadata">

**Author:** ![CatalinaAlbornoz](https://yyz2.discourse-cdn.com/flex012/user_avatar/discuss.pennylane.ai/catalinaalbornoz/32/1196_2.png) [@CatalinaAlbornoz](https://discuss.pennylane.ai/u/CatalinaAlbornoz)\
**Post date:** [November 27, 2025, 3:11pm UTC](https://discuss.pennylane.ai/t/linear-optical-network-with-correlated-photon-measurement-n-i-n-j/9122/4 "2025-11-27T15:11:07Z")

</div>

Hi @Daniel_Wang ,

You can use the [`'strawberryfields.gaussian'` device](https://pennylane.ai/devices/strawberryfields-gaussian). However, this requires the [`pennylane-sf` plugin](https://docs.pennylane.ai/projects/strawberryfields/en/latest/), which is only supported up to PennyLane version v0.29. You can install it with

```auto
pip install pennylane-sf scipy==1.13.1

```

Once you have you environment with the `pennylane-sf` plugin, you can write your code and use [`qml.TensorN()`](https://docs.pennylane.ai/en/stable/code/api/pennylane.TensorN.html) as your observable. This computes the tensor product of the NumberOperator acting on different wires.

The code below shows an example of how to use the `'strawberryfields.gaussian'` device with the `qml.TensorN` observable.

```auto
import pennylane as qml

dev = qml.device('strawberryfields.gaussian', wires=2)

@qml.qnode(dev)
def quantum_function(x, theta):
    qml.Displacement(x, 0, wires=0)
    qml.Beamsplitter(theta, 0, wires=[0, 1])
    return qml.expval(qml.TensorN(wires=[0, 1]))

quantum_function(1., 0.543)

```

I hope this helps!

---

<div class="post-metadata">

**Author:** ![Daniel\_Wang](https://yyz2.discourse-cdn.com/flex012/user_avatar/discuss.pennylane.ai/daniel_wang/32/2058_2.png) [@Daniel\_Wang](https://discuss.pennylane.ai/u/Daniel_Wang)\
**Post date:** [November 27, 2025, 8:15pm UTC](https://discuss.pennylane.ai/t/linear-optical-network-with-correlated-photon-measurement-n-i-n-j/9122/5 "2025-11-27T20:15:01Z")

</div>

Hello Catalina,

Thanks a lot for the example code. I tried to run it on google colab, but I got the following error:

Collecting pennylane-sf  
Downloading PennyLane\_SF-0.29.1-py3-none-any.whl.metadata (7.0 kB)  
Collecting scipy==1.13.1  
Downloading scipy-1.13.1-cp312-cp312-manylinux\_2\_17\_x86\_64.manylinux2014\_x86\_64.whl.metadata (60 kB)  
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 60.6/60.6 kB 1.6 MB/s eta 0:00:00  
Requirement already satisfied: numpy\<2.3,\>=1.22.4 in /usr/local/lib/python3.12/dist-packages (from scipy==1.13.1) (2.0.2)  
Collecting strawberryfields\>=0.22 (from pennylane-sf)  
Downloading StrawberryFields-0.23.0-py3-none-any.whl.metadata (7.6 kB)  
Collecting pennylane\<0.30,\>=0.19 (from pennylane-sf)  
Downloading PennyLane-0.29.1-py3-none-any.whl.metadata (8.7 kB)  
Collecting numpy\<2.3,\>=1.22.4 (from scipy==1.13.1)  
Downloading numpy-1.23.5.tar.gz (10.7 MB)  
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 10.7/10.7 MB 54.1 MB/s eta 0:00:00  
Installing build dependencies … done  
**error** : **subprocess-exited-with-error**

× Getting requirements to build wheel did not run successfully.  
│ exit code: **1**  
╰─\> See above for output.

**note** : This error originates from a subprocess, and is likely not a problem with pip.  
Getting requirements to build wheel … error  
**error** : **subprocess-exited-with-error**

× Getting requirements to build wheel did not run successfully.  
│ exit code: **1**  
╰─\> See above for output.

**note** : This error originates from a subprocess, and is likely not a problem with pip.

I dont understand why this happens. Do you have any idea?

---

<div class="post-metadata">

**Author:** ![CatalinaAlbornoz](https://yyz2.discourse-cdn.com/flex012/user_avatar/discuss.pennylane.ai/catalinaalbornoz/32/1196_2.png) [@CatalinaAlbornoz](https://discuss.pennylane.ai/u/CatalinaAlbornoz)\
**Post date:** [November 29, 2025, 12:47am UTC](https://discuss.pennylane.ai/t/linear-optical-network-with-correlated-photon-measurement-n-i-n-j/9122/7 "2025-11-29T00:47:25Z")

</div>

Hi @Daniel_Wang ,

I can reproduce your error in Google Colab. I’m not exactly sure what the error is but it seems like a version mismatch in some set of packages or Python itself. The easiest solution might be to create a local Conda environment with the requirements specified in the [GitHub](https://github.com/XanaduAI/strawberryfields/blob/master/requirements.txt).

If this doesn’t work for you let me know and I can check the versions I have in the environment where I made this test. Note that only Python 3.10 and below are supported, so my guess is that this is the main source for the error.

Let me know if this works!

---

<div class="post-metadata">

**Author:** ![Daniel\_Wang](https://yyz2.discourse-cdn.com/flex012/user_avatar/discuss.pennylane.ai/daniel_wang/32/2058_2.png) [@Daniel\_Wang](https://discuss.pennylane.ai/u/Daniel_Wang)\
**Post date:** [November 29, 2025, 11:31am UTC](https://discuss.pennylane.ai/t/linear-optical-network-with-correlated-photon-measurement-n-i-n-j/9122/8 "2025-11-29T11:31:38Z")

</div>

ok. Thanks for the advice. I can already run this code locally! My another question is:

I tried to run:

```auto

import pennylane as qml

dev = qml.device('strawberryfields.gaussian', wires=2)

@qml.qnode(dev)

def quantum_function(x, theta):

    qml.Displacement(x, 0, wires=0)

    qml.Beamsplitter(theta, 0, wires=[0, 1])

    return [qml.expval(qml.TensorN(wires=[0, 1])), qml.expval(qml.TensorN(wires=0))]

print(quantum_function(1., 0.543))

```

But I got this error; this is a bit surprising; could you also help me with this:

```auto
File “/home/shuteng/miniconda3/envs/photonic/lib/python3.9/site-packages/pennylane/\_device.py”, line 772, in batch_transform
circuits, hamiltonian_fn = qml.transforms.split_non_commuting(circuit)
File “/home/shuteng/miniconda3/envs/photonic/lib/python3.9/site-packages/pennylane/transforms/batch_transform.py”, line 331, in **call**
return self.\_tape_wrapper(\*targs, \*\*tkwargs)(qnode)
File “/home/shuteng/miniconda3/envs/photonic/lib/python3.9/site-packages/pennylane/transforms/batch_transform.py”, line 421, in 
return lambda tape: self.construct(tape, \*targs, \*\*tkwargs)
File “/home/shuteng/miniconda3/envs/photonic/lib/python3.9/site-packages/pennylane/transforms/batch_transform.py”, line 403, in construct
tapes, processing_fn = self.transform_fn(tape, \*args, \*\*kwargs)
File “/home/shuteng/miniconda3/envs/photonic/lib/python3.9/site-packages/pennylane/transforms/split_non_commuting.py”, line 158, in split_non_commuting
groups, group_coeffs = qml.pauli.group_observables(obs_list, range(len(obs_list)))
File “/home/shuteng/miniconda3/envs/photonic/lib/python3.9/site-packages/pennylane/pauli/grouping/group_observables.py”, line 227, in group_observables
if qml.math.shape(coefficients)\[0\] != len(observables):
IndexError: tuple index out of range

```

---

<div class="post-metadata">

**Author:** ![CatalinaAlbornoz](https://yyz2.discourse-cdn.com/flex012/user_avatar/discuss.pennylane.ai/catalinaalbornoz/32/1196_2.png) [@CatalinaAlbornoz](https://discuss.pennylane.ai/u/CatalinaAlbornoz)\
**Post date:** [December 2, 2025, 10:26pm UTC](https://discuss.pennylane.ai/t/linear-optical-network-with-correlated-photon-measurement-n-i-n-j/9122/9 "2025-12-02T22:26:08Z")

</div>

Hi @Daniel_Wang ,

I think these two observables may not commute so this may be why you’re getting an error. I think it might be better in that case to have each measurement being returned by separate qnodes. E.g.:

```auto
import pennylane as qml

dev = qml.device('strawberryfields.gaussian', wires=2)

@qml.qnode(dev)
def quantum_function1(x, theta):

    qml.Displacement(x, 0, wires=0)
    qml.Beamsplitter(theta, 0, wires=[0, 1])
    
    return qml.expval(qml.TensorN(wires=[0, 1]))

@qml.qnode(dev)
def quantum_function2(x, theta):

    qml.Displacement(x, 0, wires=0)
    qml.Beamsplitter(theta, 0, wires=[0, 1])
    
    return qml.expval(qml.TensorN(wires=0))

print(quantum_function1(1., 0.543))
print(quantum_function2(1., 0.543))

```

---

<div class="post-metadata">

**Author:** ![Daniel\_Wang](https://yyz2.discourse-cdn.com/flex012/user_avatar/discuss.pennylane.ai/daniel_wang/32/2058_2.png) [@Daniel\_Wang](https://discuss.pennylane.ai/u/Daniel_Wang)\
**Post date:** [December 3, 2025, 8:49am UTC](https://discuss.pennylane.ai/t/linear-optical-network-with-correlated-photon-measurement-n-i-n-j/9122/10 "2025-12-03T08:49:29Z")

</div>

Hi Catalina,

Thanks for the code and the solution. Yes, I also tried it and it indeed works. However, it is quite slow.

In my project, I want to use the correlated PNR measurements (local to global) which also results in exponentially growing dimension of the output. Therefore, it is better that there is an efficient way to return this in a single function or a single call. Otherwise, it is incredibly slow (with my tests).

Do you know if there is something like this provided by Pennylane?

Thank u,

Shuteng

---

<div class="post-metadata">

**Author:** ![CatalinaAlbornoz](https://yyz2.discourse-cdn.com/flex012/user_avatar/discuss.pennylane.ai/catalinaalbornoz/32/1196_2.png) [@CatalinaAlbornoz](https://discuss.pennylane.ai/u/CatalinaAlbornoz)\
**Post date:** [December 4, 2025, 11:47pm UTC](https://discuss.pennylane.ai/t/linear-optical-network-with-correlated-photon-measurement-n-i-n-j/9122/11 "2025-12-04T23:47:04Z")

</div>

Hi @Daniel_Wang ,

Unfortunately I don’t know of any faster way to do this. Do you know why or where the slowdown is happening? You could try to use a profiler like Snakeviz to identify the bottleneck. Maybe this could give us some ideas on what to change.

---

<div class="post-metadata">

**Author:** ![ziofil](https://yyz2.discourse-cdn.com/flex012/user_avatar/discuss.pennylane.ai/ziofil/32/693_2.png) [@ziofil](https://discuss.pennylane.ai/u/ziofil)\
**Post date:** [December 10, 2025, 8:32pm UTC](https://discuss.pennylane.ai/t/linear-optical-network-with-correlated-photon-measurement-n-i-n-j/9122/12 "2025-12-10T20:32:24Z")

</div>

It looks like this is MrMustard’s territory? [GitHub - XanaduAI/MrMustard: A differentiable bridge between phase space and Fock space](https://github.com/XanaduAI/Mrmustard)
