Skip to content

Latest commit

 

History

History
2449 lines (1958 loc) · 83.2 KB

BLISObjectAPI.md

File metadata and controls

2449 lines (1958 loc) · 83.2 KB

Contents

Operation index

This index provides a quick way to jump directly to the description for each operation discussed later in the Computational function reference section:

Introduction

This document summarizes one of the primary native APIs in BLIS--the object API. Here, we also discuss BLIS-specific type definitions, header files, and prototypes to auxiliary functions.

There are many functions that BLIS implements that are not listed here, either because they are lower-level functions, or they are considered for use primarily by developers and experts.

The object API was given its name (a) because it abstracts the floating-point types of its operands (along with many other properties) within a typedef struct {...} data structure, and (b) to contrast it with the other native API in BLIS, the typed API, which is documented here. (The third API supported by BLIS is the BLAS compatibility layer, which mimics conventional Fortran-77 BLAS.)

In general, this document should be treated more as a reference than a place to learn how to use BLIS in your application. Thus, we highly encourage all readers to first study the example code provided within the BLIS source distribution.

BLIS types

The following tables list various types used throughout the BLIS object API.

Integer-based types

BLIS integer type Type definition Used to represent...
gint_t int32_t or int64_t general-purpose signed integer; used to define signed integer types.
guint_t uint32_t or uint64_t general-purpose signed integer; used to define signed integer types.
dim_t gint_t matrix and vector dimensions.
inc_t gint_t matrix row/column strides and vector increments.
doff_t gint_t matrix diagonal offset: if k < 0, diagonal begins at element (-k,0); otherwise diagonal begins at element (0,k).
siz_t guint_t a byte size or byte offset.

Floating-point types

BLIS fp type Type definition Used to represent...
float N/A single-precision real numbers.
double N/A double-precision real numbers.
scomplex struct { float real; float imag; } single-precision complex numbers.
dcomplex struct { double real; double imag; } double-precision complex numbers.

Enumerated parameter types

num_t Semantic meaning: Matrix/vector operand...
BLIS_FLOAT contains single-precision real elements.
BLIS_DOUBLE contains double-precision real elements.
BLIS_SCOMPLEX contains single-precision complex elements.
BLIS_DCOMPLEX contains double-precision complex elements.
BLIS_INT contains integer elements of type gint_t.
BLIS_CONSTANT contains polymorphic representation of a constant value.
dom_t Semantic meaning: Matrix/vector operand...
BLIS_REAL contains real domain elements.
BLIS_COMPLEX contains complex domain elements.
prec_t Semantic meaning: Matrix/vector operand...
BLIS_SINGLE_PREC contains single-precision elements.
BLIS_DOUBLE_PREC contains double-precision elements.
trans_t Semantic meaning: Matrix operand ...
BLIS_NO_TRANSPOSE will be used as given.
BLIS_TRANSPOSE will be implicitly transposed.
BLIS_CONJ_NO_TRANSPOSE will be implicitly conjugated.
BLIS_CONJ_TRANSPOSE will be implicitly transposed and conjugated.
conj_t Semantic meaning: Matrix/vector operand...
BLIS_NO_CONJUGATE will be used as given.
BLIS_CONJUGATE will be implicitly conjugated.
side_t Semantic meaning: Matrix operand...
BLIS_LEFT appears on the left.
BLIS_RIGHT appears on the right.
struc_t Semantic meaning: Matrix operand...
BLIS_GENERAL has no structure.
BLIS_HERMITIAN has Hermitian structure.
BLIS_SYMMETRIC has symmetric structure.
BLIS_TRIANGULAR has triangular structure.
uplo_t Semantic meaning: Matrix operand...
BLIS_LOWER is stored in (and will be accessed only from) the lower triangle.
BLIS_UPPER is stored in (and will be accessed only from) the upper triangle.
BLIS_DENSE is stored as a full matrix (ie: in both triangles).
diag_t Semantic meaning: Matrix operand ...
BLIS_NONUNIT_DIAG has a non-unit diagonal that should be explicitly read from.
BLIS_UNIT_DIAG has a unit diagonal that should be implicitly assumed (and not read from).

Global scalar constants

BLIS defines a handful of scalar objects that conveniently represent various constant values for all defined numerical type values (num_t). The following table lists the constants defined by BLIS.

BLIS constant obj_t name Numerical values
BLIS_MINUS_TWO -2.0
BLIS_MINUS_ONE -1.0
BLIS_ZERO 0.0
BLIS_ONE 1.0
BLIS_TWO 2.0

These objects are polymorphic; each one contains a float, double, scomplex, dcomplex, and gint_t representation of the constant value in question. They can be used in place of any obj_t* operand in any object API function provided that the following criteria are met:

  • The object parameter requires unit dimensions (1x1). (In other words, the function expects a scalar for the operand in question.)
  • The object parameter is input-only. (In other words, the function is not trying to update the scalar.) The correct representation is chosen by context, usually by inspecting the datatype of one of the other operands involved in an operation. For example, if we create and initialize objects x and y of num_t type BLIS_DOUBLE, the following call to bli_axpyv()
    bli_axpyv( &BLIS_TWO, &x, &y );
    will use the BLIS_DOUBLE representation of BLIS_TWO.

Basic vs expert interfaces

The functions listed in this document belong to the "basic" interface subset of the BLIS object API. There is a companion "expert" interface that mirrors the basic interface, except that it also contains two additional parameters that are only of interest to experts and library developers. The expert interfaces use the same name as the basic function names, except for an additional "_ex" suffix. For example, the basic interface for gemm is

void bli_gemm
     (
       obj_t*  alpha,
       obj_t*  a,
       obj_t*  b,
       obj_t*  beta,
       obj_t*  c,
     );

while the expert interface is:

void bli_gemm_ex
     (
       obj_t*   alpha,
       obj_t*   a,
       obj_t*   b,
       obj_t*   beta,
       obj_t*   c,
       cntx_t*  cntx,
       rntm_t*  rntm
     );

The expert interface contains two additional parameters: a cntx_t* and rntm_t*. Note that calling a function from the expert interface with the cntx_t* and rntm_t* arguments each set to NULL is equivalent to calling the corresponding basic interface. Specifically, a NULL value passed in for the cntx_t* results in a valid context being queried from BLIS, and a NULL value passed in for the rntm_t* results in the current global settings for multithreading to be used.

Context type

In general, it is permissible to pass in NULL for a cntx_t* parameter when calling an expert interface such as bli_gemm_ex(). However, there are cases where NULL values are not accepted and may result in a segmentation fault. Specifically, the cntx_t* argument appears in the interfaces to the gemm, trsm, and gemmtrsm level-3 microkernels along with all level-1v and level-1f kernels. There, as a general rule, a valid pointer must be passed in. Whenever a valid context is needed, the developer may query a default context from the global kernel structure (if a context is not already available in the current scope):

cntx_t* bli_gks_query_cntx( void );

When BLIS is configured to target a configuration family (e.g. intel64, x86_64), bli_gks_query_cntx() will use cpuid or an equivalent heuristic to select and and return the appropriate context. When BLIS is configured to target a singleton sub-configuration (e.g. haswell, skx), bli_gks_query_cntx() will unconditionally return a pointer to the context appropriate for the targeted configuration.

Runtime type

When calling one of the expert interfaces, a rntm_t (runtime) object can be used to convey a thread-local request for parallelism to the underlying implementation. Runtime objects are thread-safe by nature when they are declared statically as a stack variable (or allocated via malloc()), initialized, and then passed into the expert interface of interest.

Notice that runtime objects have no analogue in most BLAS libraries, where you are forced to specify parallelism at a global level (usually via environment variables).

For more information on using rntm_t objects, please read the Multithreading documentation, paying close attention to the section on local setting of parallelism.

BLIS header file

All BLIS definitions and prototypes may be included in your C source file by including a single header file:

#include "blis.h"

Initialization and Cleanup

As of 9804adf, BLIS no longer requires explicit initialization and finalization at runtime. In other words, users do not need to call bli_init() before the application can make use of the library (and bli_finalize() after the application is finished with the library). Instead, all computational operations (and some non-computational functions) in BLIS will initialize the library on behalf of the user if it has not already been initialized. This change was made to simplify the user experience.

Application developers should keep in mind, however, that this new self-initialization regime implies the following: unless the library is explicitly finalized via bli_finalize(), it will, once initialized, remain initialized for the life of the application. This is likely not a problem in the vast majority of cases. However, a memory-constrained application that performs all of its DLA up-front, for example, may wish to explicitly finalize the library after BLIS is no longer needed in order to free up memory for other purposes.

