Advanced operator usage and custom Hamiltonians

Rimu can be used to work with custom Hamiltonians and observables that are user-defined and not part of the Rimu.jl package. To make this possible and reliable, Rimu exposes a number of interfaces and provides helper functions to test compliance with the interfaces through the submodule Rimu.InterfaceTests, see Interface tests. This section covers the relevant interfaces, the interface functions as well as potentially useful helper functions.

In order to define custom Hamiltonians or observables it is useful to know how the operator type hierarchy works in Rimu. For an example of how to implement custom Hamiltonians that are not part of the Rimu.jl package, see RimuLegacyHamiltonians.jl.

Operator type hierarchy

Rimu offers a hierarchy of abstract types that define interfaces with different requirements for operators:

AbstractHamiltonian <: AbstractOperator <: AbstractObservable

The different abstract types have different requirements and are meant to be used for different purposes.

Hamiltonians interface

Behind the implementation of a particular model is a more abstract interface for defining Hamiltonians. If you want to define a new model you should make use of this interface. A new model Hamiltonian should subtype to AbstractHamiltonian and implement the relevant methods.

Rimu.Interfaces.AbstractHamiltonianType
AbstractHamiltonian{T} <: AbstractOperator{T}

Supertype that provides an interface for linear operators over a linear space with scalar type T that are suitable for FCIQMC (with ProjectorMonteCarloProblem). Indexing is done with addresses (typically not integers) from an address space that may be large (and will not need to be completely generated).

AbstractHamiltonian instances operate on vectors of type AbstractDVec from the module DictVectors and work well with addresses of type AbstractFockAddress from the module BitStringAddresses. The type works well with the external package KrylovKit.jl.

For available implementations see Hamiltonians.

Interface

Mandatory methods to implement:

AbstractOperatorColumn has its own interface methods:

Optional additional methods to implement:

Alternative Interface (deprecated)

Provides the following functions and methods:

  • ProjectorMonteCarloProblem(H): use this Hamiltonian for FCIQMC
  • ExactDiagonalizationProblem(H): use this Hamiltonian for exact diagonalization
  • *(H, v): deterministic matrix-vector multiply (allocating)
  • H(v): equivalent to H * v.
  • mul!(w, H, v): mutating matrix-vector multiply.
  • dot(x, H, v): compute x⋅(H*v) minimizing allocations.
  • H[address1, address2]: indexing with getindex() - mostly for testing purposes (slow!)
  • BasisSetRepresentation: construct a basis set representation
  • sparse, Matrix: construct a (sparse) matrix representation

See also Hamiltonians, Interfaces, AbstractOperatorColumn, AbstractOperator, AbstractObservable.

source
Rimu.Interfaces.starting_addressFunction
starting_address(h::AbstractHamiltonian)
starting_address(column::AbstractOperatorColumn)

Return the starting address for the Hamiltonian h, or for the column.

Example

julia> address = BoseFS((3, 2, 1));

julia> H = HubbardMom1D(address);

julia> address == starting_address(H)
true

Part of the AbstractHamiltonian interface. See also AbstractOperatorColumn.

source
Rimu.Interfaces.operator_columnFunction
operator_column(operator::AbstractOperator, address) -> column <: AbstractOperatorColumn
*(o::AbstractOperator, a::AbstractFockAddress) -> column

Return a (lazy) object representing the column of operator given by address. In quantum notation, the column represents the object

\[ Ĥ|α⟩ = ∑ᵦ|β⟩⟨β|Ĥ|α⟩,\]

where $α$ is the address and $β$ represents all reachable addresses with nonzero matrix element $⟨β|Ĥ|α⟩$ of the operator $Ĥ$. Columns iterate over pairs address => matrix_element.

For more information and the definition of an interface see AbstractOperatorColumn.

Example

julia> address = BoseFS(0,1,0);

julia> H = HubbardReal1D(address; u=6.0);

