// Copyright (C) 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
// et Marie Curie.
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Spot; see the file COPYING. If not, write to the Free
// Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
#ifndef SPOT_MISC_MODGRAY_HH
# define SPOT_MISC_MODGRAY_HH
namespace spot
{
/// \brief Loopless modular mixed radix Gray code iteration.
/// \ingroup misc_tools
///
/// This class is based on the loopless modular mixed radix gray
/// code algorithm described in exercise 77 of "The Art of Computer
/// Programming", Pre-Fascicle 2A (Draft of section 7.2.1.1:
/// generating all n-tuples) by Donald E. Knuth.
///
/// The idea is to enumerate the set of all n-tuples
/// (a0,a1,...,an-1) where each
/// aj range over a distinct set (this is the mixed
/// radix part), so that only one aj changes between
/// two successive tuples of the iteration (that is the Gray
/// code part), and that this changes occurs always in the same
/// direction, cycling over the set aj must cover (i.e.,
/// modular). The algorithm is loopless in that
/// computing the next tuple done without any loop, i.e., in
/// constant time.
///
/// This class does not need to know the type of the aj,
/// it will handle them indirectly through three methods: a_first(),
/// a_next(), and a_last(). These methods need to be implemented
/// in a subclass for the particular type of aj at hand.
///
/// The class itself offers four functions to control the iteration
/// over the set of all the (a0,a1,...,
/// an-1) tuples: first(), next(), last(), and done().
/// These functions are usually used as follows:
/// \code
/// for (g.first(); !g.done(); g.next())
/// use the tuple
/// \endcode
/// How to use the tuple of course depends on the way
/// it as been stored in the subclass.
///
/// Finally, let's mention two differences between this algorithm
/// and the one in Knuth's book. This version of the algorithm does
/// not need to know the radixes (i.e., the size of set of each
/// aj) beforehand: it will discover them on-the-fly when
/// a_last(j) first return true. It will also work with
/// aj that cannot be changed. (This is achieved by
/// reindexing the elements through \c non_one_radixes_, to consider
/// only the elements with a non-singleton range.)
class loopless_modular_mixed_radix_gray_code
{
public:
/// Constructor.
///
/// \param n The size of the tuples to enumerate.
loopless_modular_mixed_radix_gray_code(int n);
virtual ~loopless_modular_mixed_radix_gray_code();
/// \name iteration over an element in a tuple
///
/// The class does not know how to modify the elements of the
/// tuple (Knuth's ajs). These changes are therefore
/// abstracted using the a_first(), a_next(), and a_last()
/// abstract functions. These need to be implemented in
/// subclasses as appropriate.
///
/// @{
/// Reset aj to its initial value.
virtual void a_first(int j) = 0;
/// \brief Advance aj to its next value.
///
/// This will never be called if a_last(j) is true.
virtual void a_next(int j) = 0;
/// Whether aj is on its last value.
virtual bool a_last(int j) const = 0;
/// @}
/// \name iteration over all the tuples
/// @{
/// \brief Reset the iteration to the first tuple.
///
/// This must be called before calling any of next(), last(), or done().
void first();
/// \brief Whether this the last tuple.
///
/// At this point it is still OK to call next(), and then done() will
/// become true.
bool
last() const
{
return f_[0] == n_;
}
/// Whether all tuple have been explored.
bool
done() const
{
return done_;
}
/// \brief Update one item of the tuple and return its position.
///
/// next() should never be called if done() is true. If it is
/// called on the last tuple (i.e., last() is true), it will return
/// -1. Otherwise it will update one aj of the tuple
/// through one the aj handling functions, and return j.
int next();
/// @}
protected:
int n_;
bool done_;
int* a_;
int* f_;
int* m_;
int* s_;
int* non_one_radixes_;
};
} // spot
# endif // SPOT_MISC_MODGRAY_HH