Similarly, an expert user may call bli_init() manually in order to control when the overhead of library initialization is incurred, even though the library would have self-initialized.

The interfaces to bli_init() and bli_finalize() are quite simple; they require no arguments and return no values:

void bli_init( void );
void bli_finalize( void );

Object management

Introduction

Before using the object API, you must first create some objects to encapsulate your vector or matrix data. We provide examples code for creating matrix objects in the examples/oapi directory of the BLIS source distribution. However, we will provide API documentation for the most common functions for creating and freeing objects in the next section.

Generally speaking, an object is created when an obj_t structure is initialized with valid properties describing the object as well as a valid data buffer (to hold the elements of the vector or matrix). The valid data buffer can be allocated automatically on your behalf at the same time that the other object fields are initialized, or "attached" in a second step after the object is initialized with preliminary values. The former is useful when using the object API at the setup stage of an application (and if malloc() is an acceptable method of allocating memory). Similarly, the latter is useful when interfacing BLIS into the middle of an application after the allocation has already taken place, or when some function other than malloc() is desired for allocating the buffer.

Only objects that were created with automatic allocation must be freed via BLIS object API. Objects that were initialized with attached buffers can be freed in whatever manner is appropriate, based on how the application originally allocated the memory in question.

Object creation function reference

void bli_obj_create
     (
       num_t   dt,
       dim_t   m,
       dim_t   n,
       inc_t   rs,
       inc_t   cs,
       obj_t*  obj
     );

Initialize an m x n object obj and allocate sufficient storage to hold mn elements whose storage type is specified by dt and with row and column strides rs and cs, respectively. This function allocates enough space to enforce alignment of leading dimensions, where the alignment factor is specific to the configuration being used, though the alignment factor is almost always equal to the size of the hardware's SIMD registers. The address obj must reference valid memory--typically an obj_t declared statically or allocated dynamically via malloc(). After an object created via bli_obj_create() is no longer needed, it should be deallocated via bli_obj_free().


void bli_obj_free
     (
       obj_t*  obj
     );

Deallocate (release) an object obj that was previously created, typically via bli_obj_create().


void bli_obj_create_without_buffer
     (
       num_t   dt,
       dim_t   m,
       dim_t   n,
       obj_t*  obj
     );

Partially initialize an m x n object obj that will eventually contain elements whose storage type is specified by dt. This function does not result in any memory allocation. Before obj can be used, the object must be fully initialized by attaching a buffer via bli_obj_attach_buffer(). This function is useful when the user wishes to encapsulate existing buffers into one or more obj_t objects. An object (partially) initialized via this function should generally not be passed to bli_obj_free() even after a buffer is attached to it via bli_obj_attach_buffer(), unless the user wishes to pass that buffer into free().


void bli_obj_attach_buffer
     (
       void*   p,
       inc_t   rs,
       inc_t   cs,
       inc_t   is,
       obj_t*  obj
     );

Given a partially initialized object (i.e., one that has already been passed to bli_obj_create_without_buffer()), attach the buffer pointed to by p to the object referenced by obj and initialize obj as containing elements with row and column strides rs and cs, respectively. The function also initializes the imaginary stride as is, which is experimental and not consistently used by all parts of BLIS.


void bli_obj_create_with_attached_buffer
     (
       num_t   dt,
       dim_t   m,
       dim_t   n,
       void*   p,
       inc_t   rs,
       inc_t   cs,
       obj_t*  obj
     );

Initialize an m x n object obj as containing mn elements whose storage type is specified by dt and with row and column strides rs and cs, respectively. The function does not allocate any memory and instead attaches the buffer pointed to by p. Note that calling this function is effectively equivalent to calling

bli_obj_create_without_buffer( dt, m, n, obj );
bli_obj_attach_buffer( p, rs, cs, 1, obj );

Objects initialized via this function should generally not be passed to bli_obj_free(), unless the user wishes to pass p into free().


void bli_obj_alloc_buffer
     (
       inc_t   rs,
       inc_t   cs,
       inc_t   is,
       obj_t*  obj
     );

Given a partially initialized m x n object, allocate and attach a buffer large enough to contain mn elements with the row and column strides rs and cs, respectively. This function allocates enough space to enforce alignment of leading dimensions, where the alignment factor is specific to the configuration being used, though the alignment factor is almost always equal to the size of the hardware's SIMD registers. Note that calling bli_obj_create() is effectively equivalent to calling

bli_obj_create_without_buffer( dt, m, n, obj );
bli_obj_alloc_buffer( rs, cs, 1, obj );

Very few users will likely have a need to call this function. We provide documentation for it mostly so that others can manually access the alignment features of bli_obj_create() without also needing to initialize an obj_t.


void bli_obj_create_1x1
     (
       num_t   dt,
       obj_t*  obj
     );

Initialize a 1 x 1 object obj and allocate sufficient storage to hold one element whose storage type is specified by dt. The address obj must reference valid memory--typically an obj_t declared statically or allocated dynamically via malloc(). This function is useful any time the user wishes to create a scalar object with an allocated buffer. Note that calling bli_obj_create_1x1() is effectively equivalent to calling

bli_obj_create_without_buffer( dt, 1, 1, obj );
bli_obj_alloc_buffer( 1, 1, 1, obj );

After an object created via bli_obj_create_1x1() is no longer needed, it should be deallocated via bli_obj_free().


void bli_obj_create_1x1_with_attached_buffer
     (
       num_t   dt,
       void*   p,
       obj_t*  obj
     );

Initialize a 1 x 1 object obj as containing one element whose storage type is specified by dt. The function does not allocate any memory and instead attaches the buffer pointed to by p. Note that calling this function is effectively equivalent to calling

bli_obj_create_without_buffer( dt, 1, 1, obj );
bli_obj_attach_buffer( p, 1, 1, 1, obj );

Objects initialized via this function should generally not be passed to bli_obj_free(), unless the user wishes to pass p into free().


void bli_obj_create_conf_to
     (
       obj_t*  s,
       obj_t*  d
     );

Initialize an object d with dimensions conformal to those of an existing object s. Object d is initialized with the same row and column strides as those of s. However, the structure, uplo, conjugation, and transposition properties of s are not inherited by d. On entry, object s must be fully initialized and the address d must reference valid memory--typically an obj_t declared statically or allocated dynamically via malloc(). Note that calling this function is effectively equivalent to calling

num_t dt = bli_obj_dt( s );
dim_t m  = bli_obj_length( s );
dim_t n  = bli_obj_width( s );
inc_t rs = bli_obj_row_stride( s );
inc_t cs = bli_obj_col_stride( s );

bli_obj_create( dt, m, n, rs, cs, d );

After an object created via bli_obj_create_conf_to() is no longer needed, it should be deallocated via bli_obj_free().


void bli_obj_scalar_init_detached
     (
       num_t   dt,
       obj_t*  obj
     );

Initialize a 1 x 1 object obj using internal storage sufficient to hold one element whose storage type is specified by dt. (Internal storage is present within every obj_t and is capable of holding on element of any supported type.) This function is similar to bli_obj_create_1x1(), except that the object does not trigger any dynamic memory allocation. Objects initialized via this function should never be passed to bli_obj_free().

Object accessor function reference

Notes for interpreting function descriptions:

  • Object accessor functions allow the caller to query certain properties of objects.
  • These functions are only guaranteed to return meaningful values when called upon objects that have been fully initialized/created.
  • Many specialized functions are omitted from this section for brevity. For a full list of accessor functions, please see frame/include/bli_obj_macro_defs.h, though most users will most likely not need methods beyond those documented below.

num_t bli_obj_dt( obj_t* obj );

Return the storage datatype property of obj.


dom_t bli_obj_domain( obj_t* obj );

Return the domain component of the storage datatype property of obj.


prec_t bli_obj_prec( obj_t* obj );

Return the precision component of the storage datatype property of obj.


trans_t bli_obj_conjtrans_status( obj_t* obj );

Return the trans_t property of obj, which may indicate transposition, conjugation, both, or neither. Thus, possible return values are BLIS_NO_TRANSPOSE, BLIS_CONJ_NO_TRANSPOSE, BLIS_TRANSPOSE, or BLIS_CONJ_TRANSPOSE.


trans_t bli_obj_onlytrans_status( obj_t* obj );

Return the transposition component of the trans_t property of obj, which may indicate transposition or no transposition. Thus, possible return values are BLIS_NO_TRANSPOSE or BLIS_TRANSPOSE.


