# apply MPO to MPS that changes quantum number

**URL:** <https://itensor.discourse.group/t/apply-mpo-to-mps-that-changes-quantum-number/143>\
**Category:** ITensor Julia Questions\
**Tags:** julia, mpo, qn\
**Created:** [May 14, 2022, 5:36pm UTC](https://itensor.discourse.group/t/apply-mpo-to-mps-that-changes-quantum-number/143 "2022-05-14T17:36:37Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![Shengtao](https://avatars.discourse-cdn.com/v4/letter/s/b19c9b/32.png) [@Shengtao](https://itensor.discourse.group/u/Shengtao)\
**Post date:** [May 14, 2022, 5:36pm UTC](https://itensor.discourse.group/t/apply-mpo-to-mps-that-changes-quantum-number/143/1 "2022-05-14T17:36:37Z")

</div>

Hi Miles and Matt,  
I would like to construct an MPO that has a definite change of quantum number (e.g. a sum of C^dag\_i C^dag\_j terms) and apply it to an MPS that has this quantum number. One way I can do it is change MPS to dense which removes all quantum numbers and makes subsequent calculations very slow. Is there a better way to do this currently?

Best,  
Shengtao

---

<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:** [May 14, 2022, 5:57pm UTC](https://itensor.discourse.group/t/apply-mpo-to-mps-that-changes-quantum-number/143/2 "2022-05-14T17:57:56Z")

</div>

Hi Shengtao, thanks for the question. If the MPO causes a definite change to the quantum number, then it should be possible to represent it with block-sparse or QN ITensors and not need to pass to dense tensors. Did you try making it using our QN system and did you run into an error?

---

<div class="post-metadata">

**Author:** ![Shengtao](https://avatars.discourse-cdn.com/v4/letter/s/b19c9b/32.png) [@Shengtao](https://itensor.discourse.group/u/Shengtao)\
**Post date:** [May 14, 2022, 10:51pm UTC](https://itensor.discourse.group/t/apply-mpo-to-mps-that-changes-quantum-number/143/3 "2022-05-14T22:51:41Z")

</div>

Hi Miles, thanks for the quick reply! I was doing it in the standard way using MPO(), here is a minimal example of it:

```auto
using ITensors

N = 2
sites=siteinds("Electron",N,conserve_qns=true)
psi=productMPS(sites,["Emp" for i=1:N])
ampo=OpSum()
ampo+="Cdagup",1,"Cdagdn",2
cdagmpo=MPO(ampo,sites)

```

On the last line it reports: ERROR: No block found with QN equal to QN((“Nf”,-2,-1),(“Sz”,0)). Is there a way to make this MPO and apply it to psi without removing the QNs?

---

<div class="post-metadata">

**Author:** ![mtfishman](https://yyz2.discourse-cdn.com/free1/user_avatar/itensor.discourse.group/mtfishman/32/11_2.png) [@mtfishman](https://itensor.discourse.group/u/mtfishman)\
**Post date:** [May 16, 2022, 2:05pm UTC](https://itensor.discourse.group/t/apply-mpo-to-mps-that-changes-quantum-number/143/4 "2022-05-16T14:05:05Z")

</div>

Hi Shengtao,

Unfortunately it is a known issue that the OpSum to MPO constructor doesn’t work when the MPO has nonzero flux (in principle it could, but we haven’t gotten around to implementing it).

An alternative it to make the MPO manually, which isn’t too hard for this case. For example:

```julia
using ITensors

function single_site_op(sites, which_op, j)
  left_ops = "Id"
  right_ops = "Id"
  if has_fermion_string(which_op, sites[j])
    left_ops = "F"
  end
  ops = [n < j ? left_ops : (n > j ? right_ops : which_op) for n in 1:length(sites)]
  return [op(ops[n], sites[n]) for n in 1:length(sites)]
end

s = siteinds("Electron", 4; conserve_qns=true)

Cdagup1 = single_site_op(s, "Cdagup", 1)
Cdagdn2 = single_site_op(s, "Cdagdn", 2)
Cdag = MPO([apply(o1, o2) for (o1, o2) in zip(Cdagup1, Cdagdn2)])
@show flux(Cdag)

```

However, please double check that this gives the correct MPO, I haven’t thoroughly tested it.

---

<div class="post-metadata">

**Author:** ![Shengtao](https://avatars.discourse-cdn.com/v4/letter/s/b19c9b/32.png) [@Shengtao](https://itensor.discourse.group/u/Shengtao)\
**Post date:** [May 17, 2022, 4:52am UTC](https://itensor.discourse.group/t/apply-mpo-to-mps-that-changes-quantum-number/143/5 "2022-05-17T04:52:39Z")

</div>

Hi Matt,  
Thanks and this works! Now I try to build on this and make an MPO for a sum of two CdagupCdagdn terms:

```auto
using ITensors

function single_site_op(sites, which_op, j)
  left_ops = "Id"
  right_ops = "Id"
  if has_fermion_string(which_op, sites[j])
    left_ops = "F"
  end
  ops = [n < j ? left_ops : (n > j ? right_ops : which_op) for n in 1:length(sites)]
  return [op(ops[n], sites[n]) for n in 1:length(sites)]
end

s = siteinds("Electron", 4; conserve_qns=true)

Cdagup1 = single_site_op(s, "Cdagup", 1)
Cdagdn2 = single_site_op(s, "Cdagdn", 2)
Cdagup3 = single_site_op(s, "Cdagup", 3)
Cdagdn4 = single_site_op(s, "Cdagdn", 4)
Cdagpt1 = MPO([apply(o1, o2) for (o1, o2) in zip(Cdagup1, Cdagdn2)])
Cdagpt2 = MPO([apply(o1, o2) for (o1, o2) in zip(Cdagup3, Cdagdn4)])

Cdag=Cdagpt1+Cdagpt2

```

The two individual MPOs were created successfully. However on the last line it reports:

```auto
In `svd`, the left or right indices are empty (the indices of `A` are (((dim=16|id=880|"Electron,Site,n=1") <Out>
 1: QN(("Nf",-2,-1),("Sz",0)) => 1
 2: QN(("Nf",-1,-1),("Sz",-1)) => 2
 3: QN(("Nf",-1,-1),("Sz",1)) => 2
 4: QN(("Nf",0,-1),("Sz",-2)) => 1
 5: QN(("Nf",0,-1),("Sz",0)) => 4
 6: QN(("Nf",0,-1),("Sz",2)) => 1
 7: QN(("Nf",1,-1),("Sz",-1)) => 2
 8: QN(("Nf",1,-1),("Sz",1)) => 2
 9: QN(("Nf",2,-1),("Sz",0)) => 1,)), but the input indices are (Index{Vector{Pair{QN, Int64}}}[(dim=16|id=880|"Electron,Site,n=1") <Out>
 1: QN(("Nf",-2,-1),("Sz",0)) => 1
 2: QN(("Nf",-1,-1),("Sz",-1)) => 2
 3: QN(("Nf",-1,-1),("Sz",1)) => 2
 4: QN(("Nf",0,-1),("Sz",-2)) => 1
 5: QN(("Nf",0,-1),("Sz",0)) => 4
 6: QN(("Nf",0,-1),("Sz",2)) => 1
 7: QN(("Nf",1,-1),("Sz",-1)) => 2
 8: QN(("Nf",1,-1),("Sz",1)) => 2
 9: QN(("Nf",2,-1),("Sz",0)) => 1])). For now, this is not supported. You may have accidentally input the wrong indices.

```

If I change conserve\_qn to false then the addition of MPO works. Am I doing this correctly?

Best,  
Shengtao

---

<div class="post-metadata">

**Author:** ![mtfishman](https://yyz2.discourse-cdn.com/free1/user_avatar/itensor.discourse.group/mtfishman/32/11_2.png) [@mtfishman](https://itensor.discourse.group/u/mtfishman)\
**Post date:** [May 17, 2022, 2:34pm UTC](https://itensor.discourse.group/t/apply-mpo-to-mps-that-changes-quantum-number/143/6 "2022-05-17T14:34:00Z")

</div>

Hi Shengtao,

This is caused by a (now fixed) bug in the MPO code that MPO functions like contraction and addition weren’t working if the MPOs didn’t have explicit link indices. If you update to ITensors 0.3.12 it should now work.

Here is a complete and slightly simplified code that should work with ITensors 0.3.12:

```julia
using ITensors

function op_mpo(sites, which_op, j)
  left_ops = "Id"
  right_ops = "Id"
  if has_fermion_string(which_op, sites[j])
    left_ops = "F"
  end
  ops = [n < j ? left_ops : (n > j ? right_ops : which_op) for n in 1:length(sites)]
  return MPO([op(ops[n], sites[n]) for n in 1:length(sites)])
end

s = siteinds("Electron", 4; conserve_qns=true)

Cdagup1 = op_mpo(s, "Cdagup", 1)
Cdagdn2 = op_mpo(s, "Cdagdn", 2)
Cdagup3 = op_mpo(s, "Cdagup", 3)
Cdagdn4 = op_mpo(s, "Cdagdn", 4)
Cdag12 = apply(Cdagup1, Cdagdn2)
Cdag34 = apply(Cdagup3, Cdagdn4)
Cdag = Cdag12 + Cdag34
@show flux(Cdag)

```

---

<div class="post-metadata">

**Author:** ![Shengtao](https://avatars.discourse-cdn.com/v4/letter/s/b19c9b/32.png) [@Shengtao](https://itensor.discourse.group/u/Shengtao)\
**Post date:** [May 18, 2022, 6:28am UTC](https://itensor.discourse.group/t/apply-mpo-to-mps-that-changes-quantum-number/143/7 "2022-05-18T06:28:43Z")

</div>

Hi Matt,  
Thanks and glad to know the bug has been fixed. But it seems that I encounter another bug when trying to apply it to my really large system:

```auto
using ITensors

function op_mpo(sites, which_op, j)
  left_ops = "Id"
  right_ops = "Id"
  if has_fermion_string(which_op, sites[j])
    left_ops = "F"
  end
  ops = [n < j ? left_ops : (n > j ? right_ops : which_op) for n in 1:length(sites)]
  return MPO([op(ops[n], sites[n]) for n in 1:length(sites)])
end

N=260 #When N>250 last line doesn't work
s = siteinds("Electron", N; conserve_qns=true)
Cdagup = op_mpo(s, "Cdagup", 5)
Cdagdn = op_mpo(s, "Cdagdn", 10)
Cdagmpo = apply(Cdagup, Cdagdn)

```

When N\>250 , ITensor reports the following error for the last line:

```auto
ERROR: BoundsError: attempt to access 0-element Vector{Pair{QN, Int64}} at index [1]

```

EDIT: Actually it’s when N\>256 it will throw that error.

---

<div class="post-metadata">

**Author:** ![mtfishman](https://yyz2.discourse-cdn.com/free1/user_avatar/itensor.discourse.group/mtfishman/32/11_2.png) [@mtfishman](https://itensor.discourse.group/u/mtfishman)\
**Post date:** [June 1, 2022, 6:04pm UTC](https://itensor.discourse.group/t/apply-mpo-to-mps-that-changes-quantum-number/143/8 "2022-06-01T18:04:19Z")

</div>

Hi Shengtao,

Sorry for the slow response. The issue you are seeing there is that the norm of the MPO diverges as you make the system larger (try printing `norm(Cdagmpo)`). This causes problems for the truncation we are doing in the MPO contraction code (the norm of the MPO gets collected on a single tensor which we are truncating, so the norm of that tensor starts to diverge and causes numerical issues). I’m working on a fix/workaround for that.

However, Miles recently [fixed](https://github.com/ITensor/ITensors.jl/pull/918) the original issue you were seeing (with constructing the MPO, so code like this should work now:

```julia
using ITensors

N = 2
sites = siteinds("Electron",N,conserve_qns=true)
psi = productMPS(sites,["Emp" for i=1:N])
os = OpSum()
os += "Cdagup", 1, "Cdagdn", 2
cdagmpo = MPO(os, sites)

```

Please try updating to the latest version of ITensors.jl and see if that works now.

Cheers,  
Matt

---

<div class="post-metadata">

**Author:** ![Shengtao](https://avatars.discourse-cdn.com/v4/letter/s/b19c9b/32.png) [@Shengtao](https://itensor.discourse.group/u/Shengtao)\
**Post date:** [June 2, 2022, 6:18am UTC](https://itensor.discourse.group/t/apply-mpo-to-mps-that-changes-quantum-number/143/9 "2022-06-02T06:18:11Z")

</div>

Hi Matt,  
Actually I’ve noticed that change and this works perfectly now. Thank you and Miles for the effort to improve this!

Best,  
Shengtao

---

<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:** [May 20, 2024, 12:55pm UTC](https://itensor.discourse.group/t/apply-mpo-to-mps-that-changes-quantum-number/143/10 "2024-05-20T12:55:00Z")

</div>

Hi, I think I’m still having the issue described here even though I’m using the latest ITensor. Here is an example of it using the function op\_mpo defined in this discourse, where I apply a particle hole transform to a maximally mixed state (which should leave it invariant).

s = siteinds(“Fermion”,2;conserve\_qns=true)

###Creating particle hole transform for site 1  
cdag = op\_mpo(s,“Cdag”,1)  
c = op\_mpo(s,“C”,1)  
PH = cdag+c

##both sites are in the identity (maximally mixed state)  
ρ = op\_mpo(s, “Id”, 1)  
ρ = ρ/tr(ρ)  
apply(PH,ρ)

This code gives the error attempt to access 0-element Vector{Pair{QN, Int64}} at index [1], but without quantum numbers it works.

---

<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:** [May 20, 2024, 1:50pm UTC](https://itensor.discourse.group/t/apply-mpo-to-mps-that-changes-quantum-number/143/11 "2024-05-20T13:50:22Z")

</div>

This is not a bug, but rather how our QN conservation system is designed to work. In our system, you are only allowed to work with tensors that have a well-defined QN “flux” i.e. transform in a well-defined way (e.g. operators that change particle number by a well-defined amount). The operator `cdag` always adds a particle and `c` always removes a particle, but `cdag+c` does not have a well-defined QN flux.

One possibility for what you’re doing is that you may need to convert your tensors to dense tensors or just not use quantum numbers in this application.

---

<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:** [May 20, 2024, 1:51pm UTC](https://itensor.discourse.group/t/apply-mpo-to-mps-that-changes-quantum-number/143/12 "2024-05-20T13:51:11Z")

</div>

Also, in the future please start a new post instead of appending to previous posts. You can always reference previous posts by linking to them.

---

<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:** [May 20, 2024, 2:31pm UTC](https://itensor.discourse.group/t/apply-mpo-to-mps-that-changes-quantum-number/143/13 "2024-05-20T14:31:32Z")

</div>

Thanks for the quick reply! I will make sure to start a new post next time. I thought that because applying a particle hole transform maps a state with a well defined particle number to another state with a well defined particle number, there could be a way of doing this calculation with quantum numbers (I want to do this for largish chains). Would there be any way to do this?

---

<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:** [May 20, 2024, 2:45pm UTC](https://itensor.discourse.group/t/apply-mpo-to-mps-that-changes-quantum-number/143/14 "2024-05-20T14:45:10Z")

</div>

Sorry I will make this a new post
