001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  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 */
017package org.apache.commons.math4.random;
018
019import java.io.Serializable;
020import java.io.IOException;
021import java.io.ObjectOutputStream;
022import java.io.ObjectInputStream;
023import org.apache.commons.math4.util.FastMath;
024import org.apache.commons.rng.RestorableUniformRandomProvider;
025import org.apache.commons.rng.simple.RandomSource;
026import org.apache.commons.rng.core.RandomProviderDefaultState;
027
028/**
029 * Adaptor that delegates to a
030 * {@link org.apache.commons.rng.UniformRandomProvider} instance.
031 * <p>
032 * It is provided for users who wish to test the new RNG implementations
033 * the <i>current</i> generators (up to version 3.6 of Commons Math) in
034 * codes that require the {@code RandomGenerator} interface.
035 * </p>
036 * <p>
037 * Applications should upgrade to use the new generators ASAP.
038 * If problems are found that jeopardize the upgrade, please report them
039 * on the project's
040 * <a href="https://issues.apache.org/jira/browse/MATH">
041 *  issue tracking system</a>.
042 * </p>
043 *
044 * <p>
045 * <b>Notes:</b>
046 * <ul>
047 *  <li>
048 *   The
049 *   {@link RandomGenerator#setSeed(int) setSeed(int)},
050 *   {@link RandomGenerator#setSeed(int[]) setSeed(int[])} and
051 *   {@link RandomGenerator#setSeed(long) setSeed(long)}
052 *   methods of the {@link RandomGenerator} are not part of the
053 *   {@link org.apache.commons.rng.UniformRandomProvider new API}.
054 *  </li>
055 *  <li>
056 *   The new RNG implementations are not {@code Serializable}.
057 *   Use {@link RestorableUniformRandomProvider#saveState()}
058 *   instead.
059 *  </li>
060 *  <li>
061 *   {@link RandomGenerator#nextGaussian() nextGaussian()} is not
062 *   part of the {@link org.apache.commons.rng.UniformRandomProvider
063 *   new API} as it defines a "post-processing" of the output of a
064 *   <i>uniform</i> RNG in order to follow a different distribution.
065 *  </li>
066 * </ul>
067 *
068 * @since 4.0
069 *
070 * @deprecated As of 4.0. This class is made available for testing
071 * the {@link RandomSource new RNG implementations} in existing
072 * applications.
073 * It will be removed in the next major release.
074 */
075@Deprecated
076public final class RngAdaptor
077    implements RandomGenerator,
078               Serializable {
079    /** Serializable version identifier. */
080    private static final long serialVersionUID = 12345L;
081    /** Source. */
082    private final RandomSource source;
083    /** Delegate. */
084    private transient RestorableUniformRandomProvider delegate;
085    /** Next gaussian. */
086    private double nextGaussian = Double.NaN;
087
088    /**
089     * Creates a new instance.
090     *
091     * @param source Source of randomness.
092     */
093    public RngAdaptor(RandomSource source) {
094        this(source, null);
095    }
096
097    /**
098     * Creates a new instance.
099     *
100     * @param source Source of randomness.
101     * @param seed Seed.  Can be {@code null}.
102     */
103    public RngAdaptor(RandomSource source,
104                      Object seed) {
105        this.source = source;
106        delegate = RandomSource.create(source, seed);
107    }
108
109    /** {@inheritDoc} */
110    @Override
111    public void setSeed(int seed) {
112        delegate = RandomSource.create(source, seed);
113        clear();
114    }
115
116    /** {@inheritDoc} */
117    @Override
118    public void setSeed(int[] seed) {
119        delegate = RandomSource.create(source, seed);
120        clear();
121    }
122
123    /** {@inheritDoc} */
124    @Override
125    public void setSeed(long seed) {
126        delegate = RandomSource.create(source, seed);
127        clear();
128    }
129
130    /** {@inheritDoc} */
131    @Override
132    public boolean nextBoolean() {
133        return delegate.nextBoolean();
134    }
135
136    /** {@inheritDoc} */
137    @Override
138    public void nextBytes(byte[] bytes) {
139        delegate.nextBytes(bytes);
140    }
141
142    /** {@inheritDoc} */
143    @Override
144    public double nextDouble() {
145        return delegate.nextDouble();
146    }
147
148    /** {@inheritDoc} */
149    @Override
150    public float nextFloat() {
151        return delegate.nextFloat();
152    }
153
154    /** {@inheritDoc} */
155    @Override
156    public double nextGaussian() {
157        final double random;
158        if (Double.isNaN(nextGaussian)) {
159            // generate a new pair of gaussian numbers
160            final double x = nextDouble();
161            final double y = nextDouble();
162            final double alpha = 2 * FastMath.PI * x;
163            final double r = FastMath.sqrt(-2 * FastMath.log(y));
164            random = r * FastMath.cos(alpha);
165            nextGaussian = r * FastMath.sin(alpha);
166        } else {
167            // use the second element of the pair already generated
168            random = nextGaussian;
169            nextGaussian = Double.NaN;
170        }
171
172        return random;
173    }
174
175    /** {@inheritDoc} */
176    @Override
177    public int nextInt() {
178        return delegate.nextInt();
179    }
180
181    /** {@inheritDoc} */
182    @Override
183    public int nextInt(int n) {
184        return delegate.nextInt(n);
185    }
186
187    /** {@inheritDoc} */
188    @Override
189    public long nextLong() {
190        return delegate.nextLong();
191    }
192
193    /**
194     * Clears the cache used by the default implementation of
195     * {@link #nextGaussian}.
196     */
197    private void clear() {
198        nextGaussian = Double.NaN;
199    }
200
201    /**
202     * @param out Output stream.
203     * @throws IOException if an error occurs.
204     */
205    private void writeObject(ObjectOutputStream out)
206        throws IOException {
207        // Write non-transient fields.
208        out.defaultWriteObject();
209
210        // Save current state.
211        out.writeObject(((RandomProviderDefaultState) delegate.saveState()).getState());
212   }
213
214    /**
215     * @param in Input stream.
216     * @throws IOException if an error occurs.
217     * @throws ClassNotFoundException if an error occurs.
218     */
219    private void readObject(ObjectInputStream in)
220        throws IOException,
221               ClassNotFoundException {
222        // Read non-transient fields.
223        in.defaultReadObject();
224
225        // Recreate the "delegate" from serialized info.
226        delegate = RandomSource.create(source);
227        // And restore its state.
228        final RandomProviderDefaultState state = new RandomProviderDefaultState((byte[]) in.readObject());
229        delegate.restoreState(state);
230    }
231}