PartitionsIterator.java

  1. /*
  2.  * Licensed to the Hipparchus project under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The Hipparchus project licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      https://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.hipparchus.util;

  18. import java.lang.reflect.Array;
  19. import java.util.ArrayDeque;
  20. import java.util.ArrayList;
  21. import java.util.Iterator;
  22. import java.util.List;
  23. import java.util.NoSuchElementException;
  24. import java.util.Queue;

  25. /** Iterator for generating partitions.
  26.  * <p>
  27.  * This class implements the iterative algorithm described in
  28.  * <a href="https://academic.oup.com/comjnl/article/32/3/281/331557">Short Note:
  29.  * A Fast Iterative Algorithm for Generating Set Partitions</a>
  30.  * by B. Djokić, M. Miyakawa, S. Sekiguchi, I. Semba, and I. Stojmenović
  31.  * (The Computer Journal, Volume 32, Issue 3, 1989, Pages 281–282,
  32.  * <a href="https://doi.org/10.1093/comjnl/32.3.281">https://doi.org/10.1093/comjnl/32.3.281</a>
  33.  * </p>
  34.  * @param <T> type of the elements
  35.  * @since 2.2
  36.  */
  37. class PartitionsIterator<T> implements Iterator<List<T>[]> {

  38.     /** List to partition. */
  39.     private final List<T> list;

  40.     /** Number of elements to partition. */
  41.     private final int   n;

  42.     /** Mapping from elements indices to parts indices. */
  43.     private final int[] partIndex;

  44.     /** Backtracking array. */
  45.     private final int[] backTrack;

  46.     /** Current part index. */
  47.     private int   r;

  48.     /** Current backtrack index. */
  49.     private int   j;

  50.     /** Pending parts already generated. */
  51.     private final Queue<List<T>[]> pending;

  52.     /** Indicator for exhausted partitions. */
  53.     private boolean exhausted;

  54.     /** Simple constructor.
  55.      * @param list list to partition
  56.      */
  57.     PartitionsIterator(final List<T> list) {

  58.         this.list      = list;
  59.         this.n         = list.size();
  60.         this.partIndex = new int[list.size()];
  61.         this.backTrack = new int[list.size() - 1];
  62.         this.r         = 0;
  63.         this.j         = 0;
  64.         this.pending   = new ArrayDeque<>(n);

  65.         // generate a first set of partitions
  66.         generate();

  67.     }

  68.     /** Generate one set of partitions.
  69.      */
  70.     private void generate() {

  71.         // put elements in the first part
  72.         while (r < n - 2) {
  73.             partIndex[++r] = 0;
  74.             backTrack[++j] = r;
  75.         }

  76.         // generate partitions
  77.         for (int i = 0; i < n - j; ++i) {

  78.             // fill-up final element
  79.             partIndex[n - 1] = i;

  80.             // count the number of parts in this partition
  81.             int max = 0;
  82.             for (final int index : partIndex) {
  83.                 max = FastMath.max(max, index);
  84.             }

  85.             // prepare storage
  86.             @SuppressWarnings("unchecked")
  87.             final List<T>[] partition = (List<T>[]) Array.newInstance(List.class, max + 1);
  88.             for (int k = 0; k < partition.length; ++k) {
  89.                 partition[k] = new ArrayList<>(n);
  90.             }

  91.             // distribute elements in the parts
  92.             for (int k = 0; k < partIndex.length; ++k) {
  93.                 partition[partIndex[k]].add(list.get(k));
  94.             }

  95.             // add the generated partition to the pending queue
  96.             pending.add(partition);

  97.         }

  98.         // backtrack to generate next partition
  99.         r = backTrack[j];
  100.         partIndex[r]++;
  101.         if (partIndex[r] > r - j) {
  102.             --j;
  103.         }

  104.         // keep track of end of generation
  105.         exhausted = r == 0;

  106.     }

  107.     /** {@inheritDoc} */
  108.     @Override
  109.     public boolean hasNext() {
  110.         return !(exhausted && pending.isEmpty());
  111.     }

  112.     /** {@inheritDoc} */
  113.     @Override
  114.     public List<T>[] next() {

  115.         if (pending.isEmpty()) {
  116.             // we need to generate more partitions
  117.             if (exhausted) {
  118.                 throw new NoSuchElementException();
  119.             }
  120.             generate();
  121.         }

  122.         return pending.remove();

  123.     }

  124. }