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 }