Refactor mju_combineSparse to eliminate temporary buffers.
Combine sparse vectors in-place by first counting total `nnz` and then working backwards from the end. This removes the need for temporary buffers in `mju_combineSparse` and its callers and speeds up the function by ~10%. PiperOrigin-RevId: 902530210 Change-Id: I4f48c327103552ab968d3915399c6067367bec9f
This commit is contained in:
committed by
Copybara-Service
parent
3230cf99f9
commit
e6d77650f7
@@ -62,11 +62,10 @@ MJAPI void mju_mulMatVecSparse(mjtNum* res, const mjtNum* mat, const mjtNum* vec
|
||||
MJAPI void mju_mulMatTVecSparse(mjtNum* res, const mjtNum* mat, const mjtNum* vec, int nr, int nc,
|
||||
const int* rownnz, const int* rowadr, const int* colind);
|
||||
|
||||
// add sparse matrix M to sparse destination matrix, requires pre-allocated buffers
|
||||
// add sparse matrix M to sparse destination matrix
|
||||
MJAPI void mju_addToMatSparse(mjtNum* dst, int* rownnz, int* rowadr, int* colind, int nr,
|
||||
const mjtNum* M, const int* M_rownnz, const int* M_rowadr,
|
||||
const int* M_colind,
|
||||
mjtNum* buf_val, int* buf_ind);
|
||||
const int* M_colind);
|
||||
|
||||
// add symmetric matrix (only lower triangle represented) to dense matrix
|
||||
MJAPI void mju_addToSymSparse(mjtNum* res, const mjtNum* mat, int n,
|
||||
@@ -294,8 +293,7 @@ void mju_addToSclScl(mjtNum* res, const mjtNum* vec, mjtNum scl1, mjtNum scl2, i
|
||||
// combine two sparse vectors: dst = a*dst + b*src, return nnz of result
|
||||
static inline
|
||||
int mju_combineSparse(mjtNum* dst, const mjtNum* src, mjtNum a, mjtNum b,
|
||||
int dst_nnz, int src_nnz, int* dst_ind, const int* src_ind,
|
||||
mjtNum* buf, int* buf_ind) {
|
||||
int dst_nnz, int src_nnz, int* dst_ind, const int* src_ind) {
|
||||
// check for identical pattern
|
||||
if (dst_nnz == src_nnz) {
|
||||
if (mju_compare(dst_ind, src_ind, dst_nnz)) {
|
||||
@@ -305,49 +303,54 @@ int mju_combineSparse(mjtNum* dst, const mjtNum* src, mjtNum a, mjtNum b,
|
||||
}
|
||||
}
|
||||
|
||||
// copy dst into buf
|
||||
if (dst_nnz) {
|
||||
memcpy(buf, dst, dst_nnz * sizeof(mjtNum));
|
||||
memcpy(buf_ind, dst_ind, dst_nnz * sizeof(int));
|
||||
}
|
||||
// compute total nnz of result
|
||||
int nnz = mju_combineSparseCount(dst_nnz, src_nnz, dst_ind, src_ind);
|
||||
|
||||
// prepare to merge buf and src into dst
|
||||
int bi = 0, si = 0, nnz = 0;
|
||||
int buf_nnz = dst_nnz;
|
||||
// set up read/write pointers at end of arrays
|
||||
int bi = dst_nnz - 1, si = src_nnz - 1, w = nnz - 1;
|
||||
|
||||
// merge vectors
|
||||
while (bi < buf_nnz && si < src_nnz) {
|
||||
int badr = buf_ind[bi];
|
||||
// merge backwards
|
||||
while (bi >= 0 && si >= 0) {
|
||||
int badr = dst_ind[bi];
|
||||
int sadr = src_ind[si];
|
||||
|
||||
if (badr == sadr) {
|
||||
dst[nnz] = a*buf[bi++] + b*src[si++];
|
||||
dst_ind[nnz++] = badr;
|
||||
dst[w] = a*dst[bi] + b*src[si];
|
||||
dst_ind[w] = badr;
|
||||
bi--;
|
||||
si--;
|
||||
}
|
||||
|
||||
// buf only
|
||||
else if (badr < sadr) {
|
||||
dst[nnz] = a*buf[bi++];
|
||||
dst_ind[nnz++] = badr;
|
||||
// dst only
|
||||
else if (badr > sadr) {
|
||||
dst[w] = a*dst[bi];
|
||||
dst_ind[w] = badr;
|
||||
bi--;
|
||||
}
|
||||
|
||||
// src only
|
||||
else {
|
||||
dst[nnz] = b*src[si++];
|
||||
dst_ind[nnz++] = sadr;
|
||||
dst[w] = b*src[si];
|
||||
dst_ind[w] = sadr;
|
||||
si--;
|
||||
}
|
||||
w--;
|
||||
}
|
||||
|
||||
// the rest of src only
|
||||
while (si < src_nnz) {
|
||||
dst[nnz] = b*src[si];
|
||||
dst_ind[nnz++] = src_ind[si++];
|
||||
// remaining src elements
|
||||
while (si >= 0) {
|
||||
dst[w] = b*src[si];
|
||||
dst_ind[w] = src_ind[si];
|
||||
si--;
|
||||
w--;
|
||||
}
|
||||
|
||||
// the rest of buf only
|
||||
while (bi < buf_nnz) {
|
||||
dst[nnz] = a*buf[bi];
|
||||
dst_ind[nnz++] = buf_ind[bi++];
|
||||
// remaining dst elements: already in place, scale by a
|
||||
if (a != 1) {
|
||||
while (bi >= 0) {
|
||||
dst[bi] *= a;
|
||||
bi--;
|
||||
}
|
||||
}
|
||||
|
||||
return nnz;
|
||||
|
||||
Reference in New Issue
Block a user