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
035         */
036        public static void seed(final int seed) {
037                generator.setSeed(seed);
038        }
039
040        /**
041         * @param seed
042         */
043        public static void seed(final int[] seed) {
044                generator.setSeed(seed);
045        }
046
047        /**
048         * @param seed
049         */
050        public static void seed(final long seed) {
051                generator.setSeed(seed);
052        }
053
054        /**
055         * @param 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
071         * @param high
072         * @param 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
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
106         * @param std standard deviation
107         * @param 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 
123         * @param high
124         * @param 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 
133         * @param high 
134         * @param 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 
156         * @param 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 
172         * @param 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
188         * @return a lazy dataset with uniformly distributed random numbers
189         */
190        public static ILazyDataset lazyRand(int... shape) {
191                return lazyRand(Dataset.FLOAT64, "random", shape);
192        }
193
194        /**
195         * @param name
196         * @param shape
197         * @return a lazy dataset with uniformly distributed random numbers
198         */
199        public static ILazyDataset lazyRand(String name, int... shape) {
200                return lazyRand(Dataset.FLOAT64, name, shape);
201        }
202
203        /**
204         * @param dtype
205         * @param name
206         * @param shape
207         * @return a lazy dataset with uniformly distributed random numbers
208         */
209        public static ILazyDataset lazyRand(int dtype, String name, int... shape) {
210                
211                return new LazyDataset(name, dtype, shape, new ILazyLoader() {
212                        private static final long serialVersionUID = ILazyLoader.serialVersionUID;
213
214                        @Override
215                        public boolean isFileReadable() {
216                                return true;
217                        }
218
219                        @Override
220                        public IDataset getDataset(IMonitor mon, SliceND slice) throws IOException {
221                                return rand(slice.getShape());
222                        }
223                });
224        }
225}