C++ API

Generated from the //! doc-comments in source/silt via Doxygen and Breathe, one section per header, grouped the same way the source tree already is (core/, op/) rather than by C++ namespace – namespaces don’t otherwise carve up this library, so file/directory grouping is the natural fit. Internal helpers (the detail namespaces, see Design Details) are excluded throughout.

Core

The tensor/view type hierarchy, shape and slice arithmetic, dtype dispatch, and error types.

namespace silt
namespace error
template<typename From, typename To>
struct cast_error : public std::exception

Public Functions

inline cast_error()
inline const char *what() const noexcept override

Private Members

std::string msg
struct mismatch_size : public std::exception

Public Functions

inline mismatch_size(size_t want, size_t have)
inline const char *what() const noexcept override

Private Members

std::string msg
struct mismatch_type : public std::exception

Public Functions

inline mismatch_type(dtype want, dtype have)
inline const char *what() const noexcept override

Private Members

std::string msg
struct mismatch_host : public std::exception

Public Functions

inline mismatch_host(host_t want, host_t have)
inline const char *what() const noexcept override

Private Members

std::string msg
struct out_of_bounds : public std::exception

Public Functions

inline out_of_bounds(size_t index, size_t max)
inline const char *what() const noexcept override

Private Members

std::string msg
struct bad_reshape : public std::exception

Public Functions

inline bad_reshape(size_t want, size_t have)
inline const char *what() const noexcept override

Private Members

std::string msg
struct unsupported_host : public std::exception

Public Functions

inline unsupported_host(host_t want, host_t have)
inline const char *what() const noexcept override

Private Members

std::string msg
struct uninitialized : public std::exception

Public Functions

inline const char *what() const noexcept override
struct missing_file : public std::exception

Public Functions

inline missing_file(std::string file)
inline const char *what() const noexcept override

Private Members

std::string msg
namespace silt

Typedefs

typedef curandState rng

Enums

enum host_t

Compute Device Enumerator.

Values:

enumerator CPU
enumerator GPU
enum dtype

Type Descriptor Enumerator.

Values:

enumerator NONE
enumerator INT32
enumerator FLOAT32
enumerator FLOAT64
enumerator RNG
enumerator INT64

Functions

template<typename F, typename ...Args>
auto select(const silt::host_t host, F lambda, Args&&... args)
template<typename F, typename ...Args>
auto select(const silt::dtype type, F lambda, Args&&... args)

select accepts a type enumerator and a templated lambda, which it subsequently calls with a strict-typed evaluation.

this effectively instantiates every required template of the desired lambda expression, and executes the runtime selection.

template<typename ...Types>
struct dtype_list
template<>
struct hostdesc

Public Static Attributes

static constexpr const char *name = "CPU"
template<>
struct hostdesc

Public Static Attributes

static constexpr const char *name = "GPU"
template<typename Type, typename F>
struct type_op_error : public std::exception

Public Functions

inline type_op_error(F lambda)
inline const char *what() const noexcept override

Private Members

std::string msg
struct typedbase

Subclassed by silt::tensor_t< int64_t >, silt::tensor_t< T >, silt::view_t< T >

Public Functions

inline virtual ~typedbase()
inline virtual constexpr silt::dtype type() noexcept
template<typename T>
struct typedesc
#include <types.hpp>

typedesc is a generic compile-time type descriptor, which provides common properties like string names, or statically related types for specific purposes.

Public Types

typedef void value_t

Public Static Attributes

static constexpr const char *name = "none"
static constexpr dtype type = NONE
template<>
struct typedesc

Public Types

typedef double value_t

Public Static Attributes

static constexpr const char *name = "double"
static constexpr dtype type = FLOAT64
template<>
struct typedesc

Public Types

typedef float value_t

Public Static Attributes

static constexpr const char *name = "float"
static constexpr dtype type = FLOAT32
template<>
struct typedesc

Public Types

typedef int value_t

Public Static Attributes

static constexpr const char *name = "int"
static constexpr dtype type = INT32
template<>
struct typedesc

Public Types

typedef int64_t value_t

Public Static Attributes

static constexpr const char *name = "int64"
static constexpr dtype type = INT64
template<>
struct typedesc

Public Types

