Synthia
Generic and flexible data structure generator
Choice.java
Go to the documentation of this file.
1 /*
2  Synthia, a data structure generator
3  Copyright (C) 2019-2021 Laboratoire d'informatique formelle
4  Université du Québec à Chicoutimi, Canada
5 
6  This program is free software: you can redistribute it and/or modify
7  it under the terms of the GNU Lesser General Public License as published
8  by the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU Lesser General Public License for more details.
15 
16  You should have received a copy of the GNU Lesser General Public License
17  along with this program. If not, see <http://www.gnu.org/licenses/>.
18  */
19 package ca.uqac.lif.synthia.util;
20 
21 import java.util.ArrayList;
22 import java.util.List;
23 
24 import ca.uqac.lif.synthia.Picker;
28 
29 /**
30  * Picks an element from a collection, where the probability of picking
31  * each element can be user-defined. Elements are added to the collection
32  * by calling {@link #add(Object, Number) add()}. For example, the following
33  * code snippet creates a collection of three strings, where <tt>"A"</tt>
34  * has twice the odds of being picked compared to <tt>"B"</tt> and <tt>"C"</tt>:
35  * <pre>
36  * RandomFloat r = new RandomFloat();
37  * Choice&lt;String&gt; ep = new Choice&lt;String&gt;(r);
38  * ep.add("A", 0.5).add("B", 0.25).add("C", 0.25);</pre>
39  * When adding elements, one must make sure that the sum of probabilities
40  * is equal to 1.
41  * @param <T> The type of the object to pick
42  * @ingroup API
43  */
44 public class Choice<T> implements Shrinkable<T>
45 {
46  /**
47  * A list storing each element with its associated probability
48  */
49  /*@ non_null @*/ protected List<ProbabilityChoice<T>> m_choices;
50 
51  /**
52  * A picker used to choose the element
53  */
54  /*@ non_null @*/ protected Picker<Float> m_floatPicker;
55 
56  /**
57  * Creates a new element picker
58  * @param picker A picker used to choose the element
59  */
60  public Choice(/*@ non_null @*/ Picker<Float> picker)
61  {
62  super();
63  m_choices = new ArrayList<ProbabilityChoice<T>>();
64  m_floatPicker = picker;
65  }
66 
67  /**
68  * Adds an object-probability association
69  * @param pc The association
70  * @return This element picker
71  */
72  /*@ non_null @*/ public Choice<T> add(/*@ non_null @*/ ProbabilityChoice<T> pc)
73  {
74  m_choices.add(pc);
75  return this;
76  }
77 
78  /**
79  * Adds an object-probability association
80  * @param t The object
81  * @param p The probability, must be between 0 and 1
82  * @return This element picker
83  */
84  /*@ non_null @*/ public Choice<T> add(/*@ non_null @*/ T t, /*@ non_null @*/ Number p)
85  {
86  ProbabilityChoice<T> pc = new ProbabilityChoice<T>(new Constant<T>(t), p);
87  return add(pc);
88  }
89 
90  /**
91  * Adds an object-probability association
92  * @param t The picker for an object
93  * @param p The probability, must be between 0 and 1
94  * @return This element picker
95  */
96  /*@ non_null @*/ public Choice<T> add(/*@ non_null @*/ Picker<T> t, /*@ non_null @*/ Number p)
97  {
98  ProbabilityChoice<T> pc = new ProbabilityChoice<T>(t, p);
99  return add(pc);
100  }
101 
102 
103  /**
104  * Puts the element picker back into its initial state. This means that the
105  * sequence of calls to {@link #pick()} will produce the same values
106  * as when the object was instantiated.
107  */
108  @Override
109  public void reset()
110  {
112  for (ProbabilityChoice<?> pc : m_choices)
113  {
114  pc.reset();
115  }
116  }
117 
118 
119  /**
120  * Picks a random element. Typically, this method is expected to return non-null
121  * objects; a <tt>null</tt> return value is used to signal that no more
122  * objects will be produced. That is, once this method returns
123  * <tt>null</tt>, it should normally return <tt>null</tt> on all subsequent
124  * calls.
125  * @return The random element.
126  */
127  @Override
128  public T pick()
129  {
130  float[] probs = new float[m_choices.size()];
131  float total_prob = 0f;
132  for (int i = 0; i < probs.length; i++)
133  {
134  total_prob += m_choices.get(i).getProbability();
135  probs[i] = total_prob;
136  }
137  float f = m_floatPicker.pick();
138  int index = 0;
139  while (index < probs.length)
140  {
141  if (f <= probs[index])
142  {
143  break;
144  }
145  index++;
146  }
147  if (index >= m_choices.size())
148  {
149  return null;
150  }
151  return m_choices.get(index).getObject();
152  }
153 
154  /**
155  * Creates a copy of the element picker.
156  * @param with_state If set to <tt>false</tt>, the returned copy is set to
157  * the class' initial state (i.e. same thing as calling the picker's
158  * constructor). If set to <tt>true</tt>, the returned copy is put into the
159  * same internal state as the object it is copied from.
160  * @return The copy of the element picker
161  */
162  @Override
163  /*@ pure non_null @*/ public Choice<T> duplicate(boolean with_state)
164  {
165  Choice<T> ep = new Choice<T>(m_floatPicker.duplicate(with_state));
166  for (ProbabilityChoice<T> pc : m_choices)
167  {
168  ep.m_choices.add(pc.duplicate(with_state));
169  }
170  return ep;
171  }
172 
173  /**
174  * Simple data structure asssociating an object with
175  * a probability.
176  * @param <T> The type of the object to which a probability is associated
177  */
178  public static class ProbabilityChoice<T>
179  {
180  /**
181  * The probability of taking this object
182  */
183  protected float m_probability;
184 
185  /**
186  * The object corresponding to that object
187  */
188  /*@ non_null @*/ protected Picker<T> m_object;
189 
190  /**
191  * Creates a new probability-object association
192  * @param t The object
193  * @param p The probability of picking this node
194  */
195  public ProbabilityChoice(/*@ non_null @*/ Picker<T> t, /*@ non_null @*/ Number p)
196  {
197  super();
198  m_object = t;
199  m_probability = p.floatValue();
200  }
201 
202  /**
203  * Resets the underlying picker for this probability choice.
204  */
205  public void reset()
206  {
207  m_object.reset();
208  }
209 
210  /**
211  * Gets the probability for this association
212  * @return The probability
213  */
214  /*@ pure @*/ public float getProbability()
215  {
216  return m_probability;
217  }
218 
219  /**
220  * Gets the tree node for this association
221  * @return The node
222  */
223  /*@ pure non_null @*/ public T getObject()
224  {
225  return m_object.pick();
226  }
227 
228 
229  /**
230  * Returns the last picked element and his probability to get picked into a string.
231  * @return The string containing the string representation of the object and his pick probability.
232  */
233  @Override
234  public String toString()
235  {
236  return m_object.toString() + " (" + m_probability + ")";
237  }
238 
239  /**
240  * Duplicates this probability-node association
241  * @param with_state If set to <tt>true</tt>, the node is duplicated
242  * with its state
243  * @return A duplicate of this association
244  */
245  /*@ pure non_null @*/ public ProbabilityChoice<T> duplicate(boolean with_state)
246  {
247  return new ProbabilityChoice<T>(m_object, m_probability);
248  }
249  }
250 
251  /**
252  * Gets the total number of alternatives available in this picker.
253  * @return The number of choices
254  */
255  public int getChoiceCount()
256  {
257  return m_choices.size();
258  }
259 
260  @Override
261  public Shrinkable<T> shrink(T o, Picker<Float> decision, float m)
262  {
263  return new PickSmallerComparable<T>(this, o);
264  }
265 
266  @Override
267  public Shrinkable<T> shrink(T o)
268  {
269  return shrink(o, RandomFloat.instance, 1);
270  }
271 }
ca.uqac.lif.synthia.Picker
Picks an object.
Definition: Picker.java:36
ca.uqac.lif.synthia.util.Choice.shrink
Shrinkable< T > shrink(T o, Picker< Float > decision, float m)
Shrinks a picker.
Definition: Choice.java:261
ca.uqac.lif.synthia.Shrinkable
Interface signaling that a picker can be shrunk.
Definition: Shrinkable.java:36
ca.uqac.lif.synthia.util.Choice.getChoiceCount
int getChoiceCount()
Gets the total number of alternatives available in this picker.
Definition: Choice.java:255
ca.uqac.lif.synthia.util.Choice.pick
T pick()
Picks a random element.
Definition: Choice.java:128
ca.uqac.lif.synthia.relative.PickSmallerComparable
A variant of PickIf that selects an element if it is smaller than a reference object.
Definition: PickSmallerComparable.java:37
ca.uqac.lif.synthia.random.RandomFloat.instance
static final transient RandomFloat instance
A public static instance of RandomFloat.
Definition: RandomFloat.java:45
ca.uqac
ca.uqac.lif.synthia.util.Choice.shrink
Shrinkable< T > shrink(T o)
Shrinks a picker with default parameters.
Definition: Choice.java:267
ca.uqac.lif.synthia.random
Pickers that produce pseudo-random objects such as numbers.
Definition: AffineTransform.java:19
ca.uqac.lif.synthia
Definition: Bounded.java:19
ca.uqac.lif.synthia.util.Constant
Picker that returns the same object every time.
Definition: Constant.java:37
ca.uqac.lif.synthia.util.Choice.duplicate
Choice< T > duplicate(boolean with_state)
Creates a copy of the element picker.
Definition: Choice.java:163
ca.uqac.lif.synthia.util.Choice.m_floatPicker
Picker< Float > m_floatPicker
A picker used to choose the element.
Definition: Choice.java:54
ca.uqac.lif
ca.uqac.lif.synthia.util.Choice.add
Choice< T > add(ProbabilityChoice< T > pc)
Adds an object-probability association.
Definition: Choice.java:72
ca
ca.uqac.lif.synthia.Picker.pick
T pick()
Picks an object.
ca.uqac.lif.synthia.relative
Pickers that produce a value in relation to another value.
Definition: package-info.java:24
ca.uqac.lif.synthia.util.Choice.m_choices
List< ProbabilityChoice< T > > m_choices
A list storing each element with its associated probability.
Definition: Choice.java:49
ca.uqac.lif.synthia.util.Choice.add
Choice< T > add(T t, Number p)
Adds an object-probability association.
Definition: Choice.java:84
ca.uqac.lif.synthia.random.RandomFloat
Picks a floating point number uniformly in an interval.
Definition: RandomFloat.java:30
ca.uqac.lif.synthia.util.Choice
Picks an element from a collection, where the probability of picking each element can be user-defined...
Definition: Choice.java:44
ca.uqac.lif.synthia.util.Choice.add
Choice< T > add(Picker< T > t, Number p)
Adds an object-probability association.
Definition: Choice.java:96
ca.uqac.lif.synthia.util.Choice.Choice
Choice(Picker< Float > picker)
Creates a new element picker.
Definition: Choice.java:60
ca.uqac.lif.synthia.Picker.duplicate
Picker< T > duplicate(boolean with_state)
Creates a copy of the picker.
ca.uqac.lif.synthia.Picker.reset
void reset()
Puts the picker back into its initial state.
ca.uqac.lif.synthia.util.Choice.reset
void reset()
Puts the element picker back into its initial state.
Definition: Choice.java:109