NormalDistribution.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.math.statistics.Φ;
025 import static org.jenetics.internal.math.statistics.φ;
026 import static org.jenetics.internal.util.object.eq;
027 import static org.jenetics.internal.util.object.nonNegative;
028 
029 import java.io.Serializable;
030 import java.util.Locale;
031 
032 import org.jenetics.internal.util.HashBuilder;
033 
034 import org.jenetics.util.Function;
035 import org.jenetics.util.Range;
036 
037 /**
038  * Normal (Gaussian) distribution. With
039  *
040  <p>
041  <img
042  *     src="doc-files/normal-pdf.gif"
043  *     alt="f(x)=\frac{1}{\sqrt{2\pi \sigma^{2}}}\cdot
044  *          e^{-\frac{(x-\mu)^2}{2\sigma^{2}}})"
045  * >
046  </p>
047  * as <i>pdf</i> and
048  <p>
049  <img
050  *     src="doc-files/normal-cdf.gif"
051  *     alt="f(x)=\frac{1}{2}\cdot \left [ 1 + \textup{erf} \left(
052  *          \frac{x - \mu }{\sqrt{2\sigma^{2}}} \right) \right ]"
053  * >
054  </p>
055  * as <i>cdf</i>.
056  *
057  @see <a href="http://en.wikipedia.org/wiki/Normal_distribution">Normal distribution</a>
058  *
059  @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
060  @since 1.0
061  @version 2.0 &mdash; <em>$Date: 2014-03-28 $</em>
062  */
063 public class NormalDistribution<
064     extends Number & Comparable<? super N>
065 >
066     implements Distribution<N>
067 {
068 
069     /**
070      <p>
071      <img
072      *     src="doc-files/normal-pdf.gif"
073      *     alt="f(x)=\frac{1}{\sqrt{2\pi \sigma^{2}}}\cdot
074      *          e^{-\frac{(x-\mu)^2}{2\sigma^{2}}})"
075      * >
076      </p>
077      *
078      @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
079      @since 1.0
080      @version 1.0 &mdash; <em>$Date: 2014-03-28 $</em>
081      */
082     static final class PDF<N extends Number & Comparable<? super N>>
083         implements
084             Function<N, Double>,
085             Serializable
086     {
087         private static final long serialVersionUID = 2L;
088 
089         private final Range<N> _domain;
090         private final double _mean;
091         private final double _var;
092         private final double _stddev;
093 
094         public PDF(final Range<N> domain, final double mean, final double var) {
095             _domain = domain;
096             _mean = mean;
097             _var = var;
098             _stddev = Math.sqrt(var);
099         }
100 
101         @Override
102         public Double apply(final N value) {
103             final double x = value.doubleValue();
104 
105             double result = 0.0;
106             if (_domain.contains(value)) {
107                 result = φ(x, _mean, _stddev);
108             }
109 
110             return result;
111         }
112 
113         @Override
114         public String toString() {
115             return format(
116                 Locale.ENGLISH,
117                 "p(x) = N[µ=%f, σ²=%f](x)", _mean, _var
118             );
119         }
120 
121     }
122 
123     /**
124      <p>
125      <img
126      *     src="doc-files/normal-cdf.gif"
127      *     alt="f(x)=\frac{1}{2}\cdot \left [ 1 + \textup{erf} \left(
128      *          \frac{x - \mu }{\sqrt{2\sigma^{2}}} \right) \right ]"
129      * >
130      </p>
131      *
132      @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
133      @since 1.0
134      @version 1.0 &mdash; <em>$Date: 2014-03-28 $</em>
135      */
136     static final class CDF<N extends Number & Comparable<? super N>>
137         implements
138             Function<N, Double>,
139             Serializable
140     {
141         private static final long serialVersionUID = 2L;
142 
143         private final double _min;
144         private final double _max;
145         private final double _mean;
146         private final double _var;
147         private final double _stddev;
148 
149         public CDF(final Range<N> domain, final double mean, final double var) {
150             _min = domain.getMin().doubleValue();
151             _max = domain.getMax().doubleValue();
152             _mean = mean;
153             _var = var;
154             _stddev = Math.sqrt(var);
155         }
156 
157         @Override
158         public Double apply(final N value) {
159             final double x = value.doubleValue();
160 
161             double result = 0.0;
162             if (x < _min) {
163                 result = 0.0;
164             else if (x > _max) {
165                 result = 1.0;
166             else {
167                 result = Φ(x, _mean, _stddev);
168             }
169 
170             return result;
171         }
172 
173         @Override
174         public String toString() {
175             return format(
176                 Locale.ENGLISH,
177                 "P(x) = 1/2(1 + erf((x - %f)/(sqrt(2·%f))))",
178                 _mean, _var
179             );
180         }
181 
182     }
183 
184     private final Range<N> _domain;
185     private final Function<N, Double> _cdf;
186     private final Function<N, Double> _pdf;
187     private final double _mean;
188     private final double _var;
189 
190     /**
191      * Create a new normal distribution object.
192      *
193      @param domain the domain of the distribution.
194      @param mean the mean value of the normal distribution.
195      @param var the variance of the normal distribution.
196      @throws NullPointerException if the {@code domain} is {@code null}.
197      @throws IllegalArgumentException if the variance is negative.
198      */
199     public NormalDistribution(
200         final Range<N> domain,
201         final double mean,
202         final double var
203     ) {
204         _domain = requireNonNull(domain, "Domain");
205         _mean = mean;
206         _var = nonNegative(var, "Variance");
207 
208         _pdf = new PDF<>(_domain, _mean, _var);
209         _cdf = new CDF<>(_domain, _mean, _var);
210     }
211 
212     @Override
213     public Range<N> getDomain() {
214         return _domain;
215     }
216 
217     /**
218      * Return a new CDF object.
219      *
220      <p>
221      <img
222      *     src="doc-files/normal-cdf.gif"
223      *     alt="f(x)=\frac{1}{2}\cdot \left [ 1 + \textup{erf} \left(
224      *          \frac{x - \mu }{\sqrt{2\sigma^{2}}} \right) \right ]"
225      * >
226      </p>
227      */
228     @Override
229     public Function<N, Double> getCDF() {
230         return _cdf;
231     }
232 
233     /**
234      * Return a new PDF object.
235      *
236      <p>
237      <img
238      *     src="doc-files/normal-pdf.gif"
239      *     alt="f(x)=\frac{1}{\sqrt{2\pi \sigma^{2}}}\cdot e^{-\frac{(x-\mu)^2}{2\sigma^{2}}})"
240      * >
241      </p>
242      */
243     @Override
244     public Function<N, Double> getPDF() {
245         return _pdf;
246     }
247 
248     @Override
249     public int hashCode() {
250         return HashBuilder.of(getClass()).and(_domain).and(_mean).and(_var).value();
251     }
252 
253     @Override
254     public boolean equals(final Object obj) {
255         if (obj == this) {
256             return true;
257         }
258         if (obj == null || obj.getClass() != getClass()) {
259             return false;
260         }
261 
262         final NormalDistribution<?> dist = (NormalDistribution<?>)obj;
263         return eq(_domain, dist._domain&&
264                 eq(_mean, dist._mean&&
265                 eq(_var, dist._var);
266     }
267 
268     @Override
269     public String toString() {
270         return format("N[µ=%f, σ²=%f]", _mean, _var);
271     }
272 
273 }