View Javadoc

1   /*
2    * Copyright 2006 - 2012 Christina Bohk and Roland Ewald
3    *  
4    * Licensed under the Apache License, Version 2.0 (the "License"); 
5    * you may not use this file except in compliance with the License. 
6    * You may obtain a copy of the License at 
7    *  
8    *  http://www.apache.org/licenses/LICENSE-2.0
9    *  
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
13   * See the License for the specific language governing permissions and 
14   * limitations under the License. 
15   */
16  package p3j.misc.math;
17  
18  import james.core.math.random.generators.IRandom;
19  
20  import java.util.Collection;
21  import java.util.List;
22  
23  import p3j.gui.P3J;
24  import p3j.misc.Misc;
25  import p3j.misc.errors.GeneratorError;
26  import p3j.misc.errors.ProbabilityError;
27  import p3j.misc.gui.GUI;
28  import p3j.pppm.IStochasticOccurrence;
29  
30  /**
31   * Class to hold static functions for checking random numbers regarding their
32   * mathematical validity, and some non-static functions for selecting an object
33   * randomly. Singleton pattern.
34   * 
35   * Created on January 21, 2007
36   * 
37   * @author Christina Bohk
38   * @author Roland Ewald
39   * 
40   */
41  public final class RandomNumberChecks {
42  
43  	/** Reference to singleton. */
44  	private static RandomNumberChecks instance = new RandomNumberChecks();
45  
46  	/** Standard text for error messages. */
47  	static final String PROB_SUM = "Probability sum of ";
48  
49  	/**
50  	 * Default constructor.
51  	 */
52  	private RandomNumberChecks() {
53  	}
54  
55  	/**
56  	 * Gets the single instance of RandomNumberChecks.
57  	 * 
58  	 * @return single instance of RandomNumberChecks
59  	 */
60  	public static RandomNumberChecks getInstance() {
61  		return instance;
62  	}
63  
64  	/**
65  	 * Tries to repeat values before throwing an exceptions. All values get
66  	 * normalised (also all 0's: this will be changed to a uniform distribution).
67  	 * 
68  	 * @param <V>
69  	 *          type of entity that shall be chosen by chance
70  	 * @param name
71  	 *          name of the objects to be checked (for generation of a suitable
72  	 *          error messages)
73  	 * @param objects
74  	 *          the collection of objects to be checked
75  	 * @param errors
76  	 *          list of error messages (to be filled if something goes wrong)
77  	 */
78  	public <V extends IStochasticOccurrence> void checkProbabilitySetting(
79  	    String name, Collection<V> objects, List<GeneratorError> errors) {
80  
81  		if (objects == null || objects.size() == 0) {
82  			GUI.printErrorMessage(P3J.getInstance(), "Missing parameter assignment",
83  			    "No assumptions are defined for parameter: " + name);
84  			throw new IllegalArgumentException(
85  			    "There are no assignments for variable '" + name + "'!");
86  		}
87  
88  		final Double probSum = getProbSum(objects);
89  
90  		// Either assign uniform probabilities...
91  		if (Misc.numEqual(probSum, 0)) {
92  			final double uniformProb = 1.0 / objects.size();
93  			for (V object : objects) {
94  				object.setProbability(uniformProb);
95  			}
96  			errors.add(new ProbabilityError(true, PROB_SUM + name
97  			    + " is zero. Probabilities have been distributed equally."));
98  		}
99  		// or normalise everything
100 		else if (!Misc.numEqual(probSum, 1.0)) {
101 			final double probFactor = 1 / probSum;
102 			for (V object : objects) {
103 				object.setProbability(object.getProbability() * probFactor);
104 			}
105 			errors
106 			    .add(new ProbabilityError(
107 			        true,
108 			        PROB_SUM
109 			            + name
110 			            + " does not equal 100%. Probabilities have been normalized accordingly."));
111 		}
112 
113 	}
114 
115 	/**
116 	 * Choose random object if the sum of all probabilities is 100.
117 	 * 
118 	 * @param <V>
119 	 *          type of randomly chosen entity
120 	 * @param objects
121 	 *          collection of objects from which to choose
122 	 * @param rand
123 	 *          randomiser to be used
124 	 * @return randomly chosen object
125 	 */
126 	public <V extends IStochasticOccurrence> V chooseNormalizedRandomObject(
127 	    Collection<V> objects, IRandom rand) {
128 		return chooseRandomObject(objects, rand, getProbSum(objects));
129 	}
130 
131 	/**
132 	 * Choose random object if the sum of all probabilities is 100.
133 	 * 
134 	 * @param <V>
135 	 *          type of randomly chosen entity
136 	 * @param objects
137 	 *          collection of objects from which to choose
138 	 * @param rand
139 	 *          the randomiser to be used
140 	 * @return randomly chosen object
141 	 */
142 	public <V extends IStochasticOccurrence> V chooseRandomObject(
143 	    Collection<V> objects, IRandom rand) {
144 		return chooseRandomObject(objects, rand, getProbSum(objects));
145 	}
146 
147 	/**
148 	 * Choose random entity based on a certain probability sum.
149 	 * 
150 	 * @param <V>
151 	 *          type of randomly chosen entity
152 	 * @param objects
153 	 *          collection of objects from which to choose
154 	 * @param rand
155 	 *          the randomiser to be used
156 	 * @param overallProbSum
157 	 *          overall probability sum
158 	 * @return randomly chosen object
159 	 */
160 	protected <V extends IStochasticOccurrence> V chooseRandomObject(
161 	    Collection<V> objects, IRandom rand, double overallProbSum) {
162 		double prob = rand.nextDouble();
163 		double currentProbSum = 0;
164 		for (V object : objects) {
165 			currentProbSum += object.getProbability() / overallProbSum;
166 			if (prob < currentProbSum) {
167 				return object;
168 			}
169 		}
170 		return null;
171 	}
172 
173 	/**
174 	 * Get the probability sum from a list of of {@link IStochasticOccurrence}
175 	 * instances.
176 	 * 
177 	 * @param objects
178 	 *          collection of objects from which to choose
179 	 * @return sum of the occurrence probabilities of all objects in the list
180 	 */
181 	public double getProbSum(Collection<? extends IStochasticOccurrence> objects) {
182 		double probSum = 0;
183 		for (IStochasticOccurrence object : objects) {
184 			probSum += object.getProbability();
185 		}
186 		return probSum;
187 	}
188 
189 }