conj_t bli_obj_conj_status( obj_t* obj );

Return the conjugation component of the trans_t property of obj, which may indicate conjugation or no conjugation. Thus, possible return values are BLIS_NO_CONJUGATE or BLIS_CONJUGATE.


struc_t bli_obj_struc( obj_t* obj );

Return the structure property of obj.


uplo_t bli_obj_uplo( obj_t* obj );

Return the uplo (i.e., storage) property of obj.


diag_t bli_obj_diag( obj_t* obj );

Return the diagonal property of obj.


doff_t bli_obj_diag_offset( obj_t* obj );

Return the diagonal offset of obj. Note that the diagonal offset will be negative, -i, if the diagonal begins at element (-i,0) and positive j if the diagonal begins at element (0,j).


dim_t bli_obj_length( obj_t* obj );

Return the number of rows (or m dimension) of obj. This value is the m dimension before taking into account the transposition property as indicated by bli_obj_onlytrans_status() or bli_obj_conjtrans_status().


dim_t bli_obj_width( obj_t* obj );

Return the number of columns (or n dimension) of obj. This value is the n dimension before taking into account the transposition property as indicated by bli_obj_onlytrans_status() or bli_obj_conjtrans_status().


dim_t bli_obj_length_after_trans( obj_t* obj );

Return the number of rows (or m dimension) of obj after taking into account the transposition property as indicated by bli_obj_onlytrans_status() or bli_obj_conjtrans_status().


dim_t bli_obj_width_after_trans( obj_t* obj );

Return the number of columns (or n dimension) of obj after taking into account the transposition property as indicated by bli_obj_onlytrans_status() or bli_obj_conjtrans_status().


inc_t bli_obj_row_stride( obj_t* obj );

Return the row stride property of obj. When storing by columns, the row stride is 1. When storing by rows, the row stride is also sometimes called the leading dimension.


inc_t bli_obj_col_stride( obj_t* obj );

Return the column stride property of obj. When storing by rows, the column stride is 1. When storing by columns, the column stride is also sometimes called the leading dimension.


dim_t bli_obj_vector_dim( obj_t* obj );

Return the number of elements in a vector object obj. This function assumes that at least one dimension of obj is unit, and that it therefore represents a vector.


inc_t bli_obj_vector_inc( obj_t* obj );

Return the storage increment of a vector object obj. This function assumes that at least one dimension of obj is unit, and that it therefore represents a vector.


void* bli_obj_buffer( obj_t* obj );

Return the address to the data buffer associated with object obj. Note: The address returned by this buffer will not take into account any subpartitioning. However, this will not be a problem for most casual users.


siz_t bli_obj_elem_size( obj_t* obj );

Return the size, in bytes, of the storage datatype as indicated by bli_obj_dt().

Object mutator function reference

Notes for interpreting function descriptions:

  • Object mutator functions allow the caller to modify certain properties of objects.
  • The user should be extra careful about modifying properties after objects are created. For typical use of these functions, please study the example code provided in examples/oapi.
  • The list of mutators below is much shorter than the list of accessor functions provided in the previous section. Most mutator functions should not be called by users (unless you know what you are doing). For a full list of mutator functions, please see frame/include/bli_obj_macro_defs.h, though most users will most likely not need methods beyond those documented below.

void bli_obj_set_conjtrans( trans_t trans, obj_t* obj );

Set both conjugation and transposition properties of obj using the corresponding components of trans.


void bli_obj_set_onlytrans( trans_t trans, obj_t* obj );

Set the transposition property of obj using the transposition component of trans. Leaves the conjugation property of obj unchanged.


void bli_obj_set_conj( conj_t conj, obj_t* obj );

Set the conjugation property of obj using conj. Leaves the transposition property of obj unchanged.


void bli_obj_apply_trans( trans_t trans, obj_t* obj );

Apply trans to the transposition property of obj. For example, applying BLIS_TRANSPOSE will toggle the transposition property of obj but leave the conjugation property unchanged; applying BLIS_CONJ_TRANSPOSE will toggle both the conjugation and transposition properties of obj.


void bli_obj_apply_conj( conj_t conj, obj_t* obj );

Apply conj to the conjugation property of obj. Specifically, applying BLIS_CONJUGATE will toggle the conjugation property of obj; applying BLIS_NO_CONJUGATE will have no effect. Leaves the transposition property of obj unchanged.


void bli_obj_set_struc( struc_t struc, obj_t* obj );

Set the structure property of obj to struc.


void bli_obj_set_uplo( uplo_t uplo, obj_t* obj );

Set the uplo (i.e., storage) property of obj to uplo.


void bli_obj_set_diag( diag_t diag, obj_t* obj );

Set the diagonal property of obj to diag.


void bli_obj_set_diag_offset( doff_t doff, obj_t* obj );

Set the diagonal offset property of obj to doff. Note that doff_t may be typecast from any signed integer.


Other object function reference


void bli_obj_induce_trans( obj_t* obj );

Modify the properties of obj to induce a logical transposition. This function operates without regard to whether the transposition property is already set. Therefore, depending on the circumstance, the caller may or may not wish to clear the transposition property after calling this function.


void bli_obj_alias_to( obj_t* a, obj_t* b );

Initialize b to be a shallow copy, or alias, of a. For most people's purposes, this is equivalent to

  b = a;

However, there is at least one field (one that only developers should be concerned with) that is not copied.


void bli_obj_real_part( obj_t* c, obj_t* r );

Initialize r to be a modified shallow copy of c that refers only to the real part of c.


void bli_obj_imag_part( obj_t* c, obj_t* i );

Initialize i to be a modified shallow copy of c that refers only to the imaginary part of c.

Computational function reference

Notes for interpreting function descriptions:

  • conj?(X) and trans?(X) should be interpreted as predicates that capture the operand X with that object's conj_t or trans_t property applied. For example:
    • conj?(x) refers to a vector x that is either conjugated or used as given.
    • trans?(A) refers to a matrix A that is either transposed, conjugated and transposed, conjugated only, or used as given.
  • Any operand marked with conj() is unconditionally conjugated.
  • Any operand marked with ^T is unconditionally transposed. Similarly, any operand that is marked with ^H is unconditionally conjugate-transposed.
  • All occurrences of alpha, beta, and rho parameters are scalars.
  • In general, unless otherwise noted, all object parameters must be stored using the same num_t datatype. In a few cases, one of the object parameters must be stored in the real projection of one of the other objects' types. (The real projection of a num_t datatype is the equivalent datatype in the real domain. So BLIS_DOUBLE is the real projection of BLIS_DCOMPLEX. BLIS_DOUBLE is also the real projection of itself.)
  • Many object API entries list the object properties that are honored/observed by the operation. For example, for bli_gemv(), the observed object properties are trans?(A) and conj?(x). The former means that matrix A may be (optionally) marked for conjugation and/or tranaposition while the latter means that vector x may be (optionally) marked for conjugation. A function may also list diagoff(A) as an observe property, which means that it will accept general diagonal offsets. Similarly, diag(A) refers to recognizing the unit/non-unit structure of the diagonal and and uplo(A) refers to reading/updating only the stored triangle/trapezoid/region of A.

Level-1v operations

Level-1v operations perform various level-1 BLAS-like operations on vectors (hence the v). Note: Most level-1v operations have a corresponding level-1v kernel through which it is primarily implemented.


addv

void bli_addv
     (
       obj_t*  x,
       obj_t*  y,
     );

Perform

  y := y + conj?(x)

where x and y are vectors of length n.

Observed object properties: conj?(x).


amaxv

void bli_amaxv
     (
       obj_t*  x,
       obj_t*  index
     );

Given a vector of length n, return the zero-based index of the element of vector x that contains the largest absolute value (or, in the complex domain, the largest complex modulus). The object index must be created of type BLIS_INT.

If NaN is encountered, it is treated as if it were a valid value that was smaller than any other value in the vector. If more than one element contains the same maximum value, the index of the latter element is returned via index.

Observed object properties: none.

Note: This function attempts to mimic the algorithm for finding the element with the maximum absolute value in the netlib BLAS routines i?amax().


axpyv

void bli_axpyv
     (
       obj_t*  alpha,
       obj_t*  x,
       obj_t*  y
     );

Perform

  y := y + conj?(alpha) * conj?(x)

where x and y are vectors of length n, and alpha is a scalar.

Observed object properties: conj?(alpha), conj?(x).


axpbyv