julia> column = H * address # construct column with `*` operator
HubbardReal1D(fs"|0 1 0⟩"; u=6.0, t=1.0) * fs"|0 1 0⟩"

julia> operator_column(H, address) == column
true

julia> diagonal_element(column) == column[address] # access elements with `getindex`
true

julia> DVec(column) # materialise as a `DVec`
DVec{BoseFS{1, 3, BitString{3, 1, UInt8}},Float64} with 2 entries, style = IsDeterministic{Float64}()
  fs"|1 0 0⟩" => -1.0
  fs"|0 0 1⟩" => -1.0

Part of the AbstractHamiltonian interface. See also AbstractOperatorColumn, parent_operator, starting_address, diagonal_element, offdiagonals, num_offdiagonals, random_offdiagonal.

source
Rimu.Interfaces.AbstractOperatorColumnType
AbstractOperatorColumn{A,T,O}

Abstract type for operator columns returned by operator_column(operator, address) or operator * address. The type parameters represent the address type (A), the eltype (T), and the type of the operator (O).

In quantum notation, the column represents the object

\[ Ĥ|α⟩ = ∑ᵦ|β⟩⟨β|Ĥ|α⟩,\]

where $α$ is the address and $β$ represents all reachable addresses with nonzero matrix element $⟨β|Ĥ|α⟩$ of the operator $Ĥ$.

Interface

The default constructor for AbstractOperatorColumn is operator_column(operator, address). The interface for AbstractOperatorColumn is defined by the following functions:

Methods for these functions need to be implemented for a new type of AbstractOperator.

Part of the AbstractHamiltonian and AbstractOperator interface. See also operator_column.

source
Rimu.Interfaces.diagonal_elementFunction
diagonal_element(column::AbstractOperatorColumn)
diagonal_element(ham, address) # (deprecated)

Compute the diagonal matrix element of the linear operator ham at address address, where column = operator_column(ham, address).

Example

julia> H = HubbardMom1D(BoseFS(3, 2, 1));

julia> column = operator_column(H, starting_address(H));

julia> diagonal_element(column)
8.666666666666664

Part of the AbstractHamiltonian interface. See also AbstractOperatorColumn and operator_column.

source
Rimu.Interfaces.offdiagonalsFunction
offdiagonals(column::AbstractOperatorColumn)
offdiagonals(h::AbstractHamiltonian, address) # (deprecated)

Return an iterator over nonzero off-diagonal matrix elements of h in the same column as address. Will iterate over pairs (newaddress, matrixelement) or newaddress => matrixelement.

Example

julia> address = BoseFS(3,2,1);

julia> H = HubbardReal1D(address);

julia> h = offdiagonals(H * address)
6-element Rimu.Hamiltonians.Offdiagonals{BoseFS{6, 3, BitString{8, 1, UInt8}}, Float64, HubbardReal1D{Float64, BoseFS{6, 3, BitString{8, 1, UInt8}}, 1.0, 1.0}}:
 (fs"|2 3 1⟩", -3.0)
 (fs"|2 2 2⟩", -2.449489742783178)
 (fs"|3 1 2⟩", -2.0)
 (fs"|4 1 1⟩", -2.8284271247461903)
 (fs"|4 2 0⟩", -2.0)
 (fs"|3 3 0⟩", -1.7320508075688772)

Part of the AbstractHamiltonian interface. See also AbstractOperatorColumn and operator_column.

source
Rimu.Interfaces.random_offdiagonalFunction
random_offdiagonal(column::AbstractOperatorColumn)
random_offdiagonal(ham::AbstractHamiltonian, address) # deprecated
-> newaddress, probability, matrixelement

Generate a single random excitation, i.e. choose from one of the accessible off-diagonal elements in the column ham * address. The result is a tuple of the new address newaddress, the probability of this excitation probability, and the matrix element matrixelement of the excitation.

Part of the AbstractHamiltonian interface. See also AbstractOperatorColumn and operator_column.