typedef rng value_t

Public Static Attributes

static constexpr const char *name = "rng"
static constexpr dtype type = RNG
namespace silt

Typedefs

template<size_t D>
using ivec = glm::vec<D, int, defaultp>
template<size_t D>
using uvec = glm::vec<D, unsigned int, defaultp>
template<size_t D>
using fvec = glm::vec<D, float, defaultp>
template<size_t D>
using dvec = glm::vec<D, double, defaultp>
template<size_t D>
using vec = fvec<D>
using ivec1 = ivec<1>
using ivec2 = ivec<2>
using ivec3 = ivec<3>
using ivec4 = ivec<4>
using uvec1 = uvec<1>
using uvec2 = uvec<2>
using uvec3 = uvec<3>
using uvec4 = uvec<4>
using fvec1 = fvec<1>
using fvec2 = fvec<2>
using fvec3 = fvec<3>
using fvec4 = fvec<4>
using dvec1 = dvec<1>
using dvec2 = dvec<2>
using dvec3 = dvec<3>
using dvec4 = dvec<4>
using vec1 = vec<1>
using vec2 = vec<2>
using vec3 = vec<3>
using vec4 = vec<4>

Variables

constexpr auto defaultp = glm::qualifier::packed_highp
namespace silt
struct shape
#include <shape.hpp>

shape is a D-dimensional compact extent, with indexing procedures for lookup into linearized tensors and views.

shape is intended for 2D and 3D applications, with a D of max 4, for 3D buffers of arbitrary depth.

Note that we use count_dim and count_elem methods so that higher nested dimensions can still contribute to the shape.

Todo:

simplify flattening / unflattening procedures.

Public Types

using vec_t = glm::vec<4, int>

Public Functions

inline shape(int d0, int d1, int d2, int d3)
inline shape(int d0, int d1, int d2)
inline shape(int d0, int d1)
inline shape(int d0)
inline shape()
inline int dim() const
inline int64_t elem() const
inline vec_t ext() const
inline int operator[](const size_t d) const

Dimension Subscript Operator.

inline bool oob(const vec_t pos) const

Out-Of-Bounds Check (Compact).

inline bool oob(const silt::ivec2 pos) const
inline bool oob(const silt::ivec3 pos) const
inline int64_t flatten(const silt::ivec2 pos) const
inline int64_t flatten(const silt::ivec3 pos) const
inline int64_t flatten(const vec_t pos) const

Flattening Operator.

inline vec_t unflatten(const int64_t index) const

Unflattening Operator.

inline void reshape(int d0, int d1 = 1, int d2 = 1, int d3 = 1)

Public Static Functions

static inline int64_t count_elem(const vec_t ext)
static inline int count_dim(const vec_t ext)

Private Members

int _dim

Total Number of Active Dimensions.

int64_t _elem

Total Number of Elements.

vec_t _ext

Per-Dimension Extent.

namespace silt
struct slice
#include <slice.hpp>

slice is a type for index conversions that supports multi-dimensional slicing.

This type exists primarily so that tensor operations can be executed on subspaces. This is distinct from a shape because it performs additional computations to transform coordinates, whereas the regular shape assumes densely packed regular data.

Todo:

Consider copy-free transpositions and other ordering implementations.

Public Types

using vec_t = glm::vec<4, int>

Public Functions

inline slice(int d0, int d1, int d2, int d3)
inline slice(int d0, int d1, int d2)
inline slice(int d0, int d1)
inline slice(int d0)
inline slice()
inline slice(const silt::shape shape)
inline silt::shape shape() const
inline int dim() const
inline int64_t maxelem() const
inline vec_t offset() const
inline vec_t stride() const
inline vec_t extent() const
inline int64_t elem() const
inline void reshape(int d0, int d1 = 1, int d2 = 1, int d3 = 1)
inline void flatten()
inline void index(const int dim, int offset, int stride, int extent)

Slice Index along individual Dimension. This is the single place slicing is validated and clamped – callers (e.g. the Python getitem binding) should unpack raw offset/stride/ extent and forward here rather than re-implementing this logic.

inline void reset()
inline int64_t transform(const int64_t index) const

Private Functions

inline vec_t _unflatten(const int64_t index) const

