A strictly monotone sequence is a monotone sequence that has no identical pairs of elements.. The testturns out to be slightly easier: template int is_strictly_monotoneconst Type *f, ul
Trang 1A strictly monotone sequence is a monotone sequence that has no identical pairs of elements The test
turns out to be slightly easier:
template <typename Type>
int is_strictly_monotone(const Type *f, ulong n)
// return
// +1 for strictly ascending order
// -1 for strictly descending order
A sequence is called convex if it starts with an ascending part and ends with a descending part A concave
sequence starts with a descending and ends with an ascending part Whether a monotone sequence isconsidered convex or concave again is a matter of convention (i.e you have the choice to consider the first
or the last element as extremum) Lacking a term that contains both convex and concave the followingroutine is called is_convex:
template <typename Type>
long is_convex(Type *f, ulong n)
//
// return
// +val for convex sequence (first rising then falling)
// -val for concave sequence (first falling then rising)
// else 0
//
// val is the (second) index of the first pair at the point
// where the ordering changes; val>=n iff seq is monotone
Trang 2if ( k==n ) return s; // sequence is monotone
// check that the ordering does not change again:
if ( s>0 ) // was: ascending > descending
The test for strictly convex (or concave) sequences is:
template <typename Type>
long is_strictly_convex(Type *f, ulong n)
//
// return
// +val for strictly convex sequence
// (i.e first strictly rising then strictly falling)
// -val for strictly concave sequence
// (i.e first strictly falling then strictly rising)
// else 0
//
// val is the (second) index of the first pair at the point
// where the ordering changes; val>=n iff seq is strictly monotone
// check that the ordering does not change again:
if ( s>0 ) // was: ascending > descending
Trang 4Selected combinatorical algorithms
This chapter presents selected combinatorical algorithms The generation of combinations, subsets, titions, and pairings of parentheses (as example for the use of ‘funcemu’) are treated here Permutationsare treated in a seperate chapter because of the not so combinatorical viewpoint taken with most of thematerial (especially the specific examples like the revbin-permutation) there
par-TBD: debruijn sequences via primitive polys possibly using bitengine
10.1 Offline functions: funcemu
Sometimes it is possible to find recursive algorithm for solving some problem that is not easily solvediteratively However the recursive implementations might produce the results in midst of its calling graph.When a utility class providing a the results one by one with some next call is required there is an apparentproblem: There is only one stack available for function calls1 We do not have offline functions.
As an example consider the following recursive code2
1 True for the majority of the programming languages.
2 given by Glenn Rhoads
152
Trang 5template <typename Type>
class funcemu
{
public:
ulong tp_; // sTate stack Pointer
ulong dp_; // Data stack Pointer
ulong *t_; // sTate stack
Type *d_; // Data stack
ulong stpeek() const { return t_[tp_-1]; }
void stpeek(ulong &x) { x = t_[tp_-1]; }
void push(Type x, Type y) { push(x); push(y); }
void push(Type x, Type y, Type z) { push(x); push(y); push(z); }
void push(Type x, Type y, Type z, Type u)
{ push(x); push(y); push(z); push(u); }
void peek(Type &x) { x = d_[dp_-1]; }
void peek(Type &x, Type &y)
Trang 6void poke(Type x, Type y)
#define PAREN 0 // initial state
fe_->pop(4); fe_->stpop(); // emu_return to caller
if ( fe_->more() ) goto redo;
return 0; // return from top level emu_call
Trang 710.2 Combinations in lexicographic order
The combinations of three elements out of six in lexicographic order are
Trang 8x_[j]; // move down edge element
// and move rest of block to high end:
while ( ++j < k_ ) x_[j] = n_ - k_ + j;
return 1;
}
const ulong * data() { return x_; }
friend ostream & operator << (ostream &os, const comb_lex &x);
};
[FXT: class comb lex in comb/comblex.h]
The listing at the beginning of this section can then be produced by a simple fragment like
Trang 9}
while ( comb.next() );
Cf [FXT: file demo/comblex-demo.cc]
10.3 Combinations in co-lexicographic order
The combinations of three elements out of six in co-lexicographic order are
Trang 10x_[j]; // move edge element down
// attach rest of low block:
while ( 0!=j ) x_[j] = x_[j+1] - 1;
return 1;
}
const ulong * data() { return x_; }
friend ostream & operator << (ostream &os, const comb_colex &x);
};
[FXT: class comb colex in comb/combcolex.h]
For the connection between lex-order and colex-order see section 7.8
Usage is completely analogue to that of the class comb lex, cf [FXT: file demo/combcolex-demo.cc]
10.4 Combinations in minimal-change order
The combinations of three elements out of six in minimal-change order are
The algorithm used in the utility class [FXT: class comb minchange in comb/combminchange.h] is based
on inlined versions of the routines that were explained in the corresponding bitmagic section (7.12).class comb_minchange
{
public:
ulong n_; // number of elements to choose from
ulong k_; // number of elements of subsets
ulong igc_bits_;
ulong bits_;
ulong igc_last_;
ulong igc_first_;
Trang 11void sync_x() // aux
// Sync bits into array and
// set sw1_ and sw2_
{
ulong tbits = gray_code( igc_bits_ );
ulong sw = bits_ ^ tbits;
Trang 1210.5 Combinations in alternative minimal-change order
There is more than one minimal-change order Consider the sequence of bitsets generated in section 7.12:alternative orderings that have the minimal-change property are e.g described by 1) the sequence witheach word reversed or, more general 2) every permutation of the bits 3) the sequence with its bits negated4) cyclical rotations of (1) (3)
Here we use the negated and bit-reversed sequence for
³
n−k n
´:
Trang 13The interesting feature is that the last combination is identical to the first shifted left by one This makes
it easy to generate the subsets of a set with n elements in monotonic minchange order by concatenating the sequences for k = 1, 2, , n.
The usage of the utility class [FXT: class comb alt minchange in comb/combaltminchange.h] is tical to that of the ”standard” minchage-order
iden-The above listing can be produced via
10.6 Subsets in lexicographic order
The (nonempty) subsets of a set of five elements enumerated in lexicographic order are:
Clearly there are 2n subsets (including the empty set) of an n-element set.
The corresponding utility class is not too complicated
class subset_lex
{
protected:
ulong *x; // subset data
ulong n; // number of elements in set
Trang 14ulong k; // index of last element in subset
// number of elements in subset == k+1
// Generate next subset
// Return number of elements in subset
// Return zero if current == last
{
if ( x[k] == n-1 ) // last element is max ?
{
if ( 0==k ) { return 0; } // note: user has to call first() again
k; // remove last element
x[k]++; // increase last element
// Generate previous subset
// Return number of elements in subset
// Return zero if current == first
{
if ( k == 0 ) // only one lement ?
{
if ( x[0]==0 ) { return 0; } // note: user has to call last() again
x[0] ; // decr first element
[FXT: class subset lex in comb/subsetlex.h]
One can generate the list at the beginning of this sections by a code fragment like:
Trang 15cout << " #=" << setw(2) << num << ": ";
print_set_as_bitset(" ", sl.data(), num, n);
print_set(" ", sl.data(), num);
cout << endl;
}
while ( (num = sl.next()) );
cf [FXT: file demo/subsetlex-demo.cc]
10.7 Subsets in minimal-change order
The subsets of a set with 5 elements in minimal-change order:
Generation is easy, for a set with n elements go through the binary gray codes of the numbers from 1 to
2n−1 and sync the bits into the array to be used:
class subset_minchange
{
protected:
ulong *x; // current subset as delta-set
ulong n; // number of elements in set
ulong num; // number of elements in current subset
ulong chg; // element that was chnged with latest call to next()
ulong idx;
ulong maxidx;
Trang 16const ulong * data() const { return x; }
ulong get_change() const { return chg; }
const ulong current() const { return idx; }
const ulong *x = sm.data();
ulong num, idx = 0;
do
{
num = sm.next(); // omit empty set
++idx;
cout << setw(2) << idx << ": ";
// print as bit set:
for (ulong k=0; k<n; ++k) cout << (x[k]?’1’:’.’);
Trang 1710.8 Subsets ordered by number of elements
Sometimes it is useful to generate all subsets ordered with respect to the number of elements, that isstarting with the 1-element subsets, continuing with 2-element subsets and so on until the full set is
reached For that purpose one needs to generate the combinations of 1 form n, 2 from n and so on.
There are of course many orderings of that type, practical choices are limited by the various generatorsfor combinations one wants to use Here we use the colex-order for the combinations:
const ulong *x = so.data();
ulong num, idx = 0;
do
{
num = so.next();
++idx;
cout << setw(2) << idx << ": ";
// print as bit set:
for (ulong k=0; k<n; ++k) cout << (x[k]?’1’:’.’);
Trang 1810.9 Subsets ordered with shift register sequences
A curious sequence of all subsets of a given set can be generated using a binary de Bruijn (or shift register) sequence, that is a cyclical sequence of zeros and ones that contains each n-bit word once In the following example (where n = 5) the empty places of the subsets are included to make the nice
by shifting it to the right and inserting the current element from the SRS
The utility class [FXT: class subset debruijn in comb/subsetdebruijn.h] uses [FXT: class debruijn
in comb/debruijn.h] (which in turn uses [FXT: class prime string in comb/primestring.h]).The list above was created via
Trang 19The utility class is
ulong i_; // level in iterative search
long *pv_; // values into which to partition
ulong *pc_; // multipliers for values
ulong pci_; // temporary for pc_[i_]
long *r_; // rest
long ri_; // temporary for r_[i_]
long x_; // value to partition
void init(ulong x); // reset state
ulong next(); // generate next partition
ulong next_func(ulong i); // aux
ulong count(ulong x); // count number of partitions
ulong count_func(ulong i); // aux
void dump() const;
int check(ulong i=0) const;
};
[FXT: class partition in comb/partition.h]
The algorithm to count the partitions is to assign to the first bucket a multiple c0· p0 ≤ x of the first set element p0 If c0· p0 = x we already found a partition, else if c0· p0 < x solve the problem for
Trang 21if ( 0==r_[i] ) // valid partition found
The routines can easily adapted to the generation of partitions satisfying certain restrictions, e.g
parti-tions into unequal parts (i.e c i ≤ 1).
Cf [FXT: file demo/partition-demo.cc]