/*************************************************************************/ /* lin_alg.cpp */ /*************************************************************************/ /* This file is part of: */ /* PMLPP Machine Learning Library */ /* https://github.com/Relintai/pmlpp */ /*************************************************************************/ /* Copyright (c) 2023-present Péter Magyar. */ /* Copyright (c) 2022-2023 Marc Melikyan */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ /* "Software"), to deal in the Software without restriction, including */ /* without limitation the rights to use, copy, modify, merge, publish, */ /* distribute, sublicense, and/or sell copies of the Software, and to */ /* permit persons to whom the Software is furnished to do so, subject to */ /* the following conditions: */ /* */ /* The above copyright notice and this permission notice shall be */ /* included in all copies or substantial portions of the Software. */ /* */ /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "lin_alg.h" #include "core/math/math_funcs.h" #include "../stat/stat.h" #include #include #include #include Ref MLPPLinAlg::gram_matrix(const Ref &A) { return A->transposen()->multn(A); // AtA } bool MLPPLinAlg::linear_independence_checker(const Ref &A) { if (gram_matrix(A)->det(A->size().y) == 0) { return false; } return true; } Ref MLPPLinAlg::gaussian_noise(int n, int m) { std::random_device rd; std::default_random_engine generator(rd()); std::normal_distribution distribution(0, 1); // Standard normal distribution. Mean of 0, std of 1. Ref A; A.instance(); A->resize(Size2i(m, n)); int a_data_size = A->data_size(); real_t *a_ptr = A->ptrw(); for (int i = 0; i < a_data_size; ++i) { a_ptr[i] = distribution(generator); } return A; } Ref MLPPLinAlg::additionnm(const Ref &A, const Ref &B) { ERR_FAIL_COND_V(!A.is_valid() || !B.is_valid(), Ref()); Size2i a_size = A->size(); ERR_FAIL_COND_V(a_size != B->size(), Ref()); Ref C; C.instance(); C->resize(a_size); const real_t *a_ptr = A->ptr(); const real_t *b_ptr = B->ptr(); real_t *c_ptr = C->ptrw(); int data_size = A->data_size(); for (int i = 0; i < data_size; ++i) { c_ptr[i] = a_ptr[i] + b_ptr[i]; } return C; } Ref MLPPLinAlg::subtractionnm(const Ref &A, const Ref &B) { ERR_FAIL_COND_V(!A.is_valid() || !B.is_valid(), Ref()); Size2i a_size = A->size(); ERR_FAIL_COND_V(a_size != B->size(), Ref()); Ref C; C.instance(); C->resize(a_size); const real_t *a_ptr = A->ptr(); const real_t *b_ptr = B->ptr(); real_t *c_ptr = C->ptrw(); int data_size = A->data_size(); for (int i = 0; i < data_size; ++i) { c_ptr[i] = a_ptr[i] - b_ptr[i]; } return C; } Ref MLPPLinAlg::matmultnm(const Ref &A, const Ref &B) { ERR_FAIL_COND_V(!A.is_valid() || !B.is_valid(), Ref()); Size2i a_size = A->size(); Size2i b_size = B->size(); ERR_FAIL_COND_V(a_size.x != b_size.y, Ref()); Ref C; C.instance(); C->resize(Size2i(b_size.x, a_size.y)); C->fill(0); const real_t *a_ptr = A->ptr(); const real_t *b_ptr = B->ptr(); real_t *c_ptr = C->ptrw(); for (int i = 0; i < a_size.y; i++) { for (int k = 0; k < b_size.y; k++) { int ind_i_k = A->calculate_index(i, k); for (int j = 0; j < b_size.x; j++) { int ind_i_j = C->calculate_index(i, j); int ind_k_j = B->calculate_index(k, j); c_ptr[ind_i_j] += a_ptr[ind_i_k] * b_ptr[ind_k_j]; //C->element_set(i, j, C->element_get(i, j) + A->element_get(i, k) * B->element_get(k, j } } } return C; } Ref MLPPLinAlg::hadamard_productnm(const Ref &A, const Ref &B) { ERR_FAIL_COND_V(!A.is_valid() || !B.is_valid(), Ref()); Size2i a_size = A->size(); ERR_FAIL_COND_V(a_size != B->size(), Ref()); Ref C; C.instance(); C->resize(a_size); const real_t *a_ptr = A->ptr(); const real_t *b_ptr = B->ptr(); real_t *c_ptr = C->ptrw(); for (int i = 0; i < a_size.y; i++) { for (int j = 0; j < a_size.x; j++) { int ind_i_j = A->calculate_index(i, j); c_ptr[ind_i_j] = a_ptr[ind_i_j] * b_ptr[ind_i_j]; } } return C; } Ref MLPPLinAlg::kronecker_productnm(const Ref &A, const Ref &B) { // [1,1,1,1] [1,2,3,4,5] // [1,1,1,1] [1,2,3,4,5] // [1,2,3,4,5] // [1,2,3,4,5] [1,2,3,4,5] [1,2,3,4,5] [1,2,3,4,5] // [1,2,3,4,5] [1,2,3,4,5] [1,2,3,4,5] [1,2,3,4,5] // [1,2,3,4,5] [1,2,3,4,5] [1,2,3,4,5] [1,2,3,4,5] // [1,2,3,4,5] [1,2,3,4,5] [1,2,3,4,5] [1,2,3,4,5] // [1,2,3,4,5] [1,2,3,4,5] [1,2,3,4,5] [1,2,3,4,5] // [1,2,3,4,5] [1,2,3,4,5] [1,2,3,4,5] [1,2,3,4,5] // Resulting matrix: A.size() * B.size() // A[0].size() * B[0].size() ERR_FAIL_COND_V(!A.is_valid() || !B.is_valid(), Ref()); Size2i a_size = A->size(); Size2i b_size = B->size(); Ref C; C.instance(); C->resize(Size2i(b_size.x * a_size.x, b_size.y * a_size.y)); const real_t *a_ptr = A->ptr(); Ref row_tmp; row_tmp.instance(); row_tmp->resize(b_size.x); for (int i = 0; i < a_size.y; ++i) { for (int j = 0; j < b_size.y; ++j) { B->row_get_into_mlpp_vector(j, row_tmp); Vector> row; for (int k = 0; k < a_size.x; ++k) { row.push_back(scalar_multiplynv(a_ptr[A->calculate_index(i, k)], row_tmp)); } Ref flattened_row = flattenmnv(row); C->row_set_mlpp_vector(i * b_size.y + j, flattened_row); } } return C; } Ref MLPPLinAlg::division_element_wisenvnm(const Ref &A, const Ref &B) { ERR_FAIL_COND_V(!A.is_valid() || !B.is_valid(), Ref()); Size2i a_size = A->size(); ERR_FAIL_COND_V(a_size != B->size(), Ref()); Ref C; C.instance(); C->resize(a_size); const real_t *a_ptr = A->ptr(); const real_t *b_ptr = B->ptr(); real_t *c_ptr = C->ptrw(); for (int i = 0; i < a_size.y; i++) { for (int j = 0; j < a_size.x; j++) { int ind_i_j = A->calculate_index(i, j); c_ptr[ind_i_j] = a_ptr[ind_i_j] / b_ptr[ind_i_j]; } } return C; } Ref MLPPLinAlg::transposenm(const Ref &A) { Size2i a_size = A->size(); Ref AT; AT.instance(); AT->resize(Size2i(a_size.y, a_size.x)); const real_t *a_ptr = A->ptr(); real_t *at_ptr = AT->ptrw(); for (int i = 0; i < a_size.y; ++i) { for (int j = 0; j < a_size.x; ++j) { at_ptr[AT->calculate_index(j, i)] = a_ptr[A->calculate_index(i, j)]; } } return AT; } Ref MLPPLinAlg::scalar_multiplynm(real_t scalar, const Ref &A) { Ref AN = A->duplicate_fast(); Size2i a_size = AN->size(); real_t *an_ptr = AN->ptrw(); for (int i = 0; i < a_size.y; ++i) { for (int j = 0; j < a_size.x; ++j) { an_ptr[AN->calculate_index(i, j)] *= scalar; } } return AN; } Ref MLPPLinAlg::scalar_addnm(real_t scalar, const Ref &A) { Ref AN = A->duplicate_fast(); Size2i a_size = AN->size(); real_t *an_ptr = AN->ptrw(); for (int i = 0; i < a_size.y; ++i) { for (int j = 0; j < a_size.x; ++j) { an_ptr[AN->calculate_index(i, j)] += scalar; } } return AN; } Ref MLPPLinAlg::lognm(const Ref &A) { ERR_FAIL_COND_V(!A.is_valid(), Ref()); Ref out; out.instance(); int data_size = A->data_size(); out->resize(A->size()); const real_t *a_ptr = A->ptr(); real_t *out_ptr = out->ptrw(); for (int i = 0; i < data_size; ++i) { out_ptr[i] = Math::log(a_ptr[i]); } return out; } Ref MLPPLinAlg::log10nm(const Ref &A) { ERR_FAIL_COND_V(!A.is_valid(), Ref()); Ref out; out.instance(); int data_size = A->data_size(); out->resize(A->size()); const real_t *a_ptr = A->ptr(); real_t *out_ptr = out->ptrw(); for (int i = 0; i < data_size; ++i) { out_ptr[i] = Math::log10(a_ptr[i]); } return out; } Ref MLPPLinAlg::expnm(const Ref &A) { ERR_FAIL_COND_V(!A.is_valid(), Ref()); Ref out; out.instance(); int data_size = A->data_size(); out->resize(A->size()); const real_t *a_ptr = A->ptr(); real_t *out_ptr = out->ptrw(); for (int i = 0; i < data_size; ++i) { out_ptr[i] = Math::exp(a_ptr[i]); } return out; } Ref MLPPLinAlg::erfnm(const Ref &A) { ERR_FAIL_COND_V(!A.is_valid(), Ref()); Ref out; out.instance(); int data_size = A->data_size(); out->resize(A->size()); const real_t *a_ptr = A->ptr(); real_t *out_ptr = out->ptrw(); for (int i = 0; i < data_size; ++i) { out_ptr[i] = Math::erf(a_ptr[i]); } return out; } Ref MLPPLinAlg::exponentiatenm(const Ref &A, real_t p) { ERR_FAIL_COND_V(!A.is_valid(), Ref()); Ref out; out.instance(); int data_size = A->data_size(); out->resize(A->size()); const real_t *a_ptr = A->ptr(); real_t *out_ptr = out->ptrw(); for (int i = 0; i < data_size; ++i) { out_ptr[i] = Math::pow(a_ptr[i], p); } return out; } Ref MLPPLinAlg::sqrtnm(const Ref &A) { ERR_FAIL_COND_V(!A.is_valid(), Ref()); Ref out; out.instance(); int data_size = A->data_size(); out->resize(A->size()); const real_t *a_ptr = A->ptr(); real_t *out_ptr = out->ptrw(); for (int i = 0; i < data_size; ++i) { out_ptr[i] = Math::sqrt(a_ptr[i]); } return out; } Ref MLPPLinAlg::cbrtnm(const Ref &A) { return exponentiatenm(A, real_t(1) / real_t(3)); } /* std::vector> MLPPLinAlg::matrixPower(std::vector> A, int n) { std::vector> B = identity(A.size()); if (n == 0) { return identity(A.size()); } else if (n < 0) { A = inverse(A); } for (int i = 0; i < std::abs(n); i++) { B = matmult(B, A); } return B; } */ Ref MLPPLinAlg::absnm(const Ref &A) { ERR_FAIL_COND_V(!A.is_valid(), Ref()); Ref out; out.instance(); int data_size = A->data_size(); out->resize(A->size()); const real_t *a_ptr = A->ptr(); real_t *out_ptr = out->ptrw(); for (int i = 0; i < data_size; ++i) { out_ptr[i] = ABS(a_ptr[i]); } return out; } real_t MLPPLinAlg::detm(const Ref &A, int d) { ERR_FAIL_COND_V(!A.is_valid(), 0); real_t deter = 0; Ref B; B.instance(); B->resize(Size2i(d, d)); B->fill(0); /* This is the base case in which the input is a 2x2 square matrix. Recursion is performed unless and until we reach this base case, such that we recieve a scalar as the result. */ if (d == 2) { return A->element_get(0, 0) * A->element_get(1, 1) - A->element_get(0, 1) * A->element_get(1, 0); } else { for (int i = 0; i < d; i++) { int sub_i = 0; for (int j = 1; j < d; j++) { int sub_j = 0; for (int k = 0; k < d; k++) { if (k == i) { continue; } B->element_set(sub_i, sub_j, A->element_get(j, k)); sub_j++; } sub_i++; } deter += Math::pow(static_cast(-1), static_cast(i)) * A->element_get(0, i) * detm(B, d - 1); } } return deter; } /* real_t MLPPLinAlg::trace(std::vector> A) { real_t trace = 0; for (uint32_t i = 0; i < A.size(); i++) { trace += A[i][i]; } return trace; } */ Ref MLPPLinAlg::cofactornm(const Ref &A, int n, int i, int j) { Ref cof; cof.instance(); cof->resize(A->size()); int sub_i = 0; int sub_j = 0; for (int row = 0; row < n; row++) { for (int col = 0; col < n; col++) { if (row != i && col != j) { cof->element_set(sub_i, sub_j++, A->element_get(row, col)); if (sub_j == n - 1) { sub_j = 0; sub_i++; } } } } return cof; } Ref MLPPLinAlg::adjointnm(const Ref &A) { Ref adj; ERR_FAIL_COND_V(!A.is_valid(), adj); Size2i a_size = A->size(); ERR_FAIL_COND_V(a_size.x != a_size.y, adj); //Resizing the initial adjoint matrix adj.instance(); adj->resize(a_size); // Checking for the case where the given N x N matrix is a scalar if (a_size.y == 1) { adj->element_set(0, 0, 1); return adj; } if (a_size.y == 2) { adj->element_set(0, 0, A->element_get(1, 1)); adj->element_set(1, 1, A->element_get(0, 0)); adj->element_set(0, 1, -A->element_get(0, 1)); adj->element_set(1, 0, -A->element_get(1, 0)); return adj; } for (int i = 0; i < a_size.y; i++) { for (int j = 0; j < a_size.x; j++) { Ref cof = cofactornm(A, a_size.y, i, j); // 1 if even, -1 if odd int sign = (i + j) % 2 == 0 ? 1 : -1; adj->element_set(j, i, sign * detm(cof, int(a_size.y) - 1)); } } return adj; } Ref MLPPLinAlg::inversenm(const Ref &A) { return scalar_multiplynm(1 / detm(A, int(A->size().y)), adjointnm(A)); } Ref MLPPLinAlg::pinversenm(const Ref &A) { return matmultnm(inversenm(matmultnm(transposenm(A), A)), transposenm(A)); } Ref MLPPLinAlg::zeromatnm(int n, int m) { Ref mat; mat.instance(); mat->resize(Size2i(m, n)); mat->fill(0); return mat; } Ref MLPPLinAlg::onematnm(int n, int m) { Ref mat; mat.instance(); mat->resize(Size2i(m, n)); mat->fill(1); return mat; } Ref MLPPLinAlg::fullnm(int n, int m, int k) { Ref mat; mat.instance(); mat->resize(Size2i(m, n)); mat->fill(k); return mat; } Ref MLPPLinAlg::sinnm(const Ref &A) { ERR_FAIL_COND_V(!A.is_valid(), Ref()); Ref out; out.instance(); int data_size = A->data_size(); out->resize(A->size()); const real_t *a_ptr = A->ptr(); real_t *out_ptr = out->ptrw(); for (int i = 0; i < data_size; ++i) { out_ptr[i] = Math::sin(a_ptr[i]); } return out; } Ref MLPPLinAlg::cosnm(const Ref &A) { ERR_FAIL_COND_V(!A.is_valid(), Ref()); Ref out; out.instance(); int data_size = A->data_size(); out->resize(A->size()); const real_t *a_ptr = A->ptr(); real_t *out_ptr = out->ptrw(); for (int i = 0; i < data_size; ++i) { out_ptr[i] = Math::cos(a_ptr[i]); } return out; } Ref MLPPLinAlg::maxnvv(const Ref &a, const Ref &b) { Ref ret; ret.instance(); ERR_FAIL_COND_V(!a.is_valid() || !b.is_valid(), ret); int a_size = a->size(); ERR_FAIL_COND_V(a_size != b->size(), ret); ret->resize(a_size); const real_t *aa = a->ptr(); const real_t *ba = b->ptr(); real_t *ret_ptr = ret->ptrw(); for (int i = 0; i < a_size; i++) { real_t aa_i = aa[i]; real_t bb_i = ba[i]; if (aa_i > bb_i) { ret_ptr[i] = aa_i; } else { ret_ptr[i] = bb_i; } } return ret; } /* real_t MLPPLinAlg::max(std::vector> A) { return max(flatten(A)); } real_t MLPPLinAlg::min(std::vector> A) { return min(flatten(A)); } std::vector> MLPPLinAlg::round(std::vector> A) { std::vector> B; B.resize(A.size()); for (uint32_t i = 0; i < B.size(); i++) { B[i].resize(A[0].size()); } for (uint32_t i = 0; i < A.size(); i++) { for (uint32_t j = 0; j < A[i].size(); j++) { B[i][j] = Math::round(A[i][j]); } } return B; } */ /* real_t MLPPLinAlg::norm_2(std::vector> A) { real_t sum = 0; for (uint32_t i = 0; i < A.size(); i++) { for (uint32_t j = 0; j < A[i].size(); j++) { sum += A[i][j] * A[i][j]; } } return Math::sqrt(sum); } */ Ref MLPPLinAlg::identitym(int d) { Ref identity_mat; identity_mat.instance(); identity_mat->resize(Size2i(d, d)); identity_mat->fill(0); real_t *im_ptr = identity_mat->ptrw(); for (int i = 0; i < d; i++) { im_ptr[identity_mat->calculate_index(i, i)] = 1; } return identity_mat; } Ref MLPPLinAlg::covnm(const Ref &A) { MLPPStat stat; Ref cov_mat; cov_mat.instance(); Size2i a_size = A->size(); cov_mat->resize(a_size); Ref a_i_row_tmp; a_i_row_tmp.instance(); a_i_row_tmp->resize(a_size.x); Ref a_j_row_tmp; a_j_row_tmp.instance(); a_j_row_tmp->resize(a_size.x); for (int i = 0; i < a_size.y; ++i) { A->row_get_into_mlpp_vector(i, a_i_row_tmp); for (int j = 0; j < a_size.x; ++j) { A->row_get_into_mlpp_vector(j, a_j_row_tmp); cov_mat->element_set(i, j, stat.covariancev(a_i_row_tmp, a_j_row_tmp)); } } return cov_mat; } MLPPLinAlg::EigenResult MLPPLinAlg::eigen(Ref A) { EigenResult res; ERR_FAIL_COND_V(!A.is_valid(), res); /* A (the entered parameter) in most use cases will be X'X, XX', etc. and must be symmetric. That simply means that 1) X' = X and 2) X is a square matrix. This function that computes the eigenvalues of a matrix is utilizing Jacobi's method. */ real_t diagonal = true; // Perform the iterative Jacobi algorithm unless and until we reach a diagonal matrix which yields us the eigenvals. HashMap val_to_vec; Ref a_new; Ref eigenvectors = identitym(A->size().y); Size2i a_size = A->size(); do { real_t a_ij = A->element_get(0, 1); real_t sub_i = 0; real_t sub_j = 1; for (int i = 0; i < a_size.y; ++i) { for (int j = 0; j < a_size.x; ++j) { real_t ca_ij = A->element_get(i, j); real_t abs_ca_ij = ABS(ca_ij); if (i != j && abs_ca_ij > a_ij) { a_ij = ca_ij; sub_i = i; sub_j = j; } else if (i != j && abs_ca_ij == a_ij) { if (i < sub_i) { a_ij = ca_ij; sub_i = i; sub_j = j; } } } } real_t a_ii = A->element_get(sub_i, sub_i); real_t a_jj = A->element_get(sub_j, sub_j); //real_t a_ji = A->element_get(sub_j, sub_i); real_t theta; if (a_ii == a_jj) { theta = Math_PI / 4; } else { theta = 0.5 * atan(2 * a_ij / (a_ii - a_jj)); } Ref P = identitym(A->size().y); P->element_set(sub_i, sub_j, -Math::sin(theta)); P->element_set(sub_i, sub_i, Math::cos(theta)); P->element_set(sub_j, sub_j, Math::cos(theta)); P->element_set(sub_j, sub_i, Math::sin(theta)); a_new = matmultnm(matmultnm(inversenm(P), A), P); Size2i a_new_size = a_new->size(); for (int i = 0; i < a_new_size.y; ++i) { for (int j = 0; j < a_new_size.x; ++j) { if (i != j && Math::is_zero_approx(Math::round(a_new->element_get(i, j)))) { a_new->element_set(i, j, 0); } } } bool non_zero = false; for (int i = 0; i < a_new_size.y; ++i) { for (int j = 0; j < a_new_size.x; ++j) { if (i != j && Math::is_zero_approx(Math::round(a_new->element_get(i, j)))) { non_zero = true; } } } if (non_zero) { diagonal = false; } else { diagonal = true; } if (a_new->is_equal_approx(A)) { diagonal = true; for (int i = 0; i < a_new_size.y; ++i) { for (int j = 0; j < a_new_size.x; ++j) { if (i != j) { a_new->element_set(i, j, 0); } } } } eigenvectors = matmultnm(eigenvectors, P); A = a_new; } while (!diagonal); Ref a_new_prior = a_new->duplicate_fast(); Size2i a_new_size = a_new->size(); // Bubble Sort. Should change this later. for (int i = 0; i < a_new_size.y - 1; ++i) { for (int j = 0; j < a_new_size.x - 1 - i; ++j) { if (a_new->element_get(j, j) < a_new->element_get(j + 1, j + 1)) { real_t temp = a_new->element_get(j + 1, j + 1); a_new->element_set(j + 1, j + 1, a_new->element_get(j, j)); a_new->element_set(j, j, temp); } } } for (int i = 0; i < a_new_size.y; ++i) { for (int j = 0; j < a_new_size.x; ++j) { if (a_new->element_get(i, i) == a_new_prior->element_get(j, j)) { val_to_vec[i] = j; } } } Ref eigen_temp = eigenvectors->duplicate_fast(); Size2i eigenvectors_size = eigenvectors->size(); for (int i = 0; i < eigenvectors_size.y; ++i) { for (int j = 0; j < eigenvectors_size.x; ++j) { eigenvectors->element_set(i, j, eigen_temp->element_get(i, val_to_vec[j])); } } res.eigen_vectors = eigenvectors; res.eigen_values = a_new; return res; } MLPPLinAlg::SVDResult MLPPLinAlg::svd(const Ref &A) { SVDResult res; ERR_FAIL_COND_V(!A.is_valid(), res); Size2i a_size = A->size(); EigenResult left_eigen = eigen(matmultnm(A, transposenm(A))); EigenResult right_eigen = eigen(matmultnm(transposenm(A), A)); Ref singularvals = sqrtnm(left_eigen.eigen_values); Ref sigma = zeromatnm(a_size.y, a_size.x); Size2i sigma_size = sigma->size(); for (int i = 0; i < sigma_size.y; ++i) { for (int j = 0; j < sigma_size.x; ++j) { sigma->element_set(i, j, singularvals->element_get(i, j)); } } res.U = left_eigen.eigen_vectors; res.S = sigma; res.Vt = right_eigen.eigen_vectors; return res; } Ref MLPPLinAlg::vector_projection(const Ref &a, const Ref &b) { real_t product = a->dot(b) / a->dot(a); return a->scalar_multiplyn(product); // Projection of vector a onto b. Denotated as proj_a(b). } Ref MLPPLinAlg::gram_schmidt_process(const Ref &p_A) { Ref A = p_A->transposen(); Size2i a_size = A->size(); Ref B; B.instance(); B->resize(a_size); B->fill(0); Ref b_i_row_tmp; b_i_row_tmp.instance(); b_i_row_tmp->resize(a_size.x); A->row_get_into_mlpp_vector(0, b_i_row_tmp); b_i_row_tmp->scalar_multiply((real_t)1 / b_i_row_tmp->norm_2()); B->row_set_mlpp_vector(0, b_i_row_tmp); Ref a_i_row_tmp; a_i_row_tmp.instance(); a_i_row_tmp->resize(a_size.x); Ref b_j_row_tmp; b_j_row_tmp.instance(); b_j_row_tmp->resize(a_size.x); for (int i = 1; i < a_size.y; ++i) { A->row_get_into_mlpp_vector(i, b_i_row_tmp); B->row_set_mlpp_vector(i, b_i_row_tmp); for (int j = i - 1; j >= 0; j--) { A->row_get_into_mlpp_vector(i, a_i_row_tmp); B->row_get_into_mlpp_vector(j, b_j_row_tmp); B->row_get_into_mlpp_vector(i, b_i_row_tmp); b_i_row_tmp->sub(vector_projection(b_j_row_tmp, a_i_row_tmp)); B->row_set_mlpp_vector(i, b_i_row_tmp); } // Very simply multiply all elements of vec B[i] by 1/||B[i]||_2 B->row_get_into_mlpp_vector(i, b_i_row_tmp); b_i_row_tmp->scalar_multiply((real_t)1 / b_i_row_tmp->norm_2()); B->row_set_mlpp_vector(i, b_i_row_tmp); } return B->transposen(); // We re-transpose the marix. } MLPPLinAlg::QRDResult MLPPLinAlg::qrd(const Ref &A) { QRDResult res; res.Q = gram_schmidt_process(A); res.R = res.Q->transposen()->multn(A); return res; } MLPPLinAlg::CholeskyResult MLPPLinAlg::cholesky(const Ref &A) { Size2i a_size = A->size(); CholeskyResult res; ERR_FAIL_COND_V(a_size.x != a_size.y, res); Ref L = zeromatnm(a_size.y, a_size.x); for (int j = 0; j < a_size.y; ++j) { // Matrices entered must be square. No problem here. for (int i = j; i < a_size.y; ++i) { if (i == j) { real_t sum = 0; for (int k = 0; k < j; k++) { real_t lik = L->element_get(i, k); sum += lik * lik; } L->element_set(i, j, Math::sqrt(A->element_get(i, j) - sum)); } else { // That is, i!=j real_t sum = 0; for (int k = 0; k < j; k++) { sum += L->element_get(i, k) * L->element_get(j, k); } L->element_set(i, j, (A->element_get(i, j) - sum) / L->element_get(j, j)); } } } res.L = L; res.Lt = L->transposen(); // Indeed, L.T is our upper triangular matrix. return res; } /* real_t MLPPLinAlg::sum_elements(std::vector> A) { real_t sum = 0; for (uint32_t i = 0; i < A.size(); i++) { for (uint32_t j = 0; j < A[i].size(); j++) { sum += A[i][j]; } } return sum; } */ Ref MLPPLinAlg::flattenvvnv(const Ref &A) { int data_size = A->data_size(); Ref res; res.instance(); res->resize(data_size); real_t *res_ptr = res->ptrw(); const real_t *a_ptr = A->ptr(); for (int i = 0; i < data_size; ++i) { res_ptr[i] = a_ptr[i]; } return res; } Ref MLPPLinAlg::solve(const Ref &A, const Ref &b) { return A->inverse()->mult_vec(b); } bool MLPPLinAlg::positive_definite_checker(const Ref &A) { EigenResult eig_result = eigen(A); Ref eigenvals = eig_result.eigen_values; Size2i eigenvals_size = eigenvals->size(); for (int i = 0; i < eigenvals_size.y; ++i) { if (eigenvals->element_get(i, i) <= 0) { // Simply check to ensure all eigenvalues are positive. return false; } } return true; } bool MLPPLinAlg::negative_definite_checker(const Ref &A) { EigenResult eig_result = eigen(A); Ref eigenvals = eig_result.eigen_values; Size2i eigenvals_size = eigenvals->size(); for (int i = 0; i < eigenvals_size.y; ++i) { if (eigenvals->element_get(i, i) >= 0) { // Simply check to ensure all eigenvalues are negative. return false; } } return true; } bool MLPPLinAlg::zero_eigenvalue(const Ref &A) { EigenResult eig_result = eigen(A); Ref eigenvals = eig_result.eigen_values; Size2i eigenvals_size = eigenvals->size(); for (int i = 0; i < eigenvals_size.y; ++i) { if (eigenvals->element_get(i, i) == 0) { // TODO should it use is_equal_approx? return false; } } return true; } Ref MLPPLinAlg::flattenmnv(const Vector> &A) { Ref a; a.instance(); int vsize = 0; for (int i = 0; i < A.size(); ++i) { vsize += A[i]->size(); } a->resize(vsize); int a_index = 0; real_t *a_ptr = a->ptrw(); for (int i = 0; i < A.size(); ++i) { const Ref &r = A[i]; int r_size = r->size(); const real_t *r_ptr = r->ptr(); for (int j = 0; j < r_size; ++j) { a_ptr[a_index] = r_ptr[j]; ++a_index; } } return a; } Ref MLPPLinAlg::hadamard_productnv(const Ref &a, const Ref &b) { ERR_FAIL_COND_V(!a.is_valid() || !b.is_valid(), Ref()); Ref out; out.instance(); int size = a->size(); ERR_FAIL_COND_V(size != b->size(), Ref()); out->resize(size); const real_t *a_ptr = a->ptr(); const real_t *b_ptr = b->ptr(); real_t *out_ptr = out->ptrw(); for (int i = 0; i < size; ++i) { out_ptr[i] = a_ptr[i] * b_ptr[i]; } return out; } void MLPPLinAlg::hadamard_productv(const Ref &a, const Ref &b, Ref out) { ERR_FAIL_COND(!a.is_valid() || !b.is_valid() || !out.is_valid()); int size = a->size(); ERR_FAIL_COND(size != b->size()); if (unlikely(out->size() != size)) { out->resize(size); } const real_t *a_ptr = a->ptr(); const real_t *b_ptr = b->ptr(); real_t *out_ptr = out->ptrw(); for (int i = 0; i < size; ++i) { out_ptr[i] = a_ptr[i] * b_ptr[i]; } } Ref MLPPLinAlg::division_element_wisenv(const Ref &a, const Ref &b) { ERR_FAIL_COND_V(!a.is_valid() || !b.is_valid(), Ref()); Ref out; out.instance(); int size = a->size(); ERR_FAIL_COND_V(size != b->size(), Ref()); out->resize(size); const real_t *a_ptr = a->ptr(); const real_t *b_ptr = b->ptr(); real_t *out_ptr = out->ptrw(); for (int i = 0; i < size; ++i) { out_ptr[i] = a_ptr[i] / b_ptr[i]; } return out; } Ref MLPPLinAlg::scalar_multiplynv(real_t scalar, const Ref &a) { ERR_FAIL_COND_V(!a.is_valid(), Ref()); Ref out; out.instance(); int size = a->size(); out->resize(size); const real_t *a_ptr = a->ptr(); real_t *out_ptr = out->ptrw(); for (int i = 0; i < size; ++i) { out_ptr[i] = a_ptr[i] * scalar; } return out; } void MLPPLinAlg::scalar_multiplyv(real_t scalar, const Ref &a, Ref out) { ERR_FAIL_COND(!a.is_valid() || !out.is_valid()); int size = a->size(); if (unlikely(out->size() != size)) { out->resize(size); } const real_t *a_ptr = a->ptr(); real_t *out_ptr = out->ptrw(); for (int i = 0; i < size; ++i) { out_ptr[i] = a_ptr[i] * scalar; } } Ref MLPPLinAlg::scalar_addnv(real_t scalar, const Ref &a) { ERR_FAIL_COND_V(!a.is_valid(), Ref()); Ref out; out.instance(); int size = a->size(); out->resize(size); const real_t *a_ptr = a->ptr(); real_t *out_ptr = out->ptrw(); for (int i = 0; i < size; ++i) { out_ptr[i] = a_ptr[i] + scalar; } return out; } void MLPPLinAlg::scalar_addv(real_t scalar, const Ref &a, Ref out) { ERR_FAIL_COND(!a.is_valid() || !out.is_valid()); int size = a->size(); if (unlikely(out->size() != size)) { out->resize(size); } const real_t *a_ptr = a->ptr(); real_t *out_ptr = out->ptrw(); for (int i = 0; i < size; ++i) { out_ptr[i] = a_ptr[i] + scalar; } } Ref MLPPLinAlg::additionnv(const Ref &a, const Ref &b) { ERR_FAIL_COND_V(!a.is_valid() || !b.is_valid(), Ref()); int size = a->size(); ERR_FAIL_COND_V(size != b->size(), Ref()); Ref out; out.instance(); out->resize(size); const real_t *a_ptr = a->ptr(); const real_t *b_ptr = b->ptr(); real_t *out_ptr = out->ptrw(); for (int i = 0; i < size; ++i) { out_ptr[i] = a_ptr[i] + b_ptr[i]; } return out; } void MLPPLinAlg::additionv(const Ref &a, const Ref &b, Ref out) { ERR_FAIL_COND(!a.is_valid() || !b.is_valid() || !out.is_valid()); int size = a->size(); ERR_FAIL_COND(size != b->size()); if (unlikely(out->size() != size)) { out->resize(size); } const real_t *a_ptr = a->ptr(); const real_t *b_ptr = b->ptr(); real_t *out_ptr = out->ptrw(); for (int i = 0; i < size; ++i) { out_ptr[i] = a_ptr[i] + b_ptr[i]; } } Ref MLPPLinAlg::subtractionnv(const Ref &a, const Ref &b) { ERR_FAIL_COND_V(!a.is_valid() || !b.is_valid(), Ref()); int size = a->size(); ERR_FAIL_COND_V(size != b->size(), Ref()); Ref out; out.instance(); if (unlikely(size == 0)) { return out; } out->resize(size); const real_t *a_ptr = a->ptr(); const real_t *b_ptr = b->ptr(); real_t *out_ptr = out->ptrw(); for (int i = 0; i < size; ++i) { out_ptr[i] = a_ptr[i] - b_ptr[i]; } return out; } void MLPPLinAlg::subtractionv(const Ref &a, const Ref &b, Ref out) { ERR_FAIL_COND(!a.is_valid() || !b.is_valid() || !out.is_valid()); int size = a->size(); ERR_FAIL_COND(size != b->size()); if (unlikely(out->size() != size)) { out->resize(size); } const real_t *a_ptr = a->ptr(); const real_t *b_ptr = b->ptr(); real_t *out_ptr = out->ptrw(); for (int i = 0; i < size; ++i) { out_ptr[i] = a_ptr[i] - b_ptr[i]; } } Ref MLPPLinAlg::lognv(const Ref &a) { ERR_FAIL_COND_V(!a.is_valid(), Ref()); Ref out; out.instance(); int size = a->size(); out->resize(size); const real_t *a_ptr = a->ptr(); real_t *out_ptr = out->ptrw(); for (int i = 0; i < size; ++i) { out_ptr[i] = Math::log(a_ptr[i]); } return out; } Ref MLPPLinAlg::log10nv(const Ref &a) { ERR_FAIL_COND_V(!a.is_valid(), Ref()); Ref out; out.instance(); int size = a->size(); out->resize(size); const real_t *a_ptr = a->ptr(); real_t *out_ptr = out->ptrw(); for (int i = 0; i < size; ++i) { out_ptr[i] = Math::log10(a_ptr[i]); } return out; } Ref MLPPLinAlg::expnv(const Ref &a) { ERR_FAIL_COND_V(!a.is_valid(), Ref()); Ref out; out.instance(); int size = a->size(); out->resize(size); const real_t *a_ptr = a->ptr(); real_t *out_ptr = out->ptrw(); for (int i = 0; i < size; ++i) { out_ptr[i] = Math::exp(a_ptr[i]); } return out; } Ref MLPPLinAlg::erfnv(const Ref &a) { ERR_FAIL_COND_V(!a.is_valid(), Ref()); Ref out; out.instance(); int size = a->size(); out->resize(size); const real_t *a_ptr = a->ptr(); real_t *out_ptr = out->ptrw(); for (int i = 0; i < size; ++i) { out_ptr[i] = Math::erf(a_ptr[i]); } return out; } Ref MLPPLinAlg::exponentiatenv(const Ref &a, real_t p) { ERR_FAIL_COND_V(!a.is_valid(), Ref()); Ref out; out.instance(); int size = a->size(); out->resize(size); const real_t *a_ptr = a->ptr(); real_t *out_ptr = out->ptrw(); for (int i = 0; i < size; ++i) { out_ptr[i] = Math::pow(a_ptr[i], p); } return out; } Ref MLPPLinAlg::sqrtnv(const Ref &a) { ERR_FAIL_COND_V(!a.is_valid(), Ref()); Ref out; out.instance(); int size = a->size(); out->resize(size); const real_t *a_ptr = a->ptr(); real_t *out_ptr = out->ptrw(); for (int i = 0; i < size; ++i) { out_ptr[i] = Math::sqrt(a_ptr[i]); } return out; } Ref MLPPLinAlg::cbrtnv(const Ref &a) { return exponentiatenv(a, static_cast(1) / static_cast(3)); } real_t MLPPLinAlg::dotnv(const Ref &a, const Ref &b) { int a_size = a->size(); ERR_FAIL_COND_V(a_size != b->size(), 0); const real_t *a_ptr = a->ptr(); const real_t *b_ptr = b->ptr(); real_t c = 0; for (int i = 0; i < a_size; ++i) { c += a_ptr[i] * b_ptr[i]; } return c; } /* std::vector MLPPLinAlg::cross(std::vector a, std::vector b) { // Cross products exist in R^7 also. Though, I will limit it to R^3 as Wolfram does this. std::vector> mat = { onevec(3), a, b }; real_t det1 = det({ { a[1], a[2] }, { b[1], b[2] } }, 2); real_t det2 = -det({ { a[0], a[2] }, { b[0], b[2] } }, 2); real_t det3 = det({ { a[0], a[1] }, { b[0], b[1] } }, 2); return { det1, det2, det3 }; } */ Ref MLPPLinAlg::absv(const Ref &a) { ERR_FAIL_COND_V(!a.is_valid(), Ref()); Ref out; out.instance(); int size = a->size(); out->resize(size); const real_t *a_ptr = a->ptr(); real_t *out_ptr = out->ptrw(); for (int i = 0; i < size; ++i) { out_ptr[i] = ABS(a_ptr[i]); } return out; } Ref MLPPLinAlg::zerovecnv(int n) { Ref vec; vec.instance(); vec->resize(n); vec->fill(0); return vec; } Ref MLPPLinAlg::onevecnv(int n) { Ref vec; vec.instance(); vec->resize(n); vec->fill(1); return vec; } Ref MLPPLinAlg::fullnv(int n, int k) { Ref vec; vec.instance(); vec->resize(n); vec->fill(k); return vec; } Ref MLPPLinAlg::sinnv(const Ref &a) { ERR_FAIL_COND_V(!a.is_valid(), Ref()); Ref out; out.instance(); int size = a->size(); out->resize(size); const real_t *a_ptr = a->ptr(); real_t *out_ptr = out->ptrw(); for (int i = 0; i < size; ++i) { out_ptr[i] = Math::sin(a_ptr[i]); } return out; } Ref MLPPLinAlg::cosnv(const Ref &a) { ERR_FAIL_COND_V(!a.is_valid(), Ref()); Ref out; out.instance(); int size = a->size(); out->resize(size); const real_t *a_ptr = a->ptr(); real_t *out_ptr = out->ptrw(); for (int i = 0; i < size; ++i) { out_ptr[i] = Math::cos(a_ptr[i]); } return out; } Ref MLPPLinAlg::maxnm(const Ref &A, const Ref &B) { Ref C; C.instance(); C->resize(A->size()); const real_t *a_ptr = A->ptr(); const real_t *b_ptr = B->ptr(); real_t *c_ptr = C->ptrw(); int size = A->data_size(); for (int i = 0; i < size; i++) { c_ptr[i] = MAX(a_ptr[i], b_ptr[i]); } return C; } real_t MLPPLinAlg::maxvr(const Ref &a) { ERR_FAIL_COND_V(!a.is_valid(), -Math_INF); int a_size = a->size(); const real_t *aa = a->ptr(); real_t max_element = -Math_INF; for (int i = 0; i < a_size; i++) { real_t current_element = aa[i]; if (current_element > max_element) { max_element = current_element; } } return max_element; } real_t MLPPLinAlg::minvr(const Ref &a) { ERR_FAIL_COND_V(!a.is_valid(), Math_INF); int a_size = a->size(); const real_t *aa = a->ptr(); real_t min_element = Math_INF; for (int i = 0; i < a_size; i++) { real_t current_element = aa[i]; if (current_element < min_element) { min_element = current_element; } } return min_element; } /* std::vector MLPPLinAlg::round(std::vector a) { std::vector b; b.resize(a.size()); for (uint32_t i = 0; i < a.size(); i++) { b[i] = Math::round(a[i]); } return b; } */ // Multidimensional Euclidean Distance real_t MLPPLinAlg::euclidean_distance(const Ref &a, const Ref &b) { ERR_FAIL_COND_V(!a.is_valid() || !b.is_valid(), 0); int a_size = a->size(); ERR_FAIL_COND_V(a_size != b->size(), 0); const real_t *aa = a->ptr(); const real_t *ba = b->ptr(); real_t dist = 0; for (int i = 0; i < a_size; i++) { dist += (aa[i] - ba[i]) * (aa[i] - ba[i]); } return Math::sqrt(dist); } real_t MLPPLinAlg::euclidean_distance_squared(const Ref &a, const Ref &b) { ERR_FAIL_COND_V(!a.is_valid() || !b.is_valid(), 0); int a_size = a->size(); ERR_FAIL_COND_V(a_size != b->size(), 0); const real_t *aa = a->ptr(); const real_t *ba = b->ptr(); real_t dist = 0; for (int i = 0; i < a_size; i++) { dist += (aa[i] - ba[i]) * (aa[i] - ba[i]); } return dist; } /* real_t MLPPLinAlg::norm_2(std::vector a) { return Math::sqrt(norm_sq(a)); } */ real_t MLPPLinAlg::norm_sqv(const Ref &a) { ERR_FAIL_COND_V(!a.is_valid(), 0); int size = a->size(); const real_t *a_ptr = a->ptr(); real_t n_sq = 0; for (int i = 0; i < size; ++i) { n_sq += a_ptr[i] * a_ptr[i]; } return n_sq; } real_t MLPPLinAlg::sum_elementsv(const Ref &a) { int a_size = a->size(); const real_t *a_ptr = a->ptr(); real_t sum = 0; for (int i = 0; i < a_size; ++i) { sum += a_ptr[i]; } return sum; } /* real_t MLPPLinAlg::cosineSimilarity(std::vector a, std::vector b) { return dot(a, b) / (norm_2(a) * norm_2(b)); } */ Ref MLPPLinAlg::mat_vec_multnv(const Ref &A, const Ref &b) { ERR_FAIL_COND_V(!A.is_valid() || !b.is_valid(), Ref()); Size2i a_size = A->size(); int b_size = b->size(); ERR_FAIL_COND_V(a_size.x < b->size(), Ref()); Ref c; c.instance(); c->resize(a_size.y); c->fill(0); const real_t *a_ptr = A->ptr(); const real_t *b_ptr = b->ptr(); real_t *c_ptr = c->ptrw(); for (int i = 0; i < a_size.y; ++i) { for (int k = 0; k < b_size; ++k) { int mat_index = A->calculate_index(i, k); c_ptr[i] += a_ptr[mat_index] * b_ptr[k]; } } return c; } Ref MLPPLinAlg::subtract_matrix_rowsnv(const Ref &a, const Ref &B) { Ref c = a->duplicate_fast(); Size2i b_size = B->size(); ERR_FAIL_COND_V(b_size.x != c->size(), c); const real_t *b_ptr = B->ptr(); real_t *c_ptr = c->ptrw(); for (int i = 0; i < b_size.y; ++i) { for (int j = 0; j < b_size.x; ++j) { c_ptr[j] -= b_ptr[B->calculate_index(i, j)]; } } return c; } Ref MLPPLinAlg::outer_product(const Ref &a, const Ref &b) { Ref C; C.instance(); Size2i size = Size2i(b->size(), a->size()); C->resize(size); const real_t *a_ptr = a->ptr(); const real_t *b_ptr = b->ptr(); for (int i = 0; i < size.y; ++i) { real_t curr_a = a_ptr[i]; for (int j = 0; j < size.x; ++j) { C->element_set(i, j, curr_a * b_ptr[j]); } } return C; } Ref MLPPLinAlg::mat_vec_addnm(const Ref &A, const Ref &b) { ERR_FAIL_COND_V(!A.is_valid() || !b.is_valid(), Ref()); Size2i a_size = A->size(); ERR_FAIL_COND_V(a_size.x != b->size(), Ref()); Ref ret; ret.instance(); ret->resize(a_size); const real_t *a_ptr = A->ptr(); const real_t *b_ptr = b->ptr(); real_t *ret_ptr = ret->ptrw(); for (int i = 0; i < a_size.y; ++i) { for (int j = 0; j < a_size.x; ++j) { int mat_index = A->calculate_index(i, j); ret_ptr[mat_index] = a_ptr[mat_index] + b_ptr[j]; } } return ret; } Ref MLPPLinAlg::diagnm(const Ref &a) { int a_size = a->size(); Ref B; B.instance(); B->resize(Size2i(a_size, a_size)); B->fill(0); const real_t *a_ptr = a->ptr(); real_t *b_ptr = B->ptrw(); for (int i = 0; i < a_size; ++i) { b_ptr[B->calculate_index(i, i)] = a_ptr[i]; } return B; } Vector> MLPPLinAlg::additionnvt(const Vector> &A, const Vector> &B) { Vector> res; res.resize(A.size()); for (int i = 0; i < res.size(); i++) { res.write[i] = additionnm(A[i], B[i]); } return res; } void MLPPLinAlg::division_element_wisevt(const Vector> &A, const Vector> &B) { for (int i = 0; i < A.size(); i++) { Ref m = A[i]; m->division_element_wise(B[i]); } } Vector> MLPPLinAlg::division_element_wisenvnvt(const Vector> &A, const Vector> &B) { Vector> res; res.resize(A.size()); for (int i = 0; i < A.size(); i++) { res.write[i] = division_element_wisenvnm(A[i], B[i]); } return res; } Vector> MLPPLinAlg::sqrtnvt(const Vector> &A) { Vector> res; res.resize(A.size()); for (int i = 0; i < A.size(); i++) { res.write[i] = sqrtnm(A[i]); } return res; } Vector> MLPPLinAlg::exponentiatenvt(const Vector> &A, real_t p) { Vector> res; res.resize(A.size()); for (int i = 0; i < A.size(); i++) { res.write[i] = exponentiatenm(A[i], p); } return res; } /* std::vector> MLPPLinAlg::tensor_vec_mult(std::vector>> A, std::vector b) { std::vector> C; C.resize(A.size()); for (uint32_t i = 0; i < C.size(); i++) { C[i].resize(A[0].size()); } for (uint32_t i = 0; i < C.size(); i++) { for (uint32_t j = 0; j < C[i].size(); j++) { C[i][j] = dot(A[i][j], b); } } return C; } */ /* std::vector MLPPLinAlg::flatten(std::vector>> A) { std::vector c; for (uint32_t i = 0; i < A.size(); i++) { std::vector flattenedVec = flatten(A[i]); c.insert(c.end(), flattenedVec.begin(), flattenedVec.end()); } return c; } */ Vector> MLPPLinAlg::scalar_multiplynvt(real_t scalar, Vector> A) { for (int i = 0; i < A.size(); i++) { A.write[i] = scalar_multiplynm(scalar, A[i]); } return A; } Vector> MLPPLinAlg::scalar_addnvt(real_t scalar, Vector> A) { for (int i = 0; i < A.size(); i++) { A.write[i] = scalar_addnm(scalar, A[i]); } return A; } void MLPPLinAlg::resizevt(Vector> &r_target, const Vector> &A) { r_target.resize(A.size()); for (int i = 0; i < r_target.size(); i++) { Ref m; m.instance(); m->resize(A[i]->size()); r_target.write[i] = m; } } Vector> MLPPLinAlg::resizencvt(const Vector> &A) { Vector> res; res.resize(A.size()); for (int i = 0; i < res.size(); i++) { Ref m; m.instance(); m->resize(A[i]->size()); res.write[i] = m; } return res; } Vector> MLPPLinAlg::maxnvt(const Vector> &A, const Vector> &B) { Vector> res; res.resize(A.size()); for (int i = 0; i < A.size(); i++) { res.write[i] = maxnm(A[i], B[i]); } return res; } Vector> MLPPLinAlg::absnvt(const Vector> &A) { Vector> res; res.resize(A.size()); for (int i = 0; i < A.size(); i++) { res.write[i] = absnm(A[i]); } return A; } /* real_t MLPPLinAlg::norm_2(std::vector>> A) { real_t sum = 0; for (uint32_t i = 0; i < A.size(); i++) { for (uint32_t j = 0; j < A[i].size(); j++) { for (uint32_t k = 0; k < A[i][j].size(); k++) { sum += A[i][j][k] * A[i][j][k]; } } } return Math::sqrt(sum); } */ /* // Bad implementation. Change this later. std::vector>> MLPPLinAlg::vector_wise_tensor_product(std::vector>> A, std::vector> B) { std::vector>> C; C = resize(C, A); for (uint32_t i = 0; i < A[0].size(); i++) { for (uint32_t j = 0; j < A[0][i].size(); j++) { std::vector currentVector; currentVector.resize(A.size()); for (uint32_t k = 0; k < C.size(); k++) { currentVector[k] = A[k][i][j]; } currentVector = mat_vec_mult(B, currentVector); for (uint32_t k = 0; k < C.size(); k++) { C[k][i][j] = currentVector[k]; } } } return C; } */ void MLPPLinAlg::_bind_methods() { }