#ifndef MIX_HPP #define MIX_HPP #include // Use like `Householder::inPlace(data)` - size must be ≥ 1 template class Householder { static constexpr T multiplier{-2.0/size}; public: static void inPlace(T *arr) { double sum = 0; for (int i = 0; i < size; ++i) { sum += arr[i]; } sum *= multiplier; for (int i = 0; i < size; ++i) { arr[i] += sum; } }; }; // Use like `Hadamard::inPlace(data)` - size must be a power of 2 template class Hadamard { public: static inline void recursiveUnscaled(T * data) { if (size <= 1) { return; } constexpr int hSize = size/2; // Two (unscaled) Hadamards of half the size Hadamard::recursiveUnscaled(data); Hadamard::recursiveUnscaled(data + hSize); // Combine the two halves using sum/difference for (int i = 0; i < hSize; ++i) { double a = data[i]; double b = data[i + hSize]; data[i] = (a + b); data[i + hSize] = (a - b); } } static inline void inPlace(T * data) { recursiveUnscaled(data); T scalingFactor = std::sqrt(1.0/size); for (int c = 0; c < size; ++c) { data[c] *= scalingFactor; } } }; template class Shuffle { public: static inline void outOfPlace(T in[size], T out[size], const int shuffle_spec[size]) { for (int c=0; c < size; c++) { T sign = 1; int s = shuffle_spec[c]; if (s < 0) { sign = -1; s *= -1; } if (s >= size) { s = 0; } out[s] = sign * in[c]; } }; static inline void inPlace(T in_out[size], const int shuffle_spec[size]) { T temp[size]; for (int c=0; c < size; c++) { temp[c] = in_out[c]; } Shuffle::outOfPlace(temp, in_out, shuffle_spec); }; }; template class Mix { public: static inline void split(T in, T out[size]) { for (uint c=0; c < size; c++) { out[c] = in; } } static inline T combine(T in_out[size]) { Householder::inPlace(in_out); return in_out[0]; } }; #endif