Compute the Position in Slice-Space.

Private Members

silt::shape _shape

Underlying Shape.

vec_t _offset

Per-Dimension Offset.

vec_t _stride

Per-Dimension Stride.

vec_t _extent

Per-Dimension Extent.

namespace silt
template<typename T>
struct view_t : public silt::typedbase
#include <view_t.hpp>

view_t is a strict-typed, lightweight data-view for vectorized memory reads.

A view_t is intended to be constructed on the fly from another data-type, so that any memory read operations from the view are compiler optimized.

The view is non-owning and shares its underlying memory, so that it can be passed cheaply while the owning data-types remaing untouched.

A check to see whether the construction of a view is valid should be done at construction time, and not at lookup time, to guarantee performance.

Public Types

typedef T val_t

Public Functions

inline view_t()
inline view_t(const silt::slice slice, const host_t host, T *data)
inline silt::slice slice() const

View Sliced Shape.

inline size_t elem() const

Number of Elements.

inline host_t host() const

Current Device (CPU / GPU).

inline const T *data() const

Raw Data Pointer (Const).

inline T *data()

Raw Data Pointer (Mutable).

inline virtual constexpr silt::dtype type() noexcept

Type Enumerator Retrieval.

inline T operator[](const size_t index) const noexcept

Const Subscript Operator: With Slice Transform!

inline T &operator[](const size_t index) noexcept

Non-Const Subscript Operator: With Slice Transform!

inline void reshape(int d0, int d1, int d2, int d3)
inline void index(const int dim, const int offset, const int stride, const int extent)
inline void reset()

Private Members

silt::slice _slice

Sliced Shape of Data.

host_t _host = CPU

Compute Device Location.

T *_data = NULL

Raw Data Pointer.

namespace silt
struct view
#include <view.hpp>

view is a tag-poylymorphic view_t wrapper type.

Public Functions

view() = default
inline view(const silt::view &rhs)

Polymorphic Tensor Copy Constructor.

inline view(silt::view &&rhs) noexcept

Polymorphic Tensor Move Constructor.

template<typename T>
inline view(const silt::view_t<T> &view, silt::tensor owner = silt::tensor())

Strict-Typed Tensor Copy Constructor. owner, if given, is kept alive for as long as this view is – see the non-owning-view lifetime note on view_t in view_t.hpp. Defaults to nothing, preserving the non-owning behaviour for internal constructions that don’t need it (e.g. views never handed to Python).

template<typename T>
inline view(silt::view_t<T> &&ten, silt::tensor owner = silt::tensor())

Strict-Typed Tensor Move Constructor.

inline ~view()
inline view &operator=(const silt::view &rhs)

Copy Assignment Operator.

inline view &operator=(silt::view &&rhs) noexcept

Move Assignment Operator.

template<typename T>
inline const view_t<T> &as() const noexcept

Polymorphic Strict-Type Cast (Const).

template<typename T>
inline view_t<T> &as() noexcept

Polymorphic Strict-Type Cast (Mutable).

inline silt::dtype type() const
inline silt::slice slice() const
inline silt::host_t host() const
inline size_t elem() const
inline void *data()
inline void reshape(int d0, int d1, int d2, int d3)
inline void index(const int dim, const int offset, const int stride, const int extent)
inline void reset()

Private Functions

inline void clear()
inline typedbase *clone() const

Clone the implementation pointer with new.

Private Members

typedbase *impl = NULL

Polymorphic Implementation Pointer

silt::tensor _owner

Keeps a slice’s source tensor alive by refcount (see the constructor above). A silt::tensor, not std::shared_ptr, for the same DLL-boundary reason tensor itself avoids std::shared_ptr (see its comment above).

namespace silt
template<typename T>
struct tensor_t : public silt::typedbase
#include <tensor_t.hpp>

tensor_t<T> is a strict-typed, owning raw-data extent.

tensor_t<T> is reference counting with correct move semantics, making copying and moving tensor_t<T> values cheap and easy.

tensor_t<T> data can be on the CPU or on the GPU.

Public Types

typedef T val_t

Public Functions

inline tensor_t()

Default Empty Constructor.

inline tensor_t(const shape shape, const host_t host = CPU)

Allocating Constructor.

