[wpiutil] Add Drake and Drake JNI (#2613)

Drake is a collection of tools for analyzing robot dynamics and building control systems.
See https://drake.mit.edu/ for details.

Co-authored-by: Tyler Veness <calcmogul@gmail.com>
This commit is contained in:
Matt
2020-07-24 08:34:30 -07:00
committed by GitHub
parent 0c18abed33
commit e759dad019
39 changed files with 4387 additions and 3 deletions

View File

@@ -22,6 +22,7 @@ repoRootNameOverride {
includeOtherLibs {
^cameraserver/
^cscore
^drake/
^hal/
^imgui
^mockdata/

View File

@@ -45,6 +45,8 @@ Team 254 Library wpilibj/src/main/java/edu/wpi/first/wpilibj/spline/SplineP
wpilibc/src/main/native/include/trajectory/TrajectoryParameterizer.h
wpilibc/src/main/native/cpp/trajectory/TrajectoryParameterizer.cpp
Portable File Dialogs simulation/halsim_gui/src/main/native/include/portable-file-dialogs.h
Drake wpiutil/src/main/native/cpp/drake/drake_assert_and_throw.cpp
wpiutil/src/main/native/cpp/drake/discrete_algebraic_riccati_equation.cpp
==============================================================================
@@ -807,3 +809,38 @@ 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.
=============
Drake Library
=============
All components of Drake are licensed under the BSD 3-Clause License
shown below. Where noted in the source code, some portions may
be subject to other permissive, non-viral licenses.
Copyright 2012-2016 Robot Locomotion Group @ CSAIL
All rights reserved.
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. Neither the name of
the Massachusetts Institute of Technology nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
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.

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */

View File

@@ -9,9 +9,11 @@ cppSrcFileInclude {
}
generatedFileExclude {
src/main/native/cpp/drake/
src/main/native/cpp/http_parser\.cpp$
src/main/native/cpp/llvm/
src/main/native/eigeninclude/
src/main/native/include/drake/
src/main/native/include/llvm/
src/main/native/include/units/base\.h$
src/main/native/include/units/units\.h$
@@ -72,6 +74,8 @@ generatedFileExclude {
src/main/native/resources/
src/test/native/cpp/UnitsTest\.cpp$
src/test/native/cpp/llvm/
src/test/native/cpp/drake/
src/test/native/include/drake/
src/main/native/windows/StackWalker
}

View File

@@ -5,7 +5,7 @@ include(GenResources)
include(CompileWarnings)
include(AddTest)
file(GLOB wpiutil_jni_src src/main/native/cpp/jni/WPIUtilJNI.cpp)
file(GLOB wpiutil_jni_src src/main/native/cpp/jni/DrakeJNI.cpp src/main/native/cpp/jni/WPIUtilJNI.cpp)
# Java bindings
if (NOT WITHOUT_JAVA)
@@ -175,7 +175,7 @@ set_property(TARGET wpiutil PROPERTY FOLDER "libraries")
target_compile_features(wpiutil PUBLIC cxx_std_17)
if (MSVC)
target_compile_options(wpiutil PUBLIC /permissive- /Zc:throwingNew /MP)
target_compile_options(wpiutil PUBLIC /permissive- /Zc:throwingNew /MP /bigobj)
target_compile_definitions(wpiutil PRIVATE -D_CRT_SECURE_NO_WARNINGS)
endif()
wpilib_target_warnings(wpiutil)
@@ -277,5 +277,6 @@ set_property(TARGET netconsoleTee PROPERTY FOLDER "examples")
if (WITH_TESTS)
wpilib_add_test(wpiutil src/test/native/cpp)
target_include_directories(wpiutil_test PRIVATE src/test/native/include)
target_link_libraries(wpiutil_test wpiutil ${LIBUTIL} gmock_main)
endif()

View File

@@ -0,0 +1,56 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpiutil.math;
import org.ejml.simple.SimpleMatrix;
public final class Drake {
private Drake() {
}
/**
* Solves the discrete alegebraic Riccati equation.
*
* @param A System matrix.
* @param B Input matrix.
* @param Q State cost matrix.
* @param R Input cost matrix.
* @return Solution of DARE.
*/
@SuppressWarnings({"LocalVariableName", "ParameterName"})
public static SimpleMatrix discreteAlgebraicRiccatiEquation(
SimpleMatrix A,
SimpleMatrix B,
SimpleMatrix Q,
SimpleMatrix R) {
var S = new SimpleMatrix(A.numRows(), A.numCols());
DrakeJNI.discreteAlgebraicRiccatiEquation(A.getDDRM().getData(), B.getDDRM().getData(),
Q.getDDRM().getData(), R.getDDRM().getData(), A.numCols(), B.numCols(),
S.getDDRM().getData());
return S;
}
/**
* Solves the discrete alegebraic Riccati equation.
*
* @param A System matrix.
* @param B Input matrix.
* @param Q State cost matrix.
* @param R Input cost matrix.
* @return Solution of DARE.
*/
@SuppressWarnings("ParameterName")
public static SimpleMatrix discreteAlgebraicRiccatiEquation(
Matrix A,
Matrix B,
Matrix Q,
Matrix R) {
return discreteAlgebraicRiccatiEquation(A.getStorage(), B.getStorage(), Q.getStorage(),
R.getStorage());
}
}

View File

@@ -0,0 +1,79 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpiutil.math;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicBoolean;
import edu.wpi.first.wpiutil.RuntimeLoader;
public final class DrakeJNI {
static boolean libraryLoaded = false;
static RuntimeLoader<DrakeJNI> loader = null;
static {
if (Helper.getExtractOnStaticLoad()) {
try {
loader = new RuntimeLoader<>("wpiutiljni", RuntimeLoader.getDefaultExtractionRoot(),
DrakeJNI.class);
loader.loadLibrary();
} catch (IOException ex) {
ex.printStackTrace();
System.exit(1);
}
libraryLoaded = true;
}
}
/**
* Force load the library.
*
* @throws IOException If the library could not be loaded or found.
*/
public static synchronized void forceLoad() throws IOException {
if (libraryLoaded) {
return;
}
loader = new RuntimeLoader<>("wpiutiljni", RuntimeLoader.getDefaultExtractionRoot(),
DrakeJNI.class);
loader.loadLibrary();
libraryLoaded = true;
}
/**
* Solves the discrete alegebraic Riccati equation.
*
* @param A Array containing elements of A in row-major order.
* @param B Array containing elements of B in row-major order.
* @param Q Array containing elements of Q in row-major order.
* @param R Array containing elements of R in row-major order.
* @param states Number of states in A matrix.
* @param inputs Number of inputs in B matrix.
* @param S Array storage for DARE solution.
*/
public static native void discreteAlgebraicRiccatiEquation(
double[] A,
double[] B,
double[] Q,
double[] R,
int states,
int inputs,
double[] S);
public static class Helper {
private static AtomicBoolean extractOnStaticLoad = new AtomicBoolean(true);
public static boolean getExtractOnStaticLoad() {
return extractOnStaticLoad.get();
}
public static void setExtractOnStaticLoad(boolean load) {
extractOnStaticLoad.set(load);
}
}
}

View File

@@ -0,0 +1,87 @@
// This file contains the implementation of both drake_assert and drake_throw.
/* clang-format off to disable clang-format-includes */
#include "drake/common/drake_assert.h"
#include "drake/common/drake_throw.h"
/* clang-format on */
#include <atomic>
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <string>
#include "drake/common/drake_assertion_error.h"
#include "drake/common/never_destroyed.h"
namespace drake {
namespace internal {
namespace {
// Singleton to manage assertion configuration.
struct AssertionConfig {
static AssertionConfig& singleton() {
static never_destroyed<AssertionConfig> global;
return global.access();
}
std::atomic<bool> assertion_failures_are_exceptions;
};
// Stream into @p out the given failure details; only @p condition may be null.
void PrintFailureDetailTo(std::ostream& out, const char* condition,
const char* func, const char* file, int line) {
out << "Failure at " << file << ":" << line << " in " << func << "()";
if (condition) {
out << ": condition '" << condition << "' failed.";
} else {
out << ".";
}
}
} // namespace
// Declared in drake_assert.h.
void Abort(const char* condition, const char* func, const char* file,
int line) {
std::cerr << "abort: ";
PrintFailureDetailTo(std::cerr, condition, func, file, line);
std::cerr << std::endl;
std::abort();
}
// Declared in drake_throw.h.
void Throw(const char* condition, const char* func, const char* file,
int line) {
std::ostringstream what;
PrintFailureDetailTo(what, condition, func, file, line);
throw assertion_error(what.str().c_str());
}
// Declared in drake_assert.h.
void AssertionFailed(const char* condition, const char* func, const char* file,
int line) {
if (AssertionConfig::singleton().assertion_failures_are_exceptions) {
Throw(condition, func, file, line);
} else {
Abort(condition, func, file, line);
}
}
} // namespace internal
} // namespace drake
// Configures the DRAKE_ASSERT and DRAKE_DEMAND assertion failure handling
// behavior.
//
// By default, assertion failures will result in an ::abort(). If this method
// has ever been called, failures will result in a thrown exception instead.
//
// Assertion configuration has process-wide scope. Changes here will affect
// all assertions within the current process.
//
// This method is intended ONLY for use by pydrake bindings, and thus is not
// declared in any header file, to discourage anyone from using it.
extern "C" void drake_set_assertion_failure_to_throw_exception() {
drake::internal::AssertionConfig::singleton().
assertion_failures_are_exceptions = true;
}

View File

@@ -0,0 +1,463 @@
#include "drake/math/discrete_algebraic_riccati_equation.h"
#include "drake/common/drake_assert.h"
#include "drake/common/drake_throw.h"
#include "drake/common/is_approx_equal_abstol.h"
#include <Eigen/Eigenvalues>
#include <Eigen/QR>
// This code has https://github.com/RobotLocomotion/drake/pull/11118 applied to
// fix an infinite loop in reorder_eigen().
namespace drake {
namespace math {
namespace {
/* helper functions */
template <typename T>
int sgn(T val) {
return (T(0) < val) - (val < T(0));
}
void check_stabilizable(const Eigen::Ref<const Eigen::MatrixXd>& A,
const Eigen::Ref<const Eigen::MatrixXd>& B) {
// This function checks if (A,B) is a stabilizable pair.
// (A,B) is stabilizable if and only if the uncontrollable eigenvalues of
// A, if any, have absolute values less than one, where an eigenvalue is
// uncontrollable if Rank[lambda * I - A, B] < n.
int n = B.rows(), m = B.cols();
Eigen::EigenSolver<Eigen::MatrixXd> es(A);
for (int i = 0; i < n; i++) {
if (es.eigenvalues()[i].real() * es.eigenvalues()[i].real() +
es.eigenvalues()[i].imag() * es.eigenvalues()[i].imag() <
1)
continue;
Eigen::MatrixXcd E(n, n + m);
E << es.eigenvalues()[i] * Eigen::MatrixXcd::Identity(n, n) - A, B;
Eigen::ColPivHouseholderQR<Eigen::MatrixXcd> qr(E);
DRAKE_THROW_UNLESS(qr.rank() == n);
}
}
void check_detectable(const Eigen::Ref<const Eigen::MatrixXd>& A,
const Eigen::Ref<const Eigen::MatrixXd>& Q) {
// This function check if (A,C) is a detectable pair, where Q = C' * C.
// (A,C) is detectable if and only if the unobservable eigenvalues of A,
// if any, have absolute values less than one, where an eigenvalue is
// unobservable if Rank[lambda * I - A; C] < n.
// Also, (A,C) is detectable if and only if (A',C') is stabilizable.
int n = A.rows();
Eigen::LDLT<Eigen::MatrixXd> ldlt(Q);
Eigen::MatrixXd L = ldlt.matrixL();
Eigen::MatrixXd D = ldlt.vectorD();
Eigen::MatrixXd D_sqrt = Eigen::MatrixXd::Zero(n, n);
for (int i = 0; i < n; i++) {
D_sqrt(i, i) = sqrt(D(i));
}
Eigen::MatrixXd C = L * D_sqrt;
check_stabilizable(A.transpose(), C.transpose());
}
// "Givens rotation" computes an orthogonal 2x2 matrix R such that
// it eliminates the 2nd coordinate of the vector [a,b]', i.e.,
// R * [ a ] = [ a_hat ]
// [ b ] [ 0 ]
// The implementation is based on
// https://en.wikipedia.org/wiki/Givens_rotation#Stable_calculation
void Givens_rotation(double a, double b, Eigen::Ref<Eigen::Matrix2d> R,
double eps = 1e-10) {
double c, s;
if (fabs(b) < eps) {
c = (a < -eps ? -1 : 1);
s = 0;
} else if (fabs(a) < eps) {
c = 0;
s = -sgn(b);
} else if (fabs(a) > fabs(b)) {
double t = b / a;
double u = sgn(a) * fabs(sqrt(1 + t * t));
c = 1 / u;
s = -c * t;
} else {
double t = a / b;
double u = sgn(b) * fabs(sqrt(1 + t * t));
s = -1 / u;
c = -s * t;
}
R(0, 0) = c, R(0, 1) = -s, R(1, 0) = s, R(1, 1) = c;
}
// The arguments S, T, and Z will be changed.
void swap_block_11(Eigen::Ref<Eigen::MatrixXd> S, Eigen::Ref<Eigen::MatrixXd> T,
Eigen::Ref<Eigen::MatrixXd> Z, int p) {
// Dooren, Case I, p124-125.
int n2 = S.rows();
Eigen::Matrix2d A = S.block<2, 2>(p, p);
Eigen::Matrix2d B = T.block<2, 2>(p, p);
Eigen::MatrixXd Z1 = Eigen::MatrixXd::Identity(n2, n2);
Eigen::Matrix2d H = A(1, 1) * B - B(1, 1) * A;
Givens_rotation(H(0, 1), H(0, 0), Z1.block<2, 2>(p, p));
S = (S * Z1).eval();
T = (T * Z1).eval();
Z = (Z * Z1).eval();
Eigen::MatrixXd Q = Eigen::MatrixXd::Identity(n2, n2);
Givens_rotation(T(p, p), T(p + 1, p), Q.block<2, 2>(p, p));
S = (Q * S).eval();
T = (Q * T).eval();
S(p + 1, p) = 0;
T(p + 1, p) = 0;
}
// The arguments S, T, and Z will be changed.
void swap_block_21(Eigen::Ref<Eigen::MatrixXd> S, Eigen::Ref<Eigen::MatrixXd> T,
Eigen::Ref<Eigen::MatrixXd> Z, int p) {
// Dooren, Case II, p126-127.
int n2 = S.rows();
Eigen::Matrix3d A = S.block<3, 3>(p, p);
Eigen::Matrix3d B = T.block<3, 3>(p, p);
// Compute H and eliminate H(1,0) by row operation.
Eigen::Matrix3d H = A(2, 2) * B - B(2, 2) * A;
Eigen::Matrix3d R = Eigen::MatrixXd::Identity(3, 3);
Givens_rotation(H(0, 0), H(1, 0), R.block<2, 2>(0, 0));
H = (R * H).eval();
Eigen::MatrixXd Z1 = Eigen::MatrixXd::Identity(n2, n2);
Eigen::MatrixXd Z2 = Eigen::MatrixXd::Identity(n2, n2);
Eigen::MatrixXd Q1 = Eigen::MatrixXd::Identity(n2, n2);
Eigen::MatrixXd Q2 = Eigen::MatrixXd::Identity(n2, n2);
// Compute Z1, Z2, Q1, Q2.
Givens_rotation(H(1, 2), H(1, 1), Z1.block<2, 2>(p + 1, p + 1));
H = (H * Z1.block<3, 3>(p, p)).eval();
Givens_rotation(H(0, 1), H(0, 0), Z2.block<2, 2>(p, p));
S = (S * Z1).eval();
T = (T * Z1).eval();
Z = (Z * Z1 * Z2).eval();
Givens_rotation(T(p + 1, p + 1), T(p + 2, p + 1),
Q1.block<2, 2>(p + 1, p + 1));
S = (Q1 * S * Z2).eval();
T = (Q1 * T * Z2).eval();
Givens_rotation(T(p, p), T(p + 1, p), Q2.block<2, 2>(p, p));
S = (Q2 * S).eval();
T = (Q2 * T).eval();
S(p + 1, p) = 0;
S(p + 2, p) = 0;
T(p + 1, p) = 0;
T(p + 2, p) = 0;
T(p + 2, p + 1) = 0;
}
// The arguments S, T, and Z will be changed.
void swap_block_12(Eigen::Ref<Eigen::MatrixXd> S, Eigen::Ref<Eigen::MatrixXd> T,
Eigen::Ref<Eigen::MatrixXd> Z, int p) {
int n2 = S.rows();
// Swap the role of S and T.
Eigen::MatrixXd Z1 = Eigen::MatrixXd::Identity(n2, n2);
Eigen::MatrixXd Z2 = Eigen::MatrixXd::Identity(n2, n2);
Eigen::MatrixXd Q0 = Eigen::MatrixXd::Identity(n2, n2);
Eigen::MatrixXd Q1 = Eigen::MatrixXd::Identity(n2, n2);
Eigen::MatrixXd Q2 = Eigen::MatrixXd::Identity(n2, n2);
Eigen::MatrixXd Q3 = Eigen::MatrixXd::Identity(n2, n2);
Givens_rotation(S(p + 1, p + 1), S(p + 2, p + 1),
Q0.block<2, 2>(p + 1, p + 1));
S = (Q0 * S).eval();
T = (Q0 * T).eval();
Eigen::Matrix3d A = S.block<3, 3>(p, p);
Eigen::Matrix3d B = T.block<3, 3>(p, p);
// Compute H and eliminate H(2,1) by column operation.
Eigen::Matrix3d H = B(0, 0) * A - A(0, 0) * B;
Eigen::Matrix3d R = Eigen::MatrixXd::Identity(3, 3);
Givens_rotation(H(2, 2), H(2, 1), R.block<2, 2>(1, 1));
H = (H * R).eval();
// Compute Q1, Q2, Z1, Z2.
Givens_rotation(H(0, 1), H(1, 1), Q1.block<2, 2>(p, p));
H = (Q1.block<3, 3>(p, p) * H).eval();
Givens_rotation(H(1, 2), H(2, 2), Q2.block<2, 2>(p + 1, p + 1));
S = (Q1 * S).eval();
T = (Q1 * T).eval();
Givens_rotation(S(p + 1, p + 1), S(p + 1, p), Z1.block<2, 2>(p, p));
S = (Q2 * S * Z1).eval();
T = (Q2 * T * Z1).eval();
Givens_rotation(S(p + 2, p + 2), S(p + 2, p + 1),
Z2.block<2, 2>(p + 1, p + 1));
S = (S * Z2).eval();
T = (T * Z2).eval();
Z = (Z * Z1 * Z2).eval();
// Swap back the role of S and T.
Givens_rotation(T(p, p), T(p + 1, p), Q3.block<2, 2>(p, p));
S = (Q3 * S).eval();
T = (Q3 * T).eval();
S(p + 2, p) = 0;
S(p + 2, p + 1) = 0;
T(p + 1, p) = 0;
T(p + 2, p) = 0;
T(p + 2, p + 1) = 0;
}
// The arguments S, T, and Z will be changed.
void swap_block_22(Eigen::Ref<Eigen::MatrixXd> S, Eigen::Ref<Eigen::MatrixXd> T,
Eigen::Ref<Eigen::MatrixXd> Z, int p) {
// Direct Swapping Algorithm based on
// "Numerical Methods for General and Structured Eigenvalue Problems" by
// Daniel Kressner, p108-111.
// ( http://sma.epfl.ch/~anchpcommon/publications/kressner_eigenvalues.pdf ).
// Also relevant but not applicable here:
// "On Swapping Diagonal Blocks in Real Schur Form" by Zhaojun Bai and James
// W. Demmelt;
int n2 = S.rows();
Eigen::MatrixXd A = S.block<4, 4>(p, p);
Eigen::MatrixXd B = T.block<4, 4>(p, p);
// Solve
// A11 * X - Y A22 = A12
// B11 * X - Y B22 = B12
// Reduce to solve Cx=D, where x=[x1;...;x4;y1;...;y4].
Eigen::Matrix<double, 8, 8> C = Eigen::Matrix<double, 8, 8>::Zero();
Eigen::Matrix<double, 8, 1> D;
// clang-format off
C << A(0, 0), 0, A(0, 1), 0, -A(2, 2), -A(3, 2), 0, 0,
0, A(0, 0), 0, A(0, 1), -A(2, 3), -A(3, 3), 0, 0,
A(1, 0), 0, A(1, 1), 0, 0, 0, -A(2, 2), -A(3, 2),
0, A(1, 0), 0, A(1, 1), 0, 0, -A(2, 3), -A(3, 3),
B(0, 0), 0, B(0, 1), 0, -B(2, 2), -B(3, 2), 0, 0,
0, B(0, 0), 0, B(0, 1), -B(2, 3), -B(3, 3), 0, 0,
B(1, 0), 0, B(1, 1), 0, 0, 0, -B(2, 2), -B(3, 2),
0, B(1, 0), 0, B(1, 1), 0, 0, -B(2, 3), -B(3, 3);
// clang-format on
D << A(0, 2), A(0, 3), A(1, 2), A(1, 3), B(0, 2), B(0, 3), B(1, 2), B(1, 3);
Eigen::MatrixXd x = C.colPivHouseholderQr().solve(D);
// Q * [ -Y ] = [ R_Y ] , Z' * [ -X ] = [ R_X ] .
// [ I ] [ 0 ] [ I ] = [ 0 ]
Eigen::Matrix<double, 4, 2> X, Y;
X << -x(0, 0), -x(1, 0), -x(2, 0), -x(3, 0), Eigen::Matrix2d::Identity();
Y << -x(4, 0), -x(5, 0), -x(6, 0), -x(7, 0), Eigen::Matrix2d::Identity();
Eigen::MatrixXd Q1 = Eigen::MatrixXd::Identity(n2, n2);
Eigen::MatrixXd Z1 = Eigen::MatrixXd::Identity(n2, n2);
Eigen::ColPivHouseholderQR<Eigen::Matrix<double, 4, 2> > qr1(X);
Z1.block<4, 4>(p, p) = qr1.householderQ();
Eigen::ColPivHouseholderQR<Eigen::Matrix<double, 4, 2> > qr2(Y);
Q1.block<4, 4>(p, p) = qr2.householderQ().adjoint();
// Apply transform Q1 * (S,T) * Z1.
S = (Q1 * S * Z1).eval();
T = (Q1 * T * Z1).eval();
Z = (Z * Z1).eval();
// Eliminate the T(p+3,p+2) entry.
Eigen::MatrixXd Q2 = Eigen::MatrixXd::Identity(n2, n2);
Givens_rotation(T(p + 2, p + 2), T(p + 3, p + 2),
Q2.block<2, 2>(p + 2, p + 2));
S = (Q2 * S).eval();
T = (Q2 * T).eval();
// Eliminate the T(p+1,p) entry.
Eigen::MatrixXd Q3 = Eigen::MatrixXd::Identity(n2, n2);
Givens_rotation(T(p, p), T(p + 1, p), Q3.block<2, 2>(p, p));
S = (Q3 * S).eval();
T = (Q3 * T).eval();
S(p + 2, p) = 0;
S(p + 2, p + 1) = 0;
S(p + 3, p) = 0;
S(p + 3, p + 1) = 0;
T(p + 1, p) = 0;
T(p + 2, p) = 0;
T(p + 2, p + 1) = 0;
T(p + 3, p) = 0;
T(p + 3, p + 1) = 0;
T(p + 3, p + 2) = 0;
}
// Functionality of "swap_block" function:
// swap the 1x1 or 2x2 blocks pointed by p and q.
// There are four cases: swapping 1x1 and 1x1 matrices, swapping 2x2 and 1x1
// matrices, swapping 1x1 and 2x2 matrices, and swapping 2x2 and 2x2 matrices.
// Algorithms are described in the papers
// "A generalized eigenvalue approach for solving Riccati equations" by P. Van
// Dooren, 1981 ( http://epubs.siam.org/doi/pdf/10.1137/0902010 ), and
// "Numerical Methods for General and Structured Eigenvalue Problems" by
// Daniel Kressner, 2005.
void swap_block(Eigen::Ref<Eigen::MatrixXd> S, Eigen::Ref<Eigen::MatrixXd> T,
Eigen::Ref<Eigen::MatrixXd> Z, int p, int q, int q_block_size,
double eps = 1e-10) {
int p_tmp = q, p_block_size;
while (p_tmp-- > p) {
p_block_size = 1;
if (p_tmp >= 1 && fabs(S(p_tmp, p_tmp - 1)) > eps) {
p_block_size = 2;
p_tmp--;
}
switch (p_block_size * 10 + q_block_size) {
case 11:
swap_block_11(S, T, Z, p_tmp);
break;
case 21:
swap_block_21(S, T, Z, p_tmp);
break;
case 12:
swap_block_12(S, T, Z, p_tmp);
break;
case 22:
swap_block_22(S, T, Z, p_tmp);
break;
}
}
}
// Functionality of "reorder_eigen" function:
// Reorder the eigenvalues of (S,T) such that the top-left n by n matrix has
// stable eigenvalues by multiplying Q's and Z's on the left and the right,
// respectively.
// Stable eigenvalues are inside the unit disk.
//
// Algorithm:
// Go along the diagonals of (S,T) from the top left to the bottom right.
// Once find a stable eigenvalue, push it to top left.
// In implementation, use two pointers, p and q.
// p points to the current block (1x1 or 2x2) and q points to the block with the
// stable eigenvalue(s).
// Push the block pointed by q to the position pointed by p.
// Finish when n stable eigenvalues are placed at the top-left n by n matrix.
// The algorithm for swapping blocks is described in the papers
// "A generalized eigenvalue approach for solving Riccati equations" by P. Van
// Dooren, 1981, and "Numerical Methods for General and Structured Eigenvalue
// Problems" by Daniel Kressner, 2005.
void reorder_eigen(Eigen::Ref<Eigen::MatrixXd> S, Eigen::Ref<Eigen::MatrixXd> T,
Eigen::Ref<Eigen::MatrixXd> Z, double eps = 1e-10) {
// abs(a) < eps => a = 0
int n2 = S.rows();
int n = n2 / 2, p = 0, q = 0;
// Find the first unstable p block.
while (p < n) {
if (fabs(S(p + 1, p)) < eps) { // p block size = 1
if (fabs(T(p, p)) > eps && fabs(S(p, p)) <= fabs(T(p, p))) { // stable
p++;
continue;
}
} else { // p block size = 2
const double det_T =
T(p, p) * T(p + 1, p + 1) - T(p + 1, p) * T(p, p + 1);
if (fabs(det_T) > eps) {
const double det_S =
S(p, p) * S(p + 1, p + 1) - S(p + 1, p) * S(p, p + 1);
if (fabs(det_S) <= fabs(det_T)) { // stable
p += 2;
continue;
}
}
}
break;
}
q = p;
// Make the first n generalized eigenvalues stable.
while (p < n && q < n2) {
// Update q.
int q_block_size = 0;
while (q < n2) {
if (q == n2 - 1 || fabs(S(q + 1, q)) < eps) { // block size = 1
if (fabs(T(q, q)) > eps && fabs(S(q, q)) <= fabs(T(q, q))) {
q_block_size = 1;
break;
}
q++;
} else { // block size = 2
const double det_T =
T(q, q) * T(q + 1, q + 1) - T(q + 1, q) * T(q, q + 1);
if (fabs(det_T) > eps) {
const double det_S =
S(q, q) * S(q + 1, q + 1) - S(q + 1, q) * S(q, q + 1);
if (fabs(det_S) <= fabs(det_T)) {
q_block_size = 2;
break;
}
}
q += 2;
}
}
if (q >= n2)
throw std::runtime_error("fail to find enough stable eigenvalues");
// Swap blocks pointed by p and q.
if (p != q) {
swap_block(S, T, Z, p, q, q_block_size);
p += q_block_size;
q += q_block_size;
}
}
if (p < n && q >= n2)
throw std::runtime_error("fail to find enough stable eigenvalues");
}
} // namespace
/**
* DiscreteAlgebraicRiccatiEquation function
* computes the unique stabilizing solution X to the discrete-time algebraic
* Riccati equation:
* \f[
* A'XA - X - A'XB(B'XB+R)^{-1}B'XA + Q = 0
* \f]
*
* @throws std::runtime_error if Q is not positive semi-definite.
* @throws std::runtime_error if R is not positive definite.
*
* Based on the Schur Vector approach outlined in this paper:
* "On the Numerical Solution of the Discrete-Time Algebraic Riccati Equation"
* by Thrasyvoulos Pappas, Alan J. Laub, and Nils R. Sandell, in TAC, 1980,
* http://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=1102434
*
* Note: When, for example, n = 100, m = 80, and entries of A, B, Q_half,
* R_half are sampled from standard normal distributions, where
* Q = Q_half'*Q_half and similar for R, the absolute error of the solution
* is 10^{-6}, while the absolute error of the solution computed by Matlab is
* 10^{-8}.
*
* TODO(weiqiao.han): I may overwrite the RealQZ function to improve the
* accuracy, together with more thorough tests.
*/
Eigen::MatrixXd DiscreteAlgebraicRiccatiEquation(
const Eigen::Ref<const Eigen::MatrixXd>& A,
const Eigen::Ref<const Eigen::MatrixXd>& B,
const Eigen::Ref<const Eigen::MatrixXd>& Q,
const Eigen::Ref<const Eigen::MatrixXd>& R) {
int n = B.rows(), m = B.cols();
DRAKE_DEMAND(m <= n);
DRAKE_DEMAND(A.rows() == n && A.cols() == n);
DRAKE_DEMAND(Q.rows() == n && Q.cols() == n);
DRAKE_DEMAND(R.rows() == m && R.cols() == m);
DRAKE_DEMAND(is_approx_equal_abstol(Q, Q.transpose(), 1e-10));
Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> es(Q);
for (int i = 0; i < n; i++) {
DRAKE_THROW_UNLESS(es.eigenvalues()[i] >= 0);
}
DRAKE_DEMAND(is_approx_equal_abstol(R, R.transpose(), 1e-10));
Eigen::LLT<Eigen::MatrixXd> R_cholesky(R);
DRAKE_THROW_UNLESS(R_cholesky.info() == Eigen::Success);
check_stabilizable(A, B);
check_detectable(A, Q);
Eigen::MatrixXd M(2 * n, 2 * n), L(2 * n, 2 * n);
M << A, Eigen::MatrixXd::Zero(n, n), -Q, Eigen::MatrixXd::Identity(n, n);
L << Eigen::MatrixXd::Identity(n, n), B * R.inverse() * B.transpose(),
Eigen::MatrixXd::Zero(n, n), A.transpose();
// QZ decomposition of M and L
// QMZ = S, QLZ = T
// where Q and Z are real orthogonal matrixes
// T is upper-triangular matrix, and S is upper quasi-triangular matrix
Eigen::RealQZ<Eigen::MatrixXd> qz(2 * n);
qz.compute(M, L); // M = Q S Z, L = Q T Z (Q and Z computed by Eigen package
// are adjoints of Q and Z above)
Eigen::MatrixXd S = qz.matrixS(), T = qz.matrixT(),
Z = qz.matrixZ().adjoint();
// Reorder the generalized eigenvalues of (S,T).
Eigen::MatrixXd Z2 = Eigen::MatrixXd::Identity(2 * n, 2 * n);
reorder_eigen(S, T, Z2);
Z = (Z * Z2).eval();
// The first n columns of Z is ( U1 ) .
// ( U2 )
// -1
// X = U2 * U1 is a solution of the discrete time Riccati equation.
Eigen::MatrixXd U1 = Z.block(0, 0, n, n), U2 = Z.block(n, 0, n, n);
Eigen::MatrixXd X = U2 * U1.inverse();
X = (X + X.adjoint().eval()) / 2.0;
return X;
}
} // namespace math
} // namespace drake

View File

@@ -0,0 +1,62 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#include <jni.h>
#include <iostream>
#include <Eigen/Core>
#include <unsupported/Eigen/MatrixFunctions>
#include "drake/math/discrete_algebraic_riccati_equation.h"
#include "edu_wpi_first_wpiutil_math_DrakeJNI.h"
#include "wpi/jni_util.h"
using namespace wpi::java;
extern "C" {
/*
* Class: edu_wpi_first_wpiutil_math_DrakeJNI
* Method: discreteAlgebraicRiccatiEquation
* Signature: ([D[D[D[DII[D)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_wpiutil_math_DrakeJNI_discreteAlgebraicRiccatiEquation
(JNIEnv* env, jclass, jdoubleArray A, jdoubleArray B, jdoubleArray Q,
jdoubleArray R, jint states, jint inputs, jdoubleArray S)
{
jdouble* nativeA = env->GetDoubleArrayElements(A, nullptr);
jdouble* nativeB = env->GetDoubleArrayElements(B, nullptr);
jdouble* nativeQ = env->GetDoubleArrayElements(Q, nullptr);
jdouble* nativeR = env->GetDoubleArrayElements(R, nullptr);
Eigen::Map<
Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>>
Amat{nativeA, states, states};
Eigen::Map<
Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>>
Bmat{nativeB, states, inputs};
Eigen::Map<
Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>>
Qmat{nativeQ, states, states};
Eigen::Map<
Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>>
Rmat{nativeR, inputs, inputs};
Eigen::MatrixXd result =
drake::math::DiscreteAlgebraicRiccatiEquation(Amat, Bmat, Qmat, Rmat);
env->ReleaseDoubleArrayElements(A, nativeA, 0);
env->ReleaseDoubleArrayElements(B, nativeB, 0);
env->ReleaseDoubleArrayElements(Q, nativeQ, 0);
env->ReleaseDoubleArrayElements(R, nativeR, 0);
env->SetDoubleArrayRegion(S, 0, states * states, result.data());
}
} // extern "C"

View File

@@ -0,0 +1,40 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008-2009 Gael Guennebaud <g.gael@free.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_AUTODIFF_MODULE
#define EIGEN_AUTODIFF_MODULE
namespace Eigen {
/**
* \defgroup AutoDiff_Module Auto Diff module
*
* This module features forward automatic differentation via a simple
* templated scalar type wrapper AutoDiffScalar.
*
* Warning : this should NOT be confused with numerical differentiation, which
* is a different method and has its own module in Eigen : \ref NumericalDiff_Module.
*
* \code
* #include <unsupported/Eigen/AutoDiff>
* \endcode
*/
//@{
}
#include "src/AutoDiff/AutoDiffScalar.h"
// #include "src/AutoDiff/AutoDiffVector.h"
#include "src/AutoDiff/AutoDiffJacobian.h"
namespace Eigen {
//@}
}
#endif // EIGEN_AUTODIFF_MODULE

View File

@@ -0,0 +1,108 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_AUTODIFF_JACOBIAN_H
#define EIGEN_AUTODIFF_JACOBIAN_H
namespace Eigen
{
template<typename Functor> class AutoDiffJacobian : public Functor
{
public:
AutoDiffJacobian() : Functor() {}
AutoDiffJacobian(const Functor& f) : Functor(f) {}
// forward constructors
#if EIGEN_HAS_VARIADIC_TEMPLATES
template<typename... T>
AutoDiffJacobian(const T& ...Values) : Functor(Values...) {}
#else
template<typename T0>
AutoDiffJacobian(const T0& a0) : Functor(a0) {}
template<typename T0, typename T1>
AutoDiffJacobian(const T0& a0, const T1& a1) : Functor(a0, a1) {}
template<typename T0, typename T1, typename T2>
AutoDiffJacobian(const T0& a0, const T1& a1, const T2& a2) : Functor(a0, a1, a2) {}
#endif
typedef typename Functor::InputType InputType;
typedef typename Functor::ValueType ValueType;
typedef typename ValueType::Scalar Scalar;
enum {
InputsAtCompileTime = InputType::RowsAtCompileTime,
ValuesAtCompileTime = ValueType::RowsAtCompileTime
};
typedef Matrix<Scalar, ValuesAtCompileTime, InputsAtCompileTime> JacobianType;
typedef typename JacobianType::Index Index;
typedef Matrix<Scalar, InputsAtCompileTime, 1> DerivativeType;
typedef AutoDiffScalar<DerivativeType> ActiveScalar;
typedef Matrix<ActiveScalar, InputsAtCompileTime, 1> ActiveInput;
typedef Matrix<ActiveScalar, ValuesAtCompileTime, 1> ActiveValue;
#if EIGEN_HAS_VARIADIC_TEMPLATES
// Some compilers don't accept variadic parameters after a default parameter,
// i.e., we can't just write _jac=0 but we need to overload operator():
EIGEN_STRONG_INLINE
void operator() (const InputType& x, ValueType* v) const
{
this->operator()(x, v, 0);
}
template<typename... ParamsType>
void operator() (const InputType& x, ValueType* v, JacobianType* _jac,
const ParamsType&... Params) const
#else
void operator() (const InputType& x, ValueType* v, JacobianType* _jac=0) const
#endif
{
eigen_assert(v!=0);
if (!_jac)
{
#if EIGEN_HAS_VARIADIC_TEMPLATES
Functor::operator()(x, v, Params...);
#else
Functor::operator()(x, v);
#endif
return;
}
JacobianType& jac = *_jac;
ActiveInput ax = x.template cast<ActiveScalar>();
ActiveValue av(jac.rows());
if(InputsAtCompileTime==Dynamic)
for (Index j=0; j<jac.rows(); j++)
av[j].derivatives().resize(x.rows());
for (Index i=0; i<jac.cols(); i++)
ax[i].derivatives() = DerivativeType::Unit(x.rows(),i);
#if EIGEN_HAS_VARIADIC_TEMPLATES
Functor::operator()(ax, &av, Params...);
#else
Functor::operator()(ax, &av);
#endif
for (Index i=0; i<jac.rows(); i++)
{
(*v)[i] = av[i].value();
jac.row(i) = av[i].derivatives();
}
}
};
}
#endif // EIGEN_AUTODIFF_JACOBIAN_H

View File

@@ -0,0 +1,694 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_AUTODIFF_SCALAR_H
#define EIGEN_AUTODIFF_SCALAR_H
namespace Eigen {
namespace internal {
template<typename A, typename B>
struct make_coherent_impl {
static void run(A&, B&) {}
};
// resize a to match b is a.size()==0, and conversely.
template<typename A, typename B>
void make_coherent(const A& a, const B&b)
{
make_coherent_impl<A,B>::run(a.const_cast_derived(), b.const_cast_derived());
}
template<typename _DerType, bool Enable> struct auto_diff_special_op;
} // end namespace internal
template<typename _DerType> class AutoDiffScalar;
template<typename NewDerType>
inline AutoDiffScalar<NewDerType> MakeAutoDiffScalar(const typename NewDerType::Scalar& value, const NewDerType &der) {
return AutoDiffScalar<NewDerType>(value,der);
}
/** \class AutoDiffScalar
* \brief A scalar type replacement with automatic differentation capability
*
* \param _DerType the vector type used to store/represent the derivatives. The base scalar type
* as well as the number of derivatives to compute are determined from this type.
* Typical choices include, e.g., \c Vector4f for 4 derivatives, or \c VectorXf
* if the number of derivatives is not known at compile time, and/or, the number
* of derivatives is large.
* Note that _DerType can also be a reference (e.g., \c VectorXf&) to wrap a
* existing vector into an AutoDiffScalar.
* Finally, _DerType can also be any Eigen compatible expression.
*
* This class represents a scalar value while tracking its respective derivatives using Eigen's expression
* template mechanism.
*
* It supports the following list of global math function:
* - std::abs, std::sqrt, std::pow, std::exp, std::log, std::sin, std::cos,
* - internal::abs, internal::sqrt, numext::pow, internal::exp, internal::log, internal::sin, internal::cos,
* - internal::conj, internal::real, internal::imag, numext::abs2.
*
* AutoDiffScalar can be used as the scalar type of an Eigen::Matrix object. However,
* in that case, the expression template mechanism only occurs at the top Matrix level,
* while derivatives are computed right away.
*
*/
template<typename _DerType>
class AutoDiffScalar
: public internal::auto_diff_special_op
<_DerType, !internal::is_same<typename internal::traits<typename internal::remove_all<_DerType>::type>::Scalar,
typename NumTraits<typename internal::traits<typename internal::remove_all<_DerType>::type>::Scalar>::Real>::value>
{
public:
typedef internal::auto_diff_special_op
<_DerType, !internal::is_same<typename internal::traits<typename internal::remove_all<_DerType>::type>::Scalar,
typename NumTraits<typename internal::traits<typename internal::remove_all<_DerType>::type>::Scalar>::Real>::value> Base;
typedef typename internal::remove_all<_DerType>::type DerType;
typedef typename internal::traits<DerType>::Scalar Scalar;
typedef typename NumTraits<Scalar>::Real Real;
using Base::operator+;
using Base::operator*;
/** Default constructor without any initialization. */
AutoDiffScalar() {}
/** Constructs an active scalar from its \a value,
and initializes the \a nbDer derivatives such that it corresponds to the \a derNumber -th variable */
AutoDiffScalar(const Scalar& value, int nbDer, int derNumber)
: m_value(value), m_derivatives(DerType::Zero(nbDer))
{
m_derivatives.coeffRef(derNumber) = Scalar(1);
}
/** Conversion from a scalar constant to an active scalar.
* The derivatives are set to zero. */
/*explicit*/ AutoDiffScalar(const Real& value)
: m_value(value)
{
if(m_derivatives.size()>0)
m_derivatives.setZero();
}
/** Constructs an active scalar from its \a value and derivatives \a der */
AutoDiffScalar(const Scalar& value, const DerType& der)
: m_value(value), m_derivatives(der)
{}
template<typename OtherDerType>
AutoDiffScalar(const AutoDiffScalar<OtherDerType>& other
#ifndef EIGEN_PARSED_BY_DOXYGEN
, typename internal::enable_if<
internal::is_same<Scalar, typename internal::traits<typename internal::remove_all<OtherDerType>::type>::Scalar>::value
&& internal::is_convertible<OtherDerType,DerType>::value , void*>::type = 0
#endif
)
: m_value(other.value()), m_derivatives(other.derivatives())
{}
friend std::ostream & operator << (std::ostream & s, const AutoDiffScalar& a)
{
return s << a.value();
}
AutoDiffScalar(const AutoDiffScalar& other)
: m_value(other.value()), m_derivatives(other.derivatives())
{}
template<typename OtherDerType>
inline AutoDiffScalar& operator=(const AutoDiffScalar<OtherDerType>& other)
{
m_value = other.value();
m_derivatives = other.derivatives();
return *this;
}
inline AutoDiffScalar& operator=(const AutoDiffScalar& other)
{
m_value = other.value();
m_derivatives = other.derivatives();
return *this;
}
inline AutoDiffScalar& operator=(const Scalar& other)
{
m_value = other;
if(m_derivatives.size()>0)
m_derivatives.setZero();
return *this;
}
// inline operator const Scalar& () const { return m_value; }
// inline operator Scalar& () { return m_value; }
inline const Scalar& value() const { return m_value; }
inline Scalar& value() { return m_value; }
inline const DerType& derivatives() const { return m_derivatives; }
inline DerType& derivatives() { return m_derivatives; }
inline bool operator< (const Scalar& other) const { return m_value < other; }
inline bool operator<=(const Scalar& other) const { return m_value <= other; }
inline bool operator> (const Scalar& other) const { return m_value > other; }
inline bool operator>=(const Scalar& other) const { return m_value >= other; }
inline bool operator==(const Scalar& other) const { return m_value == other; }
inline bool operator!=(const Scalar& other) const { return m_value != other; }
friend inline bool operator< (const Scalar& a, const AutoDiffScalar& b) { return a < b.value(); }
friend inline bool operator<=(const Scalar& a, const AutoDiffScalar& b) { return a <= b.value(); }
friend inline bool operator> (const Scalar& a, const AutoDiffScalar& b) { return a > b.value(); }
friend inline bool operator>=(const Scalar& a, const AutoDiffScalar& b) { return a >= b.value(); }
friend inline bool operator==(const Scalar& a, const AutoDiffScalar& b) { return a == b.value(); }
friend inline bool operator!=(const Scalar& a, const AutoDiffScalar& b) { return a != b.value(); }
template<typename OtherDerType> inline bool operator< (const AutoDiffScalar<OtherDerType>& b) const { return m_value < b.value(); }
template<typename OtherDerType> inline bool operator<=(const AutoDiffScalar<OtherDerType>& b) const { return m_value <= b.value(); }
template<typename OtherDerType> inline bool operator> (const AutoDiffScalar<OtherDerType>& b) const { return m_value > b.value(); }
template<typename OtherDerType> inline bool operator>=(const AutoDiffScalar<OtherDerType>& b) const { return m_value >= b.value(); }
template<typename OtherDerType> inline bool operator==(const AutoDiffScalar<OtherDerType>& b) const { return m_value == b.value(); }
template<typename OtherDerType> inline bool operator!=(const AutoDiffScalar<OtherDerType>& b) const { return m_value != b.value(); }
inline const AutoDiffScalar<DerType&> operator+(const Scalar& other) const
{
return AutoDiffScalar<DerType&>(m_value + other, m_derivatives);
}
friend inline const AutoDiffScalar<DerType&> operator+(const Scalar& a, const AutoDiffScalar& b)
{
return AutoDiffScalar<DerType&>(a + b.value(), b.derivatives());
}
// inline const AutoDiffScalar<DerType&> operator+(const Real& other) const
// {
// return AutoDiffScalar<DerType&>(m_value + other, m_derivatives);
// }
// friend inline const AutoDiffScalar<DerType&> operator+(const Real& a, const AutoDiffScalar& b)
// {
// return AutoDiffScalar<DerType&>(a + b.value(), b.derivatives());
// }
inline AutoDiffScalar& operator+=(const Scalar& other)
{
value() += other;
return *this;
}
template<typename OtherDerType>
inline const AutoDiffScalar<CwiseBinaryOp<internal::scalar_sum_op<Scalar>,const DerType,const typename internal::remove_all<OtherDerType>::type> >
operator+(const AutoDiffScalar<OtherDerType>& other) const
{
internal::make_coherent(m_derivatives, other.derivatives());
return AutoDiffScalar<CwiseBinaryOp<internal::scalar_sum_op<Scalar>,const DerType,const typename internal::remove_all<OtherDerType>::type> >(
m_value + other.value(),
m_derivatives + other.derivatives());
}
template<typename OtherDerType>
inline AutoDiffScalar&
operator+=(const AutoDiffScalar<OtherDerType>& other)
{
(*this) = (*this) + other;
return *this;
}
inline const AutoDiffScalar<DerType&> operator-(const Scalar& b) const
{
return AutoDiffScalar<DerType&>(m_value - b, m_derivatives);
}
friend inline const AutoDiffScalar<CwiseUnaryOp<internal::scalar_opposite_op<Scalar>, const DerType> >
operator-(const Scalar& a, const AutoDiffScalar& b)
{
return AutoDiffScalar<CwiseUnaryOp<internal::scalar_opposite_op<Scalar>, const DerType> >
(a - b.value(), -b.derivatives());
}
inline AutoDiffScalar& operator-=(const Scalar& other)
{
value() -= other;
return *this;
}
template<typename OtherDerType>
inline const AutoDiffScalar<CwiseBinaryOp<internal::scalar_difference_op<Scalar>, const DerType,const typename internal::remove_all<OtherDerType>::type> >
operator-(const AutoDiffScalar<OtherDerType>& other) const
{
internal::make_coherent(m_derivatives, other.derivatives());
return AutoDiffScalar<CwiseBinaryOp<internal::scalar_difference_op<Scalar>, const DerType,const typename internal::remove_all<OtherDerType>::type> >(
m_value - other.value(),
m_derivatives - other.derivatives());
}
template<typename OtherDerType>
inline AutoDiffScalar&
operator-=(const AutoDiffScalar<OtherDerType>& other)
{
*this = *this - other;
return *this;
}
inline const AutoDiffScalar<CwiseUnaryOp<internal::scalar_opposite_op<Scalar>, const DerType> >
operator-() const
{
return AutoDiffScalar<CwiseUnaryOp<internal::scalar_opposite_op<Scalar>, const DerType> >(
-m_value,
-m_derivatives);
}
inline const AutoDiffScalar<EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(DerType,Scalar,product) >
operator*(const Scalar& other) const
{
return MakeAutoDiffScalar(m_value * other, m_derivatives * other);
}
friend inline const AutoDiffScalar<EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(DerType,Scalar,product) >
operator*(const Scalar& other, const AutoDiffScalar& a)
{
return MakeAutoDiffScalar(a.value() * other, a.derivatives() * other);
}
// inline const AutoDiffScalar<typename CwiseUnaryOp<internal::scalar_multiple_op<Real>, DerType>::Type >
// operator*(const Real& other) const
// {
// return AutoDiffScalar<typename CwiseUnaryOp<internal::scalar_multiple_op<Real>, DerType>::Type >(
// m_value * other,
// (m_derivatives * other));
// }
//
// friend inline const AutoDiffScalar<typename CwiseUnaryOp<internal::scalar_multiple_op<Real>, DerType>::Type >
// operator*(const Real& other, const AutoDiffScalar& a)
// {
// return AutoDiffScalar<typename CwiseUnaryOp<internal::scalar_multiple_op<Real>, DerType>::Type >(
// a.value() * other,
// a.derivatives() * other);
// }
inline const AutoDiffScalar<EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(DerType,Scalar,product) >
operator/(const Scalar& other) const
{
return MakeAutoDiffScalar(m_value / other, (m_derivatives * (Scalar(1)/other)));
}
friend inline const AutoDiffScalar<EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(DerType,Scalar,product) >
operator/(const Scalar& other, const AutoDiffScalar& a)
{
return MakeAutoDiffScalar(other / a.value(), a.derivatives() * (Scalar(-other) / (a.value()*a.value())));
}
// inline const AutoDiffScalar<typename CwiseUnaryOp<internal::scalar_multiple_op<Real>, DerType>::Type >
// operator/(const Real& other) const
// {
// return AutoDiffScalar<typename CwiseUnaryOp<internal::scalar_multiple_op<Real>, DerType>::Type >(
// m_value / other,
// (m_derivatives * (Real(1)/other)));
// }
//
// friend inline const AutoDiffScalar<typename CwiseUnaryOp<internal::scalar_multiple_op<Real>, DerType>::Type >
// operator/(const Real& other, const AutoDiffScalar& a)
// {
// return AutoDiffScalar<typename CwiseUnaryOp<internal::scalar_multiple_op<Real>, DerType>::Type >(
// other / a.value(),
// a.derivatives() * (-Real(1)/other));
// }
template<typename OtherDerType>
inline const AutoDiffScalar<EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(
CwiseBinaryOp<internal::scalar_difference_op<Scalar> EIGEN_COMMA
const EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(DerType,Scalar,product) EIGEN_COMMA
const EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(typename internal::remove_all<OtherDerType>::type,Scalar,product) >,Scalar,product) >
operator/(const AutoDiffScalar<OtherDerType>& other) const
{
internal::make_coherent(m_derivatives, other.derivatives());
return MakeAutoDiffScalar(
m_value / other.value(),
((m_derivatives * other.value()) - (other.derivatives() * m_value))
* (Scalar(1)/(other.value()*other.value())));
}
template<typename OtherDerType>
inline const AutoDiffScalar<CwiseBinaryOp<internal::scalar_sum_op<Scalar>,
const EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(DerType,Scalar,product),
const EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(typename internal::remove_all<OtherDerType>::type,Scalar,product) > >
operator*(const AutoDiffScalar<OtherDerType>& other) const
{
internal::make_coherent(m_derivatives, other.derivatives());
return MakeAutoDiffScalar(
m_value * other.value(),
(m_derivatives * other.value()) + (other.derivatives() * m_value));
}
inline AutoDiffScalar& operator*=(const Scalar& other)
{
*this = *this * other;
return *this;
}
template<typename OtherDerType>
inline AutoDiffScalar& operator*=(const AutoDiffScalar<OtherDerType>& other)
{
*this = *this * other;
return *this;
}
inline AutoDiffScalar& operator/=(const Scalar& other)
{
*this = *this / other;
return *this;
}
template<typename OtherDerType>
inline AutoDiffScalar& operator/=(const AutoDiffScalar<OtherDerType>& other)
{
*this = *this / other;
return *this;
}
protected:
Scalar m_value;
DerType m_derivatives;
};
namespace internal {
template<typename _DerType>
struct auto_diff_special_op<_DerType, true>
// : auto_diff_scalar_op<_DerType, typename NumTraits<Scalar>::Real,
// is_same<Scalar,typename NumTraits<Scalar>::Real>::value>
{
typedef typename remove_all<_DerType>::type DerType;
typedef typename traits<DerType>::Scalar Scalar;
typedef typename NumTraits<Scalar>::Real Real;
// typedef auto_diff_scalar_op<_DerType, typename NumTraits<Scalar>::Real,
// is_same<Scalar,typename NumTraits<Scalar>::Real>::value> Base;
// using Base::operator+;
// using Base::operator+=;
// using Base::operator-;
// using Base::operator-=;
// using Base::operator*;
// using Base::operator*=;
const AutoDiffScalar<_DerType>& derived() const { return *static_cast<const AutoDiffScalar<_DerType>*>(this); }
AutoDiffScalar<_DerType>& derived() { return *static_cast<AutoDiffScalar<_DerType>*>(this); }
inline const AutoDiffScalar<DerType&> operator+(const Real& other) const
{
return AutoDiffScalar<DerType&>(derived().value() + other, derived().derivatives());
}
friend inline const AutoDiffScalar<DerType&> operator+(const Real& a, const AutoDiffScalar<_DerType>& b)
{
return AutoDiffScalar<DerType&>(a + b.value(), b.derivatives());
}
inline AutoDiffScalar<_DerType>& operator+=(const Real& other)
{
derived().value() += other;
return derived();
}
inline const AutoDiffScalar<typename CwiseUnaryOp<bind2nd_op<scalar_product_op<Scalar,Real> >, DerType>::Type >
operator*(const Real& other) const
{
return AutoDiffScalar<typename CwiseUnaryOp<bind2nd_op<scalar_product_op<Scalar,Real> >, DerType>::Type >(
derived().value() * other,
derived().derivatives() * other);
}
friend inline const AutoDiffScalar<typename CwiseUnaryOp<bind1st_op<scalar_product_op<Real,Scalar> >, DerType>::Type >
operator*(const Real& other, const AutoDiffScalar<_DerType>& a)
{
return AutoDiffScalar<typename CwiseUnaryOp<bind1st_op<scalar_product_op<Real,Scalar> >, DerType>::Type >(
a.value() * other,
a.derivatives() * other);
}
inline AutoDiffScalar<_DerType>& operator*=(const Scalar& other)
{
*this = *this * other;
return derived();
}
};
template<typename _DerType>
struct auto_diff_special_op<_DerType, false>
{
void operator*() const;
void operator-() const;
void operator+() const;
};
template<typename A_Scalar, int A_Rows, int A_Cols, int A_Options, int A_MaxRows, int A_MaxCols, typename B>
struct make_coherent_impl<Matrix<A_Scalar, A_Rows, A_Cols, A_Options, A_MaxRows, A_MaxCols>, B> {
typedef Matrix<A_Scalar, A_Rows, A_Cols, A_Options, A_MaxRows, A_MaxCols> A;
static void run(A& a, B& b) {
if((A_Rows==Dynamic || A_Cols==Dynamic) && (a.size()==0))
{
a.resize(b.size());
a.setZero();
}
}
};
template<typename A, typename B_Scalar, int B_Rows, int B_Cols, int B_Options, int B_MaxRows, int B_MaxCols>
struct make_coherent_impl<A, Matrix<B_Scalar, B_Rows, B_Cols, B_Options, B_MaxRows, B_MaxCols> > {
typedef Matrix<B_Scalar, B_Rows, B_Cols, B_Options, B_MaxRows, B_MaxCols> B;
static void run(A& a, B& b) {
if((B_Rows==Dynamic || B_Cols==Dynamic) && (b.size()==0))
{
b.resize(a.size());
b.setZero();
}
}
};
template<typename A_Scalar, int A_Rows, int A_Cols, int A_Options, int A_MaxRows, int A_MaxCols,
typename B_Scalar, int B_Rows, int B_Cols, int B_Options, int B_MaxRows, int B_MaxCols>
struct make_coherent_impl<Matrix<A_Scalar, A_Rows, A_Cols, A_Options, A_MaxRows, A_MaxCols>,
Matrix<B_Scalar, B_Rows, B_Cols, B_Options, B_MaxRows, B_MaxCols> > {
typedef Matrix<A_Scalar, A_Rows, A_Cols, A_Options, A_MaxRows, A_MaxCols> A;
typedef Matrix<B_Scalar, B_Rows, B_Cols, B_Options, B_MaxRows, B_MaxCols> B;
static void run(A& a, B& b) {
if((A_Rows==Dynamic || A_Cols==Dynamic) && (a.size()==0))
{
a.resize(b.size());
a.setZero();
}
else if((B_Rows==Dynamic || B_Cols==Dynamic) && (b.size()==0))
{
b.resize(a.size());
b.setZero();
}
}
};
} // end namespace internal
template<typename DerType, typename BinOp>
struct ScalarBinaryOpTraits<AutoDiffScalar<DerType>,typename DerType::Scalar,BinOp>
{
typedef AutoDiffScalar<DerType> ReturnType;
};
template<typename DerType, typename BinOp>
struct ScalarBinaryOpTraits<typename DerType::Scalar,AutoDiffScalar<DerType>, BinOp>
{
typedef AutoDiffScalar<DerType> ReturnType;
};
// The following is an attempt to let Eigen's known about expression template, but that's more tricky!
// template<typename DerType, typename BinOp>
// struct ScalarBinaryOpTraits<AutoDiffScalar<DerType>,AutoDiffScalar<DerType>, BinOp>
// {
// enum { Defined = 1 };
// typedef AutoDiffScalar<typename DerType::PlainObject> ReturnType;
// };
//
// template<typename DerType1,typename DerType2, typename BinOp>
// struct ScalarBinaryOpTraits<AutoDiffScalar<DerType1>,AutoDiffScalar<DerType2>, BinOp>
// {
// enum { Defined = 1 };//internal::is_same<typename DerType1::Scalar,typename DerType2::Scalar>::value };
// typedef AutoDiffScalar<typename DerType1::PlainObject> ReturnType;
// };
#define EIGEN_AUTODIFF_DECLARE_GLOBAL_UNARY(FUNC,CODE) \
template<typename DerType> \
inline const Eigen::AutoDiffScalar< \
EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(typename Eigen::internal::remove_all<DerType>::type, typename Eigen::internal::traits<typename Eigen::internal::remove_all<DerType>::type>::Scalar, product) > \
FUNC(const Eigen::AutoDiffScalar<DerType>& x) { \
using namespace Eigen; \
typedef typename Eigen::internal::traits<typename Eigen::internal::remove_all<DerType>::type>::Scalar Scalar; \
EIGEN_UNUSED_VARIABLE(sizeof(Scalar)); \
CODE; \
}
template<typename DerType>
inline const AutoDiffScalar<DerType>& conj(const AutoDiffScalar<DerType>& x) { return x; }
template<typename DerType>
inline const AutoDiffScalar<DerType>& real(const AutoDiffScalar<DerType>& x) { return x; }
template<typename DerType>
inline typename DerType::Scalar imag(const AutoDiffScalar<DerType>&) { return 0.; }
template<typename DerType, typename T>
inline AutoDiffScalar<typename Eigen::internal::remove_all<DerType>::type::PlainObject> (min)(const AutoDiffScalar<DerType>& x, const T& y) {
typedef AutoDiffScalar<typename Eigen::internal::remove_all<DerType>::type::PlainObject> ADS;
return (x <= y ? ADS(x) : ADS(y));
}
template<typename DerType, typename T>
inline AutoDiffScalar<typename Eigen::internal::remove_all<DerType>::type::PlainObject> (max)(const AutoDiffScalar<DerType>& x, const T& y) {
typedef AutoDiffScalar<typename Eigen::internal::remove_all<DerType>::type::PlainObject> ADS;
return (x >= y ? ADS(x) : ADS(y));
}
template<typename DerType, typename T>
inline AutoDiffScalar<typename Eigen::internal::remove_all<DerType>::type::PlainObject> (min)(const T& x, const AutoDiffScalar<DerType>& y) {
typedef AutoDiffScalar<typename Eigen::internal::remove_all<DerType>::type::PlainObject> ADS;
return (x < y ? ADS(x) : ADS(y));
}
template<typename DerType, typename T>
inline AutoDiffScalar<typename Eigen::internal::remove_all<DerType>::type::PlainObject> (max)(const T& x, const AutoDiffScalar<DerType>& y) {
typedef AutoDiffScalar<typename Eigen::internal::remove_all<DerType>::type::PlainObject> ADS;
return (x > y ? ADS(x) : ADS(y));
}
template<typename DerType>
inline AutoDiffScalar<typename Eigen::internal::remove_all<DerType>::type::PlainObject> (min)(const AutoDiffScalar<DerType>& x, const AutoDiffScalar<DerType>& y) {
return (x.value() < y.value() ? x : y);
}
template<typename DerType>
inline AutoDiffScalar<typename Eigen::internal::remove_all<DerType>::type::PlainObject> (max)(const AutoDiffScalar<DerType>& x, const AutoDiffScalar<DerType>& y) {
return (x.value() >= y.value() ? x : y);
}
EIGEN_AUTODIFF_DECLARE_GLOBAL_UNARY(abs,
using std::abs;
return Eigen::MakeAutoDiffScalar(abs(x.value()), x.derivatives() * (x.value()<0 ? -1 : 1) );)
EIGEN_AUTODIFF_DECLARE_GLOBAL_UNARY(abs2,
using numext::abs2;
return Eigen::MakeAutoDiffScalar(abs2(x.value()), x.derivatives() * (Scalar(2)*x.value()));)
EIGEN_AUTODIFF_DECLARE_GLOBAL_UNARY(sqrt,
using std::sqrt;
Scalar sqrtx = sqrt(x.value());
return Eigen::MakeAutoDiffScalar(sqrtx,x.derivatives() * (Scalar(0.5) / sqrtx));)
EIGEN_AUTODIFF_DECLARE_GLOBAL_UNARY(cos,
using std::cos;
using std::sin;
return Eigen::MakeAutoDiffScalar(cos(x.value()), x.derivatives() * (-sin(x.value())));)
EIGEN_AUTODIFF_DECLARE_GLOBAL_UNARY(sin,
using std::sin;
using std::cos;
return Eigen::MakeAutoDiffScalar(sin(x.value()),x.derivatives() * cos(x.value()));)
EIGEN_AUTODIFF_DECLARE_GLOBAL_UNARY(exp,
using std::exp;
Scalar expx = exp(x.value());
return Eigen::MakeAutoDiffScalar(expx,x.derivatives() * expx);)
EIGEN_AUTODIFF_DECLARE_GLOBAL_UNARY(log,
using std::log;
return Eigen::MakeAutoDiffScalar(log(x.value()),x.derivatives() * (Scalar(1)/x.value()));)
template<typename DerType>
inline const Eigen::AutoDiffScalar<
EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(typename internal::remove_all<DerType>::type,typename internal::traits<typename internal::remove_all<DerType>::type>::Scalar,product) >
pow(const Eigen::AutoDiffScalar<DerType> &x, const typename internal::traits<typename internal::remove_all<DerType>::type>::Scalar &y)
{
using namespace Eigen;
using std::pow;
return Eigen::MakeAutoDiffScalar(pow(x.value(),y), x.derivatives() * (y * pow(x.value(),y-1)));
}
template<typename DerTypeA,typename DerTypeB>
inline const AutoDiffScalar<Matrix<typename internal::traits<typename internal::remove_all<DerTypeA>::type>::Scalar,Dynamic,1> >
atan2(const AutoDiffScalar<DerTypeA>& a, const AutoDiffScalar<DerTypeB>& b)
{
using std::atan2;
typedef typename internal::traits<typename internal::remove_all<DerTypeA>::type>::Scalar Scalar;
typedef AutoDiffScalar<Matrix<Scalar,Dynamic,1> > PlainADS;
PlainADS ret;
ret.value() = atan2(a.value(), b.value());
Scalar squared_hypot = a.value() * a.value() + b.value() * b.value();
// if (squared_hypot==0) the derivation is undefined and the following results in a NaN:
ret.derivatives() = (a.derivatives() * b.value() - a.value() * b.derivatives()) / squared_hypot;
return ret;
}
EIGEN_AUTODIFF_DECLARE_GLOBAL_UNARY(tan,
using std::tan;
using std::cos;
return Eigen::MakeAutoDiffScalar(tan(x.value()),x.derivatives() * (Scalar(1)/numext::abs2(cos(x.value()))));)
EIGEN_AUTODIFF_DECLARE_GLOBAL_UNARY(asin,
using std::sqrt;
using std::asin;
return Eigen::MakeAutoDiffScalar(asin(x.value()),x.derivatives() * (Scalar(1)/sqrt(1-numext::abs2(x.value()))));)
EIGEN_AUTODIFF_DECLARE_GLOBAL_UNARY(acos,
using std::sqrt;
using std::acos;
return Eigen::MakeAutoDiffScalar(acos(x.value()),x.derivatives() * (Scalar(-1)/sqrt(1-numext::abs2(x.value()))));)
EIGEN_AUTODIFF_DECLARE_GLOBAL_UNARY(tanh,
using std::cosh;
using std::tanh;
return Eigen::MakeAutoDiffScalar(tanh(x.value()),x.derivatives() * (Scalar(1)/numext::abs2(cosh(x.value()))));)
EIGEN_AUTODIFF_DECLARE_GLOBAL_UNARY(sinh,
using std::sinh;
using std::cosh;
return Eigen::MakeAutoDiffScalar(sinh(x.value()),x.derivatives() * cosh(x.value()));)
EIGEN_AUTODIFF_DECLARE_GLOBAL_UNARY(cosh,
using std::sinh;
using std::cosh;
return Eigen::MakeAutoDiffScalar(cosh(x.value()),x.derivatives() * sinh(x.value()));)
#undef EIGEN_AUTODIFF_DECLARE_GLOBAL_UNARY
template<typename DerType> struct NumTraits<AutoDiffScalar<DerType> >
: NumTraits< typename NumTraits<typename internal::remove_all<DerType>::type::Scalar>::Real >
{
typedef typename internal::remove_all<DerType>::type DerTypeCleaned;
typedef AutoDiffScalar<Matrix<typename NumTraits<typename DerTypeCleaned::Scalar>::Real,DerTypeCleaned::RowsAtCompileTime,DerTypeCleaned::ColsAtCompileTime,
0, DerTypeCleaned::MaxRowsAtCompileTime, DerTypeCleaned::MaxColsAtCompileTime> > Real;
typedef AutoDiffScalar<DerType> NonInteger;
typedef AutoDiffScalar<DerType> Nested;
typedef typename NumTraits<typename DerTypeCleaned::Scalar>::Literal Literal;
enum{
RequireInitialization = 1
};
};
}
namespace std {
template <typename T>
class numeric_limits<Eigen::AutoDiffScalar<T> >
: public numeric_limits<typename T::Scalar> {};
} // namespace std
#endif // EIGEN_AUTODIFF_SCALAR_H

View File

@@ -0,0 +1,220 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_AUTODIFF_VECTOR_H
#define EIGEN_AUTODIFF_VECTOR_H
namespace Eigen {
/* \class AutoDiffScalar
* \brief A scalar type replacement with automatic differentation capability
*
* \param DerType the vector type used to store/represent the derivatives (e.g. Vector3f)
*
* This class represents a scalar value while tracking its respective derivatives.
*
* It supports the following list of global math function:
* - std::abs, std::sqrt, std::pow, std::exp, std::log, std::sin, std::cos,
* - internal::abs, internal::sqrt, numext::pow, internal::exp, internal::log, internal::sin, internal::cos,
* - internal::conj, internal::real, internal::imag, numext::abs2.
*
* AutoDiffScalar can be used as the scalar type of an Eigen::Matrix object. However,
* in that case, the expression template mechanism only occurs at the top Matrix level,
* while derivatives are computed right away.
*
*/
template<typename ValueType, typename JacobianType>
class AutoDiffVector
{
public:
//typedef typename internal::traits<ValueType>::Scalar Scalar;
typedef typename internal::traits<ValueType>::Scalar BaseScalar;
typedef AutoDiffScalar<Matrix<BaseScalar,JacobianType::RowsAtCompileTime,1> > ActiveScalar;
typedef ActiveScalar Scalar;
typedef AutoDiffScalar<typename JacobianType::ColXpr> CoeffType;
typedef typename JacobianType::Index Index;
inline AutoDiffVector() {}
inline AutoDiffVector(const ValueType& values)
: m_values(values)
{
m_jacobian.setZero();
}
CoeffType operator[] (Index i) { return CoeffType(m_values[i], m_jacobian.col(i)); }
const CoeffType operator[] (Index i) const { return CoeffType(m_values[i], m_jacobian.col(i)); }
CoeffType operator() (Index i) { return CoeffType(m_values[i], m_jacobian.col(i)); }
const CoeffType operator() (Index i) const { return CoeffType(m_values[i], m_jacobian.col(i)); }
CoeffType coeffRef(Index i) { return CoeffType(m_values[i], m_jacobian.col(i)); }
const CoeffType coeffRef(Index i) const { return CoeffType(m_values[i], m_jacobian.col(i)); }
Index size() const { return m_values.size(); }
// FIXME here we could return an expression of the sum
Scalar sum() const { /*std::cerr << "sum \n\n";*/ /*std::cerr << m_jacobian.rowwise().sum() << "\n\n";*/ return Scalar(m_values.sum(), m_jacobian.rowwise().sum()); }
inline AutoDiffVector(const ValueType& values, const JacobianType& jac)
: m_values(values), m_jacobian(jac)
{}
template<typename OtherValueType, typename OtherJacobianType>
inline AutoDiffVector(const AutoDiffVector<OtherValueType, OtherJacobianType>& other)
: m_values(other.values()), m_jacobian(other.jacobian())
{}
inline AutoDiffVector(const AutoDiffVector& other)
: m_values(other.values()), m_jacobian(other.jacobian())
{}
template<typename OtherValueType, typename OtherJacobianType>
inline AutoDiffVector& operator=(const AutoDiffVector<OtherValueType, OtherJacobianType>& other)
{
m_values = other.values();
m_jacobian = other.jacobian();
return *this;
}
inline AutoDiffVector& operator=(const AutoDiffVector& other)
{
m_values = other.values();
m_jacobian = other.jacobian();
return *this;
}
inline const ValueType& values() const { return m_values; }
inline ValueType& values() { return m_values; }
inline const JacobianType& jacobian() const { return m_jacobian; }
inline JacobianType& jacobian() { return m_jacobian; }
template<typename OtherValueType,typename OtherJacobianType>
inline const AutoDiffVector<
typename MakeCwiseBinaryOp<internal::scalar_sum_op<BaseScalar>,ValueType,OtherValueType>::Type,
typename MakeCwiseBinaryOp<internal::scalar_sum_op<BaseScalar>,JacobianType,OtherJacobianType>::Type >
operator+(const AutoDiffVector<OtherValueType,OtherJacobianType>& other) const
{
return AutoDiffVector<
typename MakeCwiseBinaryOp<internal::scalar_sum_op<BaseScalar>,ValueType,OtherValueType>::Type,
typename MakeCwiseBinaryOp<internal::scalar_sum_op<BaseScalar>,JacobianType,OtherJacobianType>::Type >(
m_values + other.values(),
m_jacobian + other.jacobian());
}
template<typename OtherValueType, typename OtherJacobianType>
inline AutoDiffVector&
operator+=(const AutoDiffVector<OtherValueType,OtherJacobianType>& other)
{
m_values += other.values();
m_jacobian += other.jacobian();
return *this;
}
template<typename OtherValueType,typename OtherJacobianType>
inline const AutoDiffVector<
typename MakeCwiseBinaryOp<internal::scalar_difference_op<Scalar>,ValueType,OtherValueType>::Type,
typename MakeCwiseBinaryOp<internal::scalar_difference_op<Scalar>,JacobianType,OtherJacobianType>::Type >
operator-(const AutoDiffVector<OtherValueType,OtherJacobianType>& other) const
{
return AutoDiffVector<
typename MakeCwiseBinaryOp<internal::scalar_difference_op<Scalar>,ValueType,OtherValueType>::Type,
typename MakeCwiseBinaryOp<internal::scalar_difference_op<Scalar>,JacobianType,OtherJacobianType>::Type >(
m_values - other.values(),
m_jacobian - other.jacobian());
}
template<typename OtherValueType, typename OtherJacobianType>
inline AutoDiffVector&
operator-=(const AutoDiffVector<OtherValueType,OtherJacobianType>& other)
{
m_values -= other.values();
m_jacobian -= other.jacobian();
return *this;
}
inline const AutoDiffVector<
typename MakeCwiseUnaryOp<internal::scalar_opposite_op<Scalar>, ValueType>::Type,
typename MakeCwiseUnaryOp<internal::scalar_opposite_op<Scalar>, JacobianType>::Type >
operator-() const
{
return AutoDiffVector<
typename MakeCwiseUnaryOp<internal::scalar_opposite_op<Scalar>, ValueType>::Type,
typename MakeCwiseUnaryOp<internal::scalar_opposite_op<Scalar>, JacobianType>::Type >(
-m_values,
-m_jacobian);
}
inline const AutoDiffVector<
typename MakeCwiseUnaryOp<internal::scalar_multiple_op<Scalar>, ValueType>::Type,
typename MakeCwiseUnaryOp<internal::scalar_multiple_op<Scalar>, JacobianType>::Type>
operator*(const BaseScalar& other) const
{
return AutoDiffVector<
typename MakeCwiseUnaryOp<internal::scalar_multiple_op<Scalar>, ValueType>::Type,
typename MakeCwiseUnaryOp<internal::scalar_multiple_op<Scalar>, JacobianType>::Type >(
m_values * other,
m_jacobian * other);
}
friend inline const AutoDiffVector<
typename MakeCwiseUnaryOp<internal::scalar_multiple_op<Scalar>, ValueType>::Type,
typename MakeCwiseUnaryOp<internal::scalar_multiple_op<Scalar>, JacobianType>::Type >
operator*(const Scalar& other, const AutoDiffVector& v)
{
return AutoDiffVector<
typename MakeCwiseUnaryOp<internal::scalar_multiple_op<Scalar>, ValueType>::Type,
typename MakeCwiseUnaryOp<internal::scalar_multiple_op<Scalar>, JacobianType>::Type >(
v.values() * other,
v.jacobian() * other);
}
// template<typename OtherValueType,typename OtherJacobianType>
// inline const AutoDiffVector<
// CwiseBinaryOp<internal::scalar_multiple_op<Scalar>, ValueType, OtherValueType>
// CwiseBinaryOp<internal::scalar_sum_op<Scalar>,
// CwiseUnaryOp<internal::scalar_multiple_op<Scalar>, JacobianType>,
// CwiseUnaryOp<internal::scalar_multiple_op<Scalar>, OtherJacobianType> > >
// operator*(const AutoDiffVector<OtherValueType,OtherJacobianType>& other) const
// {
// return AutoDiffVector<
// CwiseBinaryOp<internal::scalar_multiple_op<Scalar>, ValueType, OtherValueType>
// CwiseBinaryOp<internal::scalar_sum_op<Scalar>,
// CwiseUnaryOp<internal::scalar_multiple_op<Scalar>, JacobianType>,
// CwiseUnaryOp<internal::scalar_multiple_op<Scalar>, OtherJacobianType> > >(
// m_values.cwise() * other.values(),
// (m_jacobian * other.values()) + (m_values * other.jacobian()));
// }
inline AutoDiffVector& operator*=(const Scalar& other)
{
m_values *= other;
m_jacobian *= other;
return *this;
}
template<typename OtherValueType,typename OtherJacobianType>
inline AutoDiffVector& operator*=(const AutoDiffVector<OtherValueType,OtherJacobianType>& other)
{
*this = *this * other;
return *this;
}
protected:
ValueType m_values;
JacobianType m_jacobian;
};
}
#endif // EIGEN_AUTODIFF_VECTOR_H

View File

@@ -0,0 +1,152 @@
#pragma once
#include <type_traits>
/// @file
/// Provides Drake's assertion implementation. This is intended to be used
/// both within Drake and by other software. Drake's asserts can be armed
/// and disarmed independently from the system-wide asserts.
#ifdef DRAKE_DOXYGEN_CXX
/// @p DRAKE_ASSERT(condition) is similar to the built-in @p assert(condition)
/// from the C++ system header @p <cassert>. Unless Drake's assertions are
/// disarmed by the pre-processor definitions listed below, @p DRAKE_ASSERT
/// will evaluate @p condition and iff the value is false will trigger an
/// assertion failure with a message showing at least the condition text,
/// function name, file, and line.
///
/// By default, assertion failures will :abort() the program. However, when
/// using the pydrake python bindings, assertion failures will instead throw a
/// C++ exception that causes a python SystemExit exception.
///
/// Assertions are enabled or disabled using the following pre-processor macros:
///
/// - If @p DRAKE_ENABLE_ASSERTS is defined, then @p DRAKE_ASSERT is armed.
/// - If @p DRAKE_DISABLE_ASSERTS is defined, then @p DRAKE_ASSERT is disarmed.
/// - If both macros are defined, then it is a compile-time error.
/// - If neither are defined, then NDEBUG governs assertions as usual.
///
/// This header will define exactly one of either @p DRAKE_ASSERT_IS_ARMED or
/// @p DRAKE_ASSERT_IS_DISARMED to indicate whether @p DRAKE_ASSERT is armed.
///
/// This header will define both `constexpr bool drake::kDrakeAssertIsArmed`
/// and `constexpr bool drake::kDrakeAssertIsDisarmed` globals.
///
/// One difference versus the standard @p assert(condition) is that the
/// @p condition within @p DRAKE_ASSERT is always syntax-checked, even if
/// Drake's assertions are disarmed.
///
/// Treat @p DRAKE_ASSERT like a statement -- it must always be used
/// in block scope, and must always be followed by a semicolon.
#define DRAKE_ASSERT(condition)
/// Like @p DRAKE_ASSERT, except that the expression must be void-valued; this
/// allows for guarding expensive assertion-checking subroutines using the same
/// macros as stand-alone assertions.
#define DRAKE_ASSERT_VOID(expression)
/// Evaluates @p condition and iff the value is false will trigger an assertion
/// failure with a message showing at least the condition text, function name,
/// file, and line.
#define DRAKE_DEMAND(condition)
/// Silences a "no return value" compiler warning by calling a function that
/// always raises an exception or aborts (i.e., a function marked noreturn).
/// Only use this macro at a point where (1) a point in the code is truly
/// unreachable, (2) the fact that it's unreachable is knowable from only
/// reading the function itself (and not, e.g., some larger design invariant),
/// and (3) there is a compiler warning if this macro were removed. The most
/// common valid use is with a switch-case-return block where all cases are
/// accounted for but the enclosing function is supposed to return a value. Do
/// *not* use this macro as a "logic error" assertion; it should *only* be used
/// to silence false positive warnings. When in doubt, throw an exception
/// manually instead of using this macro.
#define DRAKE_UNREACHABLE()
#else // DRAKE_DOXYGEN_CXX
// Users should NOT set these; only this header should set them.
#ifdef DRAKE_ASSERT_IS_ARMED
# error Unexpected DRAKE_ASSERT_IS_ARMED defined.
#endif
#ifdef DRAKE_ASSERT_IS_DISARMED
# error Unexpected DRAKE_ASSERT_IS_DISARMED defined.
#endif
// Decide whether Drake assertions are enabled.
#if defined(DRAKE_ENABLE_ASSERTS) && defined(DRAKE_DISABLE_ASSERTS)
# error Conflicting assertion toggles.
#elif defined(DRAKE_ENABLE_ASSERTS)
# define DRAKE_ASSERT_IS_ARMED
#elif defined(DRAKE_DISABLE_ASSERTS) || defined(NDEBUG)
# define DRAKE_ASSERT_IS_DISARMED
#else
# define DRAKE_ASSERT_IS_ARMED
#endif
namespace drake {
namespace internal {
// Abort the program with an error message.
[[noreturn]]
void Abort(const char* condition, const char* func, const char* file, int line);
// Report an assertion failure; will either Abort(...) or throw.
[[noreturn]]
void AssertionFailed(
const char* condition, const char* func, const char* file, int line);
} // namespace internal
namespace assert {
// Allows for specialization of how to bool-convert Conditions used in
// assertions, in case they are not intrinsically convertible. See
// symbolic_formula.h for an example use. This is a public interface to
// extend; it is intended to be specialized by unusual Scalar types that
// require special handling.
template <typename Condition>
struct ConditionTraits {
static constexpr bool is_valid = std::is_convertible<Condition, bool>::value;
static bool Evaluate(const Condition& value) {
return value;
}
};
} // namespace assert
} // namespace drake
#define DRAKE_UNREACHABLE() \
::drake::internal::Abort( \
"Unreachable code was reached?!", __func__, __FILE__, __LINE__)
#define DRAKE_DEMAND(condition) \
do { \
typedef ::drake::assert::ConditionTraits< \
typename std::remove_cv<decltype(condition)>::type> Trait; \
static_assert(Trait::is_valid, "Condition should be bool-convertible."); \
if (!Trait::Evaluate(condition)) { \
::drake::internal::AssertionFailed( \
#condition, __func__, __FILE__, __LINE__); \
} \
} while (0)
#ifdef DRAKE_ASSERT_IS_ARMED
// Assertions are enabled.
namespace drake {
constexpr bool kDrakeAssertIsArmed = true;
constexpr bool kDrakeAssertIsDisarmed = false;
} // namespace drake
# define DRAKE_ASSERT(condition) DRAKE_DEMAND(condition)
# define DRAKE_ASSERT_VOID(expression) do { \
static_assert( \
std::is_convertible<decltype(expression), void>::value, \
"Expression should be void."); \
expression; \
} while (0)
#else
// Assertions are disabled, so just typecheck the expression.
namespace drake {
constexpr bool kDrakeAssertIsArmed = false;
constexpr bool kDrakeAssertIsDisarmed = true;
} // namespace drake
# define DRAKE_ASSERT(condition) static_assert( \
::drake::assert::ConditionTraits< \
typename std::remove_cv<decltype(condition)>::type>::is_valid, \
"Condition should be bool-convertible.");
# define DRAKE_ASSERT_VOID(expression) static_assert( \
std::is_convertible<decltype(expression), void>::value, \
"Expression should be void.")
#endif
#endif // DRAKE_DOXYGEN_CXX

View File

@@ -0,0 +1,18 @@
#pragma once
#include <stdexcept>
#include <string>
namespace drake {
namespace internal {
/// This is what DRAKE_ASSERT and DRAKE_DEMAND throw when our assertions are
/// configured to throw.
class assertion_error : public std::runtime_error {
public:
explicit assertion_error(const std::string& what_arg)
: std::runtime_error(what_arg) {}
};
} // namespace internal
} // namespace drake

View File

@@ -0,0 +1,112 @@
#pragma once
// ============================================================================
// N.B. The spelling of the macro names between doc/Doxyfile_CXX.in and this
// file must be kept in sync!
// ============================================================================
/** @file
Provides careful macros to selectively enable or disable the special member
functions for copy-construction, copy-assignment, move-construction, and
move-assignment.
http://en.cppreference.com/w/cpp/language/member_functions#Special_member_functions
When enabled via these macros, the `= default` implementation is provided.
Code that needs custom copy or move functions should not use these macros.
*/
/** DRAKE_NO_COPY_NO_MOVE_NO_ASSIGN deletes the special member functions for
copy-construction, copy-assignment, move-construction, and move-assignment.
Drake's Doxygen is customized to render the deletions in detail, with
appropriate comments. Invoke this this macro in the public section of the
class declaration, e.g.:
<pre>
class Foo {
public:
DRAKE_NO_COPY_NO_MOVE_NO_ASSIGN(Foo)
// ...
};
</pre>
*/
#define DRAKE_NO_COPY_NO_MOVE_NO_ASSIGN(Classname) \
Classname(const Classname&) = delete; \
void operator=(const Classname&) = delete; \
Classname(Classname&&) = delete; \
void operator=(Classname&&) = delete;
/** DRAKE_DEFAULT_COPY_AND_MOVE_AND_ASSIGN defaults the special member
functions for copy-construction, copy-assignment, move-construction, and
move-assignment. This macro should be used only when copy-construction and
copy-assignment defaults are well-formed. Note that the defaulted move
functions could conceivably still be ill-formed, in which case they will
effectively not be declared or used -- but because the copy constructor exists
the type will still be MoveConstructible. Drake's Doxygen is customized to
render the functions in detail, with appropriate comments. Invoke this this
macro in the public section of the class declaration, e.g.:
<pre>
class Foo {
public:
DRAKE_DEFAULT_COPY_AND_MOVE_AND_ASSIGN(Foo)
// ...
};
</pre>
*/
#define DRAKE_DEFAULT_COPY_AND_MOVE_AND_ASSIGN(Classname) \
Classname(const Classname&) = default; \
Classname& operator=(const Classname&) = default; \
Classname(Classname&&) = default; \
Classname& operator=(Classname&&) = default; \
/* Fails at compile-time if default-copy doesn't work. */ \
static void DRAKE_COPYABLE_DEMAND_COPY_CAN_COMPILE() { \
(void) static_cast<Classname& (Classname::*)( \
const Classname&)>(&Classname::operator=); \
}
/** DRAKE_DECLARE_COPY_AND_MOVE_AND_ASSIGN declares (but does not define) the
special member functions for copy-construction, copy-assignment,
move-construction, and move-assignment. Drake's Doxygen is customized to
render the declarations with appropriate comments.
This is useful when paired with DRAKE_DEFINE_DEFAULT_COPY_AND_MOVE_AND_ASSIGN_T
to work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57728 whereby the
declaration and definition must be split. Once Drake no longer supports GCC
versions prior to 6.3, this macro could be removed.
Invoke this this macro in the public section of the class declaration, e.g.:
<pre>
template <typename T>
class Foo {
public:
DRAKE_DECLARE_COPY_AND_MOVE_AND_ASSIGN(Foo)
// ...
};
DRAKE_DEFINE_DEFAULT_COPY_AND_MOVE_AND_ASSIGN_T(Foo)
</pre>
*/
#define DRAKE_DECLARE_COPY_AND_MOVE_AND_ASSIGN(Classname) \
Classname(const Classname&); \
Classname& operator=(const Classname&); \
Classname(Classname&&); \
Classname& operator=(Classname&&); \
/* Fails at compile-time if default-copy doesn't work. */ \
static void DRAKE_COPYABLE_DEMAND_COPY_CAN_COMPILE() { \
(void) static_cast<Classname& (Classname::*)( \
const Classname&)>(&Classname::operator=); \
}
/** Helper for DRAKE_DECLARE_COPY_AND_MOVE_AND_ASSIGN. Provides defaulted
definitions for the four special member functions of a templated class.
*/
#define DRAKE_DEFINE_DEFAULT_COPY_AND_MOVE_AND_ASSIGN_T(Classname) \
template <typename T> \
Classname<T>::Classname(const Classname<T>&) = default; \
template <typename T> \
Classname<T>& Classname<T>::operator=(const Classname<T>&) = default; \
template <typename T> \
Classname<T>::Classname(Classname<T>&&) = default; \
template <typename T> \
Classname<T>& Classname<T>::operator=(Classname<T>&&) = default;

View File

@@ -0,0 +1,31 @@
#pragma once
#include <type_traits>
#include "drake/common/drake_assert.h"
/// @file
/// Provides a convenient wrapper to throw an exception when a condition is
/// unmet. This is similar to an assertion, but uses exceptions instead of
/// ::abort(), and cannot be disabled.
namespace drake {
namespace internal {
// Throw an error message.
[[noreturn]]
void Throw(const char* condition, const char* func, const char* file, int line);
} // namespace internal
} // namespace drake
/// Evaluates @p condition and iff the value is false will throw an exception
/// with a message showing at least the condition text, function name, file,
/// and line.
#define DRAKE_THROW_UNLESS(condition) \
do { \
typedef ::drake::assert::ConditionTraits< \
typename std::remove_cv<decltype(condition)>::type> Trait; \
static_assert(Trait::is_valid, "Condition should be bool-convertible."); \
if (!Trait::Evaluate(condition)) { \
::drake::internal::Throw(#condition, __func__, __FILE__, __LINE__); \
} \
} while (0)

View File

@@ -0,0 +1,62 @@
#pragma once
#include <vector>
#include <Eigen/Core>
namespace drake {
/// Returns true if and only if the two matrices are equal to within a certain
/// absolute elementwise @p tolerance. Special values (infinities, NaN, etc.)
/// do not compare as equal elements.
template <typename DerivedA, typename DerivedB>
bool is_approx_equal_abstol(const Eigen::MatrixBase<DerivedA>& m1,
const Eigen::MatrixBase<DerivedB>& m2,
double tolerance) {
return (
(m1.rows() == m2.rows()) &&
(m1.cols() == m2.cols()) &&
((m1 - m2).template lpNorm<Eigen::Infinity>() <= tolerance));
}
/// Returns true if and only if a simple greedy search reveals a permutation
/// of the columns of m2 to make the matrix equal to m1 to within a certain
/// absolute elementwise @p tolerance. E.g., there exists a P such that
/// <pre>
/// forall i,j, |m1 - m2*P|_{i,j} <= tolerance
/// where P is a permutation matrix:
/// P(i,j)={0,1}, sum_i P(i,j)=1, sum_j P(i,j)=1.
/// </pre>
/// Note: Returns false for matrices of different sizes.
/// Note: The current implementation is O(n^2) in the number of columns.
/// Note: In marginal cases (with similar but not identical columns) this
/// algorithm can fail to find a permutation P even if it exists because it
/// accepts the first column match (m1(i),m2(j)) and removes m2(j) from the
/// pool. It is possible that other columns of m2 would also match m1(i) but
/// that m2(j) is the only match possible for a later column of m1.
template <typename DerivedA, typename DerivedB>
bool IsApproxEqualAbsTolWithPermutedColumns(
const Eigen::MatrixBase<DerivedA>& m1,
const Eigen::MatrixBase<DerivedB>& m2, double tolerance) {
if ((m1.cols() != m2.cols()) || (m1.rows() != m2.rows())) return false;
std::vector<bool> available(m2.cols());
for (int i = 0; i < m2.cols(); i++) available[i] = true;
for (int i = 0; i < m1.cols(); i++) {
bool found_match = false;
for (int j = 0; j < m2.cols(); j++) {
if (available[j] &&
is_approx_equal_abstol(m1.col(i), m2.col(j), tolerance)) {
found_match = true;
available[j] = false;
break;
}
}
if (!found_match) return false;
}
return true;
}
} // namespace drake

View File

@@ -0,0 +1,84 @@
#pragma once
#include <new>
#include <type_traits>
#include <utility>
#include "drake/common/drake_copyable.h"
namespace drake {
/// Wraps an underlying type T such that its storage is a direct member field
/// of this object (i.e., without any indirection into the heap), but *unlike*
/// most member fields T's destructor is never invoked.
///
/// This is especially useful for function-local static variables that are not
/// trivially destructable. We shouldn't call their destructor at program exit
/// because of the "indeterminate order of ... destruction" as mentioned in
/// cppguide's
/// <a href="https://drake.mit.edu/styleguide/cppguide.html#Static_and_Global_Variables">Static
/// and Global Variables</a> section, but other solutions to this problem place
/// the objects on the heap through an indirection.
///
/// Compared with other approaches, this mechanism more clearly describes the
/// intent to readers, avoids "possible leak" warnings from memory-checking
/// tools, and is probably slightly faster.
///
/// Example uses:
///
/// The singleton pattern:
/// @code
/// class Singleton {
/// public:
/// DRAKE_NO_COPY_NO_MOVE_NO_ASSIGN(Singleton)
/// static Singleton& getInstance() {
/// static never_destroyed<Singleton> instance;
/// return instance.access();
/// }
/// private:
/// friend never_destroyed<Singleton>;
/// Singleton() = default;
/// };
/// @endcode
///
/// A lookup table, created on demand the first time its needed, and then
/// reused thereafter:
/// @code
/// enum class Foo { kBar, kBaz };
/// Foo ParseFoo(const std::string& foo_string) {
/// using Dict = std::unordered_map<std::string, Foo>;
/// static const drake::never_destroyed<Dict> string_to_enum{
/// std::initializer_list<Dict::value_type>{
/// {"bar", Foo::kBar},
/// {"baz", Foo::kBaz},
/// }
/// };
/// return string_to_enum.access().at(foo_string);
/// }
/// @endcode
//
// The above examples are repeated in the unit test; keep them in sync.
template <typename T>
class never_destroyed {
public:
DRAKE_NO_COPY_NO_MOVE_NO_ASSIGN(never_destroyed)
/// Passes the constructor arguments along to T using perfect forwarding.
template <typename... Args>
explicit never_destroyed(Args&&... args) {
// Uses "placement new" to construct a `T` in `storage_`.
new (&storage_) T(std::forward<Args>(args)...);
}
/// Does nothing. Guaranteed!
~never_destroyed() = default;
/// Returns the underlying T reference.
T& access() { return *reinterpret_cast<T*>(&storage_); }
const T& access() const { return *reinterpret_cast<const T*>(&storage_); }
private:
typename std::aligned_storage<sizeof(T), alignof(T)>::type storage_;
};
} // namespace drake

View File

@@ -0,0 +1,32 @@
#pragma once
#include <cmath>
#include <cstdlib>
#include <Eigen/Core>
namespace drake {
namespace math {
/// Computes the unique stabilizing solution X to the discrete-time algebraic
/// Riccati equation:
///
/// \f[
/// A'XA - X - A'XB(B'XB+R)^{-1}B'XA + Q = 0
/// \f]
///
/// @throws std::runtime_error if Q is not positive semi-definite.
/// @throws std::runtime_error if R is not positive definite.
///
/// Based on the Schur Vector approach outlined in this paper:
/// "On the Numerical Solution of the Discrete-Time Algebraic Riccati Equation"
/// by Thrasyvoulos Pappas, Alan J. Laub, and Nils R. Sandell
///
Eigen::MatrixXd DiscreteAlgebraicRiccatiEquation(
const Eigen::Ref<const Eigen::MatrixXd>& A,
const Eigen::Ref<const Eigen::MatrixXd>& B,
const Eigen::Ref<const Eigen::MatrixXd>& Q,
const Eigen::Ref<const Eigen::MatrixXd>& R);
} // namespace math
} // namespace drake

View File

@@ -0,0 +1,19 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpiutil.math;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
public class DrakeJNITest {
@Test
public void testLink() {
assertDoesNotThrow(DrakeJNI::forceLoad);
}
}

View File

@@ -0,0 +1,69 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpiutil.math;
import org.ejml.simple.SimpleMatrix;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
@SuppressWarnings({"ParameterName", "LocalVariableName"})
public class DrakeTest {
public static void assertMatrixEqual(SimpleMatrix A, SimpleMatrix B) {
for (int i = 0; i < A.numRows(); i++) {
for (int j = 0; j < A.numCols(); j++) {
assertEquals(A.get(i, j), B.get(i, j), 1e-4);
}
}
}
private boolean solveDAREandVerify(SimpleMatrix A, SimpleMatrix B, SimpleMatrix Q,
SimpleMatrix R) {
var X = Drake.discreteAlgebraicRiccatiEquation(A, B, Q, R);
// expect that x is the same as it's transpose
assertEquals(X.numRows(), X.numCols());
assertMatrixEqual(X, X.transpose());
// Verify that this is a solution to the DARE.
SimpleMatrix Y = A.transpose().mult(X).mult(A)
.minus(X)
.minus(A.transpose().mult(X).mult(B)
.mult(((B.transpose().mult(X).mult(B)).plus(R))
.invert()).mult(B.transpose()).mult(X).mult(A))
.plus(Q);
assertMatrixEqual(Y, new SimpleMatrix(Y.numRows(), Y.numCols()));
return true;
}
@Test
public void testDiscreteAlgebraicRicattiEquation() {
int n1 = 4;
int m1 = 1;
// we know from Scipy that this should be [[0.05048525 0.10097051 0.20194102 0.40388203]]
SimpleMatrix A1 = new SimpleMatrix(n1, n1, true, new double[]{0.5, 1, 0, 0, 0, 0, 1,
0, 0, 0, 0, 1, 0, 0, 0, 0}).transpose();
SimpleMatrix B1 = new SimpleMatrix(n1, m1, true, new double[]{0, 0, 0, 1});
SimpleMatrix Q1 = new SimpleMatrix(n1, n1, true, new double[]{1, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0});
SimpleMatrix R1 = new SimpleMatrix(m1, m1, true, new double[]{0.25});
assertTrue(solveDAREandVerify(A1, B1, Q1, R1));
SimpleMatrix A2 = new SimpleMatrix(2, 2, true, new double[]{1, 1, 0, 1});
SimpleMatrix B2 = new SimpleMatrix(2, 1, true, new double[]{0, 1});
SimpleMatrix Q2 = new SimpleMatrix(2, 2, true, new double[]{1, 0, 0, 0});
SimpleMatrix R2 = new SimpleMatrix(1, 1, true, new double[]{0.3});
assertTrue(solveDAREandVerify(A2, B2, Q2, R2));
}
}

View File

@@ -0,0 +1,76 @@
#include "drake/math/discrete_algebraic_riccati_equation.h"
#include <Eigen/Core>
#include <Eigen/Eigenvalues>
#include <gtest/gtest.h>
#include "drake/common/test_utilities/eigen_matrix_compare.h"
#include "drake/math/autodiff.h"
using Eigen::MatrixXd;
namespace drake {
namespace math {
namespace {
void SolveDAREandVerify(const Eigen::Ref<const MatrixXd>& A,
const Eigen::Ref<const MatrixXd>& B,
const Eigen::Ref<const MatrixXd>& Q,
const Eigen::Ref<const MatrixXd>& R) {
MatrixXd X = DiscreteAlgebraicRiccatiEquation(A, B, Q, R);
// Check that X is positive semi-definite.
EXPECT_TRUE(
CompareMatrices(X, X.transpose(), 1E-10, MatrixCompareType::absolute));
int n = X.rows();
Eigen::SelfAdjointEigenSolver<MatrixXd> es(X);
for (int i = 0; i < n; i++) {
EXPECT_GE(es.eigenvalues()[i], 0);
}
// Check that X is the solution to the discrete time ARE.
MatrixXd Y = A.transpose() * X * A - X -
A.transpose() * X * B * (B.transpose() * X * B + R).inverse() *
B.transpose() * X * A +
Q;
EXPECT_TRUE(CompareMatrices(Y, MatrixXd::Zero(n, n), 1E-10,
MatrixCompareType::absolute));
}
GTEST_TEST(DARE, SolveDAREandVerify) {
// Test 1: non-invertible A
// Example 2 of "On the Numerical Solution of the Discrete-Time Algebraic
// Riccati Equation"
int n1 = 4, m1 = 1;
MatrixXd A1(n1, n1), B1(n1, m1), Q1(n1, n1), R1(m1, m1);
A1 << 0.5, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0;
B1 << 0, 0, 0, 1;
Q1 << 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
R1 << 0.25;
SolveDAREandVerify(A1, B1, Q1, R1);
// Test 2: invertible A
int n2 = 2, m2 = 1;
MatrixXd A2(n2, n2), B2(n2, m2), Q2(n2, n2), R2(m2, m2);
A2 << 1, 1, 0, 1;
B2 << 0, 1;
Q2 << 1, 0, 0, 0;
R2 << 0.3;
SolveDAREandVerify(A2, B2, Q2, R2);
// Test 3: the first generalized eigenvalue of (S,T) is stable
int n3 = 2, m3 = 1;
MatrixXd A3(n3, n3), B3(n3, m3), Q3(n3, n3), R3(m3, m3);
A3 << 0, 1, 0, 0;
B3 << 0, 1;
Q3 << 1, 0, 0, 1;
R3 << 1;
SolveDAREandVerify(A3, B3, Q3, R3);
// Test 4: A = B = Q = R = I_2 (2-by-2 identity matrix)
int n4 = 2, m4 = 2;
MatrixXd A4(n4, n4), B4(n4, m4), Q4(n4, n4), R4(m4, m4);
A4 << 1, 0, 0, 1;
B4 << 1, 0, 0, 1;
Q4 << 1, 0, 0, 1;
R4 << 1, 0, 0, 1;
SolveDAREandVerify(A4, B4, Q4, R4);
}
} // namespace
} // namespace math
} // namespace drake

View File

@@ -0,0 +1,34 @@
#pragma once
/// @file This header provides a single inclusion point for autodiff-related
/// header files in the `drake/common` directory. Users should include this
/// file. Including other individual headers such as `drake/common/autodiffxd.h`
/// will generate a compile-time warning.
// In each header included below, it asserts that this macro
// `DRAKE_COMMON_AUTODIFF_HEADER` is defined. If the macro is not defined, it
// generates diagnostic warning messages.
#define DRAKE_COMMON_AUTODIFF_HEADER
#include <Eigen/Core>
#include <unsupported/Eigen/AutoDiff>
static_assert(EIGEN_VERSION_AT_LEAST(3, 3, 3),
"Drake requires Eigen >= v3.3.3.");
// Do not alpha-sort the following block of hard-coded #includes, which is
// protected by `clang-format on/off`.
//
// Rationale: We want to maximize the use of this header, `autodiff.h`, even
// inside of the autodiff-related files to avoid any mistakes which might not be
// detected. By centralizing the list here, we make sure that everyone will see
// the correct order which respects the inter-dependencies of the autodiff
// headers. This shields us from triggering undefined behaviors due to
// order-of-specialization-includes-changed mistakes.
//
// clang-format off
#include "drake/common/eigen_autodiff_limits.h"
#include "drake/common/eigen_autodiff_types.h"
#include "drake/common/autodiffxd.h"
#include "drake/common/autodiff_overloads.h"
// clang-format on
#undef DRAKE_COMMON_AUTODIFF_HEADER

View File

@@ -0,0 +1,203 @@
/// @file
/// Overloads for STL mathematical operations on AutoDiffScalar.
///
/// Used via argument-dependent lookup (ADL). These functions appear
/// in the Eigen namespace so that ADL can automatically choose between
/// the STL version and the overloaded version to match the type of the
/// arguments. The proper use would be e.g.
///
/// \code{.cc}
/// void mymethod() {
/// using std::isinf;
/// isinf(myval);
/// }
/// \endcode{}
///
/// @note The if_then_else and cond functions for AutoDiffScalar are in
/// namespace drake because cond is defined in namespace drake in
/// "drake/common/cond.h" file.
#pragma once
#ifndef DRAKE_COMMON_AUTODIFF_HEADER
// TODO(soonho-tri): Change to #error.
#warning Do not directly include this file. Include "drake/common/autodiff.h".
#endif
#include <cmath>
#include <limits>
#include "drake/common/cond.h"
#include "drake/common/drake_assert.h"
#include "drake/common/dummy_value.h"
namespace Eigen {
/// Overloads nexttoward to mimic std::nexttoward from <cmath>.
template <typename DerType>
double nexttoward(const Eigen::AutoDiffScalar<DerType>& from, long double to) {
using std::nexttoward;
return nexttoward(from.value(), to);
}
/// Overloads round to mimic std::round from <cmath>.
template <typename DerType>
double round(const Eigen::AutoDiffScalar<DerType>& x) {
using std::round;
return round(x.value());
}
/// Overloads isinf to mimic std::isinf from <cmath>.
template <typename DerType>
bool isinf(const Eigen::AutoDiffScalar<DerType>& x) {
using std::isinf;
return isinf(x.value());
}
/// Overloads isfinite to mimic std::isfinite from <cmath>.
template <typename DerType>
bool isfinite(const Eigen::AutoDiffScalar<DerType>& x) {
using std::isfinite;
return isfinite(x.value());
}
/// Overloads isnan to mimic std::isnan from <cmath>.
template <typename DerType>
bool isnan(const Eigen::AutoDiffScalar<DerType>& x) {
using std::isnan;
return isnan(x.value());
}
/// Overloads floor to mimic std::floor from <cmath>.
template <typename DerType>
double floor(const Eigen::AutoDiffScalar<DerType>& x) {
using std::floor;
return floor(x.value());
}
/// Overloads ceil to mimic std::ceil from <cmath>.
template <typename DerType>
double ceil(const Eigen::AutoDiffScalar<DerType>& x) {
using std::ceil;
return ceil(x.value());
}
/// Overloads copysign from <cmath>.
template <typename DerType, typename T>
Eigen::AutoDiffScalar<DerType> copysign(const Eigen::AutoDiffScalar<DerType>& x,
const T& y) {
using std::isnan;
if (isnan(x)) return (y >= 0) ? NAN : -NAN;
if ((x < 0 && y >= 0) || (x >= 0 && y < 0))
return -x;
else
return x;
}
/// Overloads copysign from <cmath>.
template <typename DerType>
double copysign(double x, const Eigen::AutoDiffScalar<DerType>& y) {
using std::isnan;
if (isnan(x)) return (y >= 0) ? NAN : -NAN;
if ((x < 0 && y >= 0) || (x >= 0 && y < 0))
return -x;
else
return x;
}
/// Overloads pow for an AutoDiffScalar base and exponent, implementing the
/// chain rule.
template <typename DerTypeA, typename DerTypeB>
Eigen::AutoDiffScalar<
typename internal::remove_all<DerTypeA>::type::PlainObject>
pow(const Eigen::AutoDiffScalar<DerTypeA>& base,
const Eigen::AutoDiffScalar<DerTypeB>& exponent) {
// The two AutoDiffScalars being exponentiated must have the same matrix
// type. This includes, but is not limited to, the same scalar type and
// the same dimension.
static_assert(
std::is_same<
typename internal::remove_all<DerTypeA>::type::PlainObject,
typename internal::remove_all<DerTypeB>::type::PlainObject>::value,
"The derivative types must match.");
internal::make_coherent(base.derivatives(), exponent.derivatives());
const auto& x = base.value();
const auto& xgrad = base.derivatives();
const auto& y = exponent.value();
const auto& ygrad = exponent.derivatives();
using std::pow;
using std::log;
const auto x_to_the_y = pow(x, y);
if (ygrad.isZero(std::numeric_limits<double>::epsilon()) ||
ygrad.size() == 0) {
// The derivative only depends on ∂(x^y)/∂x -- this prevents undefined
// behavior in the corner case where ∂(x^y)/∂y is infinite when x = 0,
// despite ∂y/∂v being 0.
return Eigen::MakeAutoDiffScalar(x_to_the_y, y * pow(x, y - 1) * xgrad);
}
return Eigen::MakeAutoDiffScalar(
// The value is x ^ y.
x_to_the_y,
// The multivariable chain rule states:
// df/dv_i = (∂f/∂x * dx/dv_i) + (∂f/∂y * dy/dv_i)
// ∂f/∂x is y*x^(y-1)
y * pow(x, y - 1) * xgrad +
// ∂f/∂y is (x^y)*ln(x)
x_to_the_y * log(x) * ygrad);
}
} // namespace Eigen
namespace drake {
/// Returns the autodiff scalar's value() as a double. Never throws.
/// Overloads ExtractDoubleOrThrow from common/extract_double.h.
template <typename DerType>
double ExtractDoubleOrThrow(const Eigen::AutoDiffScalar<DerType>& scalar) {
return static_cast<double>(scalar.value());
}
/// Specializes common/dummy_value.h.
template <typename DerType>
struct dummy_value<Eigen::AutoDiffScalar<DerType>> {
static constexpr Eigen::AutoDiffScalar<DerType> get() {
constexpr double kNaN = std::numeric_limits<double>::quiet_NaN();
DerType derivatives;
derivatives.fill(kNaN);
return Eigen::AutoDiffScalar<DerType>(kNaN, derivatives);
}
};
/// Provides if-then-else expression for Eigen::AutoDiffScalar type. To support
/// Eigen's generic expressions, we use casting to the plain object after
/// applying Eigen::internal::remove_all. It is based on the Eigen's
/// implementation of min/max function for AutoDiffScalar type
/// (https://bitbucket.org/eigen/eigen/src/10a1de58614569c9250df88bdfc6402024687bc6/unsupported/Eigen/src/AutoDiff/AutoDiffScalar.h?at=default&fileviewer=file-view-default#AutoDiffScalar.h-546).
template <typename DerType1, typename DerType2>
inline Eigen::AutoDiffScalar<
typename Eigen::internal::remove_all<DerType1>::type::PlainObject>
if_then_else(bool f_cond, const Eigen::AutoDiffScalar<DerType1>& x,
const Eigen::AutoDiffScalar<DerType2>& y) {
typedef Eigen::AutoDiffScalar<
typename Eigen::internal::remove_all<DerType1>::type::PlainObject>
ADS1;
typedef Eigen::AutoDiffScalar<
typename Eigen::internal::remove_all<DerType2>::type::PlainObject>
ADS2;
static_assert(std::is_same<ADS1, ADS2>::value,
"The derivative types must match.");
return f_cond ? ADS1(x) : ADS2(y);
}
/// Provides special case of cond expression for Eigen::AutoDiffScalar type.
template <typename DerType, typename... Rest>
Eigen::AutoDiffScalar<
typename Eigen::internal::remove_all<DerType>::type::PlainObject>
cond(bool f_cond, const Eigen::AutoDiffScalar<DerType>& e_then, Rest... rest) {
return if_then_else(f_cond, e_then, cond(rest...));
}
} // namespace drake

View File

@@ -0,0 +1,423 @@
#pragma once
// This file is a modification of Eigen-3.3.3's AutoDiffScalar.h file which is
// available at
// https://bitbucket.org/eigen/eigen/raw/67e894c6cd8f5f1f604b27d37ed47fdf012674ff/unsupported/Eigen/src/AutoDiff/AutoDiffScalar.h
//
// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
// Copyright (C) 2017 Drake Authors
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef DRAKE_COMMON_AUTODIFF_HEADER
// TODO(soonho-tri): Change to #error.
#warning Do not directly include this file. Include "drake/common/autodiff.h".
#endif
#include <cmath>
#include <ostream>
#include <Eigen/Core>
namespace Eigen {
#if !defined(DRAKE_DOXYGEN_CXX)
// Explicit template specializations of Eigen::AutoDiffScalar for VectorXd.
//
// AutoDiffScalar tries to call internal::make_coherent to promote empty
// derivatives. However, it fails to do the promotion when an operand is an
// expression tree (i.e. CwiseBinaryOp). Our solution is to provide special
// overloading for VectorXd and change the return types of its operators. With
// this change, the operators evaluate terms immediately and return an
// AutoDiffScalar<VectorXd> instead of expression trees (such as CwiseBinaryOp).
// Eigen's implementation of internal::make_coherent makes use of const_cast in
// order to promote zero sized derivatives. This however interferes badly with
// our caching system and produces unexpected behaviors. See #10971 for details.
// Therefore our implementation stops using internal::make_coherent and treats
// scalars with zero sized derivatives as constants, as it should.
//
// We also provide overloading of math functions for AutoDiffScalar<VectorXd>
// which return AutoDiffScalar<VectorXd> instead of an expression tree.
//
// See https://github.com/RobotLocomotion/drake/issues/6944 for more
// information. See also drake/common/autodiff_overloads.h.
//
// TODO(soonho-tri): Next time when we upgrade Eigen, please check if we still
// need these specializations.
template <>
class AutoDiffScalar<VectorXd>
: public internal::auto_diff_special_op<VectorXd, false> {
public:
typedef internal::auto_diff_special_op<VectorXd, false> Base;
typedef typename internal::remove_all<VectorXd>::type DerType;
typedef typename internal::traits<DerType>::Scalar Scalar;
typedef typename NumTraits<Scalar>::Real Real;
using Base::operator+;
using Base::operator*;
AutoDiffScalar() {}
AutoDiffScalar(const Scalar& value, int nbDer, int derNumber)
: m_value(value), m_derivatives(DerType::Zero(nbDer)) {
m_derivatives.coeffRef(derNumber) = Scalar(1);
}
// NOLINTNEXTLINE(runtime/explicit): Code from Eigen.
AutoDiffScalar(const Real& value) : m_value(value) {
if (m_derivatives.size() > 0) m_derivatives.setZero();
}
AutoDiffScalar(const Scalar& value, const DerType& der)
: m_value(value), m_derivatives(der) {}
template <typename OtherDerType>
AutoDiffScalar(
const AutoDiffScalar<OtherDerType>& other
#ifndef EIGEN_PARSED_BY_DOXYGEN
,
typename internal::enable_if<
internal::is_same<
Scalar, typename internal::traits<typename internal::remove_all<
OtherDerType>::type>::Scalar>::value,
void*>::type = 0
#endif
)
: m_value(other.value()), m_derivatives(other.derivatives()) {
}
friend std::ostream& operator<<(std::ostream& s, const AutoDiffScalar& a) {
return s << a.value();
}
AutoDiffScalar(const AutoDiffScalar& other)
: m_value(other.value()), m_derivatives(other.derivatives()) {}
template <typename OtherDerType>
inline AutoDiffScalar& operator=(const AutoDiffScalar<OtherDerType>& other) {
m_value = other.value();
m_derivatives = other.derivatives();
return *this;
}
inline AutoDiffScalar& operator=(const AutoDiffScalar& other) {
m_value = other.value();
m_derivatives = other.derivatives();
return *this;
}
inline AutoDiffScalar& operator=(const Scalar& other) {
m_value = other;
if (m_derivatives.size() > 0) m_derivatives.setZero();
return *this;
}
inline const Scalar& value() const { return m_value; }
inline Scalar& value() { return m_value; }
inline const DerType& derivatives() const { return m_derivatives; }
inline DerType& derivatives() { return m_derivatives; }
inline bool operator<(const Scalar& other) const { return m_value < other; }
inline bool operator<=(const Scalar& other) const { return m_value <= other; }
inline bool operator>(const Scalar& other) const { return m_value > other; }
inline bool operator>=(const Scalar& other) const { return m_value >= other; }
inline bool operator==(const Scalar& other) const { return m_value == other; }
inline bool operator!=(const Scalar& other) const { return m_value != other; }
friend inline bool operator<(const Scalar& a, const AutoDiffScalar& b) {
return a < b.value();
}
friend inline bool operator<=(const Scalar& a, const AutoDiffScalar& b) {
return a <= b.value();
}
friend inline bool operator>(const Scalar& a, const AutoDiffScalar& b) {
return a > b.value();
}
friend inline bool operator>=(const Scalar& a, const AutoDiffScalar& b) {
return a >= b.value();
}
friend inline bool operator==(const Scalar& a, const AutoDiffScalar& b) {
return a == b.value();
}
friend inline bool operator!=(const Scalar& a, const AutoDiffScalar& b) {
return a != b.value();
}
template <typename OtherDerType>
inline bool operator<(const AutoDiffScalar<OtherDerType>& b) const {
return m_value < b.value();
}
template <typename OtherDerType>
inline bool operator<=(const AutoDiffScalar<OtherDerType>& b) const {
return m_value <= b.value();
}
template <typename OtherDerType>
inline bool operator>(const AutoDiffScalar<OtherDerType>& b) const {
return m_value > b.value();
}
template <typename OtherDerType>
inline bool operator>=(const AutoDiffScalar<OtherDerType>& b) const {
return m_value >= b.value();
}
template <typename OtherDerType>
inline bool operator==(const AutoDiffScalar<OtherDerType>& b) const {
return m_value == b.value();
}
template <typename OtherDerType>
inline bool operator!=(const AutoDiffScalar<OtherDerType>& b) const {
return m_value != b.value();
}
inline const AutoDiffScalar<DerType> operator+(const Scalar& other) const {
return AutoDiffScalar<DerType>(m_value + other, m_derivatives);
}
friend inline const AutoDiffScalar<DerType> operator+(
const Scalar& a, const AutoDiffScalar& b) {
return AutoDiffScalar<DerType>(a + b.value(), b.derivatives());
}
inline AutoDiffScalar& operator+=(const Scalar& other) {
value() += other;
return *this;
}
template <typename OtherDerType>
inline const AutoDiffScalar<DerType> operator+(
const AutoDiffScalar<OtherDerType>& other) const {
const bool has_this_der = m_derivatives.size() > 0;
const bool has_both_der = has_this_der && (other.derivatives().size() > 0);
return MakeAutoDiffScalar(
m_value + other.value(),
has_both_der
? VectorXd(m_derivatives + other.derivatives())
: has_this_der ? m_derivatives : VectorXd(other.derivatives()));
}
template <typename OtherDerType>
inline AutoDiffScalar& operator+=(const AutoDiffScalar<OtherDerType>& other) {
(*this) = (*this) + other;
return *this;
}
inline const AutoDiffScalar<DerType> operator-(const Scalar& b) const {
return AutoDiffScalar<DerType>(m_value - b, m_derivatives);
}
friend inline const AutoDiffScalar<DerType> operator-(
const Scalar& a, const AutoDiffScalar& b) {
return AutoDiffScalar<DerType>(a - b.value(), -b.derivatives());
}
inline AutoDiffScalar& operator-=(const Scalar& other) {
value() -= other;
return *this;
}
template <typename OtherDerType>
inline const AutoDiffScalar<DerType> operator-(
const AutoDiffScalar<OtherDerType>& other) const {
const bool has_this_der = m_derivatives.size() > 0;
const bool has_both_der = has_this_der && (other.derivatives().size() > 0);
return MakeAutoDiffScalar(
m_value - other.value(),
has_both_der
? VectorXd(m_derivatives - other.derivatives())
: has_this_der ? m_derivatives : VectorXd(-other.derivatives()));
}
template <typename OtherDerType>
inline AutoDiffScalar& operator-=(const AutoDiffScalar<OtherDerType>& other) {
*this = *this - other;
return *this;
}
inline const AutoDiffScalar<DerType> operator-() const {
return AutoDiffScalar<DerType>(-m_value, -m_derivatives);
}
inline const AutoDiffScalar<DerType> operator*(const Scalar& other) const {
return MakeAutoDiffScalar(m_value * other, m_derivatives * other);
}
friend inline const AutoDiffScalar<DerType> operator*(
const Scalar& other, const AutoDiffScalar& a) {
return MakeAutoDiffScalar(a.value() * other, a.derivatives() * other);
}
inline const AutoDiffScalar<DerType> operator/(const Scalar& other) const {
return MakeAutoDiffScalar(m_value / other,
(m_derivatives * (Scalar(1) / other)));
}
friend inline const AutoDiffScalar<DerType> operator/(
const Scalar& other, const AutoDiffScalar& a) {
return MakeAutoDiffScalar(
other / a.value(),
a.derivatives() * (Scalar(-other) / (a.value() * a.value())));
}
template <typename OtherDerType>
inline const AutoDiffScalar<DerType> operator/(
const AutoDiffScalar<OtherDerType>& other) const {
const auto& this_der = m_derivatives;
const auto& other_der = other.derivatives();
const bool has_this_der = m_derivatives.size() > 0;
const bool has_both_der = has_this_der && (other.derivatives().size() > 0);
const double scale = 1. / (other.value() * other.value());
return MakeAutoDiffScalar(
m_value / other.value(),
has_both_der ?
VectorXd(this_der * other.value() - other_der * m_value) * scale :
has_this_der ?
VectorXd(this_der * other.value()) * scale :
// has_other_der || has_neither
VectorXd(other_der * -m_value) * scale);
}
template <typename OtherDerType>
inline const AutoDiffScalar<DerType> operator*(
const AutoDiffScalar<OtherDerType>& other) const {
const bool has_this_der = m_derivatives.size() > 0;
const bool has_both_der = has_this_der && (other.derivatives().size() > 0);
return MakeAutoDiffScalar(
m_value * other.value(),
has_both_der ? VectorXd(m_derivatives * other.value() +
other.derivatives() * m_value)
: has_this_der ? VectorXd(m_derivatives * other.value())
: VectorXd(other.derivatives() * m_value));
}
inline AutoDiffScalar& operator*=(const Scalar& other) {
*this = *this * other;
return *this;
}
template <typename OtherDerType>
inline AutoDiffScalar& operator*=(const AutoDiffScalar<OtherDerType>& other) {
*this = *this * other;
return *this;
}
inline AutoDiffScalar& operator/=(const Scalar& other) {
*this = *this / other;
return *this;
}
template <typename OtherDerType>
inline AutoDiffScalar& operator/=(const AutoDiffScalar<OtherDerType>& other) {
*this = *this / other;
return *this;
}
protected:
Scalar m_value;
DerType m_derivatives;
};
#define DRAKE_EIGEN_AUTODIFFXD_DECLARE_GLOBAL_UNARY(FUNC, CODE) \
inline const AutoDiffScalar<VectorXd> FUNC( \
const AutoDiffScalar<VectorXd>& x) { \
EIGEN_UNUSED typedef double Scalar; \
CODE; \
}
DRAKE_EIGEN_AUTODIFFXD_DECLARE_GLOBAL_UNARY(
abs, using std::abs; return Eigen::MakeAutoDiffScalar(
abs(x.value()), x.derivatives() * (x.value() < 0 ? -1 : 1));)
DRAKE_EIGEN_AUTODIFFXD_DECLARE_GLOBAL_UNARY(
abs2, using numext::abs2; return Eigen::MakeAutoDiffScalar(
abs2(x.value()), x.derivatives() * (Scalar(2) * x.value()));)
DRAKE_EIGEN_AUTODIFFXD_DECLARE_GLOBAL_UNARY(
sqrt, using std::sqrt; Scalar sqrtx = sqrt(x.value());
return Eigen::MakeAutoDiffScalar(sqrtx,
x.derivatives() * (Scalar(0.5) / sqrtx));)
DRAKE_EIGEN_AUTODIFFXD_DECLARE_GLOBAL_UNARY(
cos, using std::cos; using std::sin;
return Eigen::MakeAutoDiffScalar(cos(x.value()),
x.derivatives() * (-sin(x.value())));)
DRAKE_EIGEN_AUTODIFFXD_DECLARE_GLOBAL_UNARY(
sin, using std::sin; using std::cos;
return Eigen::MakeAutoDiffScalar(sin(x.value()),
x.derivatives() * cos(x.value()));)
DRAKE_EIGEN_AUTODIFFXD_DECLARE_GLOBAL_UNARY(
exp, using std::exp; Scalar expx = exp(x.value());
return Eigen::MakeAutoDiffScalar(expx, x.derivatives() * expx);)
DRAKE_EIGEN_AUTODIFFXD_DECLARE_GLOBAL_UNARY(
log, using std::log; return Eigen::MakeAutoDiffScalar(
log(x.value()), x.derivatives() * (Scalar(1) / x.value()));)
DRAKE_EIGEN_AUTODIFFXD_DECLARE_GLOBAL_UNARY(
tan, using std::tan; using std::cos; return Eigen::MakeAutoDiffScalar(
tan(x.value()),
x.derivatives() * (Scalar(1) / numext::abs2(cos(x.value()))));)
DRAKE_EIGEN_AUTODIFFXD_DECLARE_GLOBAL_UNARY(
asin, using std::sqrt; using std::asin; return Eigen::MakeAutoDiffScalar(
asin(x.value()),
x.derivatives() * (Scalar(1) / sqrt(1 - numext::abs2(x.value()))));)
DRAKE_EIGEN_AUTODIFFXD_DECLARE_GLOBAL_UNARY(
acos, using std::sqrt; using std::acos; return Eigen::MakeAutoDiffScalar(
acos(x.value()),
x.derivatives() * (Scalar(-1) / sqrt(1 - numext::abs2(x.value()))));)
DRAKE_EIGEN_AUTODIFFXD_DECLARE_GLOBAL_UNARY(
atan, using std::atan; return Eigen::MakeAutoDiffScalar(
atan(x.value()),
x.derivatives() * (Scalar(1) / (1 + x.value() * x.value())));)
DRAKE_EIGEN_AUTODIFFXD_DECLARE_GLOBAL_UNARY(
tanh, using std::cosh; using std::tanh; return Eigen::MakeAutoDiffScalar(
tanh(x.value()),
x.derivatives() * (Scalar(1) / numext::abs2(cosh(x.value()))));)
DRAKE_EIGEN_AUTODIFFXD_DECLARE_GLOBAL_UNARY(
sinh, using std::sinh; using std::cosh;
return Eigen::MakeAutoDiffScalar(sinh(x.value()),
x.derivatives() * cosh(x.value()));)
DRAKE_EIGEN_AUTODIFFXD_DECLARE_GLOBAL_UNARY(
cosh, using std::sinh; using std::cosh;
return Eigen::MakeAutoDiffScalar(cosh(x.value()),
x.derivatives() * sinh(x.value()));)
#undef DRAKE_EIGEN_AUTODIFFXD_DECLARE_GLOBAL_UNARY
// We have this specialization here because the Eigen-3.3.3's atan2
// implementation for AutoDiffScalar does not make a return with properly sized
// derivatives.
inline const AutoDiffScalar<VectorXd> atan2(const AutoDiffScalar<VectorXd>& a,
const AutoDiffScalar<VectorXd>& b) {
const bool has_a_der = a.derivatives().size() > 0;
const bool has_both_der = has_a_der && (b.derivatives().size() > 0);
const double squared_hypot = a.value() * a.value() + b.value() * b.value();
return MakeAutoDiffScalar(
std::atan2(a.value(), b.value()),
VectorXd((has_both_der
? VectorXd(a.derivatives() * b.value() -
a.value() * b.derivatives())
: has_a_der ? VectorXd(a.derivatives() * b.value())
: VectorXd(-a.value() * b.derivatives())) /
squared_hypot));
}
inline const AutoDiffScalar<VectorXd> pow(const AutoDiffScalar<VectorXd>& a,
double b) {
using std::pow;
return MakeAutoDiffScalar(pow(a.value(), b),
a.derivatives() * (b * pow(a.value(), b - 1)));
}
#endif
} // namespace Eigen

View File

@@ -0,0 +1,44 @@
#pragma once
#include <functional>
#include <type_traits>
#include "drake/common/double_overloads.h"
namespace drake {
/** @name cond
Constructs conditional expression (similar to Lisp's cond).
@verbatim
cond(cond_1, expr_1,
cond_2, expr_2,
..., ...,
cond_n, expr_n,
expr_{n+1})
@endverbatim
The value returned by the above cond expression is @c expr_1 if @c cond_1 is
true; else if @c cond_2 is true then @c expr_2; ... ; else if @c cond_n is
true then @c expr_n. If none of the conditions are true, it returns @c
expr_{n+1}.
@note This functions assumes that @p ScalarType provides @c operator< and the
type of @c f_cond is the type of the return type of <tt>operator<(ScalarType,
ScalarType)</tt>. For example, @c symbolic::Expression can be used as a @p
ScalarType because it provides <tt>symbolic::Formula
operator<(symbolic::Expression, symbolic::Expression)</tt>.
@{
*/
template <typename ScalarType>
ScalarType cond(const ScalarType& e) {
return e;
}
template <typename ScalarType, typename... Rest>
ScalarType cond(const decltype(ScalarType() < ScalarType()) & f_cond,
const ScalarType& e_then, Rest... rest) {
return if_then_else(f_cond, e_then, cond(rest...));
}
///@}
} // namespace drake

View File

@@ -0,0 +1,19 @@
#pragma once
namespace drake {
constexpr int kQuaternionSize = 4;
constexpr int kSpaceDimension = 3;
constexpr int kRpySize = 3;
/// https://en.wikipedia.org/wiki/Screw_theory#Twist
constexpr int kTwistSize = 6;
/// http://www.euclideanspace.com/maths/geometry/affine/matrix4x4/
constexpr int kHomogeneousTransformSize = 16;
const int kRotmatSize = kSpaceDimension * kSpaceDimension;
} // namespace drake

View File

@@ -0,0 +1,21 @@
/// @file
/// Provides necessary operations on double to have it as a ScalarType in drake.
#pragma once
namespace drake {
/// Provides if-then-else expression for double. The value returned by the
/// if-then-else expression is @p v_then if @p f_cond is @c true. Otherwise, it
/// returns @p v_else.
/// The semantics is similar but not exactly the same as C++'s conditional
/// expression constructed by its ternary operator, @c ?:. In
/// <tt>if_then_else(f_cond, v_then, v_else)</tt>, both of @p v_then and @p
/// v_else are evaluated regardless of the evaluation of @p f_cond. In contrast,
/// only one of @p v_then or @p v_else is evaluated in C++'s conditional
/// expression <tt>f_cond ? v_then : v_else</tt>.
inline double if_then_else(bool f_cond, double v_then, double v_else) {
return f_cond ? v_then : v_else;
}
} // namespace drake

View File

@@ -0,0 +1,65 @@
#pragma once
/** @file
Provides a portable macro for use in generating compile-time warnings for
use of code that is permitted but discouraged. */
#ifdef DRAKE_DOXYGEN_CXX
/** Use `DRAKE_DEPRECATED("removal_date", "message")` to discourage use of
certain APIs. It can be used on classes, typedefs, variables, non-static data
members, functions, arguments, enumerations, and template specializations. When
code refers to the deprecated item, a compile time warning will be issued
displaying the given message, preceded by "DRAKE DEPRECATED: ". The Doxygen API
reference will show that the API is deprecated, along with the message.
This is typically used for constructs that have been replaced by something
better and it is good practice to suggest the appropriate replacement in the
deprecation message. Deprecation warnings are conventionally used to convey to
users that a feature they are depending on will be removed in a future release.
Every deprecation notice must include a date (as YYYY-MM-DD string) where the
deprecated item is planned for removal. Future commits may change the date
(e.g., delaying the removal) but should generally always reflect the best
current expectation for removal.
Absent any other particular need, we prefer to use a deprecation period of
three months by default, often rounded up to the next first of the month. So
for code announced as deprecated on 2018-01-22 the removal_date would nominally
be set to 2018-05-01.
Try to keep the date string immediately after the DRAKE_DEPRECATED macro name,
even if the message itself must be wrapped to a new line:
@code
DRAKE_DEPRECATED("2038-01-19",
"foo is being replaced with a safer, const-method named bar().")
int foo();
@endcode
Sample uses: @code
// Attribute comes *before* declaration of a deprecated function or variable;
// no semicolon is allowed.
DRAKE_DEPRECATED("2038-01-19", "f() is slow; use g() instead.")
int f(int arg);
// Attribute comes *after* struct, class, enum keyword.
class DRAKE_DEPRECATED("2038-01-19", "Use MyNewClass instead.")
MyClass {
};
// Type alias goes before the '='.
using NewType
DRAKE_DEPRECATED("2038-01-19", "Use NewType instead.")
= OldType;
@endcode
*/
#define DRAKE_DEPRECATED(removal_date, message)
#else // DRAKE_DOXYGEN_CXX
#define DRAKE_DEPRECATED(removal_date, message) \
[[deprecated( \
"\nDRAKE DEPRECATED: " message \
"\nThe deprecated code will be removed from Drake" \
" on or after " removal_date ".")]]
#endif // DRAKE_DOXYGEN_CXX

View File

@@ -0,0 +1,13 @@
#pragma once
// TODO(jwnimmer-tri) Once we are in --std=c++17 mode as our minimum version,
// we can remove this file and just say [[nodiscard]] directly everywhere.
#if defined(DRAKE_DOXYGEN_CXX) || __has_cpp_attribute(nodiscard)
/** Synonym for [[nodiscard]], iff the current compiler supports it;
see https://en.cppreference.com/w/cpp/language/attributes/nodiscard. */
// NOLINTNEXTLINE(whitespace/braces)
#define DRAKE_NODISCARD [[nodiscard]]
#else
#define DRAKE_NODISCARD
#endif

View File

@@ -0,0 +1,35 @@
#pragma once
#include <limits>
namespace drake {
/// Provides a "dummy" value for a ScalarType -- a value that is unlikely to be
/// mistaken for a purposefully-computed value, useful for initializing a value
/// before the true result is available.
///
/// Defaults to using std::numeric_limits::quiet_NaN when available; it is a
/// compile-time error to call the unspecialized dummy_value::get() when
/// quiet_NaN is unavailable.
///
/// See autodiff_overloads.h to use this with Eigen's AutoDiffScalar.
template <typename T>
struct dummy_value {
static constexpr T get() {
static_assert(std::numeric_limits<T>::has_quiet_NaN,
"Custom scalar types should specialize this struct");
return std::numeric_limits<T>::quiet_NaN();
}
};
template <>
struct dummy_value<int> {
static constexpr int get() {
// D is for "Dummy". We assume as least 32 bits (per cppguide) -- if `int`
// is larger than 32 bits, this will leave some fraction of the bytes zero
// instead of 0xDD, but that's okay.
return 0xDDDDDDDD;
}
};
} // namespace drake

View File

@@ -0,0 +1,20 @@
#pragma once
#ifndef DRAKE_COMMON_AUTODIFF_HEADER
// TODO(soonho-tri): Change to #error.
#warning Do not directly include this file. Include "drake/common/autodiff.h".
#endif
#include <limits>
// Eigen provides `numeric_limits<AutoDiffScalar<T>>` starting with v3.3.4.
#if !EIGEN_VERSION_AT_LEAST(3, 3, 4) // Eigen Version < v3.3.4
namespace std {
template <typename T>
class numeric_limits<Eigen::AutoDiffScalar<T>>
: public numeric_limits<typename T::Scalar> {};
} // namespace std
#endif // Eigen Version < v3.3.4

View File

@@ -0,0 +1,38 @@
#pragma once
/// @file
/// This file contains abbreviated definitions for certain uses of
/// AutoDiffScalar that are commonly used in Drake.
/// @see also eigen_types.h
#ifndef DRAKE_COMMON_AUTODIFF_HEADER
// TODO(soonho-tri): Change to #error.
#warning Do not directly include this file. Include "drake/common/autodiff.h".
#endif
#include <type_traits>
#include <Eigen/Core>
#include "drake/common/eigen_types.h"
namespace drake {
/// An autodiff variable with a dynamic number of partials.
using AutoDiffXd = Eigen::AutoDiffScalar<Eigen::VectorXd>;
// TODO(hongkai-dai): Recursive template to get arbitrary gradient order.
/// An autodiff variable with `num_vars` partials.
template <int num_vars>
using AutoDiffd = Eigen::AutoDiffScalar<Eigen::Matrix<double, num_vars, 1> >;
/// A vector of `rows` autodiff variables, each with `num_vars` partials.
template <int num_vars, int rows>
using AutoDiffVecd = Eigen::Matrix<AutoDiffd<num_vars>, rows, 1>;
/// A dynamic-sized vector of autodiff variables, each with a dynamic-sized
/// vector of partials.
typedef AutoDiffVecd<Eigen::Dynamic, Eigen::Dynamic> AutoDiffVecXd;
} // namespace drake

View File

@@ -0,0 +1,461 @@
#pragma once
/// @file
/// This file contains abbreviated definitions for certain specializations of
/// Eigen::Matrix that are commonly used in Drake.
/// These convenient definitions are templated on the scalar type of the Eigen
/// object. While Drake uses `<T>` for scalar types across the entire code base
/// we decided in this file to use `<Scalar>` to be more consistent with the
/// usage of `<Scalar>` in Eigen's code base.
/// @see also eigen_autodiff_types.h
#include <utility>
#include <Eigen/Core>
#include "drake/common/constants.h"
#include "drake/common/drake_assert.h"
#include "drake/common/drake_copyable.h"
#include "drake/common/drake_deprecated.h"
namespace drake {
/// The empty column vector (zero rows, one column), templated on scalar type.
template <typename Scalar>
using Vector0 = Eigen::Matrix<Scalar, 0, 1>;
/// A column vector of size 1 (that is, a scalar), templated on scalar type.
template <typename Scalar>
using Vector1 = Eigen::Matrix<Scalar, 1, 1>;
/// A column vector of size 1 of doubles.
using Vector1d = Eigen::Matrix<double, 1, 1>;
/// A column vector of size 2, templated on scalar type.
template <typename Scalar>
using Vector2 = Eigen::Matrix<Scalar, 2, 1>;
/// A column vector of size 3, templated on scalar type.
template <typename Scalar>
using Vector3 = Eigen::Matrix<Scalar, 3, 1>;
/// A column vector of size 4, templated on scalar type.
template <typename Scalar>
using Vector4 = Eigen::Matrix<Scalar, 4, 1>;
/// A column vector of size 6.
template <typename Scalar>
using Vector6 = Eigen::Matrix<Scalar, 6, 1>;
/// A column vector templated on the number of rows.
template <typename Scalar, int Rows>
using Vector = Eigen::Matrix<Scalar, Rows, 1>;
/// A column vector of any size, templated on scalar type.
template <typename Scalar>
using VectorX = Eigen::Matrix<Scalar, Eigen::Dynamic, 1>;
/// A vector of dynamic size templated on scalar type, up to a maximum of 6
/// elements.
template <typename Scalar>
using VectorUpTo6 = Eigen::Matrix<Scalar, Eigen::Dynamic, 1, 0, 6, 1>;
/// A row vector of size 2, templated on scalar type.
template <typename Scalar>
using RowVector2 = Eigen::Matrix<Scalar, 1, 2>;
/// A row vector of size 3, templated on scalar type.
template <typename Scalar>
using RowVector3 = Eigen::Matrix<Scalar, 1, 3>;
/// A row vector of size 4, templated on scalar type.
template <typename Scalar>
using RowVector4 = Eigen::Matrix<Scalar, 1, 4>;
/// A row vector of size 6.
template <typename Scalar>
using RowVector6 = Eigen::Matrix<Scalar, 1, 6>;
/// A row vector templated on the number of columns.
template <typename Scalar, int Cols>
using RowVector = Eigen::Matrix<Scalar, 1, Cols>;
/// A row vector of any size, templated on scalar type.
template <typename Scalar>
using RowVectorX = Eigen::Matrix<Scalar, 1, Eigen::Dynamic>;
/// A matrix of 2 rows and 2 columns, templated on scalar type.
template <typename Scalar>
using Matrix2 = Eigen::Matrix<Scalar, 2, 2>;
/// A matrix of 3 rows and 3 columns, templated on scalar type.
template <typename Scalar>
using Matrix3 = Eigen::Matrix<Scalar, 3, 3>;
/// A matrix of 4 rows and 4 columns, templated on scalar type.
template <typename Scalar>
using Matrix4 = Eigen::Matrix<Scalar, 4, 4>;
/// A matrix of 6 rows and 6 columns, templated on scalar type.
template <typename Scalar>
using Matrix6 = Eigen::Matrix<Scalar, 6, 6>;
/// A matrix of 2 rows, dynamic columns, templated on scalar type.
template <typename Scalar>
using Matrix2X = Eigen::Matrix<Scalar, 2, Eigen::Dynamic>;
/// A matrix of 3 rows, dynamic columns, templated on scalar type.
template <typename Scalar>
using Matrix3X = Eigen::Matrix<Scalar, 3, Eigen::Dynamic>;
/// A matrix of 4 rows, dynamic columns, templated on scalar type.
template <typename Scalar>
using Matrix4X = Eigen::Matrix<Scalar, 4, Eigen::Dynamic>;
/// A matrix of 6 rows, dynamic columns, templated on scalar type.
template <typename Scalar>
using Matrix6X = Eigen::Matrix<Scalar, 6, Eigen::Dynamic>;
/// A matrix of dynamic size, templated on scalar type.
template <typename Scalar>
using MatrixX = Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>;
/// A matrix of dynamic size templated on scalar type, up to a maximum of 6 rows
/// and 6 columns. Rectangular matrices, with different number of rows and
/// columns, are allowed.
template <typename Scalar>
using MatrixUpTo6 =
Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, 0, 6, 6>;
/// A quaternion templated on scalar type.
template <typename Scalar>
using Quaternion = Eigen::Quaternion<Scalar>;
/// An AngleAxis templated on scalar type.
template <typename Scalar>
using AngleAxis = Eigen::AngleAxis<Scalar>;
/// An Isometry templated on scalar type.
template <typename Scalar>
using Isometry3 = Eigen::Transform<Scalar, 3, Eigen::Isometry>;
/// A translation in 3D templated on scalar type.
template <typename Scalar>
using Translation3 = Eigen::Translation<Scalar, 3>;
/// A column vector consisting of one twist.
template <typename Scalar>
using TwistVector = Eigen::Matrix<Scalar, kTwistSize, 1>;
/// A matrix with one twist per column, and dynamically many columns.
template <typename Scalar>
using TwistMatrix = Eigen::Matrix<Scalar, kTwistSize, Eigen::Dynamic>;
/// A six-by-six matrix.
template <typename Scalar>
using SquareTwistMatrix = Eigen::Matrix<Scalar, kTwistSize, kTwistSize>;
/// A column vector consisting of one wrench (spatial force) = `[r X f; f]`,
/// where f is a force (translational force) applied at a point `P` and `r` is
/// the position vector from a point `O` (called the "moment center") to point
/// `P`.
template <typename Scalar>
using WrenchVector = Eigen::Matrix<Scalar, 6, 1>;
/// A column vector consisting of a concatenated rotational and translational
/// force. The wrench is a special case of a SpatialForce. For a general
/// SpatialForce the rotational force can be a pure torque or the accumulation
/// of moments and need not necessarily be a function of the force term.
template <typename Scalar>
using SpatialForce
DRAKE_DEPRECATED("2019-10-15", "Please use Vector6<> instead.")
= Eigen::Matrix<Scalar, 6, 1>;
/// EigenSizeMinPreferDynamic<a, b>::value gives the min between compile-time
/// sizes @p a and @p b. 0 has absolute priority, followed by 1, followed by
/// Dynamic, followed by other finite values.
///
/// Note that this is a type-trait version of EIGEN_SIZE_MIN_PREFER_DYNAMIC
/// macro in "Eigen/Core/util/Macros.h".
template <int a, int b>
struct EigenSizeMinPreferDynamic {
// clang-format off
static constexpr int value = (a == 0 || b == 0) ? 0 :
(a == 1 || b == 1) ? 1 :
(a == Eigen::Dynamic || b == Eigen::Dynamic) ? Eigen::Dynamic :
a <= b ? a : b;
// clang-format on
};
/// EigenSizeMinPreferFixed is a variant of EigenSizeMinPreferDynamic. The
/// difference is that finite values now have priority over Dynamic, so that
/// EigenSizeMinPreferFixed<3, Dynamic>::value gives 3.
///
/// Note that this is a type-trait version of EIGEN_SIZE_MIN_PREFER_FIXED macro
/// in "Eigen/Core/util/Macros.h".
template <int a, int b>
struct EigenSizeMinPreferFixed {
// clang-format off
static constexpr int value = (a == 0 || b == 0) ? 0 :
(a == 1 || b == 1) ? 1 :
(a == Eigen::Dynamic && b == Eigen::Dynamic) ? Eigen::Dynamic :
(a == Eigen::Dynamic) ? b :
(b == Eigen::Dynamic) ? a :
a <= b ? a : b;
// clang-format on
};
/// MultiplyEigenSizes<a, b> gives a * b if both of a and b are fixed
/// sizes. Otherwise it gives Eigen::Dynamic.
template <int a, int b>
struct MultiplyEigenSizes {
static constexpr int value =
(a == Eigen::Dynamic || b == Eigen::Dynamic) ? Eigen::Dynamic : a * b;
};
/*
* Determines if a type is derived from EigenBase<> (e.g. ArrayBase<>,
* MatrixBase<>).
*/
template <typename Derived>
struct is_eigen_type : std::is_base_of<Eigen::EigenBase<Derived>, Derived> {};
/*
* Determines if an EigenBase<> has a specific scalar type.
*/
template <typename Derived, typename Scalar>
struct is_eigen_scalar_same
: std::integral_constant<
bool, is_eigen_type<Derived>::value &&
std::is_same<typename Derived::Scalar, Scalar>::value> {};
/*
* Determines if an EigenBase<> type is a compile-time (column) vector.
* This will not check for run-time size.
*/
template <typename Derived>
struct is_eigen_vector
: std::integral_constant<bool, is_eigen_type<Derived>::value &&
Derived::ColsAtCompileTime == 1> {};
/*
* Determines if an EigenBase<> type is a compile-time (column) vector of a
* scalar type. This will not check for run-time size.
*/
template <typename Derived, typename Scalar>
struct is_eigen_vector_of
: std::integral_constant<
bool, is_eigen_scalar_same<Derived, Scalar>::value &&
is_eigen_vector<Derived>::value> {};
// TODO(eric.cousineau): A 1x1 matrix will be disqualified in this case, and
// this logic will qualify it as a vector. Address the downstream logic if this
// becomes an issue.
/*
* Determines if a EigenBase<> type is a compile-time non-column-vector matrix
* of a scalar type. This will not check for run-time size.
* @note For an EigenBase<> of the correct Scalar type, this logic is
* exclusive to is_eigen_vector_of<> such that distinct specializations are not
* ambiguous.
*/
template <typename Derived, typename Scalar>
struct is_eigen_nonvector_of
: std::integral_constant<
bool, is_eigen_scalar_same<Derived, Scalar>::value &&
!is_eigen_vector<Derived>::value> {};
// TODO(eric.cousineau): Add alias is_eigen_matrix_of = is_eigen_scalar_same if
// appropriate.
/// This wrapper class provides a way to write non-template functions taking raw
/// pointers to Eigen objects as parameters while limiting the number of copies,
/// similar to `Eigen::Ref`. Internally, it keeps an instance of `Eigen::Ref<T>`
/// and provides access to it via `operator*` and `operator->`.
///
/// The motivation of this class is to follow <a
/// href="https://google.github.io/styleguide/cppguide.html#Reference_Arguments">GSG's
/// "output arguments should be pointers" rule</a> while taking advantage of
/// using `Eigen::Ref`. Here is an example.
///
/// @code
/// // This function is taking an Eigen::Ref of a matrix and modifies it in
/// // the body. This violates GSG's rule on output parameters.
/// void foo(Eigen::Ref<Eigen::MatrixXd> M) {
/// M(0, 0) = 0;
/// }
/// // At Call-site, we have:
/// foo(M);
/// foo(M.block(0, 0, 2, 2));
///
/// // We can rewrite the above function into the following using EigenPtr.
/// void foo(EigenPtr<Eigen::MatrixXd> M) {
/// (*M)(0, 0) = 0;
/// }
/// // Note that, call sites should be changed to:
/// foo(&M);
///
/// // We need tmp to avoid taking the address of a temporary object such as the
/// // return value of .block().
/// auto tmp = M.block(0, 0, 2, 2);
/// foo(&tmp);
/// @endcode
///
/// Notice that methods taking an EigenPtr can mutate the entries of a matrix as
/// in method `foo()` in the example code above, but cannot change its size.
/// This is because `operator*` and `operator->` return an `Eigen::Ref<T>`
/// object and only plain matrices/arrays can be resized and not expressions.
/// This **is** the desired behavior, since resizing the block of a matrix or
/// even a more general expression should not be allowed. If you do want to be
/// able to resize a mutable matrix argument, then you must pass it as a
/// `Matrix<T>*`, like so:
/// @code
/// void bar(Eigen::MatrixXd* M) {
/// DRAKE_THROW_UNLESS(M != nullptr);
/// // In this case this method only works with 4x3 matrices.
/// if (M->rows() != 4 && M->cols() != 3) {
/// M->resize(4, 3);
/// }
/// (*M)(0, 0) = 0;
/// }
/// @endcode
///
/// @note This class provides a way to avoid the `const_cast` hack introduced in
/// <a
/// href="https://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html#TopicPlainFunctionsFailing">Eigen's
/// documentation</a>.
template <typename PlainObjectType>
class EigenPtr {
public:
typedef Eigen::Ref<PlainObjectType> RefType;
EigenPtr() : EigenPtr(nullptr) {}
/// Overload for `nullptr`.
// NOLINTNEXTLINE(runtime/explicit) This conversion is desirable.
EigenPtr(std::nullptr_t) {}
/// Constructs with a reference to the given matrix type.
// NOLINTNEXTLINE(runtime/explicit) This conversion is desirable.
EigenPtr(const EigenPtr& other) { assign(other); }
/// Constructs with a reference to another matrix type.
/// May be `nullptr`.
template <typename PlainObjectTypeIn>
// NOLINTNEXTLINE(runtime/explicit) This conversion is desirable.
EigenPtr(PlainObjectTypeIn* m) {
if (m) {
m_.set_value(m);
}
}
/// Constructs from another EigenPtr.
template <typename PlainObjectTypeIn>
// NOLINTNEXTLINE(runtime/explicit) This conversion is desirable.
EigenPtr(const EigenPtr<PlainObjectTypeIn>& other) {
// Cannot directly construct `m_` from `other.m_`.
assign(other);
}
EigenPtr& operator=(const EigenPtr& other) {
// We must explicitly override this version of operator=.
// The template below will not take precedence over this one.
return assign(other);
}
template <typename PlainObjectTypeIn>
EigenPtr& operator=(const EigenPtr<PlainObjectTypeIn>& other) {
return assign(other);
}
/// @throws std::runtime_error if this is a null dereference.
RefType& operator*() const { return get_reference(); }
/// @throws std::runtime_error if this is a null dereference.
RefType* operator->() const { return &get_reference(); }
/// Returns whether or not this contains a valid reference.
operator bool() const { return is_valid(); }
bool operator==(std::nullptr_t) const { return !is_valid(); }
bool operator!=(std::nullptr_t) const { return is_valid(); }
private:
// Simple reassignable container without requirement of heap allocation.
// This is used because `drake::optional<>` does not work with `Eigen::Ref<>`
// because `Ref` deletes the necessary `operator=` overload for
// `std::is_copy_assignable`.
class ReassignableRef {
public:
DRAKE_NO_COPY_NO_MOVE_NO_ASSIGN(ReassignableRef)
ReassignableRef() {}
~ReassignableRef() {
reset();
}
// Reset value to null.
void reset() {
if (has_value_) {
raw_value().~RefType();
has_value_ = false;
}
}
// Set value.
template <typename PlainObjectTypeIn>
void set_value(PlainObjectTypeIn* value_in) {
if (has_value_) {
raw_value().~RefType();
}
new (&raw_value()) RefType(*value_in);
has_value_ = true;
}
// Access to value.
RefType& value() {
DRAKE_ASSERT(has_value());
return raw_value();
}
// Indicates if it has a value.
bool has_value() const { return has_value_; }
private:
// Unsafe access to value.
RefType& raw_value() { return reinterpret_cast<RefType&>(storage_); }
bool has_value_{};
typename std::aligned_storage<sizeof(RefType), alignof(RefType)>::type
storage_;
};
// Use mutable, reassignable ref to permit pointer-like semantics (with
// ownership) on the stack.
mutable ReassignableRef m_;
// Consolidate assignment here, so that both the copy constructor and the
// construction from another type may be used.
template <typename PlainObjectTypeIn>
EigenPtr& assign(const EigenPtr<PlainObjectTypeIn>& other) {
if (other) {
m_.set_value(&(*other));
} else {
m_.reset();
}
return *this;
}
// Consolidate getting a reference here.
RefType& get_reference() const {
if (!m_.has_value())
throw std::runtime_error("EigenPtr: nullptr dereference");
return m_.value();
}
bool is_valid() const {
return m_.has_value();
}
};
} // namespace drake

View File

@@ -0,0 +1,116 @@
#pragma once
#include <algorithm>
#include <cmath>
#include <limits>
#include <Eigen/Core>
#include <gtest/gtest.h>
#include "drake/common/drake_nodiscard.h"
namespace drake {
enum class MatrixCompareType { absolute, relative };
/**
* Compares two matrices to determine whether they are equal to within a certain
* threshold.
*
* @param m1 The first matrix to compare.
* @param m2 The second matrix to compare.
* @param tolerance The tolerance for determining equivalence.
* @param compare_type Whether the tolereance is absolute or relative.
* @param explanation A pointer to a string variable for saving an explanation
* of why @p m1 and @p m2 are unequal. This parameter is optional and defaults
* to `nullptr`. If this is `nullptr` and @p m1 and @p m2 are not equal, an
* explanation is logged as an error message.
* @return true if the two matrices are equal based on the specified tolerance.
*/
template <typename DerivedA, typename DerivedB>
DRAKE_NODISCARD ::testing::AssertionResult CompareMatrices(
const Eigen::MatrixBase<DerivedA>& m1,
const Eigen::MatrixBase<DerivedB>& m2, double tolerance = 0.0,
MatrixCompareType compare_type = MatrixCompareType::absolute) {
if (m1.rows() != m2.rows() || m1.cols() != m2.cols()) {
return ::testing::AssertionFailure()
<< "Matrix size mismatch: (" << m1.rows() << " x " << m1.cols()
<< " vs. " << m2.rows() << " x " << m2.cols() << ")";
}
for (int ii = 0; ii < m1.rows(); ii++) {
for (int jj = 0; jj < m1.cols(); jj++) {
// First handle the corner cases of positive infinity, negative infinity,
// and NaN
const auto both_positive_infinity =
m1(ii, jj) == std::numeric_limits<double>::infinity() &&
m2(ii, jj) == std::numeric_limits<double>::infinity();
const auto both_negative_infinity =
m1(ii, jj) == -std::numeric_limits<double>::infinity() &&
m2(ii, jj) == -std::numeric_limits<double>::infinity();
using std::isnan;
const auto both_nan = isnan(m1(ii, jj)) && isnan(m2(ii, jj));
if (both_positive_infinity || both_negative_infinity || both_nan)
continue;
// Check for case where one value is NaN and the other is not
if ((isnan(m1(ii, jj)) && !isnan(m2(ii, jj))) ||
(!isnan(m1(ii, jj)) && isnan(m2(ii, jj)))) {
return ::testing::AssertionFailure() << "NaN mismatch at (" << ii
<< ", " << jj << "):\nm1 =\n"
<< m1 << "\nm2 =\n"
<< m2;
}
// Determine whether the difference between the two matrices is less than
// the tolerance.
using std::abs;
const auto delta = abs(m1(ii, jj) - m2(ii, jj));
if (compare_type == MatrixCompareType::absolute) {
// Perform comparison using absolute tolerance.
if (delta > tolerance) {
return ::testing::AssertionFailure()
<< "Values at (" << ii << ", " << jj
<< ") exceed tolerance: " << m1(ii, jj) << " vs. "
<< m2(ii, jj) << ", diff = " << delta
<< ", tolerance = " << tolerance << "\nm1 =\n"
<< m1 << "\nm2 =\n"
<< m2 << "\ndelta=\n"
<< (m1 - m2);
}
} else {
// Perform comparison using relative tolerance, see:
// http://realtimecollisiondetection.net/blog/?p=89
using std::max;
const auto max_value = max(abs(m1(ii, jj)), abs(m2(ii, jj)));
const auto relative_tolerance =
tolerance * max(decltype(max_value){1}, max_value);
if (delta > relative_tolerance) {
return ::testing::AssertionFailure()
<< "Values at (" << ii << ", " << jj
<< ") exceed tolerance: " << m1(ii, jj) << " vs. "
<< m2(ii, jj) << ", diff = " << delta
<< ", tolerance = " << tolerance
<< ", relative tolerance = " << relative_tolerance
<< "\nm1 =\n"
<< m1 << "\nm2 =\n"
<< m2 << "\ndelta=\n"
<< (m1 - m2);
}
}
}
}
return ::testing::AssertionSuccess() << "m1 =\n"
<< m1
<< "\nis approximately equal to m2 =\n"
<< m2;
}
} // namespace drake

View File

@@ -0,0 +1,53 @@
#pragma once
namespace drake {
/// Documents the argument(s) as unused, placating GCC's -Wunused-parameter
/// warning. This can be called within function bodies to mark that certain
/// parameters are unused.
///
/// When possible, removing the unused parameter is better than placating the
/// warning. However, in some cases the parameter is part of a virtual API or
/// template concept that is used elsewhere, so we can't remove it. In those
/// cases, this function might be an appropriate work-around.
///
/// Here's rough advice on how to fix Wunused-parameter warnings:
///
/// (1) If the parameter can be removed entirely, prefer that as the first
/// choice. (This may not be possible if, e.g., a method must match some
/// virtual API or template concept.)
///
/// (2) Unless the parameter name has acute value, prefer to omit the name of
/// the parameter, leaving only the type, e.g.
/// @code
/// void Print(const State& state) override { /* No state to print. */ }
/// @endcode
/// changes to
/// @code
/// void Print(const State&) override { /* No state to print. */}
/// @endcode
/// This no longer triggers the warning and further makes it clear that a
/// parameter required by the API is definitively unused in the function.
///
/// This is an especially good solution in the context of method
/// definitions (vs declarations); the parameter name used in a definition
/// is entirely irrelevant to Doxygen and most readers.
///
/// (3) When leaving the parameter name intact has acute value, it is
/// acceptable to keep the name and mark it `unused`. For example, when
/// the name appears as part of a virtual method's base class declaration,
/// the name is used by Doxygen to document the method, e.g.,
/// @code
/// /** Sets the default State of a System. This default implementation is to
/// set all zeros. Subclasses may override to use non-zero defaults. The
/// custom defaults may be based on the given @p context, when relevant. */
/// virtual void SetDefault(const Context<T>& context, State<T>* state) const {
/// unused(context);
/// state->SetZero();
/// }
/// @endcode
///
template <typename ... Args>
void unused(const Args& ...) {}
} // namespace drake

View File

@@ -0,0 +1,332 @@
/// @file
/// Utilities for arithmetic on AutoDiffScalar.
// TODO(russt): rename methods to be GSG compliant.
#pragma once
#include <cmath>
#include <tuple>
#include <Eigen/Core>
#include "drake/common/autodiff.h"
#include "drake/common/unused.h"
namespace drake {
namespace math {
template <typename Derived>
struct AutoDiffToValueMatrix {
typedef typename Eigen::Matrix<typename Derived::Scalar::Scalar,
Derived::RowsAtCompileTime,
Derived::ColsAtCompileTime> type;
};
template <typename Derived>
typename AutoDiffToValueMatrix<Derived>::type autoDiffToValueMatrix(
const Eigen::MatrixBase<Derived>& auto_diff_matrix) {
typename AutoDiffToValueMatrix<Derived>::type ret(auto_diff_matrix.rows(),
auto_diff_matrix.cols());
for (int i = 0; i < auto_diff_matrix.rows(); i++) {
for (int j = 0; j < auto_diff_matrix.cols(); ++j) {
ret(i, j) = auto_diff_matrix(i, j).value();
}
}
return ret;
}
/** `B = DiscardGradient(A)` enables casting from a matrix of AutoDiffScalars
* to AutoDiffScalar::Scalar type, explicitly throwing away any gradient
* information. For a matrix of type, e.g. `MatrixX<AutoDiffXd> A`, the
* comparable operation
* `B = A.cast<double>()`
* should (and does) fail to compile. Use `DiscardGradient(A)` if you want to
* force the cast (and explicitly declare that information is lost).
*
* This method is overloaded to permit the user to call it for double types and
* AutoDiffScalar types (to avoid the calling function having to handle the
* two cases differently).
*
* @see DiscardZeroGradient
*/
template <typename Derived>
typename std::enable_if<
!std::is_same<typename Derived::Scalar, double>::value,
Eigen::Matrix<typename Derived::Scalar::Scalar, Derived::RowsAtCompileTime,
Derived::ColsAtCompileTime, 0, Derived::MaxRowsAtCompileTime,
Derived::MaxColsAtCompileTime>>::type
DiscardGradient(const Eigen::MatrixBase<Derived>& auto_diff_matrix) {
return autoDiffToValueMatrix(auto_diff_matrix);
}
/// @see DiscardGradient().
template <typename Derived>
typename std::enable_if<
std::is_same<typename Derived::Scalar, double>::value,
const Eigen::MatrixBase<Derived>&>::type
DiscardGradient(const Eigen::MatrixBase<Derived>& matrix) {
return matrix;
}
/// @see DiscardGradient().
template <typename _Scalar, int _Dim, int _Mode, int _Options>
typename std::enable_if<
!std::is_same<_Scalar, double>::value,
Eigen::Transform<typename _Scalar::Scalar, _Dim, _Mode, _Options>>::type
DiscardGradient(const Eigen::Transform<_Scalar, _Dim, _Mode, _Options>&
auto_diff_transform) {
return Eigen::Transform<typename _Scalar::Scalar, _Dim, _Mode, _Options>(
autoDiffToValueMatrix(auto_diff_transform.matrix()));
}
/// @see DiscardGradient().
template <typename _Scalar, int _Dim, int _Mode, int _Options>
typename std::enable_if<std::is_same<_Scalar, double>::value,
const Eigen::Transform<_Scalar, _Dim, _Mode,
_Options>&>::type
DiscardGradient(
const Eigen::Transform<_Scalar, _Dim, _Mode, _Options>& transform) {
return transform;
}
/** \brief Initialize a single autodiff matrix given the corresponding value
*matrix.
*
* Set the values of \p auto_diff_matrix to be equal to \p val, and for each
*element i of \p auto_diff_matrix,
* resize the derivatives vector to \p num_derivatives, and set derivative
*number \p deriv_num_start + i to one (all other elements of the derivative
*vector set to zero).
*
* \param[in] mat 'regular' matrix of values
* \param[out] ret AutoDiff matrix
* \param[in] num_derivatives the size of the derivatives vector @default the
*size of mat
* \param[in] deriv_num_start starting index into derivative vector (i.e.
*element deriv_num_start in derivative vector corresponds to mat(0, 0)).
*@default 0
*/
template <typename Derived, typename DerivedAutoDiff>
void initializeAutoDiff(const Eigen::MatrixBase<Derived>& val,
// TODO(#2274) Fix NOLINTNEXTLINE(runtime/references).
Eigen::MatrixBase<DerivedAutoDiff>& auto_diff_matrix,
Eigen::DenseIndex num_derivatives = Eigen::Dynamic,
Eigen::DenseIndex deriv_num_start = 0) {
using ADScalar = typename DerivedAutoDiff::Scalar;
static_assert(static_cast<int>(Derived::RowsAtCompileTime) ==
static_cast<int>(DerivedAutoDiff::RowsAtCompileTime),
"auto diff matrix has wrong number of rows at compile time");
static_assert(static_cast<int>(Derived::ColsAtCompileTime) ==
static_cast<int>(DerivedAutoDiff::ColsAtCompileTime),
"auto diff matrix has wrong number of columns at compile time");
if (num_derivatives == Eigen::Dynamic) num_derivatives = val.size();
auto_diff_matrix.resize(val.rows(), val.cols());
Eigen::DenseIndex deriv_num = deriv_num_start;
for (Eigen::DenseIndex i = 0; i < val.size(); i++) {
auto_diff_matrix(i) = ADScalar(val(i), num_derivatives, deriv_num++);
}
}
/** \brief The appropriate AutoDiffScalar gradient type given the value type and
* the number of derivatives at compile time
*/
template <typename Derived, int Nq>
using AutoDiffMatrixType = Eigen::Matrix<
Eigen::AutoDiffScalar<Eigen::Matrix<typename Derived::Scalar, Nq, 1>>,
Derived::RowsAtCompileTime, Derived::ColsAtCompileTime, 0,
Derived::MaxRowsAtCompileTime, Derived::MaxColsAtCompileTime>;
/** \brief Initialize a single autodiff matrix given the corresponding value
*matrix.
*
* Create autodiff matrix that matches \p mat in size with derivatives of
*compile time size \p Nq and runtime size \p num_derivatives.
* Set its values to be equal to \p val, and for each element i of \p
*auto_diff_matrix, set derivative number \p deriv_num_start + i to one (all
*other derivatives set to zero).
*
* \param[in] mat 'regular' matrix of values
* \param[in] num_derivatives the size of the derivatives vector @default the
*size of mat
* \param[in] deriv_num_start starting index into derivative vector (i.e.
*element deriv_num_start in derivative vector corresponds to mat(0, 0)).
*@default 0
* \return AutoDiff matrix
*/
template <int Nq = Eigen::Dynamic, typename Derived>
AutoDiffMatrixType<Derived, Nq> initializeAutoDiff(
const Eigen::MatrixBase<Derived>& mat,
Eigen::DenseIndex num_derivatives = -1,
Eigen::DenseIndex deriv_num_start = 0) {
if (num_derivatives == -1) num_derivatives = mat.size();
AutoDiffMatrixType<Derived, Nq> ret(mat.rows(), mat.cols());
initializeAutoDiff(mat, ret, num_derivatives, deriv_num_start);
return ret;
}
namespace internal {
template <typename Derived, typename Scalar>
struct ResizeDerivativesToMatchScalarImpl {
// TODO(#2274) Fix NOLINTNEXTLINE(runtime/references).
static void run(Eigen::MatrixBase<Derived>&, const Scalar&) {}
};
template <typename Derived, typename DerivType>
struct ResizeDerivativesToMatchScalarImpl<Derived,
Eigen::AutoDiffScalar<DerivType>> {
using Scalar = Eigen::AutoDiffScalar<DerivType>;
// TODO(#2274) Fix NOLINTNEXTLINE(runtime/references).
static void run(Eigen::MatrixBase<Derived>& mat, const Scalar& scalar) {
for (int i = 0; i < mat.size(); i++) {
auto& derivs = mat(i).derivatives();
if (derivs.size() == 0) {
derivs.resize(scalar.derivatives().size());
derivs.setZero();
}
}
}
};
} // namespace internal
/** Resize derivatives vector of each element of a matrix to to match the size
* of the derivatives vector of a given scalar.
* \brief If the mat and scalar inputs are AutoDiffScalars, resize the
* derivatives vector of each element of the matrix mat to match
* the number of derivatives of the scalar. This is useful in functions that
* return matrices that do not depend on an AutoDiffScalar
* argument (e.g. a function with a constant output), while it is desired that
* information about the number of derivatives is preserved.
* \param mat matrix, for which the derivative vectors of the elements will be
* resized
* \param scalar scalar to match the derivative size vector against.
*/
template <typename Derived>
// TODO(#2274) Fix NOLINTNEXTLINE(runtime/references).
void resizeDerivativesToMatchScalar(Eigen::MatrixBase<Derived>& mat,
const typename Derived::Scalar& scalar) {
internal::ResizeDerivativesToMatchScalarImpl<
Derived, typename Derived::Scalar>::run(mat, scalar);
}
namespace internal {
/** \brief Helper for totalSizeAtCompileTime function (recursive)
*/
template <typename Head, typename... Tail>
struct TotalSizeAtCompileTime {
static constexpr int eval() {
return Head::SizeAtCompileTime == Eigen::Dynamic ||
TotalSizeAtCompileTime<Tail...>::eval() == Eigen::Dynamic
? Eigen::Dynamic
: Head::SizeAtCompileTime +
TotalSizeAtCompileTime<Tail...>::eval();
}
};
/** \brief Helper for totalSizeAtCompileTime function (base case)
*/
template <typename Head>
struct TotalSizeAtCompileTime<Head> {
static constexpr int eval() { return Head::SizeAtCompileTime; }
};
/** \brief Determine the total size at compile time of a number of arguments
* based on their SizeAtCompileTime static members
*/
template <typename... Args>
constexpr int totalSizeAtCompileTime() {
return TotalSizeAtCompileTime<Args...>::eval();
}
/** \brief Determine the total size at runtime of a number of arguments using
* their size() methods (base case).
*/
constexpr Eigen::DenseIndex totalSizeAtRunTime() { return 0; }
/** \brief Determine the total size at runtime of a number of arguments using
* their size() methods (recursive)
*/
template <typename Head, typename... Tail>
Eigen::DenseIndex totalSizeAtRunTime(const Eigen::MatrixBase<Head>& head,
const Tail&... tail) {
return head.size() + totalSizeAtRunTime(tail...);
}
/** \brief Helper for initializeAutoDiffTuple function (recursive)
*/
template <size_t Index>
struct InitializeAutoDiffTupleHelper {
template <typename... ValueTypes, typename... AutoDiffTypes>
static void run(const std::tuple<ValueTypes...>& values,
// TODO(#2274) Fix NOLINTNEXTLINE(runtime/references).
std::tuple<AutoDiffTypes...>& auto_diffs,
Eigen::DenseIndex num_derivatives,
Eigen::DenseIndex deriv_num_start) {
constexpr size_t tuple_index = sizeof...(AutoDiffTypes)-Index;
const auto& value = std::get<tuple_index>(values);
auto& auto_diff = std::get<tuple_index>(auto_diffs);
auto_diff.resize(value.rows(), value.cols());
initializeAutoDiff(value, auto_diff, num_derivatives, deriv_num_start);
InitializeAutoDiffTupleHelper<Index - 1>::run(
values, auto_diffs, num_derivatives, deriv_num_start + value.size());
}
};
/** \brief Helper for initializeAutoDiffTuple function (base case)
*/
template <>
struct InitializeAutoDiffTupleHelper<0> {
template <typename... ValueTypes, typename... AutoDiffTypes>
static void run(const std::tuple<ValueTypes...>& values,
const std::tuple<AutoDiffTypes...>& auto_diffs,
Eigen::DenseIndex num_derivatives,
Eigen::DenseIndex deriv_num_start) {
unused(values, auto_diffs, num_derivatives, deriv_num_start);
}
};
} // namespace internal
/** \brief Given a series of Eigen matrices, create a tuple of corresponding
*AutoDiff matrices with values equal to the input matrices and properly
*initialized derivative vectors.
*
* The size of the derivative vector of each element of the matrices in the
*output tuple will be the same, and will equal the sum of the number of
*elements of the matrices in \p args.
* If all of the matrices in \p args have fixed size, then the derivative
*vectors will also have fixed size (being the sum of the sizes at compile time
*of all of the input arguments),
* otherwise the derivative vectors will have dynamic size.
* The 0th element of the derivative vectors will correspond to the derivative
*with respect to the 0th element of the first argument.
* Subsequent derivative vector elements correspond first to subsequent elements
*of the first input argument (traversed first by row, then by column), and so
*on for subsequent arguments.
*
* \param args a series of Eigen matrices
* \return a tuple of properly initialized AutoDiff matrices corresponding to \p
*args
*
*/
template <typename... Deriveds>
std::tuple<AutoDiffMatrixType<
Deriveds, internal::totalSizeAtCompileTime<Deriveds...>()>...>
initializeAutoDiffTuple(const Eigen::MatrixBase<Deriveds>&... args) {
Eigen::DenseIndex dynamic_num_derivs = internal::totalSizeAtRunTime(args...);
std::tuple<AutoDiffMatrixType<
Deriveds, internal::totalSizeAtCompileTime<Deriveds...>()>...>
ret(AutoDiffMatrixType<Deriveds,
internal::totalSizeAtCompileTime<Deriveds...>()>(
args.rows(), args.cols())...);
auto values = std::forward_as_tuple(args...);
internal::InitializeAutoDiffTupleHelper<sizeof...(args)>::run(
values, ret, dynamic_num_derivs, 0);
return ret;
}
} // namespace math
} // namespace drake