# MPS and MPO

## Types

`ITensors.ITensorMPS.MPS`

— Type`MPS`

A finite size matrix product state type. Keeps track of the orthogonality center.

`ITensors.ITensorMPS.MPO`

— Type`MPO`

A finite size matrix product operator type. Keeps track of the orthogonality center.

## MPS Constructors

`ITensors.ITensorMPS.MPS`

— Method`MPS(N::Int)`

Construct an MPS with N sites with default constructed ITensors.

`ITensors.ITensorMPS.MPS`

— Method`MPS([::Type{ElT} = Float64, ]sites; linkdims=1)`

Construct an MPS filled with Empty ITensors of type `ElT`

from a collection of indices.

Optionally specify the link dimension with the keyword argument `linkdims`

, which by default is 1.

In the future we may generalize `linkdims`

to allow specifying each individual link dimension as a vector, and additionally allow specifying quantum numbers.

`ITensors.ITensorMPS.random_mps`

— Method```
random_mps(sites::Vector{<:Index}; linkdims=1)
random_mps(eltype::Type{<:Number}, sites::Vector{<:Index}; linkdims=1)
```

Construct a random MPS with link dimension `linkdims`

which by default has element type `Float64`

.

`linkdims`

can also accept a `Vector{Int}`

with `length(linkdims) == length(sites) - 1`

for constructing an MPS with non-uniform bond dimension.

`ITensors.ITensorMPS.random_mps`

— Method`random_mps(eltype::Type{<:Number}, sites::Vector{<:Index}; linkdims=1)`

Construct a random MPS with link dimension `linkdims`

of type `eltype`

.

`linkdims`

can also accept a `Vector{Int}`

with `length(linkdims) == length(sites) - 1`

for constructing an MPS with non-uniform bond dimension.

`ITensors.ITensorMPS.random_mps`

— Method`random_mps(sites::Vector{<:Index}, state; linkdims=1)`

Construct a real, random MPS with link dimension `linkdims`

, made by randomizing an initial product state specified by `state`

. This version of `random_mps`

is necessary when creating QN-conserving random MPS (consisting of QNITensors). The initial `state`

array provided determines the total QN of the resulting random MPS.

`ITensors.ITensorMPS.MPS`

— Method`MPS(sites::Vector{<:Index},states)`

Construct a product state MPS having site indices `sites`

, and which corresponds to the initial state given by the array `states`

. The `states`

array may consist of either an array of integers or strings, as recognized by the `state`

function defined for the relevant Index tag type.

**Examples**

```
N = 10
sites = siteinds("S=1/2", N)
states = [isodd(n) ? "Up" : "Dn" for n in 1:N]
psi = MPS(sites, states)
```

`ITensors.ITensorMPS.MPS`

— Method```
MPS(::Type{T},
sites::Vector{<:Index},
states::Union{Vector{String},
Vector{Int},
String,
Int})
```

Construct a product state MPS of element type `T`

, having site indices `sites`

, and which corresponds to the initial state given by the array `states`

. The input `states`

may be an array of strings or an array of ints recognized by the `state`

function defined for the relevant Index tag type. In addition, a single string or int can be input to create a uniform state.

**Examples**

```
N = 10
sites = siteinds("S=1/2", N)
states = [isodd(n) ? "Up" : "Dn" for n in 1:N]
psi = MPS(ComplexF64, sites, states)
phi = MPS(sites, "Up")
```

`ITensors.ITensorMPS.MPS`

— Method`MPS(ivals::Vector{<:Pair{<:Index}})`

Construct a product state MPS with element type `Float64`

and nonzero values determined from the input IndexVals.

`ITensors.ITensorMPS.MPS`

— Method`MPS(::Type{T<:Number}, ivals::Vector{<:Pair{<:Index}})`

Construct a product state MPS with element type `T`

and nonzero values determined from the input IndexVals.

## MPO Constructors

`ITensors.ITensorMPS.MPO`

— Method`MPO(N::Int)`

Make an MPO of length `N`

filled with default ITensors.

`ITensors.ITensorMPS.MPO`

— Method`MPO([::Type{ElT} = Float64}, ]sites, ops::Vector{String})`

Make an MPO with pairs of sites `s[i]`

and `s[i]'`

and operators `ops`

on each site.

`ITensors.ITensorMPS.MPO`

— Method`MPO([::Type{ElT} = Float64, ]sites, op::String)`

Make an MPO with pairs of sites `s[i]`

and `s[i]'`

and operator `op`

on every site.

## Copying behavior

`Base.copy`

— Method```
copy(::MPS)
copy(::MPO)
```

Make a shallow copy of an MPS or MPO. By shallow copy, it means that a new MPS/MPO is returned, but the data of the tensors are still shared between the returned MPS/MPO and the original MPS/MPO.

Therefore, replacing an entire tensor of the returned MPS/MPO will not modify the input MPS/MPO, but modifying the data of the returned MPS/MPO will modify the input MPS/MPO.

Use `deepcopy`

for an alternative that copies the ITensors as well.

**Examples**

```
julia> using ITensors, ITensorMPS
julia> s = siteinds("S=1/2", 3);
julia> M1 = random_mps(s; linkdims=3);
julia> norm(M1)
0.9999999999999999
julia> M2 = copy(M1);
julia> M2[1] *= 2;
julia> norm(M1)
0.9999999999999999
julia> norm(M2)
1.9999999999999998
julia> M3 = copy(M1);
julia> M3[1] .*= 3; # Modifies the tensor data
julia> norm(M1)
3.0000000000000004
julia> norm(M3)
3.0000000000000004
```

`Base.deepcopy`

— Method```
deepcopy(::MPS)
deepcopy(::MPO)
```

Make a deep copy of an MPS or MPO. By deep copy, it means that a new MPS/MPO is returned that doesn't share any data with the input MPS/MPO.

Therefore, modifying the resulting MPS/MPO will note modify the original MPS/MPO.

Use `copy`

for an alternative that performs a shallow copy that avoids copying the ITensor data.

**Examples**

```
julia> using ITensors, ITensorMPS
julia> s = siteinds("S=1/2", 3);
julia> M1 = random_mps(s; linkdims=3);
julia> norm(M1)
1.0
julia> M2 = deepcopy(M1);
julia> M2[1] .*= 2; # Modifies the tensor data
julia> norm(M1)
1.0
julia> norm(M2)
2.0
julia> M3 = copy(M1);
julia> M3[1] .*= 3; # Modifies the tensor data
julia> norm(M1)
3.0
julia> norm(M3)
3.0
```