inline tensor_t(T *data, const shape shape, const host_t host = CPU)

Non-Allocating Constructor.

inline ~tensor_t()
inline tensor_t(const tensor_t<T> &other)

Copy Constructor (Reference Increment).

inline tensor_t &operator=(const tensor_t<T> &other)

Copy Assignment Operator (Reference Increment).

inline tensor_t(tensor_t<T> &&other)

Move Constructor (Reference Steal).

inline tensor_t &operator=(tensor_t<T> &&other)

Move Assginmment Operator (Reference Steal).

inline silt::shape shape() const
inline size_t elem() const

Number of Elements.

inline size_t size() const

Total Size in Bytes.

inline size_t refs() const

Reference Count (0 if non-owning).

inline host_t host() const

Current Device (CPU / GPU).

inline const T *data() const

Raw Data Pointer (Const).

inline T *data()

Raw Data Pointer (Mutable).

inline virtual constexpr silt::dtype type() noexcept

Type Enumerator Retrieval.

inline T operator[](const size_t index) const noexcept

Const Subscript Operator (Flat).

inline T &operator[](const size_t index) noexcept

Non-Const Subscript Operator (Float).

template<typename S>
inline view_t<S> view() noexcept
template<typename S>
inline view_t<const S> view() const noexcept
inline void reshape(const int d0 = 1, const int d1 = 1, const int d2 = 1, const int d3 = 1)
inline void flatten()
void to(const host_t target)

In-Place Transfer to target – the guard logic (no-op if already on target, or if there is nothing to move) lives here; to_cpu()/ to_gpu() are simple aliases for it.

void to_cpu()

Alias for to(CPU).

void to_gpu()

Alias for to(GPU).

tensor_t<T> copy_to(const host_t target) const

Return an independent copy of this tensor’s data on target. Covers all four host pairings (CPU/GPU source x CPU/GPU target); copy_to(host()) is a same-host deep copy.

Public Members

size_t *_refs = NULL

Pointer to Reference Count.

Private Functions

void allocate(const silt::shape shape, const host_t host = CPU)

Device-Aware Allocation and De-Allocation.

void deallocate()

Private Members

silt::shape _shape

Shape of Data.

host_t _host = CPU

Currently Active Device.

T *_data = NULL

Raw Data Pointer (Device Agnostic).

namespace silt
struct tensor
#include <tensor.hpp>

tensor is a tag-poylymorphic tensor_t wrapper type.

This type stores a pointer to a tensor_t<T>, which it can cast to the appropriate type when required.

Because of the dll exported type, tensor cannot use std::shared pointer, which is why we do the funny business with the move and copy constructors:

Public Functions

tensor() = default
inline tensor(const silt::dtype type, const silt::shape shape)
inline tensor(const silt::dtype type, const silt::shape shape, const host_t host)
inline tensor(const silt::tensor &rhs)

Polymorphic Tensor Copy Constructor.

inline tensor(silt::tensor &&rhs) noexcept

Polymorphic Tensor Move Constructor.

template<typename T>
inline tensor(const silt::tensor_t<T> &ten)

Strict-Typed Tensor Copy Constructor.

template<typename T>
inline tensor(silt::tensor_t<T> &&ten)

Strict-Typed Tensor Move Constructor.

inline ~tensor()
inline tensor &operator=(const silt::tensor &rhs)

Copy Assignment Operator.

inline tensor &operator=(silt::tensor &&rhs) noexcept

Move Assignment Operator.

template<typename T>
inline const tensor_t<T> &as() const noexcept

Polymorphic Strict-Type Cast (Const).

template<typename T>
inline tensor_t<T> &as() noexcept

Polymorphic Strict-Type Cast (Mutable).

inline silt::dtype type() const
inline silt::shape shape() const
inline silt::host_t host() const
inline size_t elem() const
inline size_t size() const
inline size_t refs() const
inline void *data()
inline void reshape(const int d0 = 1, const int d1 = 1, const int d2 = 1, const int d3 = 1)
inline void flatten()

Private Functions

inline void clear()
inline typedbase *clone() const

Clone the implementation pointer with new.

Private Members

typedbase *impl = NULL

Polymorphic Implementation Pointer.

Private Static Functions