void bli_axpbyv
     (
       obj_t*  alpha,
       obj_t*  x,
       obj_t*  beta,
       obj_t*  y
     );

Perform

  y := conj?(beta) * y + conj?(alpha) * conj?(x)

where x and y are vectors of length n, and alpha and beta are scalars.

Observed object properties: conj?(alpha), conj?(x).


copyv

void bli_copyv
     (
       obj_t*  x,
       obj_t*  y
     );

Perform

  y := conj?(x)

where x and y are vectors of length n.

Observed object properties: conj?(x).


dotv

void bli_dotv
     (
       obj_t*  x,
       obj_t*  y,
       obj_t*  rho
     );

Perform

  rho := conj?(x)^T * conj?(y)

where x and y are vectors of length n, and rho is a scalar.

Observed object properties: conj?(x), conj?(y).


dotxv

void bli_dotxv
     (
       obj_t*  alpha,
       obj_t*  x,
       obj_t*  y,
       obj_t*  beta,
       obj_t*  rho
     );

Perform

  rho := conj?(beta) * rho + conj?(alpha) * conj?(x)^T * conj?(y)

where x and y are vectors of length n, and alpha, beta, and rho are scalars.

Observed object properties: conj?(alpha), conj?(beta), conj?(x), conj?(y).


invertv

void bli_invertv
     (
       obj_t*  x
     );

Invert all elements of an n-length vector x.


invscalv

void bli_invscalv
     (
       obj_t*  alpha,
       obj_t*  x
     );

Perform

  x := ( 1.0 / conj?(alpha) ) * x

where x is a vector of length n, and alpha is a scalar.

Observed object properties: conj?(alpha).


scalv

void bli_scalv
     (
       obj_t*  alpha,
       obj_t*  x
     );

Perform

  x := conj?(alpha) * x

where x is a vector of length n, and alpha is a scalar.

Observed object properties: conj?(alpha).


scal2v

void bli_scal2v
     (
       obj_t*  alpha,
       obj_t*  x,
       obj_t*  y
     );

Perform

  y := conj?(alpha) * conj?(x)

where x and y are vectors of length n, and alpha is a scalar.

Observed object properties: conj?(alpha), conj?(x).


setv

void bli_setv
     (
       obj_t*  alpha,
       obj_t*  x
     );

Perform

  x := conj?(alpha)

That is, set all elements of an n-length vector x to scalar conj?(alpha).

Observed object properties: conj?(alpha).


setrv

void bli_setrv
     (
       obj_t*  alpha,
       obj_t*  x
     );

Perform

  real(x) := real(alpha)

That is, given an n-length vector x, set all elements' real components to the real component of scalar alpha. (If alpha is complex, the imaginary component is ignored.) If x is real, this operation is equivalent to performing setv on x with the real component of scalar alpha. Note: This operation is provided for convenience as an object wrapper to setv, and thus it has no analogue in the BLIS typed API.


setiv

void bli_setiv
     (
       obj_t*  alpha,
       obj_t*  x
     );

Perform

  imag(x) := real(alpha)

That is, given an n-length vector x, set all elements' imaginary components to the real component of scalar alpha. (If alpha is complex, the imaginary component is ignored.) If x is real, this operation is equivalent to a no-op. Note: This operation is provided for convenience as an object wrapper to setv, and thus it has no analogue in the BLIS typed API.


subv

void bli_subv
     (
       obj_t*  x,
       obj_t*  y
     );

Perform

  y := y - conj?(x)

where x and y are vectors of length n.

Observed object properties: conj?(x).


swapv

void bli_swapv
     (
       obj_t*  x,
       obj_t*  y
     );

Swap corresponding elements of two n-length vectors x and y.


xpbyv

void bli_xpbyv
     (
       obj_t*  x,
       obj_t*  beta,
       obj_t*  y
     );

Perform

  y := conj?(beta) * y + conj?(x)

where x and y are vectors of length n, and beta is a scalar.

Observed object properties: conj?(beta), conj?(x).


Level-1d operations

Level-1d operations perform various level-1 BLAS-like operations on matrix diagonals (hence the d).

These operations are similar to their level-1m counterparts, except they only read and update matrix diagonals and therefore ignore the uplo property of their applicable input operands. Please see the descriptions for the corresponding level-1m operation for a description of the arguments.


addd

void bli_addd
     (
       obj_t*  a,
       obj_t*  b
     );

Observed object properties: diagoff(A), diag(A), trans?(A).


axpyd

void bli_axpyd
     (
       obj_t*  alpha,
       obj_t*  a,
       obj_t*  b
     );

Observed object properties: conj?(alpha), diagoff(A), diag(A), trans?(A).


copyd

void bli_copyd
     (
       obj_t*  a,
       obj_t*  b
     );

Observed object properties: diagoff(A), diag(A), trans?(A).


invertd

void bli_invertd
     (
       obj_t*  a
     );

Observed object properties: diagoff(A).


invscald

void bli_invscald
     (
       obj_t*  alpha,
       obj_t*  a
     );

Observed object properties: conj?(alpha), diagoff(A).


scald

void bli_scald
     (
       obj_t*  alpha,
       obj_t*  a
     );

Observed object properties: conj?(alpha), diagoff(A).


scal2d

void bli_scal2d
     (
       obj_t*  alpha,
       obj_t*  a,
       obj_t*  b
     );

Observed object properties: conj?(alpha), diagoff(A), diag(A), trans?(A).


setd

void bli_setd
     (
       obj_t*  alpha,
       obj_t*  a
     );

Observed object properties: conj?(alpha), diagoff(A).


setid

void bli_setid
     (
       obj_t*  alpha,
       obj_t*  a
     );

Set the imaginary components of every element along the diagonal of a to a scalar alpha. Note that the datatype of alpha must be the real projection of the datatype of a.

Observed object properties: diagoff(A).


shiftd

void bli_shiftd
     (
       obj_t*  alpha,
       obj_t*  a
     );

Add a constant value alpha to every element along the diagonal of a.

Observed object properties: diagoff(A).


subd

void bli_subd
     (
       obj_t*  a,
       obj_t*  b
     );

Observed object properties: diagoff(A), diag(A), trans?(A).


xpbyd

void bli_xpbyd
     (
       obj_t*  a,
       obj_t*  beta,
       obj_t*  b
     );

Observed object properties: conj?(beta), diagoff(A), diag(A), trans?(A).


Level-1m operations

Level-1m operations perform various level-1 BLAS-like operations on matrices (hence the m).


addm

void bli_addm
     (
       obj_t*  a,
       obj_t*  b
     );

Perform

  B := B + trans?(A)

where B is an m x n matrix, A is stored as a dense matrix, or lower- or upper-triangular/trapezoidal matrix with arbitrary diagonal offset and unit or non-unit diagonal. If uplo(A) indicates lower or upper storage, only that part of matrix A will be referenced and used to update B.

Observed object properties: diagoff(A), diag(A), uplo(A), trans?(A).


axpym

void bli_axpym
     (
       obj_t*  alpha,
       obj_t*  a,
       obj_t*  b
     );

Perform

  B := B + conj?(alpha) * trans?(A)

where B is an m x n matrix, A is stored as a dense matrix, or lower- or upper-triangular/trapezoidal matrix with arbitrary diagonal offset and unit or non-unit diagonal. If uplo(A) indicates lower or upper storage, only that part of matrix A will be referenced and used to update B.

Observed object properties: conj?(alpha), diagoff(A), diag(A), uplo(A), trans?(A).


copym

void bli_copym
     (
       obj_t*  a,
       obj_t*  b
     );

Perform

  B := trans?(A)

where B is an m x n matrix, A is stored as a dense matrix, or lower- or upper-triangular/trapezoidal matrix with arbitrary diagonal offset and unit or non-unit diagonal. If uplo(A) indicates lower or upper storage, only that part of matrix A will be referenced and used to update B.

Observed object properties: diagoff(A), diag(A), uplo(A), trans?(A).


invscalm

void bli_invscalm
     (
       obj_t*  alpha,
       obj_t*  a
     );

Perform

  A := ( 1.0 / conj?(alpha) ) * A

where A is an m x n matrix stored as a dense matrix, or lower- or upper-triangular/trapezoidal matrix with arbitrary diagonal offset. If uplo(A) indicates lower or upper storage, only that part of matrix A will be updated.

Observed object properties: conj?(alpha), diagoff(A), uplo(A).


scalm

void bli_scalm
     (
       obj_t*  alpha,
       obj_t*  a
     );

