source: xssim/trunk/src/simulator/RandomNumbers.java @ 104

Revision 104, 14.9 KB checked in by wojtekp, 13 years ago (diff)
  • Property svn:mime-type set to text/plain
Line 
1package simulator;
2
3import java.util.ArrayList;
4import java.util.HashMap;
5import java.util.Iterator;
6import java.util.List;
7import java.util.Map;
8import java.util.Set;
9
10import simulator.stats.random.MinMaxDistribution;
11import simulator.workload.generator.configuration.Dist;
12import simulator.workload.generator.configuration.PeriodicValidValues;
13import simulator.workload.generator.configuration.types.ParameterAttributesDistributionType;
14import cern.jet.random.AbstractDistribution;
15import cern.jet.random.Exponential;
16import cern.jet.random.Gamma;
17import cern.jet.random.Normal;
18import cern.jet.random.Poisson;
19import cern.jet.random.Uniform;
20import cern.jet.random.engine.MersenneTwister64;
21import cern.jet.random.engine.RandomEngine;
22import eduni.simjava.distributions.AbstractSpecificGenerator;
23import eduni.simjava.distributions.DetailDistGenerator;
24import eduni.simjava.distributions.GeneralGenerator;
25import eduni.simjava.distributions.PeriodicGenerator;
26
27/**
28 * A class that stores random number generator for given metrics. Its functionality is basically similar to a hash table
29 * where a key is a metric name and a value stored at that key is a previously set random number generator with proper distribution
30 * @author Stanislaw Szczepanowski
31 *
32 */
33public class RandomNumbers {
34
35        /**
36         * a hash table that stores the random number generators on the basis of the given key
37         * the key is the name of the parameter (metric name, String object), for which a random generator should be retrieved
38         */
39        protected Map<String, List<AbstractSpecificGenerator>> rndGenerators; 
40
41        /**
42         * holds mapping between node id and internal random numbers generator name.
43         */
44        protected HashMap<String, String> idMap;
45       
46        /**
47         * A field indicating, that if no seed is given to a value, this global seed is to be used.
48         * If this value is <code>null</code>, then a random number is to be picked (e.g. System.nanoTime()).
49         * Such functionality is used for example for test purposes.
50         */
51        protected static Long baseSeed;
52       
53        /**
54         * Default constructor
55         */
56        public RandomNumbers() {
57                rndGenerators = new HashMap<String, List<AbstractSpecificGenerator>>();
58                idMap = new HashMap<String, String>();
59                init();
60        }
61       
62        /**
63         * Constructor with initial capacity
64         * @param initialCapacity the initial capacity of this hash map
65         */
66        public RandomNumbers(int initialCapacity) {
67                rndGenerators = new HashMap<String, List<AbstractSpecificGenerator>>(initialCapacity);
68                idMap = new HashMap<String, String>(initialCapacity);
69                init();
70        }
71       
72        /** A common initialization method used in constructors */
73        protected void init() {
74        }
75       
76        /**
77         * Adds a random number generator at given key (name)
78         * @param parameterName the name of the generator
79         * @param generator the generator to be stored
80         */
81        public void addRandomGenerator(String parameterName, PeriodicGenerator generator) {
82                List<AbstractSpecificGenerator> list;
83               
84                if(rndGenerators.containsKey(parameterName)){
85                        list = rndGenerators.get(parameterName);
86                        list.add(generator);
87                } else {
88                        list = new ArrayList<AbstractSpecificGenerator>(1);
89                        list.add(generator);
90                        rndGenerators.put(parameterName, list);
91                }
92        }
93       
94        public void addRandomGenerator(String parameterName, DetailDistGenerator generator){
95                ArrayList <AbstractSpecificGenerator>list;
96                int idx = -1;
97                if(rndGenerators.containsKey(parameterName)){
98                        list = (ArrayList<AbstractSpecificGenerator>) rndGenerators.get(parameterName);
99                        list.ensureCapacity(list.size() + 1);
100
101                        // this should guarantee, that elements on the list are ordered.
102                        while(++idx < list.size() && generator.compareTo(list.get(idx)) > 0);
103                        list.add(idx, generator);
104                       
105                } else {
106                        list = new ArrayList<AbstractSpecificGenerator>(1);
107                        list.add(generator);
108                        rndGenerators.put(parameterName, list);
109                }
110        }
111       
112        public boolean addRandomGenerator(String parameterName, Dist detailDist){
113                Double percnt = Double.valueOf(detailDist.getContent());
114               
115                AbstractDistribution generator = createRandomGenerator(
116                                detailDist.getDistribution().getType(), detailDist.hasAvg(), detailDist.getAvg(),
117                                detailDist.getStdev(), detailDist.hasMin(), detailDist.getMin(),
118                                detailDist.hasMax(), detailDist.getMax(), detailDist.hasSeed(), detailDist.getSeed(), parameterName);
119               
120                if(generator == null)
121                        return false;
122               
123                DetailDistGenerator ddg = new DetailDistGenerator(generator, percnt);
124                addRandomGenerator(parameterName, ddg);
125               
126                return true;
127        }
128       
129        public boolean addRandomGenerator(String parameterName,  PeriodicValidValues values){
130                AbstractDistribution generator = createRandomGenerator(
131                                        values.getDistribution().getType(), values.hasAvg(), values.getAvg(),
132                                        values.getStdev(), values.hasMin(), values.getMin(),
133                                        values.hasMax(), values.getMax(), values.hasSeed(), values.getSeed(), parameterName);
134               
135                if(generator == null)
136                        return false;
137               
138                PeriodicGenerator pg = new PeriodicGenerator(generator, values.getBeginValidTime(), values.getEndValidTime());
139                addRandomGenerator(parameterName, pg);
140               
141                return true;
142        }
143
144       
145        /**
146         * Creates and stores a random numbers generator
147         * @param distribution the distribution of this generator descried as in {@link ParameterAttributesDistributionType}
148         * @param avg the average value
149         * @param stdev the standard deviation value
150         * @param min minimal value
151         * @param max maximal value
152         * @param useSeed true, if the given seed is to be used
153         * @param seed the seed for random number generator
154         * @param name the name of the random numbers generator
155         */
156        public boolean addRandomGenerator(int distribution, boolean useAvg, double avg, double stdev, boolean useMin, double min, boolean useMax, double max, boolean useSeed, long seed, String name) {
157                AbstractDistribution generator = createRandomGenerator(distribution, useAvg, avg, stdev, useMin, min, useMax, max, useSeed, seed, name);
158                if(generator == null)
159                        return false;
160               
161                GeneralGenerator gg = new GeneralGenerator(generator);
162                List<AbstractSpecificGenerator> list;
163               
164                if(rndGenerators.containsKey(name)){
165                        list = rndGenerators.get(name);
166                        list.add(gg);
167                } else {
168                        list = new ArrayList<AbstractSpecificGenerator>(1);
169                        list.add(gg);
170                        rndGenerators.put(name, list);
171                }
172               
173                return true;
174        }
175       
176       
177       
178        /**
179         * Retrieves the next random value from the given random numbers generator.
180         * Generator is valid for whole simulation time.
181         * @param parameterName the random numbers generator name
182         * @return the next random value (according to the setting of the random numbers generator)
183         * @throws IllegalAccessException
184         */
185        public double getRandomValue(String parameterName) throws IllegalAccessException{
186                List<AbstractSpecificGenerator> list = rndGenerators.get(parameterName);
187                AbstractSpecificGenerator asg;
188                AbstractDistribution generator = null;
189                double ret;
190               
191                if(list == null || list.size() == 0){
192                        throw new IllegalAccessException("No random generator for given metric " + parameterName);
193                }
194               
195                // generator on index 0 should be valid for whole simulation period, if PeriodicGenerator is used or
196                // should cover 100% of tasks if DetailDistGenerator is used
197                asg = list.get(0);
198               
199                generator = asg.getGenerator();
200               
201                ret = generator.nextDouble();
202                asg.setLastGeneratedValue(ret);
203               
204                return ret;
205        }
206       
207        public double getLastGeneratedRandomValue(String parameterName) throws IllegalAccessException{
208                List<AbstractSpecificGenerator> list = rndGenerators.get(parameterName);
209                AbstractSpecificGenerator asg = list.get(0);
210                return asg.getLastGeneratedValue();
211        }
212       
213       
214        /**
215         * Retrieves the next random value from the given random numbers generator.
216         * Generator is valid only for some period of simulation time.
217         * @param parameterName the random numbers generator name
218         * @param time current simulation time
219         * @return the next random value (according to the setting of the random numbers generator)
220         * @throws IllegalAccessException
221         */
222        public double getRandomValue(String parameterName, long time) throws IllegalAccessException {
223                List<AbstractSpecificGenerator> list = rndGenerators.get(parameterName);
224                AbstractSpecificGenerator asg = null;
225                PeriodicGenerator pGen = null;
226                AbstractDistribution generator = null;
227                double ret;
228               
229                if(list == null || list.size() == 0) {
230                        throw new IllegalAccessException("No random generator for given metric " + parameterName);
231                }
232               
233                for(int i = 1; i < list.size(); i++){
234                        asg = list.get(i);
235                        if(asg instanceof PeriodicGenerator)
236                                pGen = (PeriodicGenerator) asg;
237                        else
238                                throw new RuntimeException("Wrong specific generator type. PeriodicGenerator was expected.");
239                       
240                        if(pGen.isValid(time)){
241                                generator = pGen.getGenerator();
242                                break;
243                        }
244                }
245               
246                // generator on index = 0 should be valid for whole simulation period
247                if(generator == null) {
248                        pGen = (PeriodicGenerator)list.get(0);
249                        if(pGen.isValid(time)){
250                                generator = pGen.getGenerator();
251                        }
252                }
253               
254                if(generator == null)
255                        throw new IllegalAccessException("No valid "+parameterName+" generator for given time " + time);
256                ret = generator.nextDouble();
257               
258                return ret;
259        }
260       
261        /**
262         * Retrieves the next random value from the given random numbers generator.
263         * Generator is valid for specified percent of generated tasks.
264         * @param parameterName
265         * @param prcnt
266         * @return
267         * @throws IllegalAccessError
268         */
269        public double getRandomValue(String parameterName, double prcnt) throws IllegalAccessError {
270                int idx = 0;
271                double prcntSum = 0.0;
272                DetailDistGenerator ddg = null;
273               
274                if(!rndGenerators.containsKey(parameterName))
275                        throw new IllegalAccessError("No generators for "+parameterName+" available.");
276               
277                List <AbstractSpecificGenerator> list = rndGenerators.get(parameterName);
278
279                if(list.size() == 0)
280                        throw new IllegalAccessError("No generator for "+parameterName + " available.");
281               
282                if(list.get(0) instanceof DetailDistGenerator){
283                        /*
284                         * Looking for appropriate generator.
285                         * List of elements is ordered from min to max. For loop is checking to which interval requested
286                         * percent belongs to.
287                         */
288                        for(idx = 0; idx < list.size(); idx++){
289                                ddg = (DetailDistGenerator)list.get(idx);
290                                prcntSum = prcntSum + ddg.getPrcnt();
291                                // this is to handle double numbers representation precision
292                                if((prcntSum - prcnt) > 0.000000001)
293                                        break;
294                        }
295                       
296                        if(idx >= list.size())
297                                throw new IllegalAccessError("Value "+prcnt +" doeas not belong to any interval defined by DetailDistGenerators");
298
299                        return ddg.getGenerator().nextDouble();
300
301                } else {
302                        throw new IllegalAccessError(list.get(0).getClass().getName() +
303                                        " generator can not be used for evaluating values for multidistribution element definition.\n" +
304                                        "Use " + DetailDistGenerator.class.getName() + " instead.");
305                }
306        }
307       
308        /**
309         * Retrieves a snapshot of all random numbers generators next random values
310         * @return a result hash map has structure of pairs as: &lt;String random_numbers_generator_name, Double random_value&gt;
311         */
312        public Map<String, Double> getMappedRandomValues() {
313                Map<String, Double> resultHashMap = new HashMap<String, Double>(rndGenerators.size());
314               
315                Set<String> keys = rndGenerators.keySet();
316                for (Iterator<String> i = keys.iterator(); i.hasNext(); ) {
317                        String name = i.next();
318                        Double value = null;
319                        try {
320                                value = new Double(getRandomValue(name));
321                        } catch (IllegalAccessException e) {
322                                e.printStackTrace();
323                        }
324                        resultHashMap.put(name, value);
325                }
326               
327                return resultHashMap;
328        }
329
330        /**
331         * Constructs a new random numbers generator.
332         *
333         * @param distribution the distribution of this generator descried as in {@link ParameterAttributesDistributionType}
334         * @param useAvg <code>true</code>, if the given average value is to be used; <code>false</code> otherwise
335         * @param avg the average value
336         * @param stdev the standard deviation value
337         * @param useMin <code>true</code>, if the given minimal value is to be used; <code>false</code> otherwise
338         * @param min minimal value
339         * @param useMax <code>true</code>, if the given maximal value is to be used; <code>false</code> otherwise
340         * @param max maximal value
341         * @param useSeed <code>true</code>, if the given seed is to be used; <code>false</code> otherwise
342         * @param seed the seed for random number generator
343         * @param name the name of the random numbers generator
344         * @return the constructed random numbers generator
345         */
346        public AbstractDistribution createRandomGenerator(int distribution, boolean useAvg, double avg, double stdev, boolean useMin, double min, boolean useMax, double max, boolean useSeed, long seed, String name) {
347                AbstractDistribution resultGenerator = null;
348               
349                if(useAvg == false && useMax == false && useMin == false)
350                        return null;
351               
352                int validSeed = -1;
353                if (isBaseSeedSet()) { //use the base seed (has the highest priority)
354                        validSeed = baseSeed.intValue();
355                } else if (useSeed) {
356                        validSeed = (int) seed;
357                } else { //don't use seed
358                        validSeed = (int) System.nanoTime();
359                }
360               
361                RandomEngine randomEngine = new MersenneTwister64(validSeed);
362               
363                switch (distribution) {
364                case ParameterAttributesDistributionType.CONSTANT_TYPE:
365                        //this will result in a generator of constant values equal to avg
366                        resultGenerator = new Normal(avg, 0.0, randomEngine);
367                        break;
368
369                case ParameterAttributesDistributionType.NORMAL_TYPE:
370                        resultGenerator = new Normal(avg, stdev, randomEngine);
371                        break;
372
373                case ParameterAttributesDistributionType.POISSON_TYPE:
374                        resultGenerator = new Poisson(avg, randomEngine);
375                        break;
376
377                case ParameterAttributesDistributionType.UNIFORM_TYPE:
378                        resultGenerator = new Uniform(min, max, randomEngine);
379                        break;
380                       
381                case ParameterAttributesDistributionType.EXPONENTIAL_TYPE:
382                        resultGenerator = new Exponential(avg, randomEngine);
383                        break;
384                       
385                case ParameterAttributesDistributionType.GAMMA_TYPE:
386                        resultGenerator = new Gamma(avg, stdev, randomEngine);
387                        break;
388
389                case ParameterAttributesDistributionType.HARMONIC_TYPE:
390                        resultGenerator = null; //TODO finish implementation
391                        break;
392                }
393                Double minValue = null;
394                Double maxValue = null;
395                boolean wrap = false; //indicates, whether the wrapper should be used
396                if (useMin) {
397                        minValue = min;
398                        wrap = true;
399                }
400                if (useMax) {
401                        maxValue = max;
402                        wrap = true;
403                }
404                if (wrap) //wrap the generator, only if necessary
405                        resultGenerator = new MinMaxDistribution(resultGenerator, minValue, maxValue);
406                return resultGenerator;
407        }
408       
409        public void addIdGeneratorNameMapping(String id, String generatorName){
410                idMap.put(id, generatorName);
411        }
412       
413        public boolean containsElement(String id){
414                return idMap.containsKey(id);
415        }
416       
417        public String getGeneratorName(String id){
418                return idMap.get(id);
419        }
420       
421        public List<AbstractSpecificGenerator> getGenList(String arg){
422                return rndGenerators.get(arg);
423        }
424       
425        /**
426         * Sets a new value of the base seed for this class. If a <code>null</code> value
427         * is given, then the base seed is disabled.
428         * @param baseSeed the new value of the base seed, or <code>null</code> if the base seed is to be disabled
429         */
430        public static void setBaseSeed(Long baseSeed) {
431                RandomNumbers.baseSeed = baseSeed;
432        }
433       
434        public static boolean isBaseSeedSet() {
435                return (baseSeed != null);
436        }
437       
438        public static long getBaseSeed() {
439                return baseSeed;
440        }
441       
442        public static void clearBaseSeed() {
443                baseSeed = null;
444        }
445}
Note: See TracBrowser for help on using the repository browser.