static inline typedbase *make(const silt::dtype type, const silt::shape shape, const host_t host = CPU)

Make a new Strict-Typed Tensor.

namespace silt

Enums

enum copy_t

copy_t mirrors the cudaMemcpyKind enumerator

Values:

enumerator HOST_TO_HOST
enumerator HOST_TO_DEVICE
enumerator DEVICE_TO_HOST
enumerator DEVICE_TO_DEVICE
enumerator DEFAULT

Functions

void *device_alloc(size_t bytes)
void device_free(void *ptr)
void device_copy(void *dst, const void *src, size_t bytes, copy_t copy)
void synchronize()

Block until all queued GPU work completes, and raise silt::error::cuda_error if any of it (including a kernel launched earlier) failed.

namespace silt
namespace op

Functions

template<typename T, typename F>
void uniop_inplace(T lhs, F func)
template<typename T, typename F>
void binop_inplace(T lhs, const T rhs, F func)
template<typename T, typename F>
void indexed_apply(tensor_t<T> lhs, const tensor_t<int64_t> ind, F func)
template<typename T, typename F>
void indexed_binop_apply(tensor_t<T> lhs, const tensor_t<T> rhs, const tensor_t<int64_t> ind, F func)

Operations

Tensor operations, dispatched through silt::op – also the extension point user code hooks into to add new operations (see Extending silt).

namespace silt

Functions

template<typename T>
void set(tensor_t<T> lhs, const T value)
template<typename T>
void set(view_t<T> lhs, const T value)
template<typename T>
void add(tensor_t<T> lhs, const T value)
template<typename T>
void add(view_t<T> lhs, const T value)
template<typename T>
void multiply(tensor_t<T> lhs, const T value)
template<typename T>
void multiply(view_t<T> lhs, const T value)
template<typename T>
void divide(tensor_t<T> lhs, const T value)
template<typename T>
void divide(view_t<T> lhs, const T value)
template<typename T>
void clamp(tensor_t<T> lhs, const T min, const T max)
template<typename T>
void clamp(view_t<T> lhs, const T min, const T max)
template<typename T>
void minimum(tensor_t<T> lhs, const T value)
template<typename T>
void minimum(view_t<T> lhs, const T value)
template<typename T>
void maximum(tensor_t<T> lhs, const T value)
template<typename T>
void maximum(view_t<T> lhs, const T value)
template<typename T>
void set(tensor_t<T> lhs, const tensor_t<T> rhs)
template<typename T>
void add(tensor_t<T> lhs, const tensor_t<T> rhs)
template<typename T>
void multiply(tensor_t<T> lhs, const tensor_t<T> rhs)
template<typename T>
void divide(tensor_t<T> lhs, const tensor_t<T> rhs)
template<typename T>
void mix(tensor_t<T> lhs, const tensor_t<T> rhs, const float w)
template<typename T>
void minimum(tensor_t<T> lhs, const tensor_t<T> rhs)
template<typename T>
void maximum(tensor_t<T> lhs, const tensor_t<T> rhs)
template<typename To, typename From>
silt::tensor_t<To> cast(const silt::tensor_t<From> &tensor)
namespace silt

Typedefs

using index_t = tensor_t<int64_t>

Functions

template<typename F>
index_t make_index_set(const silt::shape shape, F predicate)
index_t index_radius(const silt::shape shape, const silt::vec2 center, const float radius)
index_t index_box(const silt::shape shape, const silt::vec2 lo, const silt::vec2 hi)
index_t index_polygon(const silt::shape shape, const tensor_t<silt::vec2> &vertices)
index_t index_slice(const silt::slice &slice)

Flat indices of every cell a slice (offset/stride/extent per dimension) visits, in slice order. Enumeration, not compaction – every candidate is included, so this needs no predicate.

template<typename T>
constexpr T positive_infinity()

+infinity for T (numeric_limits::max() for an integral T, which has no infinity).

template<typename T>
constexpr T negative_infinity()

-infinity for T (numeric_limits::min() for an integral T, which has no infinity).

template<typename T>
index_t index_range(const tensor_t<T> &data, const T lo, const T hi)

Selects by value rather than position: lo <= data[n] <= hi.