Perform

  A := conj?(alpha) * A

where A is an m x n matrix stored as a dense matrix, or lower- or upper-triangular/trapezoidal matrix with arbitrary diagonal offset. If uplo(A) indicates lower or upper storage, only that part of matrix A will be updated.

Observed object properties: conj?(alpha), diagoff(A), uplo(A).


scal2m

void bli_scal2m
     (
       obj_t*  alpha,
       obj_t*  a,
       obj_t*  b
     );

Perform

  B := conj?(alpha) * trans?(A)

where B is an m x n matrix, A is stored as a dense matrix, or lower- or upper-triangular/trapezoidal matrix with arbitrary diagonal offset and unit or non-unit diagonal. If uplo(A) indicates lower or upper storage, only that part of matrix A will be referenced and used to update B.

Observed object properties: conj?(alpha), diagoff(A), diag(A), uplo(A), trans?(A).


setm

void bli_setm
     (
       obj_t*  alpha,
       obj_t*  a
     );

Perform

  A := conj?(alpha)

That is, set all elements of A to scalar conj?(alpha), where A is an m x n matrix stored as a dense matrix, or lower- or upper-triangular/trapezoidal matrix with arbitrary diagonal offset. If uplo(A) indicates lower or upper storage, only that part of matrix A will be updated.

Observed object properties: conj?(alpha), diagoff(A), diag(A), uplo(A).


setrm

void bli_setrm
     (
       obj_t*  alpha,
       obj_t*  a
     );

Perform

  real(A) := real(alpha)

That is, given an m x n matrix A, set all elements' real components to the real component of scalar alpha. (If alpha is complex, the imaginary component is ignored.) If A is real, this operation is equivalent to performing setm on A with the real component of scalar alpha. Note: This operation is provided for convenience as an object wrapper to setm, and thus it has no analogue in the BLIS typed API.

Observed object properties: diagoff(A), diag(A), uplo(A).


setim

void bli_setim
     (
       obj_t*  alpha,
       obj_t*  a
     );

Perform

  imag(A) := real(alpha)

That is, given an m x n matrix A, set all elements' imaginary components to the real component of scalar alpha. (If alpha is complex, the imaginary component is ignored.) If A is real, this operation is equivalent to a no-op. Note: This operation is provided for convenience as an object wrapper to setm, and thus it has no analogue in the BLIS typed API.

Observed object properties: diagoff(A), diag(A), uplo(A).


subm

void bli_subm
     (
       obj_t*  a,
       obj_t*  b
     );

Perform

  B := B - trans?(A)

where B is an m x n matrix, A is stored as a dense matrix, or lower- or upper-triangular/trapezoidal matrix with arbitrary diagonal offset and unit or non-unit diagonal. If uplo(A) indicates lower or upper storage, only that part of matrix A will be referenced and used to update B.

Observed object properties: diagoff(A), diag(A), uplo(A), trans?(A).


Level-1f operations

Level-1f operations implement various fused combinations of level-1 operations (hence the f). Note: Each level-1f operation has a corresponding level-1f kernel through which it is primarily implemented.

Level-1f kernels are employed when optimizing level-2 operations.


axpy2v

void bli_axpy2v
     (
       obj_t*  alphax,
       obj_t*  alphay,
       obj_t*  x,
       obj_t*  y,
       obj_t*  z
     );

Perform

  z := z + conj?(alphax) * conj?(x) + conj?(alphay) * conj?(y)

where x, y, and z are vectors of length m. The kernel, if optimized, is implemented as a fused pair of calls to axpyv.

Observed object properties: conj?(alphax), conj?(x), conj?(alphay), conj?(y).


dotaxpyv

void bli_dotaxpyv
     (
       obj_t*  alpha,
       obj_t*  x,
       obj_t*  y,
       obj_t*  rho,
       obj_t*  z
     );

Perform

  rho := conj?(x)^T * conj?(y)
  z   := z + conj?(alpha) * conj?(x)

where x, y, and z are vectors of length m and alpha and rho are scalars. The kernel, if optimized, is implemented as a fusion of calls to dotv and axpyv.

Observed object properties: conj?(x), conj?(y), conj?(alpha).


axpyf

void bli_axpyf
     (
       obj_t*  alpha,
       obj_t*  a,
       obj_t*  x,
       obj_t*  y
     );

Perform

  y := y + alpha * conja(A) * conjx(x)

where A is an m x b matrix, and x and y are vectors. The kernel, if optimized, is implemented as a fused series of calls to axpyv where b is less than or equal to an implementation-dependent fusing factor specific to axpyf.

Observed object properties: conj?(alpha), conj?(A), conj?(x).


dotxf

void bli_dotxf
     (
       obj_t*  alpha,
       obj_t*  a,
       obj_t*  x,
       obj_t*  beta,
       obj_t*  y
     );

Perform

  y := conj?(beta) * y + conj?(alpha) * conj?(A)^T * conj?(x)

where A is an m x b matrix, and x and y are vectors. The kernel, if optimized, is implemented as a fused series of calls to dotxv where b is less than or equal to an implementation-dependent fusing factor specific to dotxf.

Observed object properties: conj?(alpha), conj?(beta), conj?(A), conj?(x).


dotxaxpyf

void bli_dotxaxpyf
     (
       obj_t*  alpha,
       obj_t*  a,
       obj_t*  w,
       obj_t*  x,
       obj_t*  beta,
       obj_t*  y,
       obj_t*  z
     );

Perform

  y := conj?(beta) * y + conj?(alpha) * conj?(A)^T * conj?(w)
  z :=               z + conj?(alpha) * conj?(A)   * conj?(x)

where A is an m x b matrix, w and z are vectors of length m, x and y are vectors of length b, and alpha and beta are scalars. The kernel, if optimized, is implemented as a fusion of calls to dotxf and axpyf.

Observed object properties: conj?(alpha), conj?(beta), conj?(A), conj?(w), conj?(x).

Level-2 operations

Level-2 operations perform various level-2 BLAS-like operations.


gemv

void bli_gemv
     (
       obj_t*  alpha,
       obj_t*  a,
       obj_t*  x,
       obj_t*  beta,
       obj_t*  y
     );

Perform

  y := conj?(beta) * y + conj?(alpha) * trans?(A) * conj?(x)

where trans?(A) is an m x n matrix, and x and y are vectors.

Observed object properties: conj?(alpha), conj?(beta), trans?(A), conj?(x).


ger

void bli_ger
     (
       obj_t*  alpha,
       obj_t*  x,
       obj_t*  y,
       obj_t*  a
     );

Perform

  A := A + conj?(alpha) * conj?(x) * conj?(y)^T

where A is an m x n matrix, and x and y are vectors of length m and n, respectively.

Observed object properties: conj?(alpha), conj?(x), conj?(y).


hemv

void bli_hemv
     (
       obj_t*  alpha,
       obj_t*  a,
       obj_t*  x,
       obj_t*  beta,
       obj_t*  y
     );

Perform

  y := conj?(beta) * y + conj?(alpha) * conj?(A) * conj?(x)

where A is an m x m Hermitian matrix stored in the lower or upper triangle as specified by uplo(A), and x and y are vectors of length m.

Observed object properties: conj?(alpha), conj?(beta), conj?(A), uplo(A), conj?(x).


her

void bli_her
     (
       obj_t*  alpha,
       obj_t*  x,
       obj_t*  a
     );

Perform

  A := A + conj?(alpha) * conj?(x) * conj?(x)^H

where A is an m x m Hermitian matrix stored in the lower or upper triangle as specified by uplo(A), and x is a vector of length m.

Observed object properties: conj?(alpha), uplo(A), conj?(x).

Note: The floating-point (num_t) type of alpha is always the real projection of the floating-point types of x and A.


her2

void bli_her2
     (
       obj_t*  alpha,
       obj_t*  x,
       obj_t*  y,
       obj_t*  a
     );

Perform

  A := A + alpha * conj?(x) * conj?(y)^H + conj(alpha) * conj?(y) * conj?(x)^H

where A is an m x m Hermitian matrix stored in the lower or upper triangle as specified by uplo(A), and x and y are vectors of length m.

Observed object properties: uplo(A), conj?(x), conj?(y).


symv

void bli_symv
     (
       obj_t*  alpha,
       obj_t*  a,
       obj_t*  x,
       obj_t*  beta,
       obj_t*  y
     );

Perform

  y := conj?(beta) * y + conj?(alpha) * conj?(A) * conj?(x)

