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 OrderedAlphabet.ih
19 * @author Jacques-Olivier Lachaud (\c jacques-olivier.lachaud@univ-savoie.fr )
20 * Laboratory of Mathematics (CNRS, UMR 5807), University of Savoie, France
21 * @author Laurent Provot (\c Laurent.Provot@loria.fr )
22 * LORIA (CNRS, UMR 7503), Nancy University, France
26 * Implementation of inline methods defined in OrderedAlphabet.h
28 * This file is part of the DGtal library.
31 ///////////////////////////////////////////////////////////////////////////////
32 // IMPLEMENTATION of inline methods.
33 ///////////////////////////////////////////////////////////////////////////////
35 //////////////////////////////////////////////////////////////////////////////
37 //////////////////////////////////////////////////////////////////////////////
41 ///////////////////////////////////////////////////////////////////////////////
42 // Implementation of inline methods //
45 * Constructor from letters
47 * @param first the first letter of the alphabet.
48 * @param nb the number of letters of the alphabet.
50 * Exemple: OrderedAlphabet( '0', 4 ) defines the alphabet for
51 * 4-connected freeman chains.
54 DGtal::OrderedAlphabet::OrderedAlphabet( char first, unsigned int nb )
55 : myFirst( first ), myNb( nb )
57 myOrder = new unsigned int[ nb ];
59 ASSERT( ( myOrder != 0 )
60 && "[DGtal::OrderedAlphabet::OrderedAlphabet( char first, int nb )] error in new: no memory left ?" );
61 for ( unsigned int i = 0; i < myNb; ++i )
66 * @param c any valid letter in this alphabet.
68 * @return the index of the letter [c] in the order relation,
69 * starting from 0 to myNb-1.
73 DGtal::OrderedAlphabet::order( char c ) const
75 ASSERT( ( c - myFirst ) < (int) myNb
76 && "[DGtal::OrderedAlphabet::order( char c )] invalid letter." );
77 return myOrder[ c - myFirst ];
81 * @param i the index of some letter in the order relation,
82 * between 0 and myNb-1.
84 * @return c the corresponding letter in this alphabet.
86 * NB: O(nb of letters in the alphabet).
90 DGtal::OrderedAlphabet::letter( unsigned int i ) const
93 for ( unsigned int j = 0; j < myNb; ++j )
94 if ( myOrder[ j ] == i )
95 return static_cast<char>(myFirst + j);
101 * @param c1 a letter in the alphabet
102 * @param c2 another letter in the same alphabet.
103 * @return 'true' iff c1 < c2
107 DGtal::OrderedAlphabet::less( char c1, char c2 ) const
109 return myOrder[ c1 - myFirst ] < myOrder[ c2 - myFirst ];
113 * @param c1 a letter in the alphabet
114 * @param c2 another letter in the same alphabet.
115 * @return 'true' iff c1 <= c2
119 DGtal::OrderedAlphabet::lessOrEqual( char c1, char c2 ) const
121 return myOrder[ c1 - myFirst ] <= myOrder[ c2 - myFirst ];
125 * @param c1 a letter in the alphabet
126 * @param c2 another letter in the same alphabet.
127 * @return 'true' iff c1 == c2
131 DGtal::OrderedAlphabet::equal( char c1, char c2 ) const
137 ///////////////////////////////////////////////////////////////////////////////
138 // Implementation of inline functions and external operators //
141 * Overloads 'operator<<' for displaying objects of class 'OrderedAlphabet'.
142 * @param out the output stream where the object is written.
143 * @param object the object of class 'OrderedAlphabet' to write.
144 * @return the output stream after the writing.
148 DGtal::operator<< ( std::ostream & out,
149 const OrderedAlphabet & object )
151 object.selfDisplay ( out );
158 ///////////////////////////////////////////////////////////////////////////////
166 DGtal::OrderedAlphabet::~OrderedAlphabet()
173 * @return the current ordered alphabet.
177 DGtal::OrderedAlphabet::orderedAlphabet() const
180 tbl = (char *)malloc((myNb + 1)*sizeof(char));
181 for ( unsigned int i = 0; i < myNb; ++i )
183 tbl[ myOrder[ i ] ] = static_cast<char>(myFirst + i);
186 std::string s( tbl );
192 * Shift a0 < a1 < ... < an to a1 < ... < an < a0
196 DGtal::OrderedAlphabet::shiftLeft()
198 unsigned int* p = myOrder;
199 unsigned int* q = myOrder + myNb;
203 *p = ( k == 0 ) ? myNb - 1 : k - 1;
209 * Shift a0 < a1 < ... < an to an < a0 < ... < an-1
213 DGtal::OrderedAlphabet::shiftRight()
215 unsigned int* p = myOrder;
216 unsigned int* q = myOrder + myNb;
219 unsigned int k = *p + 1;
220 *p = ( k == myNb ) ? 0 : k;
226 * Reverse the order a0 < a1 < ... < an to an < ... < a1 < a0
230 DGtal::OrderedAlphabet::reverse()
232 unsigned int* p = myOrder;
233 unsigned int* q = myOrder + myNb;
242 * Reverse the order a0 < a1 < ... < an to a3 < a2 < a1 < a0 < an < ...
246 DGtal::OrderedAlphabet::reverseAround12()
248 unsigned int* p = myOrder;
249 unsigned int* q = myOrder + myNb;
252 *p = ( myNb + 3 - *p ) % myNb;
261 * Gives the first lyndon factor of the word [w] starting at
262 * position [s] in this alphabet.
264 * @param len (returns) the length of the primitive Lyndon factor
265 * (which starts at position s).
267 * @param nb (returns) the number of times the Lyndon factor appears.
270 * @param s the starting index in [w].
271 * @param e the index after the end in [w] (s<e).
275 DGtal::OrderedAlphabet::firstLyndonFactor
276 ( size_t & len, size_t & nb,
277 const std::string & w,
278 index_t s, index_t e ) const
282 while ( ( j < e ) && ( lessOrEqual( w[ i ], w[ j ] ) ) )
284 if ( equal( w[ i ], w[ j ] ) )
290 len = (size_t) j - i;
291 nb = ( (size_t) ( j - s ) ) / len;
296 * Gives the first lyndon factor of the cyclic word [w]
297 * starting at position [s] in this alphabet.
299 * @param len (returns) the length of the primitive Lyndon factor
300 * (which starts at position s).
302 * @param nb (returns) the number of times the Lyndon factor appears.
305 * @param s the starting index in [w].
306 * @param e the index after the end in [w] (s and e arbitrary).
310 DGtal::OrderedAlphabet::firstLyndonFactorMod
311 ( size_t & len, size_t & nb,
312 const std::string & w,
313 index_t s, index_t e ) const
315 size_t modulo = (DGtal::OrderedAlphabet::size_t)w.size();
316 DGtal::ModuloComputer< Integer > mc( modulo );
318 index_t j = mc.next( s );
319 while ( ( j != e ) && ( lessOrEqual( w[ i ], w[ j ] ) ) )
321 if ( equal( w[ i ], w[ j ] ) )
327 len = j >= i ? (size_t) ( j - i )
328 : (size_t) ( j + modulo - i );
332 nb = ( (size_t) ( ( j + modulo - s ) % modulo ) ) / len;
337 * @param len (returns) the length of the primitive Lyndon factor
338 * (which starts at position s).
340 * @param nb (returns) the number of times the Lyndon factor appears.
342 * @param w a word which starts with a1 or a2 at position s.
343 * @param s the starting index in [w].
344 * @param e the index after the end in [w] (s<e).
347 bool DGtal::OrderedAlphabet::duvalPP( size_t & len, size_t & nb,
348 const std::string & w, index_t s, index_t e) const
350 ASSERT( ( order( w[ s ] ) == 1 ) || ( order( w[ s ] ) == 2 ) );
355 while ( ( j < e ) && ( lessOrEqual( w[ i ], w[ j ] ) ) )
357 if ( equal( w[ i ], w[ j ] ) )
365 if ( ( j != q ) || ( order ( w[ j ] ) != 2 ) )
377 len = (size_t) j - i;
378 nb = ( (size_t) (j-s) ) / len;
383 * @param len (returns) the length of the primitive Lyndon factor
384 * (which starts at position s).
386 * @param nb (returns) the number of times the Lyndon factor appears.
388 * @param n1 (returns) the number of occurrences of the letter a1
389 * in the Lyndon factor
391 * @param n2 (returns) the number of occurrences of the letter a2
392 * in the Lyndon factor
394 * @param lf1 (returns) the number of occurrences of the letter a1
395 * from 's' to the first lower leaning point.
397 * @param lf2 (returns) the number of occurrences of the letter a2
398 * from 's' to the first lower leaning point.
400 * @param w a word which starts with a1 or a2 at position s.
401 * @param s the starting index in [w].
402 * @param e the index after the end in [w] (s<e).
406 DGtal::OrderedAlphabet::duvalPPtoDSS
407 ( size_t & len, size_t & nb,
408 unsigned int & n1, unsigned int & n2,
409 unsigned int & lf1, unsigned int & lf2,
410 const std::string & w,
414 ASSERT( ( order( w[ s ] ) == 1 ) || ( order( w[ s ] ) == 2 ) );
419 unsigned int slope1 = (order( w[ i ] ) == 1) ? 1 : 0;
420 unsigned int slope2 = (order( w[ i ] ) == 2) ? 1 : 0;
425 while ( ( j < e ) && ( lessOrEqual( w[ i ], w[ j ] ) ) ) {
427 //This 'if/else if' is added to compute the vector defined by
428 //the Christoffel word, this is usefull in order to compute the
430 if (order( w[ j ] ) == 1)
432 else if (order( w[ j ] ) == 2)
435 if ( equal( w[ i ], w[ j ] ) ) {
439 //A repetition is read when j==s+(nb+1)*(p-s+1)-1
441 if ( j == nb * (p-s+1) + p ) {
446 if ( ( j != q ) || ( order ( w[ j ] ) != 2 ) ) {
454 // Extra information to compute the leaning points
455 lf1 = lf1 + (nb-1)*n1;
456 lf2 = lf2 + (nb-1)*n2;
463 len = (size_t) j - i;
465 ASSERT( nb == (size_t) (j-s) / len);
471 * Adaptation of Duval's algorithm to extract the first Lyndon factor
472 * (FLF). Whilst scanning the Lyndon factor, it also checks whether it
473 * is a Christoffel word or not. It returns 'true' if the FLF is
474 * indeed a Christoffel word, otherwise returns false. It starts the
475 * extraction at position [s] in the cyclic word [w].
477 * The alphabet takes the form a0 < a1 < a2 < ... < an-1. [w] starts
478 * with a1 or a2 at position s.
480 * See [Provencal, Lachaud 2009].
482 * @param len (returns) the length of the primitive Lyndon factor
483 * (which starts at position s).
485 * @param nb (returns) the number of times the Lyndon factor appears.
487 * @param w a (cyclic) word which starts with a1 or a2 at position s.
489 * @param s the starting index in [w].
490 * @param e the index after the end in [w] (s and e arbitrary).
494 DGtal::OrderedAlphabet::duvalPPMod( size_t & len, size_t & nb,
495 const std::string & w,
496 index_t s, index_t e ) const
498 ASSERT( ( order( w[ s ] ) == 1 )
499 || ( order( w[ s ] ) == 2 ) );
500 size_t modulo = (DGtal::OrderedAlphabet::size_t)w.size();
501 ModuloComputer< Integer > mc( modulo );
502 ModuloComputer< Integer >::UnsignedInteger i = s;
503 index_t j = mc.next( s );
506 while ( ( j != e ) && ( lessOrEqual( w[ i ], w[ j ] ) ) )
508 if ( equal( w[ i ], w[ j ] ) )
510 if ( j == mc.cast( s + q - 1 ) )
516 if ( ( j != mc.cast( s + q - 1 ) ) || ( order ( w[ j ] ) != 2 ) )
521 unsigned int tmp = p;
528 len = j >= i ? (size_t) ( j - i )
529 : (size_t) ( j + modulo - i );
530 nb = ( (size_t) ( ( j + modulo - s ) % modulo ) ) / len;
535 ///////////////////////////////////////////////////////////////////////////////
536 // Interface - public :
539 * Writes/Displays the object on an output stream.
540 * @param out the output stream where the object is written.
544 DGtal::OrderedAlphabet::selfDisplay ( std::ostream & out ) const
546 out << "[OrderedAlphabet]";
547 out << " " << orderedAlphabet() << std::endl;
551 * Checks the validity/consistency of the object.
552 * @return 'true' if the object is valid, 'false' otherwise.
556 DGtal::OrderedAlphabet::isValid() const
563 ///////////////////////////////////////////////////////////////////////////////
564 // ----------------------- MLP services ------------------------------
567 * Extracts the next edge of the minimum length polygon starting from
568 * position [s] on the word [w]. The alphabet may be modified
569 * (reversed or shifted). The output alphabet is some a0 < a1 < a2 < ...
571 * @param nb_a1 (returns) the number of letters a1 in the extracted edge (a1
572 * in the output alphabet)
574 * @param nb_a2 (returns) the number of letters a2 in the extracted edge (a2
575 * in the output alphabet)
577 * @param w the input (cyclic) word (may be modified in the process).
579 * @param s the starting point in the word (updated).
581 * @param cvx (updates) this boolean is flipped only if a change of
582 * convexity is detected.
584 * @return the number of letters of the extracted edge.
587 DGtal::OrderedAlphabet::size_t
588 DGtal::OrderedAlphabet::nextEdge( size_t & nb_a1,
594 ModuloComputer< Integer > mc( (unsigned int)w.size() );
598 bool inC = duvalPPMod( len, nb, w, s, s );
600 // case : change of convexity
602 // JOL : temporary change of letter w[ s ]
605 w[ s ] = letter( 2 ); // a3
606 this->reverseAround12();
608 l = nextEdge( nb_a1, nb_a2, w, s, cvx );
609 // JOL : former letter is put back in string.
612 else if ( ( len == 1 ) && ( order( w[ s ] ) == 1 ) )
613 // case u=a1 => Quadrant change
616 s = mc.cast( s + nb );
622 { // standard (convex) case.
624 char a2 = letter( 2 );
628 s = mc.cast( s + l );
631 if ( w[ ss ] == a2 ) ++nb_a2;
643 ///////////////////////////////////////////////////////////////////////////////
644 // Internals - private :
647 ///////////////////////////////////////////////////////////////////////////////