# Unexpected error with number-conserving MPO when result is zero

**URL:** <https://itensor.discourse.group/t/unexpected-error-with-number-conserving-mpo-when-result-is-zero/2521>\
**Category:** ITensor Julia Questions\
**Tags:** julia, mpo, qn\
**Created:** [November 1, 2025, 8:22am UTC](https://itensor.discourse.group/t/unexpected-error-with-number-conserving-mpo-when-result-is-zero/2521 "2025-11-01T08:22:54Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![phx](https://yyz2.discourse-cdn.com/free1/user_avatar/itensor.discourse.group/phx/32/673_2.png) [@phx](https://itensor.discourse.group/u/phx)\
**Post date:** [November 1, 2025, 8:22am UTC](https://itensor.discourse.group/t/unexpected-error-with-number-conserving-mpo-when-result-is-zero/2521/1 "2025-11-01T08:22:54Z")

</div>

The following code gives an error which I don’t understand.  
I set up two different states with number conservation active:

```julia
using ITensors, ITensorMPS
N = 3
s = siteinds("Electron", N; conserve_nf=true)
x = MPS(s, ["Emp", "Emp", "Emp"])
y = MPS(s, ["Emp", "Emp", "Up"])
ops = OpSum()
ops += "c†↑", 1, "c↑", 3
A = MPO(ops, s)

```

Now, if I run

```julia
apply(A, x)

```

I get the following error:

```julia
ERROR: ArgumentError: collection must be non-empty
Stacktrace:
  [1] first
    @ ./abstractarray.jl:473 [inlined]
  [2] eigen(T::LinearAlgebra.Hermitian{…}; min_blockdim::Nothing, mindim::Int64, maxdim::Int64, cutoff::Float64, use_absolute_cutoff::Nothing, use_relative_cutoff::Nothing)
    @ NDTensors /opt/julia/packages/NDTensors/Q9Zpu/src/blocksparse/linearalgebra.jl:233
  [3] eigen(A::ITensor, Linds::Vector{…}, Rinds::Vector{…}; mindim::Int64, maxdim::Int64, cutoff::Float64, use_absolute_cutoff::Nothing, use_relative_cutoff::Nothing, ishermitian::Bool, tags::ITensors.TagSets.GenericTagSet{…}, lefttags::Nothing, righttags::Nothing, plev::Nothing, leftplev::Nothing, rightplev::Nothing)
    @ ITensors /opt/julia/packages/ITensors/AOPBm/src/tensor_operations/matrix_decomposition.jl:378
  [4] contract(::NDTensors.BackendSelection.Algorithm{…}, A::MPO, ψ::MPS; cutoff::Float64, maxdim::Int64, mindim::Int64, normalize::Bool, kwargs::@Kwargs{})
    @ ITensorMPS /opt/julia/packages/ITensorMPS/3OORN/src/mpo.jl:743
  [5] contract(::NDTensors.BackendSelection.Algorithm{:densitymatrix, @NamedTuple{}}, A::MPO, ψ::MPS)
    @ ITensorMPS /opt/julia/packages/ITensorMPS/3OORN/src/mpo.jl:692
  [6] product(alg::NDTensors.BackendSelection.Algorithm{:densitymatrix, @NamedTuple{}}, A::MPO, ψ::MPS; kwargs::@Kwargs{})
    @ ITensorMPS /opt/julia/packages/ITensorMPS/3OORN/src/mpo.jl:605
  [7] product
    @ /opt/julia/packages/ITensorMPS/3OORN/src/mpo.jl:604 [inlined]
  [8] #apply#453
    @ /opt/julia/packages/ITensorMPS/3OORN/src/mpo.jl:601 [inlined]
  [9] product(A::MPO, ψ::MPS)
    @ ITensorMPS /opt/julia/packages/ITensorMPS/3OORN/src/mpo.jl:600
 [10] top-level scope
    @ REPL[42]:1

```

while the following

```julia
apply(A, y)

```

works fine. I guess that the difference in the behaviour lies in the fact that Ay = 0 whereas Ax \neq 0, but why does it throw an error? The c\_1^\dagger c\_3 operator preserves the number of particles so applying it to x or y shouldn’t be an issue.

When QNs are not active, both `apply(A,x)` and `apply(A,y)` throw no errors, with \lVert Ay\rVert = 0 as expected.

---

<div class="post-metadata">

**Author:** ![miles](https://yyz2.discourse-cdn.com/free1/user_avatar/itensor.discourse.group/miles/32/6_2.png) [@miles](https://itensor.discourse.group/u/miles)\
**Post date:** [November 1, 2025, 3:42pm UTC](https://itensor.discourse.group/t/unexpected-error-with-number-conserving-mpo-when-result-is-zero/2521/2 "2025-11-01T15:42:37Z")

</div>

On our side, we should improve this error message.

For your application, when your calculation results in a state with zero norm, further down in our system, a tensor with no blocks getting passed into `eigen`. In that situation, we don’t have a good way, even mathematically, to know or guess what the QN flux of the result should be. (We could also in the future add a system to ‘hint’ the QN of the result to work around cases like this but probably that’s too fancy.)

Do you need to be able to do `apply(A,y)` when the result will definitely end up being zero? I think at an outer level, if this is happening due to the QN sector of `y`, you could detect this by calling `flux(y)` and seeing if it’s even possible for Ay to be non-zero.

---

<div class="post-metadata">

**Author:** ![phx](https://yyz2.discourse-cdn.com/free1/user_avatar/itensor.discourse.group/phx/32/673_2.png) [@phx](https://itensor.discourse.group/u/phx)\
**Post date:** [November 1, 2025, 7:02pm UTC](https://itensor.discourse.group/t/unexpected-error-with-number-conserving-mpo-when-result-is-zero/2521/3 "2025-11-01T19:02:55Z")

</div>

I see. It does make sense that the zero vector behaves as you describe, unfortunately.

My goal was to replicate ITensor’s `correlation_function` method for an MPS that does not represent a pure state but a mixed one, as in [“Eigen currently only supports block diagonal matrices.” when applying an MPO to a MPS with QNs](https://itensor.discourse.group/t/eigen-currently-only-supports-block-diagonal-matrices-when-applying-an-mpo-to-a-mps-with-qns/2520). For this kind of object I defined custom methods to compute expectation values, using the trace and such instead of the usual inner product. The correlation matrix would be defined using these new methods.

Since I’m dealing with fermions, I use the OpSum → MPO method to construct the observable so that I don’t have to put in Jordan-Wigner strings by hand. That’s why I’m using `apply` in this situation.
