LinearDistribution.java
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> &lt; 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 &mdash; <em>$Date: 2014-03-28 $</em>
069  */
070 public class LinearDistribution<
071     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 &mdash; <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 &mdash; <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 }