Skip to content

Commit 06d0e4e

Browse files
committed
Cleaned up some of the documentation, and added Python bindings for the SESyncProblem class
1 parent 809f42a commit 06d0e4e

File tree

4 files changed

+172
-54
lines changed

4 files changed

+172
-54
lines changed

C++/SE-Sync/include/SESync/SESyncProblem.h

Lines changed: 39 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ class SESyncProblem {
166166

167167
/// ACCESSORS
168168

169-
/** Returns the specific formulation of this SE-Sync problem */
169+
/** Returns the specific formulation of this problem */
170170
Formulation formulation() const { return form_; }
171171

172172
/** Returns the type of matrix factorization used to compute the action of the
@@ -185,8 +185,9 @@ class SESyncProblem {
185185
return reg_Chol_precon_max_cond_;
186186
}
187187

188-
/** Returns the number of poses appearing in this problem */
189-
size_t num_poses() const { return n_; }
188+
/** Returns the number of states (poses or rotations) appearing in this
189+
* problem */
190+
size_t num_states() const { return n_; }
190191

191192
/** Returns the number of measurements in this problem */
192193
size_t num_measurements() const { return m_; }
@@ -195,16 +196,13 @@ class SESyncProblem {
195196
* over which this problem is defined */
196197
size_t dimension() const { return d_; }
197198

198-
/** Returns the relaxation rank r of this problem */
199+
/** Returns the current relaxation rank r of this problem */
199200
size_t relaxation_rank() const { return r_; }
200201

201202
/** Returns the oriented incidence matrix A of the underlying measurement
202203
* graph over which this problem is defined */
203204
const SparseMatrix &oriented_incidence_matrix() const { return A_; }
204205

205-
/** Returns the StiefelProduct manifold underlying this SE-Sync problem */
206-
const StiefelProduct &Stiefel_product_manifold() const { return SP_; }
207-
208206
/// OPTIMIZATION AND GEOMETRY
209207

210208
/** Given a matrix X, this function computes and returns the orthogonal
@@ -247,78 +245,75 @@ class SESyncProblem {
247245
Matrix data_matrix_product(const Matrix &Y) const;
248246

249247
/** Given a matrix Y, this function computes and returns F(Y), the value of
250-
* the objective evaluated at X */
248+
* the objective evaluated at Y */
251249
Scalar evaluate_objective(const Matrix &Y) const;
252250

253251
/** Given a matrix Y, this function computes and returns nabla F(Y), the
254252
* *Euclidean* gradient of F at Y. */
255253
Matrix Euclidean_gradient(const Matrix &Y) const;
256254

257-
/** Given a matrix Y in the domain D of the SE-Sync optimization problem and
258-
* the *Euclidean* gradient nabla F(Y) at Y, this function computes and
259-
* returns the *Riemannian* gradient grad F(Y) of F at Y */
255+
/** Given a matrix Y in the domain D of the relaxation and the *Euclidean*
256+
* gradient nabla F(Y) at Y, this function computes and returns the
257+
* *Riemannian* gradient grad F(Y) of F at Y */
260258
Matrix Riemannian_gradient(const Matrix &Y, const Matrix &nablaF_Y) const;
261259

262-
/** Given a matrix Y in the domain D of the SE-Sync optimization problem, this
263-
* function computes and returns grad F(Y), the *Riemannian* gradient of F
264-
* at Y */
260+
/** Given a matrix Y in the domain D of the relaxation, this function computes
261+
* and returns grad F(Y), the *Riemannian* gradient of F at Y */
265262
Matrix Riemannian_gradient(const Matrix &Y) const;
266263

267-
/** Given a matrix Y in the domain D of the SE-Sync optimization problem, the
268-
* *Euclidean* gradient nablaF_Y of F at Y, and a tangent vector dotY in
269-
* T_D(Y), the tangent space of the domain of the optimization problem at Y,
270-
* this function computes and returns Hess F(Y)[dotY], the action of the
264+
/** Given a matrix Y in the domain D of the relaxation, the *Euclidean*
265+
* gradient nablaF_Y of F at Y, and a tangent vector dotY in T_Y(D), the
266+
* tangent space of the domain of the optimization problem at Y, this function
267+
* computes and returns Hess F(Y)[dotY], the action of the
271268
* Riemannian Hessian on dotY */
272269
Matrix Riemannian_Hessian_vector_product(const Matrix &Y,
273270
const Matrix &nablaF_Y,
274271
const Matrix &dotY) const;
275272

276-
/** Given a matrix Y in the domain D of the SE-Sync optimization problem, and
277-
* a tangent vector dotY in T_D(Y), the tangent space of the domain of the
278-
* optimization problem at Y, this function computes and returns Hess
273+
/** Given a matrix Y in the domain D of the relaxation and a tangent vector
274+
* dotY in T_Y(D), the tangent space of the domain of the optimization problem
275+
* at Y, this function computes and returns Hess
279276
* F(Y)[dotY], the action of the Riemannian Hessian on dotX */
280277
Matrix Riemannian_Hessian_vector_product(const Matrix &Y,
281278
const Matrix &dotY) const;
282279

283-
/** Given a matrix Y in the domain D of the SE-Sync optimization problem, and
284-
* a tangent vector dotY in T_D(Y), this function applies the selected
285-
* preconditioning strategy to dotY */
280+
/** Given a matrix Y in the domain D of the relaxation and a tangent vector
281+
* dotY in T_Y(D), this function applies the selected preconditioning strategy
282+
* to dotY */
286283
Matrix precondition(const Matrix &Y, const Matrix &dotY) const;
287284

288-
/** Given a matrix Y in the domain D of the SE-Sync optimization problem and a
289-
tangent vector dotY in T_Y(E), the tangent space of Y considered as a generic
290-
matrix, this function computes and returns the orthogonal projection of dotY
291-
onto T_D(Y), the tangent space of the domain D at Y*/
285+
/** Given a matrix Y in the domain D of the relaxation and a tangent vector
286+
* dotY in T_Y(E), the tangent space of Y considered as a generic matrix, this
287+
* function computes and returns the orthogonal projection of dotY onto
288+
* T_D(Y), the tangent space of the domain D at Y*/
292289
Matrix tangent_space_projection(const Matrix &Y, const Matrix &dotY) const;
293290

294-
/** Given a matrix Y in the domain D of the SE-Sync optimization problem and a
295-
* tangent vector dotY in T_D(Y), this function returns the point Yplus in D
296-
* obtained by retracting along dotY */
291+
/** Given a matrix Y in the domain D of the relaxation and a tangent vector
292+
* dotY in T_D(Y), this function returns the point Yplus in D obtained by
293+
* retracting along dotY */
297294
Matrix retract(const Matrix &Y, const Matrix &dotY) const;
298295

299-
/** Given a point Y in the domain D of the rank-r relaxation of the SE-Sync
300-
* optimization problem, this function computes and returns a matrix
301-
* X = [t | R] comprised of translations and rotations for a set of feasible
302-
* poses for the original estimation problem obtained by rounding the point Y
296+
/** Given a point Y in the domain D of the rank-r relaxation, this function
297+
* computes and returns a matrix X = [t | R] composed of translations and
298+
* rotations for a set of feasible poses for the original estimation problem
299+
* obtained by rounding the point Y
303300
*/
304301
Matrix round_solution(const Matrix Y) const;
305302

306-
/** Given a critical point Y of the rank-r relaxation of the SE-Sync
307-
* optimization problem, this function computes and returns a d x dn matrix
308-
* comprised of d x d block elements of the associated block-diagonal Lagrange
309-
* multiplier matrix associated with the orthonormality constraints on the
310-
* generalized orientations of the poses (cf. eq. (119) in the SE-Sync tech
311-
* report) */
303+
/** Given a critical point Y of the rank-r relaxation, this function computes
304+
* and returns a d x dn matrix comprised of d x d block elements of the
305+
* associated block-diagonal Lagrange multiplier matrix associated with the
306+
* orthonormality constraints on the generalized orientations of the poses
307+
* (cf. eq. (119) in the SE-Sync tech report) */
312308
Matrix compute_Lambda_blocks(const Matrix &Y) const;
313309

314310
/** Given the d x dn block matrix containing the diagonal blocks of Lambda,
315311
* this function computes and returns the matrix Lambda itself */
316312
SparseMatrix
317313
compute_Lambda_from_Lambda_blocks(const Matrix &Lambda_blocks) const;
318314

319-
/** Given a critical point Y of the rank-r relaxation of the SE-Sync
320-
* optimization problem, this function computes and returns the corresponding
321-
* Lagrange multiplier matrix Lambda */
315+
/** Given a critical point Y of the rank-r relaxation, this function computes
316+
* and returns the corresponding Lagrange multiplier matrix Lambda */
322317
SparseMatrix compute_Lambda(const Matrix &Y) const;
323318

324319
/** Given a critical point Y in the domain of the optimization problem, this

C++/SE-Sync/src/PySESync.cpp

Lines changed: 124 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "SESync/RelativePoseMeasurement.h"
22
#include "SESync/SESync.h"
3+
#include "SESync/SESyncProblem.h"
34
#include "SESync/SESync_types.h"
45
#include "SESync/SESync_utils.h"
56

@@ -149,6 +150,9 @@ PYBIND11_MODULE(PySESync, m) {
149150
&SESync::SESyncOpts::projection_factorization,
150151
"Type of cached matrix factorization to use for computing "
151152
"orthogonal projections")
153+
.def_readwrite("preconditioner", &SESync::SESyncOpts::preconditioner,
154+
"The preconditioning strategy to use in the Riemannian "
155+
"trust-region algorithm")
152156
.def_readwrite(
153157
"reg_Chol_precon_max_cond",
154158
&SESync::SESyncOpts::reg_Cholesky_precon_max_condition_number)
@@ -367,6 +371,109 @@ PYBIND11_MODULE(PySESync, m) {
367371
"a pair consisting of (1) the orbit distance d_O(X,Y) between them and "
368372
"(2) the optimal registration G_O in O(d) aligning Y to X");
369373

374+
/// Bindings for SESyncProblem class
375+
py::class_<SESync::SESyncProblem>(
376+
m, "SESyncProblem",
377+
"This class encapsulates an instance of the rank-restricted Riemannian "
378+
"form of the semidefinite relaxation of a special Euclidean. It "
379+
"contains all of the precomputed and cached data matrices necessary to "
380+
"describe the problem and run the optimization algorithm, as well as "
381+
"functions for performing geometric operations on the underlying "
382+
"manifold (tangent space projection and retraction) and evaluating the "
383+
"optimization objective and its gradient and Hessian operator. ")
384+
.def(py::init<>(), "Default constructor: produces an empyt "
385+
"(uninitialized) problem instance")
386+
.def(py::init<SESync::measurements_t, SESync::Formulation,
387+
SESync::ProjectionFactorization, SESync::Preconditioner,
388+
SESync::Scalar>(),
389+
py::arg("measurements"),
390+
py::arg("formulation") = SESync::Formulation::Simplified,
391+
py::arg("projection_factorization") =
392+
SESync::ProjectionFactorization::Cholesky,
393+
py::arg("preconditioner") =
394+
SESync::Preconditioner::IncompleteCholesky,
395+
py::arg("reg_chol_precon_max_cond") = 1e6, "Basic constructor.")
396+
.def("set_relaxation_rank", &SESync::SESyncProblem::set_relaxation_rank,
397+
"Set maximum rank of the rank-restricted semidefinite relaxation.")
398+
.def("formulation", &SESync::SESyncProblem::formulation,
399+
"Get the specific formulation of this problem")
400+
.def(
401+
"projection_factorization",
402+
&SESync::SESyncProblem::projection_factorization,
403+
"Returns the type of matrix factorization used to compute the action "
404+
"of the orthogonal projection operator Pi when solving a Simplified "
405+
"instance of the special Euclidean synchronization problem")
406+
.def("preconditioner", &SESync::SESyncProblem::preconditioner,
407+
"Get the preconditioning strategy")
408+
.def("num_states", &SESync::SESyncProblem::num_states,
409+
"Get the number of states (poses or rotations) appearing in this "
410+
"problem")
411+
.def("num_measurements", &SESync::SESyncProblem::num_measurements,
412+
"Get the number of measurements appearing in this problem")
413+
.def("dimension", &SESync::SESyncProblem::dimension,
414+
"Get the dimension d of the group SE(d) or SO(d) over which this "
415+
"problem is defined")
416+
.def("relaxation_rank", &SESync::SESyncProblem::relaxation_rank,
417+
"Get the current relaxation rank r of this problem")
418+
.def("oriented_incidence_matrix",
419+
&SESync::SESyncProblem::oriented_incidence_matrix,
420+
"Returns the oriented incidence matrix A of the underlying "
421+
"measurement graph over which the problem is defined")
422+
.def("Pi_product", &SESync::SESyncProblem::Pi_product,
423+
"Given a matrix X, this function computes and returns the "
424+
"orthogonal projection Pi*X")
425+
.def("Q_product", &SESync::SESyncProblem::Q_product,
426+
"Given a matrix X, computes the product Q*X")
427+
.def("data_matrix_product", &SESync::SESyncProblem::data_matrix_product,
428+
"Given a matrix Y, this function computes and returns the matrix "
429+
"product SY, where S is the symmetric matrix parameterizing the "
430+
"quadratic objective")
431+
.def("evaluate_objective", &SESync::SESyncProblem::evaluate_objective,
432+
"Evaluate the objective of the rank-restricted relaxation")
433+
.def("Euclidean_gradient", &SESync::SESyncProblem::Euclidean_gradient,
434+
"Evaluate the Euclidean gradient of the objective")
435+
.def("Riemannian_gradient",
436+
static_cast<SESync::Matrix (SESync::SESyncProblem::*)(
437+
const SESync::Matrix &) const>(
438+
&SESync::SESyncProblem::Riemannian_gradient),
439+
"Evaluate the Riemannian gradient of the objective")
440+
.def("Riemannian_Hessian_vector_product",
441+
static_cast<SESync::Matrix (SESync::SESyncProblem::*)(
442+
const SESync::Matrix &, const SESync::Matrix &) const>(
443+
&SESync::SESyncProblem::Riemannian_Hessian_vector_product),
444+
"Given a matrix Y in the domain D of the relaxation and a tangent "
445+
"vector dotY in T_Y(D), this function computes and returns Hess "
446+
"F(Y)[dotY], the action of the Riemannian Hessian on dotY")
447+
.def("precondition", &SESync::SESyncProblem::precondition,
448+
"Given a matrix Y in the domain D of the relaxation and a tangent "
449+
"vector dotY in T_D(Y), this function applies the selected "
450+
"preconditioning strategy to dotY")
451+
.def("tangent_space_projection",
452+
&SESync::SESyncProblem::tangent_space_projection,
453+
"Given a matrix Y in the domain D of the relaxation and a tangent "
454+
"vector dotY of the ambient Eucliean space at Y, this function "
455+
"computes and returns the orthogonal projection of dotY onto T_D(Y)")
456+
.def("retract", &SESync::SESyncProblem::retract,
457+
"Given a matrix Y in the domain of the relaxation and a tangent "
458+
"vector dotY in T_Y(D), this function computes the retraction of Y "
459+
"along dotY")
460+
.def("round_solution", &SESync::SESyncProblem::round_solution,
461+
"Given a point Y in the domain D of the rank-r relaxation, this "
462+
"function computes and returns a matrix X = [t|R] composed of "
463+
"translations and rotations for a set of feasible poses for the "
464+
"original estimation problem obtained by rounding the point Y")
465+
.def("compute_Lambda", &SESync::SESyncProblem::compute_Lambda,
466+
"Given a critical point Y of the rank-r relaxation, this function "
467+
"computes and returns the corresponding Lagrange multiplier matrix "
468+
"Lambda")
469+
.def("chordal_initialization",
470+
&SESync::SESyncProblem::chordal_initialization,
471+
"This function computes and returns a chordal initialization for "
472+
"the rank-restricted semidefinite relaxation")
473+
.def("random_sample", &SESync::SESyncProblem::random_sample,
474+
"Randomly sample a point in the domain of the rank-restricted "
475+
"semidefinite relaxation");
476+
370477
/// Bindings for the main SESync driver
371478
m.def(
372479
"SESync",
@@ -381,7 +488,23 @@ PYBIND11_MODULE(PySESync, m) {
381488
py::arg("measurements"), py::arg("options") = SESync::SESyncOpts(),
382489
py::arg("Y0") = SESync::Matrix(),
383490
"Main SE-Sync function: Given a list of relative pose measurements "
384-
"specifying a special Euclidean synchronization problem, this function "
491+
"specifying a special Euclidean synchronization problem, this "
492+
"function "
385493
"computes and returns an estimated solution using the SE-Sync "
386494
"algorithm ");
495+
496+
m.def(
497+
"SESync",
498+
[](SESync::SESyncProblem &problem, const SESync::SESyncOpts &options,
499+
const SESync::Matrix &Y0) -> SESync::SESyncResult {
500+
// Redirect emitted output from (C++) stdout to (Python) sys.stdout
501+
py::scoped_ostream_redirect stream(
502+
std::cout, py::module::import("sys").attr("stdout"));
503+
return SESync::SESync(problem, options, Y0);
504+
},
505+
py::arg("problem"), py::arg("options") = SESync::SESyncOpts(),
506+
py::arg("Y0") = SESync::Matrix(),
507+
"Main SE-Sync function: Given an SESyncProblem instance, this "
508+
"function computes and returns an estimated solution using the SE-Sync "
509+
"algorithm ");
387510
}

C++/SE-Sync/src/SESync.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -467,15 +467,15 @@ SESyncResult SESync(SESyncProblem &problem, const SESyncOpts &options,
467467
SESyncResults.Fxhat =
468468
(problem.formulation() == Formulation::Simplified
469469
? problem.evaluate_objective(SESyncResults.xhat.block(
470-
0, problem.num_poses(), problem.dimension(),
471-
problem.dimension() * problem.num_poses()))
470+
0, problem.num_states(), problem.dimension(),
471+
problem.dimension() * problem.num_states()))
472472
: problem.evaluate_objective(SESyncResults.xhat));
473473

474474
// Compute the primal optimal SDP solution Lambda and its objective value
475475
Matrix Lambda_blocks = problem.compute_Lambda_blocks(SESyncResults.Yopt);
476476

477477
SESyncResults.trLambda = 0;
478-
for (size_t i = 0; i < problem.num_poses(); i++)
478+
for (size_t i = 0; i < problem.num_states(); i++)
479479
SESyncResults.trLambda +=
480480
Lambda_blocks
481481
.block(0, i * problem.dimension(), problem.dimension(),

C++/SE-Sync/src/SESyncProblem.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -533,12 +533,12 @@ SESyncProblem::SMinusLambdaProdFunctor::SMinusLambdaProdFunctor(
533533

534534
if ((problem_->formulation() == Formulation::Simplified) ||
535535
(problem_->formulation() == Formulation::SOSync)) {
536-
rows_ = problem_->dimension() * problem_->num_poses();
537-
cols_ = problem_->dimension() * problem_->num_poses();
536+
rows_ = problem_->dimension() * problem_->num_states();
537+
cols_ = problem_->dimension() * problem_->num_states();
538538
} else // mode == Explicit
539539
{
540-
rows_ = (problem_->dimension() + 1) * problem_->num_poses();
541-
cols_ = (problem_->dimension() + 1) * problem_->num_poses();
540+
rows_ = (problem_->dimension() + 1) * problem_->num_states();
541+
cols_ = (problem_->dimension() + 1) * problem_->num_states();
542542
}
543543

544544
// Compute and cache this on construction
@@ -557,10 +557,10 @@ void SESyncProblem::SMinusLambdaProdFunctor::perform_op(Scalar *x,
557557
size_t offset = (((problem_->formulation() == Formulation::Simplified) ||
558558
(problem_->formulation() == Formulation::SOSync))
559559
? 0
560-
: problem_->num_poses());
560+
: problem_->num_states());
561561

562562
#pragma omp parallel for
563-
for (size_t i = 0; i < problem_->num_poses(); ++i)
563+
for (size_t i = 0; i < problem_->num_states(); ++i)
564564
Y.segment(offset + i * dim_, dim_) -=
565565
Lambda_blocks_.block(0, i * dim_, dim_, dim_) *
566566
X.segment(offset + i * dim_, dim_);

0 commit comments

Comments
 (0)