2 * This program is free software: you can redistribute it and/or modify
3 * it under the terms of the GNU Lesser General Public License as
4 * published by the Free Software Foundation, either version 3 of the
5 * License, or (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 * @file AngleLinearMinimizer.ih
20 * @author Jacques-Olivier Lachaud (\c jacques-olivier.lachaud@univ-savoie.fr )
21 * Laboratory of Mathematics (CNRS, UMR 5807), University of Savoie, France
23 * @author (backported from ImaGene by) Bertrand Kerautret (\c kerautre@loria.fr )
24 * LORIA (CNRS, UMR 7503), University of Nancy, France
28 * Implementation of inline methods defined in AngleLinearMinimizer.h
30 * This file is part of the DGtal library.
33///////////////////////////////////////////////////////////////////////////////
34// IMPLEMENTATION of inline methods.
35///////////////////////////////////////////////////////////////////////////////
37//////////////////////////////////////////////////////////////////////////////
39//////////////////////////////////////////////////////////////////////////////
43///////////////////////////////////////////////////////////////////////////////
44// Implementation of inline methods //
48 * Sum of all the absolute displacements of the last optimisation step.
52DGtal::AngleLinearMinimizer::sum() const
58 * Max of all the absolute displacements of the last optimisation step.
62DGtal::AngleLinearMinimizer::max() const
69 * Default constructor. Does nothing.
72DGtal::AngleLinearMinimizerByRelaxation::AngleLinearMinimizerByRelaxation()
77 * Destructor. Does nothing.
80DGtal::AngleLinearMinimizerByRelaxation::~AngleLinearMinimizerByRelaxation()
85 * Default constructor. Does nothing.
88DGtal::AngleLinearMinimizerByGradientDescent::AngleLinearMinimizerByGradientDescent
95 * Destructor. Does nothing.
98DGtal::AngleLinearMinimizerByGradientDescent::~AngleLinearMinimizerByGradientDescent()
103 * Default constructor. Does nothing.
106DGtal::AngleLinearMinimizerByAdaptiveStepGradientDescent::AngleLinearMinimizerByAdaptiveStepGradientDescent
112 * Destructor. Does nothing.
115DGtal::AngleLinearMinimizerByAdaptiveStepGradientDescent::~AngleLinearMinimizerByAdaptiveStepGradientDescent()
121 * @return a reference on the information structure of the [i]th value.
124DGtal::AngleLinearMinimizer::ValueInfo &
125DGtal::AngleLinearMinimizer::rw( unsigned int i )
127 ASSERT( ( myValues != 0 ) && ( i < maxSize() ) );
128 return myValues[ i ];
133 * @return a const reference on the information structure of the [i]th value.
136const DGtal::AngleLinearMinimizer::ValueInfo &
137DGtal::AngleLinearMinimizer::ro( unsigned int i ) const
139 ASSERT( ( myValues != 0 ) && ( i < maxSize() ) );
140 return myValues[ i ];
145 * @return the maximum number of values stored in the object.
149DGtal::AngleLinearMinimizer::maxSize() const
156 * @return the number of values stored in the object.
160DGtal::AngleLinearMinimizer::size() const
167 * Specifies the exact number of valid values.
168 * @param nb any number below 'maxSize()'.
172DGtal::AngleLinearMinimizer::setSize( unsigned int nb )
174 ASSERT( nb <= maxSize() );
180 * Specifies if the curve is open or not.
181 * @param isCurveOpen when 'true' the curve is open and the last
182 * value does not depend on the first one, otherwise the curve is
183 * closed and the last value is linked to the first one.
187DGtal::AngleLinearMinimizer::setIsCurveOpen( bool isCurveOpen)
189 myIsCurveOpen = isCurveOpen;
193DGtal::AngleLinearMinimizer::~AngleLinearMinimizer()
200DGtal::AngleLinearMinimizer::AngleLinearMinimizer()
208DGtal::AngleLinearMinimizer::reset()
222DGtal::AngleLinearMinimizer::init( unsigned int nbMax )
225 myValues = new ValueInfo[ nbMax ];
228 myIsCurveOpen = false;
234///////////////////////////////////////////////////////////////////////////////
235// ------------------------- Optimization services --------------------------
239DGtal::AngleLinearMinimizer::getEnergy( unsigned int i1, unsigned int i2 ) const
241 ModuloComputer<int> mc( size() );
243 for ( unsigned int i = mc.next( i1 ); i != i2; )
245 unsigned int inext = mc.next( i );
246 const ValueInfo & vi = this->ro( i );
247 const ValueInfo & viprev = this->ro( mc.previous( i ) );
248 double dev = AngleComputer::deviation( vi.value, viprev.value );
249 E += (dev * dev) / viprev.distToNext;
259DGtal::AngleLinearMinimizer::getFormerEnergy( unsigned int i1, unsigned int i2 ) const
261 ModuloComputer<int> mc( size() );
263 for ( unsigned int i = mc.next( i1 ); i != i2; )
265 unsigned int inext = mc.next( i );
266 const ValueInfo & vi = this->ro( i );
267 const ValueInfo & viprev = this->ro( mc.previous( i ) );
268 double dev = AngleComputer::deviation( vi.oldValue, viprev.oldValue );
269 E += (dev * dev) / viprev.distToNext;
280DGtal::AngleLinearMinimizer::getGradient() const
282 ModuloComputer<int> mc( size() );
284 std::vector<double> grad( size() );
285 for ( unsigned int i = 0; i < size(); i++ )
287 unsigned int iprev = mc.previous( i );
288 unsigned int inext = mc.next( i );
289 const ValueInfo & vi = this->ro( i );
290 double val = vi.value;
291 if ( myIsCurveOpen && ( i == ( size() - 1 ) ) )
292 { // free extremity to the front/right.
293 const ValueInfo & viprev = this->ro( iprev );
294 double valp = viprev.value;
295 grad[ i ] = 2.0 * AngleComputer::deviation( val, valp ) / viprev.distToNext;
297 else if ( myIsCurveOpen && ( i == 0 ) )
298 { // free extremity to the back/left.
299 const ValueInfo & vinext = this->ro( inext );
300 double valn = vinext.value;
301 grad[ i ] = -2.0 * AngleComputer::deviation( valn, val ) / vi.distToNext;
305 const ValueInfo & viprev = this->ro( iprev );
306 const ValueInfo & vinext = this->ro( inext );
307 double valp = viprev.value;
308 double valn = vinext.value;
309 grad[ i ] = 2.0*( AngleComputer::deviation( val, valp ) / viprev.distToNext
310 - AngleComputer::deviation( valn, val ) / vi.distToNext ) ;
321DGtal::AngleLinearMinimizer::getFormerGradient() const
323 ModuloComputer< int> mc( size() );
325 std::vector<double> grad( size() );
326 for ( unsigned int i = 0; i < size(); i++ )
328 unsigned int iprev = mc.previous( i );
329 unsigned int inext = mc.next( i );
330 const ValueInfo & vi = this->ro( i );
331 double val = vi.oldValue;
332 if ( myIsCurveOpen && ( i == ( size() - 1 ) ) )
333 { // free extremity to the front/right.
334 const ValueInfo & viprev = this->ro( iprev );
335 double valp = viprev.oldValue;
336 grad[ i ] = 2.0 * AngleComputer::deviation( val, valp ) / viprev.distToNext;
338 else if ( myIsCurveOpen && ( i == 0 ) )
339 { // free extremity to the back/left.
340 const ValueInfo & vinext = this->ro( inext );
341 double valn = vinext.oldValue;
342 grad[ i ] = -2.0 * AngleComputer::deviation( valn, val ) / vi.distToNext;
346 const ValueInfo & viprev = this->ro( iprev );
347 const ValueInfo & vinext = this->ro( inext );
348 double valp = viprev.oldValue;
349 double valn = vinext.oldValue;
350 grad[ i ] = 2.0*( AngleComputer::deviation( val, valp ) / viprev.distToNext
351 - AngleComputer::deviation( valn, val ) / vi.distToNext ) ;
360DGtal::AngleLinearMinimizer::optimize()
362 return optimize( 0, 0 );
368DGtal::AngleLinearMinimizer::optimize( unsigned int i1, unsigned int i2 )
370 ASSERT( size() > 2 );
371 ModuloComputer< int> mc( size() );
374 // (I) first pass to work on old values.
377 ValueInfo & vi = this->rw( i );
378 vi.oldValue = vi.value;
383 this->oneStep( i1, i2 );
390 const ValueInfo & vi = this->ro( i );
391 double diff = fabs( AngleComputer::deviation( vi.value, vi.oldValue ) );
405DGtal::AngleLinearMinimizer::lastDelta() const
413DGtal::AngleLinearMinimizer::oneStep( unsigned int i1, unsigned int i2 )
415 ModuloComputer< int> mc( size() );
419 unsigned int iprev = mc.previous( i );
422 unsigned int inext = mc.next( i );
423 ValueInfo & vi = this->rw( i );
424 if ( myIsCurveOpen && ( i == ( size() - 1 ) ) )
425 { // free extremity to the front/right.
426 const ValueInfo & viprev = this->ro( iprev );
427 mid = viprev.oldValue; // - viprev.delta;
429 else if ( myIsCurveOpen && ( i == 0 ) )
430 { // free extremity to the back/left.
431 const ValueInfo & vinext = this->ro( inext );
432 mid = vinext.oldValue; // + vi.delta;
436 const ValueInfo & viprev = this->ro( iprev );
437 const ValueInfo & vinext = this->ro( inext );
438 double valp = viprev.oldValue; // - viprev.delta;
439 double valn = vinext.oldValue; // + vi.delta;
442 double y = AngleComputer::deviation( valn, valp );
443 mid = ( viprev.distToNext * y )
444 / ( vi.distToNext + viprev.distToNext );
445 mid = AngleComputer::cast( mid + valp );
448 if ( AngleComputer::less( mid, vi.min ) ) mid = vi.min;
449 if ( AngleComputer::less( vi.max, mid ) ) mid = vi.max;
450 double mvt = AngleComputer::deviation( mid, vi.oldValue );
451 vi.value = AngleComputer::cast( vi.oldValue + 0.5 * mvt );
465DGtal::AngleLinearMinimizerByRelaxation::oneStep( unsigned int i1, unsigned int i2 )
467 ModuloComputer< int> mc( size() );
471 unsigned int iprev = mc.previous( i );
474 unsigned int inext = mc.next( i );
475 ValueInfo & vi = this->rw( i );
476 // vi.oldValue = vi.value;
477 if ( myIsCurveOpen && ( i == ( size() - 1 ) ) )
478 { // free extremity to the front/right.
479 const ValueInfo & viprev = this->ro( iprev );
480 mid = viprev.value; // - viprev.delta;
482 else if ( myIsCurveOpen && ( i == 0 ) )
483 { // free extremity to the back/left.
484 const ValueInfo & vinext = this->ro( inext );
485 mid = vinext.oldValue; // + vi.delta;
489 const ValueInfo & viprev = this->ro( iprev );
490 const ValueInfo & vinext = this->ro( inext );
491 double valp = viprev.value; // - viprev.delta;
492 double valn = vinext.value;
495 double y = AngleComputer::deviation( valn, valp );
496 mid = ( viprev.distToNext * y )
497 / ( vi.distToNext + viprev.distToNext );
498 mid = AngleComputer::cast( mid + valp );
500 if ( AngleComputer::less( mid, vi.min ) ) mid = vi.min;
501 if ( AngleComputer::less( vi.max, mid ) ) mid = vi.max;
514DGtal::AngleLinearMinimizerByRelaxation::lastDelta() const
523DGtal::AngleLinearMinimizerByGradientDescent::oneStep( unsigned int i1, unsigned int i2 )
525 ModuloComputer< int> mc( size() );
527 std::vector<double> grad ( getFormerGradient() );
532 unsigned int inext = mc.next( i );
533 ValueInfo & vi = this->rw( i );
534 double val = vi.oldValue;
535 mid = AngleComputer::cast( val - myStep*grad[ i ] );
536 if ( AngleComputer::less( mid, vi.min ) ) mid = vi.min;
537 if ( AngleComputer::less( vi.max, mid ) ) mid = vi.max;
549DGtal::AngleLinearMinimizerByGradientDescent::lastDelta() const
551 std::vector<double> grad ( getFormerGradient() );
553 for ( unsigned int i = 0; i < size(); i++ )
555 const ValueInfo & vi = this->ro( i );
556 if ( vi.value != vi.oldValue )
558 double n = fabs( grad[ i ] );
559 if ( n > ninf ) ninf = n;
570DGtal::AngleLinearMinimizerByAdaptiveStepGradientDescent::oneStep( unsigned int i1, unsigned int i2 )
572 ModuloComputer< int> mc( size() );
573 std::vector<double> grad ( getFormerGradient() );
579 unsigned int inext = mc.next( i );
580 ValueInfo & vi = this->rw( i );
581 double val = vi.oldValue;
582 mid = AngleComputer::cast( val - myStep*grad[ i ] );
583 if ( AngleComputer::less( mid, vi.min ) ) mid = vi.min;
584 if ( AngleComputer::less( vi.max, mid ) ) mid = vi.max;
591 double E1 = getFormerEnergy( i1, i2 );
592 double E2 = getEnergy( i1, i2 );
608DGtal::AngleLinearMinimizerByAdaptiveStepGradientDescent::lastDelta() const
610 std::vector<double> grad ( getFormerGradient() );
612 for ( unsigned int i = 0; i < size(); i++ )
614 const ValueInfo & vi = this->ro( i );
615 if ( vi.value != vi.oldValue )
617 double n = fabs( grad[ i ] );
618 if ( n > ninf ) ninf = n;
627///////////////////////////////////////////////////////////////////////////////
628// Interface - public :
631 * Writes/Displays the object on an output stream.
632 * @param aStream the output stream where the object is written.
636DGtal::AngleLinearMinimizer::selfDisplay ( std::ostream & aStream ) const
638 aStream << "[AngleLinearMinimizer::standard 0.5]";
643 * Writes/Displays the object on an output stream.
644 * @param aStream the output stream where the object is written.
648DGtal::AngleLinearMinimizerByRelaxation::selfDisplay( std::ostream & aStream ) const
650 aStream << "[LinearMinimizer::relaxation]";
654 * Writes/Displays the object on an output stream.
655 * @param aStream the output stream where the object is written.
659DGtal::AngleLinearMinimizerByGradientDescent::selfDisplay( std::ostream& aStream ) const
661 aStream << "[LinearMinimizer::gradient descent " << myStep << "]";
665 * Writes/Displays the object on an output stream.
666 * @param aStream the output stream where the object is written.
670DGtal::AngleLinearMinimizerByAdaptiveStepGradientDescent::selfDisplay( std::ostream& aStream ) const
672 aStream << "[LinearMinimizer::gradient descent with adaptive step " << myStep << "]";
676 * Checks the validity/consistency of the object.
677 * @return 'true' if the object is valid, 'false' otherwise.
681DGtal::AngleLinearMinimizer::isValid() const
688///////////////////////////////////////////////////////////////////////////////
689// Internals - private :
692///////////////////////////////////////////////////////////////////////////////
697///////////////////////////////////////////////////////////////////////////////
698// Implementation of inline functions and external operators //
702DGtal::AngleLinearMinimizer::className() const
704 return "AngleLinearMinimizer";
708 * Overloads 'operator<<' for displaying objects of class 'AngleLinearMinimizer'.
709 * @param out the output stream where the object is written.
710 * @param object the object of class 'AngleLinearMinimizer' to write.
711 * @return the output stream after the writing.
715DGtal::operator<< ( std::ostream & out,
716 const AngleLinearMinimizer & object )
718 object.selfDisplay ( out );
723///////////////////////////////////////////////////////////////////////////////