diff --git a/.github/workflows/macos-linux-windows-pixi.yml b/.github/workflows/macos-linux-windows-pixi.yml index f65cc4053..b804c9795 100644 --- a/.github/workflows/macos-linux-windows-pixi.yml +++ b/.github/workflows/macos-linux-windows-pixi.yml @@ -82,8 +82,9 @@ jobs: env: CMAKE_BUILD_PARALLEL_LEVEL: 2 COAL_BUILD_TYPE: ${{ matrix.build_type }} - COAL_CXX_FLAGS: ${{ matrix.cxx_options }} + shell: bash -el {0} run: | + export CXXFLAGS="$CXXFLAGS ${{ matrix.cxx_options }}" pixi run -e ${{ matrix.environment }} build - name: Test Coal [MacOS/Linux/Windows] @@ -96,9 +97,9 @@ jobs: env: CMAKE_BUILD_PARALLEL_LEVEL: 2 COAL_BUILD_TYPE: ${{ matrix.build_type }} - COAL_CXX_FLAGS: ${{ matrix.cxx_options }} shell: bash -el {0} run: | + export CXXFLAGS="$CXXFLAGS ${{ matrix.cxx_options }}" pixi run -e ${{ matrix.environment }} configure \ -DBUILD_PYTHON_INTERFACE=OFF \ -B build_cpp @@ -109,9 +110,9 @@ jobs: env: CMAKE_BUILD_PARALLEL_LEVEL: 2 COAL_BUILD_TYPE: ${{ matrix.build_type }} - COAL_CXX_FLAGS: ${{ matrix.cxx_options }} shell: bash -el {0} run: | + export CXXFLAGS="$CXXFLAGS ${{ matrix.cxx_options }}" pixi run -e ${{ matrix.environment }} configure \ -DBUILD_PYTHON_INTERFACE=ON \ -DBUILD_STANDALONE_PYTHON_INTERFACE=ON \ diff --git a/CMakeLists.txt b/CMakeLists.txt index 92c40c74f..2f84ec255 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,6 +79,7 @@ option( "Build with tracy profiler for performance analysis" FALSE ) +option(COAL_BUILD_BENCHMARK "Build benchmarks" FALSE) # Check if the submodule cmake have been initialized set(JRL_CMAKE_MODULES "${CMAKE_CURRENT_LIST_DIR}/cmake") @@ -523,7 +524,10 @@ if(BUILD_PYTHON_INTERFACE) endif() if(BUILD_TESTING) add_subdirectory(test) -endif(BUILD_TESTING) +endif() +if(COAL_BUILD_BENCHMARK) + add_subdirectory(benchmark) +endif() PKG_CONFIG_APPEND_LIBS("coal") if(COAL_HAS_OCTOMAP) diff --git a/benchmark/CMakeLists.txt b/benchmark/CMakeLists.txt new file mode 100644 index 000000000..50f0d5e04 --- /dev/null +++ b/benchmark/CMakeLists.txt @@ -0,0 +1,18 @@ +add_project_dependency(benchmark REQUIRED) +add_project_dependency(hwy REQUIRED) + +# Add icosahedron building library +add_library(coal-bench-utils-icosahedron STATIC utils/icosahedron.cpp) +target_link_libraries(coal-bench-utils-icosahedron PUBLIC Eigen3::Eigen) + +# Add coal-bench-convex-support benchmark +add_executable(coal-bench-convex-support convex_support.cpp + convex_support_highway.cpp) +set_standard_output_directory(coal-bench-convex-support) +target_link_libraries( + coal-bench-convex-support + PRIVATE ${LIBRARY_NAME} Eigen3::Eigen Boost::boost benchmark::benchmark + hwy::hwy coal-bench-utils-icosahedron) +# This is mandatory to support highway auto include +target_include_directories(coal-bench-convex-support + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/benchmark/convex_support.cpp b/benchmark/convex_support.cpp new file mode 100644 index 000000000..cb7a4a3ab --- /dev/null +++ b/benchmark/convex_support.cpp @@ -0,0 +1,671 @@ +#include "convex_support_highway.hh" +#include "utils/icosahedron.hh" +#include "utils/sparse_set.hh" + +#include +#include + +#include + +#include + +#include + +#include +#include +#include +#include + +namespace coal { +namespace bench { + +template +Eigen::Vector fromSpherical(Scalar horiz, Scalar vert) { + const auto sin_horiz = std::sin(horiz); + const auto cos_horiz = std::cos(horiz); + const auto sin_vert = std::sin(vert); + const auto cos_vert = std::cos(vert); + return Eigen::Vector(cos_horiz * cos_vert, sin_vert, + sin_horiz * cos_vert); +} + +template +EIGEN_DONT_INLINE static std::vector> sampleVector( + double horiz, double vert, double std_dev) { + using Vec3 = Eigen::Vector; + + std::mt19937 gen{1234}; + std::normal_distribution d{0.0, std_dev}; + + constexpr std::size_t N = 50; + std::vector ret; + ret.reserve(N); + + for (std::size_t i = 0; i < N; ++i) { + Scalar rand_horiz = static_cast(d(gen)); + Scalar rand_vert = static_cast(d(gen)); + ret.push_back(fromSpherical(static_cast(horiz) + rand_horiz, + static_cast(vert) + rand_vert)); + } + return ret; +} + +struct WarmStartMesh { + static WarmStartMesh construct(std::size_t points_horizontal, + std::size_t points_vertical) { + const auto half_pi = boost::math::constants::half_pi(); + const auto pi = boost::math::constants::pi(); + const auto two_pi = boost::math::constants::two_pi(); + WarmStartMesh ws; + ws.points.reserve(points_horizontal * points_vertical); + for (std::size_t x = 0; x < points_horizontal; ++x) { + for (std::size_t y = 0; y < points_vertical; ++y) { + const double horiz = + (static_cast(x) / static_cast(points_horizontal)) * + two_pi; + const double vert = + -half_pi + (static_cast(y + 1) / + static_cast(points_vertical + 1)) * + pi; + ws.points.push_back(fromSpherical(horiz, vert)); + } + } + ws.points.push_back(Eigen::Vector3d::UnitY()); + ws.points.push_back(-Eigen::Vector3d::UnitY()); + return ws; + } + + std::vector points; +}; + +template +struct LegacyLinearAlgorithm { + using Scalar = _Scalar; + using Vec3 = Eigen::Vector; + using Algorithm = LegacyLinearAlgorithm; + + static Algorithm fromPoints(const std::vector& points) { + Algorithm algo; + algo.points.reserve(points.size()); + for (std::size_t i = 0; i < points.size(); ++i) { + algo.points.push_back(points[i].cast()); + } + return algo; + } + + Scalar support(const Vec3& dir) const { + Scalar max_dot = points[0].dot(dir); + for (std::size_t i = 1; i < points.size(); ++i) { + Scalar dot = points[i].dot(dir); + if (dot > max_dot) { + max_dot = dot; + } + } + return max_dot; + } + + std::tuple supportWithIndex(const Vec3& dir) const { + std::size_t max_index = 0; + Scalar max_dot = points[0].dot(dir); + for (std::size_t i = 1; i < points.size(); ++i) { + Scalar dot = points[i].dot(dir); + if (dot > max_dot) { + max_dot = dot; + max_index = i; + } + } + return std::make_tuple(max_dot, max_index); + } + + std::vector points; +}; + +template +struct LegacyLogWarmStart { + using Scalar = _Scalar; + using Vec3 = Eigen::Vector; + using SearchAlgorithm = LegacyLinearAlgorithm; + // using SearchAlgorithm = SOAHighwayAlgorithm; + + static LegacyLogWarmStart fromPoints( + const std::vector& points) { + LegacyLogWarmStart warm_start; + auto warm_start_mesh = WarmStartMesh::construct(4, 3); + auto init_search_algo = SearchAlgorithm::fromPoints(points); + warm_start.search_algo = + SearchAlgorithm::fromPoints(warm_start_mesh.points); + warm_start.closest_index.reserve(warm_start_mesh.points.size()); + + // Match warm_start_mesh points with geometry points + for (const auto& p : warm_start_mesh.points) { + auto [_, index] = + init_search_algo.supportWithIndex(p.template cast()); + warm_start.closest_index.push_back(index); + } + + return warm_start; + } + + std::size_t hint(const Vec3& dir) const { + auto [__, index] = search_algo.supportWithIndex(dir); + return closest_index[index]; + } + + SearchAlgorithm search_algo; + std::vector closest_index; +}; + +template +struct LegacyLogAlgorithm { + using Scalar = _Scalar; + using Vec3 = Eigen::Vector; + using NeighborIndexes = std::vector; + using WarmStart = LegacyLogWarmStart; + using Algorithm = LegacyLogAlgorithm; + using SparseSet = utils::SparseSet; + + static Algorithm fromPointsAndNeighbors( + const std::vector& points, + std::vector neighbors) { + Algorithm algo; + + algo.warm_start = WarmStart::fromPoints(points); + algo.points.reserve(points.size()); + for (std::size_t i = 0; i < points.size(); ++i) { + algo.points.push_back(points[i].cast()); + } + algo.visited = SparseSet(points.size(), points.size()); + algo.neighbors = std::move(neighbors); + return algo; + } + + std::tuple supportWithIndex(const Vec3& dir, + std::size_t hint) const { + visited.clear(); + // Compute initial hint if dir is too far from last_dir + const Scalar use_warm_start_threshold = Scalar(0.9); + Vec3 dir_normalized = dir.normalized(); + if (last_dir.isZero() || + last_dir.dot(dir_normalized) < use_warm_start_threshold) { + hint = warm_start.hint(dir); + } + last_dir = dir_normalized; + + bool found = true; + bool loose_check = true; + std::size_t current_vertex_index = hint; + Scalar max_dot = points[current_vertex_index].dot(dir); + while (found) { + const NeighborIndexes& n = neighbors[current_vertex_index]; + found = false; + for (const auto neighbor_index : n) { + if (visited.contains(neighbor_index)) continue; + + visited.insert(neighbor_index); + const Scalar dot = points[neighbor_index].dot(dir); + bool better = false; + if (dot > max_dot) { + better = true; + loose_check = false; + } else if (loose_check && dot == max_dot) { + better = true; + } + + if (better) { + max_dot = dot; + current_vertex_index = neighbor_index; + found = true; + } + } + } + return std::make_tuple(max_dot, current_vertex_index); + } + + std::vector points; + std::vector neighbors; + WarmStart warm_start; + mutable SparseSet visited; + mutable Vec3 last_dir = Vec3::Zero(); +}; + +template +struct SOALocalNeighborLogAlgorithm { + using Scalar = _Scalar; + using Vec3 = Eigen::Vector; + using NeighborIndexes = std::vector; + using WarmStart = LegacyLogWarmStart; + using SearchAlgorithm = SOAHighwayAlgorithm; + using Algorithm = SOALocalNeighborLogAlgorithm; + using SparseSet = utils::SparseSet; + + static Algorithm fromPointsAndNeighbors( + const std::vector& points, + std::vector neighbors) { + Algorithm algo; + + algo.warm_start = WarmStart::fromPoints(points); + std::vector points_and_neighbors; + std::size_t max_neighbors = 0; + algo.points.reserve(points.size()); + for (std::size_t i = 0; i < points.size(); ++i) { + algo.points.push_back(points[i].template cast()); + max_neighbors = std::max(max_neighbors, neighbors[i].size()); + } + points_and_neighbors.resize(max_neighbors + 1, Eigen::Vector3d::Zero()); + algo.last_points_and_neighbors = + SearchAlgorithm::fromPoints(points_and_neighbors); + algo.neighbors = std::move(neighbors); + algo.visited = SparseSet(points.size(), points.size()); + return algo; + } + + void fillLocalPointsAndNeighbors(std::size_t current_point) const { + const auto& p = points[current_point]; + last_points_and_neighbors.x[0] = p.x(); + last_points_and_neighbors.y[0] = p.y(); + last_points_and_neighbors.z[0] = p.z(); + const auto& point_neighbors = neighbors[current_point]; + for (std::size_t i = 0; i < point_neighbors.size(); ++i) { + const auto& pn = points[point_neighbors[i]]; + last_points_and_neighbors.x[i + 1] = pn.x(); + last_points_and_neighbors.y[i + 1] = pn.y(); + last_points_and_neighbors.z[i + 1] = pn.z(); + } + for (std::size_t i = point_neighbors.size() + 1; + i < last_points_and_neighbors.count; ++i) { + last_points_and_neighbors.x[i] = p.x(); + last_points_and_neighbors.y[i] = p.y(); + last_points_and_neighbors.z[i] = p.z(); + } + } + + std::tuple supportWithIndexLegacy( + const Vec3& dir, Scalar max_dot, std::size_t hint) const { + bool found = true; + bool loose_check = true; + std::size_t current_vertex_index = hint; + while (found) { + const NeighborIndexes& n = neighbors[current_vertex_index]; + found = false; + for (const auto neighbor_index : n) { + if (visited.contains(neighbor_index)) continue; + + visited.insert(neighbor_index); + const Scalar dot = points[neighbor_index].dot(dir); + bool better = false; + if (dot > max_dot) { + better = true; + loose_check = false; + } else if (loose_check && dot == max_dot) { + better = true; + } + + if (better) { + max_dot = dot; + current_vertex_index = neighbor_index; + found = true; + } + } + } + return std::make_tuple(max_dot, current_vertex_index); + } + + std::tuple supportWithIndex(const Vec3& dir, + std::size_t hint) const { + visited.clear(); + // Compute initial hint if dir is too far from last_dir + const Scalar use_warm_start_threshold = Scalar(0.9); + Vec3 dir_normalized = dir.normalized(); + std::size_t current_vertex_index = hint; + + Scalar max_dot; + if (last_dir.isZero() || + last_dir.dot(dir_normalized) < use_warm_start_threshold) { + // Init or too far: we launch the legacy algorithm + current_vertex_index = warm_start.hint(dir); + max_dot = points[current_vertex_index].dot(dir); + std::tie(max_dot, current_vertex_index) = + supportWithIndexLegacy(dir, max_dot, current_vertex_index); + } else { + // Near, we first look in the local buffer, then launch the legacy + // algorithm + std::size_t index; + std::tie(max_dot, index) = + last_points_and_neighbors.supportWithIndex(dir); + if (index > 0) { + const auto& n_init = neighbors[current_vertex_index]; + current_vertex_index = n_init[index - 1]; + for (const auto neighbor_index : n_init) { + visited.insert(neighbor_index); + } + std::tie(max_dot, current_vertex_index) = + supportWithIndexLegacy(dir, max_dot, current_vertex_index); + } + } + last_dir = dir_normalized; + + if (current_vertex_index != hint) { + fillLocalPointsAndNeighbors(current_vertex_index); + } + return std::make_tuple(max_dot, current_vertex_index); + } + + std::vector points; + std::vector neighbors; + WarmStart warm_start; + mutable Vec3 last_dir = Vec3::Zero(); + mutable SearchAlgorithm last_points_and_neighbors; + mutable SparseSet visited; +}; + +template +struct SOANeighborLogAlgorithm { + using Scalar = _Scalar; + using Vec3 = Eigen::Vector; + using NeighborIndexes = std::vector; + using WarmStart = LegacyLogWarmStart; + using SearchAlgorithm = SOAHighwayAlgorithm; + using Algorithm = SOANeighborLogAlgorithm; + + static Algorithm fromPointsAndNeighbors( + const std::vector& points, + std::vector neighbors) { + Algorithm algo; + + algo.warm_start = WarmStart::fromPoints(points); + algo.points_and_neighbors.reserve(points.size()); + std::vector points_and_neighbors; + for (std::size_t i = 0; i < points.size(); ++i) { + points_and_neighbors.clear(); + points_and_neighbors.push_back(points[i]); + const auto& point_neighbors = neighbors[i]; + for (std::size_t j = 0; j < point_neighbors.size(); ++j) { + points_and_neighbors.push_back(points[point_neighbors[j]]); + } + algo.points_and_neighbors.push_back( + SearchAlgorithm::fromPoints(points_and_neighbors)); + } + algo.neighbors = std::move(neighbors); + return algo; + } + + std::tuple supportWithIndex(const Vec3& dir, + std::size_t hint) const { + // Compute initial hint if dir is too far from last_dir + const Scalar use_warm_start_threshold = Scalar(0.9); + Vec3 dir_normalized = dir.normalized(); + if (last_dir.isZero() || + last_dir.dot(dir_normalized) < use_warm_start_threshold) { + hint = warm_start.hint(dir); + } + last_dir = dir_normalized; + + std::size_t current_vertex_index = hint; + + auto [max_dot, index] = + points_and_neighbors[current_vertex_index].supportWithIndex(dir); + while (index > 0) { + current_vertex_index = neighbors[current_vertex_index][index - 1]; + std::tie(max_dot, index) = + points_and_neighbors[current_vertex_index].supportWithIndex(dir); + } + return std::make_tuple(max_dot, current_vertex_index); + } + + std::vector points_and_neighbors; + std::vector neighbors; + WarmStart warm_start; + mutable Vec3 last_dir = Vec3::Zero(); +}; + +struct SOAFloatEigenLinearAlgorithm { + using Scalar = float; + using Vec = Eigen::Vector; + using Array4 = Eigen::Array; + using Mask4 = Eigen::Array; + using Vec3 = Eigen::Vector; + using Algorithm = SOAFloatEigenLinearAlgorithm; + + static Algorithm fromPoints(const std::vector& points) { + Algorithm algo; + std::size_t i = 0; + for (; (i + 4) < points.size(); i += 4) { + Array4 x, y, z; + x << static_cast(points[i].x()), + static_cast(points[i + 1].x()), + static_cast(points[i + 2].x()), + static_cast(points[i + 3].x()); + y << static_cast(points[i].y()), + static_cast(points[i + 1].y()), + static_cast(points[i + 2].y()), + static_cast(points[i + 3].y()); + z << static_cast(points[i].z()), + static_cast(points[i + 1].z()), + static_cast(points[i + 2].z()), + static_cast(points[i + 3].z()); + algo.x.push_back(x); + algo.y.push_back(y); + algo.z.push_back(z); + } + for (; i < points.size(); ++i) { + algo.remainder.push_back(points[i].cast()); + } + return algo; + } + + Scalar support(const Vec3& dir) { + assert(x.size() == y.size() == z.size()); + + Array4 x_dir(dir.x(), dir.x(), dir.x(), dir.x()); + Array4 y_dir(dir.y(), dir.y(), dir.y(), dir.y()); + Array4 z_dir(dir.z(), dir.z(), dir.z(), dir.z()); + + constexpr Scalar min_scalar = std::numeric_limits::min(); + Array4 max_dot(min_scalar, min_scalar, min_scalar, min_scalar); + + for (size_t i = 0; i < x.size(); ++i) { + Array4 dot_x = x[i] * x_dir; + Array4 dot_y = y[i] * y_dir; + Array4 dot_z = z[i] * z_dir; + Array4 dot = dot_x + dot_y + dot_z; + + Mask4 mask = max_dot > dot; + max_dot = mask.select(max_dot, dot); + } + + Scalar max_dot_scalar = max_dot.maxCoeff(); + for (size_t i = 0; i < remainder.size(); ++i) { + Scalar dot = remainder[i].dot(dir); + if (dot > max_dot_scalar) { + max_dot_scalar = dot; + } + } + + return max_dot_scalar; + } + + std::vector x, y, z; + std::vector remainder; +}; + +template +static void legacyLinearAlgorithmBench(benchmark::State& state) { + using Algorithm = LegacyLinearAlgorithm; + auto ico = + utils::IcosahedronDatabase::get(static_cast(state.range(0))); + auto algo = Algorithm::fromPoints(ico.points); + auto vec = Algorithm::Vec3::UnitX(); + for (auto _ : state) { + auto res = algo.support(vec); + benchmark::DoNotOptimize(res); + } +} + +static void SOAFloatEigenLinearAlgorithmBench(benchmark::State& state) { + using Algorithm = SOAFloatEigenLinearAlgorithm; + auto ico = + utils::IcosahedronDatabase::get(static_cast(state.range(0))); + auto algo = Algorithm::fromPoints(ico.points); + auto vec = Algorithm::Vec3::UnitX(); + for (auto _ : state) { + auto res = algo.support(vec); + benchmark::DoNotOptimize(res); + } +} + +template +static void SOAHighwayLinearAlgorithmBench(benchmark::State& state) { + using Algorithm = SOAHighwayAlgorithm; + + const auto target = state.range(0); + const auto num_subdiv = state.range(1); + + auto ico = + utils::IcosahedronDatabase::get(static_cast(num_subdiv)); + auto vec = Algorithm::Vec3::UnitX(); + hwy::SetSupportedTargetsForTest(target); + auto algo = Algorithm::fromPoints(ico.points); + for (auto _ : state) { + auto res = algo.support(vec); + benchmark::DoNotOptimize(res); + } + hwy::SetSupportedTargetsForTest(0); +} + +template +static void SOAHighwayLinearWithIndexAlgorithmBench(benchmark::State& state) { + using Algorithm = SOAHighwayAlgorithm; + + const auto target = state.range(0); + const auto num_subdiv = state.range(1); + + auto ico = + utils::IcosahedronDatabase::get(static_cast(num_subdiv)); + auto vec = Algorithm::Vec3::UnitX(); + hwy::SetSupportedTargetsForTest(target); + auto algo = Algorithm::fromPoints(ico.points); + for (auto _ : state) { + auto res = algo.supportWithIndex(vec); + benchmark::DoNotOptimize(res); + } + hwy::SetSupportedTargetsForTest(0); +} + +template +static void legacyLogWarmStartAlgorithmBench(benchmark::State& state) { + using Algorithm = LegacyLogAlgorithm; + + const auto std_dev = static_cast(state.range(0)) / 100.; + const auto num_subdiv = state.range(1); + + auto ico = utils::IcosahedronWithNeighborsDatabase::get( + static_cast(num_subdiv)); + auto algo = Algorithm::fromPointsAndNeighbors(ico.points, ico.neighbors); + + auto vecs = sampleVector(2., 2., std_dev); + + std::size_t hint = 0; + std::size_t i = 0; + for (auto _ : state) { + auto res_hint = algo.supportWithIndex(vecs[i % vecs.size()], hint); + benchmark::DoNotOptimize(res_hint); + hint = std::get<1>(res_hint); + ++i; + } +} + +template +static void SOANeighborLogWarmStartAlgorithmBench(benchmark::State& state) { + using Algorithm = SOANeighborLogAlgorithm; + + const auto std_dev = static_cast(state.range(0)) / 100.; + const auto num_subdiv = state.range(1); + + auto ico = utils::IcosahedronWithNeighborsDatabase::get( + static_cast(num_subdiv)); + auto algo = Algorithm::fromPointsAndNeighbors(ico.points, ico.neighbors); + + auto vecs = sampleVector(2., 2., std_dev); + + std::size_t hint = 0; + std::size_t i = 0; + for (auto _ : state) { + auto res_hint = algo.supportWithIndex(vecs[i % vecs.size()], hint); + benchmark::DoNotOptimize(res_hint); + hint = std::get<1>(res_hint); + ++i; + } +} + +template +static void SOALocalNeighborLogWarmStartAlgorithmBench( + benchmark::State& state) { + using Algorithm = SOALocalNeighborLogAlgorithm; + + const auto std_dev = static_cast(state.range(0)) / 100.; + const auto num_subdiv = state.range(1); + + auto ico = utils::IcosahedronWithNeighborsDatabase::get( + static_cast(num_subdiv)); + auto algo = Algorithm::fromPointsAndNeighbors(ico.points, ico.neighbors); + + auto vecs = sampleVector(2., 2., std_dev); + + std::size_t hint = 0; + std::size_t i = 0; + for (auto _ : state) { + auto res_hint = algo.supportWithIndex(vecs[i % vecs.size()], hint); + benchmark::DoNotOptimize(res_hint); + hint = std::get<1>(res_hint); + ++i; + } +} + +static void LinearCustomArguments(benchmark::internal::Benchmark* b) { + // 5 subdivide doesn't fit into L1 cache (10242 points > 48KB) + b->Arg(0)->Arg(1)->Arg(2)->Arg(3)->Arg(4)->Arg(5); +} +static void LinearCustomArgumentsHighway(benchmark::internal::Benchmark* b) { + for (std::int64_t target : hwy::SupportedAndGeneratedTargets()) { + if (target != HWY_SSSE3 && target != HWY_SSE4 && target != HWY_NEON_BF16) { + // 5 subdivide doesn't fit into L1 cache (10242 points > 48KB) + b->Args({target, 0}) + ->Args({target, 1}) + ->Args({target, 2}) + ->Args({target, 3}) + ->Args({target, 4}) + ->Args({target, 5}); + } + } +} +static void LogCustomArguments(benchmark::internal::Benchmark* b) { + // 5 subdivide doesn't fit into L1 cache (10242 points > 48KB) + b->ArgsProduct({{0, 1, 10, 1000}, {0, 1, 2, 3, 4, 5}}); +} + +BENCHMARK(legacyLinearAlgorithmBench)->Apply(LinearCustomArguments); +BENCHMARK(legacyLinearAlgorithmBench)->Apply(LinearCustomArguments); +BENCHMARK(SOAFloatEigenLinearAlgorithmBench)->Apply(LinearCustomArguments); +BENCHMARK(SOAHighwayLinearAlgorithmBench) + ->Apply(LinearCustomArgumentsHighway); +BENCHMARK(SOAHighwayLinearAlgorithmBench) + ->Apply(LinearCustomArgumentsHighway); +BENCHMARK(SOAHighwayLinearWithIndexAlgorithmBench) + ->Apply(LinearCustomArgumentsHighway); +BENCHMARK(SOAHighwayLinearWithIndexAlgorithmBench) + ->Apply(LinearCustomArgumentsHighway); +BENCHMARK(legacyLogWarmStartAlgorithmBench)->Apply(LogCustomArguments); +BENCHMARK(legacyLogWarmStartAlgorithmBench)->Apply(LogCustomArguments); +BENCHMARK(SOANeighborLogWarmStartAlgorithmBench) + ->Apply(LogCustomArguments); +BENCHMARK(SOANeighborLogWarmStartAlgorithmBench) + ->Apply(LogCustomArguments); +BENCHMARK(SOALocalNeighborLogWarmStartAlgorithmBench) + ->Apply(LogCustomArguments); +BENCHMARK(SOALocalNeighborLogWarmStartAlgorithmBench) + ->Apply(LogCustomArguments); + +} // namespace bench +} // namespace coal + +BENCHMARK_MAIN(); diff --git a/benchmark/convex_support_highway.cpp b/benchmark/convex_support_highway.cpp new file mode 100644 index 000000000..723619051 --- /dev/null +++ b/benchmark/convex_support_highway.cpp @@ -0,0 +1,242 @@ +#include "convex_support_highway.hh" + +#include +#include + +#undef HWY_TARGET_INCLUDE +#define HWY_TARGET_INCLUDE "convex_support_highway.cpp" +#include + +#include +#include + +HWY_BEFORE_NAMESPACE(); +namespace coal { +namespace bench { +namespace HWY_NAMESPACE { +namespace { + +namespace hn = hwy::HWY_NAMESPACE; + +template +SOAHighwayAlgorithm _fromPoints( + const std::vector& points) { + using Algorithm = SOAHighwayAlgorithm; + + const hn::ScalableTag d; + const std::size_t N = hn::Lanes(d); + const std::size_t remainder = points.size() % N; + const std::size_t padded_size = points.size() + (N - remainder); + + Algorithm algo; + algo.x = hwy::AllocateAligned(padded_size * 3); + algo.y = algo.x.get() + padded_size; + algo.z = algo.x.get() + 2 * padded_size; + algo.count = padded_size; + + for (std::size_t i = 0; i < points.size(); ++i) { + algo.x[i] = static_cast(points[i].x()); + algo.y[i] = static_cast(points[i].y()); + algo.z[i] = static_cast(points[i].z()); + } + for (std::size_t i = points.size(); i < padded_size; ++i) { + algo.x[i] = static_cast(points.back().x()); + algo.y[i] = static_cast(points.back().y()); + algo.z[i] = static_cast(points.back().z()); + } + return algo; +} + +template +Scalar _support(const Scalar* HWY_RESTRICT x, const Scalar* HWY_RESTRICT y, + const Scalar* HWY_RESTRICT z, Scalar x_dir, Scalar y_dir, + Scalar z_dir, std::size_t count) { + const hn::ScalableTag d; + const size_t N = hn::Lanes(d); + using V = decltype(hn::Zero(d)); + + V x_dir_v = hn::Set(d, x_dir); + V y_dir_v = hn::Set(d, y_dir); + V z_dir_v = hn::Set(d, z_dir); + + auto func = [&](std::size_t i) -> V { + const V x_v_ = hn::Load(d, x + i); + const V dot_v1_ = x_v_ * x_dir_v; + const V y_v_ = hn::Load(d, y + i); + const V dot_v2_ = hn::MulAdd(y_v_, y_dir_v, dot_v1_); + const V z_v_ = hn::Load(d, z + i); + return hn::MulAdd(z_v_, z_dir_v, dot_v2_); + }; + + V max_dot_v_ilp1 = hn::Set(d, std::numeric_limits::min()); + V max_dot_v_ilp2 = hn::Set(d, std::numeric_limits::min()); + size_t i = 0; + for (; i + N * 2 <= count; i += N * 2) { + const V dot_v_ilp1 = func(i); + max_dot_v_ilp1 = hn::Max(max_dot_v_ilp1, dot_v_ilp1); + + const V dot_v_ilp2 = func(i + 1 * N); + max_dot_v_ilp2 = hn::Max(max_dot_v_ilp2, dot_v_ilp2); + } + V max_dot_v = hn::Max(max_dot_v_ilp1, max_dot_v_ilp2); + + for (; i + N <= count; i += N) { + const V dot_v = func(i); + max_dot_v = hn::Max(max_dot_v, dot_v); + } + + return hn::ReduceMax(d, max_dot_v); +} + +template +std::tuple _supportWithIndex(const Scalar* HWY_RESTRICT x, + const Scalar* HWY_RESTRICT y, + const Scalar* HWY_RESTRICT z, + Scalar x_dir, Scalar y_dir, + Scalar z_dir, + std::size_t count) { + using DF = hn::ScalableTag; + const DF d; + const size_t N = hn::Lanes(d); + using V = decltype(hn::Zero(d)); + + // Create unsigned integer Vector type with same number + // of lanes than DF + const hn::RebindToUnsigned dui; + using VUI = decltype(hn::Zero(dui)); + + const V x_dir_v = hn::Set(d, x_dir); + const V y_dir_v = hn::Set(d, y_dir); + const V z_dir_v = hn::Set(d, z_dir); + + const VUI indices_increment_v = hn::Set(dui, 2 * N); + + // Compute dot product + auto dot_product = [&](std::size_t i) -> V { + const V x_v_ = hn::Load(d, x + i); + const V dot_v1_ = x_v_ * x_dir_v; + const V y_v_ = hn::Load(d, y + i); + const V dot_v2_ = hn::MulAdd(y_v_, y_dir_v, dot_v1_); + const V z_v_ = hn::Load(d, z + i); + return hn::MulAdd(z_v_, z_dir_v, dot_v2_); + }; + + // Extract max dot product and corresponding max indices + auto max_dot_and_indices = + [&dui](const V& dot_v, const VUI& indices_v, const V& max_dot_v, + const VUI& max_indices_v) -> std::tuple { + const auto mask_v = max_dot_v > dot_v; + // Max give better perf than using the mask + const V max_dot_v_tmp = hn::Max(max_dot_v, dot_v); + const VUI max_indices_v_tmp = + hn::IfThenElse(hn::RebindMask(dui, mask_v), max_indices_v, indices_v); + return std::make_tuple(max_dot_v_tmp, max_indices_v_tmp); + }; + + V max_dot_v_ilp1 = hn::Set(d, std::numeric_limits::min()); + V max_dot_v_ilp2 = hn::Set(d, std::numeric_limits::min()); + // Initialize indices with right index (0, 1, 2, ...) + VUI indices_v_ilp1 = hn::Iota(dui, 0); + VUI indices_v_ilp2 = hn::Iota(dui, N); + VUI max_indices_v_ilp1 = hn::Set(dui, 0); + VUI max_indices_v_ilp2 = hn::Set(dui, 0); + size_t i = 0; + // First pass with 2 ILP + for (; i + N * 2 <= count; i += N * 2) { + const V dot_v_ilp1 = dot_product(i); + std::tie(max_dot_v_ilp1, max_indices_v_ilp1) = max_dot_and_indices( + dot_v_ilp1, indices_v_ilp1, max_dot_v_ilp1, max_indices_v_ilp1); + indices_v_ilp1 += indices_increment_v; + + const V dot_v_ilp2 = dot_product(i + 1 * N); + std::tie(max_dot_v_ilp2, max_indices_v_ilp2) = max_dot_and_indices( + dot_v_ilp2, indices_v_ilp2, max_dot_v_ilp2, max_indices_v_ilp2); + indices_v_ilp2 += indices_increment_v; + } + // Merge first pass result + auto [max_dot_v, max_indices_v] = max_dot_and_indices( + max_dot_v_ilp1, max_indices_v_ilp1, max_dot_v_ilp2, max_indices_v_ilp2); + + // Second pass with the remaining batch + if (i + N <= count) { + const V dot_v = dot_product(i); + std::tie(max_dot_v, max_indices_v) = + max_dot_and_indices(dot_v, indices_v_ilp1, max_dot_v, max_indices_v); + } + + // Extract max scalar dot product and corresponding max indices + Scalar max_dot = hn::ReduceMax(d, max_dot_v); + const auto max_scalar_mask_v = max_dot_v == hn::Set(d, max_dot); + std::size_t best_index = hn::FindKnownFirstTrue(d, max_scalar_mask_v); + return std::make_tuple(max_dot, hn::ExtractLane(max_indices_v, best_index)); +} + +} // namespace +} // namespace HWY_NAMESPACE +} // namespace bench +} // namespace coal +HWY_AFTER_NAMESPACE(); + +#if HWY_ONCE +namespace coal { +namespace bench { + +namespace { + +HWY_EXPORT_T(_supportFloat, _support); +HWY_EXPORT_T(_supportDouble, _support); +HWY_EXPORT_T(_supportWithIndexFloat, _supportWithIndex); +HWY_EXPORT_T(_supportWithIndexDouble, _supportWithIndex); +HWY_EXPORT_T(_fromPointsFloat, _fromPoints); +HWY_EXPORT_T(_fromPointsDouble, _fromPoints); + +} // namespace + +float support(const float* HWY_RESTRICT x, const float* HWY_RESTRICT y, + const float* HWY_RESTRICT z, float x_dir, float y_dir, + float z_dir, std::size_t count) { + return HWY_DYNAMIC_DISPATCH_T(_supportFloat)(x, y, z, x_dir, y_dir, z_dir, + count); +} +double support(const double* HWY_RESTRICT x, const double* HWY_RESTRICT y, + const double* HWY_RESTRICT z, double x_dir, double y_dir, + double z_dir, std::size_t count) { + return HWY_DYNAMIC_DISPATCH_T(_supportDouble)(x, y, z, x_dir, y_dir, z_dir, + count); +} + +std::tuple supportWithIndex(const float* HWY_RESTRICT x, + const float* HWY_RESTRICT y, + const float* HWY_RESTRICT z, + float x_dir, float y_dir, + float z_dir, + std::size_t count) { + return HWY_DYNAMIC_DISPATCH_T(_supportWithIndexFloat)(x, y, z, x_dir, y_dir, + z_dir, count); +} +std::tuple supportWithIndex(const double* HWY_RESTRICT x, + const double* HWY_RESTRICT y, + const double* HWY_RESTRICT z, + double x_dir, double y_dir, + double z_dir, + std::size_t count) { + return HWY_DYNAMIC_DISPATCH_T(_supportWithIndexDouble)(x, y, z, x_dir, y_dir, + z_dir, count); +} + +template <> +SOAHighwayAlgorithm SOAHighwayAlgorithm::fromPoints( + const std::vector& points) { + return HWY_DYNAMIC_DISPATCH_T(_fromPointsFloat)(points); +} + +template <> +SOAHighwayAlgorithm SOAHighwayAlgorithm::fromPoints( + const std::vector& points) { + return HWY_DYNAMIC_DISPATCH_T(_fromPointsDouble)(points); +} + +} // namespace bench +} // namespace coal + +#endif // if HWY_ONCE diff --git a/benchmark/convex_support_highway.hh b/benchmark/convex_support_highway.hh new file mode 100644 index 000000000..8d92c08fb --- /dev/null +++ b/benchmark/convex_support_highway.hh @@ -0,0 +1,54 @@ +#ifndef COAL_BENCH_CONVEX_SUPPORT_HIGHWAY_HH +#define COAL_BENCH_CONVEX_SUPPORT_HIGHWAY_HH + +#include + +#include + +namespace coal { +namespace bench { + +float support(const float* HWY_RESTRICT x, const float* HWY_RESTRICT y, + const float* HWY_RESTRICT z, float x_dir, float y_dir, + float z_dir, std::size_t count); +double support(const double* HWY_RESTRICT x, const double* HWY_RESTRICT y, + const double* HWY_RESTRICT z, double x_dir, double y_dir, + double z_dir, std::size_t count); +std::tuple supportWithIndex(const float* HWY_RESTRICT x, + const float* HWY_RESTRICT y, + const float* HWY_RESTRICT z, + float x_dir, float y_dir, + float z_dir, std::size_t count); +std::tuple supportWithIndex(const double* HWY_RESTRICT x, + const double* HWY_RESTRICT y, + const double* HWY_RESTRICT z, + double x_dir, double y_dir, + double z_dir, + std::size_t count); + +template +struct SOAHighwayAlgorithm { + using Vec3 = Eigen::Vector; + using Algorithm = SOAHighwayAlgorithm; + + static Algorithm fromPoints(const std::vector& points); + Scalar support(const Vec3& dir) const { + return coal::bench::support(x.get(), y, z, dir.x(), dir.y(), dir.z(), + count); + } + std::tuple supportWithIndex(const Vec3& dir) const { + return coal::bench::supportWithIndex(x.get(), y, z, dir.x(), dir.y(), + dir.z(), count); + } + + // Allocate all in data in x. y and z are pointing inside x buffer. + // Only work if count is a multiple of Lanes (misalignment or load split) + hwy::AlignedFreeUniquePtr x; + Scalar *y, *z; + std::size_t count; +}; + +} // namespace bench +} // namespace coal + +#endif // ifndef COAL_BENCH_CONVEX_SUPPORT_HIGHWAY_HH diff --git a/benchmark/utils/icosahedron.cpp b/benchmark/utils/icosahedron.cpp new file mode 100644 index 000000000..4ed70e8b0 --- /dev/null +++ b/benchmark/utils/icosahedron.cpp @@ -0,0 +1,206 @@ +// associated header +#include "icosahedron.hh" + +#include +#include + +namespace coal { +namespace bench { +namespace utils { + +namespace { + +static Eigen::Vector3d toSphere(const Eigen::Vector3d& point, double scale) { + return scale / point.norm() * point; +} + +struct key_hash { + using Key = std::tuple; + std::size_t operator()(const Key& k) const { + return std::get<0>(k) ^ std::get<1>(k); + } +}; + +struct MiddlePointCache { + using Key = std::tuple; + + MiddlePointCache(std::vector* points) : points(points) {} + + std::size_t getMiddlePoint(std::size_t point1_index, + std::size_t point2_index) { + const auto [min, max] = std::minmax(point1_index, point2_index); + const auto [it, emplaced] = + index_from_segment.try_emplace({min, max}, points->size()); + if (emplaced) { + const Eigen::Vector3d& p1 = (*points)[point1_index]; + const Eigen::Vector3d& p2 = (*points)[point2_index]; + points->push_back(toSphere((p1 + p2) * 0.5, 1.)); + } + return it->second; + } + + void clear() { index_from_segment.clear(); } + + std::unordered_map index_from_segment; + std::vector* points; +}; + +} // namespace + +Icosahedron Icosahedron::construct(double scale) { + const double PHI = (1 + std::sqrt(5)) / 2; + Icosahedron ico; + ico.points.reserve(12); + ico.points.push_back(toSphere(Eigen::Vector3d(-1, PHI, 0), scale)); + ico.points.push_back(toSphere(Eigen::Vector3d(1, PHI, 0), scale)); + ico.points.push_back(toSphere(Eigen::Vector3d(-1, -PHI, 0), scale)); + ico.points.push_back(toSphere(Eigen::Vector3d(1, -PHI, 0), scale)); + + ico.points.push_back(toSphere(Eigen::Vector3d(0, -1, PHI), scale)); + ico.points.push_back(toSphere(Eigen::Vector3d(0, 1, PHI), scale)); + ico.points.push_back(toSphere(Eigen::Vector3d(0, -1, -PHI), scale)); + ico.points.push_back(toSphere(Eigen::Vector3d(0, 1, -PHI), scale)); + + ico.points.push_back(toSphere(Eigen::Vector3d(PHI, 0, -1), scale)); + ico.points.push_back(toSphere(Eigen::Vector3d(PHI, 0, 1), scale)); + ico.points.push_back(toSphere(Eigen::Vector3d(-PHI, 0, -1), scale)); + ico.points.push_back(toSphere(Eigen::Vector3d(-PHI, 0, 1), scale)); + + ico.triangles.reserve(20); + ico.triangles.push_back({0, 11, 5}); + ico.triangles.push_back({0, 5, 1}); + ico.triangles.push_back({0, 1, 7}); + ico.triangles.push_back({0, 7, 10}); + ico.triangles.push_back({0, 10, 11}); + + ico.triangles.push_back({1, 5, 9}); + ico.triangles.push_back({5, 11, 4}); + ico.triangles.push_back({11, 10, 2}); + ico.triangles.push_back({10, 7, 6}); + ico.triangles.push_back({7, 1, 8}); + + ico.triangles.push_back({3, 9, 4}); + ico.triangles.push_back({3, 4, 2}); + ico.triangles.push_back({3, 2, 6}); + ico.triangles.push_back({3, 6, 8}); + ico.triangles.push_back({3, 8, 9}); + + ico.triangles.push_back({4, 9, 5}); + ico.triangles.push_back({2, 4, 11}); + ico.triangles.push_back({6, 2, 10}); + ico.triangles.push_back({8, 6, 7}); + ico.triangles.push_back({9, 8, 1}); + + return ico; +} + +Icosahedron Icosahedron::subdivide(std::size_t num_subdiv) const { + Icosahedron ico(*this); + + // Temporary buffer + std::vector new_triangles; + + // Reserve memory to avoid reallocation + std::size_t total_points_count = points.size(); + std::size_t triangle_pow = 1; + for (std::size_t i = 0; i < num_subdiv; ++i) { + // 6 new points per 4 triangles + total_points_count += 6 * (triangle_pow * triangles.size()) / 4; + triangle_pow *= 4; + } + ico.points.reserve(total_points_count); + std::size_t total_triangle_count = triangle_pow * triangles.size(); + new_triangles.reserve(total_triangle_count); + ico.triangles.reserve(total_triangle_count); + + MiddlePointCache cache(&ico.points); + + for (std::size_t step = 0; step < num_subdiv; ++step) { + new_triangles.clear(); + for (const auto& tri : ico.triangles) { + std::size_t v1_index = cache.getMiddlePoint(tri[0], tri[1]); + std::size_t v2_index = cache.getMiddlePoint(tri[1], tri[2]); + std::size_t v3_index = cache.getMiddlePoint(tri[2], tri[0]); + + new_triangles.push_back({tri[0], v1_index, v3_index}); + new_triangles.push_back({tri[1], v2_index, v1_index}); + new_triangles.push_back({tri[2], v3_index, v2_index}); + new_triangles.push_back({v1_index, v2_index, v3_index}); + } + std::swap(ico.triangles, new_triangles); + } + return ico; +} + +void Icosahedron::toSTL(std::ostream& stream) const { + stream << "solid icosahedron\n"; + for (const auto& tri : triangles) { + const auto& v1 = points[tri[0]]; + const auto& v2 = points[tri[1]]; + const auto& v3 = points[tri[2]]; + stream << " facet normal 0 0 0\n"; + stream << " outer loop\n"; + stream << " vertex " << v1.x() << " " << v1.y() << " " << v1.z() + << "\n"; + stream << " vertex " << v2.x() << " " << v2.y() << " " << v2.z() + << "\n"; + stream << " vertex " << v3.x() << " " << v3.y() << " " << v3.z() + << "\n"; + stream << " endloop\n"; + stream << " endfacet\n"; + } + stream << "endsolid icosahedron\n"; +} + +void IcosahedronWithNeighbors::constructNeighbors() { + neighbors.resize(points.size()); + auto push_if_not_exist = [&](std::size_t vertex_index, + std::size_t neighbor_index) { + auto& vertex_neighbors = neighbors[vertex_index]; + auto it = std::find(vertex_neighbors.begin(), vertex_neighbors.end(), + neighbor_index); + if (it == vertex_neighbors.end()) { + vertex_neighbors.push_back(neighbor_index); + } + }; + for (const auto& tri : triangles) { + push_if_not_exist(tri[0], tri[1]); + push_if_not_exist(tri[0], tri[2]); + + push_if_not_exist(tri[1], tri[0]); + push_if_not_exist(tri[1], tri[2]); + + push_if_not_exist(tri[2], tri[0]); + push_if_not_exist(tri[2], tri[1]); + } +} + +const Icosahedron& IcosahedronDatabase::get(std::size_t num_subdiv) { + auto it = icosahedrons.find(num_subdiv); + if (it != icosahedrons.end()) { + return it->second; + } + return icosahedrons + .insert({num_subdiv, Icosahedron::construct(1.).subdivide(num_subdiv)}) + .first->second; +} +std::unordered_map IcosahedronDatabase::icosahedrons; + +const IcosahedronWithNeighbors& IcosahedronWithNeighborsDatabase::get( + std::size_t num_subdiv) { + auto it = icosahedrons.find(num_subdiv); + if (it != icosahedrons.end()) { + return it->second; + } + return icosahedrons + .insert( + {num_subdiv, IcosahedronWithNeighbors( + Icosahedron::construct(1.).subdivide(num_subdiv))}) + .first->second; +} +std::unordered_map + IcosahedronWithNeighborsDatabase::icosahedrons; + +} // namespace utils +} // namespace bench +} // namespace coal diff --git a/benchmark/utils/icosahedron.hh b/benchmark/utils/icosahedron.hh new file mode 100644 index 000000000..a3ab3b39c --- /dev/null +++ b/benchmark/utils/icosahedron.hh @@ -0,0 +1,71 @@ +#ifndef COAL_BENCH_UTILS_ICOSAHEDRON_HH +#define COAL_BENCH_UTILS_ICOSAHEDRON_HH + +#include + +#include +#include +#include +#include + +namespace coal { +namespace bench { +namespace utils { + +class Icosahedron { + public: + using TriangleIndex = std::array; + + /// Construct a icosahedron. + /// For explanation, see: + /// https://sinestesia.co/blog/tutorials/python-icospheres/ + static Icosahedron construct(double scale); + + Icosahedron subdivide(std::size_t num_subdiv) const; + void toSTL(std::ostream& stream) const; + + public: + std::vector points; + std::vector triangles; +}; + +class IcosahedronWithNeighbors { + public: + using TriangleIndex = std::array; + using NeighborIndexes = std::vector; + + IcosahedronWithNeighbors(Icosahedron ico) + : points(std::move(ico.points)), triangles(std::move(ico.triangles)) { + constructNeighbors(); + } + + protected: + void constructNeighbors(); + + public: + std::vector points; + std::vector triangles; + std::vector neighbors; +}; + +class IcosahedronDatabase { + public: + static const Icosahedron& get(std::size_t num_subdiv); + + protected: + static std::unordered_map icosahedrons; +}; + +class IcosahedronWithNeighborsDatabase { + public: + static const IcosahedronWithNeighbors& get(std::size_t num_subdiv); + + protected: + static std::unordered_map icosahedrons; +}; + +} // namespace utils +} // namespace bench +} // namespace coal + +#endif // ifndef COAL_BENCH_UTILS_ICOSAHEDRON_HH diff --git a/benchmark/utils/sparse_set.hh b/benchmark/utils/sparse_set.hh new file mode 100644 index 000000000..b379ec3ff --- /dev/null +++ b/benchmark/utils/sparse_set.hh @@ -0,0 +1,82 @@ +#ifndef COAL_BENCH_UTILS_SPARSE_SET_HH +#define COAL_BENCH_UTILS_SPARSE_SET_HH + +// includes +// std +#include +#include + +namespace coal { +namespace bench { +namespace utils { + +template +class SparseSet { + public: + using IndexType = _IndexType; + + public: + SparseSet() = default; + SparseSet(std::size_t max_val, std::size_t capacity) + : m_dense(), + m_sparse(max_val, DenseIndex(static_cast(capacity))) { + m_dense.reserve(capacity); + } + + void insert(std::size_t sparse_index) { + assert(("SparseSet::insert fail: Out of range query", + sparse_index < m_sparse.size())); + + SparseIndex si(static_cast(sparse_index)); + DenseIndex di(static_cast(size())); + + value(si, di); + push_back(si); + } + + bool contains(std::size_t sparse_index) const { + assert(("SparseSet::contains fail: Out of range query", + sparse_index < m_sparse.size())); + // Check that the sparse value is pointing through a valid dense index + // and that the dense value is equal to the sparse index + SparseIndex si(static_cast(sparse_index)); + auto di = value(si); + if (static_cast(di.index) < size() && + value(di).index == si.index) { + return true; + } + return false; + } + + std::size_t size() const { return m_dense.size(); } + + void clear() { m_dense.clear(); } + + private: + struct SparseIndex { + SparseIndex() = default; + explicit SparseIndex(IndexType i) : index(i) {} + IndexType index; + }; + struct DenseIndex { + DenseIndex() = default; + explicit DenseIndex(IndexType i) : index(i) {} + IndexType index; + }; + + DenseIndex value(SparseIndex i) const { return m_sparse[i.index]; } + SparseIndex value(DenseIndex i) const { return m_dense[i.index]; } + + void value(SparseIndex si, DenseIndex di) { m_sparse[si.index] = di; } + void push_back(SparseIndex si) { m_dense.push_back(si); }; + + private: + std::vector m_dense; + std::vector m_sparse; +}; + +} // namespace utils +} // namespace bench +} // namespace coal + +#endif // ifndef COAL_BENCH_UTILS_SPARSE_SET_HH diff --git a/development/scripts/pixi/activation.bat b/development/scripts/pixi/activation.bat index 89fa491ea..e15f9fbb8 100644 --- a/development/scripts/pixi/activation.bat +++ b/development/scripts/pixi/activation.bat @@ -15,3 +15,4 @@ if not defined COAL_BUILD_TYPE (set COAL_BUILD_TYPE=Release) if not defined COAL_PYTHON_STUBS (set COAL_PYTHON_STUBS=ON) if not defined COAL_PYTHON_NANOBIND (set COAL_PYTHON_NANOBIND=ON) if not defined COAL_HAS_QHULL (set COAL_HAS_QHULL=OFF) +if not defined COAL_BUILD_BENCHMARK (set COAL_BUILD_BENCHMARK=OFF) diff --git a/development/scripts/pixi/activation.sh b/development/scripts/pixi/activation.sh index a178c73f2..746f794a0 100644 --- a/development/scripts/pixi/activation.sh +++ b/development/scripts/pixi/activation.sh @@ -12,11 +12,17 @@ unset LDFLAGS if [[ $host_alias == *"apple"* ]]; then + # Conda compilers look automatically inside this directory but clangd is unaware of it + # without this flag + export CXXFLAGS="-isystem $CONDA_PREFIX/include" # On OSX setting the rpath and -L it's important to use the conda libc++ instead of the system one. # If conda-forge use install_name_tool to package some libs, -headerpad_max_install_names is then mandatory export LDFLAGS="-Wl,-headerpad_max_install_names -Wl,-rpath,$CONDA_PREFIX/lib -L$CONDA_PREFIX/lib" elif [[ $host_alias == *"linux"* ]]; then + # Conda compilers look automatically inside this directory but clangd is unaware of it + # without this flag + export CXXFLAGS="-isystem $CONDA_PREFIX/include" # On GNU/Linux, I don't know if these flags are mandatory with g++ but # it allow to use clang++ as compiler export LDFLAGS="-Wl,-rpath,$CONDA_PREFIX/lib -Wl,-rpath-link,$CONDA_PREFIX/lib -L$CONDA_PREFIX/lib" @@ -39,3 +45,4 @@ export COAL_BUILD_TYPE=${COAL_BUILD_TYPE:=Release} export COAL_PYTHON_STUBS=${COAL_PYTHON_STUBS:=ON} export COAL_PYTHON_NANOBIND=${COAL_PYTHON_NANOBIND:=ON} export COAL_HAS_QHULL=${COAL_HAS_QHULL:=OFF} +export COAL_BUILD_BENCHMARK=${COAL_BUILD_BENCHMARK:=OFF} diff --git a/pixi.lock b/pixi.lock index bb923fc8b..a419ea129 100644 --- a/pixi.lock +++ b/pixi.lock @@ -8,6 +8,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-64/assimp-5.4.3-hecf2907_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/benchmark-1.9.4-h5888daf_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils-2.44-h4852527_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_impl_linux-64-2.44-hdf8817f_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_linux-64-2.44-h4852527_2.conda @@ -56,6 +57,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.1.0-hcea5267_5.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.1.0-h767d61c_5.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libhiredis-1.0.2-h2cc385e_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/libhwy-1.3.0-h4c17acf_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h3b78370_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-36_h47877c9_openblas.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.1-hb9d3cd8_2.conda @@ -100,6 +102,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb8e6e7a_2.conda osx-64: - conda: https://conda.anaconda.org/conda-forge/osx-64/assimp-5.4.3-hd65d9c6_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/benchmark-1.9.4-h240833e_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/bzip2-1.0.8-h500dc9f_8.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/c-ares-1.34.5-hf13058a_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/c-compiler-1.11.0-h7a00415_0.conda @@ -146,6 +149,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran-15.1.0-h5f6db21_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran5-15.1.0-hfa3c126_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libhiredis-1.0.2-h2beb688_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-64/libhwy-1.3.0-hab838a1_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libiconv-1.18-h57a12c2_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libintl-0.25.1-h3184127_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/liblapack-3.9.0-36_h859234e_openblas.conda @@ -190,6 +194,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/zstd-1.5.7-h8210216_2.conda osx-arm64: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/assimp-5.4.3-h31c7375_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/benchmark-1.9.4-h286801f_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-hd037594_8.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.5-h5505292_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-compiler-1.11.0-h61f9b84_0.conda @@ -237,6 +242,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran5-15.1.0-hb74de2c_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libglib-2.86.0-h1bb475b_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libhiredis-1.0.2-hbec66e7_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libhwy-1.3.0-h48b13b8_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libiconv-1.18-h23cfdf5_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libintl-0.25.1-h493aca8_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblapack-3.9.0-36_hd9741b5_openblas.conda @@ -281,6 +287,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.7-h6491c7d_2.conda win-64: - conda: https://conda.anaconda.org/conda-forge/win-64/assimp-5.4.3-hfc39600_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/benchmark-1.9.4-he0c23c2_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h0ad9c76_8.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2025.8.3-h4c7d964_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/ccache-4.11.3-h12b022e_0.conda @@ -306,6 +313,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/win-64/libglib-2.86.0-h5f26cbf_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libhiredis-1.0.2-h0e60522_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/win-64/libhwloc-2.12.1-default_h88281d1_1000.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libhwy-1.3.0-ha71e874_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libiconv-1.18-hc1393d2_2.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libintl-0.22.5-h5728263_3.conda - conda: https://conda.anaconda.org/conda-forge/win-64/liblapack-3.9.0-35_hf9ab0e9_mkl.conda @@ -354,6 +362,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-64/assimp-5.4.3-hecf2907_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/benchmark-1.9.4-h5888daf_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils-2.44-h4852527_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_impl_linux-64-2.44-hdf8817f_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_linux-64-2.44-h4852527_2.conda @@ -405,6 +414,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.1.0-hcea5267_5.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.1.0-h767d61c_5.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libhiredis-1.0.2-h2cc385e_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/libhwy-1.3.0-h4c17acf_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h3b78370_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-36_h47877c9_openblas.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.1-hb9d3cd8_2.conda @@ -450,6 +460,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb8e6e7a_2.conda osx-64: - conda: https://conda.anaconda.org/conda-forge/osx-64/assimp-5.4.3-hd65d9c6_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/benchmark-1.9.4-h240833e_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/bzip2-1.0.8-h500dc9f_8.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/c-ares-1.34.5-hf13058a_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/c-compiler-1.11.0-h7a00415_0.conda @@ -499,6 +510,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran-15.1.0-h5f6db21_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran5-15.1.0-hfa3c126_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libhiredis-1.0.2-h2beb688_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-64/libhwy-1.3.0-hab838a1_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libiconv-1.18-h57a12c2_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libintl-0.25.1-h3184127_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/liblapack-3.9.0-36_h859234e_openblas.conda @@ -544,6 +556,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/zstd-1.5.7-h8210216_2.conda osx-arm64: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/assimp-5.4.3-h31c7375_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/benchmark-1.9.4-h286801f_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-hd037594_8.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.5-h5505292_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-compiler-1.11.0-h61f9b84_0.conda @@ -594,6 +607,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran5-15.1.0-hb74de2c_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libglib-2.86.0-h1bb475b_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libhiredis-1.0.2-hbec66e7_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libhwy-1.3.0-h48b13b8_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libiconv-1.18-h23cfdf5_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libintl-0.25.1-h493aca8_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblapack-3.9.0-36_hd9741b5_openblas.conda @@ -639,6 +653,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.7-h6491c7d_2.conda win-64: - conda: https://conda.anaconda.org/conda-forge/win-64/assimp-5.4.3-hfc39600_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/benchmark-1.9.4-he0c23c2_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h0ad9c76_8.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2025.8.3-h4c7d964_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/ccache-4.11.3-h12b022e_0.conda @@ -667,6 +682,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/win-64/libglib-2.86.0-h5f26cbf_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libhiredis-1.0.2-h0e60522_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/win-64/libhwloc-2.12.1-default_h88281d1_1000.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libhwy-1.3.0-ha71e874_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libiconv-1.18-hc1393d2_2.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libintl-0.22.5-h5728263_3.conda - conda: https://conda.anaconda.org/conda-forge/win-64/liblapack-3.9.0-35_hf9ab0e9_mkl.conda @@ -714,6 +730,7 @@ environments: packages: win-64: - conda: https://conda.anaconda.org/conda-forge/win-64/assimp-5.4.3-hfc39600_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/benchmark-1.9.4-he0c23c2_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h0ad9c76_8.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2025.8.3-h4c7d964_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/ccache-4.11.3-h12b022e_0.conda @@ -739,6 +756,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/win-64/libglib-2.86.0-h5f26cbf_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libhiredis-1.0.2-h0e60522_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/win-64/libhwloc-2.12.1-default_h88281d1_1000.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libhwy-1.3.0-ha71e874_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libiconv-1.18-hc1393d2_2.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libintl-0.22.5-h5728263_3.conda - conda: https://conda.anaconda.org/conda-forge/win-64/liblapack-3.9.0-35_hf9ab0e9_mkl.conda @@ -787,6 +805,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-64/assimp-5.4.3-hecf2907_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/benchmark-1.9.4-h5888daf_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils-2.44-h4852527_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_impl_linux-64-2.44-hdf8817f_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_linux-64-2.44-h4852527_2.conda @@ -835,6 +854,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.1.0-hcea5267_5.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.1.0-h767d61c_5.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libhiredis-1.0.2-h2cc385e_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/libhwy-1.3.0-h4c17acf_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h3b78370_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-36_h47877c9_openblas.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.1-hb9d3cd8_2.conda @@ -880,6 +900,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb8e6e7a_2.conda osx-64: - conda: https://conda.anaconda.org/conda-forge/osx-64/assimp-5.4.3-hd65d9c6_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/benchmark-1.9.4-h240833e_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/bzip2-1.0.8-h500dc9f_8.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/c-ares-1.34.5-hf13058a_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/c-compiler-1.11.0-h7a00415_0.conda @@ -926,6 +947,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran-15.1.0-h5f6db21_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran5-15.1.0-hfa3c126_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libhiredis-1.0.2-h2beb688_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-64/libhwy-1.3.0-hab838a1_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libiconv-1.18-h57a12c2_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libintl-0.25.1-h3184127_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/liblapack-3.9.0-36_h859234e_openblas.conda @@ -970,6 +992,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/zstd-1.5.7-h8210216_2.conda osx-arm64: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/assimp-5.4.3-h31c7375_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/benchmark-1.9.4-h286801f_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-hd037594_8.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.5-h5505292_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-compiler-1.11.0-h61f9b84_0.conda @@ -1017,6 +1040,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran5-15.1.0-hb74de2c_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libglib-2.86.0-h1bb475b_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libhiredis-1.0.2-hbec66e7_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libhwy-1.3.0-h48b13b8_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libiconv-1.18-h23cfdf5_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libintl-0.25.1-h493aca8_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblapack-3.9.0-36_hd9741b5_openblas.conda @@ -1061,6 +1085,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.7-h6491c7d_2.conda win-64: - conda: https://conda.anaconda.org/conda-forge/win-64/assimp-5.4.3-hfc39600_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/benchmark-1.9.4-he0c23c2_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h0ad9c76_8.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2025.8.3-h4c7d964_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/ccache-4.11.3-h12b022e_0.conda @@ -1086,6 +1111,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/win-64/libglib-2.86.0-h5f26cbf_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libhiredis-1.0.2-h0e60522_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/win-64/libhwloc-2.12.1-default_h88281d1_1000.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libhwy-1.3.0-ha71e874_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libiconv-1.18-hc1393d2_2.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libintl-0.22.5-h5728263_3.conda - conda: https://conda.anaconda.org/conda-forge/win-64/liblapack-3.9.0-35_hf9ab0e9_mkl.conda @@ -1126,6 +1152,349 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/vswhere-3.1.7-h40126e0_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/zlib-1.3.1-h2466b09_2.conda - conda: https://conda.anaconda.org/conda-forge/win-64/zstd-1.5.7-hbeecb71_2.conda + benchmark: + channels: + - url: https://conda.anaconda.org/conda-forge/ + packages: + linux-64: + - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/assimp-5.4.3-hecf2907_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/benchmark-1.9.4-h5888daf_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils-2.44-h4852527_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_impl_linux-64-2.44-hdf8817f_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_linux-64-2.44-h4852527_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_8.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.5-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/c-compiler-1.11.0-h4d9bdce_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2025.8.3-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ccache-4.11.3-h80c52d3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cmake-4.1.2-hc85cc9f_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/conda-gcc-specs-14.3.0-hb991d5c_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cxx-compiler-1.11.0-hfcd1e18_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/doxygen-1.13.2-h8e693c7_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/eigen-3.4.0-h00ab1b0_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gcc-14.3.0-h76bdaa0_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gcc_impl_linux-64-14.3.0-hd9e9e21_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gcc_linux-64-14.3.0-h1382650_11.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/git-2.51.0-pl5321h8305f47_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gxx-14.3.0-he448592_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gxx_impl_linux-64-14.3.0-he663afc_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gxx_linux-64-14.3.0-ha7acb78_11.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/icu-75.1-he02047a_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/kernel-headers_linux-64-4.18.0-he073ed8_8.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.3-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.21.3-h659f571_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.44-ha97dd6f_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libamd-3.3.3-h456b2da_7100101.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-36_h4a7cf45_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libboost-1.88.0-hed09d94_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libboost-devel-1.88.0-hfcd1e18_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libboost-headers-1.88.0-ha770c72_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcamd-3.3.3-hf02c80a_7100101.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-36_h0358290_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libccolamd-3.3.4-hf02c80a_7100101.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcholmod-5.3.1-h9cf07ce_7100101.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcolamd-3.3.4-hf02c80a_7100101.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.14.1-h332b0f4_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-hd590300_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.7.1-hecca717_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.6-h2dba641_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.1.0-h767d61c_5.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/libgcc-devel_linux-64-14.3.0-h85bb3a7_105.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.1.0-h69a702a_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.1.0-h69a702a_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-ng-15.1.0-h69a702a_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.1.0-hcea5267_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.1.0-h767d61c_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libhiredis-1.0.2-h2cc385e_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/libhwy-1.3.0-h4c17acf_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h3b78370_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-36_h47877c9_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.1-hb9d3cd8_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.67.0-had1ee68_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.30-pthreads_h94d23a6_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsanitizer-14.3.0-hd08acf3_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.50.4-h0c1763c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-hcf80075_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.1.0-h8f9b012_5.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/libstdcxx-devel_linux-64-14.3.0-h85bb3a7_105.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-15.1.0-h4852527_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsuitesparseconfig-7.10.1-h901830b_7100101.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.41.2-he9a06e4_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.51.0-hb03c661_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.13.8-h04c0eec_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxslt-1.1.43-h7a3aeb2_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lxml-6.0.2-py313h6b0e12e_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nanobind-2.9.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/nanoeigenpy-0.4.0-np2py313h7a8f570_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ninja-1.13.1-h171cf75_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.3.3-py313hf6604e3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.5.3-h26f9b46_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.46-h1321c63_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/perl-5.32.1-7_hd590300_perl5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pkg-config-0.29.2-h4bc722e_1009.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pylatexenc-2.10-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.13.7-h2b335a9_100_cp313.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.13-8_cp313.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8c095d6_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/rhash-1.4.6-hb9d3cd8_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sysroot_linux-64-2.28-h4ee821c_8.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_hd72426e_102.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025b-h78e105d_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.1-hb9d3cd8_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb8e6e7a_2.conda + osx-64: + - conda: https://conda.anaconda.org/conda-forge/osx-64/assimp-5.4.3-hd65d9c6_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/benchmark-1.9.4-h240833e_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/bzip2-1.0.8-h500dc9f_8.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/c-ares-1.34.5-hf13058a_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/c-compiler-1.11.0-h7a00415_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2025.8.3-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ccache-4.11.3-h33566b8_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/cctools-1024.3-h67a6458_4.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/cctools_osx-64-1024.3-h3b512aa_4.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clang-19-19.1.7-default_hc369343_4.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clang-19.1.7-default_h1323312_4.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clang_impl_osx-64-19.1.7-hc73cdc9_25.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clang_osx-64-19.1.7-h7e5c614_25.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx-19.1.7-default_h1c12a56_4.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx_impl_osx-64-19.1.7-hb295874_25.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx_osx-64-19.1.7-h7e5c614_25.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/cmake-4.1.2-h29fc008_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/compiler-rt-19.1.7-he914875_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/compiler-rt_osx-64-19.1.7-h138dee1_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/cxx-compiler-1.11.0-h307afc9_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/doxygen-1.13.2-h27064b9_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/eigen-3.4.0-h1c7c39f_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/git-2.51.0-pl5321h110a47f_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/icu-75.1-h120a0e1_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/krb5-1.21.3-h37d8d59_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ld64-955.13-hc3792c1_4.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ld64_osx-64-955.13-h466f870_4.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libamd-3.3.3-ha5840a7_7100102.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libblas-3.9.0-36_he492b99_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libboost-1.88.0-hf9ddd82_5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libboost-devel-1.88.0-h7a7523a_5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libboost-headers-1.88.0-h694c41f_5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libcamd-3.3.3-hca54c18_7100102.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libcblas-3.9.0-36_h9b27e0a_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libccolamd-3.3.4-hca54c18_7100102.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libcholmod-5.3.1-h7ea7d7c_7100102.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libclang-cpp19.1-19.1.7-default_hc369343_4.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libcolamd-3.3.4-hca54c18_7100102.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libcurl-8.14.1-h5dec5d8_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libcxx-21.1.2-h3d58e20_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libcxx-devel-19.1.7-h7c275be_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libedit-3.1.20250104-pl5321ha958ccf_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libev-4.33-h10d778d_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libexpat-2.7.1-h21dd04a_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libffi-3.4.6-h281671d_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran-15.1.0-h5f6db21_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran5-15.1.0-hfa3c126_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libhiredis-1.0.2-h2beb688_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-64/libhwy-1.3.0-hab838a1_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libiconv-1.18-h57a12c2_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libintl-0.25.1-h3184127_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/liblapack-3.9.0-36_h859234e_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libllvm19-19.1.7-hc29ff6c_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/liblzma-5.8.1-hd471939_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libmpdec-4.0.0-h6e16a3a_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libnghttp2-1.67.0-h3338091_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libopenblas-0.3.30-openmp_h83c2472_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.50.4-h39a8b3b_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libssh2-1.11.1-hed3591d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libsuitesparseconfig-7.10.1-h00e5f87_7100102.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libuv-1.51.0-h58003a5_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libxml2-2.13.8-he1bc88e_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libxslt-1.1.43-h59ddae0_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libzlib-1.3.1-hd23fc13_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-openmp-21.1.2-h472b3d1_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-tools-19-19.1.7-he90a8e3_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-tools-19.1.7-h3fe3016_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/lxml-6.0.2-py313hab0d6fc_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nanobind-2.9.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/nanoeigenpy-0.4.0-np2py313h93e9891_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ncurses-6.5-h0622a9a_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ninja-1.13.1-h0ba0a54_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/numpy-2.3.3-py313ha99c057_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.5.3-h230baf5_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/pcre2-10.46-ha3e7e28_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/perl-5.32.1-7_h10d778d_perl5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/pkg-config-0.29.2-hf7e621a_1009.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pylatexenc-2.10-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/python-3.13.7-h5eba815_100_cp313.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.13-8_cp313.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/readline-8.2-h7cca4af_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/rhash-1.4.6-h6e16a3a_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/sigtool-0.1.3-h88f4db0_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-64/tapi-1300.6.5-h390ca13_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.13-hf689a15_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025b-h78e105d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/zlib-1.3.1-hd23fc13_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/zstd-1.5.7-h8210216_2.conda + osx-arm64: + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/assimp-5.4.3-h31c7375_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/benchmark-1.9.4-h286801f_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-hd037594_8.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.5-h5505292_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-compiler-1.11.0-h61f9b84_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2025.8.3-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ccache-4.11.3-hd7c7cec_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cctools-1024.3-hd01ab73_4.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cctools_osx-arm64-1024.3-h8c76c84_4.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang-19-19.1.7-default_h73dfc95_4.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang-19.1.7-default_hf9bcbb7_4.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang_impl_osx-arm64-19.1.7-h76e6a08_25.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang_osx-arm64-19.1.7-h07b0088_25.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clangxx-19.1.7-default_h36137df_4.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clangxx_impl_osx-arm64-19.1.7-h276745f_25.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clangxx_osx-arm64-19.1.7-h07b0088_25.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cmake-4.1.2-h54ad630_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/compiler-rt-19.1.7-h855ad52_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/compiler-rt_osx-arm64-19.1.7-he32a8d3_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cxx-compiler-1.11.0-h88570a1_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/doxygen-1.13.2-h493aca8_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/eigen-3.4.0-h1995070_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/git-2.51.0-pl5321h6ee1a4f_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-75.1-hfee45f7_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/krb5-1.21.3-h237132a_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ld64-955.13-he86490a_4.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ld64_osx-arm64-955.13-h6922315_4.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libamd-3.3.3-h5087772_7100102.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libblas-3.9.0-36_h51639a9_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libboost-1.88.0-h18cd856_5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libboost-devel-1.88.0-hf450f58_5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libboost-headers-1.88.0-hce30654_5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcamd-3.3.3-h99b4a89_7100102.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcblas-3.9.0-36_hb0561ab_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libccolamd-3.3.4-h99b4a89_7100102.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcholmod-5.3.1-hbba04d7_7100102.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libclang-cpp19.1-19.1.7-default_h73dfc95_4.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcolamd-3.3.4-h99b4a89_7100102.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcurl-8.14.1-h73640d1_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-21.1.2-hf598326_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-devel-19.1.7-h6dc3340_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libedit-3.1.20250104-pl5321hafb1f1b_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libev-4.33-h93a5062_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.7.1-hec049ff_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.4.6-h1da3d7d_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran-15.1.0-hfdf1602_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran5-15.1.0-hb74de2c_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libglib-2.86.0-h1bb475b_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libhiredis-1.0.2-hbec66e7_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libhwy-1.3.0-h48b13b8_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libiconv-1.18-h23cfdf5_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libintl-0.25.1-h493aca8_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblapack-3.9.0-36_hd9741b5_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libllvm19-19.1.7-hc4b4ae8_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-5.8.1-h39f12f2_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libmpdec-4.0.0-h5505292_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libnghttp2-1.67.0-hc438710_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libopenblas-0.3.30-openmp_h60d53f8_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.50.4-h4237e3c_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libssh2-1.11.1-h1590b86_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsuitesparseconfig-7.10.1-h4a8fc20_7100102.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libuv-1.51.0-h6caf38d_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libxml2-2.13.8-h4a9ca0c_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libxslt-1.1.43-h429d6fd_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.1-h8359307_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-openmp-21.1.2-h4a912ad_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-tools-19-19.1.7-h87a4c7e_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-tools-19.1.7-hd2aecb6_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/lxml-6.0.2-py313he472ade_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nanobind-2.9.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nanoeigenpy-0.4.0-np2py313hd3e4208_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h5e97a16_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ninja-1.13.1-h4f10f1e_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.3.3-py313h9771d21_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.5.3-h5503f6c_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pcre2-10.46-h7125dd6_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/perl-5.32.1-7_h4614cfb_perl5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pkg-config-0.29.2-hde07d2e_1009.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pylatexenc-2.10-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.13.7-h5c937ed_100_cp313.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.13-8_cp313.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.2-h1d1bf99_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/rhash-1.4.6-h5505292_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/sigtool-0.1.3-h44b9a77_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tapi-1300.6.5-h03f4b80_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h892fb3f_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025b-h78e105d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zlib-1.3.1-h8359307_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.7-h6491c7d_2.conda + win-64: + - conda: https://conda.anaconda.org/conda-forge/win-64/assimp-5.4.3-hfc39600_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/benchmark-1.9.4-he0c23c2_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h0ad9c76_8.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2025.8.3-h4c7d964_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/ccache-4.11.3-h12b022e_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/cmake-4.1.2-hdcbee5b_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/cxx-compiler-1.11.0-h1c1089f_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/doxygen-1.13.2-hbf3f430_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/eigen-3.4.0-h91493d7_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/git-2.51.0-h57928b3_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/krb5-1.21.3-hdf4eb48_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libamd-3.3.3-h60129d2_7100102.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libblas-3.9.0-35_h5709861_mkl.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libboost-1.88.0-h9dfe17d_5.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libboost-devel-1.88.0-h1c1089f_5.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libboost-headers-1.88.0-h57928b3_5.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libcamd-3.3.3-h8c1c262_7100102.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libcblas-3.9.0-35_h2a3cdd5_mkl.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libccolamd-3.3.4-h8c1c262_7100102.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libcholmod-5.3.1-hdf2ebef_7100102.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libcolamd-3.3.4-h8c1c262_7100102.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libcurl-8.14.1-h88aaa65_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libexpat-2.7.1-hac47afa_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libffi-3.4.6-h537db12_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libglib-2.86.0-h5f26cbf_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libhiredis-1.0.2-h0e60522_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/win-64/libhwloc-2.12.1-default_h88281d1_1000.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libhwy-1.3.0-ha71e874_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libiconv-1.18-hc1393d2_2.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libintl-0.22.5-h5728263_3.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/liblapack-3.9.0-35_hf9ab0e9_mkl.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/liblzma-5.8.1-h2466b09_2.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libmpdec-4.0.0-h2466b09_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.50.4-hf5d6505_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libssh2-1.11.1-h9aa295b_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libsuitesparseconfig-7.10.1-h0795de7_7100102.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libuv-1.51.0-hfd05255_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libwinpthread-12.0.0.r4.gg4f2fc60ca-h57928b3_9.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libxml2-2.13.8-h741aa76_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libxslt-1.1.43-h25c3957_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libzlib-1.3.1-h2466b09_2.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/llvm-openmp-21.1.2-hfa2b4ca_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/lxml-6.0.2-py313he881f1c_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/mkl-2024.2.2-h57928b3_16.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nanobind-2.9.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/nanoeigenpy-0.4.0-np2py313hb1d1d87_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/ninja-1.13.1-h477610d_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/numpy-2.3.3-py313hce7ae62_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.5.3-h725018a_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/pcre2-10.46-h3402e2f_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/pkg-config-0.29.2-h88c491f_1009.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pylatexenc-2.10-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/python-3.13.7-hdf00ec1_100_cp313.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.13-8_cp313.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/tbb-2021.13.0-h18a62a1_3.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/tk-8.6.13-h2c6b04d_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025b-h78e105d_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/ucrt-10.0.26100.0-h57928b3_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/vc-14.3-h41ae7f8_31.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/vc14_runtime-14.44.35208-h818238b_31.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/vcomp14-14.44.35208-h818238b_31.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/vs2015_runtime-14.44.35208-h38c0c73_31.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/vs2022_win-64-19.44.35207-ha74f236_31.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/vswhere-3.1.7-h40126e0_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/zlib-1.3.1-h2466b09_2.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/zstd-1.5.7-hbeecb71_2.conda clang: channels: - url: https://conda.anaconda.org/conda-forge/ @@ -3397,6 +3766,48 @@ packages: license_family: BSD size: 12437416 timestamp: 1753275562799 +- conda: https://conda.anaconda.org/conda-forge/linux-64/benchmark-1.9.4-h5888daf_0.conda + sha256: d9a8e7243b4aad9352cc6ad2165396192d23b7b4c69276dee45659111babed47 + md5: 8dc41abc97df6e4aae27c4e2e0e83c94 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libstdcxx >=13 + license: Apache-2.0 + license_family: Apache + size: 273265 + timestamp: 1747680846005 +- conda: https://conda.anaconda.org/conda-forge/osx-64/benchmark-1.9.4-h240833e_0.conda + sha256: eee5a0b1bacfd9a097d8251c8c9eceeb3aad4ccd58f936cf8e217cd8f6b28f2b + md5: 86ce129128a343e087b5f1183b442303 + depends: + - __osx >=10.13 + - libcxx >=18 + license: Apache-2.0 + license_family: Apache + size: 216184 + timestamp: 1747680920194 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/benchmark-1.9.4-h286801f_0.conda + sha256: 84c5e3bff081133fa9312eba26f4aa800768dd71330b47a5104296fe2da3ab55 + md5: 6a03d93df7fff16c06985aa979c562c6 + depends: + - __osx >=11.0 + - libcxx >=18 + license: Apache-2.0 + license_family: Apache + size: 208949 + timestamp: 1747681218396 +- conda: https://conda.anaconda.org/conda-forge/win-64/benchmark-1.9.4-he0c23c2_0.conda + sha256: e9b8f328e21672387dc7993ec0dc05f8898da453bef6dacf8467dae112154c38 + md5: 157ea5315fc383c046b9420ff5c19ff3 + depends: + - ucrt >=10.0.20348.0 + - vc >=14.2,<15 + - vc14_runtime >=14.29.30139 + license: Apache-2.0 + license_family: Apache + size: 218360 + timestamp: 1747681032796 - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils-2.44-h4852527_2.conda sha256: 1461b66ef4801c20dc39d7005eed559bfcd3a62c219dc030343ddd570b58a9e6 md5: 7f77703af8f54071370e0bc3a4b225af @@ -5689,6 +6100,44 @@ packages: license_family: BSD size: 2412139 timestamp: 1752762145331 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libhwy-1.3.0-h4c17acf_1.conda + sha256: 2bdd1cdd677b119abc5e83069bec2e28fe6bfb21ebaea3cd07acee67f38ea274 + md5: c2a0c1d0120520e979685034e0b79859 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libstdcxx >=14 + license: Apache-2.0 OR BSD-3-Clause + size: 1448617 + timestamp: 1758894401402 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libhwy-1.3.0-hab838a1_1.conda + sha256: 2f49632a3fd9ec5e38a45738f495f8c665298b0b35e6c89cef8e0fbc39b3f791 + md5: bb8ff4fec8150927a54139af07ef8069 + depends: + - __osx >=10.13 + - libcxx >=19 + license: Apache-2.0 OR BSD-3-Clause + size: 1003288 + timestamp: 1758894613094 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libhwy-1.3.0-h48b13b8_1.conda + sha256: 837fe775ba8ec9f08655bb924e28dba390d917423350333a75fd5eeac0776174 + md5: 6375717f5fcd756de929a06d0e40fab0 + depends: + - __osx >=11.0 + - libcxx >=19 + license: Apache-2.0 OR BSD-3-Clause + size: 581579 + timestamp: 1758894814983 +- conda: https://conda.anaconda.org/conda-forge/win-64/libhwy-1.3.0-ha71e874_1.conda + sha256: c722a04f065656b988a46dee87303ff0bf037179c50e2e76704b693def7f9a96 + md5: f4649d4b6bf40d616eda57d6255d2333 + depends: + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: Apache-2.0 OR BSD-3-Clause + size: 536186 + timestamp: 1758894243956 - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h3b78370_2.conda sha256: c467851a7312765447155e071752d7bf9bf44d610a5687e32706f480aad2833f md5: 915f5995e94f60e9a4826e0b0920ee88 diff --git a/pixi.toml b/pixi.toml index 042b49151..6f0e749cc 100644 --- a/pixi.toml +++ b/pixi.toml @@ -35,10 +35,7 @@ scripts = ["development/scripts/pixi/activation.sh"] scripts = ["development/scripts/pixi/activation.bat"] [tasks] -# We must avoid to set CMAKE_CXX_FLAGS because of WIN32 -# https://discourse.cmake.org/t/strictly-appending-to-cmake-lang-flags/6478 configure = { cmd = [ - "CXXFLAGS=$COAL_CXX_FLAGS", "cmake", "-G", "Ninja", @@ -52,6 +49,7 @@ configure = { cmd = [ "-DGENERATE_PYTHON_STUBS=$COAL_PYTHON_STUBS", "-DCOAL_HAS_QHULL=$COAL_HAS_QHULL", "-DCOAL_PYTHON_NANOBIND=$COAL_PYTHON_NANOBIND", + "-DCOAL_BUILD_BENCHMARK=$COAL_BUILD_BENCHMARK", ] } build = { cmd = "cmake --build build --target all", depends-on = ["configure"] } clean = { cmd = "rm -rf build" } @@ -69,7 +67,6 @@ tomlkit = ">=0.13.2" [feature.new-version.tasks] configure_new_version = { cmd = [ - "CXXFLAGS=$COAL_CXX_FLAGS", "cmake", "-G", "Ninja", @@ -103,6 +100,11 @@ activation.env = { COAL_PYTHON_NANOBIND = "OFF" } [feature.octomap] dependencies = { octomap = ">=1.10" } +# Benchmark support +[feature.benchmark] +dependencies = { benchmark = ">=1.9.4", libhwy = ">=1.3.0" } +activation = { env = { COAL_BUILD_BENCHMARK = "ON" } } + [feature.python-latest.dependencies] python = "3.13.*" @@ -130,6 +132,10 @@ default = { features = ["python-latest"], solve-group = "python-latest" } clang = { features = ["clang", "python-latest"] } lint = { features = ["lint"], solve-group = "python-latest" } qhull = { features = ["qhull", "python-latest"], solve-group = "python-latest" } +benchmark = { features = [ + "benchmark", + "python-latest", +], solve-group = "python-latest" } octomap = { features = [ "octomap", "python-latest", @@ -138,23 +144,27 @@ python-oldest = { features = ["python-oldest"], solve-group = "python-oldest" } all = { features = [ "qhull", "octomap", + "benchmark", "python-latest", ], solve-group = "python-latest" } # No solve-group, because boost.python will be legacy all-boost-python = { features = [ "qhull", "octomap", + "benchmark", "python-latest", "boost-python", -]} +] } all-python-oldest = { features = [ "qhull", "octomap", + "benchmark", "python-oldest", ], solve-group = "python-oldest" } all-clang-cl = { features = [ "qhull", "octomap", + "benchmark", "clang-cl", "python-latest", ], solve-group = "python-latest" }