## Properties

`Base.eltype`

— Method```
eltype(m::MPS)
eltype(m::MPO)
```

The element type of the MPS/MPO. Always returns `ITensor`

.

For the element type of the ITensors of the MPS/MPO, use `promote_itensor_eltype`

.

`ITensors.flux`

— Method```
flux(M::MPS)
flux(M::MPO)
totalqn(M::MPS)
totalqn(M::MPO)
```

For an MPS or MPO which conserves quantum numbers, compute the total QN flux. For a tensor network such as an MPS or MPO, the flux is the sum of fluxes of each of the tensors in the network. The name `totalqn`

is an alias for `flux`

.

`ITensors.hasqns`

— Method```
hasqns(M::MPS)
hasqns(M::MPO)
```

Return true if the MPS or MPO has tensors which carry quantum numbers.

`Base.length`

— Method`length(::MPS/MPO)`

The number of sites of an MPS/MPO.

`ITensors.ITensorMPS.maxlinkdim`

— Method```
maxlinkdim(M::MPS)
maxlinkdim(M::MPO)
```

Get the maximum link dimension of the MPS or MPO.

The minimum this will return is `1`

, even if there are no link indices.

## Obtaining and finding indices

`ITensors.SiteTypes.siteinds`

— Method```
siteinds(commoninds, A::MPO, B::MPS, j::Integer; kwargs...)
siteinds(commonind, A::MPO, B::MPO, j::Integer; kwargs...)
```

Get the site index (or indices) of the `j`

th MPO tensor of `A`

that is shared with MPS/MPO `B`

.

`ITensors.SiteTypes.siteinds`

— Method```
siteinds(uniqueinds, A::MPO, B::MPS, j::Integer; kwargs...)
siteinds(uniqueind, A::MPO, B::MPS, j::Integer; kwargs...)
```

Get the site index (or indices) of MPO `A`

that is unique to `A`

(not shared with MPS/MPO `B`

).

`ITensors.ITensorMPS.findsite`

— Function`findsite(M::Union{MPS, MPO}, is)`

Return the first site of the MPS or MPO that has at least one Index in common with the Index or collection of indices `is`

.

To find all sites with common indices with `is`

, use the `findsites`

function.

**Examples**

```
s = siteinds("S=1/2", 5)
ψ = random_mps(s)
findsite(ψ, s[3]) == 3
findsite(ψ, (s[3], s[4])) == 3
M = MPO(s)
findsite(M, s[4]) == 4
findsite(M, s[4]') == 4
findsite(M, (s[4]', s[4])) == 4
findsite(M, (s[4]', s[3])) == 3
```

`ITensors.ITensorMPS.findsites`

— Function`findsites(M::Union{MPS, MPO}, is)`

Return the sites of the MPS or MPO that have indices in common with the collection of site indices `is`

.

**Examples**

```
s = siteinds("S=1/2", 5)
ψ = random_mps(s)
findsites(ψ, s[3]) == [3]
findsites(ψ, (s[4], s[1])) == [1, 4]
M = MPO(s)
findsites(M, s[4]) == [4]
findsites(M, s[4]') == [4]
findsites(M, (s[4]', s[4])) == [4]
findsites(M, (s[4]', s[3])) == [3, 4]
```

`ITensors.ITensorMPS.firstsiteinds`

— Function`firstsiteinds(M::MPO; kwargs...)`

Get a Vector of the first site Index found on each site of M.

By default, it finds the first site Index with prime level 0.

`ITensors.ITensorMPS.linkind`

— Method```
linkind(M::MPS, j::Integer)
linkind(M::MPO, j::Integer)
```

Get the link or bond Index connecting the MPS or MPO tensor on site j to site j+1.

If there is no link Index, return `nothing`

.

`ITensors.SiteTypes.siteind`

— Method`siteind(M::MPS, j::Int; kwargs...)`

Get the first site Index of the MPS. Return `nothing`

if none is found.

`ITensors.SiteTypes.siteind`

— Method`siteind(::typeof(first), M::Union{MPS,MPO}, j::Integer; kwargs...)`

Return the first site Index found on the MPS or MPO (the first Index unique to the `j`

th MPS/MPO tensor).

You can choose different filters, like prime level and tags, with the `kwargs`

.

`ITensors.SiteTypes.siteinds`

— Method```
siteinds(M::MPS)
siteinds(::typeof(first), M::MPS)
```

Get a vector of the first site Index found on each tensor of the MPS.

`siteinds(::typeof(only), M::MPS)`

Get a vector of the only site Index found on each tensor of the MPS. Errors if more than one is found.

`siteinds(::typeof(all), M::MPS)`

Get a vector of the all site Indices found on each tensor of the MPS. Returns a Vector of IndexSets.

`ITensors.SiteTypes.siteind`

— Method`siteind(M::MPO, j::Int; plev = 0, kwargs...)`

Get the first site Index of the MPO found, by default with prime level 0.

`ITensors.SiteTypes.siteinds`

— Method`siteinds(M::MPO; kwargs...)`

Get a Vector of IndexSets of all the site indices of M.

`ITensors.SiteTypes.siteinds`

— Method`siteinds(M::Union{MPS, MPO}}, j::Integer; kwargs...)`

Return the site Indices found of the MPO or MPO at the site `j`

as an IndexSet.

Optionally filter prime tags and prime levels with keyword arguments like `plev`

and `tags`

.

## Priming and tagging

`ITensors.prime`

— Method```
prime[!](M::MPS, args...; kwargs...)
prime[!](M::MPO, args...; kwargs...)
```

Apply prime to all ITensors of an MPS/MPO, returning a new MPS/MPO.

The ITensors of the MPS/MPO will be a view of the storage of the original ITensors. Alternatively apply the function in-place.

`ITensors.prime`

— Method```
prime[!](siteinds, M::MPS, args...; kwargs...)
prime[!](siteinds, M::MPO, args...; kwargs...)
```

Apply prime to all site indices of an MPS/MPO, returning a new MPS/MPO.

The ITensors of the MPS/MPO will be a view of the storage of the original ITensors.

`ITensors.prime`

— Method```
prime[!](linkinds, M::MPS, args...; kwargs...)
prime[!](linkinds, M::MPO, args...; kwargs...)
```

Apply prime to all link indices of an MPS/MPO, returning a new MPS/MPO.

The ITensors of the MPS/MPO will be a view of the storage of the original ITensors.

