Skip to content

Commit

Permalink
[core] Faster ground profile querying. (#824)
Browse files Browse the repository at this point in the history
* [core] Replace MurmurHash3 by xxHash32 which is faster.
* [core] Make gradient computation optional for heightmap functions.
  • Loading branch information
duburcqa authored Jul 13, 2024
1 parent d2e76ac commit 3306e66
Show file tree
Hide file tree
Showing 10 changed files with 279 additions and 107 deletions.
7 changes: 5 additions & 2 deletions core/include/jiminy/core/engine/engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -292,10 +292,13 @@ namespace jiminy
config["groundProfile"] = HeightmapFunction(
[](const Eigen::Vector2d & /* xy */,
double & height,
Eigen::Ref<Eigen::Vector3d> normal) -> void
std::optional<Eigen::Ref<Eigen::Vector3d>> normal) -> void
{
height = 0.0;
normal = Eigen::Vector3d::UnitZ();
if (normal.has_value())
{
normal.value() = Eigen::Vector3d::UnitZ();
}
});

return config;
Expand Down
21 changes: 11 additions & 10 deletions core/include/jiminy/core/fwd.h
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
#ifndef JIMINY_FORWARD_H
#define JIMINY_FORWARD_H

#include <string_view> // `std::string_view`
#include <cstdint> // `int32_t`, `int64_t`, `uint32_t`, `uint64_t`, ...
#include <functional> // `std::function`, `std::invoke`
#include <limits> // `std::numeric_limits`
#include <map> // `std::map`
#include <unordered_map> // `std::unordered_map`
#include <deque> // `std::deque`
#include <vector> // `std::vector`
#include <utility> // `std::pair`
#include <optional> // `std::optional`
#include <string> // `std::string`
#include <sstream> // `std::ostringstream`
#include <unordered_map> // `std::unordered_map`
#include <utility> // `std::pair`
#include <vector> // `std::vector`
#include <functional> // `std::function`, `std::invoke`
#include <limits> // `std::numeric_limits`
#include <memory> // `std::addressof`
#include <utility> // `std::forward`
#include <stdexcept> // `std::runtime_error`, `std::logic_error`
#include <stdexcept> // `std::logic_error`
#include <type_traits> // `std::enable_if_t`, `std::decay_t`, `std::add_pointer_t`, `std::is_same_v`, ...

#include "pinocchio/fwd.hpp" // To avoid having to include it everywhere
Expand Down Expand Up @@ -196,9 +196,10 @@ namespace jiminy

// Ground profile functors.
// FIXME: use `std::move_only_function` instead of `std::function` when moving to C++23
using HeightmapFunction = std::function<void(const Eigen::Vector2d & /* xy */,
double & /* height */,
Eigen::Ref<Eigen::Vector3d> /* normal */)>;
using HeightmapFunction =
std::function<void(const Eigen::Vector2d & /* xy */,
double & /* height */,
std::optional<Eigen::Ref<Eigen::Vector3d>> /* normal */)>;

// Flexible joints
struct FlexibilityJointConfig
Expand Down
12 changes: 12 additions & 0 deletions core/include/jiminy/core/utilities/random.h
Original file line number Diff line number Diff line change
Expand Up @@ -410,8 +410,20 @@ namespace jiminy

// ****************************** Continuous Perlin processes ****************************** //

/// \brief Non-cryptographic hash function initially designed for hash-based lookup.
///
/// \sa Murmursh algorithms were proposed by Austin Appleby and placed in public domain.
/// The author hereby disclaims copyright to this source code:
/// https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp
uint32_t MurmurHash3(const void * key, int32_t len, uint32_t seed) noexcept;

/// \brief Non-cryptographic hash function initially designed for hash-based lookup.
///
/// \sa xxHash algorithms were proposed by Yann Collet and placed in the public domain.
/// The author hereby disclaims copyright to this source code:
/// https://github.com/Cyan4973/xxHash/blob/dev/xxhash.h
uint32_t xxHash(const void * key, int32_t len, uint32_t seed) noexcept;

template<template<unsigned int> class DerivedPerlinNoiseOctave, unsigned int N>
class JIMINY_TEMPLATE_DLLAPI AbstractPerlinNoiseOctave
{
Expand Down
14 changes: 7 additions & 7 deletions core/include/jiminy/core/utilities/random.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ namespace jiminy

static inline double derivativeFade(double delta) noexcept
{
return 30 * delta * delta * (delta * (delta - 2.0) + 1.0);
return 30.0 * delta * delta * (delta * (delta - 2.0) + 1.0);
}

template<typename T1, typename T2>
Expand Down Expand Up @@ -419,7 +419,7 @@ namespace jiminy
constexpr float fHashMax = static_cast<float>(std::numeric_limits<uint32_t>::max());

// Compute knot hash
uint32_t hash = MurmurHash3(knot.data(), static_cast<int32_t>(sizeof(int32_t) * N), seed_);
uint32_t hash = xxHash(knot.data(), static_cast<int32_t>(sizeof(int32_t) * N), seed_);

/* Generate random gradient uniformly distributed on n-ball.
For technical reference, see:
Expand All @@ -437,17 +437,17 @@ namespace jiminy
{
// Sample random vector on a 2-ball (disk) using
// const double theta = 2 * M_PI * static_cast<float>(hash) / fHashMax;
// hash = MurmurHash3(&hash, sizeof(uint32_t), seed_);
// hash = xxHash(&hash, sizeof(uint32_t), seed_);
// const float radius = std::sqrt(static_cast<float>(hash) / fHashMax);
// return VectorN<double>{radius * std::cos(theta), radius * std::sin(theta)};

/* The rejection method is much fast in 2d because it does not involve complex math
(sqrt, sincos) and the acceptance rate is high (~78%) compared to the cost of
sampling random numbers using `MurmurHash3`. */
sampling random numbers using `xxHash`. */
while (true)
{
const float x = 2 * static_cast<float>(hash) / fHashMax - 1.0F;
hash = MurmurHash3(&hash, sizeof(uint32_t), seed_);
hash = xxHash(&hash, sizeof(uint32_t), seed_);
const float y = 2 * static_cast<float>(hash) / fHashMax - 1.0F;
if (x * x + y * y <= 1.0F)
{
Expand All @@ -463,9 +463,9 @@ namespace jiminy
{
// Generate 2 uniformly distributed random variables
const float u1 = static_cast<float>(hash) / fHashMax;
hash = MurmurHash3(&hash, sizeof(uint32_t), seed_);
hash = xxHash(&hash, sizeof(uint32_t), seed_);
const float u2 = static_cast<float>(hash) / fHashMax;
hash = MurmurHash3(&hash, sizeof(uint32_t), seed_);
hash = xxHash(&hash, sizeof(uint32_t), seed_);

// Apply Box-Mueller algorithm to deduce 2 normally distributed random variables
const double theta = 2 * M_PI * u2;
Expand Down
7 changes: 5 additions & 2 deletions core/src/io/serialization.cc
Original file line number Diff line number Diff line change
Expand Up @@ -250,10 +250,13 @@ namespace boost::serialization
{
fun = [](const Eigen::Vector2d & /* xy */,
double & height,
Eigen::Ref<Eigen::Vector3d> normal)
std::optional<Eigen::Ref<Eigen::Vector3d>> normal)
{
height = 0.0;
normal = Eigen::Vector3d::UnitZ();
if (normal.has_value())
{
normal.value() = Eigen::Vector3d::UnitZ();
}
};
}

Expand Down
Loading

0 comments on commit 3306e66

Please sign in to comment.