Skip to content

Commit

Permalink
Merge pull request #218 from keenon/keenon/acc-minimizer
Browse files Browse the repository at this point in the history
Adding native AccelerationMinimizer support
  • Loading branch information
keenon authored Sep 11, 2024
2 parents af61a7d + 8c28aa5 commit b95d2d3
Show file tree
Hide file tree
Showing 12 changed files with 419 additions and 5 deletions.
2 changes: 1 addition & 1 deletion VERSION.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.10.44
0.10.45
144 changes: 144 additions & 0 deletions dart/utils/AccelerationMinimizer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
#include "AccelerationMinimizer.hpp"

#include <iostream>

// #include <Eigen/Core>
// #include <Eigen/Dense>
#include <Eigen/IterativeLinearSolvers>
// #include <unsupported/Eigen/IterativeSolvers>

#include "dart/math/MathTypes.hpp"

namespace dart {
namespace utils {

/**
* Create (and pre-factor) a smoother that can remove the "jerk" from a time
* series of data.
*
* The alpha value will determine how much smoothing to apply. A value of 0
* corresponds to no smoothing.
*/
AccelerationMinimizer::AccelerationMinimizer(
int timesteps,
s_t smoothingWeight,
s_t regularizationWeight,
s_t startPositionZeroWeight,
s_t endPositionZeroWeight,
s_t startVelocityZeroWeight,
s_t endVelocityZeroWeight,
int numIterations)
: mTimesteps(timesteps),
mSmoothingWeight(smoothingWeight),
mRegularizationWeight(regularizationWeight),
mStartPositionZeroWeight(startPositionZeroWeight * timesteps),
mEndPositionZeroWeight(endPositionZeroWeight * timesteps),
mStartVelocityZeroWeight(startVelocityZeroWeight * timesteps),
mEndVelocityZeroWeight(endVelocityZeroWeight * timesteps),
mNumIterations(numIterations),
mNumIterationsBackoff(6),
mDebugIterationBackoff(false),
mConvergenceTolerance(1e-10)
{
Eigen::Vector3s stamp;
stamp << -1, 2, -1;
stamp *= mSmoothingWeight;

typedef Eigen::Triplet<s_t> T;
std::vector<T> tripletList;
const int accTimesteps = mTimesteps - 2;
for (int i = 0; i < accTimesteps; i++)
{
for (int j = 0; j < 3; j++)
{
tripletList.push_back(T(i, i + j, stamp(j)));
}
}
// Add start velocity zero constraint
tripletList.push_back(T(accTimesteps, 0, mStartVelocityZeroWeight));
tripletList.push_back(T(accTimesteps, 1, -mStartVelocityZeroWeight));
// Add end velocity zero constraint
tripletList.push_back(
T(accTimesteps + 1, mTimesteps - 2, mEndVelocityZeroWeight));
tripletList.push_back(
T(accTimesteps + 1, mTimesteps - 1, -mEndVelocityZeroWeight));
// Add start position zero constraint
tripletList.push_back(T(accTimesteps + 2, 0, mStartPositionZeroWeight));
// Add end position zero constraint
tripletList.push_back(
T(accTimesteps + 3, mTimesteps - 1, mEndPositionZeroWeight));
for (int i = 0; i < mTimesteps; i++)
{
tripletList.push_back(T(accTimesteps + 4 + i, i, mRegularizationWeight));
}
mB_sparse
= Eigen::SparseMatrix<s_t>(accTimesteps + 4 + mTimesteps, mTimesteps);
mB_sparse.setFromTriplets(tripletList.begin(), tripletList.end());
mB_sparse.makeCompressed();
mB_sparseSolver.analyzePattern(mB_sparse);
mB_sparseSolver.factorize(mB_sparse);
if (mB_sparseSolver.info() != Eigen::Success)
{
std::cout << "mB_sparseSolver.factorize(mB_sparse) error: "
<< mB_sparseSolver.lastErrorMessage() << std::endl;
}
assert(mB_sparseSolver.info() == Eigen::Success);
}

Eigen::VectorXs AccelerationMinimizer::minimize(Eigen::VectorXs series)
{
const int accTimesteps = mTimesteps - 2;
Eigen::VectorXs b = Eigen::VectorXs(accTimesteps + 4 + mTimesteps);
b.segment(0, accTimesteps + 4).setZero();
b.segment(accTimesteps + 4, mTimesteps) = series * mRegularizationWeight;

Eigen::VectorXs x = series;

int iterations = mNumIterations;
for (int i = 0; i < mNumIterationsBackoff; i++)
{
Eigen::LeastSquaresConjugateGradient<Eigen::SparseMatrix<s_t>> solver;
solver.compute(mB_sparse);
solver.setTolerance(mConvergenceTolerance);
solver.setMaxIterations(iterations);
x = solver.solveWithGuess(b, series);
// Check convergence
if (solver.info() == Eigen::Success)
{
// Converged
break;
}
else
{
if (mDebugIterationBackoff)
{
std::cout
<< "[AccelerationMinimizer] LeastSquaresConjugateGradient did "
"not converge in "
<< iterations << ", with error " << solver.error()
<< " so doubling iteration count and trying again." << std::endl;
}
iterations *= 2;
}
}

return x;
}

void AccelerationMinimizer::setDebugIterationBackoff(bool debug)
{
mDebugIterationBackoff = debug;
}

void AccelerationMinimizer::setNumIterationsBackoff(int numIterations)
{
mNumIterationsBackoff = numIterations;
}

void AccelerationMinimizer::setConvergenceTolerance(s_t tolerance)
{
mConvergenceTolerance = tolerance;
}

} // namespace utils
} // namespace dart
53 changes: 53 additions & 0 deletions dart/utils/AccelerationMinimizer.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#ifndef UTILS_ACC_MINIMIZER
#define UTILS_ACC_MINIMIZER

