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 /* 19 * This is not the original file distributed by the Apache Software Foundation 20 * It has been modified by the Hipparchus project 21 */ 22 23 package org.hipparchus.distribution.continuous; 24 25 import org.hipparchus.exception.LocalizedCoreFormats; 26 import org.hipparchus.exception.MathIllegalArgumentException; 27 import org.hipparchus.util.FastMath; 28 import org.hipparchus.util.MathUtils; 29 30 /** 31 * Implementation of the triangular real distribution. 32 * 33 * @see <a href="http://en.wikipedia.org/wiki/Triangular_distribution"> 34 * Triangular distribution (Wikipedia)</a> 35 */ 36 public class TriangularDistribution extends AbstractRealDistribution { 37 /** Serializable version identifier. */ 38 private static final long serialVersionUID = 20120112L; 39 /** Lower limit of this distribution (inclusive). */ 40 private final double a; 41 /** Upper limit of this distribution (inclusive). */ 42 private final double b; 43 /** Mode of this distribution. */ 44 private final double c; 45 46 /** 47 * Creates a triangular real distribution using the given lower limit, 48 * upper limit, and mode. 49 * 50 * @param a Lower limit of this distribution (inclusive). 51 * @param b Upper limit of this distribution (inclusive). 52 * @param c Mode of this distribution. 53 * @throws MathIllegalArgumentException if {@code a >= b} or if {@code c > b}. 54 * @throws MathIllegalArgumentException if {@code c < a}. 55 */ 56 public TriangularDistribution(double a, double c, double b) 57 throws MathIllegalArgumentException { 58 super(); 59 60 if (a >= b) { 61 throw new MathIllegalArgumentException( 62 LocalizedCoreFormats.LOWER_BOUND_NOT_BELOW_UPPER_BOUND, 63 a, b, false); 64 } 65 if (c < a) { 66 throw new MathIllegalArgumentException( 67 LocalizedCoreFormats.NUMBER_TOO_SMALL, c, a, true); 68 } 69 if (c > b) { 70 throw new MathIllegalArgumentException( 71 LocalizedCoreFormats.NUMBER_TOO_LARGE, c, b, true); 72 } 73 74 this.a = a; 75 this.c = c; 76 this.b = b; 77 } 78 79 /** 80 * Returns the mode {@code c} of this distribution. 81 * 82 * @return the mode {@code c} of this distribution 83 */ 84 public double getMode() { 85 return c; 86 } 87 88 /** 89 * {@inheritDoc} 90 * 91 * For lower limit {@code a}, upper limit {@code b} and mode {@code c}, the 92 * PDF is given by 93 * <ul> 94 * <li>{@code 2 * (x - a) / [(b - a) * (c - a)]} if {@code a <= x < c},</li> 95 * <li>{@code 2 / (b - a)} if {@code x = c},</li> 96 * <li>{@code 2 * (b - x) / [(b - a) * (b - c)]} if {@code c < x <= b},</li> 97 * <li>{@code 0} otherwise. 98 * </ul> 99 */ 100 @Override 101 public double density(double x) { 102 if (x < a) { 103 return 0; 104 } 105 if (a <= x && x < c) { 106 double divident = 2 * (x - a); 107 double divisor = (b - a) * (c - a); 108 return divident / divisor; 109 } 110 if (x == c) { 111 return 2 / (b - a); 112 } 113 if (c < x && x <= b) { 114 double divident = 2 * (b - x); 115 double divisor = (b - a) * (b - c); 116 return divident / divisor; 117 } 118 return 0; 119 } 120 121 /** 122 * {@inheritDoc} 123 * 124 * For lower limit {@code a}, upper limit {@code b} and mode {@code c}, the 125 * CDF is given by 126 * <ul> 127 * <li>{@code 0} if {@code x < a},</li> 128 * <li>{@code (x - a)^2 / [(b - a) * (c - a)]} if {@code a <= x < c},</li> 129 * <li>{@code (c - a) / (b - a)} if {@code x = c},</li> 130 * <li>{@code 1 - (b - x)^2 / [(b - a) * (b - c)]} if {@code c < x <= b},</li> 131 * <li>{@code 1} if {@code x > b}.</li> 132 * </ul> 133 */ 134 @Override 135 public double cumulativeProbability(double x) { 136 if (x < a) { 137 return 0; 138 } 139 if (a <= x && x < c) { 140 double divident = (x - a) * (x - a); 141 double divisor = (b - a) * (c - a); 142 return divident / divisor; 143 } 144 if (x == c) { 145 return (c - a) / (b - a); 146 } 147 if (c < x && x <= b) { 148 double divident = (b - x) * (b - x); 149 double divisor = (b - a) * (b - c); 150 return 1 - (divident / divisor); 151 } 152 return 1; 153 } 154 155 /** 156 * {@inheritDoc} 157 * 158 * For lower limit {@code a}, upper limit {@code b}, and mode {@code c}, 159 * the mean is {@code (a + b + c) / 3}. 160 */ 161 @Override 162 public double getNumericalMean() { 163 return (a + b + c) / 3; 164 } 165 166 /** 167 * {@inheritDoc} 168 * 169 * For lower limit {@code a}, upper limit {@code b}, and mode {@code c}, 170 * the variance is {@code (a^2 + b^2 + c^2 - a * b - a * c - b * c) / 18}. 171 */ 172 @Override 173 public double getNumericalVariance() { 174 return (a * a + b * b + c * c - a * b - a * c - b * c) / 18; 175 } 176 177 /** 178 * {@inheritDoc} 179 * 180 * The lower bound of the support is equal to the lower limit parameter 181 * {@code a} of the distribution. 182 * 183 * @return lower bound of the support 184 */ 185 @Override 186 public double getSupportLowerBound() { 187 return a; 188 } 189 190 /** 191 * {@inheritDoc} 192 * 193 * The upper bound of the support is equal to the upper limit parameter 194 * {@code b} of the distribution. 195 * 196 * @return upper bound of the support 197 */ 198 @Override 199 public double getSupportUpperBound() { 200 return b; 201 } 202 203 /** 204 * {@inheritDoc} 205 * 206 * The support of this distribution is connected. 207 * 208 * @return {@code true} 209 */ 210 @Override 211 public boolean isSupportConnected() { 212 return true; 213 } 214 215 /** {@inheritDoc} */ 216 @Override 217 public double inverseCumulativeProbability(double p) 218 throws MathIllegalArgumentException { 219 MathUtils.checkRangeInclusive(p, 0, 1); 220 221 if (p == 0) { 222 return a; 223 } 224 if (p == 1) { 225 return b; 226 } 227 if (p < (c - a) / (b - a)) { 228 return a + FastMath.sqrt(p * (b - a) * (c - a)); 229 } 230 return b - FastMath.sqrt((1 - p) * (b - a) * (b - c)); 231 } 232 }