Synthia
Generic and flexible data structure generator
Knit.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.sequence;
20 
21 import java.util.ArrayList;
22 import java.util.List;
23 
25 import ca.uqac.lif.synthia.Picker;
26 
27 /**
28  * Picker producing an "interleaved" sequence of objects from calls to multiple
29  * other pickers. The <tt>Knit</tt> picker must be instantiated by passing to
30  * it a picker of pickers <tt>p</tt> (that is, a
31  * <tt>Picker&lt;Picker&lt;T&gt;&gt;</tt>). Upon every call to {@link #pick()},
32  * <tt>Knit</tt> proceeds as follows:
33  * <ol>
34  * <li>It flips a coin to decide whether to create a new instance of
35  * <tt>Picker&lt;T&gt;</tt>; if so, it calls <tt>p.pick()</tt> and adds the
36  * resulting picker instance to its set of "living" pickers.</li>
37  * <li>It selects one of the living pickers, and returns the object resulting
38  * from a call to {@link #pick()} on that picker.</li>
39  * <li>If this picker cannot produce a new value (e.g. it throws a
40  * {@link NoMoreElementException}), it is considered "dead" and is removed from
41  * the set of living pickers. In such a case, <tt>Knit</tt> flips a coin to
42  * to decide whether to create a new instance of <tt>Picker&lt;T&gt;</tt> to
43  * replace it; if so, it calls <tt>p.pick()</tt> and adds the
44  * resulting picker instance to its set of "living" pickers.</li>
45  * </ol>
46  * @author Sylvain Hallé
47  *
48  * @param <T> The type of the objects to produce
49  * @ingroup API
50  */
51 public class Knit<T> implements Picker<T>
52 {
53  /**
54  * Maximum number of tries to get a new element from an instance before
55  * giving up.
56  */
57  protected static final transient int s_maxTries = 1000;
58 
59  /**
60  * A picker producing pickers.
61  */
62  /*@ non_null @*/ protected Picker<? extends Picker<T>> m_instancePicker;
63 
64  /**
65  * A picker deciding whether to start a new instance at any moment.
66  */
67  /*@ non_null @*/ protected Picker<Boolean> m_newInstance;
68 
69  /**
70  * A picker deciding whether to start a new instance when one has just
71  * finished.
72  */
73  /*@ non_null @*/ protected Picker<Boolean> m_renewInstance;
74 
75  /**
76  * A picker used to pick a living instance.
77  */
78  /*@ non_null @*/ protected Picker<Float> m_floatSource;
79 
80  /**
81  * The picker instances that are currently "alive".
82  */
83  /*@ non_null @*/ protected List<Picker<T>> m_instances;
84 
85  /**
86  * Creates a new instance of the picker.
87  * @param instance_picker A picker producing picker instances
88  * @param new_instance A picker deciding whether to start a new instance at
89  * any moment
90  * @param renew_instance A picker deciding whether to start a new instance
91  * when one has just finished
92  * @param float_source A picker used to pick a living instance
93  */
94  public Knit(Picker<? extends Picker<T>> instance_picker, Picker<Boolean> new_instance,
95  Picker<Boolean> renew_instance, Picker<Float> float_source)
96  {
97  super();
98  m_instancePicker = instance_picker;
99  m_newInstance = new_instance;
100  m_renewInstance = renew_instance;
101  m_floatSource = float_source;
102  m_instances = new ArrayList<Picker<T>>();
103  }
104 
105  @Override
106  public void reset()
107  {
108  m_instancePicker.reset();
112  m_instances.clear();
113  }
114 
115  @Override
116  public T pick()
117  {
118  if (m_instances.isEmpty() || m_newInstance.pick())
119  {
120  // Spawn a new instance
121  Picker<T> new_instance = m_instancePicker.pick();
122  m_instances.add(new_instance);
123  }
124  for (int i = 0; i < s_maxTries; i++)
125  {
126  int index = (int) Math.floor(((float) m_instances.size()) * m_floatSource.pick());
127  Picker<T> current_instance = m_instances.get(index);
128  try
129  {
130  return current_instance.pick();
131  }
132  catch (NoMoreElementException e)
133  {
134  m_instances.remove(index);
135  if (m_instances.isEmpty() || m_renewInstance.pick())
136  {
137  // Spawn a new instance
138  Picker<T> new_instance = m_instancePicker.pick().duplicate(false);
139  m_instances.add(new_instance);
140  }
141  }
142  }
143  throw new NoMoreElementException();
144  }
145 
146  @Override
147  public Knit<T> duplicate(boolean with_state)
148  {
149  Knit<T> k = new Knit<T>(m_instancePicker.duplicate(with_state), m_newInstance.duplicate(with_state), m_renewInstance.duplicate(with_state), m_floatSource.duplicate(with_state));
150  if (with_state)
151  {
152  for (Picker<T> p : m_instances)
153  {
154  k.m_instances.add(p.duplicate(with_state));
155  }
156  }
157  return k;
158  }
159 
160  @Override
161  public String toString()
162  {
163  return "Knit";
164  }
165 }
ca.uqac.lif.synthia.Picker
Picks an object.
Definition: Picker.java:36
ca.uqac.lif.synthia.sequence.Knit.m_instances
List< Picker< T > > m_instances
The picker instances that are currently "alive".
Definition: Knit.java:83
ca.uqac.lif.synthia.sequence.Knit.toString
String toString()
Definition: Knit.java:161
ca.uqac.lif.synthia.sequence.Knit.reset
void reset()
Puts the picker back into its initial state.
Definition: Knit.java:106
ca.uqac
ca.uqac.lif.synthia
Definition: Bounded.java:19
ca.uqac.lif.synthia.sequence.Knit.s_maxTries
static final transient int s_maxTries
Maximum number of tries to get a new element from an instance before giving up.
Definition: Knit.java:57
ca.uqac.lif.synthia.sequence.Knit.pick
T pick()
Picks an object.
Definition: Knit.java:116
ca.uqac.lif.synthia.sequence.Knit.Knit
Knit(Picker<? extends Picker< T >> instance_picker, Picker< Boolean > new_instance, Picker< Boolean > renew_instance, Picker< Float > float_source)
Creates a new instance of the picker.
Definition: Knit.java:94
ca.uqac.lif
ca
ca.uqac.lif.synthia.Picker.pick
T pick()
Picks an object.
ca.uqac.lif.synthia.sequence.Knit.m_floatSource
Picker< Float > m_floatSource
A picker used to pick a living instance.
Definition: Knit.java:78
ca.uqac.lif.synthia.sequence.Knit
Picker producing an "interleaved" sequence of objects from calls to multiple other pickers.
Definition: Knit.java:51
ca.uqac.lif.synthia.sequence.Knit.duplicate
Knit< T > duplicate(boolean with_state)
Creates a copy of the picker.
Definition: Knit.java:147
ca.uqac.lif.synthia.sequence.Knit.m_renewInstance
Picker< Boolean > m_renewInstance
A picker deciding whether to start a new instance when one has just finished.
Definition: Knit.java:73
ca.uqac.lif.synthia.NoMoreElementException
An exception to throw when a picker can't pick an other element.
Definition: NoMoreElementException.java:25
ca.uqac.lif.synthia.sequence.Knit.m_instancePicker
Picker<? extends Picker< T > > m_instancePicker
A picker producing pickers.
Definition: Knit.java:62
ca.uqac.lif.synthia.Picker.duplicate
Picker< T > duplicate(boolean with_state)
Creates a copy of the picker.
ca.uqac.lif.synthia.sequence.Knit.m_newInstance
Picker< Boolean > m_newInstance
A picker deciding whether to start a new instance at any moment.
Definition: Knit.java:67
ca.uqac.lif.synthia.Picker.reset
void reset()
Puts the picker back into its initial state.