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