// Copyright 2021 DeepMind Technologies Limited // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "engine/engine_util_sparse.h" #include "engine/engine_util_sparse_avx.h" #include #include #include #include "engine/engine_io.h" #include "engine/engine_macro.h" #include "engine/engine_util_blas.h" //------------------------------ sparse operations ------------------------------------------------- // dot-product, first vector is sparse mjtNum mju_dotSparse(const mjtNum* vec1, const mjtNum* vec2, const int nnz1, const int* ind1) { #ifdef mjUSEAVX return mju_dotSparse_avx(vec1, vec2, nnz1, ind1); #else int i = 0; mjtNum res = 0; int n_4 = nnz1 - 4; mjtNum res0 = 0; mjtNum res1 = 0; mjtNum res2 = 0; mjtNum res3 = 0; for (; i<=n_4; i+=4) { res0 += vec1[i+0] * vec2[ind1[i+0]]; res1 += vec1[i+1] * vec2[ind1[i+1]]; res2 += vec1[i+2] * vec2[ind1[i+2]]; res3 += vec1[i+3] * vec2[ind1[i+3]]; } res = (res0 + res2) + (res1 + res3); // scalar part for (; i= rownnz[r]) r++; // swap rows with columns and increment res_rowadr int c = res_rowadr[colind[i]]++; res[c] = mat[i]; res_colind[c] = r; } // shift back row addresses for (int i = nc-1; i>0; i--) { res_rowadr[i] = res_rowadr[i-1]; } res_rowadr[0] = 0; } // construct row supernodes void mju_superSparse(int nr, int* rowsuper, const int* rownnz, const int* rowadr, const int* colind) { // no rows: nothing to do if (!nr) { return; } // find match to child for (int r=0; r=0; r--) { if (rowsuper[r]) { rowsuper[r] += rowsuper[r+1]; } } } // compute sparse M'*diag*M (diag=NULL: compute M'*M), res has uncompressed layout void mju_sqrMatTDSparse(mjtNum* res, const mjtNum* mat, const mjtNum* matT, const mjtNum* diag, int nr, int nc, int* res_rownnz, int* res_rowadr, int* res_colind, const int* rownnz, const int* rowadr, const int* colind, const int* rowsuper, const int* rownnzT, const int* rowadrT, const int* colindT, const int* rowsuperT, mjData* d) { // allocate space for accumulation buffer and matT mjMARKSTACK; // set uncompressed layout (the following doesn't depend on this layout) for (int r=0; r0 && rowsuperT[i-1]) { res_rownnz[i] = res_rownnz[i-1]; memcpy(cols, res_colind+res_rowadr[i-1], res_rownnz[i]*sizeof(int)); } // iterate through each row of M' int end = rowadrT[i] + rownnzT[i]; for (int r = rowadrT[i]; ri) { break; } buffer[cc] += v*mat[c]; // only need to insert nnz if not marked if (!markers[cc]) { markers[cc] = 1; // since i is the rightmost column, it can be inserted at the end if (cc==i) { cols[res_rownnz[i]++] = cc; continue; } // insert col in order via binary search int l = 0, h = res_rownnz[i]; while (l> 1; if (cols[m]