About Documentation Tutorial

Documentation flint.hpp, flint_helper.hpp

Introduction

The C++ Documentation (contained completly in
flint.hpp
) is splitted into three parts (and sites): For the most operations on Tensors the interface and implementation is the same and exists twice just for type safety, so it should suffice to have a look at the multidimensional variant, but for some dimension specific operations the implementation may differ slightly.
What follows are the documentations of flint.hpp (static functions for Tensor and generators like image loading, random or constant Tensors) and flint_helper.hpp (structures and helper functions used and returned by some methods of the Tensor implementations).
The use of Tensors alone isn't enough to correctly use Flint. Especially cleaning up the library when you are finished is important to allow the backends to deallocate resources and joining Threads. The function
Flint::cleanup()
automatically cleans up all initialized backends.

flint.hpp

Overview

static void setLoggingLevel(FLogType level) 

Sets the Logging Level of the Flint Backend
static Tensor<float, 3> load_image(std::string path) 

Loads an image from the given path. The image will be stored in floating point data and the shape will be h, w, c where w is the width, h is the height and c are the chanels.
static void store_image(Tensor &t, std::string path,
								FImageFormat format) 

Expects an image in
t
with shape width, height, channels (the number of channels will be passed to stbi).
path
is the filepath to which the image should be written,
format
denotes the file type of the output file.
template <typename K, unsigned int n>
		static Tensor<K, n> concat(const Tensor &a, const Tensor &b,
								   unsigned int ax) 

Concatenates two tensors along one axis. The nodes have to have the same type and dimensions. E.g.
 Tensor<int, 3> a = {{{0, 1}, {2, 3}}, {{4, 5}, {6, 7}}};
 Tensor<int, 3> b = {{{8}, {9}}, {{10}, {11}}};
 std::cout << Flint::concat(a, b, 2)() << std::endl;
 // Tensor<int32, shape: [2, 2, 3]>(
 // [[[0, 1, 8],
 //   [2, 3, 9]],
 //  [[4, 5, 10],
 //   [6, 7, 11]]])
template <size_t n>
		static Tensor<double, (unsigned int)n>
		random_array(std::array shape) 

Creates a Tensor filled with random values in [0, 1) with the requested shape (given as an array instead of a variadic template).
template <typename... args>
		static Tensor<double, sizeof...(args)> random(args... sizes) 

Creates a Tensor filled with random values in [0, 1) with the requested shape in sizes.
template <size_t n>
		static Tensor<double, (unsigned int)n>
		random_normal(std::array shape, double sigma = 1,
					  double mu = 0) 

Creates a Tensor filled with random, normally distributed (
mu
is the mean,
sigma
is the variance) random numbers. It works by implementing the Box-Muller transformation.
template <typename T, size_t n>
		static Tensor<T, (unsigned int)n>
		constant_array(T value, std::array shape) 

Generates a Tensor containing the single given value in every entry. The resulting Tensor will have a dimensionality of
n
and a shape denoted by each entry in
shape
. e.g.
 Tensor<double, 3> foo = Flint::constant_array(3.141592,
 std::array<double, 3>(2, 2, 2)); std::cout << foo << std::endl;
 // Tensor<FLOAT64, shape: [2, 2, 2]>(
 // [[[3.141592, 3.141592],
 //  [3.141592, 3.141592]],
 // [[3.141592, 3.141592],
 //  [3.141592, 3.141592]]])
template <typename T, typename... args>
		static Tensor<T, sizeof...(args)> constant(T value, args... sizes) 

Generates a Tensor containing the single given value in every entry. The resulting Tensor will have a dimensionality of
sizeof...(args)
and a shape denoted by each entry in
sizes
. e.g.
 Tensor<double, 3> foo = Tensor<double, 3>::constant(3.141592, 2, 2,
 2); std::cout << foo << std::endl;
 // Tensor<FLOAT64, shape: [2, 2, 2]>(
 // [[[3.141592, 3.141592],
 //  [3.141592, 3.141592]],
 // [[3.141592, 3.141592],
 //  [3.141592, 3.141592]]])
template <unsigned int n>
		static Tensor<long, n> arange_array(unsigned int ax,
											std::array shape) 

Creates a int64 tensor that contains the indices relative to a given dimension
ax
for each element, i.e. each entry is its index in that corresponding dimension. If you need to index more than one dimension, create multiple such tensors with
arange
. Uses an array instead of the variadic template.
template <typename... args>
		static Tensor<long, sizeof...(args)> arange(unsigned int axis,
													args... sizes) 

