DualBound.java

  1. package org.opentrafficsim.base.parameters.constraint;

  2. import org.djunits.value.vdouble.scalar.AbstractDoubleScalar;
  3. import org.djutils.exceptions.Throw;

  4. /**
  5.  * Continuous constraints with a dual bound. To allow both {@code Double} and {@code AbstractDoubleScalar<?, ?>} constraints,
  6.  * the generic type is restricted to {@code Number}. However, that also allows other subclasses of {@code Number}, e.g.
  7.  * {@code Integer}. Due to rounding and value limits from the type (e.g. {@code Integer.MAX_VALEU}), bounds may not function
  8.  * correctly after a call to {@code Number.doubleValue()}. To restrict the usage, the constructor is private and static factory
  9.  * methods for {@code Double} and {@code AbstractDoubleScalar<?, ?>} are supplied.
  10.  * <p>
  11.  * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
  12.  * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
  13.  * <p>
  14.  * @version $Revision$, $LastChangedDate$, by $Author$, initial version 8 sep. 2017 <br>
  15.  * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
  16.  * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
  17.  * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
  18.  * @param <T> value type
  19.  */
  20. public final class DualBound<T extends Number> extends SingleBound<T>
  21. {

  22.     /**
  23.      * Standard dual bound on the unit interval [0...1]. This can be used for both {@code Double} and
  24.      * {@code AbstractDoubleScalar<?, ?>} parameters.
  25.      */
  26.     public static final DualBound<Number> UNITINTERVAL = createClosed(0.0, 1.0);

  27.     /** The upper bound. */
  28.     private final Bound upperBound;

  29.     /**
  30.      * Creates a dual bound <i>including</i> the bounds; {@code lowerBound <= value <= upperBound}. Bounds may be equal.
  31.      * @param lowerBound double; lower bound value
  32.      * @param upperBound double; upper bound value
  33.      * @return closed dual bound
  34.      */
  35.     public static DualBound<Double> closed(final double lowerBound, final double upperBound)
  36.     {
  37.         return createClosed(lowerBound, upperBound);
  38.     }

  39.     /**
  40.      * Creates a dual bound <i>including</i> the bounds; {@code lowerBound <= value <= upperBound}.
  41.      * @param lowerBound T; lower bound value
  42.      * @param upperBound T; upper bound value
  43.      * @param <T> value type
  44.      * @return closed dual bound
  45.      */
  46.     public static <T extends AbstractDoubleScalar<?, ?>> DualBound<T> closed(final T lowerBound, final T upperBound)
  47.     {
  48.         return createClosed(lowerBound, upperBound);
  49.     }

  50.     /**
  51.      * Creates a dual bound <i>including</i> the bounds; {@code lowerBound <= value <= upperBound}.
  52.      * @param lowerBound T; lower bound value
  53.      * @param upperBound T; upper bound value
  54.      * @param <T> value type
  55.      * @return closed dual bound
  56.      */
  57.     private static <T extends Number> DualBound<T> createClosed(final T lowerBound, final T upperBound)
  58.     {
  59.         Throw.when(lowerBound.doubleValue() > upperBound.doubleValue(), IllegalArgumentException.class,
  60.                 "Lower bound must be smaller or equal than the upper bound for a closed interval.");
  61.         return new DualBound<>(new LowerBoundInclusive<>(lowerBound), new UpperBoundInclusive<>(upperBound), String
  62.                 .format("Value is not greater than or equal to %s and smaller than or equal to %s", lowerBound, upperBound));
  63.     }

  64.     /**
  65.      * Creates a dual bound <i>excluding</i> the bounds; {@code lowerBound < value < upperBound}.
  66.      * @param lowerBound double; lower bound value
  67.      * @param upperBound double; upper bound value
  68.      * @return open dual bound
  69.      */
  70.     public static DualBound<Double> open(final double lowerBound, final double upperBound)
  71.     {
  72.         return createOpen(lowerBound, upperBound);
  73.     }

  74.     /**
  75.      * Creates a dual bound <i>excluding</i> the bounds; {@code lowerBound < value < upperBound}.
  76.      * @param lowerBound T; lower bound value
  77.      * @param upperBound T; upper bound value
  78.      * @param <T> value type
  79.      * @return open dual bound
  80.      */
  81.     public static <T extends AbstractDoubleScalar<?, ?>> DualBound<T> open(final T lowerBound, final T upperBound)
  82.     {
  83.         return createOpen(lowerBound, upperBound);
  84.     }

  85.     /**
  86.      * Creates a dual bound <i>excluding</i> the bounds; {@code lowerBound < value < upperBound}.
  87.      * @param lowerBound T; lower bound value
  88.      * @param upperBound T; upper bound value
  89.      * @param <T> value type
  90.      * @return open dual bound
  91.      */
  92.     private static <T extends Number> DualBound<T> createOpen(final T lowerBound, final T upperBound)
  93.     {
  94.         checkSeparation(lowerBound, upperBound);
  95.         return new DualBound<>(new LowerBoundExclusive<>(lowerBound), new UpperBoundExclusive<>(upperBound),
  96.                 String.format("Value is not greater than %s and smaller than %s", lowerBound, upperBound));
  97.     }

  98.     /**
  99.      * Creates a dual bound <i>excluding</i> the lower bound and <i>including</i> the upper bound;
  100.      * {@code lowerBound < value <= upperBound}.
  101.      * @param lowerBound double; lower bound value
  102.      * @param upperBound double; upper bound value
  103.      * @return dual bound; excluding the lower bound and including the upper bound
  104.      */
  105.     public static DualBound<Double> leftOpenRightClosed(final double lowerBound, final double upperBound)
  106.     {
  107.         return createLeftOpenRightClosed(lowerBound, upperBound);
  108.     }

  109.     /**
  110.      * Creates a dual bound <i>excluding</i> the lower bound and <i>including</i> the upper bound;
  111.      * {@code lowerBound < value <= upperBound}.
  112.      * @param lowerBound T; lower bound value
  113.      * @param upperBound T; upper bound value
  114.      * @param <T> value type
  115.      * @return dual bound; excluding the lower bound and including the upper bound
  116.      */
  117.     public static <T extends AbstractDoubleScalar<?, ?>> DualBound<T> leftOpenRightClosed(final T lowerBound,
  118.             final T upperBound)
  119.     {
  120.         return createLeftOpenRightClosed(lowerBound, upperBound);
  121.     }

  122.     /**
  123.      * Creates a dual bound <i>excluding</i> the lower bound and <i>including</i> the upper bound;
  124.      * {@code lowerBound < value <= upperBound}.
  125.      * @param lowerBound T; lower bound value
  126.      * @param upperBound T; upper bound value
  127.      * @param <T> value type
  128.      * @return dual bound; excluding the lower bound and including the upper bound
  129.      */
  130.     private static <T extends Number> DualBound<T> createLeftOpenRightClosed(final T lowerBound, final T upperBound)
  131.     {
  132.         checkSeparation(lowerBound, upperBound);
  133.         return new DualBound<>(new LowerBoundExclusive<>(lowerBound), new UpperBoundInclusive<>(upperBound),
  134.                 String.format("Value is not greater than %s and smaller than or equal to %s", lowerBound, upperBound));
  135.     }

  136.     /**
  137.      * Creates a dual bound <i>including</i> the lower bound and <i>excluding</i> the upper bound;
  138.      * {@code lowerBound <= value < upperBound}.
  139.      * @param lowerBound double; lower bound value
  140.      * @param upperBound double; upper bound value
  141.      * @return dual bound; including the lower bound and excluding the upper bound
  142.      */
  143.     public static DualBound<Double> leftClosedRightOpen(final double lowerBound, final double upperBound)
  144.     {
  145.         return createLeftClosedRightOpen(lowerBound, upperBound);
  146.     }

  147.     /**
  148.      * Creates a dual bound <i>including</i> the lower bound and <i>excluding</i> the upper bound;
  149.      * {@code lowerBound <= value < upperBound}.
  150.      * @param lowerBound T; lower bound value
  151.      * @param upperBound T; upper bound value
  152.      * @param <T> value type
  153.      * @return dual bound; including the lower bound and excluding the upper bound
  154.      */
  155.     public static <T extends AbstractDoubleScalar<?, ?>> DualBound<T> leftClosedRightOpen(final T lowerBound,
  156.             final T upperBound)
  157.     {
  158.         return createLeftClosedRightOpen(lowerBound, upperBound);
  159.     }

  160.     /**
  161.      * Creates a dual bound <i>including</i> the lower bound and <i>excluding</i> the upper bound;
  162.      * {@code lowerBound <= value < upperBound}.
  163.      * @param lowerBound T; lower bound value
  164.      * @param upperBound T; upper bound value
  165.      * @param <T> value type
  166.      * @return dual bound; including the lower bound and excluding the upper bound
  167.      */
  168.     private static <T extends Number> DualBound<T> createLeftClosedRightOpen(final T lowerBound, final T upperBound)
  169.     {
  170.         checkSeparation(lowerBound, upperBound);
  171.         return new DualBound<>(new LowerBoundInclusive<>(lowerBound), new UpperBoundExclusive<>(upperBound),
  172.                 String.format("Value is not greater than or equal to %s and smaller than %s", lowerBound, upperBound));
  173.     }

  174.     /**
  175.      * Checks whether both values for the bounds are positively separated. This should not be used for a closed interval where
  176.      * equal bounds can be accepted.
  177.      * @param lowerBound T; lower bound value
  178.      * @param upperBound T; upper bound value
  179.      * @throws IllegalArgumentException if the bound values are not positively separated
  180.      * @param <T> value type
  181.      */
  182.     private static <T extends Number> void checkSeparation(final T lowerBound, final T upperBound)
  183.     {
  184.         Throw.when(lowerBound.doubleValue() >= upperBound.doubleValue(), IllegalArgumentException.class,
  185.                 "Lower bound must be smaller than the upper bound.");
  186.     }

  187.     /**
  188.      * Constructor.
  189.      * @param lowerBound Bound; lower bound
  190.      * @param upperBound Bound; upper bound
  191.      * @param failMessage String; message about values that do not comply with the bound
  192.      */
  193.     private DualBound(final Bound lowerBound, final Bound upperBound, final String failMessage)
  194.     {
  195.         super(lowerBound, failMessage);
  196.         this.upperBound = upperBound;
  197.     }

  198.     /** {@inheritDoc} */
  199.     @Override
  200.     public boolean accept(final T value)
  201.     {
  202.         return super.accept(value) && this.upperBound.accept(value);
  203.     }

  204.     /** {@inheritDoc} */
  205.     @Override
  206.     public String toString()
  207.     {
  208.         return "DualBound [" + this.getBound() + ", " + this.upperBound + "]";
  209.     }

  210. }