IndexStream.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-2.0.2).
003  * Copyright (c) 2007-2014 Franz Wilhelmstötter
004  *
005  * Licensed under the Apache License, Version 2.0 (the "License");
006  * you may not use this file except in compliance with the License.
007  * You may obtain a copy of the License at
008  *
009  *      http://www.apache.org/licenses/LICENSE-2.0
010  *
011  * Unless required by applicable law or agreed to in writing, software
012  * distributed under the License is distributed on an "AS IS" BASIS,
013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014  * See the License for the specific language governing permissions and
015  * limitations under the License.
016  *
017  * Author:
018  *    Franz Wilhelmstötter (franz.wilhelmstoetter@gmx.at)
019  */
020 package org.jenetics.util;
021 
022 import static java.lang.String.format;
023 import static java.util.Objects.requireNonNull;
024 
025 import java.util.Random;
026 
027 import org.jenetics.internal.math.probability;
028 
029 /**
030  * Interface which delivers a stream of (positive) indexes ({@code int}s)s. The
031  * stream ends if {@link #next()} returns {@code -1}. Here some usage examples:
032  *
033  * [code]
034  * final IndexStream stream = ...;
035  * for (int index = stream.next(); index != -1; index = stream.next()) {
036  *     System.out.println(index);
037  * }
038  * [/code]
039  * [code]
040  * final IndexStream stream = ...;
041  * int index = 0;
042  * while ((index = stream.next()) != -1) {
043  *     System.out.println(index);
044  * }
045  * [/code]
046  *
047  @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
048  @since 1.0
049  @version 2.0 &mdash; <em>$Date: 2014-03-31 $</em>
050  */
051 public abstract class IndexStream {
052 
053     protected IndexStream() {
054     }
055 
056     /**
057      * Return the next (positive inclusive zero) index, or -1 if the stream has
058      * reached its end.
059      *
060      @return the next index, or -1 if the stream has reached its end.
061      */
062     public abstract int next();
063 
064     /**
065      * Applies a {@code function} to all elements of this stream.
066      *
067      @param function the function to apply to the elements.
068      @throws NullPointerException if the given {@code function} is
069      *         {@code null}.
070      */
071     <R> void forEach(final Function<? super Integer, ? extends R> function) {
072         requireNonNull(function, "Function");
073         for (int i = next(); i != -1; i = next()) {
074             function.apply(i);
075         }
076     }
077 
078     /**
079      * Create a new random IndexIterator.
080      @param n the maximal value (exclusively) the created index stream will
081      *         return.
082      @param probability the index selection probability.
083      @return a new {@code IndexStream} with the given parameter
084      @throws IllegalArgumentException if {@code n == Integer.MAX_VALUE} or
085      *         {@code n <= 0} or the given {@code probability} is not valid.
086      */
087     public static IndexStream Random(final int n, final double probability) {
088         return Random(n, probability, RandomRegistry.getRandom());
089     }
090 
091     /**
092      * Create a new random IndexIterator. The elements returned by this stream
093      * are strictly increasing.
094      *
095      @param n the maximal value (exclusively) the created index stream will
096      *        return.
097      @param p the index selection probability.
098      @param random the random engine used for creating the random indexes.
099      @return a new {@code IndexStream} with the given parameter
100      @throws IllegalArgumentException if {@code n == Integer.MAX_VALUE} or
101      *         {@code n <= 0} or the given {@code probability} is not valid.
102      @throws NullPointerException if the given {@code random} engine is
103      *         {@code null}.
104      */
105     public static IndexStream Random(
106         final int n,
107         final double p,
108         final Random random
109     ) {
110         if (n == Integer.MAX_VALUE) {
111             throw new IllegalArgumentException(format(
112                 "n must be smaller than Integer.MAX_VALUE."
113             ));
114         }
115         if (n <= 0) {
116             throw new IllegalArgumentException(format(
117                 "n must be greater than zero: %d", n
118             ));
119         }
120 
121         IndexStream stream = new RandomIndexStream(n, p, random);
122         if (Double.compare(p, 0.0== 0) {
123             stream = new RandomIndexStreamP0();
124         else if (Double.compare(p, 1.0== 0) {
125             stream = new RandomIndexStreamP1(n);
126         }
127         return stream;
128     }
129 
130 }
131 
132 /**
133  @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
134  @since 1.4
135  @version 1.5 &mdash; <em>$Date: 2014-03-31 $</em>
136  */
137 final class RandomIndexStream extends IndexStream {
138     private final int _n;
139     private final int _p;
140     private final Random _random;
141 
142     private int _pos = -1;
143 
144     RandomIndexStream(final int n, final double p, final Random random) {
145         _n = n;
146         _p = probability.toInt(p);
147         _random = requireNonNull(random, "Random object must not be null.");
148     }
149 
150     @Override
151     public final int next() {
152         while (_pos < _n && _random.nextInt() >= _p) {
153             ++_pos;
154         }
155         ++_pos;
156 
157         return _pos < _n ? _pos : -1;
158     }
159 }
160 
161 /**
162  @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
163  @since 1.5
164  @version 1.5 &mdash; <em>$Date: 2014-03-31 $</em>
165  */
166 final class RandomIndexStreamP0 extends IndexStream {
167     @Override public int next() {
168         return -1;
169     }
170 }
171 
172 /**
173  @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
174  @since 1.5
175  @version 1.5 &mdash; <em>$Date: 2014-03-31 $</em>
176  */
177 final class RandomIndexStreamP1 extends IndexStream {
178     private final int _n;
179     private int _pos = -1;
180 
181     RandomIndexStreamP1(final int n) {
182         _n = n;
183     }
184 
185     @Override public int next() {
186         ++_pos;
187         return _pos < _n ? _pos : -1;
188     }
189 }