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