source
Rimu.Interfaces.num_offdiagonalsFunction
num_offdiagonals(column::AbstractOperatorColumn)
num_offdiagonals(ham, address) # (deprecated)

Compute the number of number of reachable configurations from address address, where column = operator_column(ham, address). If necessary, this may be an upper bound.

Example

julia> H = HubbardMom1D(BoseFS(3, 2, 1));

julia> column = operator_column(H, starting_address(H));

julia> num_offdiagonals(column)
10

Part of the AbstractHamiltonian interface. See also AbstractOperatorColumn and operator_column.

source
Rimu.Interfaces.get_offdiagonalFunction
newadd, me = get_offdiagonal(ham, address, chosen) # (deprecated)

Compute value me and new address newadd of a single (off-diagonal) matrix element in a Hamiltonian ham. The off-diagonal element is in the same column as address address and is indexed by integer index chosen.

Example

julia> addr = BoseFS(3, 2, 1);

julia> H = HubbardMom1D(addr);

julia> get_offdiagonal(H, addr, 3)
(BoseFS{6,3}(2, 1, 3), 1.0)

Part of the AbstractHamiltonian interface.

source

The following functions come with default implementations, but may be customized.

Rimu.Interfaces.LOStructureType
LOStructure(op::AbstractHamiltonian)
LOStructure(typeof(op))

Return information about the structure of the linear operator op. LOStructure is used as a trait to speficy symmetries or other properties of the linear operator op that may simplify or speed up calculations. Implemented instances are:

  • IsDiagonal(): The operator is diagonal.
  • IsHermitian(): The operator is complex and Hermitian or real and symmetric.
  • AdjointKnown(): The operator is not Hermitian, but its adjoint is implemented.
  • AdjointUnknown(): adjoint for this operator is not implemented.

Part of the AbstractHamiltonian interface.

In order to define this trait for a new linear operator type, define a method for LOStructure(::Type{<:MyNewLOType}) = ….

source
Rimu.Hamiltonians.dimensionFunction
dimension(h::AbstractHamiltonian, addr=starting_address(h))
dimension(h::AbstractObservable, addr)
dimension(addr::AbstractFockAddress)
dimension(::Type{<:AbstractFockAddress})

Return the estimated dimension of Hilbert space. May return a BigInt number.

When called on an address or address type, the dimension of the linear space spanned by the address type is returned. When called on an AbstractHamiltonian, an upper bound on the dimension of the matrix representing the Hamiltonian is returned.

Examples

julia> dimension(OccupationNumberFS(1,2,3))
16777216

julia> dimension(HubbardReal1D(OccupationNumberFS(1,2,3)))
28

julia> dimension(BoseFS{200,100})
1386083821086188248261127842108801860093488668581216236221011219101585442774669540

julia> Float64(ans)
1.3860838210861882e81

Part of the AbstractHamiltonian interface. See also BasisSetRepresentation.

Extended Help

The default fallback for dimension called on an AbstractHamiltonian is to return the dimension of the address space, which provides an upper bound. For new Hamiltonians a tighter bound can be provided by defining a custom method.

When extending AbstractHamiltonian, define a method for the two-argument form dimension(h::MyNewHamiltonian, addr). For number-conserving Hamiltonians, the function Hamiltonians.number_conserving_dimension may be useful.

When extending AbstractFockAddress, define a method for dimension(::Type{MyNewFockAddress}).

source
Rimu.Interfaces.has_random_offdiagonalFunction
has_random_offdiagonal(operatortype::Type)::Bool

Return true if the operator's columns have a random_offdiagonal method implemented.

Example

julia> using Rimu.Interfaces

julia> h = HubbardReal1D(BoseFS(1,2,3));

julia> has_random_offdiagonal(typeof(h))
true

When extending the interface, implement a method for Rimu.Interfaces.has_random_offdiagonal(::Type{<:MyNewOperator}).

