RosenNumberPartitionIterator.java

  1. /* Copyright 2011 Axel Kramer
  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.util.Iterator;
  19. import java.util.NoSuchElementException;

  20. import org.hipparchus.exception.LocalizedCoreFormats;
  21. import org.hipparchus.exception.MathIllegalArgumentException;

  22. /**
  23.  * An iterator that generates all partitions of <code>n</code> elements, into <code>k</code> parts
  24.  * containing the number of elements in each part, based on Rosen's algorithm.
  25.  * <p>
  26.  * This is a copy of the class (with slight edits) with the same name from the
  27.  * <a href="https://github.com/axkr/symja_android_library">Symja Library</a>.
  28.  * The original file was published under the terms of the GPLV3 license,
  29.  * but the Hipparchus project was <a
  30.  * href="https://github.com/Hipparchus-Math/hipparchus/issues/197#issuecomment-1193259547">explicitly allowed</a>
  31.  * to include it relicensed to Apache V2.
  32.  * </p>
  33.  * <p>
  34.  * See Kenneth H. Rosen, Discrete Mathematics and Its Applications, 2nd edition (NY: McGraw-Hill,
  35.  * 1991), pp. 284-286
  36.  * </p>
  37.  */
  38. public class RosenNumberPartitionIterator implements Iterator<int[]> {

  39.     /** Number of elements. */
  40.     private final int n;

  41.     /** Subset/sample size. */
  42.     private final int k;

  43.     /** Work array. */
  44.     private int[] a;

  45.     /** Count of unique combinations. */
  46.     private long count;

  47.     /** Simple constructor.
  48.      * @param n the number of elements
  49.      * @param k divided into k parts
  50.      */
  51.     public RosenNumberPartitionIterator(final int n, final int k) {

  52.         this.n = n - 1;
  53.         this.k = k - 1;
  54.         if (k > n || k < 1) {
  55.             throw new MathIllegalArgumentException(LocalizedCoreFormats.OUT_OF_RANGE_SIMPLE, k, 1, n);
  56.         }

  57.         reset();

  58.     }

  59.     /**
  60.      * {@inheritDoc}
  61.      *
  62.      * @see java.util.Iterator#hasNext()
  63.      */
  64.     @Override
  65.     public final boolean hasNext() {
  66.         return count > 0;
  67.     }

  68.     /**
  69.      * {@inheritDoc}
  70.      *
  71.      * @see java.util.Iterator#next()
  72.      */
  73.     @Override
  74.     public final int[] next() {

  75.         if (count == 0) {
  76.             throw new NoSuchElementException();
  77.         }

  78.         // rosenNext start
  79.         if (a == null) {
  80.             this.a = new int[k];
  81.             for (int i = 0; i < k; ++i) {
  82.                 this.a[i] = i;
  83.             }
  84.         } else {
  85.             int i = k - 1;
  86.             while (a[i] == n - k + i) {
  87.                 i--;
  88.             }
  89.             final int t = ++a[i] - i++;
  90.             int j = i;
  91.             while (j < k) {
  92.                 a[j] = t + j++;
  93.             }
  94.         }
  95.         --count;
  96.         // rosenNext end

  97.         final int kPlus1 = k + 1;
  98.         final int[] temp = new int[kPlus1];

  99.         for (int i = 0; i < kPlus1; i++) {
  100.             if (i == 0) {
  101.                 temp[i] = a[i] + 1;
  102.             } else {
  103.                 if (i == k) {
  104.                     temp[i] = n - a[i - 1];
  105.                 } else {
  106.                     temp[i] = a[i] - a[i - 1];
  107.                 }
  108.             }
  109.         }
  110.         return temp;
  111.     }

  112.     /** Reset this iterator to the start condition.
  113.      */
  114.     public void reset() {
  115.         count = 1;
  116.         for (int i = 0; i < k; ++i) {
  117.             count = count * (n - i) / (i + 1);
  118.         }
  119.         a = null;
  120.     }

  121. }