/teinst

Tensor Interoperability Standard

Primary LanguageMakefileBSD 3-Clause "New" or "Revised" LicenseBSD-3-Clause

Tensor Interoperability Standard

T["einst"]

Introduction

This project is an effort to standardize the usage of Tensor Frameworks (TF) by defining a common application programming interface (API). One of the main goals is to ease the creation of bindings for diverse programming languages. Most TF are written in C++ and make extensive use of generic programming through C++ templates. This in turn makes creating bindings burdensome.

This projects aims to define a common API in the C programming language which can access most basic functionality of these libraries. We choose to focus on C since most programming languages provide a well supported infrastructure for interfacing with C data structures. This standard strives to be as general as possible, but a trade-off must be waged. Therefore, not all features of TF can be made to fit in.

Examples

This section should be a compilation of use cases that should motivate the definition of the API. The goal is to define a series of general examples and implement them using the API of different TF.

Example 1: Coupled Cluster Energy

In this example we will consider the calculation of the simple coupled cluster energy.

\begin{equation} E_\mathrm{CC} = \frac{1}{4} ∑a, b, i, j Tabij Vijab \end{equation}

CTF

In this example we will illustrate how one uses the library Cyclops Tensor Framework (CTF).

#include <mpi.h>
#include <ctf.hpp>

template <typename F> using T = CTF::Tensor<F>;
template <typename F> using S = CTF::Scalar<F>;

template <typename F>
F ccEnergy(T<F> &t, T<F> &vhhpp) {
  S<F> energy;
  energy[""] = (0.25)
             * t["abij"]
             * vijab["ijab"]
             ;
  return energy.get_val();
}

int main() {

  int no(20)
    , nv(200)
    , order(4)
    , symmetries[] = {NS, NS, NS, NS}
    , lensT[] = {nv, nv, no, no}
    , lensV[] = {no, no, nv, nv}
    ;

  auto T<double>(order, symmetries, lensT, MPI_COMM_WORLD)
     , V<double>(order, symmetries, lensV, MPI_COMM_WORLD)
     ;

  double e(ccEnergy(T, V));
  std::cout << "Energy " << e << std::endl;

}

  • [X] Write a makefile file to download and compile CTF.
  • [ ] Write a makefile file to download and compile libtensor.
  • [ ] Write a makefile file to download and compile tiledarray.
  • [ ] Write a makefile target to compile and run examples.
  • [X] Define an example to do basic full contraction.
  • [ ] Define an example to do slicing.
  • [ ] Define an example to apply map function to values of a tensor.
  • [ ] Define an example to define sparse tensors.

Propositions

Names

  • Prefix library functions by teinst_
  • Use s, d, and z for real, double and complex types
  • Use a marker in the name to indicate if an operation is in-place. I think the default should be to have one output-only parameter and multiple const input-only parameters to functions.

Types

  • Dimensioning variables should always be given as int64
  • Use only the C native types in the API. If a struct is needed, return a pointer and provide functions to interact with the struct

Behavior and source code

  • Return a return code TEINST_SUCCESS or TEINST_FAILURE for every function call
  • Do not allocate temporary memory, let the user pass some pointers to allocated memory
  • Test preconditions and post-conditions with asserts in all functions. For example, test if dimensions are compatible and if the tensors point to allocated memory. We can also provide unsafe versions which don’t do the checks, such that the safe version
    1. tests the pre-conditions
    2. call the unsafe function
    3. tests the post-conditions
  • Provide a test for each function
  • All operations are deep (copies, allocations, etc)
  • If we have some data structures, we should make it impossible to have them incompletely filled
  • Use const whenever possible
  • All functions should be independent of the context

Functions to write

  • Convert scalars and arrays to tensors, and backwards (copy)
  • Allocate and return a pointer
  • Free the tensor
  • Test if a pointer points on an allocated tensor
  • Contractions
  • Add, subtract, multiply and divide element-wise along selected directions
  • Slicing
  • Map function
return_code = teinst_dcontr(E, "", T, "abij", V, "ijab", 0.25);