where A is an m x m symmetric matrix stored in the lower or upper triangle as specified by uplo(A), and x and y are vectors of length m.

Observed object properties: conj?(alpha), conj?(beta), conj?(A), uplo(A), conj?(x).


syr

void bli_syr
     (
       obj_t*  alpha,
       obj_t*  x,
       obj_t*  a
     );

Perform

  A := A + conj?(alpha) * conj?(x) * conj?(x)^T

where A is an m x m symmetric matrix stored in the lower or upper triangle as specified by uploa, and x is a vector of length m.

Observed object properties: conj?(alpha), conj?(x).


syr2

void bli_syr2
     (
       obj_t*  alpha,
       obj_t*  x,
       obj_t*  y,
       obj_t*  a
     );

Perform

  A := A + alpha * conj?(x) * conj?(y)^T + conj(alpha) * conj?(y) * conj?(x)^T

where A is an m x m symmetric matrix stored in the lower or upper triangle as specified by uplo(A), and x and y are vectors of length m.

Observed object properties: uplo(A), conj?(x), conj?(y).


trmv

void bli_trmv
     (
       obj_t*  alpha,
       obj_t*  a,
       obj_t*  x
     );

Perform

  x := conj?(alpha) * transa(A) * x

where A is an m x m triangular matrix stored in the lower or upper triangle as specified by uplo(A) with unit/non-unit nature specified by diag(A), and x is a vector of length m.

Observed object properties: conj?(alpha), uplo(A), trans?(A), diag(A).


trsv

void bli_trsv
     (
       obj_t*  alpha,
       obj_t*  a,
       obj_t*  y
     );

Solve the linear system

  transa(A) * x = alpha * y

where A is an m x m triangular matrix stored in the lower or upper triangle as specified by uplo(A) with unit/non-unit nature specified by diag(A), and x and y are vectors of length m. The right-hand side vector operand y is overwritten with the solution vector x.

Observed object properties: conj?(alpha), uplo(A), trans?(A), diag(A).


Level-3 operations

Level-3 operations perform various level-3 BLAS-like operations. Note: Each All level-3 operations are implemented through a handful of level-3 microkernels. Please see the Kernels Guide for more details.


gemm

void bli_gemm
     (
       obj_t*  alpha,
       obj_t*  a,
       obj_t*  b,
       obj_t*  beta,
       obj_t*  c
     );

Perform

  C := beta * C + alpha * trans?(A) * trans?(B)

where C is an m x n matrix, trans?(A) is an m x k matrix, and trans?(B) is a k x n matrix.

Observed object properties: trans?(A), trans?(B).


gemmt

void bli_gemmt
     (
       obj_t*  alpha,
       obj_t*  a,
       obj_t*  b,
       obj_t*  beta,
       obj_t*  c
     );

Perform

  C := beta * C + alpha * trans?(A) * trans?(B)

where C is an m x m matrix, trans?(A) is an m x k matrix, and trans?(B) is a k x m matrix. This operation is similar to bli_gemm() except that it only updates the lower or upper triangle of C as specified by uplo(C).

Observed object properties: trans?(A), trans?(B), uplo(C).


hemm

void bli_hemm
     (
       side_t  sidea,
       obj_t*  alpha,
       obj_t*  a,
       obj_t*  b,
       obj_t*  beta,
       obj_t*  c
     );

Perform

  C := beta * C + alpha * conj?(A) * trans?(B)

if sidea is BLIS_LEFT, or

  C := beta * C + alpha * trans?(B) * conj?(A)

if sidea is BLIS_RIGHT, where C and B are m x n matrices and A is a Hermitian matrix stored in the lower or upper triangle as specified by uplo(A). When sidea is BLIS_LEFT, A is m x m, and when sidea is BLIS_RIGHT, A is n x n.

Observed object properties: uplo(A), conj?(A), trans?(B).


herk

void bli_herk
     (
       obj_t*  alpha,
       obj_t*  a,
       obj_t*  beta,
       obj_t*  c
     );

Perform

  C := beta * C + alpha * trans?(A) * trans?(A)^H

where C is an m x m Hermitian matrix stored in the lower or upper triangle as specified by uplo(C) and trans?(A) is an m x k matrix.

Observed object properties: trans?(A), uplo(C).

Note: The floating-point (num_t) types of alpha and beta are always the real projection of the floating-point types of A and C.


her2k

void bli_her2k
     (
       obj_t*  alpha,
       obj_t*  a,
       obj_t*  b,
       obj_t*  beta,
       obj_t*  c
     );

Perform

  C := beta * C + alpha * trans?(A) * trans?(B)^H + conj(alpha) * trans?(B) * trans?(A)^H

where C is an m x m Hermitian matrix stored in the lower or upper triangle as specified by uplo(C) and trans?(A) and trans?(B) are m x k matrices.

Observed object properties: trans?(A), trans?(B), uplo(C).

Note: The floating-point (num_t) type of beta is always the real projection of the floating-point types of A and C.


symm

void bli_symm
     (
       side_t  sidea,
       obj_t*  alpha,
       obj_t*  a,
       obj_t*  b,
       obj_t*  beta,
       obj_t*  c
     );

Perform

  C := beta * C + alpha * conj?(A) * trans?(B)

if sidea is BLIS_LEFT, or

  C := beta * C + alpha * trans?(B) * conj?(A)

if sidea is BLIS_RIGHT, where C and B are m x n matrices and A is a symmetric matrix stored in the lower or upper triangle as specified by uplo(A). When sidea is BLIS_LEFT, A is m x m, and when sidea is BLIS_RIGHT, A is n x n.

Observed object properties: uplo(A), conj?(A), trans?(B).


syrk

void bli_syrk
     (
       obj_t*  alpha,
       obj_t*  a,
       obj_t*  beta,
       obj_t*  c
     );

Perform

  C := beta * C + alpha * trans?(A) * trans?(A)^T

where C is an m x m symmetric matrix stored in the lower or upper triangle as specified by uplo(A) and trans?(A) is an m x k matrix.

Observed object properties: trans?(A), uplo(C).


syr2k

void bli_syr2k
     (
       obj_t*  alpha,
       obj_t*  a,
       obj_t*  b,
       obj_t*  beta,
       obj_t*  c
     );

Perform

  C := beta * C + alpha * trans?(A) * trans?(B)^T + alpha * trans?(B) * trans?(A)^T

where C is an m x m symmetric matrix stored in the lower or upper triangle as specified by uplo(A) and trans?(A) and trans?(B) are m x k matrices.

Observed object properties: trans?(A), trans?(B), uplo(C).


trmm

void bli_trmm
     (
       side_t  sidea,
       obj_t*  alpha,
       obj_t*  a,
       obj_t*  b
     );

Perform

  B := alpha * transa(A) * B

if sidea is BLIS_LEFT, or

  B := alpha * B * transa(A)

if sidea is BLIS_RIGHT, where B is an m x n matrix and A is a triangular matrix stored in the lower or upper triangle as specified by uplo(A) with unit/non-unit nature specified by diag(A). When sidea is BLIS_LEFT, A is m x m, and when sidea is BLIS_RIGHT, A is n x n.

Observed object properties: uplo(A), trans?(A), diag(A).


trmm3

void bli_trmm3
     (
       side_t  sidea,
       obj_t*  alpha,
       obj_t*  a,
       obj_t*  b,
       obj_t*  beta,
       obj_t*  c
     );

Perform

  C := beta * C + alpha * trans?(A) * trans?(B)

if sidea is BLIS_LEFT, or

  C := beta * C + alpha * trans?(B) * trans?(A)

if sidea is BLIS_RIGHT, where C and trans?(B) are m x n matrices and A is a triangular matrix stored in the lower or upper triangle as specified by uplo(A) with unit/non-unit nature specified by diag(A). When sidea is BLIS_LEFT, A is m x m, and when sidea is BLIS_RIGHT, A is n x n.

Observed object properties: uplo(A), trans?(A), diag(A), trans?(B).


trsm

void bli_trsm
     (
       side_t  sidea,
       obj_t*  alpha,
       obj_t*  a,
       obj_t*  b
     );

Solve the linear system with multiple right-hand sides

  transa(A) * X = alpha * B

if sidea is BLIS_LEFT, or

  X * transa(A) = alpha * B

if sidea is BLIS_RIGHT, where X and B are an m x n matrices and A is a triangular matrix stored in the lower or upper triangle as specified by uplo(A) with unit/non-unit nature specified by diag(A). When sidea is BLIS_LEFT, A is m x m, and when sidea is BLIS_RIGHT, A is n x n. The right-hand side matrix operand B is overwritten with the solution matrix X.

