31#if defined(ATSolver2D_RECURSES)
32#error Recursive header files inclusion detected in ATSolver2D.h
35#define ATSolver2D_RECURSES
37#if !defined ATSolver2D_h
46#include "DGtal/base/Common.h"
47#include "DGtal/base/ConstAlias.h"
48#include "DGtal/math/linalg/EigenSupport.h"
49#include "DGtal/dec/DiscreteExteriorCalculus.h"
50#include "DGtal/dec/DiscreteExteriorCalculusSolver.h"
51#include "DGtal/dec/DECHelpers.h"
88 template <
typename TKSpace,
89 typename TLinearAlgebra = EigenLinearAlgebraBackend >
160 std::vector<PrimalForm2>
g2;
164 std::vector<PrimalForm2>
u2;
214 for (
Index index = 0; index < size2; ++index) {
286 template <
typename VectorFieldInput,
typename SurfelRangeConstIterator>
289 SurfelRangeConstIterator itB, SurfelRangeConstIterator itE,
290 bool normalize =
false )
293 trace.
beginBlock(
"[ATSolver2D::initInputVectorFieldU2] Initializing input data" );
294 ASSERT( ! input.empty() );
296 if (
verbose >= 2 )
trace.
info() <<
"input g as " << N <<
" 2-forms." << std::endl;
300 for (
auto it = itB; it != itE; ++it, ++i )
304 g2[ k ].myContainer( idx ) = input[ i ][ k ];
308 trace.
info() <<
"Unknown u[:] = g[:] at beginning." << std::endl;
328 template <
typename ScalarFieldInput,
typename SurfelRangeConstIterator>
331 SurfelRangeConstIterator itB, SurfelRangeConstIterator itE )
334 trace.
beginBlock(
"[ATSolver2D::initInputVectorFieldU2] Initializing input data" );
335 ASSERT( ! input.empty() );
340 for (
auto it = itB; it != itE; ++it, ++i )
343 g2[ 0 ].myContainer( idx ) = input[ i ];
347 trace.
info() <<
"Unknown u[:] = g[:] at beginning." << std::endl;
369 template <
typename ScalarVector>
372 bool normalize =
false )
375 if (
verbose >= 2 )
trace.
info() <<
"discontinuity 0-form v = 1." << std::endl;
376 const Dimension N = ScalarVector().size();
377 if (
verbose >= 2 )
trace.
info() <<
"input g as " << N <<
" 2-forms." << std::endl;
380 const ScalarVector zero;
382 for (
Index index = 0; index < size(2); index++)
384 const SCell& cell =
g2[ 0 ].getSCell( index );
385 const auto it = input.find( cell );
386 const auto n = ( it != input.end() ) ? it->second : zero;
387 nbok += ( it != input.end() ) ? 1 : 0;
389 g2[ k ].myContainer( index ) = n[ k ];
393 trace.
info() <<
"Unknown u[:] = g[:] at beginning." << std::endl;
409 template <
typename Scalar>
414 if (
verbose >= 2 )
trace.
info() <<
"discontinuity 0-form v = 1." << std::endl;
421 for (
Index index = 0; index < size(2); index++)
423 const SCell& cell =
g2[ 0 ].getSCell( index );
424 const auto it = input.find( cell );
425 const auto n = ( it != input.end() ) ? *it : zero;
426 nbok += ( it != input.end() ) ? 1 : 0;
427 g2[ 0 ].myContainer( index ) = n;
430 if (
verbose >= 2 )
trace.
info() <<
"Unknown u[:] = g[:] at beginning." << std::endl;
463 void setUp(
double a,
double l,
const std::map<Surfel,Scalar>& weights )
470 trace.
info() <<
"Using variable weights for fitting (alpha term)" << std::endl;
473 for (
Index index = 0; index < size( 2 ); index++)
475 const SCell& cell =
g2[ 0 ].getSCell( index );
476 const Scalar& w = weights[ cell ];
479 alpha_g2[ k ].myContainer( index ) *= w;
498 template <
typename AlphaWeights,
typename SurfelRangeConstIterator>
500 const AlphaWeights& weights,
501 SurfelRangeConstIterator itB, SurfelRangeConstIterator itE )
508 trace.
info() <<
"Using variable weights for fitting (alpha term)" << std::endl;
512 for (
auto it = itB; it != itE; ++it, ++i )
515 const Scalar w = weights[ i ];
518 alpha_g2[ k ].myContainer( idx ) *= w;
548 bool solve_ok =
true;
555 if (
verbose >= 2 )
trace.
info() <<
"Prefactoring matrix U associated to u" << std::endl;
558 for (
Dimension d = 0; d < u2.size(); ++d )
560 if (
verbose >= 2 )
trace.
info() <<
"Solving U u[" << d <<
"] = a g[" << d <<
"]" << std::endl;
564 solve_ok = solve_ok && solver_u2.
isValid();
571 for (
Dimension d = 0; d < u2.size(); ++d )
573 trace.
info() <<
"build metric u2" << std::endl;
578 if (
verbose >= 2 )
trace.
info() <<
"Prefactoring matrix V associated to v" << std::endl;
585 solve_ok = solve_ok && solver_v0.
isValid();
606 double n_oo_max = 1e-4,
607 unsigned int iter_max = 10 )
611 std::ostringstream sstr;
612 sstr <<
"******* Solving AT for epsilon = " << eps <<
" **********";
616 for (
unsigned int i = 0; i < iter_max; ++i )
620 << i <<
"/" << iter_max <<
" ---------------" << std::endl;
625 trace.
info() <<
"Variation |v^k+1 - v^k|_oo = " << std::get<0>( diffs_v )
628 trace.
info() <<
"Variation |v^k+1 - v^k|_2 = " << std::get<1>( diffs_v )
630 trace.
info() <<
"Variation |v^k+1 - v^k|_1 = " << std::get<2>( diffs_v )
634 if ( std::get<0>( diffs_v ) < 1e-4 )
break;
659 bool compute_smallest_epsilon_map =
false,
660 double n_oo_max = 1e-4,
661 unsigned int iter_max = 10 )
664 if ( epsr <= 1.0 ) epsr = 2.0;
668 for (
double eps = eps1; eps >= eps2; eps /= epsr )
671 if ( compute_smallest_epsilon_map )
685 for (
Index index = 0; index < size( 2 ); index++)
688 for (
unsigned int d = 0; d < u2.size(); ++d )
689 n2 += u2[ d ].myContainer( index ) * u2[ d ].myContainer( index );
690 double norm = sqrt( n2 );
691 if (norm == 0.0)
continue;
692 for (
unsigned int d = 0; d < u2.size(); ++d )
693 u2[ d ].myContainer( index ) /= norm;
701 std::tuple<double,double,double>
diffV0()
const
708 return std::make_tuple( n_oo, n_2, n_1 );
722 std::tuple<double,double,double>
checkV0()
const
724 const double m1 = v0.myContainer.minCoeff();
725 const double m2 = v0.myContainer.maxCoeff();
726 const double ma = v0.myContainer.mean();
728 trace.
info() <<
"0-form v (should be in [0,1]): min=" << m1 <<
" avg=" << ma <<
" max=" << m2 << std::endl;
729 return std::make_tuple( m1, m2, ma );
769 template <
typename VectorFieldOutput,
typename SurfelRangeConstIterator>
772 SurfelRangeConstIterator itB, SurfelRangeConstIterator itE )
776 for (
auto it = itB; it != itE; ++it, ++i )
779 ASSERT( output[ i ].size() >= N );
781 output[ i ][ k ] = u2[ k ].myContainer( idx );
795 template <
typename ScalarFieldOutput,
typename SurfelRangeConstIterator>
798 SurfelRangeConstIterator itB, SurfelRangeConstIterator itE )
800 ASSERT( u2.size() == 1 &&
"[ATSolver2D::getOutputScalarFieldU2] "
801 "You try to output a scalar field from a vector field." );
803 for (
auto it = itB; it != itE; ++it, ++i )
806 output[ i ] = u2[ 0 ].myContainer( idx );
821 template <
typename ScalarFieldOutput,
typename CellRangeConstIterator>
824 CellRangeConstIterator itB, CellRangeConstIterator itE,
833 for (
auto it = itB; it != itE; ++it, ++i )
835 const Cell pointel = *it;
837 output[ i ] = v0.myContainer( idx );
842 for (
auto it = itB; it != itE; ++it, ++i )
844 const Cell linel = *it;
846 const Cell p0 =
K.uIncident( linel, d,
false );
847 const Cell p1 =
K.uIncident( linel, d,
true );
862 for (
auto it = itB; it != itE; ++it, ++i )
864 const Cell face = *it;
866 const Cell l0 =
K.uIncident( face, d,
false );
867 const Cell l1 =
K.uIncident( face, d,
true );
869 const Cell p00 =
K.uIncident( l0, j,
false );
870 const Cell p01 =
K.uIncident( l0, j,
true );
871 const Cell p10 =
K.uIncident( l1, j,
false );
872 const Cell p11 =
K.uIncident( l1, j,
true );
879 output[ i ] = 0.25 * ( v0.myContainer( idx00 ) + v0.myContainer( idx01 )
880 + v0.myContainer( idx10 ) + v0.myContainer( idx11 ) );
883 output[ i ] = std::min( std::min( v0.myContainer( idx00 ), v0.myContainer( idx01 ) ),
884 std::min( v0.myContainer( idx10 ), v0.myContainer( idx11 ) ) );
887 output[ i ] = std::max( std::max( v0.myContainer( idx00 ), v0.myContainer( idx01 ) ),
888 std::max( v0.myContainer( idx10 ), v0.myContainer( idx11 ) ) );
905 for (
const SCell surfel :
ptrCalculus->template getIndexedSCells<2, PRIMAL>() )
907 const Cell face =
K.unsigns( surfel );
909 const Cell l0 =
K.uIncident( face, k1,
false );
910 const Cell l1 =
K.uIncident( face, k1,
true );
912 const Cell ll0 =
K.uIncident( face, k2,
false );
913 const Cell ll1 =
K.uIncident( face, k2,
true );
914 const Cell p00 =
K.uIncident( l0, k2,
false );
915 const Cell p01 =
K.uIncident( l0, k2,
true );
916 const Cell p10 =
K.uIncident( l1, k2,
false );
917 const Cell p11 =
K.uIncident( l1, k2,
true );
919 std::vector<double> features( 4 );
920 features[ 0 ] = v0.myContainer(
ptrCalculus->getCellIndex( p00 ) );
921 features[ 1 ] = v0.myContainer(
ptrCalculus->getCellIndex( p01 ) );
922 features[ 2 ] = v0.myContainer(
ptrCalculus->getCellIndex( p10 ) );
923 features[ 3 ] = v0.myContainer(
ptrCalculus->getCellIndex( p11 ) );
924 std::sort( features.begin(), features.end() );
926 if ( features[ 1 ] <= threshold )
930 it->second = std::min(
epsilon, it->second );
951 out <<
"[ATSolver2D] v is between min/avg/max:"
952 << std::get<0>(cv) <<
"/"
953 << std::get<1>(cv) <<
"/"
954 << std::get<2>(cv) << std::endl;
978 if (
verbose >= 2 )
trace.
info() <<
"derivative of primal 0-forms: primal_D0" << std::endl;
980 if (
verbose >= 2 )
trace.
info() <<
"derivative of primal 1-forms: primal_D1" << std::endl;
982 if (
verbose >= 2 )
trace.
info() <<
"antiderivative of primal 2-forms: primal_AD2" << std::endl;
984 if (
verbose >= 2 )
trace.
info() <<
"vertex to edge average operator: M01" << std::endl;
987 if (
verbose >= 2 )
trace.
info() <<
"edge to face average operator: M12" << std::endl;
1007 template <
typename T>
1022#undef ATSolver2D_RECURSES
Aim: This class solves Ambrosio-Tortorelli functional on a two-dimensional digital space (a 2D grid o...
bool solveForEpsilon(double eps, double n_oo_max=1e-4, unsigned int iter_max=10)
Index initInputVectorFieldU2(const std::map< Surfel, ScalarVector > &input, bool normalize=false)
Calculus::PrimalHodge2 PrimalHodge2
Index initInputScalarFieldU2(const std::map< Surfel, Scalar > &input)
void getOutputScalarFieldU2(ScalarFieldOutput &output, SurfelRangeConstIterator itB, SurfelRangeConstIterator itE)
void setUp(double a, double l, const AlphaWeights &weights, SurfelRangeConstIterator itB, SurfelRangeConstIterator itE)
void getOutputScalarFieldV0(ScalarFieldOutput &output, CellRangeConstIterator itB, CellRangeConstIterator itE, CellOutputPolicy policy=CellOutputPolicy::Average)
Calculus::PrimalDerivative0 PrimalDerivative0
static const Dimension dimension
Calculus::PrimalHodge0 PrimalHodge0
bool solveOneAlternateStep()
PrimalForm2 getU2(Dimension k) const
void initInputScalarFieldU2(const ScalarFieldInput &input, SurfelRangeConstIterator itB, SurfelRangeConstIterator itE)
std::vector< PrimalForm2 > alpha_g2
The alpha-weighted N-array of input primal 2-forms g.
std::vector< PrimalForm2 > u2
The N-array of regularized primal 2-forms u.
void setUp(double a, double l)
PrimalIdentity2 alpha_Id2
The alpha-weighted identity operator for primal 2-forms (stored for performance)
Calculus::PrimalIdentity1 PrimalIdentity1
ATSolver2D(ConstAlias< Calculus > aCalculus, int aVerbose=0)
HyperRectDomain< Space > Domain
Calculus::PrimalForm0 PrimalForm0
int verbose
Tells the verbose level.
void updateSmallestEpsilonMap(const double threshold=.5)
RealVector::Component Scalar
Calculus::PrimalAntiderivative1 PrimalAntiderivative1
EigenLinearAlgebraBackend::SolverSimplicialLDLT LinearAlgebraSolver
TLinearAlgebra LinearAlgebra
void setEpsilon(double e)
void initInputVectorFieldU2(const VectorFieldInput &input, SurfelRangeConstIterator itB, SurfelRangeConstIterator itE, bool normalize=false)
PrimalDerivative1 M12
The primal edge to face average operator.
SmallestEpsilonMap smallest_epsilon_map
Calculus::PrimalForm1 PrimalForm1
std::tuple< double, double, double > diffV0() const
PrimalForm0 l_1_over_4e
The primal 0-form lambda/(4epsilon) (stored for performance)
PrimalForm0 getV0() const
PrimalAntiderivative2 primal_AD2
The antiderivative of primal 2-forms.
Index size(const int order) const
Calculus::PrimalIdentity2 PrimalIdentity2
ATSolver2D & operator=(const ATSolver2D &other)=default
PrimalForm1 getV1() const
Calculus::PrimalDerivative1 PrimalDerivative1
DiscreteExteriorCalculus< 2, dimension, LinearAlgebra > Calculus
void initOperators()
Initializes the operators.
void setUp(double a, double l, const std::map< Surfel, Scalar > &weights)
Calculus::PrimalAntiderivative2 PrimalAntiderivative2
ATSolver2D(ATSolver2D &&other)=default
KSpace::template SurfelMap< double >::Type SmallestEpsilonMap
Surfel2IndexMap surfel2idx
Calculus::PrimalHodge1 PrimalHodge1
Space::RealVector RealVector
KSpace::template SurfelMap< Index >::Type Surfel2IndexMap
Calculus::PrimalIdentity0 PrimalIdentity0
bool solveGammaConvergence(double eps1=2.0, double eps2=0.25, double epsr=2.0, bool compute_smallest_epsilon_map=false, double n_oo_max=1e-4, unsigned int iter_max=10)
Calculus::PrimalForm2 PrimalForm2
PrimalForm2 getV2() const
PrimalDerivative1 primal_D1
the derivative operator for primal 1-forms
DiscreteExteriorCalculusSolver< Calculus, LinearAlgebraSolver, 0, PRIMAL, 0, PRIMAL > SolverV0
PrimalIdentity0 l_1_over_4e_Id0
The 1/(4epsilon)-weighted identity operator for primal 0-forms (stored for performance)
ATSolver2D< KSpace, LinearAlgebra > Self
void selfDisplay(std::ostream &out) const
bool normalize_u2
Indicates whether to normalize U (unit norm) at each iteration or not.
PrimalForm0 former_v0
The primal 0-form v at the previous iteration.
std::tuple< double, double, double > checkV0() const
DiscreteExteriorCalculusSolver< Calculus, LinearAlgebraSolver, 2, PRIMAL, 2, PRIMAL > SolverU2
std::vector< PrimalForm2 > g2
The N-array of input primal 2-forms g.
void getOutputVectorFieldU2(VectorFieldOutput &output, SurfelRangeConstIterator itB, SurfelRangeConstIterator itE)
PrimalDerivative0 primal_D0
the derivative operator for primal 0-forms
@ Maximum
compute maximum value at cell vertices
@ Average
compute average values at cell vertices
@ Minimum
compute minimum value at cell vertices,
CountedConstPtrOrConstPtr< Calculus > ptrCalculus
A smart (or not) pointer to a calculus object.
PrimalDerivative0 M01
The primal vertex to edge average operator.
ATSolver2D(const ATSolver2D &other)=default
Aim: This class encapsulates its parameter class so that to indicate to the user that the object/poin...
Aim: Smart or simple const pointer on T. It can be a smart pointer based on reference counts or a sim...
Aim: This wraps a linear algebra solver around a discrete exterior calculus.
SolutionKForm solve(const InputKForm &input_kform) const
LinearAlgebraSolver myLinearAlgebraSolver
DiscreteExteriorCalculusSolver & compute(const Operator &linear_operator)
Aim: DiscreteExteriorCalculus represents a calculus in the dec package. This is the main structure in...
LinearAlgebraBackend::DenseVector::Index Index
Aim: Parallelepidec region of a digital space, model of a 'CDomain'.
static const constexpr Dimension dimension
Aim: LinearOperator represents discrete linear operator between discrete kforms in the DEC package.
TransposedLinearOperator transpose() const
Aim: Implements basic operations that will be used in Point and Vector classes.
TEuclideanRing Component
Type for Vector elements.
void beginBlock(const std::string &keyword="")
DGtal::LinearOperator< Calculus, dim, duality, dim, duality > diagonal(const DGtal::KForm< Calculus, dim, duality > &kform)
DGtal is the top-level namespace which contains all DGtal functions and types.
std::ostream & operator<<(std::ostream &out, const ClosedIntegerHalfPlane< TSpace > &object)
DGtal::uint32_t Dimension
Eigen::SimplicialLDLT< SparseMatrix > SolverSimplicialLDLT
Represents a signed cell in a cellular grid space by its Khalimsky coordinates and a boolean value.