001/*-
002 *******************************************************************************
003 * Copyright (c) 2011, 2016 Diamond Light Source Ltd.
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the Eclipse Public License v1.0
006 * which accompanies this distribution, and is available at
007 * http://www.eclipse.org/legal/epl-v10.html
008 *
009 * Contributors:
010 *    Peter Chang - initial API and implementation and/or initial documentation
011 *******************************************************************************/
012
013package org.eclipse.january.dataset;
014
015
016import java.io.IOException;
017
018import org.apache.commons.math3.random.MersenneTwister;
019import org.apache.commons.math3.random.RandomDataGenerator;
020import org.apache.commons.math3.random.RandomGenerator;
021import org.eclipse.january.IMonitor;
022import org.eclipse.january.io.ILazyLoader;
023
024/**
025 * Class to hold methods to create random datasets
026 * 
027 * Emulates numpy.random
028 */
029public class Random {
030        private final static RandomGenerator generator = new MersenneTwister();
031        private final static RandomDataGenerator prng = new RandomDataGenerator(generator);
032
033        /**
034         * @param seed value for generator
035         */
036        public static void seed(final int seed) {
037                generator.setSeed(seed);
038        }
039
040        /**
041         * @param seed values for generator
042         */
043        public static void seed(final int[] seed) {
044                generator.setSeed(seed);
045        }
046
047        /**
048         * @param seed value for generator
049         */
050        public static void seed(final long seed) {
051                generator.setSeed(seed);
052        }
053
054        /**
055         * @param shape output shape
056         * @return an array of values sampled from a uniform distribution between 0 (inclusive) and 1 (exclusive) 
057         */
058        public static DoubleDataset rand(final int... shape) {
059                DoubleDataset data = DatasetFactory.zeros(DoubleDataset.class, shape);
060                double[] buf = data.getData();
061
062                for (int i = 0; i < buf.length; i++) {
063                        buf[i] = generator.nextDouble();
064                }
065
066                return data;
067        }
068
069        /**
070         * @param low lower exclusive bound
071         * @param high upper exclusive bound
072         * @param shape output shape
073         * @return an array of values sampled from a uniform distribution between low and high (both exclusive) 
074         */
075        public static DoubleDataset rand(double low, double high, final int... shape) {
076                DoubleDataset data = DatasetFactory.zeros(DoubleDataset.class, shape);
077                double[] buf = data.getData();
078
079                for (int i = 0; i < buf.length; i++) {
080                        buf[i] = prng.nextUniform(low, high);
081                }
082
083                return data;
084        }
085
086        /**
087         * @param shape output shape
088         * @return an array of values sampled from a Gaussian distribution with mean 0 and variance 1 
089         * 
090         * (The term Gaussian here is a description of a shape of data taken from the mathematician of the
091         * same name Carl Friedrich Gauss  http://en.wikipedia.org/wiki/Carl_Friedrich_Gauss born in 1777.)
092         */
093        public static DoubleDataset randn(final int... shape) {
094                DoubleDataset data = DatasetFactory.zeros(DoubleDataset.class, shape);
095                double[] buf = data.getData();
096
097                for (int i = 0; i < buf.length; i++) {
098                        buf[i] = generator.nextGaussian();
099                }
100
101                return data;
102        }
103
104        /**
105         * @param mean mean of distribution
106         * @param std standard deviation
107         * @param shape output shape
108         * @return an array of values sampled from a Gaussian distribution with given mean and standard deviation 
109         */
110        public static DoubleDataset randn(double mean, double std, final int... shape) {
111                DoubleDataset data = DatasetFactory.zeros(DoubleDataset.class, shape);
112                double[] buf = data.getData();
113
114                for (int i = 0; i < buf.length; i++) {
115                        buf[i] = prng.nextGaussian(mean, std);
116                }
117
118                return data;
119        }
120
121        /**
122         * @param low lower inclusive bound
123         * @param high upper exclusive bound
124         * @param shape output shape
125         * @return an array of values sampled from a discrete uniform distribution in range [low, high)
126         */
127        public static IntegerDataset randint(final int low, final int high, final int[] shape) {
128                return random_integers(low, high-1, shape);
129        }
130
131        /**
132         * @param low lower inclusive bound
133         * @param high upper inclusive bound
134         * @param shape output shape
135         * @return an array of values sampled from a discrete uniform distribution in range [low, high]
136         */
137        public static IntegerDataset random_integers(final int low, final int high, final int[] shape) {
138                IntegerDataset data = DatasetFactory.zeros(IntegerDataset.class, shape);
139                int[] buf = data.getData();
140
141                if (low == high) {
142                        for (int i = 0; i < buf.length; i++) {
143                                buf[i] = low;
144                        }                       
145                } else {
146                        for (int i = 0; i < buf.length; i++) {
147                                buf[i] = prng.nextInt(low, high);
148                        }
149                }
150
151                return data;
152        }
153
154        /**
155         * @param beta mean
156         * @param shape output shape
157         * @return an array of values sampled from an exponential distribution with mean beta
158         */
159        public static DoubleDataset exponential(final double beta, final int... shape) {
160                DoubleDataset data = DatasetFactory.zeros(DoubleDataset.class, shape);
161                double[] buf = data.getData();
162
163                for (int i = 0; i < buf.length; i++) {
164                        buf[i] = prng.nextExponential(beta);
165                }
166
167                return data;
168        }
169
170        /**
171         * @param lam Poisson parameter
172         * @param shape output shape
173         * @return an array of values sampled from an exponential distribution with mean lambda
174         */
175        public static IntegerDataset poisson(final double lam, final int... shape) {
176                IntegerDataset data = DatasetFactory.zeros(IntegerDataset.class, shape);
177                int[] buf = data.getData();
178
179                for (int i = 0; i < buf.length; i++) {
180                        buf[i] = (int) prng.nextPoisson(lam);
181                }
182
183                return data;
184        }
185
186        /**
187         * @param shape output shape
188         * @return a lazy dataset with uniformly distributed random numbers
189         */
190        public static ILazyDataset lazyRand(int... shape) {
191                return lazyRand("random", DoubleDataset.class, shape);
192        }
193
194        /**
195         * @param name dataset name
196         * @param shape output shape
197         * @return a lazy dataset with uniformly distributed random numbers
198         */
199        public static ILazyDataset lazyRand(String name, int... shape) {
200                return lazyRand(name, DoubleDataset.class, shape);
201        }
202
203        /**
204         * @param dtype dataset type
205         * @param name dataset name
206         * @param shape output shape
207         * @return a lazy dataset with uniformly distributed random numbers
208         * @deprecated Use {@link #lazyRand(String, Class, int...)}
209         */
210        @Deprecated
211        public static ILazyDataset lazyRand(int dtype, String name, int... shape) {
212                return lazyRand(name, DTypeUtils.getInterface(dtype), shape);
213        }
214
215        /**
216         * @param name dataset name
217         * @param clazz dataset sub-interface
218         * @param shape output shape
219         * @return a lazy dataset with uniformly distributed random numbers
220         * @since 2.3
221         */
222        public static ILazyDataset lazyRand(String name, final Class<? extends Dataset> clazz, int... shape) {
223                
224                return new LazyDataset(new ILazyLoader() {
225                        private static final long serialVersionUID = ILazyLoader.serialVersionUID;
226
227                        @Override
228                        public boolean isFileReadable() {
229                                return true;
230                        }
231
232                        @Override
233                        public IDataset getDataset(IMonitor mon, SliceND slice) throws IOException {
234                                return rand(slice.getShape()).cast(clazz);
235                        }
236                },
237                name, clazz, shape);
238        }
239}