From b5f66b06a1fe11187b00ecbbecb22f9d79d1f27b Mon Sep 17 00:00:00 2001 From: B1ueber2y Date: Thu, 20 Jun 2024 22:34:28 +0200 Subject: [PATCH 1/8] update. --- _pyceres/core/bindings.h | 2 ++ _pyceres/core/crs_matrix.h | 54 ++++++++++++++++++++++++++++++++++++++ _pyceres/core/problem.h | 9 ++++++- 3 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 _pyceres/core/crs_matrix.h diff --git a/_pyceres/core/bindings.h b/_pyceres/core/bindings.h index 872bd44..c2e67a9 100644 --- a/_pyceres/core/bindings.h +++ b/_pyceres/core/bindings.h @@ -3,6 +3,7 @@ #include "_pyceres/core/callbacks.h" #include "_pyceres/core/cost_functions.h" #include "_pyceres/core/covariance.h" +#include "_pyceres/core/crs_matrix.h" #include "_pyceres/core/loss_functions.h" #include "_pyceres/core/manifold.h" #include "_pyceres/core/problem.h" @@ -17,6 +18,7 @@ void BindCore(py::module& m) { BindTypes(m); BindCallbacks(m); BindCovariance(m); + BindCRSMatrix(m); BindSolver(m); BindLossFunctions(m); BindCostFunctions(m); diff --git a/_pyceres/core/crs_matrix.h b/_pyceres/core/crs_matrix.h new file mode 100644 index 0000000..9c38a80 --- /dev/null +++ b/_pyceres/core/crs_matrix.h @@ -0,0 +1,54 @@ +#pragma once + +#include "_pyceres/core/wrappers.h" +#include "_pyceres/helpers.h" +#include "_pyceres/logging.h" + +#include +#include +#include +#include + +namespace py = pybind11; + +namespace { +py::tuple ConvertCRSToPyTuple(const ceres::CRSMatrix& crsMatrix) { + std::vector rows, cols; + std::vector values; + + for (int row = 0; row < crsMatrix.num_rows; ++row) { + for (int k = crsMatrix.rows[row]; k < crsMatrix.rows[row + 1]; ++k) { + rows.push_back(row); + cols.push_back(crsMatrix.cols[k]); + values.push_back(crsMatrix.values[k]); + } + } + + // convert std::vector data to py::array_t + py::array_t rows_array(rows.size()); + py::array_t cols_array(cols.size()); + py::array_t values_array(values.size()); + std::copy(rows.begin(), rows.end(), rows_array.mutable_data()); + std::copy(cols.begin(), cols.end(), cols_array.mutable_data()); + std::copy(values.begin(), values.end(), values_array.mutable_data()); + + //return as a tulple + return py::make_tuple(rows_array, cols_array, values_array); +} +} + +void BindCRSMatrix(py::module& m) { + using CRSMatrix = ceres::CRSMatrix; + py::class_ PyCRSMatrix(m, "CRSMatrix"); + PyCRSMatrix.def(py::init<>()) + .def_readonly("num_rows", &CRSMatrix::num_rows) + .def_readonly("num_cols", &CRSMatrix::num_cols) + .def_readonly("rows", &CRSMatrix::rows) + .def_readonly("cols", &CRSMatrix::cols) + .def_readonly("values", &CRSMatrix::values) + .def("to_tuple", [](CRSMatrix& self) { + return ConvertCRSToPyTuple(self); + }); +} + + diff --git a/_pyceres/core/problem.h b/_pyceres/core/problem.h index 562fd76..0c40903 100644 --- a/_pyceres/core/problem.h +++ b/_pyceres/core/problem.h @@ -233,5 +233,12 @@ void BindProblem(py::module& m) { .def("remove_residual_block", [](ceres::Problem& self, ResidualBlockIDWrapper& residual_block_id) { self.RemoveResidualBlock(residual_block_id.id); - }); + }) + .def("evaluate_jacobian", + [](ceres::Problem& self, const ceres::Problem::EvaluateOptions& options) { + ceres::CRSMatrix jacobian; + self.Evaluate(options, nullptr, nullptr, nullptr, &jacobian); + return jacobian; + } + ); } From 97319e626a0ae0d07ef8da0d227c33ce0c634b22 Mon Sep 17 00:00:00 2001 From: B1ueber2y Date: Thu, 20 Jun 2024 22:35:21 +0200 Subject: [PATCH 2/8] formatting. --- _pyceres/core/crs_matrix.h | 25 +++++++++++-------------- _pyceres/core/problem.h | 12 ++++++------ 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/_pyceres/core/crs_matrix.h b/_pyceres/core/crs_matrix.h index 9c38a80..3d9a55d 100644 --- a/_pyceres/core/crs_matrix.h +++ b/_pyceres/core/crs_matrix.h @@ -4,9 +4,9 @@ #include "_pyceres/helpers.h" #include "_pyceres/logging.h" +#include #include #include -#include #include namespace py = pybind11; @@ -15,7 +15,7 @@ namespace { py::tuple ConvertCRSToPyTuple(const ceres::CRSMatrix& crsMatrix) { std::vector rows, cols; std::vector values; - + for (int row = 0; row < crsMatrix.num_rows; ++row) { for (int k = crsMatrix.rows[row]; k < crsMatrix.rows[row + 1]; ++k) { rows.push_back(row); @@ -32,23 +32,20 @@ py::tuple ConvertCRSToPyTuple(const ceres::CRSMatrix& crsMatrix) { std::copy(cols.begin(), cols.end(), cols_array.mutable_data()); std::copy(values.begin(), values.end(), values_array.mutable_data()); - //return as a tulple + // return as a tuple return py::make_tuple(rows_array, cols_array, values_array); } -} +} // namespace void BindCRSMatrix(py::module& m) { using CRSMatrix = ceres::CRSMatrix; py::class_ PyCRSMatrix(m, "CRSMatrix"); PyCRSMatrix.def(py::init<>()) - .def_readonly("num_rows", &CRSMatrix::num_rows) - .def_readonly("num_cols", &CRSMatrix::num_cols) - .def_readonly("rows", &CRSMatrix::rows) - .def_readonly("cols", &CRSMatrix::cols) - .def_readonly("values", &CRSMatrix::values) - .def("to_tuple", [](CRSMatrix& self) { - return ConvertCRSToPyTuple(self); - }); + .def_readonly("num_rows", &CRSMatrix::num_rows) + .def_readonly("num_cols", &CRSMatrix::num_cols) + .def_readonly("rows", &CRSMatrix::rows) + .def_readonly("cols", &CRSMatrix::cols) + .def_readonly("values", &CRSMatrix::values) + .def("to_tuple", + [](CRSMatrix& self) { return ConvertCRSToPyTuple(self); }); } - - diff --git a/_pyceres/core/problem.h b/_pyceres/core/problem.h index 0c40903..dd86d74 100644 --- a/_pyceres/core/problem.h +++ b/_pyceres/core/problem.h @@ -235,10 +235,10 @@ void BindProblem(py::module& m) { self.RemoveResidualBlock(residual_block_id.id); }) .def("evaluate_jacobian", - [](ceres::Problem& self, const ceres::Problem::EvaluateOptions& options) { - ceres::CRSMatrix jacobian; - self.Evaluate(options, nullptr, nullptr, nullptr, &jacobian); - return jacobian; - } - ); + [](ceres::Problem& self, + const ceres::Problem::EvaluateOptions& options) { + ceres::CRSMatrix jacobian; + self.Evaluate(options, nullptr, nullptr, nullptr, &jacobian); + return jacobian; + }); } From 0fd4d44a290e3bc243c870d16fb7a123c60a9b98 Mon Sep 17 00:00:00 2001 From: B1ueber2y Date: Thu, 20 Jun 2024 23:21:59 +0200 Subject: [PATCH 3/8] add support for partial evaluation --- _pyceres/core/problem.h | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/_pyceres/core/problem.h b/_pyceres/core/problem.h index dd86d74..54131f5 100644 --- a/_pyceres/core/problem.h +++ b/_pyceres/core/problem.h @@ -40,11 +40,15 @@ void BindProblem(py::module& m) { .def_readwrite("disable_all_safety_checks", &options::disable_all_safety_checks); - // TODO: bind Problem::Evaluate py::class_(m, "EvaluateOptions") .def(py::init<>()) - // Doesn't make sense to wrap this as you can't see the pointers in python - //.def_readwrite("parameter_blocks",&ceres::Problem::EvaluateOptions) + .def("set_parameter_blocks", [](ceres::Problem::EvaluateOptions& self, std::vector>& blocks) { + self.parameter_blocks.clear(); + for (auto it = blocks.begin(); it != blocks.end(); ++it) { + py::buffer_info info = it->request(); + self.parameter_blocks.push_back(static_cast(info.ptr)); + } + }) .def_readwrite("apply_loss_function", &ceres::Problem::EvaluateOptions::apply_loss_function) .def_readwrite("num_threads", @@ -234,11 +238,20 @@ void BindProblem(py::module& m) { [](ceres::Problem& self, ResidualBlockIDWrapper& residual_block_id) { self.RemoveResidualBlock(residual_block_id.id); }) + .def("evaluate_residuals", + [](ceres::Problem& self, + const ceres::Problem::EvaluateOptions& options) { + std::vector residuals; + self.Evaluate(options, nullptr, &residuals, nullptr, nullptr); + return residuals; + }, + py::arg("options") = ceres::Problem::EvaluateOptions()) .def("evaluate_jacobian", [](ceres::Problem& self, const ceres::Problem::EvaluateOptions& options) { ceres::CRSMatrix jacobian; self.Evaluate(options, nullptr, nullptr, nullptr, &jacobian); return jacobian; - }); + }, + py::arg("options") = ceres::Problem::EvaluateOptions()); } From 6ac90f0570e2d5a48fa7fe7502bffd48364cb05f Mon Sep 17 00:00:00 2001 From: B1ueber2y Date: Thu, 20 Jun 2024 23:22:18 +0200 Subject: [PATCH 4/8] formatting. --- _pyceres/core/problem.h | 48 ++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/_pyceres/core/problem.h b/_pyceres/core/problem.h index 54131f5..10d7627 100644 --- a/_pyceres/core/problem.h +++ b/_pyceres/core/problem.h @@ -42,13 +42,15 @@ void BindProblem(py::module& m) { py::class_(m, "EvaluateOptions") .def(py::init<>()) - .def("set_parameter_blocks", [](ceres::Problem::EvaluateOptions& self, std::vector>& blocks) { - self.parameter_blocks.clear(); - for (auto it = blocks.begin(); it != blocks.end(); ++it) { - py::buffer_info info = it->request(); - self.parameter_blocks.push_back(static_cast(info.ptr)); - } - }) + .def("set_parameter_blocks", + [](ceres::Problem::EvaluateOptions& self, + std::vector>& blocks) { + self.parameter_blocks.clear(); + for (auto it = blocks.begin(); it != blocks.end(); ++it) { + py::buffer_info info = it->request(); + self.parameter_blocks.push_back(static_cast(info.ptr)); + } + }) .def_readwrite("apply_loss_function", &ceres::Problem::EvaluateOptions::apply_loss_function) .def_readwrite("num_threads", @@ -238,20 +240,22 @@ void BindProblem(py::module& m) { [](ceres::Problem& self, ResidualBlockIDWrapper& residual_block_id) { self.RemoveResidualBlock(residual_block_id.id); }) - .def("evaluate_residuals", + .def( + "evaluate_residuals", [](ceres::Problem& self, - const ceres::Problem::EvaluateOptions& options) { - std::vector residuals; - self.Evaluate(options, nullptr, &residuals, nullptr, nullptr); - return residuals; - }, - py::arg("options") = ceres::Problem::EvaluateOptions()) - .def("evaluate_jacobian", - [](ceres::Problem& self, - const ceres::Problem::EvaluateOptions& options) { - ceres::CRSMatrix jacobian; - self.Evaluate(options, nullptr, nullptr, nullptr, &jacobian); - return jacobian; - }, - py::arg("options") = ceres::Problem::EvaluateOptions()); + const ceres::Problem::EvaluateOptions& options) { + std::vector residuals; + self.Evaluate(options, nullptr, &residuals, nullptr, nullptr); + return residuals; + }, + py::arg("options") = ceres::Problem::EvaluateOptions()) + .def( + "evaluate_jacobian", + [](ceres::Problem& self, + const ceres::Problem::EvaluateOptions& options) { + ceres::CRSMatrix jacobian; + self.Evaluate(options, nullptr, nullptr, nullptr, &jacobian); + return jacobian; + }, + py::arg("options") = ceres::Problem::EvaluateOptions()); } From 4e4c77ccd7dfb9c37d70ff4bdfec27ebc1272f9f Mon Sep 17 00:00:00 2001 From: B1ueber2y Date: Fri, 21 Jun 2024 01:23:26 +0200 Subject: [PATCH 5/8] update. --- _pyceres/core/crs_matrix.h | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/_pyceres/core/crs_matrix.h b/_pyceres/core/crs_matrix.h index 3d9a55d..5bffa09 100644 --- a/_pyceres/core/crs_matrix.h +++ b/_pyceres/core/crs_matrix.h @@ -24,16 +24,8 @@ py::tuple ConvertCRSToPyTuple(const ceres::CRSMatrix& crsMatrix) { } } - // convert std::vector data to py::array_t - py::array_t rows_array(rows.size()); - py::array_t cols_array(cols.size()); - py::array_t values_array(values.size()); - std::copy(rows.begin(), rows.end(), rows_array.mutable_data()); - std::copy(cols.begin(), cols.end(), cols_array.mutable_data()); - std::copy(values.begin(), values.end(), values_array.mutable_data()); - // return as a tuple - return py::make_tuple(rows_array, cols_array, values_array); + return py::make_tuple(rows, cols, values); } } // namespace From 1432ab6c5db00de79adec94a6c0cbbf1ae7b7142 Mon Sep 17 00:00:00 2001 From: B1ueber2y Date: Mon, 24 Jun 2024 14:02:36 +0200 Subject: [PATCH 6/8] update, --- _pyceres/core/crs_matrix.h | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/_pyceres/core/crs_matrix.h b/_pyceres/core/crs_matrix.h index 5bffa09..3c65f0e 100644 --- a/_pyceres/core/crs_matrix.h +++ b/_pyceres/core/crs_matrix.h @@ -13,14 +13,21 @@ namespace py = pybind11; namespace { py::tuple ConvertCRSToPyTuple(const ceres::CRSMatrix& crsMatrix) { - std::vector rows, cols; - std::vector values; + size_t n_values = crsMatrix.values.size(); + py::array_t rows(n_values), cols(n_values); + py::array_t values(n_values); + int* rows_data = static_cast(rows.request().ptr); + int* cols_data = static_cast(cols.request().ptr); + double* values_data = static_cast(values.request().ptr); + + int counter = 0; for (int row = 0; row < crsMatrix.num_rows; ++row) { for (int k = crsMatrix.rows[row]; k < crsMatrix.rows[row + 1]; ++k) { - rows.push_back(row); - cols.push_back(crsMatrix.cols[k]); - values.push_back(crsMatrix.values[k]); + rows_data[counter] = row; + cols_data[counter] = crsMatrix.cols[k]; + values_data[counter] = crsMatrix.values[k]; + counter++; } } @@ -38,6 +45,5 @@ void BindCRSMatrix(py::module& m) { .def_readonly("rows", &CRSMatrix::rows) .def_readonly("cols", &CRSMatrix::cols) .def_readonly("values", &CRSMatrix::values) - .def("to_tuple", - [](CRSMatrix& self) { return ConvertCRSToPyTuple(self); }); + .def("to_tuple", &ConvertCRSToPyTuple); } From 80f0d4191f243e08bb6afcb4e6ca1df8cf57dd0f Mon Sep 17 00:00:00 2001 From: B1ueber2y Date: Mon, 24 Jun 2024 14:17:02 +0200 Subject: [PATCH 7/8] minor. --- _pyceres/core/crs_matrix.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_pyceres/core/crs_matrix.h b/_pyceres/core/crs_matrix.h index 3c65f0e..0d43e83 100644 --- a/_pyceres/core/crs_matrix.h +++ b/_pyceres/core/crs_matrix.h @@ -13,7 +13,7 @@ namespace py = pybind11; namespace { py::tuple ConvertCRSToPyTuple(const ceres::CRSMatrix& crsMatrix) { - size_t n_values = crsMatrix.values.size(); + const size_t n_values = crsMatrix.values.size(); py::array_t rows(n_values), cols(n_values); py::array_t values(n_values); From e2377984b413504f5a7ec347542a76d76bbcf9cf Mon Sep 17 00:00:00 2001 From: B1ueber2y Date: Mon, 24 Jun 2024 14:20:33 +0200 Subject: [PATCH 8/8] minor. --- _pyceres/core/crs_matrix.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/_pyceres/core/crs_matrix.h b/_pyceres/core/crs_matrix.h index 0d43e83..c21577b 100644 --- a/_pyceres/core/crs_matrix.h +++ b/_pyceres/core/crs_matrix.h @@ -17,9 +17,9 @@ py::tuple ConvertCRSToPyTuple(const ceres::CRSMatrix& crsMatrix) { py::array_t rows(n_values), cols(n_values); py::array_t values(n_values); - int* rows_data = static_cast(rows.request().ptr); - int* cols_data = static_cast(cols.request().ptr); - double* values_data = static_cast(values.request().ptr); + int* const rows_data = static_cast(rows.request().ptr); + int* const cols_data = static_cast(cols.request().ptr); + double* const values_data = static_cast(values.request().ptr); int counter = 0; for (int row = 0; row < crsMatrix.num_rows; ++row) {