Stop over-allocating memory in Newton solver.
PiperOrigin-RevId: 684797464 Change-Id: I3389416cb69a8564b5119f6e3944b579893ea511
This commit is contained in:
committed by
Copybara-Service
parent
9aca4bccac
commit
2dd518734f
+5
-1
@@ -8,9 +8,13 @@ Upcoming version (not yet released)
|
||||
General
|
||||
^^^^^^^
|
||||
|
||||
- The Newton solver no longer requires ``nv*nv`` memory allocation, allowing for much larger models. See e.g.,
|
||||
`100_humanoids.xml <https://github.com/google-deepmind/mujoco/blob/main/model/humanoid/100_humanoids.xml>`__.
|
||||
Two quadratic-memory allocations still remain to be fully sparsified: ``mjData.actuator_moment`` and the matrices used
|
||||
by the PGS solver.
|
||||
- Removed the :at:`solid` and :at:`membrane` plugins and moved the associated computations into the engine. See `3D
|
||||
example model <https://github.com/google-deepmind/mujoco/blob/main/model/flex/floppy.xml>`__ and `2D example model
|
||||
<https://github.com/google-deepmind/mujoco/blob/main/src/model/trampoline.xml>`__ for examples of flex objects
|
||||
<https://github.com/google-deepmind/mujoco/blob/main/model/flex/trampoline.xml>`__ for examples of flex objects
|
||||
that previously required these plugins.
|
||||
- Replaced the function ``mjs_setActivePlugins`` with :ref:`mjs_activatePlugin`.
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
<!-- 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.
|
||||
-->
|
||||
|
||||
<mujoco model="100 Humanoids">
|
||||
<option timestep="0.005"/>
|
||||
|
||||
<size memory="100M"/>
|
||||
|
||||
<asset>
|
||||
<texture type="skybox" builtin="gradient" rgb1=".3 .5 .7" rgb2="0 0 0" width="512" height="512"/>
|
||||
<texture name="floor" type="2d" builtin="checker" width="512" height="512" rgb1=".1 .2 .3" rgb2=".2 .3 .4"/>
|
||||
<material name="floor" texture="floor" texrepeat="1 1" texuniform="true" reflectance=".2"/>
|
||||
<model name="humanoid" file="humanoid.xml"/>
|
||||
</asset>
|
||||
|
||||
<visual>
|
||||
<map force="0.1" zfar="30"/>
|
||||
<rgba haze="0.15 0.25 0.35 1"/>
|
||||
<quality shadowsize="4096" numslices="16" numstacks="8"/>
|
||||
<global offwidth="800" offheight="800"/>
|
||||
</visual>
|
||||
|
||||
<worldbody>
|
||||
<geom name="floor" size="10 10 .05" type="plane" material="floor" condim="3"/>
|
||||
<light directional="true" diffuse=".4 .4 .4" specular="0.1 0.1 0.1" pos="0 0 5" dir="0 0 -1" castshadow="false"/>
|
||||
<light name="spotlight" mode="targetbodycom" target="world" diffuse="1 1 1" specular="0.3 0.3 0.3" pos="-6 -6 4" cutoff="60"/>
|
||||
<replicate count="10" euler="0 0 36" sep="-">
|
||||
<frame pos="1 0 0">
|
||||
<replicate count="10" euler="0 0 15" sep="-" offset="0.5 0 0">
|
||||
<attach model="humanoid" body="torso" prefix="_"/>
|
||||
</replicate>
|
||||
</frame>
|
||||
</replicate>
|
||||
<replicate count="5" euler="0 0 72" sep="-">
|
||||
<light pos="0 -4 4"/>
|
||||
</replicate>
|
||||
</worldbody>
|
||||
</mujoco>
|
||||
+22
-16
@@ -756,7 +756,7 @@ void mj_printFormattedData(const mjModel* m, mjData* d, const char* filename,
|
||||
mjERROR("attempting to print mjData when stack is in use");
|
||||
}
|
||||
|
||||
mjtNum *M;
|
||||
mjtNum *M = NULL;
|
||||
mj_markStack(d);
|
||||
|
||||
// check format string
|
||||
@@ -780,8 +780,10 @@ void mj_printFormattedData(const mjModel* m, mjData* d, const char* filename,
|
||||
return;
|
||||
}
|
||||
|
||||
// allocate full inertia
|
||||
M = mj_stackAllocNum(d, m->nv*m->nv);
|
||||
// allocate full inertia if it's small
|
||||
if (m->nv <= 200) {
|
||||
M = mj_stackAllocNum(d, m->nv*m->nv);
|
||||
}
|
||||
|
||||
#ifdef MEMORY_SANITIZER
|
||||
// If memory sanitizer is active, d->buffer will be marked as poisoned, even
|
||||
@@ -969,13 +971,15 @@ void mj_printFormattedData(const mjModel* m, mjData* d, const char* filename,
|
||||
printArray("ACTUATOR_MOMENT", m->nu, m->nv, d->actuator_moment, fp, float_format);
|
||||
printArray("CRB", m->nbody, 10, d->crb, fp, float_format);
|
||||
|
||||
// construct and print full M matrix
|
||||
mj_fullM(m, M, d->qM);
|
||||
printArray("QM", m->nv, m->nv, M, fp, float_format);
|
||||
if (M) {
|
||||
// construct and print full M matrix
|
||||
mj_fullM(m, M, d->qM);
|
||||
printArray("QM", m->nv, m->nv, M, fp, float_format);
|
||||
|
||||
// construct and print full LD matrix
|
||||
mj_fullM(m, M, d->qLD);
|
||||
printArray("QLD", m->nv, m->nv, M, fp, float_format);
|
||||
// construct and print full LD matrix
|
||||
mj_fullM(m, M, d->qLD);
|
||||
printArray("QLD", m->nv, m->nv, M, fp, float_format);
|
||||
}
|
||||
|
||||
printArray("QLDIAGINV", m->nv, 1, d->qLDiagInv, fp, float_format);
|
||||
printArray("QLDIAGSQRTINV", m->nv, 1, d->qLDiagSqrtInv, fp, float_format);
|
||||
@@ -1064,14 +1068,16 @@ void mj_printFormattedData(const mjModel* m, mjData* d, const char* filename,
|
||||
}
|
||||
fprintf(fp, "\n\n");
|
||||
|
||||
// print qDeriv
|
||||
mju_sparse2dense(M, d->qDeriv, m->nv, m->nv, d->D_rownnz, d->D_rowadr, d->D_colind);
|
||||
printArray("QDERIV", m->nv, m->nv, M, fp, float_format);
|
||||
if (M) {
|
||||
// print qDeriv
|
||||
mju_sparse2dense(M, d->qDeriv, m->nv, m->nv, d->D_rownnz, d->D_rowadr, d->D_colind);
|
||||
printArray("QDERIV", m->nv, m->nv, M, fp, float_format);
|
||||
|
||||
// print qLU
|
||||
mju_sparse2dense(M, d->qLU, m->nv, m->nv, d->D_rownnz, d->D_rowadr,
|
||||
d->D_colind);
|
||||
printArray("QLU", m->nv, m->nv, M, fp, float_format);
|
||||
// print qLU
|
||||
mju_sparse2dense(M, d->qLU, m->nv, m->nv, d->D_rownnz, d->D_rowadr,
|
||||
d->D_colind);
|
||||
printArray("QLU", m->nv, m->nv, M, fp, float_format);
|
||||
}
|
||||
|
||||
// contact
|
||||
fprintf(fp, "CONTACT\n");
|
||||
|
||||
+130
-59
@@ -830,11 +830,29 @@ static void CGallocate(const mjModel* m, mjData* d, mjCGContext* ctx,
|
||||
|
||||
// Hessian (Newton only)
|
||||
ctx->flg_Newton = flg_Newton;
|
||||
if (flg_Newton && mj_isSparse(m)) {
|
||||
d->L_rowadr = mj_arenaAllocByte(d, sizeof(int) * nv, _Alignof(int));
|
||||
if (!d->L_rowadr) mjERROR("failed to allocate L_rowadr");
|
||||
d->L_rownnz = mj_arenaAllocByte(d, sizeof(int) * nv, _Alignof(int));
|
||||
if (!d->L_rownnz) mjERROR("failed to allocate L_rownnz");
|
||||
if (flg_Newton) {
|
||||
// sparse: allocate L_rowadr, L_rownnz
|
||||
if (mj_isSparse(m)) {
|
||||
d->L_rowadr = mj_arenaAllocByte(d, sizeof(int) * nv, _Alignof(int));
|
||||
if (!d->L_rowadr) mjERROR("failed to allocate L_rowadr");
|
||||
d->L_rownnz = mj_arenaAllocByte(d, sizeof(int) * nv, _Alignof(int));
|
||||
if (!d->L_rownnz) mjERROR("failed to allocate L_rownnz");
|
||||
|
||||
// zero nnzL, clear pointers (compute and allocate later in HessianDirect)
|
||||
d->nnzL = 0;
|
||||
d->L_colind = NULL;
|
||||
d->L = NULL;
|
||||
d->Lcone = NULL;
|
||||
}
|
||||
|
||||
// dense: allocate L
|
||||
else if (d->nnzL != nv*nv) {
|
||||
d->L = mj_arenaAllocByte(d, sizeof(mjtNum) * nv*nv, _Alignof(mjtNum));
|
||||
if (!d->L) mjERROR("failed to allocate L");
|
||||
|
||||
// set dense nnzL
|
||||
d->nnzL = nv*nv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1362,6 +1380,16 @@ static mjtNum CGsearch(const mjModel* m, const mjData* d, mjCGContext* ctx) {
|
||||
static void HessianCone(const mjModel* m, mjData* d, mjCGContext* ctx) {
|
||||
int nv = m->nv, nefc = d->nefc;
|
||||
mjtNum local[36];
|
||||
|
||||
// allocate Lcone if required
|
||||
if (!d->Lcone) {
|
||||
d->Lcone = mj_arenaAllocByte(d, sizeof(mjtNum) * d->nnzL, _Alignof(mjtNum));
|
||||
}
|
||||
if (!d->Lcone) mjERROR("failed to allocate Lcone");
|
||||
|
||||
// start with Hcone = H
|
||||
mju_copy(d->Lcone, d->L, d->nnzL);
|
||||
|
||||
mj_markStack(d);
|
||||
|
||||
// storage for L'*J
|
||||
@@ -1369,9 +1397,6 @@ static void HessianCone(const mjModel* m, mjData* d, mjCGContext* ctx) {
|
||||
mjtNum* LTJ_row = mj_stackAllocNum(d, nv);
|
||||
int* LTJ_ind = mj_stackAllocInt(d, nv);
|
||||
|
||||
// start with Hcone = H
|
||||
mju_copy(d->Lcone, d->L, d->nnzL);
|
||||
|
||||
// add contributions
|
||||
for (int i=0; i < nefc; i++) {
|
||||
if (d->efc_state[i] == mjCNSTRSTATE_CONE) {
|
||||
@@ -1440,21 +1465,6 @@ static void HessianCone(const mjModel* m, mjData* d, mjCGContext* ctx) {
|
||||
// TODO: b/295296178 - add island support to Newton solver
|
||||
static void HessianDirect(const mjModel* m, mjData* d, mjCGContext* ctx) {
|
||||
int nv = m->nv, nefc = d->nefc;
|
||||
|
||||
// allocate Hessian on arena if not already allocated
|
||||
if (!d->nnzL) {
|
||||
int nnz = nv*nv;
|
||||
if (mj_isSparse(m)) {
|
||||
d->L_colind = mj_arenaAllocByte(d, sizeof(int) * nnz, _Alignof(int));
|
||||
if (!d->L_colind) mjERROR("failed to allocate L_colind");
|
||||
}
|
||||
d->L = mj_arenaAllocByte(d, sizeof(mjtNum) * nnz, _Alignof(mjtNum));
|
||||
if (!d->L) mjERROR("failed to allocate L");
|
||||
d->Lcone = mj_arenaAllocByte(d, sizeof(mjtNum) * nnz, _Alignof(mjtNum));
|
||||
if (!d->Lcone) mjERROR("failed to allocate Lcone");
|
||||
d->nnzL = nnz;
|
||||
}
|
||||
|
||||
mj_markStack(d);
|
||||
|
||||
// compute D corresponding to quad states
|
||||
@@ -1469,44 +1479,109 @@ static void HessianDirect(const mjModel* m, mjData* d, mjCGContext* ctx) {
|
||||
|
||||
// sparse
|
||||
if (mj_isSparse(m)) {
|
||||
// fill-in reduced sparse inertia matrix C (no off-diagonals for simple dofs)
|
||||
int nC = m->nC;
|
||||
mjtNum* C = mj_stackAllocNum(d, nC);
|
||||
for (int i=0; i < nC; i++) {
|
||||
// copy values of reduced sparse inertia matrix C, get nnz
|
||||
int nnz_C = m->nC;
|
||||
mjtNum* C = mj_stackAllocNum(d, nnz_C);
|
||||
for (int i=0; i < nnz_C; i++) {
|
||||
C[i] = d->qM[d->mapM2C[i]];
|
||||
}
|
||||
|
||||
// compute H = J'*D*J
|
||||
// allocate and initialize Hessian rowadr, rownnz; get nnz for J'*J
|
||||
int* H_rowadr = mj_stackAllocInt(d, nv);
|
||||
int* H_rownnz = mj_stackAllocInt(d, nv);
|
||||
mju_sqrMatTDSparseInit(H_rownnz, H_rowadr, nv,
|
||||
d->efc_J_rownnz, d->efc_J_rowadr, d->efc_J_colind,
|
||||
d->efc_JT_rownnz, d->efc_JT_rowadr, d->efc_JT_colind, d->efc_JT_rowsuper,
|
||||
d);
|
||||
int nnz_JTJ = H_rowadr[nv-1] + H_rownnz[nv-1];
|
||||
|
||||
// TODO(b/266802572): remove uncompressed layout
|
||||
mju_sqrMatTDUncompressedInit(d->L_rowadr, nv);
|
||||
mju_sqrMatTDSparse(d->L, d->efc_J, d->efc_JT, D, nefc, nv,
|
||||
d->L_rownnz, d->L_rowadr, d->L_colind,
|
||||
d->efc_J_rownnz, d->efc_J_rowadr,
|
||||
d->efc_J_colind, NULL,
|
||||
d->efc_JT_rownnz, d->efc_JT_rowadr,
|
||||
d->efc_JT_colind, d->efc_JT_rowsuper, d);
|
||||
|
||||
// compute H = M + J'*D*J
|
||||
mj_addMSparse(m, d, d->L, d->L_rownnz, d->L_rowadr, d->L_colind,
|
||||
C, d->C_rownnz, d->C_rowadr, d->C_colind);
|
||||
|
||||
// factorize H, uncompressed layout
|
||||
int rank = mju_cholFactorSparse(d->L, nv, mjMINVAL,
|
||||
d->L_rownnz, d->L_rowadr, d->L_colind, d);
|
||||
|
||||
// rank-defficient, SHOULD NOT OCCUR
|
||||
if (rank != nv) {
|
||||
mjERROR("rank-defficient Hessian");
|
||||
// shift H rowadr to make room for C
|
||||
int shift = 0;
|
||||
for (int r = 0; r < nv - 1; r++) {
|
||||
shift += d->C_rownnz[r];
|
||||
H_rowadr[r + 1] += shift;
|
||||
}
|
||||
|
||||
// compress layout of H
|
||||
mju_compressSparse(d->L, nv, nv, d->L_rownnz, d->L_rowadr, d->L_colind);
|
||||
// allocate Hessian H, colind
|
||||
int nnz_H = nnz_C + nnz_JTJ;
|
||||
mjtNum* H = mj_stackAllocNum(d, nnz_H);
|
||||
int* H_colind = mj_stackAllocInt(d, nnz_H);
|
||||
|
||||
// count nnz
|
||||
d->nnzL = d->L_rowadr[nv-1] + d->L_rownnz[nv-1];
|
||||
if (d->nnzL > nv*nv) { // SHOULD NOT OCCUR
|
||||
mjERROR("more nonzero values than elements in sparse direct-solver Hessian");
|
||||
// compute H = J'*D*J
|
||||
mju_sqrMatTDSparse(H, d->efc_J, d->efc_JT, D, nefc, nv,
|
||||
H_rownnz, H_rowadr, H_colind,
|
||||
d->efc_J_rownnz, d->efc_J_rowadr, d->efc_J_colind, NULL,
|
||||
d->efc_JT_rownnz, d->efc_JT_rowadr, d->efc_JT_colind, d->efc_JT_rowsuper,
|
||||
d);
|
||||
|
||||
// add mass matrix; H = J'*D*J + C
|
||||
mj_addMSparse(m, d, H, H_rownnz, H_rowadr, H_colind,
|
||||
C, d->C_rownnz, d->C_rowadr, d->C_colind);
|
||||
|
||||
// count row and total non-zeros of reverse-Cholesky factor L
|
||||
int* parent = mj_stackAllocInt(d, nv);
|
||||
int* flag = mj_stackAllocInt(d, nv);
|
||||
int nnz_L = mju_cholFactorNNZ(d->L_rownnz, parent, flag, H_rownnz, H_rowadr, H_colind, nv);
|
||||
|
||||
// allocate L_colind, L on arena if required
|
||||
if (!d->nnzL) {
|
||||
// nnzL is 0 but pointers are allocated; SHOULD NOT OCCUR
|
||||
if (d->L_colind || d->L) {
|
||||
mjERROR("nnzL is 0 but L_colind or L or Lcone are allocated");
|
||||
}
|
||||
|
||||
// allocate on arena
|
||||
d->L_colind = mj_arenaAllocByte(d, sizeof(int) * nnz_L, _Alignof(int));
|
||||
if (!d->L_colind) mjERROR("failed to allocate L_colind");
|
||||
d->L = mj_arenaAllocByte(d, sizeof(mjtNum) * nnz_L, _Alignof(mjtNum));
|
||||
if (!d->L) mjERROR("failed to allocate L");
|
||||
|
||||
// set nnzL
|
||||
d->nnzL = nnz_L;
|
||||
} else if (d->nnzL != nnz_L) {
|
||||
// nnzL is nonzero but not equal to computed value; SHOULD NOT OCCUR
|
||||
mjERROR("nnzL is nonzero but not equal to computed value");
|
||||
}
|
||||
|
||||
// compute L row adresses: L_rowadr = cumsum(L_rownnz)
|
||||
d->L_rowadr[0] = 0;
|
||||
for (int r=1; r < nv; r++) {
|
||||
d->L_rowadr[r] = d->L_rowadr[r-1] + d->L_rownnz[r-1];
|
||||
}
|
||||
|
||||
// copy H lower-triangle into L
|
||||
for (int r = 0; r < nv; r++) {
|
||||
// count H non-zeros up to diagonal (inclusive) for row r
|
||||
const int* colind = H_colind + H_rowadr[r];
|
||||
int rownnz = 1;
|
||||
while (rownnz < nv && colind[rownnz - 1] < r) {
|
||||
rownnz++;
|
||||
}
|
||||
|
||||
// last row element is not the diagonal; SHOULD NOT OCCUR
|
||||
if (colind[rownnz - 1] != r) {
|
||||
mjERROR("Newton solver Hessian has zero diagonal on row %d", r);
|
||||
}
|
||||
|
||||
// copy values and column indices
|
||||
mju_copy(d->L + d->L_rowadr[r], H + H_rowadr[r], rownnz);
|
||||
mju_copyInt(d->L_colind + d->L_rowadr[r], H_colind + H_rowadr[r], rownnz);
|
||||
|
||||
// set L_rownnz
|
||||
d->L_rownnz[r] = rownnz;
|
||||
}
|
||||
|
||||
// in-place sparse factorization L = chol(H)
|
||||
int rank = mju_cholFactorSparse(d->L, nv, mjMINVAL, d->L_rownnz, d->L_rowadr, d->L_colind, d);
|
||||
|
||||
// rank-deficient; SHOULD NOT OCCUR
|
||||
if (rank != nv) {
|
||||
mjERROR("rank-deficient Hessian");
|
||||
}
|
||||
|
||||
// pre-counted nnzL does not match post-factorization nnzL; SHOULD NOT OCCUR
|
||||
if (d->nnzL != d->L_rowadr[nv-1] + d->L_rownnz[nv-1]) {
|
||||
mjERROR("mismatch between pre-counted and post-factorization L nonzeros");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1518,9 +1593,6 @@ static void HessianDirect(const mjModel* m, mjData* d, mjCGContext* ctx) {
|
||||
|
||||
// factorize H
|
||||
mju_cholFactor(d->L, nv, mjMINVAL);
|
||||
|
||||
// set nnz
|
||||
d->nnzL = nv*nv;
|
||||
}
|
||||
|
||||
mj_freeStack(d);
|
||||
@@ -1538,8 +1610,7 @@ static void HessianDirect(const mjModel* m, mjData* d, mjCGContext* ctx) {
|
||||
|
||||
// incremental update to Hessian
|
||||
// TODO: b/295296178 - add island support to Newton solver
|
||||
static void HessianIncremental(const mjModel* m, mjData* d,
|
||||
mjCGContext* ctx, const int* oldstate) {
|
||||
static void HessianIncremental(const mjModel* m, mjData* d, mjCGContext* ctx, const int* oldstate) {
|
||||
int rank, nv = m->nv, nefc = d->nefc;
|
||||
mj_markStack(d);
|
||||
|
||||
|
||||
@@ -141,28 +141,15 @@ int mju_cholUpdate(mjtNum* mat, mjtNum* x, int n, int flg_plus) {
|
||||
//---------------------------- sparse Cholesky -----------------------------------------------------
|
||||
|
||||
// sparse reverse-order Cholesky decomposition: mat = L'*L; return 'rank'
|
||||
// mat must have uncompressed layout; rownnz is modified to end at diagonal
|
||||
// mat must be lower-triangular, have preallocated space for fill-in
|
||||
int mju_cholFactorSparse(mjtNum* mat, int n, mjtNum mindiag,
|
||||
int* rownnz, int* rowadr, int* colind,
|
||||
int* rownnz, const int* rowadr, int* colind,
|
||||
mjData* d) {
|
||||
int rank = n;
|
||||
|
||||
mj_markStack(d);
|
||||
mjtNum* buf = mj_stackAllocNum(d, n);
|
||||
int* buf_ind = mj_stackAllocInt(d, n);
|
||||
mjtNum* sparse_buf = mj_stackAllocNum(d, n);
|
||||
|
||||
// shrink rows so that rownnz ends at diagonal
|
||||
for (int r=0; r < n; r++) {
|
||||
// shrink
|
||||
while (rownnz[r] > 0 && colind[rowadr[r]+rownnz[r]-1] > r) {
|
||||
rownnz[r]--;
|
||||
}
|
||||
|
||||
// check
|
||||
if (rownnz[r] == 0 || colind[rowadr[r]+rownnz[r]-1] != r) {
|
||||
mjERROR("matrix must have non-zero diagonal");
|
||||
}
|
||||
}
|
||||
|
||||
// backpass over rows
|
||||
for (int r=n-1; r >= 0; r--) {
|
||||
@@ -191,7 +178,7 @@ int mju_cholFactorSparse(mjtNum* mat, int n, mjtNum mindiag,
|
||||
// mat(c,0:c) = mat(c,0:c) - mat(r,c) * mat(r,0:c)
|
||||
int nnz_c = mju_combineSparse(mat + rowadr[c], mat+rowadr[r], 1, -mat[adr+i],
|
||||
rownnz[c], i+1, colind+rowadr[c], colind+rowadr[r],
|
||||
sparse_buf, buf_ind);
|
||||
buf, buf_ind);
|
||||
|
||||
// assign new nnz to row c
|
||||
rownnz[c] = nnz_c;
|
||||
@@ -251,7 +238,7 @@ void mju_cholSolveSparse(mjtNum* res, const mjtNum* mat, const mjtNum* vec, int
|
||||
// sparse reverse-order Cholesky rank-one update: L'*L +/- x*x'; return rank
|
||||
// x is sparse, change in sparsity pattern of mat is not allowed
|
||||
int mju_cholUpdateSparse(mjtNum* mat, mjtNum* x, int n, int flg_plus,
|
||||
int* rownnz, int* rowadr, int* colind, int x_nnz, int* x_ind,
|
||||
const int* rownnz, const int* rowadr, int* colind, int x_nnz, int* x_ind,
|
||||
mjData* d) {
|
||||
mj_markStack(d);
|
||||
int* buf_ind = mj_stackAllocInt(d, n);
|
||||
|
||||
@@ -33,8 +33,9 @@ MJAPI void mju_cholSolve(mjtNum* res, const mjtNum* mat, const mjtNum* vec, int
|
||||
MJAPI int mju_cholUpdate(mjtNum* mat, mjtNum* x, int n, int flg_plus);
|
||||
|
||||
// sparse reverse-order Cholesky decomposition: mat = L'*L; return 'rank'
|
||||
// mat must have uncompressed layout; rownnz is modified to end at diagonal
|
||||
int mju_cholFactorSparse(mjtNum* mat, int n, mjtNum mindiag, int* rownnz, int* rowadr, int* colind,
|
||||
// mat must be lower-triangular, have preallocated space for fill-in
|
||||
int mju_cholFactorSparse(mjtNum* mat, int n, mjtNum mindiag,
|
||||
int* rownnz, const int* rowadr, int* colind,
|
||||
mjData* d);
|
||||
|
||||
// sparse reverse-order Cholesky solve
|
||||
@@ -44,7 +45,7 @@ void mju_cholSolveSparse(mjtNum* res, const mjtNum* mat, const mjtNum* vec, int
|
||||
// sparse reverse-order Cholesky rank-one update: L'*L +/i x*x'; return rank
|
||||
// x is sparse, change in sparsity pattern of mat is not allowed
|
||||
int mju_cholUpdateSparse(mjtNum* mat, mjtNum* x, int n, int flg_plus,
|
||||
int* rownnz, int* rowadr, int* colind, int x_nnz, int* x_ind,
|
||||
const int* rownnz, const int* rowadr, int* colind, int x_nnz, int* x_ind,
|
||||
mjData* d);
|
||||
|
||||
// band-dense Cholesky decomposition
|
||||
|
||||
@@ -28,7 +28,8 @@ test_model() {
|
||||
local iterations=10
|
||||
# for particularly slow models, only run 2 steps under ASAN, or skip.
|
||||
if [[ ${TESTSPEED_ASAN:-0} != 0 ]]; then
|
||||
if [[ "$model" == */composite/particle.xml ||
|
||||
if [[ "$model" == */humanoid/100_humanoids.xml ||
|
||||
"$model" == */composite/particle.xml ||
|
||||
"$model" == */replicate/bunnies.xml ||
|
||||
"$model" == */replicate/leaves.xml ||
|
||||
"$model" == */replicate/particle.xml ||
|
||||
|
||||
@@ -1312,7 +1312,8 @@ TEST_F(XMLWriterTest, WriteReadCompare) {
|
||||
std::string xml = p.path().string();
|
||||
|
||||
// if file is meant to fail, skip it
|
||||
if (absl::StrContains(p.path().string(), "malformed_") ||
|
||||
if (absl::StrContains(p.path().string(), "100_humanoids") ||
|
||||
absl::StrContains(p.path().string(), "malformed_") ||
|
||||
absl::StrContains(p.path().string(), "touch_grid") ||
|
||||
absl::StrContains(p.path().string(), "gmsh_") ||
|
||||
absl::StrContains(p.path().string(), "shark_") ||
|
||||
|
||||
Reference in New Issue
Block a user