NABLA  Nabla Ain't Basic Linear Algebra
Complexity Concept

Actually all expressions have their algorithmic complexity.

In context of this library complexity of an operation means an estimation of it's algorithmic complexity.

For example imagine we are adding two vectors. That means we add together corresponding elements of these vectors and thus we get the resulting vector. Number of sums is equal to initial vectors' size, i.e. n. Thus we can speak about linear complexity because our effort for computing result are growing linearly in size of the initial vectors. In so called "big O" notation we have an O(n) complexity.

Expressions have the following complexity values:

All these values are conventional of course.

This information is very useful to decide what to do with objects provided by reference: copy the result to a temporary or to use "as is", whichever seems to be faster. For example imagine a function which has to perform some operation getting a reference to an expression. If the operation refers to each element of the source expression only once then there is no need to store the result of expression evaluation to a temporary storage. Even if the expression has high complexity copying the result to temporary is not necessary. The different case is when the operation needs the value of an arbitrary element several times during a computation. If the complexity of the source expression is higher than constant value (i.e. O(1)) then sequential computations of same element will bring nothing but sorrow. Instead, the result of the source expression must be saved in a temporary and then used with much less overal performance penalty.

There is a rule for "big O" arithmetic: if you add two values then the dominating one wins, i.e.
O(na) + O(nb) equates to O(nmax(a, b)).
Another example:
O(n) + O(n log n) equates to O(n log n)
(because (n log n) dominates over n).

It also applies to matrix and vector expressions: if an expresion with complexity O(na) is a subexpression of an expression with complexity O(nb) then the actual complexity of the whole composite expression is O(nmax(a, b)).

