Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Code cleanup #29

Merged
merged 7 commits into from
Jan 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
77 changes: 12 additions & 65 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -1,66 +1,13 @@
---
Language: Cpp
# BasedOnStyle: Google
AccessModifierOffset: -1
AlignAfterOpenBracket: true
AlignConsecutiveAssignments: false
AlignEscapedNewlinesLeft: true
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: true
AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: true
BinPackArguments: true
BinPackParameters: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
ColumnLimit: 90
CommentPragmas: '^ IWYU pragma:'
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
BasedOnStyle: Google
BinPackArguments: false
BinPackParameters: false
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
IndentCaseLabels: true
IndentWidth: 2
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: false
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Left
SpaceAfterCStyleCast: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Auto
TabWidth: 8
UseTab: Never
...
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^"_pyceres'
Priority: 1
- Regex: '^<[[:alnum:]_]+>'
Priority: 2
- Regex: '.*'
Priority: 3
SortIncludes: true
25 changes: 25 additions & 0 deletions .github/workflows/code-formatting.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: clang-format Check
on:
push:
branches:
- main
pull_request:
types: [ assigned, opened, synchronize, reopened ]
jobs:
formatting-check:
name: Formatting Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run clang-format style check for C/C++/Protobuf programs.
uses: jidicula/[email protected]
with:
clang-format-version: '14'
- uses: actions/setup-python@v4
with:
python-version: '3.10'
cache: 'pip'
- run: python -m pip install --upgrade pip
- run: python -m pip install isort black
- run: python -m isort . --profile black --check-only --diff
- run: python -m black . --check --diff
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ find_package(Python REQUIRED COMPONENTS Interpreter Development.Module)
find_package(pybind11 2.11.1 REQUIRED)

pybind11_add_module(pyceres _pyceres/bindings.cc)
target_include_directories(pyceres PRIVATE ${PROJECT_SOURCE_DIR}/_pyceres)
target_include_directories(pyceres PRIVATE ${PROJECT_SOURCE_DIR})
target_link_libraries(pyceres PRIVATE colmap::colmap glog::glog Ceres::ceres)
target_compile_definitions(pyceres PRIVATE VERSION_INFO="${PROJECT_VERSION}")
install(TARGETS pyceres LIBRARY DESTINATION .)
15 changes: 7 additions & 8 deletions _pyceres/bindings.cc
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
#include "_pyceres/core/bindings.h"

#include "_pyceres/factors/bindings.h"
#include "_pyceres/glog.h"
#include "_pyceres/helpers.h"

#include <pybind11/iostream.h>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/stl_bind.h>
namespace py = pybind11;

#include "core/bindings.cc"
#include "factors/bindings.cc"
#include "glog.cc"
#include "helpers.h"

void bind_core(py::module&);
void bind_factors(py::module&);
namespace py = pybind11;

