# Are Jordan Wigner strings handled in apply?

**URL:** https://itensor.discourse.group/t/are-jordan-wigner-strings-handled-in-apply/2266
**Category:** ITensor Julia Questions
**Created:** [February 26, 2025, 1:27pm UTC](https://itensor.discourse.group/t/are-jordan-wigner-strings-handled-in-apply/2266 "2025-02-26T13:27:38Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![DavidStrachan1](https://yyz2.discourse-cdn.com/free1/user_avatar/itensor.discourse.group/davidstrachan1/32/165_2.png) [@DavidStrachan1](https://itensor.discourse.group/u/DavidStrachan1)
#### Post date: [February 26, 2025, 1:27pm UTC](https://itensor.discourse.group/t/are-jordan-wigner-strings-handled-in-apply/2266/1 "2025-02-26T13:27:38Z")

</div>

Hi,

Just a quick question on fermionic/electronic sitetypes and where the JW strings are handled automatically. Looking at [Fermion site-type operator `c`: `inner()` indicates `c` on different sites commute - #3 by christopherdavidwhit](https://itensor.discourse.group/t/fermion-site-type-operator-c-inner-indicates-c-on-different-sites-commute/1851/3) and [Proper way to construct fermion gates](https://itensor.discourse.group/t/proper-way-to-construct-fermion-gates/172), it’s unclear if Jordan Wigner strings are handled automatically in apply.

EDIT:  
From some testing, it seems to depend on whether QN conservation is used. Here’s a minimal example showing this, where I create a state of two maximally entangled pairs. I will denote fermionic creation operators with c’s, bosonic creation operators as a’s, and pauli Z operators as F’s.

\ket{\psi} =\frac{1}{2}(\hat{c}^{\dag}\_{2}+\hat{c}^{\dag}\_{4})(\hat{c}^{\dag}\_{1}+\hat{c}^{\dag}\_{3})\ket{\textrm{vac}}, \\ =\frac{1}{2} (F\_{1}\hat{a}^{\dag}\_{2}+F\_{1}F\_{2}F\_{3}\hat{a}^{\dag}\_{4})(\hat{a}^{\dag}\_{1}+F\_{1}F\_{2}\hat{a}^{\dag}\_{3})\ket{\textrm{vac}}, \\ = \frac{1}{2}(F\_{1}\hat{a}^{\dag}\_{2}\hat{a}^{\dag}\_{1}+\hat{a}^{\dag}\_{2}\hat{a}^{\dag}\_{3}+F\_{1}\hat{a}^{\dag}\_{4}\hat{a}^{\dag}\_{1}+F\_{3}\hat{a}^{\dag}\_{4}\hat{a}^{\dag}\_{3})\ket{\textrm{vac}} ,\\ = \frac{1}{2}(-\ket{1100}+\ket{0110}-\ket{1001}-\ket{0011}).

If the operators are applied in the opposite order, the answer should be

\ket{\psi} =\frac{1}{2} (\hat{a}^{\dag}\_{1}+F\_{1}F\_{2}\hat{a}^{\dag}\_{3})(F\_{1}\hat{a}^{\dag}\_{2}+F\_{1}F\_{2}F\_{3}\hat{a}^{\dag}\_{4})\ket{\textrm{vac}}, \\ = \frac{1}{2}(\ket{1100}-\ket{0110}+\ket{1001}+\ket{0011}),

i.e. minus the answer of the opposite ordering.

Here is the code to test whether the F factors are included.

```auto
N = 4
s = siteinds("Fermion",N,conserve_qns = true)
cdag = [op(s,"Cdag",i) for i in 1:N]
Id = [op(s,"Id",i) for i in 1:N]
psi = MPS(ComplexF64,s,"0")
gate1 = (cdag[1]*Id[3] + Id[1]*cdag[3])/sqrt(2)
gate2 = (cdag[2]*Id[4] + Id[2]*cdag[4])/sqrt(2)
psi = apply(gate1,psi)
psi = apply(gate2,psi)
@show(psi[1]*psi[2]*psi[3]*psi[4])

```

If conserve\_qns = false, the result is the state with no minus signs (i.e the c operators are treated bosonically) either way the operators are applied. If conserve\_qns=true, the answer is strange. If gate1 is applied first and then gate2, the answer is

\ket{\psi}= \frac{1}{2}(\ket{1100}+\ket{0110}+\ket{1001}-\ket{0011}),

which is wrong. If gate2 is applied first and then gate1, the answer is

\ket{\psi}= \frac{1}{2}(\ket{1100}-\ket{0110}+\ket{1001}+\ket{0011}),

which is as expected. If you could help clear up the confusion for me that would be great!

---

<div class="post-metadata">

### Author: ![ryanlevy](https://yyz2.discourse-cdn.com/free1/user_avatar/itensor.discourse.group/ryanlevy/32/150_2.png) [@ryanlevy](https://itensor.discourse.group/u/ryanlevy)
#### Post date: [March 5, 2025, 7:16pm UTC](https://itensor.discourse.group/t/are-jordan-wigner-strings-handled-in-apply/2266/2 "2025-03-05T19:16:47Z")

</div>

I think product states can sometimes be tricky to look at. I will say that `apply` is using swap gates to move sites to be neighbors for two site gates, and so this can sometimes get the signs right.

But here is my explanatory example:

```julia
julia> using ITensors,ITensorMPS
       s = siteinds("Electron",10; conserve_qns=true);
       state = [isodd(n) ? "Up" : "Dn" for n in 1:length(s)]
       psi0 = random_mps(s, state; linkdims=10);

julia> correlation_matrix(psi0,"Sz","Sz")[2,5]
-0.008653137186117061

julia> inner(psi0,apply(ops([("Sz",2),("Sz",5)],s),psi0))
-0.008653137186117061

julia> correlation_matrix(psi0,"Ntot * Sz","Nup")[2,5] # these don't commute
-0.007789870264149597

julia> inner(psi0,apply(ops([("Ntot * Sz",2),("Nup",5)],s),psi0))
-0.0077898702641496205

```

Things _without_ JW strings work just fine, however let’s do some hops:

```julia
julia> os = OpSum()
       os += "Cdagup",2,"Cup",5
       O = MPO(os,s);

julia> inner(psi0',O,psi0) # this takes care of strings
0.01640983389785411

julia> correlation_matrix(psi0,"Cdagup","Cup")[2,5] # also takes care of strings
0.01640983389785412

julia> inner(psi0,apply(ops([("Cdagup",2),("Cup",5)],s),psi0)) #!! Don't do this
0.0583564218628752

```

where we see the strings are not being handled correctly, and if we insert them

```julia
julia> inner(psi0,apply(ops([("Cdagup * F",2),("F",3),("F",4),("Cup",5)],s),psi0))
0.016409833897854137

```

it checks out up to some numerical noise.

* * *

Using odd number of fermion strings will not be handled automatically anywhere

> **examples:**
>
> ```julia
> julia>
> os = OpSum()
> os += "Cdagup",2
> O = MPO(os,s);
> ERROR: Parity-odd fermionic terms not yet supported by OpSum to MPO conversion
> # ...
> 
> ```
> 
> and
> 
> ```julia
> julia> left = apply(op("Cup",s[2]),psi0)
> right = apply(op("Cup",s[5]),psi0)
> inner(left,right)
> 0.05835642186287519
> 
> ```
> 
> and with strings
> 
> ```julia
> julia> left = apply(ops([("F",1),("Cup",2)],s),psi0)
> right = apply(ops([("F",1),("F",2),("F",3),("F",4),("Cup",5)],s),psi0)
> inner(left,right)
> 0.016409833897854116
> 
> ```

Note that ITensors is being rewritten and future versions may not have this issue

---

<div class="post-metadata">

### Author: ![ryanlevy](https://yyz2.discourse-cdn.com/free1/user_avatar/itensor.discourse.group/ryanlevy/32/150_2.png) [@ryanlevy](https://itensor.discourse.group/u/ryanlevy)
#### Post date: [March 5, 2025, 7:22pm UTC](https://itensor.discourse.group/t/are-jordan-wigner-strings-handled-in-apply/2266/3 "2025-03-05T19:22:18Z")

</div>

To show how `apply` can get the signs right, lets say you have a two site gate:

```julia
julia> O = op("Cdagup * F",s[2])*op("Cup",s[5]); # this is a ord=4 ITensor

julia> inner(psi0,apply(O,psi0))
0.01640983389785411

```

Here because the internals are using swap gates we didn’t have to insert more `F` strings, but we did have to include an `F` with the `Cdagup`

---

<div class="post-metadata">

### Author: ![DavidStrachan1](https://yyz2.discourse-cdn.com/free1/user_avatar/itensor.discourse.group/davidstrachan1/32/165_2.png) [@DavidStrachan1](https://itensor.discourse.group/u/DavidStrachan1)
#### Post date: [April 1, 2025, 1:07pm UTC](https://itensor.discourse.group/t/are-jordan-wigner-strings-handled-in-apply/2266/4 "2025-04-01T13:07:47Z")

</div>

Thankyou for the response!
