Skip to content
Open
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
aefe5db
add a part of the FRICP (robust transformation estimation)
yaoyx689 Dec 11, 2024
213e84f
update
yaoyx689 Dec 11, 2024
f2f6dea
Correct format
yaoyx689 Dec 17, 2024
f5d0bda
Merge branch 'PointCloudLibrary:master' into add_fricp
duanbotu123 Nov 9, 2025
7c81280
add Anderson acceleration fricp.hpp etc.UPdate cmakelist
duanbotu123 Nov 9, 2025
d87a99e
fix bug
duanbotu123 Nov 9, 2025
574f036
fix bug
duanbotu123 Nov 9, 2025
266ab88
fix bug in test
duanbotu123 Nov 10, 2025
b1a1a7b
fix the bug of parameter
duanbotu123 Nov 10, 2025
d329abf
Update test
duanbotu123 Nov 11, 2025
3f9a439
repush
duanbotu123 Nov 17, 2025
3d70839
Merge branch 'PointCloudLibrary:master' into add_fricp
duanbotu123 Nov 17, 2025
8efff92
fix bug in clang-tidy,merge the new update in pcl
duanbotu123 Nov 17, 2025
3fc1db5
fix bug in clang-tidy,merge the new update in pcl
duanbotu123 Nov 17, 2025
34d5dc3
fix bug in clang-tidy again
duanbotu123 Nov 18, 2025
e8acb9f
fix bug in clang-tidy again
duanbotu123 Nov 18, 2025
d5bdecc
fix bug in clang-tidy again
duanbotu123 Nov 19, 2025
ee430dc
fix bug in clang-tidy again
duanbotu123 Nov 19, 2025
0fe5fdc
Merge branch 'PointCloudLibrary:master' into add_fricp
duanbotu123 Mar 22, 2026
08d883c
Address all review comments in PR 6199
duanbotu123 Mar 22, 2026
397b7f3
Fix FRICP KdTree/Search mismatch in test_registration_api
duanbotu123 Mar 22, 2026
b45c4ea
Update registration/include/pcl/registration/fricp.h
duanbotu123 Mar 25, 2026
6ba19c8
Apply PR6199 review fixes without build artifacts
duanbotu123 Mar 25, 2026
1e17bf6
Update registration/include/pcl/registration/fricp.h
duanbotu123 Mar 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions registration/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ set(incs
"include/pcl/${SUBSYS_NAME}/ndt.h"
"include/pcl/${SUBSYS_NAME}/ndt_2d.h"
"include/pcl/${SUBSYS_NAME}/ppf_registration.h"
"include/pcl/${SUBSYS_NAME}/anderson_acceleration.h"

"include/pcl/${SUBSYS_NAME}/impl/pairwise_graph_registration.hpp"

Expand All @@ -60,10 +61,12 @@ set(incs
"include/pcl/${SUBSYS_NAME}/transformation_estimation_point_to_plane_lls.h"
"include/pcl/${SUBSYS_NAME}/transformation_estimation_point_to_plane_lls_weighted.h"
"include/pcl/${SUBSYS_NAME}/transformation_estimation_symmetric_point_to_plane_lls.h"
"include/pcl/${SUBSYS_NAME}/transformation_estimation_point_to_point_robust.h"
"include/pcl/${SUBSYS_NAME}/transformation_validation.h"
"include/pcl/${SUBSYS_NAME}/transformation_validation_euclidean.h"
"include/pcl/${SUBSYS_NAME}/gicp.h"
"include/pcl/${SUBSYS_NAME}/gicp6d.h"
"include/pcl/${SUBSYS_NAME}/fricp.h"
"include/pcl/${SUBSYS_NAME}/bfgs.h"
"include/pcl/${SUBSYS_NAME}/warp_point_rigid.h"
"include/pcl/${SUBSYS_NAME}/warp_point_rigid_6d.h"
Expand Down Expand Up @@ -110,8 +113,10 @@ set(impl_incs
"include/pcl/${SUBSYS_NAME}/impl/transformation_estimation_point_to_plane_lls_weighted.hpp"
"include/pcl/${SUBSYS_NAME}/impl/transformation_estimation_point_to_plane_weighted.hpp"
"include/pcl/${SUBSYS_NAME}/impl/transformation_estimation_symmetric_point_to_plane_lls.hpp"
"include/pcl/${SUBSYS_NAME}/impl/transformation_estimation_point_to_point_robust.hpp"
"include/pcl/${SUBSYS_NAME}/impl/transformation_validation_euclidean.hpp"
"include/pcl/${SUBSYS_NAME}/impl/gicp.hpp"
"include/pcl/${SUBSYS_NAME}/impl/fricp.hpp"
"include/pcl/${SUBSYS_NAME}/impl/sample_consensus_prerejective.hpp"
"include/pcl/${SUBSYS_NAME}/impl/ia_fpcs.hpp"
"include/pcl/${SUBSYS_NAME}/impl/ia_kfpcs.hpp"
Expand Down Expand Up @@ -157,6 +162,7 @@ set(srcs
src/transformation_estimation_point_to_plane_weighted.cpp
src/transformation_estimation_point_to_plane_lls.cpp
src/transformation_estimation_point_to_plane_lls_weighted.cpp
src/transformation_estimation_point_to_point_robust.cpp
src/transformation_validation_euclidean.cpp
src/sample_consensus_prerejective.cpp
)
Expand Down
185 changes: 185 additions & 0 deletions registration/include/pcl/registration/anderson_acceleration.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
#pragma once

#include <pcl/exceptions.h>
#include <pcl/memory.h>

#include <Eigen/Core>
#include <Eigen/QR>

#include <algorithm>
#include <cstddef>

namespace pcl {
namespace registration {

/**
* \brief Lightweight Anderson acceleration helper used to speed up fixed-point
* iterations in FRICP.
*
* The class stores a short history of the most recent residuals and solves the
* normal equations following the scheme described in "Fast and Robust Iterative
* Closest Point", Zhang et al., 2022.
*
* Only double precision is supported internally to maximise numerical stability.
*/
class AndersonAcceleration {
public:
AndersonAcceleration() = default;

/**
* \brief Initialise the accelerator with a circular buffer of size \a history.
*
* \param[in] history Number of previous iterates to keep (m in the paper).
* \param[in] dimension Dimensionality of the flattened state vector.
* \param[in] initial_state Pointer to the initial state (expects
* \a dimension doubles).
*/
inline void
init(std::size_t history, std::size_t dimension, const double* initial_state)
{
if ((history == 0) || (dimension == 0)) {
PCL_THROW_EXCEPTION(pcl::BadArgumentException,
"AndersonAcceleration::init expects non-zero sizes");
}

history_length_ = history;
dimension_ = dimension;
iteration_ = 0;
column_index_ = 0;
initialized_ = true;

current_u_.resize(dimension_);
current_F_.resize(dimension_);
prev_dG_.setZero(dimension_, history_length_);
prev_dF_.setZero(dimension_, history_length_);
normal_eq_matrix_.setZero(history_length_, history_length_);
theta_.setZero(history_length_);
dF_scale_.setZero(history_length_);

current_u_ = Eigen::Map<const Eigen::VectorXd>(initial_state, dimension_);
}

inline bool
isInitialized() const
{
return initialized_;
}

inline std::size_t
history() const
{
return history_length_;
}

inline std::size_t
dimension() const
{
return dimension_;
}

inline void
replace(const double* state)
{
if (!initialized_)
return;
current_u_ = Eigen::Map<const Eigen::VectorXd>(state, dimension_);
}

inline void
reset(const double* state)
{
if (!initialized_)
return;
iteration_ = 0;
column_index_ = 0;
current_u_ = Eigen::Map<const Eigen::VectorXd>(state, dimension_);
}

/**
* \brief Apply one Anderson acceleration update.
*
* \param[in] next_state Flattened state obtained from the fixed-point iteration.
* \return Reference to the accelerated state vector.
*/
inline const Eigen::VectorXd&
compute(const double* next_state)
{
if (!initialized_) {
PCL_THROW_EXCEPTION(pcl::PCLException,
"AndersonAcceleration::compute called before init");
}

Eigen::Map<const Eigen::VectorXd> G(next_state, dimension_);
current_F_ = G - current_u_;

constexpr double eps = 1e-14;

if (iteration_ == 0) {
prev_dF_.col(0) = -current_F_;
prev_dG_.col(0) = -G;
current_u_ = G;
}
else {
prev_dF_.col(column_index_) += current_F_;
prev_dG_.col(column_index_) += G;

double scale = std::max(eps, prev_dF_.col(column_index_).norm());
dF_scale_(column_index_) = scale;
prev_dF_.col(column_index_) /= scale;

const std::size_t m_k = std::min(history_length_, iteration_);

if (m_k == 1) {
theta_(0) = 0.0;
const double dF_norm = prev_dF_.col(column_index_).norm();
normal_eq_matrix_(0, 0) = dF_norm * dF_norm;
if (dF_norm > eps) {
theta_(0) = (prev_dF_.col(column_index_) / dF_norm).dot(current_F_ / dF_norm);
}
}
else {
// update Gram matrix row/column corresponding to the newest column
const Eigen::VectorXd new_inner_prod = prev_dF_.col(column_index_).transpose() *
prev_dF_.block(0, 0, dimension_, m_k);
normal_eq_matrix_.block(column_index_, 0, 1, m_k) = new_inner_prod.transpose();
normal_eq_matrix_.block(0, column_index_, m_k, 1) = new_inner_prod;
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a compile-time type mismatch: prev_dF_.col(...).transpose() * prev_dF_.block(...) is a 1×m_k row vector, but it is being stored in an Eigen::VectorXd (m_k×1). This should be an Eigen::RowVectorXd (or explicitly transpose the product) so the subsequent assignments to normal_eq_matrix_ match dimensions.

Suggested change
const Eigen::VectorXd new_inner_prod = prev_dF_.col(column_index_).transpose() *
prev_dF_.block(0, 0, dimension_, m_k);
normal_eq_matrix_.block(column_index_, 0, 1, m_k) = new_inner_prod.transpose();
normal_eq_matrix_.block(0, column_index_, m_k, 1) = new_inner_prod;
const Eigen::RowVectorXd new_inner_prod = prev_dF_.col(column_index_).transpose() *
prev_dF_.block(0, 0, dimension_, m_k);
normal_eq_matrix_.block(column_index_, 0, 1, m_k) = new_inner_prod;
normal_eq_matrix_.block(0, column_index_, m_k, 1) = new_inner_prod.transpose();

Copilot uses AI. Check for mistakes.

cod_.compute(normal_eq_matrix_.block(0, 0, m_k, m_k));
theta_.head(m_k) =
cod_.solve(prev_dF_.block(0, 0, dimension_, m_k).transpose() * current_F_);
}

const Eigen::ArrayXd scaled_theta =
theta_.head(m_k).array() / dF_scale_.head(m_k).array();
current_u_ = G - prev_dG_.block(0, 0, dimension_, m_k) * scaled_theta.matrix();

column_index_ = (column_index_ + 1) % history_length_;
prev_dF_.col(column_index_) = -current_F_;
prev_dG_.col(column_index_) = -G;
}

++iteration_;
return current_u_;
}

private:
std::size_t history_length_{0};
std::size_t dimension_{0};
std::size_t iteration_{0};
std::size_t column_index_{0};
bool initialized_{false};

Eigen::VectorXd current_u_;
Eigen::VectorXd current_F_;
Eigen::MatrixXd prev_dG_;
Eigen::MatrixXd prev_dF_;
Eigen::MatrixXd normal_eq_matrix_;
Eigen::VectorXd theta_;
Eigen::VectorXd dF_scale_;
Eigen::CompleteOrthogonalDecomposition<Eigen::MatrixXd> cod_;

PCL_MAKE_ALIGNED_OPERATOR_NEW
};

} // namespace registration
} // namespace pcl
Loading
Loading