Vector Dot Product (dotprod
)¶
This module provides interfaces for computing a vector dot product between two equally-sized vectors. Dot products are commonly used in digital signal processing for communications, particularly in filtering and matrix operations. Given two vectors of equal length \(\vec{x} = \left[x(0),x(1),\ldots,x(N-1)\right]^T\) and \(\vec{v} = \left[v(0),v(1),\ldots,v(N-1)\right]^T\), the vector dot product between them is computed as
A number of other liquid modules rely on dotprod, such as filtering and equalization.
Specific machine architectures¶
The vector dot product has a complexity of \(\mathcal{O}(N)\) multiply-and-accumulate operations. Because of its prevalence in multimedia applications, a considerable amount of research has been put into computing the vector dot product as efficiently as possible. Software-defined radio is no exception as basic profiling will likely demonstrate that a considerable portion of the processor is spent computing it. Certain machine architectures have specific instructions for computing vector dot products, particularly those which use a single instruction for multiple data (SIMD) such as MMX, SSE, AVX, AltiVec, and Neon.
Interface¶
There are effectively two ways to use the dotprod module. In the first and most general case, a vector dot product is computed on two input vectors \(\vec{x}\) and \(\vec{v}\) whose values are not known a priori. In the second case, a dotprod object is created around vector \(\vec{v}\) which does not change (or rarely changes) throughout its life cycle. This is the more convenient method for filtering objects which don’t usually have time-dependent coefficients. Listed below is a simple interface example to the dotprod module object:
#include <liquid/liquid.h>
int main() {
// create input arrays
float x[] = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f};
float v[] = { 0.1f, -0.2f, 1.0f, -0.2f, 0.1f};
float y;
// run the basic vector dot product, store in 'y'
dotprod_rrrf_run(x,v,5,&y);
// create dotprod object and execute, store in 'y'
dotprod_rrrf q = dotprod_rrrf_create(v,5);
dotprod_rrrf_execute(q,x,&y);
dotprod_rrrf_destroy(q);
}
In both cases the dotprod can be easily integrated with the window object ([section-buffer-window]) for managing input data and alignment. There are three types of dot product objects and are listed in [tab-dotprod-objects].
Precision |
Input/Output |
Coefficients |
Interface |
---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
Listed below is the full interface to the dotprod
family of
objects.
run()
¶
Run dot product without creating object. This is less efficient than creating the object as it is an unoptimized portable implementation that doesn’t take advantage of processor extensions. It is meant to provide a baseline for performance comparison and a convenient way to invoke a dot product operation when fast operation is not necessary.
int = dotprod_rrrf_run(float * _v, float * _x, unsigned int _n, float * _y);
float * _v
: coefficients arrayfloat * _x
: input arrayunsigned int _n
: dotprod lengthfloat * _y
: output sample pointerreturns standard error code
int = dotprod_cccf_run(float complex * _v, float complex * _x, unsigned int _n, float complex * _y);
float complex * _v
: coefficients arrayfloat complex * _x
: input arrayunsigned int _n
: dotprod lengthfloat complex * _y
: output sample pointerreturns standard error code
int = dotprod_crcf_run(float * _v, float complex * _x, unsigned int _n, float complex * _y);
float * _v
: coefficients arrayfloat complex * _x
: input arrayunsigned int _n
: dotprod lengthfloat complex * _y
: output sample pointerreturns standard error code
run4()
¶
This provides the same unoptimized operation as the ‘run()’ method above, but with the loop unrolled by a factor of 4. It is marginally faster than ‘run()’ without unrolling the loop.
int = dotprod_rrrf_run4(float * _v, float * _x, unsigned int _n, float * _y);
float * _v
: coefficients arrayfloat * _x
: input arrayunsigned int _n
: dotprod lengthfloat * _y
: output sample pointerreturns standard error code
int = dotprod_cccf_run4(float complex * _v, float complex * _x, unsigned int _n, float complex * _y);
float complex * _v
: coefficients arrayfloat complex * _x
: input arrayunsigned int _n
: dotprod lengthfloat complex * _y
: output sample pointerreturns standard error code
int = dotprod_crcf_run4(float * _v, float complex * _x, unsigned int _n, float complex * _y);
float * _v
: coefficients arrayfloat complex * _x
: input arrayunsigned int _n
: dotprod lengthfloat complex * _y
: output sample pointerreturns standard error code
create()
¶
Create vector dot product object
dotprod_rrrf = dotprod_rrrf_create(float * _v, unsigned int _n);
float * _v
: coefficients arrayunsigned int _n
: dotprod lengthreturns new
dotprod_rrrf
object
dotprod_cccf = dotprod_cccf_create(float complex * _v, unsigned int _n);
float complex * _v
: coefficients arrayunsigned int _n
: dotprod lengthreturns new
dotprod_cccf
object
dotprod_crcf = dotprod_crcf_create(float * _v, unsigned int _n);
float * _v
: coefficients arrayunsigned int _n
: dotprod lengthreturns new
dotprod_crcf
object
create_rev()
¶
Create vector dot product object with time-reversed coefficients
dotprod_rrrf = dotprod_rrrf_create_rev(float * _v, unsigned int _n);
float * _v
: time-reversed coefficients arrayunsigned int _n
: dotprod lengthreturns new
dotprod_rrrf
object
dotprod_cccf = dotprod_cccf_create_rev(float complex * _v, unsigned int _n);
float complex * _v
: time-reversed coefficients arrayunsigned int _n
: dotprod lengthreturns new
dotprod_cccf
object
dotprod_crcf = dotprod_crcf_create_rev(float * _v, unsigned int _n);
float * _v
: time-reversed coefficients arrayunsigned int _n
: dotprod lengthreturns new
dotprod_crcf
object
recreate()
¶
Re-create dot product object of potentially a different length with different coefficients. If the length of the dot product object does not change, no memory reallocation is invoked.
dotprod_rrrf = dotprod_rrrf_recreate(dotprod_rrrf _q, float * _v, unsigned int _n);
dotprod_rrrf _q
: old dotprod objectfloat * _v
: coefficients arrayunsigned int _n
: dotprod lengthreturns new
dotprod_rrrf
object
dotprod_cccf = dotprod_cccf_recreate(dotprod_cccf _q, float complex * _v, unsigned int _n);
dotprod_cccf _q
: old dotprod objectfloat complex * _v
: coefficients arrayunsigned int _n
: dotprod lengthreturns new
dotprod_cccf
object
dotprod_crcf = dotprod_crcf_recreate(dotprod_crcf _q, float * _v, unsigned int _n);
dotprod_crcf _q
: old dotprod objectfloat * _v
: coefficients arrayunsigned int _n
: dotprod lengthreturns new
dotprod_crcf
object
recreate_rev()
¶
Re-create dot product object of potentially a different length with different coefficients. If the length of the dot product object does not change, no memory reallocation is invoked. Filter coefficients are stored in reverse order.
dotprod_rrrf = dotprod_rrrf_recreate_rev(dotprod_rrrf _q, float * _v, unsigned int _n);
dotprod_rrrf _q
: old dotprod objectfloat * _v
: time-reversed coefficients arrayunsigned int _n
: dotprod lengthreturns new
dotprod_rrrf
object
dotprod_cccf = dotprod_cccf_recreate_rev(dotprod_cccf _q, float complex * _v, unsigned int _n);
dotprod_cccf _q
: old dotprod objectfloat complex * _v
: time-reversed coefficients arrayunsigned int _n
: dotprod lengthreturns new
dotprod_cccf
object
dotprod_crcf = dotprod_crcf_recreate_rev(dotprod_crcf _q, float * _v, unsigned int _n);
dotprod_crcf _q
: old dotprod objectfloat * _v
: time-reversed coefficients arrayunsigned int _n
: dotprod lengthreturns new
dotprod_crcf
object
copy()
¶
Copy object including all internal objects and state
dotprod_rrrf = dotprod_rrrf_copy(dotprod_rrrf _q);
dotprod_rrrf _q
:returns new
dotprod_rrrf
object
dotprod_cccf = dotprod_cccf_copy(dotprod_cccf _q);
dotprod_cccf _q
:returns new
dotprod_cccf
object
dotprod_crcf = dotprod_crcf_copy(dotprod_crcf _q);
dotprod_crcf _q
:returns new
dotprod_crcf
object
destroy()
¶
Destroy dotprod object, freeing all internal memory
int = dotprod_rrrf_destroy(dotprod_rrrf _q);
dotprod_rrrf _q
:returns standard error code
int = dotprod_cccf_destroy(dotprod_cccf _q);
dotprod_cccf _q
:returns standard error code
int = dotprod_crcf_destroy(dotprod_crcf _q);
dotprod_crcf _q
:returns standard error code
print()
¶
Print dotprod object internals to standard output
int = dotprod_rrrf_print(dotprod_rrrf _q);
dotprod_rrrf _q
:returns standard error code
int = dotprod_cccf_print(dotprod_cccf _q);
dotprod_cccf _q
:returns standard error code
int = dotprod_crcf_print(dotprod_crcf _q);
dotprod_crcf _q
:returns standard error code
execute()
¶
Execute dot product on an input array
int = dotprod_rrrf_execute(dotprod_rrrf _q, float * _x, float * _y);
dotprod_rrrf _q
: dotprod objectfloat * _x
: input arrayfloat * _y
: output sample pointerreturns standard error code
int = dotprod_cccf_execute(dotprod_cccf _q, float complex * _x, float complex * _y);
dotprod_cccf _q
: dotprod objectfloat complex * _x
: input arrayfloat complex * _y
: output sample pointerreturns standard error code
int = dotprod_crcf_execute(dotprod_crcf _q, float complex * _x, float complex * _y);
dotprod_crcf _q
: dotprod objectfloat complex * _x
: input arrayfloat complex * _y
: output sample pointerreturns standard error code