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