`ITensors.prime`

— Method```
prime[!](siteinds, commoninds, M1::MPO, M2::MPS, args...; kwargs...)
prime[!](siteinds, commoninds, M1::MPO, M2::MPO, args...; kwargs...)
```

Apply prime to the site indices that are shared by `M1`

and `M2`

.

Returns new MPSs/MPOs. The ITensors of the MPSs/MPOs will be a view of the storage of the original ITensors.

`ITensors.prime`

— Method`prime[!](siteinds, uniqueinds, M1::MPO, M2::MPS, args...; kwargs...)`

Apply prime to the site indices of `M1`

that are not shared with `M2`

. Returns new MPSs/MPOs.

The ITensors of the MPSs/MPOs will be a view of the storage of the original ITensors.

`ITensors.swapprime`

— Method```
swapprime[!](M::MPS, args...; kwargs...)
swapprime[!](M::MPO, args...; kwargs...)
```

Apply swapprime to all ITensors of an MPS/MPO, returning a new MPS/MPO.

The ITensors of the MPS/MPO will be a view of the storage of the original ITensors. Alternatively apply the function in-place.

`ITensors.setprime`

— Method```
setprime[!](M::MPS, args...; kwargs...)
setprime[!](M::MPO, args...; kwargs...)
```

Apply setprime to all ITensors of an MPS/MPO, returning a new MPS/MPO.

The ITensors of the MPS/MPO will be a view of the storage of the original ITensors. Alternatively apply the function in-place.

`ITensors.setprime`

— Method```
setprime[!](siteinds, M::MPS, args...; kwargs...)
setprime[!](siteinds, M::MPO, args...; kwargs...)
```

Apply setprime to all site indices of an MPS/MPO, returning a new MPS/MPO.

The ITensors of the MPS/MPO will be a view of the storage of the original ITensors.

`ITensors.setprime`

— Method```
setprime[!](linkinds, M::MPS, args...; kwargs...)
setprime[!](linkinds, M::MPO, args...; kwargs...)
```

Apply setprime to all link indices of an MPS/MPO, returning a new MPS/MPO.

The ITensors of the MPS/MPO will be a view of the storage of the original ITensors.

`ITensors.setprime`

— Method```
setprime[!](siteinds, commoninds, M1::MPO, M2::MPS, args...; kwargs...)
setprime[!](siteinds, commoninds, M1::MPO, M2::MPO, args...; kwargs...)
```

Apply setprime to the site indices that are shared by `M1`

and `M2`

.

Returns new MPSs/MPOs. The ITensors of the MPSs/MPOs will be a view of the storage of the original ITensors.

`ITensors.setprime`

— Method`setprime[!](siteinds, uniqueinds, M1::MPO, M2::MPS, args...; kwargs...)`

Apply setprime to the site indices of `M1`

that are not shared with `M2`

. Returns new MPSs/MPOs.

The ITensors of the MPSs/MPOs will be a view of the storage of the original ITensors.

`ITensors.noprime`

— Method```
noprime[!](M::MPS, args...; kwargs...)
noprime[!](M::MPO, args...; kwargs...)
```

Apply noprime to all ITensors of an MPS/MPO, returning a new MPS/MPO.

`ITensors.noprime`

— Method```
noprime[!](siteinds, M::MPS, args...; kwargs...)
noprime[!](siteinds, M::MPO, args...; kwargs...)
```

Apply noprime to all site indices of an MPS/MPO, returning a new MPS/MPO.

The ITensors of the MPS/MPO will be a view of the storage of the original ITensors.

`ITensors.noprime`

— Method```
noprime[!](linkinds, M::MPS, args...; kwargs...)
noprime[!](linkinds, M::MPO, args...; kwargs...)
```

Apply noprime to all link indices of an MPS/MPO, returning a new MPS/MPO.

The ITensors of the MPS/MPO will be a view of the storage of the original ITensors.

`ITensors.noprime`

— Method```
noprime[!](siteinds, commoninds, M1::MPO, M2::MPS, args...; kwargs...)
noprime[!](siteinds, commoninds, M1::MPO, M2::MPO, args...; kwargs...)
```

Apply noprime to the site indices that are shared by `M1`

and `M2`

.

Returns new MPSs/MPOs. The ITensors of the MPSs/MPOs will be a view of the storage of the original ITensors.

`ITensors.noprime`

— Method`noprime[!](siteinds, uniqueinds, M1::MPO, M2::MPS, args...; kwargs...)`

Apply noprime to the site indices of `M1`

that are not shared with `M2`

. Returns new MPSs/MPOs.

The ITensors of the MPSs/MPOs will be a view of the storage of the original ITensors.

`ITensors.TagSets.addtags`

— Method```
addtags[!](M::MPS, args...; kwargs...)
addtags[!](M::MPO, args...; kwargs...)
```

Apply addtags to all ITensors of an MPS/MPO, returning a new MPS/MPO.

`ITensors.TagSets.addtags`

— Method```
addtags[!](siteinds, M::MPS, args...; kwargs...)
addtags[!](siteinds, M::MPO, args...; kwargs...)
```

Apply addtags to all site indices of an MPS/MPO, returning a new MPS/MPO.

The ITensors of the MPS/MPO will be a view of the storage of the original ITensors.

`ITensors.TagSets.addtags`

— Method```
addtags[!](linkinds, M::MPS, args...; kwargs...)
addtags[!](linkinds, M::MPO, args...; kwargs...)
```

Apply addtags to all link indices of an MPS/MPO, returning a new MPS/MPO.

The ITensors of the MPS/MPO will be a view of the storage of the original ITensors.

`ITensors.TagSets.addtags`

— Method```
addtags[!](siteinds, commoninds, M1::MPO, M2::MPS, args...; kwargs...)
addtags[!](siteinds, commoninds, M1::MPO, M2::MPO, args...; kwargs...)
```

Apply addtags to the site indices that are shared by `M1`

and `M2`

.

`ITensors.TagSets.addtags`

— Method`addtags[!](siteinds, uniqueinds, M1::MPO, M2::MPS, args...; kwargs...)`

Apply addtags to the site indices of `M1`

that are not shared with `M2`

. Returns new MPSs/MPOs.

The ITensors of the MPSs/MPOs will be a view of the storage of the original ITensors.

`ITensors.TagSets.removetags`

— Method```
removetags[!](M::MPS, args...; kwargs...)
removetags[!](M::MPO, args...; kwargs...)
```

