Geogram Version 1.9.6-rc
A programming library of geometric algorithms
Loading...
Searching...
No Matches
optimal_transport.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2000-2022 Inria
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * * Neither the name of the ALICE Project-Team nor the names of its
14 * contributors may be used to endorse or promote products derived from this
15 * software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 *
29 * Contact: Bruno Levy
30 *
31 * https://www.inria.fr/fr/bruno-levy
32 *
33 * Inria,
34 * Domaine de Voluceau,
35 * 78150 Le Chesnay - Rocquencourt
36 * FRANCE
37 *
38 */
39
40#ifndef H_EXPLORAGRAM_OPTIMAL_TRANSPORT_OPTIMAL_TRANSPORT_H
41#define H_EXPLORAGRAM_OPTIMAL_TRANSPORT_OPTIMAL_TRANSPORT_H
42
44
45struct NLMatrixStruct;
47
48namespace GEO {
54 OT_PRECG, OT_SUPERLU, OT_CHOLMOD
55 };
56}
57
58#ifndef GOMGEN
59
60#include <geogram/mesh/mesh.h>
61#include <geogram/voronoi/RVD.h>
63#include <geogram/NL/nl.h>
65#include <geogram/third_party/HLBFGS/HLBFGS.h>
66
72namespace GEO {
73 class CentroidalVoronoiTesselation;
74
75
92 public:
100 index_t dimension,
101 Mesh* mesh,
102 const std::string& delaunay = "default",
103 bool BRIO = false
104 );
105
110
116 return dimension_;
117 }
118
124 return *mesh_;
125 }
126
133 void set_Newton(bool x) {
134 newton_ = x;
135 }
136
149 index_t nb_points, const double* points, index_t stride=0
150 );
151
165 index_t nb_air_particles, const double* air_particles, index_t stride,
166 double air_fraction
167 ) {
168 nb_air_particles_ = nb_air_particles;
169 air_particles_ = air_particles;
170 air_particles_stride_ = (stride == 0) ? dimension_ : stride;
171 air_fraction_ = air_fraction;
172 // "continuous air" mode (air fraction declared without any air
173 // particle).
174 clip_by_balls_ = (nb_air_particles == 0) && (air_fraction != 0.0);
175 }
176
181 double air_fraction() const {
182 return air_fraction_;
183 }
184
190 return nb_air_particles_;
191 }
192
201 void set_nu(index_t i, double nu);
202
203
209 void set_Laguerre_centroids(double* x) {
210 Laguerre_centroids_ = x;
211 }
212
218 void set_epsilon(double eps) {
219 epsilon_ = eps;
220 }
221
222
228 void set_linsolve_epsilon(double eps) {
229 linsolve_epsilon_ = eps;
230 }
231
238 linsolve_maxiter_ = maxiter;
239 }
240
247 linesearch_maxiter_ = maxiter;
248 }
249
259 linesearch_init_iter_ = init_iter;
260 }
261
269 void set_regularization(double eps_reg) {
270 epsilon_regularization_ = eps_reg;
271 }
272
273
282 linear_solver_ = solver;
283 }
284
291 void optimize(index_t max_iterations);
292
298 void set_verbose(bool x) {
299 verbose_ = x;
300 }
301
312 void optimize_full_Newton(index_t max_iterations, index_t n=0);
313
324 void optimize_level(index_t b, index_t e, index_t max_iterations);
325
337 const vector<index_t>& levels, index_t max_iterations
338 );
339
346 return weights_.size();
347 }
348
355 const double* point_ptr(index_t i) const {
356 geo_debug_assert(i < nb_points());
357 return &(points_dimp1_[dimp1_ * i]);
358 }
359
365 double weight(index_t i) const {
366 return weights_[i];
367 }
368
374 void set_weight(index_t i, double val) {
375 weights_[i] = val;
376 }
377
383 double potential(index_t i) const {
384 return points_dimp1_[dimp1_*i + dimension_];
385 }
386
395 static void funcgrad_CB(
396 index_t n, double* x, double& f, double* g
397 );
398
407 static void newiteration_CB(
408 index_t n, const double* x, double f, const double* g, double gnorm
409 );
410
416 return RVD_;
417 }
418
432 bool x,
433 bool show_RVD_seed = false,
434 bool last_iter_only = false
435 ) {
436 if(last_iter_only) {
437 save_RVD_iter_ = false;
438 save_RVD_last_iter_ = true;
439 } else {
440 save_RVD_iter_ = x;
441 }
442 show_RVD_seed_ = show_RVD_seed;
443 }
444
449 virtual void get_RVD(Mesh& M) = 0;
450
456 virtual void compute_Laguerre_centroids(double* centroids) = 0;
457
463
470 void new_linear_system(index_t n, double* x);
471
477 void add_ij_coefficient(index_t i, index_t j, double a) {
478 if(!user_H_g_) {
479 nlAddIJCoefficient(i,j,a);
480 } else {
481 if(user_H_ != nullptr) {
482 geo_debug_assert(user_H_->type == NL_MATRIX_SPARSE_DYNAMIC);
483 nlSparseMatrixAdd((NLSparseMatrix*)user_H_, i, j, a);
484 }
485 }
486 }
487
493 void add_i_right_hand_side(index_t i, double a) {
494 if(!user_H_g_) {
496 }
497 }
498
505
513 void set_initial_weight(index_t i, double w) {
514 weights_[i] = w;
515 }
516
521 double total_mass() const {
522 return total_mass_;
523 }
524
536 const double* weights, NLMatrix Laplacian, double* measures
537 );
538
539 protected:
540
545 double nu(index_t p) const {
546 return nu_.size() == 0 ? constant_nu_ : nu_[p];
547 }
548
549
553 virtual void newiteration();
554
563
571 void funcgrad(index_t n, double* w, double& f, double* g);
572
577 virtual void call_callback_on_RVD() = 0;
578
589 index_t n, const double* w,
590 double& f, double* g
591 );
592
602 double gradient_threshold(index_t n) const {
603 return ::sqrt(double(n) * geo_sqr(epsilon_ * constant_nu_));
604 }
605
606 public:
607
612 class Callback {
613 public:
620 ) : OTM_(OTM),
621 Newton_step_(false),
622 eval_F_(false),
623 n_(0),
624 w_(nullptr),
625 g_(nullptr),
626 mg_(nullptr) {
627 weighted_ =
628 OTM->mesh().vertices.attributes().is_defined("weight");
629 }
630
634 virtual ~Callback();
635
643 void set_Laguerre_centroids(double* mg) {
644 mg_ = mg;
645 }
646
653 return (mg_ != nullptr);
654 }
655
663 return mg_;
664 }
665
671 void set_w(const double* w, index_t n) {
672 w_ = w;
673 n_ = n;
674 }
675
683 void set_Newton_step(bool Newton) {
684 Newton_step_ = Newton;
685 }
686
692 bool is_Newton_step() const {
693 return Newton_step_;
694 }
695
702 funcval_.assign(nb, 0.0);
703 }
704
709 void set_g(double* g) {
710 g_ = g;
711 }
712
721 void set_eval_F(bool x) {
722 eval_F_ = x;
723 }
724
730 double funcval() const {
731 double result = 0.0;
732 FOR(i,funcval_.size()) {
733 result += funcval_[i];
734 }
735 return result;
736 }
737
738 protected:
740 bool weighted_;
741 bool Newton_step_;
742 bool eval_F_;
743 vector<double> funcval_;
744 index_t n_;
745 const double* w_;
746 double* g_;
747 double* mg_;
748 };
749
750 protected:
751 static OptimalTransportMap* instance_;
752 index_t dimension_;
754 Mesh* mesh_;
755 Delaunay_var delaunay_;
757 vector<double> points_dimp1_;
758 vector<double> weights_;
759 double total_mass_;
762 double epsilon_;
764 index_t current_call_iter_;
765
766 Callback* callback_;
767
768 std::string last_stats_;
769 bool pretty_log_;
770 index_t level_;
771
772 bool save_RVD_iter_;
773 bool save_RVD_last_iter_;
774 bool show_RVD_seed_;
775 index_t current_iter_;
776 bool newton_;
777 bool verbose_;
778
785
790
794 double g_norm_;
795
800
806
809
812
815
818
821
824
826 const double* air_particles_;
827
830
836
841
847
848
854
859 };
860
861}
862
863#endif
864
865#endif
Class and functions to compute restricted Voronoi diagrams and extract information from them.
#define geo_debug_assert(x)
Verifies that a condition is met.
Definition assert.h:196
bool is_defined(const std::string &name) const
Tests whether an attribute is defined.
Definition attributes.h:964
AttributesManager & attributes() const
Gets the attributes manager.
Definition mesh.h:109
Represents a mesh.
Definition mesh.h:3050
Base class for the callbacks executed for each intersection between a Laguerre cell and a simplex of ...
void set_nb_threads(index_t nb)
Specifies the number of threads.
bool has_Laguerre_centroids() const
Tests whether Laguerre centroids should be computed.
bool is_Newton_step() const
Tests whether the current step is a Newton step.
void set_g(double *g)
Specifies where the gradient should be stored.
void set_Newton_step(bool Newton)
Specifies whether current step is a Newton step.
Callback(OptimalTransportMap *OTM)
Callback constructor.
double * Laguerre_centroids()
Gets a pointer to the Laguerre centroids.
void set_eval_F(bool x)
Specifies whether the objective function should be evaluated.
virtual ~Callback()
Callback destructor.
void set_w(const double *w, index_t n)
Sets the weight vector.
double funcval() const
Gets the computed value of the objective function.
void set_Laguerre_centroids(double *mg)
Sets where centroids should be output.
Computes semi-discrete optimal transport maps.
double gradient_threshold(index_t n) const
Computes the stopping criterion of the solver.
OTLinearSolver linear_solver_
one of OT_PRECG, OT_SUPERLU, OT_CHOLMOD.
RestrictedVoronoiDiagram * RVD()
Gets the restricted Voronoi diagram.
double nu(index_t p) const
Gets the mass of the Dirac associated with point p.
NLMatrix user_H_
User-defined Hessian matrix.
double air_fraction_
The fraction of the total mass occupied by air.
void set_save_RVD_iter(bool x, bool show_RVD_seed=false, bool last_iter_only=false)
Sets whether the restricted Voronoi diagram at each iteration should be saved.
double measure_of_smallest_cell_
Measure of the smallest Laguerre cell.
void optimize_levels(const vector< index_t > &levels, index_t max_iterations)
Multi-level optimization.
void save_RVD(index_t id)
Saves the RVD at each iteration if specified on command line (just for debugging/ explaining the algo...
bool w_did_not_change_
True if w did not change, thus there is no need to recompute the power diagram.
void set_linsolve_epsilon(double eps)
Sets the tolerance for linear solve.
static void funcgrad_CB(index_t n, double *x, double &f, double *g)
Callback for the numerical solver.
double * Laguerre_centroids_
If user-specified, then Laguerre centroids are output here.
void set_linear_solver(OTLinearSolver solver)
Specifies whether a direct solver should be used.
void set_epsilon(double eps)
Sets the maximum error.
void set_nu(index_t i, double nu)
Sets the desired mass at one of the Diracs.
index_t linsolve_maxiter_
maximum number of iterations for linear solve
double epsilon_regularization_
Add a regularization term to remove translational degree of freedom for the weights.
bool user_H_g_
True if class is just used by user to compute Hessian and gradient instead of doing full computation.
index_t nb_points() const
Gets the number of points.
void set_regularization(double eps_reg)
Sets the weight of the regularization term.
double epsilon_
Acceptable relative deviation for the measure of a cell.
index_t nb_air_particles() const
Gets the number of air particles.
virtual ~OptimalTransportMap()
OptimalTransportMap destructor.
index_t air_particles_stride_
Number of doubles between two consecutive air particles in air_particles_.
OptimalTransportMap(index_t dimension, Mesh *mesh, const std::string &delaunay="default", bool BRIO=false)
OptimalTransportMap constructor.
virtual void get_RVD(Mesh &M)=0
Computes a mesh with the restricted Voronoi diagram.
bool clip_by_balls_
Enabled if air fraction is specified without any air particles.
void set_linesearch_init_iter(index_t init_iter)
Sets the number of steplength reductions to be done at the first iteration.
void solve_linear_system()
Solves a linear system.
const double * air_particles_
if set, pointer to the air particles.
void set_initial_weight(index_t i, double w)
Sets the initial value of the weight associated with one of the points.
double constant_nu_
Value of one of the Diracs if cte.
void new_linear_system(index_t n, double *x)
Starts a new linear system.
double weight(index_t i) const
Gets weight of a point.
void set_air_particles(index_t nb_air_particles, const double *air_particles, index_t stride, double air_fraction)
Sets the air particles that define the volume occupied by the free space.
void compute_P1_Laplacian(const double *weights, NLMatrix Laplacian, double *measures)
Computes the P1 Laplacian of the Laguerre cells.
double potential(index_t i) const
Gets the d+1-th coordinate of the embedding for a point.
void set_linsolve_maxiter(index_t maxiter)
Sets the maximum number of iterations for linear solve.
void set_weight(index_t i, double val)
Sets a weight of a point.
vector< double > nu_
Value of all the Diracs.
index_t nb_air_particles_
if non-zero, number of air particles.
void set_verbose(bool x)
Enable/disable messages during optimization.
static void newiteration_CB(index_t n, const double *x, double f, const double *g, double gnorm)
Callback for the numerical solver.
index_t linesearch_maxiter_
maximum number of steplength divisions
void eval_func_grad_Hessian(index_t n, const double *w, double &f, double *g)
Computes the objective function, its gradient and its Hessian.
double g_norm_
Norm of the gradient in last iteration.
virtual void call_callback_on_RVD()=0
Calls the callback for each intersection between a Laguerre cell and a simplex of the background mesh...
double air_fraction() const
Gets the air fraction.
const double * point_ptr(index_t i) const
Gets a point.
virtual void newiteration()
Callback for the numerical solver.
void add_i_right_hand_side(index_t i, double a)
Adds a coefficient to the right hand side.
void optimize(index_t max_iterations)
Computes the weights that realize the optimal transport map between the source mesh and the target po...
double total_mass() const
Gets the total mass of the domain.
virtual void compute_Laguerre_centroids(double *centroids)=0
Computes the centroids of the Laguerre cells.
void set_Laguerre_centroids(double *x)
Specifies a user vector where the centroids of the Laguerre cells will be stored after computing tran...
void optimize_level(index_t b, index_t e, index_t max_iterations)
Optimizes one level of the multilevel algorithm.
void set_linesearch_maxiter(index_t maxiter)
Sets the maximum number of line search iterations.
void update_sparsity_pattern()
Updates the sparsity pattern of the Hessian right after a new Laguerre diagram was computed.
void set_points(index_t nb_points, const double *points, index_t stride=0)
Sets the points that define the target distribution.
void set_Newton(bool x)
Sets whether Newton algorithm should be used.
index_t nbZ_
Number of empty cells in last iteration.
void funcgrad(index_t n, double *w, double &f, double *g)
Computes the objective function and its gradient.
double linsolve_epsilon_
maximum value of
index_t dimension() const
Gets the dimension.
index_t linesearch_init_iter_
starting number of steplength divisions
void add_ij_coefficient(index_t i, index_t j, double a)
Adds a coefficient to the matrix of the system.
Mesh & mesh()
Gets the mesh.
index_t dimp1_
dimension_ + 1
void optimize_full_Newton(index_t max_iterations, index_t n=0)
Computes the weights that realize the optimal transport map between the source mesh and the target po...
Computes a Restricted Voronoi Diagram (RVD).
Definition RVD.h:89
Vector with aligned memory allocation.
Definition memory.h:660
Abstract interface for Delaunay.
#define EXPLORAGRAM_API
Linkage declaration for exploragram symbols.
Definition defs.h:18
Included by all headers in exploragram.
The class that represents a mesh.
Global Vorpaline namespace.
Definition basic.h:55
T geo_sqr(T x)
Gets the square value of a value.
Definition numeric.h:301
OTLinearSolver
Specifies the linear solver to be used with OptimalTransport.
geo_index_t index_t
The type for storing and manipulating indices.
Definition numeric.h:329
The public API of the OpenNL linear solver library. Click the "More..." link below for simple example...
NLAPI NLulong NLAPIENTRY nlAddIJCoefficient(NLuint i, NLuint j, NLdouble value)
Adds a coefficient to the current matrix.
NLAPI void NLAPIENTRY nlAddIRightHandSide(NLuint i, NLdouble value)
Adds a coefficient to a component of the right hand side of the equation.
Internal OpenNL functions to manipulate sparse matrices.
The base class for abstract matrices.
Definition nl_matrix.h:80