35#define _USE_MATH_DEFINES
47#define M_PI 3.14159265358979323846
65 template <
class T,
size_t... Dims>
67 return double(
sum(arr)) / arr.fsize();
79 template <
class T,
size_t... Dims>
83 arr.for_each([&](
const T &x) {
84 double d = double(x) - m;
87 return sq_sum / (arr.fsize() - (
sample ? 1 : 0));
99 template <
class T,
size_t... Dims>
113 template <
class T,
size_t N>
115 return std::inner_product(a.fbegin(), a.fend(), b.fbegin(),
T{});
125 template <
class T,
size_t N>
127 return std::sqrt(
double(
dot(a, a)));
138 template <
class T,
size_t N>
150 template <
class T,
size_t N>
152 double len =
norm(a);
153 if (std::abs(len) < std::numeric_limits<double>::epsilon())
return a;
155 auto ai = a.fbegin();
156 auto ri = result.fbegin();
157 while (ri != result.fend()) *ri++ = *ai++ / len;
169 template <
class T,
size_t N>
172 auto ai = a.fbegin();
173 auto bi = b.fbegin();
174 while (ai != a.fend()) {
175 double d = *ai++ - *bi++;
178 return std::sqrt(
sum);
189 template <
class T,
size_t N>
192 auto ai = a.fbegin();
193 auto bi = b.fbegin();
194 while (ai != a.fend())
sum += std::abs(*ai++ - *bi++);
199#ifndef CONSOLE_MATMUL_BLOCK_SIZE
200#define CONSOLE_MATMUL_BLOCK_SIZE 128
213 template <
class T,
size_t M,
size_t N,
size_t K>
219 for (
size_t i0 = 0; i0 <
M; i0 += BLOCK)
220 for (
size_t j0 = 0; j0 <
K; j0 += BLOCK)
221 for (
size_t k0 = 0; k0 <
N; k0 += BLOCK)
222 for (
size_t i = i0; i <
min(i0 + BLOCK,
M); ++i)
223 for (
size_t j = j0; j <
min(j0 + BLOCK,
K); ++j)
224 for (
size_t k = k0; k <
min(k0 + BLOCK,
N); ++k)
225 C[i][j] +=
A[i][k] *
B[k][j];
239 template <
class T,
size_t M,
size_t N,
size_t K>
243 for (
size_t i = 0; i <
M; ++i)
244 for (
size_t j = 0; j <
K; ++j)
245 for (
size_t k = 0; k <
N; ++k)
C[i][j] +=
A[i][k] *
B[k][j];
259 template <
class T,
size_t M,
size_t N,
size_t K>
276 template <
class T,
size_t M,
size_t N,
size_t K>
293 template <
class T,
size_t M,
size_t N,
size_t K>
294 inline MultiArray<T, M, K>
297 constexpr bool use_blocked =
M >= BLOCK &&
N >= BLOCK &&
K >= BLOCK;
298 return matmul_impl(
A,
B, std::integral_constant<bool, use_blocked>{});
313 template <
class T,
size_t M,
size_t N,
size_t K>
319 const size_t num_i_blocks = (
M + BLOCK - 1) / BLOCK;
320 const size_t num_j_blocks = (
K + BLOCK - 1) / BLOCK;
321 std::vector<std::future<void>> futures;
322 futures.reserve(num_i_blocks * num_j_blocks);
323 for (
size_t i0_idx = 0; i0_idx < num_i_blocks; ++i0_idx)
324 for (
size_t j0_idx = 0; j0_idx < num_j_blocks; ++j0_idx) {
325 size_t i0 = i0_idx * BLOCK;
326 size_t j0 = j0_idx * BLOCK;
328 for (
size_t k0 = 0; k0 <
N; k0 += BLOCK)
329 for (
size_t i = i0; i <
min(i0 + BLOCK,
M); ++i)
330 for (
size_t j = j0; j <
min(j0 + BLOCK,
K); ++j) {
332 for (
size_t k = k0; k <
min(k0 + BLOCK,
N); ++k)
333 sum +=
A[i][k] *
B[k][j];
338 for (
auto &f : futures) f.get();
350 template <
class T,
size_t M,
size_t N>
353 for (
size_t i = 0; i <
M; i++)
354 for (
size_t j = 0; j <
N; j++)
B[j][i] =
A[i][j];
364 template <
class T,
size_t N>
367 for (
size_t i = 0; i <
N; i++) I[i][i] =
T{1};
378 template <
class T,
size_t N>
381 for (
size_t i = 0; i <
N; i++) result +=
A[i][i];
396 a[2] * b[0] - a[0] * b[2],
397 a[0] * b[1] - a[1] * b[0]};
410 template <
class T,
size_t... Dims>
411 MultiArray<T, Dims...>
414 auto ri = result.fbegin();
415 auto ai = arr.fbegin();
416 while (ri != result.fend()) {
417 *ri = *ai < low ? low : (*ai > high ? high : *ai);
431 template <
class T,
size_t... Dims>
434 auto ri = result.fbegin();
435 auto ai = arr.fbegin();
436 while (ri != result.fend()) *ri++ = std::abs(*ai++);
449 template <
class T,
size_t... Dims>
452 arr.for_each([&](
T &x) { x = dis(
thread_rng()); });
463 template <
class T,
size_t... Dims>
466 std::normal_distribution<T> dis(
mean,
stddev);
467 arr.for_each([&](
T &x) { x = dis(
thread_rng()); });
478 template <
class T,
size_t... Dims>
480 size_t n = arr.fsize();
481 for (
size_t i = 0; i < n; i++)
482 arr.fbegin()[i] = start + (end - start) * i / (n - 1);
493 template <
class T,
size_t... Dims>
495 return std::accumulate(
496 arr.fbegin(), arr.fend(),
T{1}, std::multiplies<T>());
507 template <
class T,
size_t... Dims>
509 if (k >= arr.fsize()) k = arr.fsize() - 1;
510 std::nth_element(arr.fbegin(), arr.fbegin() + k, arr.fend());
511 return arr.fbegin()[k];
523 template <
class T,
size_t N,
size_t K>
524 MultiArray<T, N + K - 1>
527 for (
size_t i = 0; i <
N; i++) {
529 for (
size_t j = 0; j <
K; j++)
530 result[i + j] += signal[i] * kernel[j];
543 template <
class T,
size_t... Dims>
546 auto ri = result.fbegin();
547 auto ai = arr.fbegin();
548 while (ri != result.fend()) *ri++ = std::sin(*ai++);
559 template <
class T,
size_t... Dims>
562 auto ri = result.fbegin();
563 auto ai = arr.fbegin();
564 while (ri != result.fend()) *ri++ = std::cos(*ai++);
575 template <
class T,
size_t... Dims>
578 auto ri = result.fbegin();
579 auto ai = arr.fbegin();
580 while (ri != result.fend()) *ri++ = std::tan(*ai++);
591 template <
class T,
size_t... Dims>
594 auto ri = result.fbegin();
595 auto ai = arr.fbegin();
596 while (ri != result.fend()) *ri++ = std::asin(*ai++);
607 template <
class T,
size_t... Dims>
610 auto ri = result.fbegin();
611 auto ai = arr.fbegin();
612 while (ri != result.fend()) *ri++ = std::acos(*ai++);
623 template <
class T,
size_t... Dims>
626 auto ri = result.fbegin();
627 auto ai = arr.fbegin();
628 while (ri != result.fend()) *ri++ = std::atan(*ai++);
639 template <
class T,
size_t... Dims>
642 auto ri = result.fbegin();
643 auto ai = arr.fbegin();
644 while (ri != result.fend()) *ri++ = std::sinh(*ai++);
655 template <
class T,
size_t... Dims>
658 auto ri = result.fbegin();
659 auto ai = arr.fbegin();
660 while (ri != result.fend()) *ri++ = std::cosh(*ai++);
671 template <
class T,
size_t... Dims>
674 auto ri = result.fbegin();
675 auto ai = arr.fbegin();
676 while (ri != result.fend()) *ri++ = std::tanh(*ai++);
688 template <
class T,
size_t... Dims>
691 auto ri = result.fbegin();
692 auto ai = arr.fbegin();
693 while (ri != result.fend()) *ri++ = std::exp(*ai++);
704 template <
class T,
size_t... Dims>
707 auto ri = result.fbegin();
708 auto ai = arr.fbegin();
709 while (ri != result.fend()) *ri++ = std::log(*ai++);
720 template <
class T,
size_t... Dims>
723 auto ri = result.fbegin();
724 auto ai = arr.fbegin();
725 while (ri != result.fend()) *ri++ = std::log10(*ai++);
737 template <
class T,
size_t... Dims>
740 auto ri = result.fbegin();
741 auto ai = arr.fbegin();
742 while (ri != result.fend()) *ri++ = std::pow(*ai++, exponent);
754 template <
class T,
size_t... Dims>
755 MultiArray<T, Dims...>
758 auto bi = base.fbegin();
759 auto ei =
exp.fbegin();
760 auto ri = result.fbegin();
761 while (ri != result.fend()) *ri++ = std::pow(*bi++, *ei++);
773 template <
class T,
size_t... Dims>
776 auto ri = result.fbegin();
777 auto ai = arr.fbegin();
778 while (ri != result.fend()) *ri++ = std::floor(*ai++);
789 template <
class T,
size_t... Dims>
792 auto ri = result.fbegin();
793 auto ai = arr.fbegin();
794 while (ri != result.fend()) *ri++ = std::ceil(*ai++);
805 template <
class T,
size_t... Dims>
808 auto ri = result.fbegin();
809 auto ai = arr.fbegin();
810 while (ri != result.fend()) *ri++ = std::round(*ai++);
826 class Traits = std::char_traits<CharT>>
829 const std::string &name =
"") {
830 if (!name.empty()) os <<
"=== " << name <<
" ===" <<
'\n';
831 os <<
" sum : " <<
sum(arr) <<
'\n';
832 os <<
" mean : " <<
mean(arr) <<
'\n';
833 os <<
" min : " <<
min(arr) <<
'\n';
834 os <<
" max : " <<
max(arr) <<
'\n';
835 os <<
" stddev: " <<
stddev(arr) << std::endl;
846 template <
class T,
size_t... Dims>
849 double mean_a =
mean(a);
850 double mean_b =
mean(b);
852 auto ai = a.fbegin();
853 auto bi = b.fbegin();
854 while (ai != a.fend()) {
855 sum += (double(*ai) - mean_a) * (
double(*bi) - mean_b);
859 return sum / (a.fsize() - 1);
870 template <
class T,
size_t... Dims>
876 if (std_a == 0 || std_b == 0)
return 0;
877 return cov / (std_a * std_b);
887 template <
class T,
size_t... Dims>
889 size_t n = arr.fsize();
890 auto begin = arr.fbegin();
891 auto end = arr.fend();
892 std::nth_element(begin, begin + n / 2, end);
894 return double(arr.fbegin()[n / 2]);
896 double a = double(arr.fbegin()[n / 2 - 1]);
897 double b = double(arr.fbegin()[n / 2]);
924 template <
class T,
size_t... Dims>
928 size_t n = arr.fsize();
929 if (n == 0)
return 0;
932 auto begin = arr.fbegin();
933 auto end = arr.fend();
936 size_t idx = size_t(q * (n - 1) + 0.5);
937 if (idx >= n) idx = n - 1;
938 std::nth_element(begin, begin + idx, end);
939 return double(arr.fbegin()[idx]);
942 double pos = q * (n - 1);
943 size_t idx = size_t(pos);
944 double frac = pos - idx;
946 std::nth_element(begin, begin + n - 1, end);
947 return double(arr.fbegin()[n - 1]);
949 std::nth_element(begin, begin + idx + 1, end);
950 double a = double(arr.fbegin()[idx]);
951 double b = double(arr.fbegin()[idx + 1]);
952 return a + (b - a) * frac;
955 double pos = q * (n - 1);
956 size_t idx = size_t(pos);
958 std::nth_element(begin, begin + n - 1, end);
959 return double(arr.fbegin()[n - 1]);
961 std::nth_element(begin, begin + idx + 1, end);
962 double a = double(arr.fbegin()[idx]);
963 double b = double(arr.fbegin()[idx + 1]);
967 size_t idx = size_t(q * (n - 1));
968 if (idx >= n) idx = n - 1;
969 std::nth_element(begin, begin + idx, end);
970 return double(arr.fbegin()[idx]);
973 size_t idx = size_t(q * (n - 1));
974 if (idx >= n - 1)
return double(arr.fbegin()[n - 1]);
976 std::nth_element(begin, begin + idx, end);
977 return double(arr.fbegin()[idx]);
980 double pos = (n - 1) * q;
981 size_t idx = size_t(pos);
982 double frac = pos - idx;
984 return double(arr.fbegin()[n - 1]);
986 std::nth_element(begin, begin + idx + 1, end);
987 double a = double(arr.fbegin()[idx]);
988 double b = double(arr.fbegin()[idx + 1]);
989 return a + (b - a) * frac;
992 double pos = (n + 1) * q;
993 size_t idx = size_t(pos);
994 double frac = pos - idx;
995 if (idx < 1) idx = 1;
998 std::nth_element(begin, begin + n - 1, end);
999 return double(arr.fbegin()[n - 1]);
1001 return double(arr.fbegin()[n - 1]);
1003 std::nth_element(begin, begin + idx, end);
1004 double a = double(arr.fbegin()[idx - 1]);
1005 double b = double(arr.fbegin()[idx]);
1006 return a + (b - a) * frac;
1021 return A[0][0] *
A[1][1] -
A[0][1] *
A[1][0];
1032 return A[0][0] * (
A[1][1] *
A[2][2] -
A[1][2] *
A[2][1])
1033 -
A[0][1] * (
A[1][0] *
A[2][2] -
A[1][2] *
A[2][0])
1034 +
A[0][2] * (
A[1][0] *
A[2][1] -
A[1][1] *
A[2][0]);
1048 A[1][1] / d, -
A[0][1] / d, -
A[1][0] / d,
A[0][0] / d};
1062 B[0][0] = (
A[1][1] *
A[2][2] -
A[1][2] *
A[2][1]) / d;
1063 B[0][1] = (
A[0][2] *
A[2][1] -
A[0][1] *
A[2][2]) / d;
1064 B[0][2] = (
A[0][1] *
A[1][2] -
A[0][2] *
A[1][1]) / d;
1065 B[1][0] = (
A[1][2] *
A[2][0] -
A[1][0] *
A[2][2]) / d;
1066 B[1][1] = (
A[0][0] *
A[2][2] -
A[0][2] *
A[2][0]) / d;
1067 B[1][2] = (
A[0][2] *
A[1][0] -
A[0][0] *
A[1][2]) / d;
1068 B[2][0] = (
A[1][0] *
A[2][1] -
A[1][1] *
A[2][0]) / d;
1069 B[2][1] = (
A[0][1] *
A[2][0] -
A[0][0] *
A[2][1]) / d;
1070 B[2][2] = (
A[0][0] *
A[1][1] -
A[0][1] *
A[1][0]) / d;
1081 template <
class T,
size_t... Dims>
1084 auto ri = result.fbegin();
1085 auto ai = arr.fbegin();
1086 while (ri != result.fend()) {
1087 *ri++ =
T(1) / (
T(1) + std::exp(-*ai++));
1099 template <
class T,
size_t... Dims>
1102 auto ri = result.fbegin();
1103 auto ai = arr.fbegin();
1104 while (ri != result.fend()) {
1105 *ri++ = *ai < 0 ? 0 : *ai;
1118 template <
class T,
size_t... Dims>
1120 auto max_val =
max(arr);
1122 auto ri = exp_arr.fbegin();
1123 auto ai = arr.fbegin();
1124 while (ri != exp_arr.fend()) {
1125 *ri++ = std::exp(*ai++ - max_val);
1127 T sum_exp =
sum(exp_arr);
1129 ri = result.fbegin();
1130 ai = exp_arr.fbegin();
1131 while (ri != result.fend()) {
1132 *ri++ = *ai++ / sum_exp;
1148 template <
class T,
size_t H,
size_t W,
size_t KH,
size_t KW>
1151 constexpr size_t OH = H - KH + 1;
1152 constexpr size_t OW =
W - KW + 1;
1154 for (
size_t i = 0; i < OH; ++i) {
1155 for (
size_t j = 0; j < OW; ++j) {
1157 for (
size_t ki = 0; ki < KH; ++ki) {
1158 for (
size_t kj = 0; kj < KW; ++kj) {
1159 sum += image[i + ki][j + kj] * kernel[ki][kj];
1177 template <
class T,
size_t M,
size_t N>
1180 const char *name =
nullptr) {
1181 if (name) os << name <<
" = \n";
1182 for (
size_t i = 0; i <
M; ++i) {
1184 for (
size_t j = 0; j <
N; ++j) {
1186 if (j <
N - 1) os <<
", ";
1198 template <
class T,
size_t N>
1199 MultiArray<std::complex<T>, N>
1201 static_assert((
N & (
N - 1)) == 0,
"FFT length must be a power of 2");
1203 for (
size_t i = 0; i <
N; ++i) {
1205 for (
size_t k = 1; k <
N; k <<= 1) {
1211 if (i < j) std::swap(result[i], result[j]);
1213 for (
size_t len = 2; len <=
N; len <<= 1) {
1214 T angle =
T(-2 *
M_PI) / len;
1215 std::complex<T> wlen(std::cos(angle), std::sin(angle));
1216 for (
size_t i = 0; i <
N; i += len) {
1217 std::complex<T> w = 1;
1218 for (
size_t j = 0; j < len / 2; ++j) {
1219 auto u = result[i + j];
1220 auto v = result[i + j + len / 2] * w;
1221 result[i + j] = u + v;
1222 result[i + j + len / 2] = u - v;
1236 template <
class T,
size_t N>
1237 MultiArray<std::complex<T>, N>
1240 for (
size_t i = 0; i <
N; ++i) conj_X[i] = std::conj(
X[i]);
1242 auto result =
fft(conj_X);
1244 for (
size_t i = 0; i <
N; ++i) {
1245 result[i] = std::conj(result[i]) /
T(
N);
1257 template <
class T,
size_t N>
1260 for (
size_t i = 0; i < N; ++i) cx[i] = std::complex<T>(x[i], 0);
1270 template <
class T,
size_t N>
1274 for (
size_t i = 0; i <
N; ++i) result[i] = cx[i].real();
1286 template <
class T,
size_t N>
1291 for (
size_t i = 0; i <=
N / 2; ++i) mag[i] = std::abs(f[i]) *
norm;
1302 template <
class T,
size_t N>
1305 for (
size_t i = 0; i < mag.fsize(); ++i) {
1306 mag[i] = mag[i] * mag[i];
1318 template <
class T,
size_t N>
1322 for (
size_t i = 0; i <=
N / 2; ++i) {
1323 phase[i] = std::arg(f[i]);
1335 template <
class T,
size_t N>
1339 for (
size_t i = 0; i < mag.fsize(); ++i) {
1341 logmag[i] = (val > 0) ?
T(20) * std::log10(val) :
T(-100);
1355 template <
class T,
size_t M,
size_t N>
1359 for (
size_t i = 0; i <
M; ++i) {
1361 for (
size_t j = 0; j <
N; ++j) {
1362 sum +=
A[i][j] * x[j];
1378 template <
class T,
size_t M,
size_t N>
1382 for (
size_t i = 0; i <
M; ++i) {
1383 for (
size_t j = 0; j <
N; ++j) {
1384 result[i][j] = a[i] * b[j];
1398 template <
class T,
size_t M,
size_t N>
1401 for (
auto it =
A.fbegin(); it !=
A.fend(); ++it) {
1402 double v = double(*it);
1405 return std::sqrt(
sum);
1416 template <
class T,
size_t M,
size_t N>
1419 for (
size_t j = 0; j <
N; ++j) {
1421 for (
size_t i = 0; i <
M; ++i) {
1422 col_sum += std::abs(
A[i][j]);
1424 if (j == 0 || col_sum > max_col) max_col = col_sum;
1437 template <
class T,
size_t M,
size_t N>
1440 for (
size_t i = 0; i <
M; ++i) {
1442 for (
size_t j = 0; j <
N; ++j) {
1443 row_sum += std::abs(
A[i][j]);
1445 if (i == 0 || row_sum > max_row) max_row = row_sum;
1456 template <
class T,
size_t N>
1459 for (
size_t i = 0; i <
N; ++i) {
1460 win[i] =
T(0.5) * (
T(1) - std::cos(
T(2 *
M_PI) * i / (
N - 1)));
1471 template <
class T,
size_t N>
1474 for (
size_t i = 0; i <
N; ++i) {
1475 win[i] =
T(0.54) -
T(0.46) * std::cos(
T(2 *
M_PI) * i / (
N - 1));
1486 template <
class T,
size_t N>
1489 for (
size_t i = 0; i <
N; ++i) {
1490 T a =
T(2 *
M_PI) * i / (
N - 1);
1491 win[i] =
T(0.42) -
T(0.5) * std::cos(a) +
T(0.08) * std::cos(2 * a);
1503 template <
class T,
size_t N>
1506 size_t half =
N / 2;
1507 for (
size_t i = 0; i < half; ++i) {
1508 result[i] = x[i + half];
1509 result[i + half] = x[i];
1523 template <
class T,
size_t N,
size_t M>
1524 MultiArray<T, N + M - 1>
1527 for (
size_t i = 0; i <
N; ++i) {
1528 for (
size_t j = 0; j <
M; ++j) {
1529 result[i + j] += a[i] * b[j];
编译期固定维度的多维数组(堆版本)。
Definition multiarray.h:461
std::vector< typename C::value_type > sample(const C &c, size_t size, bool replace=false, std::mt19937 &gen=thread_rng())
从容器中随机抽取指定数量的元素(有放回或无放回)。
Definition random.h:421
std::mt19937 & thread_rng()
获取一个全局的、以当前时间戳为种子的 Mersenne Twister 随机数引擎。
Definition random.h:55
std::enable_if< is_string< typenamestd::decay< T >::type >::value >::type repr(T &&value, std::basic_ostream< CharT, Traits > &os=std::cout)
输出字符串类型(std::string, const char* 等)的表示,带双引号。
Definition repr.h:97
typename uniform_distribution_impl< T >::type uniform_distribution_t
取得对印类型所对应的均匀分布。
Definition sfinae.h:328
提供编译期维度固定的多维数组容器 MultiArray,支持任意维度和元素级算术/逻辑/位运算。
auto submit(F &&f, Args &&...args) -> std::future< decltype(std::forward< F >(f)(std::forward< Args >(args)...))>
提交任务到线程池。
Definition pool.h:327
T min(const MultiArray< T, Dims... > &a)
求最小值。
Definition multiarray.h:1676
T max(const MultiArray< T, Dims... > &a)
求最大值。
Definition multiarray.h:1685
T sum(const MultiArray< T, Dims... > &a)
求和所有元素。
Definition multiarray.h:1665
简单的线程池实现,模仿了 Python 的 concurrent.futures.ThreadPoolExecutor 接口。
提供编译期类型特征检测(SFINAE 工具), 用于判断容器、可调用对象、迭代器、下标访问、字符串、可打印类型、字符类型等。