Part of the AbstractHamiltonian interface. See also AbstractOperatorColumn and operator_column.

source
Rimu.Interfaces.allows_address_typeFunction
allows_address_type(operator, addr_or_type)

Returns true if addr_or_type is a valid address for operator. Otherwise, returns false.

Part of the AbstractHamiltonian interface.

Extended help

Defaults to addr_or_type <: typeof(starting_address(operator)). Overload this function if the operator can be used with addresses of different types.

source
Base.eltypeFunction
eltype(op::AbstractObservable)

Return the type of the elements of the operator. This can be a vector value. For the underlying scalar type use scalartype.

Part of the AbstractObservable interface.

Note

New types do not have to implement this method explicitly. An implementation is provided based on the AbstractObservable's type parameter.

source
VectorInterface.scalartypeFunction
scalartype(op::AbstractObservable)

Return the type of the underlying scalar field of the operator. This may be different from the element type of the operator returned by eltype, which can be a vector value.

Part of the AbstractObservable interface.

Note

New types do not have to implement this method explicitly. An implementation is provided based on the AbstractObservable's type parameter.

source
LinearAlgebra.mul!Function
LinearAlgebra.mul!(w::AbstractDVec, op::AbstractOperator, v::AbstractDVec)

In place multiplication of op with v and storing the result in w. The result is returned. Note that w needs to have a valtype that can hold a product of instances of eltype(op) and valtype(v). Moreover, the StochasticStyle of w needs to be <:IsDeterministic.

Part of the AbstractOperator interface.

source

This interface relies on unexported functionality, including

LinearAlgebra.dotFunction
dot(w, op::AbstractObservable, v)

Evaluate w⋅op(v) minimizing memory allocations.

source
Rimu.Hamiltonians.AbstractOffdiagonalsType
AbstractOffdiagonals{A,T}<:AbstractVector{Tuple{A,T}}

Iterator over new address and matrix elements for reachable off-diagonal matrix elements of a linear operator.

See Offdiagonals for a default implementation.

Methods to define

  • offdiagonals(h, a)::AbstractOffdiagonals: This function is used to construct the correct type of offdiagonals for a given combination of Hamiltonian h and Fock address a.
  • Base.getindex(::AbstractOffdiagonals, i): should be equivalent to get_offdiagonal(h, a, i).
  • Base.size(::AbstractOffdiagonals): should be equivalent to num_offdiagonals(h, a).

See also offdiagonals, AbstractHamiltonian, AbstractOperator.

source
Rimu.Hamiltonians.OffdiagonalsType
Offdiagonals(h, address) <: AbstractOffdiagonals

Iterator over new address and matrix element for reachable off-diagonal matrix elements of linear operator h from address address. Represents an abstract vector containing the non-zero off-diagonal matrix elements of the column of h indexed by address. To construct this iterator use offdiagonals.

This is the default implementation of AbstractOffdiagonals defined in terms of num_offdiagonals and get_offdiagonal.

See also offdiagonals, AbstractHamiltonian, AbstractOperator.

source
Rimu.Hamiltonians.check_address_typeFunction
check_address_type(h::AbstractObservable, addr_or_type)

Throw an ArgumentError if addr_or_type is not compatible with h, otherwise return true. Acceptable arguments are either an address or an address type, or a tuple or array thereof.

See also allows_address_type.

source

Operator and observable interface

Rimu.Interfaces.AbstractObservableType
AbstractObservable{T}

Most permissive supertype for operators in the type hierarchy:

AbstractHamiltonian{T} <: AbstractOperator{T} <: AbstractObservable{T}

AbstractObservable provides an interface for operators that can appear in a three-way dot product dot(x, op, y) with two vectors of type AbstractDVec. The result is a value of type T, which is also returned by the eltype function. This may be a vector type associated with a scalar type returned by the scalartype function.

The AbstractObservable type is useful for defining observables that can be calculated in the context of a ProjectorMonteCarloProblem using AllOverlaps.

