Mathematical Operations

The following classes are all defined within the namespace HIPP::ALGORITHM.

class OuterProduct
template<typename It, typename UnaryOp>
static void indices(It b, It e, UnaryOp &&op)
template<typename It, typename UnaryOp, typename ItStk>
static void indices(It b, It e, UnaryOp &&op, ItStk it_stk)

Outer product of index lists, i.e., \((0,1,...,n_0-1)\times(0,1,...,n_1-1), ..., (0,1,...,n_{K-1}-1)\), where \(\times\) is the Cartesian product. The result is an array of \(n=n_0 \times n_1 \times ... \times n_{K-1}\) vectors.

The size \(n\) can be extremely large. To avoid significant memory consumption, the above functions do not return the results, but accept an operator which acts on each of the result vectors.

Arguments:

Template paramsters It and ItStk must be random accessible iterators referring to signed or unsigned integers.

b and e define the upper limits of indices, i.e., the loop on the range [b, e) gives \(n_0, n_1, ..., n_{K-1}\) (all must be positive), where e-b==K. If b >= e, the functions have no effect.

op is the operator acting on each of the result vector. It is called as op(ptr) where ptr is a random access iterator referring to the first element of the result vector. In the first overload, ptr is a pointer to an array of elements with the same type as *b. In the second overload, ptr is typed ItStk.

it_stk is a buffer. If provided, internal buffer allocation is avoided. The buffer length must be equal or large than max(e-b, 0)+1.

Complexity:

The algorithm has a time complexity \(\mathcal{O}(n)\).

In the first overload, a buffer sized K+1 is allocated. In the second overload, no extra space is allocated.

Example:

const int n = 2;
int maxs[n] = {2, 3};
auto op = [n](int *p){ pout << '(', pout(p, p+n), ") "; };
OuterProduct::indices(maxs, maxs+n, op);

Output are

(0,0) (0,1) (0,2) (1,0) (1,1) (1,2)
template<typename T>
class LinSpaced

Produce linear-spaced values. Let \(s\), \(n\), \(\epsilon\) to be the starting value, number of values and the stride, respectively, LinSpaced produces the following sequence

\[(s,\ s+\epsilon,\ s+2 \epsilon,\ ...,\ s+(n-1)\epsilon)\]
typedef std::ptrdiff_t diff_t
typedef T value_t

diff_t is used to represent the number of values. value_t is the type of result values.

LinSpaced(value_t start, diff_t n, value_t stride = value_t(1)) noexcept

Initialize the linear-spaced sequence by providing the starting value start, number of values n and the stride stride.

The value sequence is not directly produced on the construction. To get the value sequence, call the following methods.

template<typename It>
const LinSpaced &operator>>(It b) const

Write the sequence into a range started from the output iterator b.

template<typename Container>
const LinSpaced &get_to(Container &c) const

Write the sequence into a container c. clear() is called on c, and values are written by push_back() into c.

template<typename Container = vector<value_t>>
Container get() const

Get the sequence of values. Defaultly it returns a std::vector.

Example:

The following codes show how to produce linear-spaced sequences:

int a[4];
double b[2][4];
vector<float> c;

/* write linearly-spaced values into an array */
LinSpaced(1, 4) >> a;
pout << "Int Array: ", pout(a, a+4), endl;

/* row-major writting is used for high-dimensional array */
LinSpaced(0., 8, 10.0) >> b[0];
pout << "Double Array:\n",
        PrtArray(b[0], b[0]+8).ncol(4).width(3), endl;

/* get() returns a new vector. get_to() writes into an existing vector */
c = LinSpaced(float(0.), 4).get();
pout << "Float Vector: ", c, endl;

LinSpaced(float(0.), 8).get_to(c);
pout << "Float Vector: ", c, endl;

/* write log-spaced values into vector */
LogSpaced(float(0.), 6, float(0.2)).get_to(c);
pout << "Float Vector: ", c, endl;

Here, values are printed into the “pretty stream” HIPP::pout (similar to std::cout). HIPP::PrtArray is used to format the 2-d array. The output is

Int Array: 1,2,3,4
Double Array:
  0, 10, 20, 30,
 40, 50, 60, 70
Float Vector: 0,1,2,3
Float Vector: 0,1,2,3,4,5,6,7
Float Vector: 1,1.58489,2.51189,3.98107,6.30957,10
template<typename T>
class LogSpaced

Produce log10-spaced values. Let \(s\), \(n\), \(\epsilon\) to be the starting value, number of values and the stride, respectively, LogSpaced produces the following sequence

\[(10^s,\ 10^{s+\epsilon},\ 10^{s+2 \epsilon},\ ...,\ 10^{s+(n-1)\epsilon})\]
typedef std::ptrdiff_t diff_t
typedef T value_t

diff_t is used to represent the number of values. value_t is the type of result values.

LogSpaced(value_t start, diff_t n, value_t stride = value_t(1)) noexcept

Initialize the log-spaced sequence by providing the starting value start, number of values n and the stride stride.

The value sequence is not directly produced on the construction. To get the value sequence, call the following methods.

template<typename It>
const LogSpaced &operator>>(It b) const

Write the sequence into a range started from the output iterator b.

template<typename Container>
const LogSpaced &get_to(Container &c) const

Write the sequence into a container c. clear() is called on c, and values are written by push_back() into c.

template<typename Container = vector<value_t>>
Container get() const

Get the sequence of values. Defaultly it returns a std::vector.

Example: see the example in LinSpaced.