+1 vote
asked by (700 points)


I have been trying to define my own SiteType by following the "Electron" site type source code on Github, but I got confused by the different versions where the usage of val() function and state() function varies.

To be precise, for https://github.com/ITensor/ITensors.jl/blob/main/src/physics/site_types/electron.jl
The val() function is used, and the state() function is assigned vectors.
However, for https://github.com/ITensor/ITensors.jl/blob/629_setindex_complex/src/physics/site_types/electron.jl
The val() function is not used, and the state() function is assigned integer scalars.

I roughly understand that the state() function serves as a basis for defining the matrix operators, so are both vectors and scalars fine?
Also, what exactly does the val() function do?

Thanks a lot for your help,

1 Answer

+1 vote
answered by (70.1k points)

Hi Mason,
Thanks for asking about this. One potential source of confusion is that we are changing the behavior of these functions between the 0.1.x versions of ITensors.jl (the current release being 0.1.41 right now) and the upcoming 0.2.0 version of ITensors.jl, which corresponds to the current "main" branch.

The first link you provided is to the 'main' branch whereas the second link is to an unmerged PR branch that is forked off of the 0.1.41 version. So the code there is different, and the function state has a different meaning.

Here is a summary of the situation in the current 0.1.x versions versus the upcoming 0.2.0 version:

  • In the 0.1.x versions:

    • the function state makes an IndexVal (Index stored together with an integer value) given an input such as "Up" or "Dn". This is implemented in the site_types/ files as returning just the integer, and the Index is included automatically by the calling function (generic implementation of state).
    • there is no "val" function of this type (other than an unrelated one for getting part of an IndexVal)
  • After the 0.2.0 release (probably in the next week or so):

    • the function val replaces the older state function, and just returns an integer value. So for "Up" for a spin it would return 1, and for "Dn" it would return 2 for S=1/2 and 3 for S=1, etc.
    • the function state now has a different meaning, and returns a single-site wavefunction (single site state) corresponding to different provided names. So providing "Up" will return a wavefunction with the spin being exactly up, where as providing "X+" will return a single-site wavefunction with the spin in the positive X direction, etc.

Hope that clarifies the situation! Much of the code, like the strings of "states" you pass to the productMPS constructor, will have exactly the same interface as before. But if you have code which directly calls the state function it will have to be upgraded in the new version. We will provide an upgrade guide in the docs.


commented by (700 points)
edited by
Thank you Miles, that clarifies a lot.

But somehow the productMPS is still not working and gives me the error "LoadError: ArgumentError: Overload of "state" function not found for Index tags "CFermion,Site,n=1", even though I can print out the states and sites in productMPS(sites, states).

I copy and paste my code below for your reference: (I followed the "Electron" site type closely)

using ITensors

