---
jupytext:
  encoding: '# -*- coding: utf-8 -*-'
  formats: md:myst,ipynb
  text_representation:
    extension: .md
    format_name: myst
    format_version: 0.13
    jupytext_version: 1.16.4
kernelspec:
  display_name: Python 3 (ipykernel)
  language: python
  name: python3
---

```{code-cell}
import mmf_setup
```

```{code-cell}
mmf_setup.nbinit()
```

# Programming Interfaces

+++

To make programming easier and ensure that future versions of the code work well, we defined some programming interfaces to glue various pieces together.  This system consists of several interrelated parts.

+++

## States

At the lowest level are the various `IState` interfaces defined in the `pytimeode` project.  Objects that implement these interfaces can be used with the various evolvers provided by the `pytimeode` class.  At a minimum, the user must define the `IStateMinimal` interface (though much of this is provided by various mixin classes) and one of the following:

* `IStateForABMEvolvers`: This essentially requires that the user provide a `compute_dy_dt(dy)` method which computes the time-derivative of the state and stores it in `dy`.  This allows one to use the `pytimeode.evolvers.EvolverABM` evolver for high-precision time-evolution.  If the basis resolution is chosen correctly, one should be able to evolve with a timestep of up to `dt=0.5*state.t_scale` with values of `0.2` being quite typical.  (If `dt` must be significantly smaller, you probably do not have sufficient resolution in your state.)  One advantage of this evolver is that, if it converges, it is generally accurate.  Once convergence is broken, the evolver usually blows up, raising floating-point errors (NaNs, Inf, etc.).

* `IStateForSplitEvolvers`: This essentially requires that the user provide two methods: `apply_exp_K(dt)` and `apply_exp_V(dt, state)` which apply the exponential of the kinetic and potential operators over time interval `dt` to the state.  This requires the true matrix exponential of these operators, so (modulo clever reasoning) requires that these operators be diagonalizable in either the position (for $\op{V}$) or momentum (for $\op{K}$) bases.  If these can be implement, this gives a low-order, but unitary evolution scheme that can be used with large time-steps to get a qualitative (but usually not quantitative) idea of what is happening.  Large time-steps can be used here with imaginary time cooling to good effect.  This can also be invaluable when designing a problem and for debugging.

+++

Here we define a variety of states that implement various physical scenarios.  For example, we have different states for different bases – periodic, axial, tubes, etc. – and for different types of problems such as single-component or multi-component mixtures.

To complement these, we provide a set of experiment classes which are intended to define an experimental protocol that can be used

+++

## Experiment

+++

# Reference

+++

Here are the programmatically generated interfaces:

+++

## `IStateForABMEvolvers`

```{code-cell}
from mmfutils.interface import describe_interface
from pytimeode import interfaces
```

```{code-cell}
display(describe_interface(interfaces.IStateForABMEvolvers))
```

## `IStateForSplitEvolvers`

```{code-cell}
display(describe_interface(interfaces.IStateForSplitEvolvers))
```

## `IStateMinimal`

```{code-cell}
display(describe_interface(interfaces.IStateMinimal))
```

## `IState`

```{code-cell}
display(describe_interface(interfaces.IState))
```