#include <Eigen/Sparse>
#include <Eigen/SparseQR>

#include "dart/math/MathTypes.hpp"

namespace dart {
namespace utils {

class AccelerationMinimizer
{
public:
AccelerationMinimizer(
int numTimesteps,
s_t smoothingWeight = 1.0,
s_t regularizationWeight = 0.01,
s_t startPositionZeroWeight = 0.0,
s_t endPositionZeroWeight = 0.0,
s_t startVelocityZeroWeight = 0.0,
s_t endVelocityZeroWeight = 0.0,
int numIterations = 10000);

Eigen::VectorXs minimize(Eigen::VectorXs series);

void setDebugIterationBackoff(bool debug);

void setNumIterationsBackoff(int numIterations);

void setConvergenceTolerance(s_t tolerance);

protected:
int mTimesteps;
s_t mSmoothingWeight;
s_t mRegularizationWeight;
s_t mStartPositionZeroWeight;
s_t mEndPositionZeroWeight;
s_t mStartVelocityZeroWeight;
s_t mEndVelocityZeroWeight;
int mNumIterations;
int mNumIterationsBackoff;
bool mDebugIterationBackoff;
s_t mConvergenceTolerance;
Eigen::SparseMatrix<s_t> mB_sparse;
Eigen::SparseQR<Eigen::SparseMatrix<s_t>, Eigen::NaturalOrdering<int>>
mB_sparseSolver;
};

} // namespace utils
} // namespace dart

