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 — <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 — <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 — <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 — <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 }
|