template<typename T>
index_t index_greater(const tensor_t<T> &data, const T value)

Alias for index_range(data, value, +infinity) – data[n] >= value.

template<typename T>
index_t index_lesser(const tensor_t<T> &data, const T value)

Alias for index_range(data, -infinity, value) – data[n] <= value.

template<typename T>
index_t index_match(const tensor_t<T> &data, const T value)

Alias for index_range(data, value, value) – data[n] == value.

template<typename T>
void indexed_set(tensor_t<T> lhs, const T rhs, const index_t ind)

lhs[i] = rhs, for i in ind.

template<typename T>
void indexed_add(tensor_t<T> lhs, const T rhs, const index_t ind)

lhs[i] += rhs, for i in ind.

template<typename T>
void indexed_add(tensor_t<T> lhs, const tensor_t<T> rhs, const index_t ind)

lhs[i] += rhs[i], for i in ind.

template<typename T>
void indexed_multiply(tensor_t<T> lhs, const T rhs, const index_t ind)

lhs[i] *= rhs, for i in ind.

template<typename T>
void indexed_multiply(tensor_t<T> lhs, const tensor_t<T> rhs, const index_t ind)

lhs[i] *= rhs[i], for i in ind.

template<typename T>
void indexed_divide(tensor_t<T> lhs, const T rhs, const index_t ind)

lhs[i] /= rhs, for i in ind.

template<typename T>
void indexed_divide(tensor_t<T> lhs, const tensor_t<T> rhs, const index_t ind)

lhs[i] /= rhs[i], for i in ind.

template<typename T>
void indexed_mix(tensor_t<T> lhs, const tensor_t<T> rhs, const index_t ind, const float w)

lhs[i] = mix(lhs[i], rhs[i], w), for i in ind.

template<typename T>
T indexed_sum(const tensor_t<T> lhs, const index_t ind)

Sum of lhs[i], for i in ind.

template<typename T>
T indexed_mean(const tensor_t<T> lhs, const index_t ind)

Mean of lhs[i], for i in ind.

template<typename T>
T indexed_min(const tensor_t<T> lhs, const index_t ind)

Min of lhs[i], for i in ind. NaN-skipping, like the dense min().

template<typename T>
T indexed_max(const tensor_t<T> lhs, const index_t ind)

Max of lhs[i], for i in ind. NaN-skipping, like the dense max().

template<typename T>
int64_t indexed_argmin(const tensor_t<T> lhs, const index_t ind)

Flat index into lhs of the minimal element among lhs[i], i in ind.

template<typename T>
int64_t indexed_argmax(const tensor_t<T> lhs, const index_t ind)

Flat index into lhs of the maximal element among lhs[i], i in ind.

struct box_predicate
#include <indexed.hpp>

All cells in the half-open box [lo, hi).

Public Functions

inline bool operator()(const int64_t n) const

Public Members

silt::shape shape
silt::vec2 lo
silt::vec2 hi
struct polygon_predicate
#include <indexed.hpp>

Point-in-polygon (even-odd / ray-casting rule).

Public Functions

inline bool operator()(const int64_t n) const

Public Members

silt::shape shape
const silt::vec2 *vertices
int count
struct radius_predicate
#include <indexed.hpp>

All cells within radius of center (Euclidean, in cell units).

Public Functions

inline bool operator()(const int64_t n) const

Public Members

silt::shape shape
silt::vec2 center
float radius
template<typename T>
struct range_predicate
#include <indexed.hpp>

All cells where lo <= data[n] <= hi (closed interval).

Public Functions

inline bool operator()(const int64_t n) const

Public Members

const T *data
T lo
T hi
namespace silt

Functions

void seed(tensor_t<rng> &buf, const size_t seed, const size_t offset)

Seed a Random Number Generator Tensor.

tensor_t<float> sample_uniform(tensor_t<rng> &buf)

Generate Uniform Samples from a Random Number Generator Tensor.

tensor_t<float> sample_uniform(tensor_t<rng> &buf, const float min, const float max)
tensor_t<float> sample_normal(tensor_t<rng> &buf)

Generate Normal Distributed Samples from a Random Number Generator Tensor.

tensor_t<float> sample_normal(tensor_t<rng> &buf, const float mean, const float std)