#endif
61 changes: 61 additions & 0 deletions python/_nimblephysics/biomechanics/MarkerLabeller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,67 @@ void MarkerLabeller(py::module& m)
{
(void)m;
::py::class_<dart::biomechanics::MarkerTrace>(m, "MarkerTrace")
.def_static(
"createRawTraces",
&dart::biomechanics::MarkerTrace::createRawTraces,
::py::arg("pointClouds"),
::py::arg("mergeDistance") = 0.01,
::py::arg("mergeFrames") = 5)
.def(
"appendPoint",
&dart::biomechanics::MarkerTrace::appendPoint,
::py::arg("time"),
::py::arg("point"),
"Add a point to the end of the marker trace")
.def(
"pointToAppendDistance",
&dart::biomechanics::MarkerTrace::pointToAppendDistance,
::py::arg("time"),
::py::arg("point"),
::py::arg("extrapolate"),
"This gives the distance from the last point (or an extrapolation at "
"this timestep of the last point, of order up to 2)")
.def(
"computeBodyMarkerStats",
&dart::biomechanics::MarkerTrace::computeBodyMarkerStats,
::py::arg("skel"),
::py::arg("posesOverTime"),
::py::arg("scalesOverTime"),
"Each possible combination of (trace, body) can create a marker. So "
"we can compute some summary statistics for each body we could "
"assign this trace to.")
.def(
"computeBodyMarkerLoss",
&dart::biomechanics::MarkerTrace::computeBodyMarkerLoss,
::py::arg("bodyName"),
"Each possible combination of (trace, body) can create a marker. "
"This returns a score for a given body, for how \"good\" of a marker "
"that body would create when combined with this trace. Lower is "
"better.")
.def(
"getBestMarker",
&dart::biomechanics::MarkerTrace::getBestMarker,
"This finds the best body to pair this trace with (using the stats "
"from computeBodyMarkerStats()) and returns the best marker")
.def(
"overlap",
&dart::biomechanics::MarkerTrace::overlap,
::py::arg("toAppend"),
"Returns true if these traces overlap in time")
.def(
"concat",
&dart::biomechanics::MarkerTrace::concat,
::py::arg("toAppend"),
"This merges two MarkerTrace's together, to create a new trace "
"object")
.def(
"firstTimestep",
&dart::biomechanics::MarkerTrace::firstTimestep,
"This returns when this MarkerTrace begins (inclusive)")
.def(
"lastTimestep",
&dart::biomechanics::MarkerTrace::lastTimestep,
"This returns when this MarkerTrace ends (inclusive)")
.def_readonly("minTime", &dart::biomechanics::MarkerTrace::mMinTime)
.def_readonly("maxTime", &dart::biomechanics::MarkerTrace::mMaxTime)
.def_readonly("times", &dart::biomechanics::MarkerTrace::mTimes)
Expand Down
74 changes: 74 additions & 0 deletions python/_nimblephysics/utils/AccelerationMinimizer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Copyright (c) 2011-2019, The DART development contributors
* All rights reserved.
*
* The list of contributors can be found at:
* https://github.com/dartsim/dart/blob/master/LICENSE
*
* This file is provided under the following "BSD-style" License:
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

#include <dart/utils/AccelerationMinimizer.hpp>
#include <pybind11/eigen.h>
#include <pybind11/pybind11.h>

namespace py = pybind11;

namespace dart {
namespace python {

void AccelerationMinimizer(py::module& m)
{
::py::class_<dart::utils::AccelerationMinimizer>(m, "AccelerationMinimizer")
.def(
::py::init<int, s_t, s_t, s_t, s_t, s_t, s_t, int>(),
::py::arg("numTimesteps"),
::py::arg("smoothingWeight") = 1.0,
::py::arg("regularizationWeight") = 0.01,
::py::arg("startPositionZeroWeight") = 0.0,
::py::arg("endPositionZeroWeight") = 0.0,
::py::arg("startVelocityZeroWeight") = 0.0,
::py::arg("endVelocityZeroWeight") = 0.0,
::py::arg("numIterations") = 10000)
.def(
"minimize",
&dart::utils::AccelerationMinimizer::minimize,
::py::arg("series"))
.def(
"setDebugIterationBackoff",
&dart::utils::AccelerationMinimizer::setDebugIterationBackoff,
::py::arg("iterations"))
.def(
"setNumIterationsBackoff",
&dart::utils::AccelerationMinimizer::setNumIterationsBackoff,
::py::arg("series"))
.def(
"setConvergenceTolerance",
&dart::utils::AccelerationMinimizer::setConvergenceTolerance,
::py::arg("tolerance"));
}

} // namespace python
} // namespace dart
2 changes: 2 additions & 0 deletions python/_nimblephysics/utils/module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ void StringUtils(py::module& sm);
void MJCFExporter(py::module& sm);
void UniversalLoader(py::module& sm);
void AccelerationSmoother(py::module& sm);
void AccelerationMinimizer(py::module& sm);

void dart_utils(py::module& m)
{
Expand All @@ -56,6 +57,7 @@ void dart_utils(py::module& m)
MJCFExporter(sm);
UniversalLoader(sm);
AccelerationSmoother(sm);
AccelerationMinimizer(sm);
}

} // namespace python
Expand Down
2 changes: 1 addition & 1 deletion python/nimblephysics.egg-info/PKG-INFO
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: nimblephysics
Version: 0.10.42.1
Version: 0.10.45
Summary: A differentiable fully featured physics engine
Author: Keenon Werling
Author-email: keenonwerling@gmail.com
Expand Down
Loading

0 comments on commit b95d2d3

Please sign in to comment.