Creates a int64 tensor that contains the indices relative to a given dimension
ax
for each element, i.e. each entry is its index in that corresponding dimension. If you need to index more than one dimension, create multiple such tensors with
arange
.

flint_helper.hpp

Overview

template <typename T, unsigned int n> struct Tensor

This is the base class of the C++ implementation of Flint.
Instances of a implementation of this template wrap around the
FGraphNode
struct by providing C++ style operations and a template representing the underlying datatype of the node (adding type safety) and its dimensionality (sometimes refered to as rank). That allows conversion to STL objects like the
operator*
does and dimensionality safety for operations like
operator[]
or
slice
.
When using it it behaves like a single Tensor representation (i.e. operations can be called on it, its data may be queried), but internally it may rather store applied operations and parameters for later lazy execution.
When you apply an operation to an instance it usually returns a new
Tensor
object, representing that operation applied to the old object. If eager execution is enabled (see
Flint::enable_eager_execution()
) the operation is directly executed with the generation of the new object, else it only executes if you query its data (with
operator*
or
operator[]
) or if a previous operation requires its data (keep in mind that some operations have to execute the operations of their parameters directly, because their data is already completly needed during execution e.g. reduce operations or matrix multiplication).
The template is recursively defined on the dimensionality
n
. Meaning there are two implementations: one for the basis case
n=1
and one for the general case
n>1
. The interface should not differ much, except that some operations that are dimension specific behave differently.
namespace FLINT_HPP_HELPER 

Useful helper functions used by the library itself.
template <typename T>
static inline std::string vector_string(const std::vector &vec,
									   std::string indentation = "") 

Transforms a vector of arbitrary recursive dimensions to a string
template <typename T, size_t n>
static inline std::string array_string(const std::array &vec) 

Transforms an array of arbitrary recursive dimensions to a string
template <typename T> static constexpr void is_tensor_type() 

statically checks if the given type is one of the allowed tensor types
template <typename K, typename V> static constexpr bool is_stronger() 

checks type precedence (e.g.
isStronger<int, double>() = false,
 isStronger<float, long>() = true
)
template <typename T> static constexpr FType to_flint_type() 

Transforms a C/C++ type to a
FType
inline FType higher_type(const FType a, const FType b) 

Returns the higher of two flint types
inline constexpr FType higher_type_constexpr(const FType a, const FType b) 

Returns the higher of two flint types, as a constexpr
template <typename T>
using to_float = typename std::conditional<is_int<T>(), double, T>::type

Transforms integer types to doubles (for all other types returns identity)
template <typename T, unsigned int dimensions> class TensorView

Encapsulates the data of a tensor. Is only valid as long as the Tensor is valid. Provides an interface for index operations on multidimensional data.
template <typename T> class TensorView

One dimensional TensorView, either of a one dimensional Tensor or an already indexed one. Directly accesses the result data. This TensorView is only valid as long as the original Tensor (and its data) is valid.
T &operator[](size_t index) 

Returns a read-write-reference to the index data entry of the Tensor-data. Only valid as long as the original Tensor is valid.
template <typename T, unsigned int n> class TensorView 

Multi dimensional TensorView. Indirectly indexes the data, which is only accessible when as many indices as dimensions are given. This TensorView is only valid as long as the original Tensor (and its data) is valid. Needed to abstract multidimensional indexing.
TensorView<T, n - 1> operator[](size_t index) 

Returns a new TensorView object with one more index for the current dimension (i.e. the new TensorView has one dimension less). Only valid as long as the original Tensor is valid.
struct TensorRange 

Describes a slice operation for one dimension.
struct GradientContext 

Starts a gradient context on construction and stops it on destruction. Because of the overhead it is advised to stop a gradient context as soon as possible, so try to keep the lifetime of this object as short as possible as well. For all Tensors which were constructed during the lifetime of this object the gradient to a watched variable may be computed. See
fStartGradientContext
and
fStopGradientContext
.
struct FlintContext 

Initializes Flint on construction and cleans it up on destruction. See
flintInit
and
flintCleanup
FlintContext() 

Initializes both backends
FlintContext(int backends, FLogType logging = F_INFO) 

Received a value of
FLINT_BACKEND_BOTH
,
FLINT_BACKEND_CPU
or
FLINT_BACKEND_GPU
that denotes the backend to be used and a logging level of
F_DEBUG
,
F_VERBOSE
,
F_INFO
,
F_WARNING
,
F_ERROR
(default is
F_INFO
).