Interface

Basic interface methods to implement:

Optional additional methods to implement:

See also AbstractOperator, AbstractHamiltonian, Interfaces.

source
Rimu.Interfaces.AbstractOperatorType
AbstractOperator{T} <: AbstractObservable{T}

Supertype that provides an interface for linear operators over a linear space with elements of type T (returned by eltype) and general (custom type) indices called 'addresses'.

AbstractOperator instances operate on vectors of type AbstractDVec from the module DictVectors and work well with addresses of type AbstractFockAddress from the module BitStringAddresses.

The defining feature of an AbstractOperator is that it can be applied to a vector with mul!(y, op, x) and that three-way dot products can be calculated with dot(x, op, y).

The AbstractOperator type is useful for defining operators that are not necessarily Hamiltonians, but that can be used in the context of a ProjectorMonteCarloProblem as observable operators in a ReplicaStrategy, e.g. for defining correlation functions. In contrast to AbstractHamiltonians, AbstractOperators do not need to have a starting_address. Moreover, the eltype of an AbstractOperator can be a vector value whereas AbstractHamiltonians require a scalar eltype.

AbstractHamiltonian{T} <: AbstractOperator{T} <: AbstractObservable{T}

The AbstractOperator type is part of the AbstractObservable hierarchy. It is more restrictive than AbstractObservable in that it requires the interface for the generation of diagonal and off-diagonal elements.

For concrete implementations see Hamiltonians. In order to implement a Hamiltonian for use in ProjectorMonteCarloProblem or ExactDiagonalizationProblem use the type AbstractHamiltonian instead.

Interface

Mandatory methods to implement:

Optional additional methods to implement:

Alternative Interface (deprecated)

If the number of non-zero matrix elements that can be reached from any address is known, and they can be separately generated:

In order to calculate observables efficiently, it may make sense to implement custom methods for Interfaces.dot_from_right(x, ham, y) and LinearAlgebra.mul!(y, ham, x).

See also AbstractHamiltonian, Interfaces.

source

Hamiltonian wrapper interface

ModifiedHamiltonian provides an interface for wrapping Hamiltonians into a new type with modified properties. Fully implemented Hamiltonian wrappers are documented in the Hamiltonians section.

Rimu.Hamiltonians.ModifiedHamiltonianType
abstract type ModifiedHamiltonian{T} <: AbstractHamiltonian{T} end

Abstract type for defining wrappers over AbstractHamiltonians that modify diagonal and off-diagonal elements via the functions modify_diagonal and modify_offdiagonal.

The ModifiedHamiltonian can only be used to implement wrappers that modify the (off)-diagonals individually and cannot be used to introduce additional off-diagonal elements to the Hamiltonian.

The following need to be implemented

The following are provided:

source

Interface tests

Helper functions that can be used for testing the various interfaces are provided in the (unexported) submodule Rimu.InterfaceTests.

Testing functions

Rimu.InterfaceTests.test_hamiltonian_interfaceFunction
test_hamiltonian_interface(h, addr=starting_address(h); kwargs...)

The main purpose of this test function is to check that all required methods of the AbstractHamiltonian interface are defined and work as expected.

Keyword arguments

  • test_iterable_offdiagonals = has_iterable_offdiagonals(typeof(h)): If true, tests that the offdiagonals(column) is iterable.
  • test_random_offdiagonal = has_random_offdiagonal(typeof(h)): If true, tests that the random_offdiagonal(column) is defined.

This function also tests the following properties of the Hamiltonian:

  • dimension(h) ≥ dimension(h, addr)
  • scalartype(h) === eltype(h)
  • Hamiltonian action on a vector <: AbstractDVec
  • starting_address returns an allows_address_type address
  • LOStructure is one of IsDiagonal, IsHermitian, AdjointKnown
  • the AbstractOperator interface is tested
  • the AbstractObservable interface is tested