ITensors.space(::SiteType"CFermion") = 4
function ITensors.space(
  if conserve_nfparity && conserve_Q1
    return [
      QN((qnname_nfparity, 0, -2), (qnname_Q1, 0)) => 1,
      QN((qnname_nfparity, 1, -2), (qnname_Q1, +1)) => 1,
      QN((qnname_nfparity, 1, -2), (qnname_Q1, +2)) => 1,
      QN((qnname_nfparity, 0, -2), (qnname_Q1, +3)) => 1
  return 4

#val(::ValName"Emp", ::SiteType"CFermion") = 1
#val(::ValName"f1", ::SiteType"CFermion") = 2
#val(::ValName"f2", ::SiteType"CFermion") = 3
#val(::ValName"f1f2", ::SiteType"CFermion") = 4
ITensors.state(::StateName"Emp", ::SiteType"CFermion") = [1.0,0,0,0]
ITensors.state(::StateName"f1", ::SiteType"CFermion") = [0.0,1,0,0]
ITensors.state(::StateName"f2", ::SiteType"CFermion") = [0.0,0,1,0]
ITensors.state(::StateName"f1f2", ::SiteType"CFermion") = [0.0,0,0,1]

function ITensors.op!(Op::ITensor, ::OpName"C1", ::SiteType"CFermion", s::Index)
  Op[s' => 1, s => 2] = 1.0
  return Op[s' => 3, s => 4] = 1.0

function ITensors.op!(Op::ITensor, ::OpName"C1d", ::SiteType"CFermion", s::Index)
  Op[s' => 2, s => 1] = 1.0
  return Op[s' => 4, s => 3] = 1.0

function ITensors.op!(Op::ITensor, ::OpName"C2", ::SiteType"CFermion", s::Index)
  Op[s' => 1, s => 3] = 1.0
  return Op[s' => 2, s => 4] = 1.0

function ITensors.op!(Op::ITensor, ::OpName"C2d", ::SiteType"CFermion", s::Index)
  Op[s' => 3, s => 1] = 1.0
  return Op[s' => 4, s => 2] = 1.0

function ITensors.op!(Op::ITensor, ::OpName"N1", ::SiteType"CFermion", s::Index)
  Op[s' => 2, s => 2] = 1.0
  return Op[s' => 4, s => 4] = 1.0

function ITensors.op!(Op::ITensor, ::OpName"N2", ::SiteType"CFermion", s::Index)
  Op[s' => 3, s => 3] = 1.0
  return Op[s' => 4, s => 4] = 1.0

has_fermion_string(::OpName"C1", ::SiteType"CFermion") = true
has_fermion_string(::OpName"C1d", ::SiteType"CFermion") = true
has_fermion_string(::OpName"C2", ::SiteType"CFermion") = true
has_fermion_string(::OpName"C2d", ::SiteType"CFermion") = true

    N = 6

    sites = siteinds("CFermion",N; conserve_qns = true)
    states = [mod(i,2)==0 ? "f1" : "f2" for i=1:N]
    psi0 = productMPS(sites,states)

commented by (70.1k points)
Quick question: what version of ITensor are you using? The current tagged version 0.1.41 (what you would obtain by default through the Julia package manager) or the main/master branch ? (Development version?)
commented by (700 points)
edited by
It's v0.1.36. Should I try to update?
Edit: I just updated to v0.1.41, and the same error persists.
commented by (70.1k points)
Thanks. So my answer above may have been overly long. The part of the answer that applies to your setup (because you aren't using the development / main branch version 0.2 which is fine) is that you should define the `ITensors.state` function to return a single number, not a vector. There is no `val` function yet in the version of ITensor you're using, or indeed in the latest tagged release of ITensor either.

Once we release the 0.2.0 version then the behavior of `state` will switch at that time (to what you're seeing on Github, which is the main branch) and also `val` will be introduced.
commented by (700 points)
I tried using 1,2,3,4 to label my four states, but it gives the same error. Thanks again.
commented by (70.1k points)
I see. So I think I spotted the problem: apparently we also switched the order of the arguments to `state` in the new version of the code (which you were looking at to compare to). If you look at this version of the code which matches the version you are using (0.1.36) then you will see that you should put the SiteType first then the StateName. Does that now work as expected? (Basically you should be able to closely follow the design of this file linked below:)


[Note how on Github it is showing that this version of the file is for 0.1.36.]
commented by (700 points)
Ah I see, now it works. Thank you so much!
commented by (70.1k points)
Great! Glad it is working
commented by (700 points)
Hi Miles, sorry to bother you again. I tried to add in interactions based on the previous code by using (as a minimal example):

ampo += g, "C2dC1", 1, "C1", 2
ampo += g, "C1d", 2, "C1dC2", 1

where the "C2dC1" and  "C1dC2" are defined the usual way:

function ITensors.op!(Op::ITensor, ::OpName"C2dC1", ::SiteType"CFermion", s::Index)  
  return Op[s' => 3, s => 2] = 1.0
function ITensors.op!(Op::ITensor, ::OpName"C1dC2", ::SiteType"CFermion", s::Index)  
  return Op[s' => 2, s => 3] = 1.0

However, making MPO by using MPO(sites, states) gives me the error: " No block found with QN equal to QN(("NfParity",1,-2),("Q1",0))" when I set conserve_qn to be true.

The strange part is the QN(("NfParity",1,-2),("Q1",0)), because it has 0 charge, but fermion parity is 1, which isn't supposed to appear based on my definition of the local Hilbert space and the operators. I'm not sure what I'm missing here.

Thanks again,
commented by (70.1k points)
Hi Mason,
So I noticed something unusual about the QN subspaces in your custom site type that might be causing this issue. The thing I noticed is that your "Q1" quantum numbers have the values +0,+1,+2,+3. In contrast, for an Electron site the particle number values would be 0,1,1,2 (corresponding to no electrons, one up electron, one down electron, or both kinds of electrons).

So could you explain more about the choice of 0,1,2,3 and what is behind it? Or do you think that's possibly an error?

commented by (700 points)
Hi Miles, I think I just found out the problem. The simple test interaction added doesn't preserve Fermion parity, even though my eventual goal is to study parity-conserving interaction. So the error pops up when I was trying to enforce parity.

Sorry that I wasn't clear enough in my question. In my case, f1 is a fermion with charge 1 and f2 is a fermion with charge 2. Both spinless. The QN name is "Q1" because I'll add another "Q2" quantum number in future.

Thanks again for your time.
commented by (70.1k points)
Oh ok thanks for explaining and glad you found the issue!
Welcome to ITensor Support Q&A, where you can ask questions and receive answers from other members of the community.

Formatting Tips:
  • To format code, indent by four spaces
  • To format inline LaTeX, surround it by @@ on both sides
  • To format LaTeX on its own line, surround it by $$ above and below
  • For LaTeX, it may be necessary to backslash-escape underscore characters to obtain proper formatting. So for example writing \sum\_i to represent a sum over i.
If you cannot register due to firewall issues (e.g. you cannot see the capcha box) please email Miles Stoudenmire to ask for an account.

To report ITensor bugs, please use the issue tracker.