TriangularDistribution.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      https://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */

  17. /*
  18.  * This is not the original file distributed by the Apache Software Foundation
  19.  * It has been modified by the Hipparchus project
  20.  */

  21. package org.hipparchus.distribution.continuous;

  22. import org.hipparchus.exception.LocalizedCoreFormats;
  23. import org.hipparchus.exception.MathIllegalArgumentException;
  24. import org.hipparchus.util.FastMath;
  25. import org.hipparchus.util.MathUtils;

  26. /**
  27.  * Implementation of the triangular real distribution.
  28.  *
  29.  * @see <a href="http://en.wikipedia.org/wiki/Triangular_distribution">
  30.  * Triangular distribution (Wikipedia)</a>
  31.  */
  32. public class TriangularDistribution extends AbstractRealDistribution {
  33.     /** Serializable version identifier. */
  34.     private static final long serialVersionUID = 20120112L;
  35.     /** Lower limit of this distribution (inclusive). */
  36.     private final double a;
  37.     /** Upper limit of this distribution (inclusive). */
  38.     private final double b;
  39.     /** Mode of this distribution. */
  40.     private final double c;

  41.     /**
  42.      * Creates a triangular real distribution using the given lower limit,
  43.      * upper limit, and mode.
  44.      *
  45.      * @param a Lower limit of this distribution (inclusive).
  46.      * @param b Upper limit of this distribution (inclusive).
  47.      * @param c Mode of this distribution.
  48.      * @throws MathIllegalArgumentException if {@code a >= b} or if {@code c > b}.
  49.      * @throws MathIllegalArgumentException if {@code c < a}.
  50.      */
  51.     public TriangularDistribution(double a, double c, double b)
  52.         throws MathIllegalArgumentException {
  53.         super();

  54.         if (a >= b) {
  55.             throw new MathIllegalArgumentException(
  56.                             LocalizedCoreFormats.LOWER_BOUND_NOT_BELOW_UPPER_BOUND,
  57.                             a, b, false);
  58.         }
  59.         if (c < a) {
  60.             throw new MathIllegalArgumentException(
  61.                     LocalizedCoreFormats.NUMBER_TOO_SMALL, c, a, true);
  62.         }
  63.         if (c > b) {
  64.             throw new MathIllegalArgumentException(
  65.                     LocalizedCoreFormats.NUMBER_TOO_LARGE, c, b, true);
  66.         }

  67.         this.a = a;
  68.         this.c = c;
  69.         this.b = b;
  70.     }

  71.     /**
  72.      * Returns the mode {@code c} of this distribution.
  73.      *
  74.      * @return the mode {@code c} of this distribution
  75.      */
  76.     public double getMode() {
  77.         return c;
  78.     }

  79.     /**
  80.      * {@inheritDoc}
  81.      *
  82.      * For lower limit {@code a}, upper limit {@code b} and mode {@code c}, the
  83.      * PDF is given by
  84.      * <ul>
  85.      * <li>{@code 2 * (x - a) / [(b - a) * (c - a)]} if {@code a <= x < c},</li>
  86.      * <li>{@code 2 / (b - a)} if {@code x = c},</li>
  87.      * <li>{@code 2 * (b - x) / [(b - a) * (b - c)]} if {@code c < x <= b},</li>
  88.      * <li>{@code 0} otherwise.
  89.      * </ul>
  90.      */
  91.     @Override
  92.     public double density(double x) {
  93.         if (x < a) {
  94.             return 0;
  95.         }
  96.         if (a <= x && x < c) {
  97.             double divident = 2 * (x - a);
  98.             double divisor = (b - a) * (c - a);
  99.             return divident / divisor;
  100.         }
  101.         if (x == c) {
  102.             return 2 / (b - a);
  103.         }
  104.         if (c < x && x <= b) {
  105.             double divident = 2 * (b - x);
  106.             double divisor = (b - a) * (b - c);
  107.             return divident / divisor;
  108.         }
  109.         return 0;
  110.     }

  111.     /**
  112.      * {@inheritDoc}
  113.      *
  114.      * For lower limit {@code a}, upper limit {@code b} and mode {@code c}, the
  115.      * CDF is given by
  116.      * <ul>
  117.      * <li>{@code 0} if {@code x < a},</li>
  118.      * <li>{@code (x - a)^2 / [(b - a) * (c - a)]} if {@code a <= x < c},</li>
  119.      * <li>{@code (c - a) / (b - a)} if {@code x = c},</li>
  120.      * <li>{@code 1 - (b - x)^2 / [(b - a) * (b - c)]} if {@code c < x <= b},</li>
  121.      * <li>{@code 1} if {@code x > b}.</li>
  122.      * </ul>
  123.      */
  124.     @Override
  125.     public double cumulativeProbability(double x)  {
  126.         if (x < a) {
  127.             return 0;
  128.         }
  129.         if (a <= x && x < c) {
  130.             double divident = (x - a) * (x - a);
  131.             double divisor = (b - a) * (c - a);
  132.             return divident / divisor;
  133.         }
  134.         if (x == c) {
  135.             return (c - a) / (b - a);
  136.         }
  137.         if (c < x && x <= b) {
  138.             double divident = (b - x) * (b - x);
  139.             double divisor = (b - a) * (b - c);
  140.             return 1 - (divident / divisor);
  141.         }
  142.         return 1;
  143.     }

  144.     /**
  145.      * {@inheritDoc}
  146.      *
  147.      * For lower limit {@code a}, upper limit {@code b}, and mode {@code c},
  148.      * the mean is {@code (a + b + c) / 3}.
  149.      */
  150.     @Override
  151.     public double getNumericalMean() {
  152.         return (a + b + c) / 3;
  153.     }

  154.     /**
  155.      * {@inheritDoc}
  156.      *
  157.      * For lower limit {@code a}, upper limit {@code b}, and mode {@code c},
  158.      * the variance is {@code (a^2 + b^2 + c^2 - a * b - a * c - b * c) / 18}.
  159.      */
  160.     @Override
  161.     public double getNumericalVariance() {
  162.         return (a * a + b * b + c * c - a * b - a * c - b * c) / 18;
  163.     }

  164.     /**
  165.      * {@inheritDoc}
  166.      *
  167.      * The lower bound of the support is equal to the lower limit parameter
  168.      * {@code a} of the distribution.
  169.      *
  170.      * @return lower bound of the support
  171.      */
  172.     @Override
  173.     public double getSupportLowerBound() {
  174.         return a;
  175.     }

  176.     /**
  177.      * {@inheritDoc}
  178.      *
  179.      * The upper bound of the support is equal to the upper limit parameter
  180.      * {@code b} of the distribution.
  181.      *
  182.      * @return upper bound of the support
  183.      */
  184.     @Override
  185.     public double getSupportUpperBound() {
  186.         return b;
  187.     }

  188.     /**
  189.      * {@inheritDoc}
  190.      *
  191.      * The support of this distribution is connected.
  192.      *
  193.      * @return {@code true}
  194.      */
  195.     @Override
  196.     public boolean isSupportConnected() {
  197.         return true;
  198.     }

  199.     /** {@inheritDoc} */
  200.     @Override
  201.     public double inverseCumulativeProbability(double p)
  202.         throws MathIllegalArgumentException {
  203.         MathUtils.checkRangeInclusive(p, 0, 1);

  204.         if (p == 0) {
  205.             return a;
  206.         }
  207.         if (p == 1) {
  208.             return b;
  209.         }
  210.         if (p < (c - a) / (b - a)) {
  211.             return a + FastMath.sqrt(p * (b - a) * (c - a));
  212.         }
  213.         return b - FastMath.sqrt((1 - p) * (b - a) * (b - c));
  214.     }
  215. }