# FCIDump

### *class* FCIDump

An electronic structure Hamiltonian in FCIDump format.

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

## Definition

The FCIDump format was originally defined by Knowles and Handy, 1989 <sup>[1](#id2)</sup>.
It is a widespread format for exporting electronic structure Hamiltonians in a plain-text file.

The present data structure only stores the information relevant for constructing the second
quantized operator.
However, this implementation goes beyond the original definition by supporting unrestricted
spin data to be loaded. The table below outlines how integrals are associated with spin species
based on the intervals in which the indices fall (assuming a header with `NORB=n`):

| Integral Type      | i          | j          | k          | l          |
|--------------------|------------|------------|------------|------------|
| Constant           | ${0}$      | ${0}$      | ${0}$      | ${0}$      |
| 1-body alpha       | ${0}$      | ${0}$      | $[1,n]$    | $[1,n]$    |
| 1-body beta        | ${0}$      | ${0}$      | $[n+1,2n]$ | $[n+1,2n]$ |
| 2-body alpha-alpha | $[1,n]$    | $[1,n]$    | $[1,n]$    | $[1,n]$    |
| 2-body alpha-beta  | $[1,n]$    | $[1,n]$    | $[n+1,2n]$ | $[n+1,2n]$ |
| 2-body beta-beta   | $[n+1,2n]$ | $[n+1,2n]$ | $[n+1,2n]$ | $[n+1,2n]$ |

The only required values are the 1-body alpha-spin integrals.

The two-body integrals are expected in chemist ordering, $(ij|kl)$, matching the FCIDump
convention.

<a id="fcidump-implementation"></a>

## Implementation

The integrals are stored as flattened arrays exploiting their permutational symmetry, which is
also the layout the [`FermionOperator`](qiskit_fermions.operators.FermionOperator.html.md#qiskit_fermions.operators.FermionOperator) electronic-integral constructors expect. Writing
$n$ for the number of orbitals ([`norb`](#qiskit_fermions.operators.library.FCIDump.norb)) and
$\text{npair} = n (n + 1) / 2$, a single data structure contains up to 5 arrays:

| `one_body_a`   | $\text{npair}$                        | The $\alpha$-spin 1-body integrals.   |
|----------------|---------------------------------------|---------------------------------------|
| `one_body_b`   | $\text{npair}$                        | The $\beta$-spin 1-body integrals.    |
| `two_body_aa`  | $\text{npair} (\text{npair} + 1) / 2$ | The $\alpha\alpha$ 2-body integrals.  |
| `two_body_ab`  | $\text{npair}^2$                      | The $\alpha\beta$ 2-body integrals.   |
| `two_body_bb`  | $\text{npair} (\text{npair} + 1) / 2$ | The $\beta\beta$ 2-body integrals.    |

The 1-body arrays are the flattened lower triangle of an $(n, n)$ matrix, indexed as
`ia = i * (i + 1) // 2 + a` with `a <= i`. The `two_body_aa` and `two_body_bb` arrays are
8-fold (S8) symmetric: the flattened lower triangle of a
$(\text{npair}, \text{npair})$ matrix, whose own two axes are each such a pair index.

#### WARNING
`two_body_ab` is packed *differently* from its siblings. It is only 4-fold (S4) symmetric, so
it holds the **full** $(\text{npair}, \text{npair})$ matrix in row-major order, indexed as
`iajb = ia * npair + jb`. Its row pair indexes the $\alpha$-spin species and its column
pair the $\beta$-spin species, so it is *not* symmetric under exchanging the two pairs.

#### NOTE
You can access **read-only copies** of these internal arrays via their respective methods:
[`get_one_body_tril_a()`](#qiskit_fermions.operators.library.FCIDump.get_one_body_tril_a), [`get_one_body_tril_b()`](#qiskit_fermions.operators.library.FCIDump.get_one_body_tril_b), [`get_two_body_tril_aa()`](#qiskit_fermions.operators.library.FCIDump.get_two_body_tril_aa),
[`get_two_body_tril_ab()`](#qiskit_fermions.operators.library.FCIDump.get_two_body_tril_ab), and [`get_two_body_tril_bb()`](#qiskit_fermions.operators.library.FCIDump.get_two_body_tril_bb).

The 1-body $\beta$-spin and the $\alpha\beta$ / $\beta\beta$ 2-body arrays are
only present for a file carrying unrestricted spin data. They are absent together, so
[`is_unrestricted`](#qiskit_fermions.operators.library.FCIDump.is_unrestricted) reports on all three at once.

The stored values are the integrals as they appear in the file. In particular, they do **not**
carry the conventional factor of $\frac{1}{2}$ that the 2-body operator terms do, so a
coefficient of an operator built via [`FermionOperator.from_fcidump()`](qiskit_fermions.operators.FermionOperator.html.md#qiskit_fermions.operators.FermionOperator.from_fcidump) is half the
corresponding value returned here.

## Conversion

Operator implementations which can be constructed from an instance of [`FCIDump`](#qiskit_fermions.operators.library.FCIDump) provide
a `from_fcidump` classmethod:

| [`FermionOperator.from_fcidump()`](qiskit_fermions.operators.FermionOperator.html.md#qiskit_fermions.operators.FermionOperator.from_fcidump)   | Constructs a [`FermionOperator`](qiskit_fermions.operators.FermionOperator.html.md#qiskit_fermions.operators.FermionOperator) from an [`FCIDump`](#qiskit_fermions.operators.library.FCIDump).   |
|------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
* <a id='id2'>**[1]**</a> 1. 1. Knowles and N. C. Handy, Computer Physics Communications 54 (1989) 75-83.

### Attributes

#### constant

Returns the constant energy offset, if the file provides one.

This is the value of the integral line whose four indices are all zero, which for an
electronic structure Hamiltonian is the nuclear-repulsion energy. It is `None` when the file
carries no such line.

#### SEE ALSO
[`FermionOperator.from_fcidump()`](qiskit_fermions.operators.FermionOperator.html.md#qiskit_fermions.operators.FermionOperator.from_fcidump), which includes this value as the identity term.

```pycon
>>> from qiskit_fermions.operators.library import FCIDump
>>> fcidump = FCIDump.from_file("tests/h2.fcidump")
>>> fcidump.constant
0.7199689944489797
```

* **Returns:**
  The constant energy offset, or `None` when the file provides none.

#### is_unrestricted

Whether this data structure carries unrestricted (spin-dependent) integrals.

The $\beta$-spin 1-body and the $\alpha\beta$ / $\beta\beta$ 2-body arrays
are present exactly when this is `True`; they are absent together.

```pycon
>>> from qiskit_fermions.operators.library import FCIDump
>>> FCIDump.from_file("tests/h2.fcidump").is_unrestricted
False
>>> FCIDump.from_file("tests/heh.fcidump").is_unrestricted
True
```

* **Returns:**
  Whether the beta-spin integral arrays are present.

#### ms2

Returns twice the spin quantum number, $2S$.

This number, $2S$, is extracted from the `MS2=2S` field in the header of the FCIDump
file.

#### nelec

Returns the number of electrons.

This number is extracted from the `NELEC` field in the header of the FCIDump file.

#### norb

Returns the number of orbitals.

This number, $n$, is extracted from the `NORB=n` field in the header of the FCIDump
file.

### Methods

#### *classmethod* from_file(file_path)

Parses an FCIDump file.

Assuming you have an FCIDump file called `molecule.fcidump`, you use this method like so:

```python
from qiskit_fermions.operators.library import FCIDump

fcidump = FCIDump.from_file("molecule.fcidump")
```

* **Parameters:**
  **file_path** – the path to the FCIDump file.
* **Returns:**
  The constructed data structure.
* **Raises:**
  * [**OSError**](https://docs.python.org/3/builtins/exceptions.html#OSError) – if `file_path` cannot be opened or read.
  * [**ValueError**](https://docs.python.org/3/builtins/exceptions.html#ValueError) – if the file does not honor the FCIDump format (a missing header namelist, a
        missing `NORB` or `NELEC` field, or a malformed `MS2` field), or if it carries
        an MO energy value, which is not supported yet.

#### get_one_body_tril_a()

Returns a read-only copy of the $\alpha$-spin 1-body integrals.

#### NOTE
This method returns a **copy** of the internal data.

#### SEE ALSO
The explanation of the internal data structure, [here](#fcidump-implementation), and
[`FermionOperator.from_1body_tril_spin_sym()`](qiskit_fermions.operators.FermionOperator.html.md#qiskit_fermions.operators.FermionOperator.from_1body_tril_spin_sym), which consumes this array.

```pycon
>>> from qiskit_fermions.operators.library import FCIDump
>>> fcidump = FCIDump.from_file("tests/h2.fcidump")
>>> fcidump.get_one_body_tril_a().shape
(3,)
```

* **Returns:**
  The flattened lower-triangular 1-body integrals, of length
  $\text{npair} = n (n + 1) / 2$.

#### get_one_body_tril_b()

Returns a read-only copy of the $\beta$-spin 1-body integrals.

#### NOTE
This method returns a **copy** of the internal data.

#### SEE ALSO
The explanation of the internal data structure, [here](#fcidump-implementation), and
[`FermionOperator.from_1body_tril_spin()`](qiskit_fermions.operators.FermionOperator.html.md#qiskit_fermions.operators.FermionOperator.from_1body_tril_spin), which consumes this array.

* **Returns:**
  The flattened lower-triangular 1-body integrals, of length
  $\text{npair} = n (n + 1) / 2$, or `None` when
  [`is_unrestricted`](#qiskit_fermions.operators.library.FCIDump.is_unrestricted) is `False`.

#### get_two_body_tril_aa()

Returns a read-only copy of the $\alpha\alpha$-spin 2-body integrals.

The values are in chemist ordering, $(ij|kl)$, and carry no factor of
$\frac{1}{2}$.

#### NOTE
This method returns a **copy** of the internal data.

#### SEE ALSO
The explanation of the internal data structure, [here](#fcidump-implementation), and
[`FermionOperator.from_2body_tril_spin_sym()`](qiskit_fermions.operators.FermionOperator.html.md#qiskit_fermions.operators.FermionOperator.from_2body_tril_spin_sym), which consumes this array.

```pycon
>>> from qiskit_fermions.operators.library import FCIDump
>>> fcidump = FCIDump.from_file("tests/h2.fcidump")
>>> fcidump.get_two_body_tril_aa().shape
(6,)
```

* **Returns:**
  The 8-fold symmetric (S8) flattened 2-body integrals, of length
  $\text{npair} (\text{npair} + 1) / 2$.

#### get_two_body_tril_ab()

Returns a read-only copy of the $\alpha\beta$-spin 2-body integrals.

The values are in chemist ordering, $(ij|kl)$, and carry no factor of
$\frac{1}{2}$.

#### WARNING
Unlike the other 2-body arrays, this one is only 4-fold (S4) symmetric: it holds the
**full** $(\text{npair}, \text{npair})$ matrix, whose row pair indexes the
$\alpha$-spin and whose column pair indexes the $\beta$-spin species. It is
therefore *not* symmetric under exchanging the two pairs.

#### NOTE
This method returns a **copy** of the internal data.

#### SEE ALSO
The explanation of the internal data structure, [here](#fcidump-implementation), and
[`FermionOperator.from_2body_tril_spin()`](qiskit_fermions.operators.FermionOperator.html.md#qiskit_fermions.operators.FermionOperator.from_2body_tril_spin), which consumes this array.

* **Returns:**
  The 4-fold symmetric (S4) flattened 2-body integrals, of length
  $\text{npair}^2$, or `None` when [`is_unrestricted`](#qiskit_fermions.operators.library.FCIDump.is_unrestricted) is `False`.

#### get_two_body_tril_bb()

Returns a read-only copy of the $\beta\beta$-spin 2-body integrals.

The values are in chemist ordering, $(ij|kl)$, and carry no factor of
$\frac{1}{2}$.

#### NOTE
This method returns a **copy** of the internal data.

#### SEE ALSO
The explanation of the internal data structure, [here](#fcidump-implementation), and
[`FermionOperator.from_2body_tril_spin()`](qiskit_fermions.operators.FermionOperator.html.md#qiskit_fermions.operators.FermionOperator.from_2body_tril_spin), which consumes this array.

* **Returns:**
  The 8-fold symmetric (S8) flattened 2-body integrals, of length
  $\text{npair} (\text{npair} + 1) / 2$, or `None` when
  [`is_unrestricted`](#qiskit_fermions.operators.library.FCIDump.is_unrestricted) is `False`.
