1 package org.opentrafficsim.base.parameters.constraint;
2
3 import org.djunits.value.vdouble.scalar.AbstractDoubleScalar;
4 import org.djutils.exceptions.Throw;
5
6 /**
7 * Continuous constraints with a single bound. To allow both {@code Double} and {@code AbstractDoubleScalar<?, ?>} constraints,
8 * the generic type is restricted to {@code Number}. However, that also allows other subclasses of {@code Number}, e.g.
9 * {@code Integer}. Due to rounding and value limits from the type (e.g. {@code Integer.MAX_VALEU}), bounds may not function
10 * correctly after a call to {@code Number.doubleValue()}. To restrict the usage, the constructor is private and static factory
11 * methods for {@code Double} and {@code AbstractDoubleScalar<?, ?>} are supplied.
12 * <p>
13 * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
14 * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
15 * <p>
16 * @version $Revision$, $LastChangedDate$, by $Author$, initial version Aug 14, 2017 <br>
17 * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
18 * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
19 * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
20 * @param <T> value type
21 */
22 public class SingleBound<T extends Number> implements Constraint<T>
23 {
24
25 /** The bound. */
26 private final Bound bound;
27
28 /** Message about values that do not comply with the bound. */
29 private final String failMessage;
30
31 /**
32 * Creates a lower inclusive bound; {@code value >= bound}.
33 * @param bound double; bound value
34 * @return lower inclusive bound
35 */
36 public static final SingleBound<Double> lowerInclusive(final double bound)
37 {
38 return createLowerInclusive(bound);
39 }
40
41 /**
42 * Creates a lower inclusive bound; {@code value >= bound}.
43 * @param bound T; bound value
44 * @param <T> value type
45 * @return lower inclusive bound
46 */
47 public static final <T extends AbstractDoubleScalar<?, ?>> SingleBound<T> lowerInclusive(final T bound)
48 {
49 return createLowerInclusive(bound);
50 }
51
52 /**
53 * Creates a lower inclusive bound; {@code value >= bound}.
54 * @param bound T; bound value
55 * @param <T> value type
56 * @return lower inclusive bound
57 */
58 private static <T extends Number> SingleBound<T> createLowerInclusive(final T bound)
59 {
60 return new SingleBound<>(new LowerBoundInclusive<>(bound),
61 String.format("Value is not greater than or equal to %s", bound));
62 }
63
64 /**
65 * Creates a lower exclusive bound; {@code value > bound}.
66 * @param bound double; bound value
67 * @return lower exclusive bound
68 */
69 public static final SingleBound<Double> lowerExclusive(final double bound)
70 {
71 return createLowerExclusive(bound);
72 }
73
74 /**
75 * Creates a lower exclusive bound; {@code value > bound}.
76 * @param bound T; bound value
77 * @param <T> value type
78 * @return lower exclusive bound
79 */
80 public static final <T extends AbstractDoubleScalar<?, ?>> SingleBound<T> lowerExclusive(final T bound)
81 {
82 return createLowerExclusive(bound);
83 }
84
85 /**
86 * Creates a lower exclusive bound; {@code value > bound}.
87 * @param bound T; bound value
88 * @param <T> value type
89 * @return lower exclusive bound
90 */
91 private static <T extends Number> SingleBound<T> createLowerExclusive(final T bound)
92 {
93 return new SingleBound<>(new LowerBoundExclusive<>(bound), String.format("Value is not greater than %s", bound));
94 }
95
96 /**
97 * Creates an upper inclusive bound; {@code value <= bound}.
98 * @param bound double; bound value
99 * @return upper inclusive bound
100 */
101 public static final SingleBound<Double> upperInclusive(final double bound)
102 {
103 return createUpperInclusive(bound);
104 }
105
106 /**
107 * Creates an upper inclusive bound; {@code value <= bound}.
108 * @param bound T; bound value
109 * @return upper inclusive bound
110 * @param <T> value type
111 */
112 public static final <T extends AbstractDoubleScalar<?, ?>> SingleBound<T> upperInclusive(final T bound)
113 {
114 return createUpperInclusive(bound);
115 }
116
117 /**
118 * Creates an upper inclusive bound; {@code value <= bound}.
119 * @param bound T; bound value
120 * @param <T> value type
121 * @return upper inclusive bound
122 */
123 private static <T extends Number> SingleBound<T> createUpperInclusive(final T bound)
124 {
125 return new SingleBound<>(new UpperBoundInclusive<>(bound),
126 String.format("Value is not smaller than or equal to %s", bound));
127 }
128
129 /**
130 * Creates an upper exclusive bound; {@code value < bound}.
131 * @param bound double; bound value
132 * @return upper exclusive bound
133 */
134 public static final SingleBound<Double> upperExclusive(final double bound)
135 {
136 return createUpperExclusive(bound);
137 }
138
139 /**
140 * Creates an upper exclusive bound; {@code value < bound}.
141 * @param bound T; bound value
142 * @param <T> value type
143 * @return upper exclusive bound
144 */
145 public static final <T extends AbstractDoubleScalar<?, ?>> SingleBound<T> upperExclusive(final T bound)
146 {
147 return createUpperExclusive(bound);
148 }
149
150 /**
151 * Creates an upper exclusive bound; {@code value < bound}.
152 * @param bound T; bound value
153 * @param <T> value type
154 * @return upper exclusive bound
155 */
156 private static <T extends Number> SingleBound<T> createUpperExclusive(final T bound)
157 {
158 return new SingleBound<>(new UpperBoundExclusive<>(bound), String.format("Value is not smaller than %s", bound));
159 }
160
161 /**
162 * Constructor.
163 * @param bound Bound; bound
164 * @param failMessage String; message about values that do not comply with the bound
165 */
166 SingleBound(final Bound bound, final String failMessage)
167 {
168 this.bound = bound;
169 this.failMessage = failMessage;
170 }
171
172 /** {@inheritDoc} */
173 @Override
174 public boolean accept(final T value)
175 {
176 return this.bound.accept(value);
177 }
178
179 /** {@inheritDoc} */
180 @Override
181 public String failMessage()
182 {
183 return this.failMessage;
184 }
185
186 /**
187 * @return bound.
188 */
189 public Bound getBound()
190 {
191 return this.bound;
192 }
193
194 /**
195 * Super class for classes that implement a specific numeric check.
196 * <p>
197 * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
198 * <br>
199 * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
200 * <p>
201 * @version $Revision$, $LastChangedDate$, by $Author$, initial version 8 sep. 2017 <br>
202 * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
203 * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
204 * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
205 */
206 abstract static class Bound
207 {
208
209 /** Value of the bound. */
210 @SuppressWarnings("checkstyle:visibilitymodifier")
211 final Number bound;
212
213 /** Hashcode of the value class. */
214 @SuppressWarnings("checkstyle:visibilitymodifier")
215 final int classHashcode;
216
217 /** String representation of this bound with %s for the value. */
218 private final String stringFormat;
219
220 /**
221 * Constructor.
222 * @param bound Number; value of the bound
223 * @param stringFormat String; string representation of this bound with %s for the value
224 */
225 Bound(final Number bound, final String stringFormat)
226 {
227 Throw.whenNull(bound, "Bound may not be null.");
228 Throw.whenNull(bound, "String format may not be null.");
229 Throw.when(Double.isNaN(bound.doubleValue()), IllegalArgumentException.class, "Bound value may not be NaN.");
230 this.bound = bound;
231 this.classHashcode = bound.getClass().hashCode();
232 this.stringFormat = stringFormat;
233 }
234
235 /**
236 * Returns true if the bound accepts the value.
237 * @param value Number; the value to check
238 * @return true if the bound accepts the value
239 */
240 abstract boolean accept(Number value);
241
242 /** {@inheritDoc} */
243 @Override
244 public final String toString()
245 {
246 return String.format(this.stringFormat, this.bound);
247 }
248 }
249
250 /**
251 * Class implementing a lower inclusive bound; {@code value >= bound}.
252 * <p>
253 * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
254 * <br>
255 * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
256 * <p>
257 * @version $Revision$, $LastChangedDate$, by $Author$, initial version 8 sep. 2017 <br>
258 * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
259 * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
260 * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
261 * @param <T> value type
262 */
263 static class LowerBoundInclusive<T extends Number> extends Bound
264 {
265
266 /**
267 * Constructor.
268 * @param bound T; bound
269 */
270 LowerBoundInclusive(final T bound)
271 {
272 super(bound, "%s <= value");
273 }
274
275 /** {@inheritDoc} */
276 protected boolean accept(final Number value)
277 {
278 return this.bound.doubleValue() <= value.doubleValue();
279 }
280
281 }
282
283 /**
284 * Class implementing a lower exclusive bound; {@code value > bound}.
285 * <p>
286 * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
287 * <br>
288 * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
289 * <p>
290 * @version $Revision$, $LastChangedDate$, by $Author$, initial version 8 sep. 2017 <br>
291 * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
292 * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
293 * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
294 * @param <T> value type
295 */
296 static class LowerBoundExclusive<T extends Number> extends Bound
297 {
298
299 /**
300 * Constructor.
301 * @param bound T; bound
302 */
303 LowerBoundExclusive(final T bound)
304 {
305 super(bound, "%s < value");
306 }
307
308 /** {@inheritDoc} */
309 protected boolean accept(final Number value)
310 {
311 return this.bound.doubleValue() < value.doubleValue();
312 }
313
314 }
315
316 /**
317 * Class implementing an upper inclusive bound; {@code value <= bound}.
318 * <p>
319 * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
320 * <br>
321 * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
322 * <p>
323 * @version $Revision$, $LastChangedDate$, by $Author$, initial version 8 sep. 2017 <br>
324 * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
325 * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
326 * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
327 * @param <T> value type
328 */
329 static class UpperBoundInclusive<T extends Number> extends Bound
330 {
331
332 /**
333 * Constructor.
334 * @param bound T; bound
335 */
336 UpperBoundInclusive(final T bound)
337 {
338 super(bound, "value <= %s");
339 }
340
341 /** {@inheritDoc} */
342 protected boolean accept(final Number value)
343 {
344 return this.bound.doubleValue() >= value.doubleValue();
345 }
346
347 }
348
349 /**
350 * Class implementing an upper exclusive bound; {@code value < bound}.
351 * <p>
352 * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
353 * <br>
354 * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
355 * <p>
356 * @version $Revision$, $LastChangedDate$, by $Author$, initial version 8 sep. 2017 <br>
357 * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
358 * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
359 * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
360 * @param <T> value type
361 */
362 static class UpperBoundExclusive<T extends Number> extends Bound
363 {
364
365 /**
366 * Constructor.
367 * @param bound T; bound
368 */
369 UpperBoundExclusive(final T bound)
370 {
371 super(bound, "value < %s");
372 }
373
374 /** {@inheritDoc} */
375 protected boolean accept(final Number value)
376 {
377 return this.bound.doubleValue() > value.doubleValue();
378 }
379
380 }
381
382 /** {@inheritDoc} */
383 @Override
384 public String toString()
385 {
386 return "SingleBound [" + this.bound + "]";
387 }
388
389 }