The same applies to binary expressions:
bin_expression(O(na))( expression1(O(nb)), expression2(O(nc) )
actually has complexity O(na) + O(nb) + O(nc) which equates to O(nmax(a, b, c)).

For example imagine two matrices n by n elements each are multiplied. That is an O(n3) operation. Then it need to be transposed. Generally speaking a transposition is an O(1) operation because one only needs to swap indeces of elements. But a transposition of a matrix multiplication has algorithmic complexity O(n3).

Consider complexitiy of different expressions (m denotes a matrix, v denotes a vector and s denotes a scalar value):

Member nabla::conj (const matrix_expression< value_t, expr_t, tag > &a)
conj(m): algorithmic complexity of this operation is constant (i.e. O(1)).
Member nabla::conj (const matrix_expression< value_t, expr_t, tag > &a)
conj(m): algorithmic complexity of this operation is constant (i.e. O(1)).
Member nabla::conj (const vector_expression< value_t, expr_t, tag > &a)
conj(v): algorithmic complexity of this operation is constant (i.e. O(1)).
Member nabla::conj (const vector_expression< value_t, expr_t, tag > &a)
conj(v): algorithmic complexity of this operation is constant (i.e. O(1)).
Member nabla::div (const vector_expression< value_t, expr1, tag1 > &left, const vector_expression< value_t, expr2, tag2 > &right)
div(v, v): algorithmic complexity of this operation is linear (i.e. O(n)).
Member nabla::div (const vector_expression< value_t, expr1, tag1 > &left, const vector_expression< value_t, expr2, tag2 > &right)
div(v, v): algorithmic complexity of this operation is linear (i.e. O(n)).
Member nabla::div (const matrix_expression< value_t, expr1, tag1 > &left, const matrix_expression< value_t, expr2, tag2 > &right)
mul(m, m): algorithmic complexity of this operation is square (i.e. O(n2)).
Member nabla::div (const matrix_expression< value_t, expr1, tag1 > &left, const matrix_expression< value_t, expr2, tag2 > &right)
mul(m, m): algorithmic complexity of this operation is square (i.e. O(n2)).
Member nabla::dot_product (const vector_expression< value_t, expr1, tag1 > &v1, const vector_expression< value_t, expr2, tag2 > &v2)
dot_product(v, v): algorithmic complexity of this operation is linear (i.e. O(n)).
Member nabla::dot_product (const vector_expression< value_t, expr1, tag1 > &v1, const vector_expression< value_t, expr2, tag2 > &v2)
dot_product(v, v): algorithmic complexity of this operation is linear (i.e. O(n)).
Member nabla::map (const matrix_expression< value_t, expr1, tag1 > &linear_map, const vector_expression< value_t, expr2, tag2 > &v)
map(m, v): algorithmic complexity of this operation is square (i.e. O(n2)).
Member nabla::map (const matrix_expression< value_t, expr1, tag1 > &linear_map, const vector_expression< value_t, expr2, tag2 > &v)
map(m, v): algorithmic complexity of this operation is square (i.e. O(n2)).
Member nabla::mul (const vector_expression< value_t, expr1, tag1 > &left, const vector_expression< value_t, expr2, tag2 > &right)
mul(v, v): algorithmic complexity of this operation is linear (i.e. O(n)).
Member nabla::mul (const matrix_expression< value_t, expr1, tag1 > &left, const matrix_expression< value_t, expr2, tag2 > &right)
mul(m, m): algorithmic complexity of this operation is square (i.e. O(n2)).
Member nabla::mul (const matrix_expression< value_t, expr1, tag1 > &left, const matrix_expression< value_t, expr2, tag2 > &right)
mul(m, m): algorithmic complexity of this operation is square (i.e. O(n2)).
Member nabla::mul (const vector_expression< value_t, expr1, tag1 > &left, const vector_expression< value_t, expr2, tag2 > &right)
mul(v, v): algorithmic complexity of this operation is linear (i.e. O(n)).
Member nabla::norm (const vector_expression< value_t, expr_t, tag > &v)
norm(v): algorithmic complexity of this operation is linear (i.e. O(n)).
Member nabla::norm (const vector_expression< value_t, expr_t, tag > &v)
norm(v): algorithmic complexity of this operation is linear (i.e. O(n)).
Member nabla::operator* (const matrix_expression< value_t, expr1, tag1 > &left, const vector_expression< value_t, expr2, tag2, orientation::column > &right)
m*v: algorithmic complexity of this operation is square (i.e. O(n2)).
Member nabla::operator* (const vector_expression< value_t, expr_t, tag > &a, const typename expr_t::value_type &s)
v*s: algorithmic complexity of this operation is linear (i.e.
Member nabla::operator* (const typename expr_t::value_type &s, const vector_expression< value_t, expr_t, tag > &a)
s*v: algorithmic complexity of this operation is linear (i.e.
Member nabla::operator* (const matrix_expression< value_t, expr_t, tag > &a, const typename expr_t::value_type &s)
m*s: algorithmic complexity of this operation is square (i.e.
Member nabla::operator* (const matrix_expression< value_t, expr_t, tag > &a, const typename expr_t::value_type &s)
m*s: algorithmic complexity of this operation is square (i.e.
Member nabla::operator* (const typename expr_t::value_type &s, const matrix_expression< value_t, expr_t, tag > &a)
s*m: algorithmic complexity of this operation is square (i.e.
Member nabla::operator* (const matrix_expression< value_t, expr1, tag1 > &left, const matrix_expression< value_t, expr2, tag2 > &right)
m*m: algorithmic complexity of this operation is cubic (i.e. O(n3)).
Member nabla::operator* (const matrix_expression< value_t, expr1, tag1 > &left, const matrix_expression< value_t, expr2, tag2 > &right)
m*m: algorithmic complexity of this operation is cubic (i.e. O(n3)).
Member nabla::operator* (const matrix_expression< value_t, expr1, tag1 > &left, const vector_expression< value_t, expr2, tag2, orientation::column > &right)
m*v: algorithmic complexity of this operation is square (i.e. O(n2)).
Member nabla::operator* (const vector_expression< value_t, expr_t, tag > &a, const typename expr_t::value_type &s)
v*s: algorithmic complexity of this operation is linear (i.e.
Member nabla::operator* (const typename expr_t::value_type &s, const vector_expression< value_t, expr_t, tag > &a)
s*v: algorithmic complexity of this operation is linear (i.e.
Member nabla::operator* (const typename expr_t::value_type &s, const matrix_expression< value_t, expr_t, tag > &a)
s*m: algorithmic complexity of this operation is square (i.e.
Member nabla::operator*= (vector_expression< value_t, expr_t, tag::reference > &left, const value_t &right)
v *= s: algorithmic complexity of this operation is linear (i.e. O(n)).
Member nabla::operator*= (matrix_expression< value_t, expr1, tag::storage > &left, const matrix_expression< value_t, expr2, tag2 > &right)
m *= m: algorithmic complexity of this operation is cubic (i.e. O(n3)).
Member nabla::operator*= (vector_expression< value_t, expr_t, tag::storage > &left, const value_t &right)
v *= s: algorithmic complexity of this operation is linear (i.e.
Member nabla::operator*= (vector_expression< value_t, expr_t, tag::reference > &left, const value_t &right)
v *= s: algorithmic complexity of this operation is linear (i.e. O(n)).
Member nabla::operator*= (vector_expression< value_t, expr_t, tag::storage > &left, const value_t &right)
v *= s: algorithmic complexity of this operation is linear (i.e.
Member nabla::operator*= (matrix_expression< value_t, expr_t, tag::storage > &left, const value_t &right)
m *= s: algorithmic complexity of this operation is square (i.e.
Member nabla::operator*= (matrix_expression< value_t, expr1, tag::storage > &left, const matrix_expression< value_t, expr2, tag2 > &right)
m *= m: algorithmic complexity of this operation is cubic (i.e. O(n3)).
Member nabla::operator*= (matrix_expression< value_t, expr_t, tag::storage > &left, const value_t &right)
m *= s: algorithmic complexity of this operation is square (i.e.
Member nabla::operator+ (const vector_expression< value_t, expr_t, tag > &a)
+v: algorithmic complexity of this operation is constant (i.e.
Member nabla::operator+ (const matrix_expression< value_t, expr1, tag1 > &left, const matrix_expression< value_t, expr2, tag2 > &right)
m + m: algorithmic complexity of this operation is square (i.e. O(n2)).
Member nabla::operator+ (const vector_expression< value_t, expr1, tag1 > &left, const vector_expression< value_t, expr2, tag2 > &right)
v + v: algorithmic complexity of this operation is linear (i.e. O(n)).
Member nabla::operator+ (const vector_expression< value_t, expr1, tag1 > &left, const vector_expression< value_t, expr2, tag2 > &right)
v + v: algorithmic complexity of this operation is linear (i.e. O(n)).
Member nabla::operator+ (const matrix_expression< value_t, expr_t, tag > &a)
+m: algorithmic complexity of this operation is constant (i.e.
Member nabla::operator+ (const matrix_expression< value_t, expr_t, tag > &a)
+m: algorithmic complexity of this operation is constant (i.e.
Member nabla::operator+ (const vector_expression< value_t, expr_t, tag > &a)
+v: algorithmic complexity of this operation is constant (i.e.
Member nabla::operator+ (const matrix_expression< value_t, expr1, tag1 > &left, const matrix_expression< value_t, expr2, tag2 > &right)
m + m: algorithmic complexity of this operation is square (i.e. O(n2)).
Member nabla::operator+= (vector_expression< value_t, expr1, tag::storage > &left, const vector_expression< value_t, expr2, tag2 > &right)
v += v: algorithmic complexity of this operation is linear (i.e. O(n)).
Member nabla::operator+= (vector_expression< value_t, expr1, tag::reference > &left, const vector_expression< value_t, expr2, tag2 > &right)
v += v: algorithmic complexity of this operation is linear (i.e. O(n)).
Member nabla::operator+= (vector_expression< value_t, expr1, tag::storage > &left, const vector_expression< value_t, expr2, tag2 > &right)
v += v: algorithmic complexity of this operation is linear (i.e. O(n)).
Member nabla::operator+= (vector_expression< value_t, expr1, tag::reference > &left, const vector_expression< value_t, expr2, tag2 > &right)
v += v: algorithmic complexity of this operation is linear (i.e. O(n)).
Member nabla::operator+= (matrix_expression< value_t, expr1, tag::storage > &left, const matrix_expression< value_t, expr2, tag2 > &right)
m += m: algorithmic complexity of this operation is square (i.e. O(n2)).
Member nabla::operator+= (matrix_expression< value_t, expr1, tag::storage > &left, const matrix_expression< value_t, expr2, tag2 > &right)
m += m: algorithmic complexity of this operation is square (i.e. O(n2)).
Member nabla::operator- (const vector_expression< value_t, expr1, tag1 > &left, const vector_expression< value_t, expr2, tag2 > &right)
v - v: algorithmic complexity of this operation is linear (i.e. O(n)).
Member nabla::operator- (const matrix_expression< value_t, expr_t, tag > &a)
-m: algorithmic complexity of this operation is constant (i.e.
Member nabla::operator- (const vector_expression< value_t, expr1, tag1 > &left, const vector_expression< value_t, expr2, tag2 > &right)
v - v: algorithmic complexity of this operation is linear (i.e. O(n)).
Member nabla::operator- (const matrix_expression< value_t, expr_t, tag > &a)
-m: algorithmic complexity of this operation is constant (i.e.
Member nabla::operator- (const matrix_expression< value_t, expr1, tag1 > &left, const matrix_expression< value_t, expr2, tag2 > &right)
m - m: algorithmic complexity of this operation is square (i.e. O(n2)).
Member nabla::operator- (const matrix_expression< value_t, expr1, tag1 > &left, const matrix_expression< value_t, expr2, tag2 > &right)
m - m: algorithmic complexity of this operation is square (i.e. O(n2)).
Member nabla::operator- (const vector_expression< value_t, expr_t, tag > &a)
-v: algorithmic complexity of this operation is constant (i.e.
Member nabla::operator- (const vector_expression< value_t, expr_t, tag > &a)
-v: algorithmic complexity of this operation is constant (i.e.
Member nabla::operator-= (vector_expression< value_t, expr1, tag::storage > &left, const vector_expression< value_t, expr2, tag2 > &right)
v -= v: algorithmic complexity of this operation is linear (i.e. O(n)).
Member nabla::operator-= (vector_expression< value_t, expr1, tag::reference > &left, const vector_expression< value_t, expr2, tag2 > &right)
v -= v: algorithmic complexity of this operation is linear (i.e. O(n)).
Member nabla::operator-= (vector_expression< value_t, expr1, tag::storage > &left, const vector_expression< value_t, expr2, tag2 > &right)
v -= v: algorithmic complexity of this operation is linear (i.e. O(n)).
Member nabla::operator-= (matrix_expression< value_t, expr1, tag::storage > &left, const matrix_expression< value_t, expr2, tag2 > &right)
m -= m: algorithmic complexity of this operation is square (i.e. O(n2)).
Member nabla::operator-= (vector_expression< value_t, expr1, tag::reference > &left, const vector_expression< value_t, expr2, tag2 > &right)
v -= v: algorithmic complexity of this operation is linear (i.e. O(n)).
Member nabla::operator-= (matrix_expression< value_t, expr1, tag::storage > &left, const matrix_expression< value_t, expr2, tag2 > &right)
m -= m: algorithmic complexity of this operation is square (i.e. O(n2)).
Member nabla::reshape (const matrix_expression< value_t, expr_t, tag > &a)
reshape<shape_id>(m): algorithmic complexity of this operation is constant (i.e. O(1)).
Member nabla::reshape (const matrix_expression< value_t, expr_t, tag > &a)
reshape<shape_id>(m): algorithmic complexity of this operation is constant (i.e. O(1)).
Member nabla::sqrnorm (const vector_expression< value_t, expr_t, tag > &v)
sqrnorm(v): algorithmic complexity of this operation is linear (i.e. O(n)).
Member nabla::sqrnorm (const vector_expression< value_t, expr_t, tag > &v)
sqrnorm(v): algorithmic complexity of this operation is linear (i.e. O(n)).
Member nabla::sum_of_products (const vector_expression< value_t, expr1, tag1 > &a, const vector_expression< value_t, expr2, tag2 > &b)
sum_of_products(v, v): algorithmic complexity of this operation is linear (i.e. O(n)).
Member nabla::sum_of_products (const vector_expression< value_t, expr1, tag1 > &a, const vector_expression< value_t, expr2, tag2 > &b)
sum_of_products(v, v): algorithmic complexity of this operation is linear (i.e. O(n)).
Member nabla::swap (vector_expression< value_t, expr1, tag::storage > &a, vector_expression< value_t, expr2, tag::storage > &b)
swap(v, v): algorithmic complexity of this operation is linear (i.e. O(n)).
Member nabla::swap (vector_expression< value_t, expr1, tag::storage > &a, vector_expression< value_t, expr2, tag::storage > &b)
swap(v, v): algorithmic complexity of this operation is linear (i.e. O(n)).
Member nabla::swap (vector_expression< value_t, expr1, tag::storage > &a, vector_ref< expr2, tag::reference, orientation > b)
swap(v, v): algorithmic complexity of this operation is linear (i.e. O(n)).
Member nabla::swap (vector_expression< value_t, expr1, tag::storage > &a, vector_ref< expr2, tag::reference, orientation > b)
swap(v, v): algorithmic complexity of this operation is linear (i.e. O(n)).
Member nabla::transpose (const matrix_expression< value_t, expr_t, tag > &a)
transpose(m): algorithmic complexity of this operation is constant (i.e.
Member nabla::transpose (const matrix_expression< value_t, expr_t, tag > &a)
transpose(m): algorithmic complexity of this operation is constant (i.e.