Observed object properties: uplo(A), trans?(A), diag(A).


Utility operations


asumv

void bli_asumv
     (
       obj_t*  x,
       obj_t*  asum
     );

Compute the sum of the absolute values of the fundamental elements of vector x. The resulting sum is stored to asum.

Observed object properties: none.

Note: The floating-point type of asum is always the real projection of the floating-point type of x. Note: This function attempts to mimic the algorithm for computing the absolute vector sum in the netlib BLAS routines *asum().


norm1m

normfm

normim

void bli_norm[1fi]m
     (
       obj_t*  a,
       obj_t*  norm
     );

Compute the one-norm (bli_norm1m()), Frobenius norm (bli_normfm()), or infinity norm (bli_normim()) of the elements in an m x n matrix A. If uplo(A) is BLIS_LOWER or BLIS_UPPER then A is assumed to be lower or upper triangular, respectively, with the main diagonal located at offset diagoff(A). The resulting norm is stored to norm.

Observed object properties: diagoff(A), diag(A), uplo(A).

Note: The floating-point (num_t) type of norm is always the real projection of the floating-point type of x.


norm1v

normfv

normiv

void bli_norm[1fi]v
     (
       obj_t*  x,
       obj_t*  norm
     );

Compute the one-norm (bli_norm1v()), Frobenius norm (bli_normfv()), or infinity norm (bli_normiv()) of the elements in a vector x of length n. The resulting norm is stored to norm.

Observed object properties: diagoff(A), diag(A), uplo(A).

Note: The floating-point (num_t) type of norm is always the real projection of the floating-point type of x.


mkherm

void bli_mkherm
     (
       obj_t*  a
     );

Make an m x m matrix A explicitly Hermitian by copying the conjugate of the triangle specified by uplo(A) to the opposite triangle. Imaginary components of diagonal elements are explicitly set to zero. It is assumed that the diagonal offset of A is zero.

Observed object properties: uplo(A).


mksymm

void bli_mksymm
     (
       obj_t*  a
     );

Make an m x m matrix A explicitly symmetric by copying the triangle specified by uplo(A) to the opposite triangle. It is assumed that the diagonal offset of A is zero.

Observed object properties: uplo(A).


mktrim

void bli_mktrim
     (
       obj_t*  a
     );

Make an m x m matrix A explicitly triangular by preserving the triangle specified by uplo(A) and zeroing the elements in the opposite triangle. It is assumed that the diagonal offset of A is zero.

Observed object properties: uplo(A).


fprintv

void bli_fprintv
     (
       FILE*   file,
       char*   s1,
       obj_t*  x,
       char*   format,
       char*   s2
     );

Print a vector x of length m to file stream file, where file is a file pointer returned by the standard C library function fopen(). The caller may also pass in a global file pointer such as stdout or stderr. The strings s1 and s2 are printed immediately before and after the output (respectively), and the format specifier format is used to format the individual elements. For valid format specifiers, please see documentation for the standard C library function printf().

Note: For complex datatypes, the format specifier is applied to both the real and imaginary components individually. Therefore, you should use format specifiers such as "%5.2f", but not "%5.2f + %5.2f".


fprintm

void bli_fprintm
     (
       FILE*   file,
       char*   s1,
       obj_t*  a,
       char*   format,
       char*   s2
     );

Print an m x n matrix A to file stream file, where file is a file pointer returned by the standard C library function fopen(). The caller may also pass in a global file pointer such as stdout or stderr. The strings s1 and s2 are printed immediately before and after the output (respectively), and the format specifier format is used to format the individual elements. For valid format specifiers, please see documentation for the standard C library function printf().

Note: For complex datatypes, the format specifier is applied to both the real and imaginary components individually. Therefore, you should use format specifiers such as "%5.2f", but not "%5.2f + %5.2f".


printv

void bli_printv
     (
       char*   s1,
       obj_t*  x,
       char*   format,
       char*   s2
     );

Print a vector x of length m to standard output. This function call is equivalent to calling bli_fprintv() with stdout as the file pointer.


printm

void bli_printm
     (
       char*   s1,
       obj_t*  a,
       char*   format,
       char*   s2
     );

Print an m x n matrix a to standard output. This function call is equivalent to calling bli_fprintm() with stdout as the file pointer.


randv

void bli_randv
     (
       obj_t*  x
     );

Set the elements of a vector x of length n to random values on the interval [-1,1).

Note: For complex datatypes, the real and imaginary components of each element are randomized individually and independently of one another.


randm

void bli_randm
     (
       obj_t*  a
     );

Set the elements of an m x n matrix A to random values on the interval [-1,1). Off-diagonal elements (in the triangle specified by uplo(A)) are scaled by 1.0/max(m,n).

Observed object properties: diagoff(A), uplo(A).

Note: For complex datatypes, the real and imaginary components of each off-diagonal element are randomized individually and independently of one another. Note: If uplo(A) is BLIS_LOWER or BLIS_UPPER and you plan to use this matrix to test trsv or trsm, additional scaling of the diagonal is recommended to ensure that the matrix is invertible. In this case, try using the addd operation to increase the magnitude to the diagonal elements.


sumsqv

void bli_sumsqv
     (
       obj_t*  x,
       obj_t*  scale,
       obj_t*  sumsq
     );

Compute the sum of the squares of the elements in a vector x of length n. The result is computed in scaled form, and in such a way that it may be used repeatedly to accumulate the sum of the squares of several vectors.

The function computes scale_new and sumsq_new such that

  scale_new^2 * sumsq_new = x[0]^2 + x[1]^2 + ... x[m-1]^2 + scale_old^2 * sumsq_old

where, on entry, scale and sumsq contain scale_old and sumsq_old, respectively, and on exit, scale and sumsq contain scale_new and sumsq_new, respectively.

Note: This function attempts to mimic the algorithm for computing the Frobenius norm in the netlib LAPACK routine ?lassq(). Note: The floating-point (num_t) types of scale and sumsq are always the real projection of the floating-point type of x.


getsc

void bli_getsc
     (
       obj_t*   chi,
       double*  zeta_r,
       double*  zeta_i
     );

Copy the real and imaginary values from the scalar object chi to zeta_r and zeta_i. If chi is stored as a real type, then zeta_i is set to zero. (If chi is stored in single precision, the corresponding elements are typecast/promoted during the copy.)


getijv

err_t bli_getijv
      (
        dim_t    i,
        obj_t*   x,
        double*  ar,
        double*  ai
      )

Copy the real and imaginary values at the ith element of vector object x to ar and ai. If elements of x are stored as real types, then only ar is overwritten and ai is left unchanged. (If x contains elements stored in single precision, the corresponding elements are typecast/promoted during the copy.) If either the element offset i is beyond the vector dimension of x or less than zero, the function returns BLIS_FAILURE without taking any action. Similarly, if x is a global scalar constant such as BLIS_ONE, the function returns BLIS_FAILURE.


getijm

err_t bli_getijm
      (
        dim_t    i,
        dim_t    j,
        obj_t*   b,
        double*  ar,
        double*  ai
      )

Copy the real and imaginary values at the (i,j) element of object b to ar and ai. If elements of b are stored as real types, then only ar is overwritten and ai is left unchanged. (If b contains elements stored in single precision, the corresponding elements are typecast/promoted during the copy.) If either the row offset i is beyond the m dimension of b or less than zero, or column offset j is beyond the n dimension of b or less than zero, the function returns BLIS_FAILURE without taking any action. Similarly, if b is a global scalar constant such as BLIS_ONE, the function returns BLIS_FAILURE.


setsc

void bli_setsc
     (
       double  zeta_r,
       double  zeta_i,
       obj_t*  chi
     );

Copy real and imaginary values zeta_r and zeta_i to the scalar object chi. If chi is stored as a real type, then zeta_i is ignored. (If chi is stored in single precision, the contents are typecast/demoted during the copy.)


setijv

err_t bli_setijv
     (
       double  ar,
       double  ai,
       dim_t   i,
       obj_t*  x
     );

Copy real and imaginary values ar and ai to the ith element of vector object x. If elements of x are stored as real types, then only ar is copied and ai is ignored. (If x contains elements stored in single precision, the corresponding elements are typecast/demoted during the copy.) If the element offset i is beyond the vector dimension of x or less than zero, the function returns BLIS_FAILURE without taking any action. Similarly, if x is a global scalar constant such as BLIS_ONE, the function returns BLIS_FAILURE.