Apply removetags to all ITensors of an MPS/MPO, returning a new MPS/MPO.

`ITensors.TagSets.removetags`

— Method```
removetags[!](siteinds, M::MPS, args...; kwargs...)
removetags[!](siteinds, M::MPO, args...; kwargs...)
```

Apply removetags to all site indices of an MPS/MPO, returning a new MPS/MPO.

The ITensors of the MPS/MPO will be a view of the storage of the original ITensors.

`ITensors.TagSets.removetags`

— Method```
removetags[!](linkinds, M::MPS, args...; kwargs...)
removetags[!](linkinds, M::MPO, args...; kwargs...)
```

Apply removetags to all link indices of an MPS/MPO, returning a new MPS/MPO.

The ITensors of the MPS/MPO will be a view of the storage of the original ITensors.

`ITensors.TagSets.removetags`

— Method```
removetags[!](siteinds, commoninds, M1::MPO, M2::MPS, args...; kwargs...)
removetags[!](siteinds, commoninds, M1::MPO, M2::MPO, args...; kwargs...)
```

Apply removetags to the site indices that are shared by `M1`

and `M2`

.

`ITensors.TagSets.removetags`

— Method`removetags[!](siteinds, uniqueinds, M1::MPO, M2::MPS, args...; kwargs...)`

Apply removetags to the site indices of `M1`

that are not shared with `M2`

. Returns new MPSs/MPOs.

The ITensors of the MPSs/MPOs will be a view of the storage of the original ITensors.

`ITensors.TagSets.replacetags`

— Method```
replacetags[!](M::MPS, args...; kwargs...)
replacetags[!](M::MPO, args...; kwargs...)
```

Apply replacetags to all ITensors of an MPS/MPO, returning a new MPS/MPO.

`ITensors.TagSets.replacetags`

— Method```
replacetags[!](siteinds, M::MPS, args...; kwargs...)
replacetags[!](siteinds, M::MPO, args...; kwargs...)
```

Apply replacetags to all site indices of an MPS/MPO, returning a new MPS/MPO.

The ITensors of the MPS/MPO will be a view of the storage of the original ITensors.

`ITensors.TagSets.replacetags`

— Method```
replacetags[!](linkinds, M::MPS, args...; kwargs...)
replacetags[!](linkinds, M::MPO, args...; kwargs...)
```

Apply replacetags to all link indices of an MPS/MPO, returning a new MPS/MPO.

The ITensors of the MPS/MPO will be a view of the storage of the original ITensors.

`ITensors.TagSets.replacetags`

— Method```
replacetags[!](siteinds, commoninds, M1::MPO, M2::MPS, args...; kwargs...)
replacetags[!](siteinds, commoninds, M1::MPO, M2::MPO, args...; kwargs...)
```

Apply replacetags to the site indices that are shared by `M1`

and `M2`

.

`ITensors.TagSets.replacetags`

— Method`replacetags[!](siteinds, uniqueinds, M1::MPO, M2::MPS, args...; kwargs...)`

Apply replacetags to the site indices of `M1`

that are not shared with `M2`

. Returns new MPSs/MPOs.

The ITensors of the MPSs/MPOs will be a view of the storage of the original ITensors.

`ITensors.settags`

— Method```
settags[!](M::MPS, args...; kwargs...)
settags[!](M::MPO, args...; kwargs...)
```

Apply settags to all ITensors of an MPS/MPO, returning a new MPS/MPO.

`ITensors.settags`

— Method```
settags[!](siteinds, M::MPS, args...; kwargs...)
settags[!](siteinds, M::MPO, args...; kwargs...)
```

Apply settags to all site indices of an MPS/MPO, returning a new MPS/MPO.

The ITensors of the MPS/MPO will be a view of the storage of the original ITensors.

`ITensors.settags`

— Method```
settags[!](linkinds, M::MPS, args...; kwargs...)
settags[!](linkinds, M::MPO, args...; kwargs...)
```

Apply settags to all link indices of an MPS/MPO, returning a new MPS/MPO.

The ITensors of the MPS/MPO will be a view of the storage of the original ITensors.

`ITensors.settags`

— Method```
settags[!](siteinds, commoninds, M1::MPO, M2::MPS, args...; kwargs...)
settags[!](siteinds, commoninds, M1::MPO, M2::MPO, args...; kwargs...)
```

Apply settags to the site indices that are shared by `M1`

and `M2`

.

`ITensors.settags`

— Method`settags[!](siteinds, uniqueinds, M1::MPO, M2::MPS, args...; kwargs...)`

Apply settags to the site indices of `M1`

that are not shared with `M2`

. Returns new MPSs/MPOs.

The ITensors of the MPSs/MPOs will be a view of the storage of the original ITensors.

## Operations

`ITensors.ITensorMPS.expect`

— Method```
expect(psi::MPS, op::AbstractString...; kwargs...)
expect(psi::MPS, op::Matrix{<:Number}...; kwargs...)
expect(psi::MPS, ops; kwargs...)
```

Given an MPS `psi`

and a single operator name, returns a vector of the expected value of the operator on each site of the MPS.

If multiple operator names are provided, returns a tuple of expectation value vectors.

If a container of operator names is provided, returns the same type of container with names replaced by vectors of expectation values.

**Optional Keyword Arguments**

`sites = 1:length(psi)`

: compute expected values only for sites in the given range

**Examples**

```
N = 10
s = siteinds("S=1/2", N)
psi = random_mps(s; linkdims=8)
Z = expect(psi, "Sz") # compute for all sites
Z = expect(psi, "Sz"; sites=2:4) # compute for sites 2,3,4
Z3 = expect(psi, "Sz"; sites=3) # compute for site 3 only (output will be a scalar)
XZ = expect(psi, ["Sx", "Sz"]) # compute Sx and Sz for all sites
Z = expect(psi, [1/2 0; 0 -1/2]) # same as expect(psi,"Sz")
s = siteinds("Electron", N)
psi = random_mps(s; linkdims=8)
dens = expect(psi, "Ntot")
updens, dndens = expect(psi, "Nup", "Ndn") # pass more than one operator
```

`ITensors.ITensorMPS.correlation_matrix`

— Method```
correlation_matrix(psi::MPS,
Op1::AbstractString,
Op2::AbstractString;
kwargs...)
correlation_matrix(psi::MPS,
Op1::Matrix{<:Number},
Op2::Matrix{<:Number};
kwargs...)
```