Example

julia> using Rimu.InterfaceTests

julia> test_hamiltonian_interface(HubbardRealSpace(BoseFS(2,0,3,1)));
Test Summary:                          | Pass  Total  Time
Observable interface: HubbardRealSpace |    4      4  0.0s
Test Summary:       | Pass  Total  Time
allows_address_type |    1      1  0.0s
Test Summary:                        | Pass  Total  Time
Operator interface: HubbardRealSpace |    9      9  0.0s
Test Summary:       | Pass  Total  Time
allows_address_type |    1      1  0.0s
Test Summary:                                 | Pass  Total  Time
Hamiltonians-only tests with HubbardRealSpace |    6      6  0.0s

See also test_operator_interface, test_observable_interface.

source
Rimu.InterfaceTests.test_hamiltonian_structureFunction
test_hamiltonian_structure(h::AbstractHamiltonian; sizelim=20)

Test the LOStructure of a small Hamiltonian h by instantiating it as a sparse matrix and checking whether the structure of the matrix is constistent with the result of LOStructure(h) and the eltype is consistent with eltype(h).

This function is intended to be used in automated test for small Hamiltonians where instantiating the matrix is quick. A warning will print if the dimension of the Hamiltonian is larger than 20.

Example

julia> using Rimu.InterfaceTests

julia> test_hamiltonian_structure(HubbardRealSpace(BoseFS(2,0,1)));
Test Summary: | Pass  Total  Time
structure     |    4      4  0.0s
source
Rimu.InterfaceTests.test_observable_interfaceFunction
test_observable_interface(obs, addr)

This function tests compliance with the AbstractObservable interface for an observable obs at address addr (typically <: AbstractFockAddress) by checking that all required methods are defined.

The following properties are tested:

  • dot(v, obs, v) returns a value of the same type as the eltype of the observable
  • LOStructure is set consistently

Example

julia> using Rimu.InterfaceTests

julia> test_observable_interface(ReducedDensityMatrix(2), FermiFS(1,0,1,1));
Test Summary:                              | Pass  Total  Time
Observable interface: ReducedDensityMatrix |    4      4  0.0s

See also AbstractObservable, test_operator_interface, test_hamiltonian_interface.

source
Rimu.InterfaceTests.test_operator_interfaceFunction
test_operator_interface(op, addr; kwargs...)

This function tests compliance with the AbstractOperator interface for an operator op at address addr (typically <: AbstractFockAddress) by checking that all required methods are defined.

Keyword arguments

  • test_iterable_offdiagonals = has_iterable_offdiagonals(typeof(op)): If true, tests that the offdiagonals(column) is iterable.
  • test_random_offdiagonal = has_random_offdiagonal(typeof(op)): If true, tests that the random_offdiagonal(column) is defined.

The following properties are tested:

If test_random_offdiagonal is true, tests are performed that require random_offdiagonal(column) to be defined. If test_iterable_offdiagonals is true, tests are performed that require offdiagonals(column) to be iterable.

  • diagonal_element(column) returns a value of the same type as the eltype of the operator
  • offdiagonals iterates address => value pairs of consistent type (only if test_iterable_offdiagonals==true)
  • random_offdiagonal returns a tuple with the correct types (only if test_random_offdiagonal == true)
  • mul! and dot work as expected
  • dimension returns a consistent value
  • the AbstractObservable interface is tested

Example

julia> using Rimu.InterfaceTests

julia> test_operator_interface(SuperfluidCorrelator(3), BoseFS(1, 2, 3, 1));
Test Summary:                              | Pass  Total  Time
Observable interface: SuperfluidCorrelator |    4      4  0.0s
Test Summary:       | Pass  Total  Time
allows_address_type |    1      1  0.0s
Test Summary:                            | Pass  Total  Time
Operator interface: SuperfluidCorrelator |    9      9  0.0s

See also AbstractOperator, test_observable_interface, test_hamiltonian_interface.

