Skip to content

Commit

Permalink
[ad] Add support for nearest-integer functions (RobotLocomotion#17657)
Browse files Browse the repository at this point in the history
  • Loading branch information
jwnimmer-tri authored Aug 1, 2022
1 parent 10d0ee6 commit 2f97a3f
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 0 deletions.
1 change: 1 addition & 0 deletions common/ad/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ drake_cc_googletest(
"test/standard_operations_dec_test.cc",
"test/standard_operations_div_test.cc",
"test/standard_operations_inc_test.cc",
"test/standard_operations_integer_test.cc",
"test/standard_operations_mul_test.cc",
"test/standard_operations_stream_test.cc",
"test/standard_operations_sub_test.cc",
Expand Down
24 changes: 24 additions & 0 deletions common/ad/internal/standard_operations.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,30 @@
namespace drake {
namespace ad {

AutoDiff ceil(AutoDiff x) {
x.value() = std::ceil(x.value());
x.partials().SetZero();
return x;
}

AutoDiff floor(AutoDiff x) {
x.value() = std::floor(x.value());
x.partials().SetZero();
return x;
}

AutoDiff round(AutoDiff x) {
x.value() = std::round(x.value());
x.partials().SetZero();
return x;
}

AutoDiff nexttoward(AutoDiff from, long double to) {
from.value() = std::nexttoward(from.value(), to);
from.partials().SetZero();
return from;
}

std::ostream& operator<<(std::ostream& s, const AutoDiff& x) {
return s << fmt::format("{}", x.value());
}
Expand Down
43 changes: 43 additions & 0 deletions common/ad/internal/standard_operations.h
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,49 @@ inline AutoDiff operator/(double a, const AutoDiff& b) {

//@}

/// @name Math functions: Nearest integer floating point operations
///
/// https://en.cppreference.com/w/cpp/numeric/math#Nearest_integer_floating_point_operations
///
/// https://en.cppreference.com/w/cpp/numeric/math#Floating_point_manipulation_functions
//@{

/** ADL overload to mimic std::ceil from <cmath>.
The result's derivatives are always zero. */
AutoDiff ceil(AutoDiff x);

/** ADL overload to mimic std::floor from <cmath>.
The result's derivatives are always zero. */
AutoDiff floor(AutoDiff x);

/** ADL overload to mimic std::round from <cmath>.
The result's derivatives are always zero. */
AutoDiff round(AutoDiff x);

/** ADL overload to mimic std::nexttoward from <cmath>.
The result's derivatives are always zero. */
AutoDiff nexttoward(AutoDiff from, long double to);

/** ADL overload to mimic std::isfinite from <cmath>.
Because the return type is `bool`, the derivatives are not preserved. */
inline bool isfinite(const AutoDiff& x) {
return std::isfinite(x.value());
}

/** ADL overload to mimic std::isinf from <cmath>.
Because the return type is `bool`, the derivatives are not preserved. */
inline bool isinf(const AutoDiff& x) {
return std::isinf(x.value());
}

/** ADL overload to mimic std::isnan from <cmath>.
Because the return type is `bool`, the derivatives are not preserved. */
inline bool isnan(const AutoDiff& x) {
return std::isnan(x.value());
}

//@}

/// @name Miscellaneous functions
//@{

Expand Down
51 changes: 51 additions & 0 deletions common/ad/test/standard_operations_integer_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#include <sstream>

#include "drake/common/ad/auto_diff.h"
#include "drake/common/ad/test/standard_operations_test.h"

namespace drake {
namespace test {
namespace {

TEST_F(StandardOperationsTest, Ceil) {
const AutoDiffDut x{0.5, 3, 0};
const AutoDiffDut y = ceil(x);
EXPECT_EQ(y.value(), std::ceil(x.value()));
EXPECT_EQ(y.derivatives(), Eigen::Vector3d::Zero());
}

TEST_F(StandardOperationsTest, Floor) {
const AutoDiffDut x{0.5, 3, 0};
const AutoDiffDut y = floor(x);
EXPECT_EQ(y.value(), std::floor(x.value()));
EXPECT_EQ(y.derivatives(), Eigen::Vector3d::Zero());
}

TEST_F(StandardOperationsTest, Round) {
const AutoDiffDut x{0.5, 3, 0};
const AutoDiffDut y = round(x);
EXPECT_EQ(y.value(), std::round(x.value()));
EXPECT_EQ(y.derivatives(), Eigen::Vector3d::Zero());
}

TEST_F(StandardOperationsTest, NextToward) {
const AutoDiffDut x{0.5, 3, 0};
const AutoDiffDut y = nexttoward(x, 1.0);
EXPECT_EQ(y.value(), std::nexttoward(x.value(), 1.0));
EXPECT_EQ(y.derivatives(), Eigen::Vector3d::Zero());
}

TEST_F(StandardOperationsTest, Classify) {
const AutoDiffDut a{0.5, 3, 0};
const AutoDiffDut b{std::numeric_limits<double>::infinity(), 3, 0};
const AutoDiffDut c{std::numeric_limits<double>::quiet_NaN(), 3, 0};
for (const auto& x : {a, b, c}) {
EXPECT_EQ(isfinite(x), std::isfinite(x.value())) << x;
EXPECT_EQ(isinf(x), std::isinf(x.value())) << x;
EXPECT_EQ(isnan(x), std::isnan(x.value())) << x;
}
}

} // namespace
} // namespace test
} // namespace drake

0 comments on commit 2f97a3f

Please sign in to comment.