Synthia
Generic and flexible data structure generator
PickIf.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.relative;
20 
21 import java.util.ArrayList;
22 import java.util.List;
23 
24 import ca.uqac.lif.petitpoucet.NodeFactory;
25 import ca.uqac.lif.petitpoucet.Part;
26 import ca.uqac.lif.petitpoucet.PartNode;
27 import ca.uqac.lif.petitpoucet.function.ExplanationQueryable;
29 import ca.uqac.lif.synthia.Picker;
31 import ca.uqac.lif.synthia.util.Mutator;
32 
33 /**
34  * Returns object from a picker satisfying a condition.
35  *
36  * @param <T> The object type returned by the picker.
37  * @ingroup API
38  */
39 public class PickIf<T> extends Mutator<T> implements ExplanationQueryable
40 {
41  /**
42  * The maximal number of iteration that the while loop of the {@link #pick()} method can do.
43  * If the value is negative, there will be no maximum number of iterations.
44  */
45  protected int m_maxIteration;
46 
47  /**
48  * A list keeping track of the number of rejected elements between each
49  * output element. This list is only used to answer calls to {@link #query()}.
50  */
51  /*@ non_null @*/ protected List<Integer> m_rejected;
52 
53  /**
54  * Constructor with default {@link #m_maxIteration} value.
55  *
56  * @param picker The picker used to generate objects.
57  */
58  public PickIf(Picker<? extends T> picker)
59  {
60  super(picker);
61  m_maxIteration = 10000;
62  m_rejected = new ArrayList<Integer>();
63  m_rejected.add(0);
64  }
65 
66  /**
67  * Constructor who takes a {@link #m_maxIteration} value.
68  *
69  * @param picker The picker used to generate objects.
70  * @param max_iteration The maximum number of iterations the {@link #pick()} will try to generate
71  * an object before giving up.
72  */
73  public PickIf(Picker<? extends T> picker, int max_iteration)
74  {
75  super(picker);
76  m_maxIteration = max_iteration;
77  }
78 
79  /**
80  * Method to evaluate if an element is satisfying a condition. The difference
81  * with {@link #canChoose(Object) canChoose()} is that this method keeps
82  * track of the number of rejected elements between each element that is let
83  * through.
84  *
85  * @param element The element to check
86  * @return <tt>true</tt> if the condition is satisfied and <tt>false</tt> if it's not the case.
87  */
88  private boolean canChoose(T element)
89  {
90  int index = m_rejected.size() - 1;
91  if (!select(element))
92  {
93  m_rejected.set(index, m_rejected.get(index) + 1);
94  return false;
95  }
96  m_rejected.add(0);
97  return true;
98  }
99 
100  /**
101  * Method to evaluate if an element is satisfying a condition. Descendants
102  * of this class must override this method to define a selection criterion.
103  *
104  * @param element The element to check
105  * @return <tt>true</tt> if the condition is satisfied and <tt>false</tt> if it's not the case.
106  */
107  protected boolean select(T element)
108  {
109  return true;
110  }
111 
112  protected void copyInto(PickIf<T> m, boolean with_state)
113  {
114  super.copyInto(m, with_state);
115  if (with_state)
116  {
117  m.m_rejected.addAll(m_rejected);
118  }
119 
120  }
121 
122  /**
123  * Method to pick the first object generated by the picker who satisfies the condition.
124  * WARNING: For now, this method can result in a infinite loop if the picker can't generate
125  * an object who satisfies the condition.
126  *
127  * @return The object.
128  */
129  public T pick()
130  {
131  int iteration_counter = 0;
132  T picked_value = m_picker.pick();
133  while (!canChoose(picked_value))
134  {
135  if (checkIfInfiniteLoop(iteration_counter))
136  {
137  throw new GiveUpException();
138  }
139  picked_value = m_picker.pick();
140  iteration_counter++;
141  }
142  return picked_value;
143  }
144 
145  /**
146  * Protected method to check if the instance of the class detects that the while loop of
147  * the {@link #pick()} method fell into an infinite loop by supposing that if the loop exceed
148  * a maximal number of iteration, it will cause an infinite loop.
149  *
150  * @warning If {@link #m_maxIteration} is negative, the {@link #pick} method will not check if
151  * the iteration counter has exceeded the value of {@link #m_maxIteration} and this
152  * method will always return false. This means that it's possible that calling {@link #pick}
153  * causes an infinite loop. Only use a negative value for {@link #m_maxIteration} if you assume
154  * that calling {@link #pick} could cause an infinite loop.
155  *
156  * @return <tt>true</tt> if infinite loop is detected and <tt>false</tt> if it's not the case.
157  */
158  protected boolean checkIfInfiniteLoop(int iteration_counter)
159  {
160  if (m_maxIteration < 0)
161  {
162  return false;
163  }
164  else
165  {
166  return !(iteration_counter < m_maxIteration);
167  }
168  }
169 
170  @Override
171  public PickIf<T> duplicate(boolean with_state)
172  {
173  PickIf<T> pif = new PickIf<T>(m_picker.duplicate(with_state), m_maxIteration);
174  copyInto(pif, with_state);
175  return pif;
176  }
177 
178  @Override
179  public void reset()
180  {
181  m_picker.reset();
182  m_rejected.clear();
183  m_rejected.add(0);
184  }
185 
186  @Override
187  public PartNode getExplanationForOutput(int index, Part p, NodeFactory f)
188  {
189  PartNode root = f.getPartNode(p, this);
190  if (index >= m_rejected.size() - 1)
191  {
192  // Not a valid part, end there
193  return root;
194  }
195  int current_index = m_rejected.get(0);
196  for (int i = 1; i < index; i++)
197  {
198  current_index += m_rejected.get(i);
199  }
200  Part new_p = NthSuccessiveOutput.replaceOutIndexBy(p, current_index + index);
201  root.addChild(f.getPartNode(new_p, m_picker));
202  return root;
203  }
204 
205  @Override
206  public String toString()
207  {
208  return "PickIf";
209  }
210 }
ca.uqac.lif.synthia.Picker
Picks an object.
Definition: Picker.java:36
ca.uqac.lif.synthia.relative.PickIf.PickIf
PickIf(Picker<? extends T > picker, int max_iteration)
Constructor who takes a m_maxIteration value.
Definition: PickIf.java:73
ca.uqac.lif.synthia.relative.PickIf.PickIf
PickIf(Picker<? extends T > picker)
Constructor with default m_maxIteration value.
Definition: PickIf.java:58
ca.uqac.lif.synthia.util.Mutator.m_picker
Picker<? extends T > m_picker
The underlying picker producing the values to transform.
Definition: Mutator.java:38
ca.uqac.lif.synthia.explanation.NthSuccessiveOutput.replaceOutIndexBy
static Part replaceOutIndexBy(Part from, int index)
Given an arbitrary designator, replaces the first occurrence of NthOutput by an instance of NthInput ...
Definition: NthSuccessiveOutput.java:100
ca.uqac.lif.synthia.util
Miscellaneous pickers performing various functions.
Definition: ArrayPicker.java:19
ca.uqac.lif.synthia.relative.PickIf.reset
void reset()
Puts the picker back into its initial state.
Definition: PickIf.java:179
ca.uqac.lif.synthia.relative.PickIf.toString
String toString()
Definition: PickIf.java:206
ca.uqac.lif.synthia.relative.PickIf.getExplanationForOutput
PartNode getExplanationForOutput(int index, Part p, NodeFactory f)
Definition: PickIf.java:187
ca.uqac
ca.uqac.lif.synthia
Definition: Bounded.java:19
ca.uqac.lif.synthia.explanation
Objects related to the explanation of results produced by pickers.
Definition: Explanation.java:19
ca.uqac.lif
ca.uqac.lif.synthia.relative.PickIf
Returns object from a picker satisfying a condition.
Definition: PickIf.java:39
ca
ca.uqac.lif.synthia.Picker.pick
T pick()
Picks an object.
ca.uqac.lif.synthia.relative.PickIf.checkIfInfiniteLoop
boolean checkIfInfiniteLoop(int iteration_counter)
Protected method to check if the instance of the class detects that the while loop of the pick() meth...
Definition: PickIf.java:158
ca.uqac.lif.synthia.util.Mutator
A picker that applies a transformation ("mutation") on the value produced by another picker.
Definition: Mutator.java:33
ca.uqac.lif.synthia.relative.PickIf.select
boolean select(T element)
Method to evaluate if an element is satisfying a condition.
Definition: PickIf.java:107
ca.uqac.lif.synthia.relative.PickIf.copyInto
void copyInto(PickIf< T > m, boolean with_state)
Definition: PickIf.java:112
ca.uqac.lif.synthia.relative.PickIf.m_maxIteration
int m_maxIteration
The maximal number of iteration that the while loop of the pick() method can do.
Definition: PickIf.java:45
ca.uqac.lif.synthia.GiveUpException
An exception to throw to prevent the pick method of a PickIf picker from falling into an infinite loo...
Definition: GiveUpException.java:28
ca.uqac.lif.synthia.relative.PickIf.duplicate
PickIf< T > duplicate(boolean with_state)
Creates a copy of the picker.
Definition: PickIf.java:171
ca.uqac.lif.synthia.relative.PickIf.pick
T pick()
Method to pick the first object generated by the picker who satisfies the condition.
Definition: PickIf.java:129
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.relative.PickIf.m_rejected
List< Integer > m_rejected
A list keeping track of the number of rejected elements between each output element.
Definition: PickIf.java:51
ca.uqac.lif.synthia.explanation.NthSuccessiveOutput
A Part pointing to the n-th output produced by a picker since its last call to reset().
Definition: NthSuccessiveOutput.java:36