PYBIND11_MODULE(pyceres, m) {
m.doc() = "PyCeres";
Expand Down
31 changes: 12 additions & 19 deletions _pyceres/core/bindings.cc → _pyceres/core/bindings.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,27 +28,20 @@
// Author: [email protected] (Nikolaus Mitchell)
// Edited by: [email protected] (Philipp Lindenberger)

#include <pybind11/pybind11.h>
namespace py = pybind11;
#pragma once

#include "core/callbacks.cc"
#include "core/cost_functions.cc"
#include "core/covariance.cc"
#include "core/loss_functions.cc"
#include "core/manifold.cc"
#include "core/problem.cc"
#include "core/solver.cc"
#include "core/types.cc"
#include "_pyceres/core/callbacks.h"
#include "_pyceres/core/cost_functions.h"
#include "_pyceres/core/covariance.h"
#include "_pyceres/core/loss_functions.h"
#include "_pyceres/core/manifold.h"
#include "_pyceres/core/problem.h"
#include "_pyceres/core/solver.h"
#include "_pyceres/core/types.h"

void init_types(py::module& m);
void init_callbacks(py::module& m);
void init_covariance(py::module& m);
void init_solver(py::module& m);
void init_loss_functions(py::module& m);
void init_cost_functions(py::module& m);
void init_manifold(py::module& m);
void init_problem(py::module& m);
void init_pyceres(py::module& m);
#include <pybind11/pybind11.h>

namespace py = pybind11;

void bind_core(py::module& m) {
init_types(m);
Expand Down
17 changes: 10 additions & 7 deletions _pyceres/core/callbacks.cc → _pyceres/core/callbacks.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@
//
// Author: [email protected] (Nikolaus Mitchell)
// Edited by: [email protected] (Philipp Lindenberger)

#pragma once

#include <ceres/ceres.h>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/stl_bind.h>

#include <ceres/ceres.h>

namespace py = pybind11;

// Trampoline class so we can create an EvaluationCallback in Python.
Expand All @@ -44,10 +46,11 @@ class PyEvaluationCallBack : public ceres::EvaluationCallback {
void PrepareForEvaluation(bool evaluate_jacobians,
bool new_evaluation_point) override {
PYBIND11_OVERLOAD_PURE(
void, /* Return type */
ceres::EvaluationCallback, /* Parent class */
PrepareForEvaluation, // Name of function in C++ (fn)
evaluate_jacobians, new_evaluation_point /* Argument(s) */
void, /* Return type */
ceres::EvaluationCallback, /* Parent class */
PrepareForEvaluation, // Name of function in C++ (fn)
evaluate_jacobians,
new_evaluation_point /* Argument(s) */
);
}
};
Expand Down Expand Up @@ -93,4 +96,4 @@ void init_callbacks(py::module& m) {
py::keep_alive<1, 2>());
py::implicitly_convertible<py::list,
std::vector<ceres::IterationCallback*>>();
}
}
70 changes: 42 additions & 28 deletions _pyceres/core/cost_functions.cc → _pyceres/core/cost_functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@
// Author: [email protected] (Nikolaus Mitchell)
// Edited by: [email protected] (Philipp Lindenberger)

#include <pybind11/pybind11.h>
namespace py = pybind11;
#pragma once

#include "_pyceres/helpers.h"
#include "_pyceres/log_exceptions.h"

#include <ceres/ceres.h>
#include <pybind11/pybind11.h>

#include "helpers.h"
#include "log_exceptions.h"
namespace py = pybind11;

