Skip to content

States

Quantum states \(| \psi \rangle\) are represented in XDiag by using a State object.

Creating states

The most direct way to create a state is to hand a block together with a vector holding the coefficients on the computational basis of that block. The length of the vector must equal the dimension of the block. The coefficients can be real or complex, given as an arma::vec or arma::cx_vec in C++, respectively as a Vector{Float64} or Vector{ComplexF64} in Julia. XDiag automatically creates a real or complex state accordingly.

d = size(block)

v = rand(Float64, d)         # real coefficients
psi = State(block, v)

vc = rand(ComplexF64, d)     # complex coefficients
psic = State(block, vc)
int64_t d = size(block);

arma::vec v(d, arma::fill::randu);       // real coefficients
auto psi = State(block, v);

arma::cx_vec vc(d, arma::fill::randu);   // complex coefficients
auto psic = State(block, vc);

A state with zero coefficients is created either implicitly by calling the constructor of State with a given block, or explicitly by calling the zero_state function. In both cases, the parameter real is optional, can be omitted, and defaults to true; it controls whether the state holds real (double precision) or complex (double precision) coefficients.

real = true
psi1 = State(block, real=real)        # a zero state (created implicitly)
psi2 = zero_state(block, real=real)   # a zero state (created explicitly)
bool real = true;
auto psi1 = State(block, real);        // a zero state (created implicitly)
auto psi2 = zero_state(block, real);   // a zero state (created explicitly)

We can also create product states. A product state is specified by its per-site local quantum numbers, given as integers, following the same convention as the ProductState configurations discussed in the Hilbert spaces section. For a Spinhalf block, for example, 0 denotes a \(\downarrow\)-spin and 1 an \(\uparrow\)-spin. The meaning of the integers for every block type is documented on the respective block pages.

phi = product_state(block, [1, 0])    # per-site local states: Up=1, Dn=0
auto phi = product_state(block, {1, 0});   // per-site local states: Up=1, Dn=0

Finally, a random state with normal \(\mathcal{N}(0, 1)\) distributed coefficients is created using the random_state function.

seed = 1234
chi = random_state(block, seed=seed)
int64_t seed = 1234;
auto chi = random_state(block, true, 1, seed);

The random number generation is deterministic and controlled by the integer seed argument: calling random_state with the same seed (and the same block) always produces exactly the same state. This is essential for reproducibility. To obtain a different random state, simply choose a different seed. The seed argument is optional and defaults to a fixed value.

Norms and overlaps

The \(2\)-norm \(\parallel | \psi \rangle\parallel_2\) and dot product \(\langle \psi_1 | \psi_2 \rangle\) of states can easily be computed using the norm and dot/dotC functions.

nrm = norm(psi)
d = dot(psi1, psi2)
double nrm = norm(psi);
double d = dot(psi1, psi2);
complex dc = dotC(psi1, psi2);

The function dotC is only available in C++, and returns a complex (double precision) number whenever one of the involved states is complex. This is necessary, as the return type of a function must be known at compile time in C++, whereas Julia permits dynamic typing.

Accessing coefficients

The coefficients of a given state can be retrieved using the vector/vectorC functions.

v = vector(psi)
arma::vec v = vector(psi);
arma::cx_vec vc = vectorC(psi);

Again, the function vectorC only exists in the C++ version since the return type needs to be known at compile time. In Julia, the type of the vector is decided at runtime.

Applying operators

Finally, we can apply an operator OpSum to a state using the apply function.

phi = apply(H, psi)
auto phi = apply(H, psi);

Importantly, if the block of the State object has a well-defined quantum number, for example, a conserved particle number, XDiag will automatically detect the quantum number of the resulting state or report an error if the operator does not have a well-defined quantum number. This could be the case, for example, when applying a raising or lowering operator on a particle number conserving state. The apply function acts on a state without creating a matrix representation of the operator, sometimes referred to as on-the-fly matrix application.