001 /*
002 * Java Genetic Algorithm Library (jenetics-2.0.2).
003 * Copyright (c) 2007-2014 Franz Wilhelmstötter
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 *
017 * Author:
018 * Franz Wilhelmstötter (franz.wilhelmstoetter@gmx.at)
019 */
020 package org.jenetics.stat;
021
022 import static java.lang.String.format;
023 import static java.util.Objects.requireNonNull;
024 import static org.jenetics.internal.util.object.eq;
025
026 import java.io.Serializable;
027 import java.util.Locale;
028
029 import org.jenetics.internal.util.HashBuilder;
030
031 import org.jenetics.util.Function;
032 import org.jenetics.util.Range;
033
034
035 /**
036 * <p>This distribution has the following cdf.</p>
037 * <p><img src="doc-files/LinearDistribution.png" alt="Distribution"></p>
038 * <p>
039 * The only restriction is that the integral of the cdf must be one.
040 * </p>
041 * <p>
042 * <img src="doc-files/linear-precondition.gif"
043 * alt="\int_{x_1}^{x_2}\left(
044 * \\underset{k} {\\underbrace {\frac{y_2-y_1}{x_2-x_1}}} \cdot x +
045 * \\underset{d}{\\underbrace {y_1-\frac{y_2-y_1}{x_2-x_1}\cdot x_1}}
046 * \right)\mathrm{d}x = 1"
047 * >
048 * </p>
049 *
050 * Solving this integral leads to
051 * <p>
052 * <img src="doc-files/linear-precondition-y2.gif"
053 * alt="y_2 = -\frac{(x_2-x_1)\cdot y_1 - 2}{x_2-x_1}"
054 * >
055 * </p>
056 *
057 * for fixed values for <i>x<sub>1</sub></i>, <i>x<sub>2</sub></i> and
058 * <i>y<sub>1</sub></i>.
059 * <p>
060 * If the value of <i>y<sub>2</sub></i> < 0, the value of <i>x<sub>2</sub></i>
061 * is decreased so that the resulting triangle (<i>x<sub>1</sub></i>,0),
062 * (<i>x<sub>1</sub></i>,<i>y<sub>1</sub></i>), (<i>x<sub>2</sub></i>,0) has
063 * an area of <i>one</i>.
064 * </p>
065 *
066 * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
067 * @since 1.0
068 * @version 2.0 — <em>$Date: 2014-03-28 $</em>
069 */
070 public class LinearDistribution<
071 N extends Number & Comparable<? super N>
072 >
073 implements Distribution<N>
074 {
075
076 /**
077 * <p>
078 * <img
079 * src="doc-files/linear-pdf.gif"
080 * alt="f(x) = \left(
081 * \frac{y_2-y_1}{x_2-x_1} \cdot x +
082 * y_1-\frac{y_2-y_1}{x_2-x_1}\cdot x_1
083 * \right)"
084 * >
085 * </p>
086 *
087 * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
088 * @since 1.0
089 * @version 2.0 — <em>$Date: 2014-03-28 $</em>
090 */
091 static final class PDF<N extends Number & Comparable<? super N>>
092 implements
093 Function<N, Double>,
094 Serializable
095 {
096 private static final long serialVersionUID = 2L;
097
098 private final double _min;
099 private final double _max;
100 private final double _k;
101 private final double _d;
102
103 public PDF(
104 final double x1, final double y1,
105 final double x2, final double y2
106 ) {
107 _min = x1;
108 _max = x2;
109 _k = (y2 - y1)/(x2 - x1);
110 _d = y1 - _k*x1;
111 }
112
113 @Override
114 public Double apply(final N value) {
115 final double x = value.doubleValue();
116
117 double result = 0.0;
118 if (x >= _min && x <= _max) {
119 result = _k*x + _d;
120 }
121
122 return result;
123 }
124
125 @Override
126 public String toString() {
127 return format(Locale.ENGLISH, "p(x) = %f·x + %f", _k, _d);
128 }
129
130 }
131
132 /**
133 * <p>
134 * <img
135 * src="doc-files/linear-cdf.gif"
136 * alt="f(x)=-\frac{(x^2-2x_2x)y_1 - (x^2 - 2x_1x)y_2}
137 * {2(x_2 - x_1)}"
138 * >
139 * </p>
140 *
141 * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
142 * @since 1.0
143 * @version 2.0 — <em>$Date: 2014-03-28 $</em>
144 */
145 static final class CDF<N extends Number & Comparable<? super N>>
146 implements
147 Function<N, Double>,
148 Serializable
149 {
150 private static final long serialVersionUID = 2L;
151
152 private final double _x1;
153 private final double _x2;
154
155 private final double _k;
156 private final double _d;
157
158 public CDF(
159 final double x1, final double y1,
160 final double x2, final double y2
161 ) {
162 _x1 = x1;
163 _x2 = x2;
164 _k = (y2 - y1)/(x2 - x1);
165 _d = y1 - _k*x1;
166 }
167
168 @Override
169 public Double apply(final N value) {
170 final double x = value.doubleValue();
171
172 double result = 0;
173 if (x < _x1) {
174 result = 0.0;
175 } else if (x > _x2) {
176 result = 1.0;
177 } else {
178 // result = Double.valueOf(
179 // -((x*x - 2*x*_x2)*_y1 - (x*x - 2*x*_x1)*_y2)/
180 // (2*(_x2 - _x1))
181 // );
182 result = _k*x*x/2.0 + _d*x;
183 }
184
185 return result;
186 }
187
188 @Override
189 public String toString() {
190 return format(Locale.ENGLISH, "P(x) = %f·x² - %f·x", _k/2.0, _d);
191 }
192
193 }
194
195
196 private final Range<N> _domain;
197 private final Function<N, Double> _cdf;
198 private final Function<N, Double> _pdf;
199
200 private final double _x1;
201 private final double _x2;
202 private final double _y1;
203 private final double _y2;
204
205 public LinearDistribution(final Range<N> domain, final double y1) {
206 _domain = requireNonNull(domain);
207
208 _y1 = Math.max(y1, 0.0);
209 _x1 = domain.getMin().doubleValue();
210 _y2 = Math.max(y2(_x1, domain.getMax().doubleValue(), y1), 0.0);
211 if (_y2 == 0) {
212 _x2 = 2.0/_y1 + _x1;
213 } else {
214 _x2 = domain.getMax().doubleValue();
215 }
216
217 _cdf = new CDF<>(_x1, _y1, _x2, _y2);
218 _pdf = new PDF<>(_x1, _y1, _x2, _y2);
219 }
220
221 private static double y2(final double x1, final double x2, final double y1) {
222 return -((x2 - x1)*y1 - 2)/(x2 - x1);
223 }
224
225 @Override
226 public Range<N> getDomain() {
227 return _domain;
228 }
229
230 /**
231 * Return a new CDF object.
232 *
233 * <p>
234 * <img
235 * src="doc-files/linear-cdf.gif"
236 * alt="f(x)=-\frac{(x^2-2x_2x)y_1 - (x^2 - 2x_1x)y_2}
237 * {2(x_2 - x_1)}"
238 * >
239 * </p>
240 *
241 */
242 @Override
243 public Function<N, Double> getCDF() {
244 return _cdf;
245 }
246
247 /**
248 * Return a new PDF object.
249 *
250 * <p>
251 * <img
252 * src="doc-files/linear-pdf.gif"
253 * alt="f(x) = \left(
254 * \frac{y_2-y_1}{x_2-x_1} \cdot x +
255 * y_1-\frac{y_2-y_1}{x_2-x_1}\cdot x_1
256 * \right)"
257 * >
258 * </p>
259 *
260 */
261 @Override
262 public Function<N, Double> getPDF() {
263 return _pdf;
264 }
265
266 @Override
267 public int hashCode() {
268 return HashBuilder.of(getClass()).
269 and(_domain).
270 and(_x1).and(_x2).
271 and(_y1).and(_y2).value();
272 }
273
274 @Override
275 public boolean equals(final Object obj) {
276 if (obj == this) {
277 return true;
278 }
279 if (obj == null || getClass() != obj.getClass()) {
280 return false;
281 }
282
283 final LinearDistribution<?> dist = (LinearDistribution<?>)obj;
284 return eq(_domain, dist._domain) &&
285 eq(_x1, dist._x1) && eq(_x2, dist._x2) &&
286 eq(_y1, dist._y1) && eq(_y2, dist._y2);
287 }
288
289 @Override
290 public String toString() {
291 return format(
292 "LinearDistribution[(%f, %f), (%f, %f)]",
293 _x1, _y1, _x2, _y2
294 ) ;
295 }
296
297 }
|