setijm

err_t bli_setijm
     (
       double  ar,
       double  ai,
       dim_t   i,
       dim_t   j,
       obj_t*  b
     );

Copy real and imaginary values ar and ai to the (i,j) element of object b. If elements of b are stored as real types, then only ar is copied and ai is ignored. (If b contains elements stored in single precision, the corresponding elements are typecast/demoted during the copy.) If either the row offset i is beyond the m dimension of b or less than zero, or column offset j is beyond the n dimension of b or less than zero, the function returns BLIS_FAILURE without taking any action. Similarly, if b is a global scalar constant such as BLIS_ONE, the function returns BLIS_FAILURE.


eqsc

void bli_eqsc
     (
       obj_t*  chi,
       obj_t*  psi,
       bool*   is_eq
     );

Perform an element-wise comparison between scalars chi and psi and store the boolean result in the bool pointed to by is_eq. If exactly one of conj(chi) or conj(psi) (but not both) indicate a conjugation, then one of the scalars will be implicitly conjugated for purposes of the comparision.

Observed object properties: conj?(chi), conj?(psi).


eqv

void bli_eqv
     (
       obj_t*  x,
       obj_t*  y,
       bool*   is_eq
     );

Perform an element-wise comparison between vectors x and y and store the boolean result in the bool pointed to by is_eq. If exactly one of conj(x) or conj(y) (but not both) indicate a conjugation, then one of the vectors will be implicitly conjugated for purposes of the comparision.

Observed object properties: conj?(x), conj?(y).


eqm

void bli_eqm
     (
       obj_t*  a,
       obj_t*  b,
       bool*   is_eq
     );

Perform an element-wise comparison between matrices A and B and store the boolean result in the bool pointed to by is_eq. Here, A is stored as a dense matrix, or lower- or upper-triangular/trapezoidal matrix with arbitrary diagonal offset and unit or non-unit diagonal. If diag(A) indicates a unit diagonal, the diagonals of both matrices will be ignored for purposes of the comparision. If uplo(A) indicates lower or upper storage, only that part of both matrices A and B will be referenced. If exactly one of trans(A) or trans(B) (but not both) indicate a transposition, then one of the matrices will be transposed for purposes of the comparison. Similarly, if exactly one of trans(A) or trans(B) (but not both) indicate a conjugation, then one of the matrices will be implicitly conjugated for purposes of the comparision.

Observed object properties: diagoff(A), diag(A), uplo(A), trans?(A), trans?(B).

Query function reference

BLIS allows applications to query information about how BLIS was configured. The bli_info_ API provides several categories of query routines. Most values are returned as a gint_t, which is a signed integer. The size of this integer can be queried through a special routine that returns the size in a character string:

char* bli_info_get_int_type_size_str( void );

Note: All of the bli_info_ functions are always thread-safe, no matter how BLIS was configured.

General library information

The following routine returns the address the full BLIS version string:

char* bli_info_get_version_str( void );

Specific configuration

The following routine returns a unique ID of type arch_t that identifies the current current active configuration:

arch_t bli_arch_query_id( void );

This is most useful when BLIS is configured with multiple configurations. (When linking to multi-configuration builds of BLIS, you don't know for sure which configuration will be used until runtime since the configuration-specific parameters are not loaded until after calling a hueristic to detect the hardware--usually based the CPUID instruction.)

Once the configuration's ID is known, it can be used to query a string that contains the name of the configuration:

char* bli_arch_string( arch_t id );

General configuration

The following routines return various general-purpose constants that affect the entire framework. All of these settings default to sane values, which can then be overridden by the configuration in bli_config.h. If they are absent from a particular configuration's bli_config.h header file, then the default value is used, as specified in frame/include/bli_config_macro_defs.h.

gint_t bli_info_get_int_type_size( void );
gint_t bli_info_get_num_fp_types( void );
gint_t bli_info_get_max_type_size( void );
gint_t bli_info_get_page_size( void );
gint_t bli_info_get_simd_num_registers( void );
gint_t bli_info_get_simd_size( void );
gint_t bli_info_get_simd_align_size( void );
gint_t bli_info_get_stack_buf_max_size( void );
gint_t bli_info_get_stack_buf_align_size( void );
gint_t bli_info_get_heap_addr_align_size( void );
gint_t bli_info_get_heap_stride_align_size( void );
gint_t bli_info_get_pool_addr_align_size( void );
gint_t bli_info_get_enable_stay_auto_init( void );
gint_t bli_info_get_enable_blas( void );
gint_t bli_info_get_blas_int_type_size( void );

Kernel information

Micro-kernel implementation type query

The following routines allow the caller to obtain a string that identifies the implementation type of each microkernel that is currently active (ie: part of the current active configuration, as identified bi bli_arch_query_id()).

char* bli_info_get_gemm_ukr_impl_string( ind_t method, num_t dt )
char* bli_info_get_gemmtrsm_l_ukr_impl_string( ind_t method, num_t dt )
char* bli_info_get_gemmtrsm_u_ukr_impl_string( ind_t method, num_t dt )
char* bli_info_get_trsm_l_ukr_impl_string( ind_t method, num_t dt )
char* bli_info_get_trsm_u_ukr_impl_string( ind_t method, num_t dt )

Possible implementation (ie: the ind_t method argument) types are:

  • BLIS_1M: Implementation based on the 1m method. (This is the default induced method when real domain kernels are present but complex kernels are missing.)
  • BLIS_NAT: Implementation based on "native" execution (ie: NOT an induced method).

Possible microkernel types (ie: the return values for bli_info_get_*_ukr_impl_string()) are:

  • BLIS_REFERENCE_UKERNEL ("refrnce"): This value is returned when the queried microkernel is provided by the reference implementation.
  • BLIS_VIRTUAL_UKERNEL ("virtual"): This value is returned when the queried microkernel is driven by a the "virtual" microkernel provided by an induced method. This happens for any method value that is not BLIS_NAT (ie: native), but only applies to the complex domain.
  • BLIS_OPTIMIZED_UKERNEL ("optimzd"): This value is returned when the queried microkernel is provided by an implementation that is neither reference nor virtual, and thus we assume the kernel author would deem it to be "optimized". Such a microkernel may not be optimal in the literal sense of the word, but nonetheless is intended to be optimized, at least relative to the reference microkernels.
  • BLIS_NOTAPPLIC_UKERNEL ("notappl"): This value is returned usually when performing a gemmtrsm or trsm microkernel type query for any method value that is not BLIS_NAT (ie: native). That is, induced methods cannot be (purely) used on trsm-based microkernels because these microkernels perform more a triangular inversion, which is not matrix multiplication.

Clock functions


clock

double bli_clock
     (
       void
     );

Return the amount of time that has elapsed since some fixed time in the past. The return values of bli_clock() typically feature nanosecond precision, though this is not guaranteed.

Note: On Linux, bli_clock() is implemented in terms of clock_gettime() using the clockid_t value of CLOCK_MONOTONIC. On OS X, bli_clock is implemented in terms of mach_absolute_time(). And on Windows, bli_clock is implemented in terms of QueryPerformanceFrequency(). Please see frame/base/bli_clock.c for more details. Note: This function is returns meaningless values when BLIS is configured with --disable-system.


clock_min_diff

double bli_clock_min_diff
     (
       double  time_prev_min,
       double  time_start
     );

This function computes an intermediate value, time_diff, equal to bli_clock() - time_start, and then tentatively prepares to return the minimum value of time_diff and time_min. If that minimum value is extremely small (close to zero), the function returns time_min instead.

This function is meant to be used in conjuction with bli_clock() for performance timing within applications--specifically in loops where only the fastest timing is of interest. For example:

double t_save = DBL_MAX;
for( i = 0; i < 3; ++i )
{
   double t = bli_clock();
   bli_gemm( ... );
   t_save = bli_clock_min_diff( t_save, t );
}
double gflops = ( 2.0 * m * k * n ) / ( t_save * 1.0e9 );

This code calls bli_gemm() three times and computes the performance, in GFLOPS, of the fastest of the three executions.


Example code

BLIS provides lots of example code in the examples/oapi directory of the BLIS source distribution. The example code in this directory is set up like a tutorial, and so we recommend starting from the beginning. Topics include creating and managing objects, printing vectors and matrices, setting and querying object properties, and calling a representative subset of the computational level-1v, -1m, -2, -3, and utility operations documented above. Please read the README contained within the examples/oapi directory for further details.