Program Listing for File set_partition.hpp

Return to documentation for file (ckpttncpp/set_partition.hpp)

#pragma once

#include <type_traits>

template <int N, int K>
constexpr auto Stirling2nd()
{
    if constexpr (K >= N || K <= 1)
    {
        return std::integral_constant<int, 1> {};
    }
    else
    {
        return std::integral_constant<int,
            Stirling2nd<N - 1, K - 1>() + K * Stirling2nd<N - 1, K>()> {};
    }
}

// Set Partition
//
// A set partition of the set [n] = {1,2,3,...,n} is a collection B0,
// B1, ... Bj of disjoint subsets of [n] whose union is [n]. Each Bj
// is called a block. Below we show the partitions of [4]. The periods
// separtate the individual sets so that, for example, 1.23.4 is the
// partition {{1},{2,3},{4}}.
//   1 block:  1234
//   2 blocks: 123.4   124.3   134.2   1.234   12.34   13.24   14.23
//   3 blocks: 1.2.34  1.24.3  14.2.3  13.2.4  12.3.4
//   4 blocks: 1.2.3.4
//
// Each partition above has its blocks listed in increasing order of
// smallest element; thus block 0 contains element 1, block1 contains
// the smallest element not in block 0, and so on. A Restricted Growth
// string (or RG string) is a sring a[1..n] where a[i] is the block in
// whcih element i occurs. Restricted Growth strings are often called
// restricted growth functions. Here are the RG strings corresponding
// to the partitions shown above.
//
//   1 block:  0000
//   2 blocks: 0001, 0010, 0100, 0111, 0011, 0101, 0110
//   3 blocks: 0122, 0121, 0112, 0120, 0102,
//
// ...more
//
// Reference:
// Frank Ruskey. Simple combinatorial Gray codes constructed by
// reversing sublists. Lecture Notes in Computer Science, #762,
// 201-208. Also downloadable from
// http://webhome.cs.uvic.ca/~ruskey/Publications/SimpleGray/SimpleGray.html
//
#include <boost/coroutine2/all.hpp>
#include <cassert>
#include <cctype>
#include <cstdio>
#include <functional>
#include <utility>

class set_partition_
{
    using ret_t = std::tuple<int, int>;
    using Fun = std::function<void(ret_t)>;

  private:
    // int b[100 + 1]; /* maximum value of n */
    // int cnt{};
    Fun yield;

  public:
    explicit set_partition_(Fun yield_)
        : yield(std::move(yield_))
    {
    }

    void run(int n, int k)
    {
        if (k % 2 == 0)
        {
            this->_GEN0_even(n, k);
        }
        else
        {
            this->_GEN0_odd(n, k);
        }
    }

  private:
    void _Move(int x, int y)
    {
        yield(std::tuple {x, y});
    }

    void _GEN0_even(int n, int k);

    void _NEG0_even(int n, int k);

    void _GEN1_even(int n, int k);

    void _NEG1_even(int n, int k);

    void _GEN0_odd(int n, int k);

    void _NEG0_odd(int n, int k);

    void _GEN1_odd(int n, int k);

    void _NEG1_odd(int n, int k);
};

using ret_t = std::tuple<int, int>;
using coro_t = boost::coroutines2::coroutine<ret_t>;

extern coro_t::pull_type set_partition(int n, int k);