Given an MPS psi and two strings denoting operators (as recognized by the `op`

function), computes the two-point correlation function matrix C[i,j] = <psi| Op1i Op2j |psi> using efficient MPS techniques. Returns the matrix C.

**Optional Keyword Arguments**

`sites = 1:length(psi)`

: compute correlations only for sites in the given range`ishermitian = false`

: if`false`

, force independent calculations of the matrix elements above and below the diagonal, while if`true`

assume they are complex conjugates.

For a correlation matrix of size NxN and an MPS of typical bond dimension m, the scaling of this algorithm is N^2*m^3.

**Examples**

```
N = 30
m = 4
s = siteinds("S=1/2", N)
psi = random_mps(s; linkdims=m)
Czz = correlation_matrix(psi, "Sz", "Sz")
Czz = correlation_matrix(psi, [1/2 0; 0 -1/2], [1/2 0; 0 -1/2]) # same as above
s = siteinds("Electron", N; conserve_qns=true)
psi = random_mps(s, n -> isodd(n) ? "Up" : "Dn"; linkdims=m)
Cuu = correlation_matrix(psi, "Cdagup", "Cup"; sites=2:8)
```

`ITensors.dag`

— Method```
dag[!](M::MPS, args...; kwargs...)
dag[!](M::MPO, args...; kwargs...)
```

Apply dag to all ITensors of an MPS/MPO, returning a new MPS/MPO.

`NDTensors.dense`

— Method`dense(::MPS/MPO)`

Given an MPS (or MPO), return a new MPS (or MPO) having called `dense`

on each ITensor to convert each tensor to use dense storage and remove any QN or other sparse structure information, if it is not dense already.

`ITensors.ITensorMPS.movesite`

— Method`movesite(::Union{MPS, MPO}, n1n2::Pair{Int, Int})`

Create a new MPS/MPO where the site at `n1`

is moved to `n2`

, for a pair `n1n2 = n1 => n2`

.

This is done with a series a pairwise swaps, and can introduce a lot of entanglement into your state, so use with caution.

`ITensors.ITensorMPS.orthogonalize!`

— Function```
orthogonalize!(M::MPS, j::Int; kwargs...)
orthogonalize(M::MPS, j::Int; kwargs...)
orthogonalize!(M::MPO, j::Int; kwargs...)
orthogonalize(M::MPO, j::Int; kwargs...)
```

Move the orthogonality center of the MPS to site `j`

. No observable property of the MPS will be changed, and no truncation of the bond indices is performed. Afterward, tensors `1,2,...,j-1`

will be left-orthogonal and tensors `j+1,j+2,...,N`

will be right-orthogonal.

Either modify in-place with `orthogonalize!`

or out-of-place with `orthogonalize`

.

`ITensors.ITensorMPS.replacebond!`

— Method`replacebond!(M::MPS, b::Int, phi::ITensor; kwargs...)`

Factorize the ITensor `phi`

and replace the ITensors `b`

and `b+1`

of MPS `M`

with the factors. Choose the orthogonality with `ortho="left"/"right"`

.

`ITensors.ITensorMPS.sample`

— Method`sample(m::MPS)`

Given a normalized MPS m with `orthocenter(m)==1`

, returns a `Vector{Int}`

of `length(m)`

corresponding to one sample of the probability distribution defined by squaring the components of the tensor that the MPS represents

`ITensors.ITensorMPS.sample!`

— Method`sample!(m::MPS)`

Given a normalized MPS m, returns a `Vector{Int}`

of `length(m)`

corresponding to one sample of the probability distribution defined by squaring the components of the tensor that the MPS represents. If the MPS does not have an orthogonality center, orthogonalize!(m,1) will be called before computing the sample.

`ITensors.ITensorMPS.sample`

— Method`sample(M::MPO)`

Given a normalized MPO `M`

, returns a `Vector{Int}`

of `length(M)`

corresponding to one sample of the probability distribution defined by the MPO, treating the MPO as a density matrix.

The MPO `M`

should have an (approximately) positive spectrum.

`ITensors.ITensorMPS.swapbondsites`

— Method`swapbondsites(ψ::Union{MPS, MPO}, b::Integer; kwargs...)`

Swap the sites `b`

and `b+1`

.

`NDTensors.truncate!`

— Function```
truncate!(M::MPS; kwargs...)
truncate!(M::MPO; kwargs...)
```

Perform a truncation of all bonds of an MPS/MPO, using the truncation parameters (cutoff,maxdim, etc.) provided as keyword arguments.

Keyword arguments:

`site_range`

=1:N - only truncate the MPS bonds between these sites

## Gate evolution

`ITensors.product`

— Method```
apply(o::ITensor, ψ::Union{MPS, MPO}, [ns::Vector{Int}]; kwargs...)
product([...])
```

Get the product of the operator `o`

with the MPS/MPO `ψ`

, where the operator is applied to the sites `ns`

. If `ns`

are not specified, the sites are determined by the common indices between `o`

and the site indices of `ψ`

.

If `ns`

are non-contiguous, the sites of the MPS are moved to be contiguous. By default, the sites are moved back to their original locations. You can leave them where they are by setting the keyword argument `move_sites_back`

to false.

**Keywords**

`cutoff::Real`

: singular value truncation cutoff.`maxdim::Int`

: maximum MPS/MPO dimension.`apply_dag::Bool = false`

: apply the gate and the dagger of the gate (only relevant for MPO evolution).`move_sites_back::Bool = true`

: after the ITensors are applied to the MPS or MPO, move the sites of the MPS or MPO back to their original locations.

`ITensors.product`

— Method```
apply(As::Vector{<:ITensor}, M::Union{MPS, MPO}; kwargs...)
product([...])
```

Apply the ITensors `As`

to the MPS or MPO `M`

, treating them as gates or matrices from pairs of prime or unprimed indices.

**Keywords**

`cutoff::Real`

: singular value truncation cutoff.`maxdim::Int`

: maximum MPS/MPO dimension.`apply_dag::Bool = false`

: apply the gate and the dagger of the gate (only relevant for MPO evolution).`move_sites_back::Bool = true`

: after the ITensor is applied to the MPS or MPO, move the sites of the MPS or MPO back to their original locations.

**Examples**

Apply one-site gates to an MPS:

```
N = 3
ITensors.op(::OpName"σx", ::SiteType"S=1/2", s::Index) =
2*op("Sx", s)
ITensors.op(::OpName"σz", ::SiteType"S=1/2", s::Index) =
2*op("Sz", s)
# Make the operator list.
os = [("σx", n) for n in 1:N]
append!(os, [("σz", n) for n in 1:N])
@show os
s = siteinds("S=1/2", N)
gates = ops(os, s)
# Starting state |↑↑↑⟩
ψ0 = MPS(s, "↑")
# Apply the gates.
ψ = apply(gates, ψ0; cutoff = 1e-15)
# Test against exact (full) wavefunction
prodψ = apply(gates, prod(ψ0))
@show prod(ψ) ≈ prodψ
# The result is:
# σz₃ σz₂ σz₁ σx₃ σx₂ σx₁ |↑↑↑⟩ = -|↓↓↓⟩
@show inner(ψ, MPS(s, "↓")) == -1
```

Apply nonlocal two-site gates and one-site gates to an MPS:

```
# 2-site gate
function ITensors.op(::OpName"CX", ::SiteType"S=1/2", s1::Index, s2::Index)
mat = [1 0 0 0
0 1 0 0
0 0 0 1
0 0 1 0]
return itensor(mat, s2', s1', s2, s1)
end
os = [("CX", 1, 3), ("σz", 3)]
@show os
# Start with the state |↓↑↑⟩
ψ0 = MPS(s, n -> n == 1 ? "↓" : "↑")
# The result is:
# σz₃ CX₁₃ |↓↑↑⟩ = -|↓↑↓⟩
ψ = apply(ops(os, s), ψ0; cutoff = 1e-15)
@show inner(ψ, MPS(s, n -> n == 1 || n == 3 ? "↓" : "↑")) == -1
```

Perform TEBD-like time evolution:

```
# Define the nearest neighbor term `S⋅S` for the Heisenberg model
function ITensors.op(::OpName"expS⋅S", ::SiteType"S=1/2",
s1::Index, s2::Index; τ::Number)
O = 0.5 * op("S+", s1) * op("S-", s2) +
0.5 * op("S-", s1) * op("S+", s2) +
op("Sz", s1) * op("Sz", s2)
return exp(τ * O)
end
τ = -0.1im
os = [("expS⋅S", (1, 2), (τ = τ,)),
("expS⋅S", (2, 3), (τ = τ,))]
ψ0 = MPS(s, n -> n == 1 ? "↓" : "↑")
expτH = ops(os, s)
ψτ = apply(expτH, ψ0)
```

## Algebra Operations

`ITensors.inner`

— Method```
inner(A::MPS, B::MPS)
inner(A::MPO, B::MPO)
```

Compute the inner product `⟨A|B⟩`

. If `A`

and `B`

are MPOs, computes the Frobenius inner product.

Use `loginner`

to avoid underflow/overflow for taking overlaps of large MPS or MPO.

Before ITensors 0.3, `inner`

had a keyword argument `make_inds_match`

that default to `true`

. When true, the function attempted to make the site indices match before contracting. So for example, the inputs could have different site indices, as long as they have the same dimensions or QN blocks. This behavior was fragile since it only worked for MPS with single site indices per tensor, and as of ITensors 0.3 has been deprecated. As of ITensors 0.3 you will need to make sure the MPS or MPO you input have compatible site indices to contract over, such as by making sure the prime levels match properly.

Same as `dot`

.

`LinearAlgebra.dot`

— Method`ITensors.ITensorMPS.loginner`

— Method```
loginner(A::MPS, B::MPS)
loginner(A::MPO, B::MPO)
```

Compute the logarithm of the inner product `⟨A|B⟩`

. If `A`

and `B`

are MPOs, computes the logarithm of the Frobenius inner product.

This is useful for larger MPS/MPO, where in the limit of large numbers of sites the inner product can diverge or approach zero.

Before ITensors 0.3, `inner`

had a keyword argument `make_inds_match`

that default to `true`

. When true, the function attempted to make the site indices match before contracting. So for example, the inputs could have different site indices, as long as they have the same dimensions or QN blocks. This behavior was fragile since it only worked for MPS with single site indices per tensor, and as of ITensors 0.3 has been deprecated. As of ITensors 0.3 you will need to make sure the MPS or MPO you input have compatible site indices to contract over, such as by making sure the prime levels match properly.

Same as `logdot`

.

`ITensors.ITensorMPS.logdot`

— Method`ITensors.inner`

— Method`inner(y::MPS, A::MPO, x::MPS)`

Compute `⟨y|A|x⟩ = ⟨y|Ax⟩`

efficiently and exactly without making any intermediate MPOs. In general it is more efficient and accurate than `inner(y, apply(A, x))`

.

This is helpful for computing the expectation value of an operator `A`

, which would be:

`inner(x', A, x)`

assuming `x`

is normalized.

If you want to compute `⟨By|Ax⟩`

you can use `inner(B::MPO, y::MPS, A::MPO, x::MPS)`

.

This is helpful for computing the variance of an operator `A`

, which would be:

`inner(A, x, A, x) - inner(x', A, x) ^ 2`

assuming `x`

is normalized.

Before ITensors 0.3, `inner`

had a keyword argument `make_inds_match`

that default to `true`

. When true, the function attempted to make the site indices match before contracting. So for example, the inputs could have different site indices, as long as they have the same dimensions or QN blocks. This behavior was fragile since it only worked for MPS with single site indices per tensor, and as of ITensors 0.3 has been deprecated. As of ITensors 0.3 you will need to make sure the MPS or MPO you input have compatible site indices to contract over, such as by making sure the prime levels match properly.

Same as `dot`

.

`LinearAlgebra.dot`

— Method`dot(y::MPS, A::MPO, x::MPS)`

Same as `inner`

.

`ITensors.inner`

— Method`inner(B::MPO, y::MPS, A::MPO, x::MPS)`

Compute `⟨By|A|x⟩ = ⟨By|Ax⟩`

efficiently and exactly without making any intermediate MPOs. In general it is more efficient and accurate than `inner(apply(B, y), apply(A, x))`

.

This is helpful for computing the variance of an operator `A`

, which would be:

`inner(A, x, A, x) - inner(x, A, x) ^ 2`

`inner`

had a keyword argument `make_inds_match`

that default to `true`

. When true, the function attempted to make the site indices match before contracting. So for example, the inputs could have different site indices, as long as they have the same dimensions or QN blocks. This behavior was fragile since it only worked for MPS with single site indices per tensor, and as of ITensors 0.3 has been deprecated. As of ITensors 0.3 you will need to make sure the MPS or MPO you input have compatible site indices to contract over, such as by making sure the prime levels match properly.