source

Utilities for harmonic oscillator models

Useful utilities for harmonic oscillator in Cartesian basis, see HOCartesianContactInteractions and HOCartesianEnergyConservedPerDim.

Rimu.Hamiltonians.get_all_blocksFunction
get_all_blocks(h::Union{HOCartesianContactInteractions,HOCartesianEnergyConservedPerDim};
    target_energy = nothing,
    max_energy = nothing,
    max_blocks = nothing,
    method = :vertices,
    kwargs...) -> df

Find all distinct blocks of h. Returns a DataFrame with columns

  • block_id: index of block in order found
  • block_E0: noninteracting energy of all elements in the block
  • block_size: number of elements in the block
  • addr: first address that generates the block with e.g. BasisSetRepresentation
  • indices: tuple of mode indices that allow recreation of the generating address addr; in this case use e.g. BoseFS(M; indices .=> 1) This is useful when the DataFrame is loaded from file since Arrow.jl converts custom types to NamedTuples.
  • t_basis: time to generate the basis for each block

Keyword arguments:

  • target_energy: only blocks with this noninteracting energy are found
  • max_energy: only blocks with noninteracting energy less than this are found
  • max_blocks: exit after finding this many blocks
  • method: Choose between :vertices and :comb for method of enumerating tuples of quantum numbers
  • save_to_file=nothing: if set then the DataFrame recording blocks is saved after each new block is found
  • additional kwargs: passed to isapprox for comparing block energies. Useful for anisotropic traps

Note: If h was constructed with option block_by_level = false then the block seeds addr are determined by parity. In this case the blocks are not generated; t_basis will be zero, and block_size will be an estimate. Pass the seed addresses to BasisSetRepresentation with an appropriate filter to generate the blocks.

source
Rimu.Hamiltonians.fock_to_cartFunction
fock_to_cart(addr, S; zero_index = true)

Convert a Fock state address addr to Cartesian harmonic oscillator basis indices $n_x,n_y,\ldots$. These indices are bounded by S which is a tuple of the maximum number of states in each dimension. By default the groundstate in each dimension is indexed by 0, but this can be changed by setting zero_index = false.

source

Underlying integrals for the interaction matrix elements are implemented in the following unexported functions

Rimu.Hamiltonians.four_oscillator_integral_generalFunction
four_oscillator_integral_general(i, j, k, l; max_level = typemax(Int))

Integral of four one-dimensional harmonic oscillator functions,

\[ \mathcal{I}(i,j,k,l) = \int_{-\infty}^\infty dx \, \phi_i(x) \phi_j(x) \phi_k(x) \phi_l(x)\]

Indices i,j,k,l start at 0 for the groundstate.

This integral has a closed form in terms of the hypergeometric $_{3}F_2$ function, and is non-zero unless $i+j+k+l$ is odd. See e.g. Titchmarsh (1948). This is a generalisation of the closed form in Papenbrock (2002), which is is the special case where $i+j == k+l$, but is numerically unstable for large arguments. Used in HOCartesianContactInteractions and HOCartesianEnergyConservedPerDim.

source
Rimu.Hamiltonians.ho_delta_potentialFunction
ho_delta_potential(S, i, j; [vals])

Returns the matrix element of a delta potential at the centre of a trap, i.e. the product of two harmonic oscillator functions evaluated at the origin,

\[ v_{ij} = \phi_{\mathbf{n}_i}(0) \phi_{\mathbf{n}_j}(0)\]

which is only non-zero for even-parity states. The ith single particle state corresponds to a $D$-tuple of harmonic oscillator indices $\mathbf{n}_i$. S defines the bounds of Cartesian harmonic oscillator indices for each dimension. The optional keyword argument vals allows passing pre-computed values of $\phi_i(0)$ to speed-up the calculation. The values can be calculated with log_abs_oscillator_zero.

See also HOCartesianCentralImpurity.

source

Index