// Class which we can use to create a ceres::CostFunction in python.
// This allows use to create python based cost functions.
Expand All @@ -44,7 +46,8 @@ class PyCostFunction : public ceres::CostFunction {
using ceres::CostFunction::CostFunction;
using ceres::CostFunction::set_num_residuals;

bool Evaluate(double const* const* parameters, double* residuals,
bool Evaluate(double const* const* parameters,
double* residuals,
double** jacobians) const override {
pybind11::gil_scoped_acquire gil;

Expand All @@ -57,9 +60,10 @@ class PyCostFunction : public ceres::CostFunction {
for (size_t idx = 0; idx < parameter_block_sizes().size(); ++idx) {
parameters_vec.emplace_back(py::array_t<double>(
this->parameter_block_sizes()[idx], parameters[idx], no_copy));
jacobians_vec.emplace_back(
py::array_t<double>(this->parameter_block_sizes()[idx] * num_residuals(),
jacobians[idx], no_copy));
jacobians_vec.emplace_back(py::array_t<double>(
this->parameter_block_sizes()[idx] * num_residuals(),
jacobians[idx],
no_copy));
}
cached_flag = true;
}
Expand All @@ -72,26 +76,28 @@ class PyCostFunction : public ceres::CostFunction {
info = parameters_vec[0].request(true);
if (info.ptr != parameters) {
for (size_t idx = 0; idx < parameters_vec.size(); ++idx) {
parameters_vec[idx] = py::array_t<double>(this->parameter_block_sizes()[idx],
parameters[idx], no_copy);
parameters_vec[idx] = py::array_t<double>(
this->parameter_block_sizes()[idx], parameters[idx], no_copy);
}
}
if (jacobians) {
info = jacobians_vec[0].request(true);
if (info.ptr != jacobians) {
for (size_t idx = 0; idx < jacobians_vec.size(); ++idx) {
jacobians_vec[idx] =
py::array_t<double>(this->parameter_block_sizes()[idx] * num_residuals(),
jacobians[idx], no_copy);
jacobians_vec[idx] = py::array_t<double>(
this->parameter_block_sizes()[idx] * num_residuals(),
jacobians[idx],
no_copy);
}
}
}

pybind11::function overload =
pybind11::get_overload(static_cast<const ceres::CostFunction*>(this), "Evaluate");
pybind11::function overload = pybind11::get_overload(
static_cast<const ceres::CostFunction*>(this), "Evaluate");
if (overload) {
auto o = overload.operator()<pybind11::return_value_policy::reference>(
parameters_vec, residuals_wrap,
parameters_vec,
residuals_wrap,
jacobians ? &jacobians_vec : nullptr); // nullptr gets cast to None
return pybind11::detail::cast_safe<bool>(std::move(o));
}
Expand All @@ -108,21 +114,24 @@ class PyCostFunction : public ceres::CostFunction {
mutable std::vector<py::array_t<double>> jacobians_vec;
mutable bool cached_flag = false; // Flag used to determine if the vectors
// need to be resized
mutable py::array_t<double> residuals_wrap; // Buffer to contain the residuals
mutable py::array_t<double>
residuals_wrap; // Buffer to contain the residuals
// pointer
mutable py::str no_copy; // Dummy variable for pybind11 to avoid copy
// copy
};

void init_cost_functions(py::module& m) {
py::class_<ceres::CostFunction, PyCostFunction /* <--- trampoline*/>(m, "CostFunction")
py::class_<ceres::CostFunction, PyCostFunction /* <--- trampoline*/>(
m, "CostFunction")
.def(py::init<>())
.def("num_residuals", &ceres::CostFunction::num_residuals)
.def("num_parameter_blocks",
[](ceres::CostFunction& myself) {
return myself.parameter_block_sizes().size();
})
.def("parameter_block_sizes", &ceres::CostFunction::parameter_block_sizes,
.def("parameter_block_sizes",
&ceres::CostFunction::parameter_block_sizes,
py::return_value_policy::reference)
.def("set_num_residuals", &PyCostFunction::set_num_residuals)
.def("set_parameter_block_sizes",
Expand All @@ -135,31 +144,36 @@ void init_cost_functions(py::module& m) {
.def(
"evaluate",
[](ceres::CostFunction& self, const py::args& parameters) {
THROW_CHECK_EQ(parameters.size(), self.parameter_block_sizes().size());
THROW_CHECK_EQ(parameters.size(),
self.parameter_block_sizes().size());
std::vector<double*> params(parameters.size());
Eigen::Matrix<double, -1, -1, Eigen::RowMajor> residuals(self.num_residuals(),
1);
std::vector<Eigen::Matrix<double, -1, -1, Eigen::RowMajor>> jacobians;
Eigen::Matrix<double, -1, -1, Eigen::RowMajor> residuals(
self.num_residuals(), 1);
std::vector<Eigen::Matrix<double, -1, -1, Eigen::RowMajor>>
jacobians;
for (int i = 0; i < parameters.size(); i++) {
py::buffer_info param_buf =
parameters[i].cast<py::array_t<double, py::array::c_style>>().request();
parameters[i]
.cast<py::array_t<double, py::array::c_style>>()
.request();
params[i] = static_cast<double*>(param_buf.ptr);
ssize_t num_dims = 1;
std::vector<ssize_t> param_shape = param_buf.shape;
for (int k = 0; k < param_shape.size(); k++) {
num_dims *= param_shape[k];
}
THROW_CHECK_EQ(num_dims, self.parameter_block_sizes()[i]);
jacobians.push_back(Eigen::Matrix<double, -1, -1, Eigen::RowMajor>(
self.num_residuals(), num_dims));
jacobians.push_back(
Eigen::Matrix<double, -1, -1, Eigen::RowMajor>(
self.num_residuals(), num_dims));
}
std::vector<double*> jacobian_ptrs;
for (int i = 0; i < parameters.size(); i++) {
jacobian_ptrs.push_back(jacobians[i].data());
}

bool success =
self.Evaluate(params.data(), residuals.data(), jacobian_ptrs.data());
bool success = self.Evaluate(
params.data(), residuals.data(), jacobian_ptrs.data());
if (success) {
return py::make_tuple(residuals, jacobians);
} else {
Expand Down
Loading
Loading