Same as `dot`

.

`LinearAlgebra.dot`

— Method`dot(B::MPO, y::MPS, A::MPO, x::MPS)`

Same as `inner`

.

`LinearAlgebra.norm`

— Method```
norm(A::MPS)
norm(A::MPO)
```

Compute the norm of the MPS or MPO.

If the MPS or MPO has a well defined orthogonality center, this reduces to the norm of the orthogonality center tensor. Otherwise, it computes the norm with the full inner product of the MPS/MPO with itself.

See also `lognorm`

.

`LinearAlgebra.normalize`

— Method```
normalize(A::MPS; (lognorm!)=[])
normalize(A::MPO; (lognorm!)=[])
```

Return a new MPS or MPO `A`

that is the same as the original MPS or MPO but with `norm(A) ≈ 1`

.

In practice, this evenly spreads `lognorm(A)`

over the tensors within the range of the orthogonality center to avoid numerical overflow in the case of diverging norms.

See also `normalize!`

, `norm`

, `lognorm`

.

`LinearAlgebra.normalize!`

— Method```
normalize!(A::MPS; (lognorm!)=[])
normalize!(A::MPO; (lognorm!)=[])
```

Change the MPS or MPO `A`

in-place such that `norm(A) ≈ 1`

. This modifies the data of the tensors within the orthogonality center.

In practice, this evenly spreads `lognorm(A)`

over the tensors within the range of the orthogonality center to avoid numerical overflow in the case of diverging norms.

If the norm of the input MPS or MPO is 0, normalizing is ill-defined. In this case, we just return the original MPS or MPO. You can check for this case as follows:

```
s = siteinds("S=1/2", 4)
ψ = 0 * random_mps(s)
lognorm_ψ = []
normalize!(ψ; (lognorm!)=lognorm_ψ)
lognorm_ψ[1] == -Inf # There was an infinite norm
```

`ITensors.ITensorMPS.lognorm`

— Method```
lognorm(A::MPS)
lognorm(A::MPO)
```

Compute the logarithm of the norm of the MPS or MPO.

This is useful for larger MPS/MPO that are not gauged, where in the limit of large numbers of sites the norm can diverge or approach zero.

`Base.:+`

— Method```
+(A::MPS/MPO...; kwargs...)
add(A::MPS/MPO...; kwargs...)
```

Add arbitrary numbers of MPS/MPO with each other, optionally truncating the results.

A cutoff of 1e-15 is used by default, and in general users should set their own cutoff for their particular application.

**Keywords**

`cutoff::Real`

: singular value truncation cutoff`maxdim::Int`

: maximum MPS/MPO bond dimension`alg = "densitymatrix"`

:`"densitymatrix"`

or`"directsum"`

.`"densitymatrix"`

adds the MPS/MPO by adding up and diagoanlizing local density matrices site by site in a single sweep through the system, truncating the density matrix with`cutoff`

and`maxdim`

.`"directsum"`

performs a direct sum of each tensors on each site of the input MPS/MPO being summed. It doesn't perform any truncation, and therefore ignores`cutoff`

and`maxdim`

. The bond dimension of the output is the sum of the bond dimensions of the inputs. You can truncate the resulting MPS/MPO with the`truncate!`

function.

**Examples**

```
N = 10
s = siteinds("S=1/2", N; conserve_qns = true)
state = n -> isodd(n) ? "↑" : "↓"
ψ₁ = random_mps(s, state; linkdims=2)
ψ₂ = random_mps(s, state; linkdims=2)
ψ₃ = random_mps(s, state; linkdims=2)
ψ = +(ψ₁, ψ₂; cutoff = 1e-8)
# Can use:
#
# ψ = ψ₁ + ψ₂
#
# but generally you want to set a custom `cutoff` and `maxdim`.
println()
@show inner(ψ, ψ)
@show inner(ψ₁, ψ₂) + inner(ψ₁, ψ₂) + inner(ψ₂, ψ₁) + inner(ψ₂, ψ₂)
# Computes ψ₁ + 2ψ₂
ψ = ψ₁ + 2ψ₂
println()
@show inner(ψ, ψ)
@show inner(ψ₁, ψ₁) + 2 * inner(ψ₁, ψ₂) + 2 * inner(ψ₂, ψ₁) + 4 * inner(ψ₂, ψ₂)
# Computes ψ₁ + 2ψ₂ + ψ₃
ψ = ψ₁ + 2ψ₂ + ψ₃
println()
@show inner(ψ, ψ)
@show inner(ψ₁, ψ₁) + 2 * inner(ψ₁, ψ₂) + inner(ψ₁, ψ₃) +
2 * inner(ψ₂, ψ₁) + 4 * inner(ψ₂, ψ₂) + 2 * inner(ψ₂, ψ₃) +
inner(ψ₃, ψ₁) + 2 * inner(ψ₃, ψ₂) + inner(ψ₃, ψ₃)
```

`NDTensors.contract`

— Method```
contract(ψ::MPS, A::MPO; kwargs...) -> MPS
*(::MPS, ::MPO; kwargs...) -> MPS
contract(A::MPO, ψ::MPS; kwargs...) -> MPS
*(::MPO, ::MPS; kwargs...) -> MPS
```

Contract the `MPO`

`A`

with the `MPS`

`ψ`

, returning an `MPS`

with the unique site indices of the `MPO`

.

For example, for an MPO with site indices with prime levels of 1 and 0, such as `-s'-A-s-`

, and an MPS with site indices with prime levels of 0, such as `-s-x`

, the result is an MPS `y`

with site indices with prime levels of 1, `-s'-y = -s'-A-s-x`

.

Since it is common to contract an MPO with prime levels of 1 and 0 with an MPS with prime level of 0 and want a resulting MPS with prime levels of 0, we provide a convenience function `apply`

:

`apply(A, x; kwargs...) = replaceprime(contract(A, x; kwargs...), 2 => 1)`.`

Choose the method with the `method`

keyword, for example `"densitymatrix"`

and `"naive"`

.

**Keywords**

`cutoff::Float64=1e-13`

: the cutoff value for truncating the density matrix eigenvalues. Note that the default is somewhat arbitrary and subject to change, in general you should set a`cutoff`

value.`maxdim::Int=maxlinkdim(A) * maxlinkdim(ψ))`

: the maximal bond dimension of the results MPS.`mindim::Int=1`

: the minimal bond dimension of the resulting MPS.`normalize::Bool=false`

: whether or not to normalize the resulting MPS.`method::String="densitymatrix"`

: the algorithm to use for the contraction. Currently the options are "densitymatrix", where the network formed by the MPO and MPS is squared and contracted down to a density matrix which is diagonalized iteratively at each site, and "naive", where the MPO and MPS tensor are contracted exactly at each site and then a truncation of the resulting MPS is performed.

See also `apply`

.

`ITensors.apply`

— Method`apply(A::MPO, x::MPS; kwargs...)`

Contract the `MPO`

`A`

with the `MPS`

`x`

and then map the prime level of the resulting MPS back to 0.

Equivalent to `replaceprime(contract(A, x; kwargs...), 2 => 1)`

.

See also `contract`

for details about the arguments available.

`NDTensors.contract`

— Method```
contract(A::MPO, B::MPO; kwargs...) -> MPO
*(::MPO, ::MPO; kwargs...) -> MPO
```

Contract the `MPO`

`A`

with the `MPO`

`B`

, returning an `MPO`

with the site indices that are not shared between `A`

and `B`

.

If you are contracting two MPOs with the same sets of indices, likely you want to call something like:

```
C = contract(A', B; cutoff=1e-12)
C = replaceprime(C, 2 => 1)
```

That is because if MPO `A`

has the index structure `-s'-A-s-`

and MPO `B`

has the Index structure `-s'-B-s-`

, if we only want to contract over on set of the indices, we would do `(-s'-A-s-)'-s'-B-s- = -s''-A-s'-s'-B-s- = -s''-C-s-`

, and then map the prime levels back to pairs of primed and unprimed indices with: `replaceprime(-s''-C-s-, 2 => 1) = -s'-C-s-`

.

Since this is a common use case, you can use the convenience function:

`C = apply(A, B; cutoff=1e-12)`

which is the same as the code above.

If you are contracting MPOs that have diverging norms, such as MPOs representing sums of local operators, the truncation can become numerically unstable (see https://arxiv.org/abs/1909.06341 for a more numerically stable alternative). For now, you can use the following options to contract MPOs like that:

```
C = contract(A, B; alg="naive", truncate=false)
# Bring the indices back to pairs of primed and unprimed
C = apply(A, B; alg="naive", truncate=false)
```

**Keywords**

`cutoff::Float64=1e-14`

: the cutoff value for truncating the density matrix eigenvalues. Note that the default is somewhat arbitrary and subject to change, in general you should set a`cutoff`

value.`maxdim::Int=maxlinkdim(A) * maxlinkdim(B))`

: the maximal bond dimension of the results MPS.`mindim::Int=1`

: the minimal bond dimension of the resulting MPS.`alg="zipup"`

: Either`"zipup"`

or`"naive"`

.`"zipup"`

contracts pairs of site tensors and truncates with SVDs in a sweep across the sites, while`"naive"`

first contracts pairs of tensor exactly and then truncates at the end if`truncate=true`

.`truncate=true`

: Enable or disable truncation. If`truncate=false`

, ignore other truncation parameters like`cutoff`

and`maxdim`

. This is most relevant for the`"naive"`

version, if you just want to contract the tensors pairwise exactly. This can be useful if you are contracting MPOs that have diverging norms, such as MPOs originating from sums of local operators.

See also `apply`

for details about the arguments available.

`ITensors.apply`

— Method`apply(A::MPO, B::MPO; kwargs...)`

Contract the `MPO`

`A'`

with the `MPO`

`B`

and then map the prime level of the resulting MPO back to having pairs of indices with prime levels of 1 and 0.

Equivalent to `replaceprime(contract(A', B; kwargs...), 2 => 1)`

.

See also `contract`

for details about the arguments available.

`ITensors.ITensorMPS.error_contract`

— Method```
error_contract(y::MPS, A::MPO, x::MPS;
make_inds_match::Bool = true)
error_contract(y::MPS, x::MPS, x::MPO;
make_inds_match::Bool = true)
```

Compute the distance between A|x> and an approximation MPS y: `| |y> - A|x> |/| A|x> | = √(1 + (<y|y> - 2*real(<y|A|x>))/<Ax|A|x>)`

.

If `make_inds_match = true`

, the function attempts match the site indices of `y`

with the site indices of `A`

that are not common with `x`

.

`NDTensors.outer`

— Method`outer(x::MPS, y::MPS; <keyword argument>) -> MPO`

Compute the outer product of `MPS`

`x`

and `MPS`

`y`

, returning an `MPO`

approximation. Note that `y`

will be conjugated.

In Dirac notation, this is the operation `|x⟩⟨y|`

.

If you want an outer product of an MPS with itself, you should call `outer(x', x; kwargs...)`

so that the resulting MPO has site indices with indices coming in pairs of prime levels of 1 and 0. If not, the site indices won't be unique which would not be an outer product.

For example:

```
s = siteinds("S=1/2", 5)
x = random_mps(s)
y = random_mps(s)
outer(x, y) # Incorrect! Site indices must be unique.
outer(x', y) # Results in an MPO with pairs of primed and unprimed indices.
```

This allows for more general outer products, such as more general MPO outputs which don't have pairs of primed and unprimed indices, or outer products where the input MPS are vectorizations of MPOs.

For example:

```
s = siteinds("S=1/2", 5)
X = MPO(s, "Id")
Y = MPO(s, "Id")
x = convert(MPS, X)
y = convert(MPS, Y)
outer(x, y) # Incorrect! Site indices must be unique.
outer(x', y) # Incorrect! Site indices must be unique.
outer(addtags(x, "Out"), addtags(y, "In")) # This performs a proper outer product.
```

The keyword arguments determine the truncation, and accept the same arguments as `contract(::MPO, ::MPO; kwargs...)`

.

`ITensors.ITensorMPS.projector`

— Method`projector(x::MPS; <keyword argument>) -> MPO`

Computes the projector onto the state `x`

. In Dirac notation, this is the operation `|x⟩⟨x|/|⟨x|x⟩|²`

.

Use keyword arguments to control the level of truncation, which are the same as those accepted by `contract(::MPO, ::MPO; kw...)`

.

**Keywords**

`normalize::Bool=true`

: whether or not to normalize the input MPS before forming the projector. If`normalize==false`

and the input MPS is not already normalized, this function will not output a proper project, and simply outputs`outer(x, x) = |x⟩⟨x|`

, i.e. the projector scaled by`norm(x)^2`

.- truncation keyword arguments accepted by
`contract(::MPO, ::MPO; kw...)`

.