001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. 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
018 package org.apache.commons.math.random;
019
020 import org.apache.commons.math.util.FastMath;
021
022
023 /**
024 * Generate random vectors isotropically located on the surface of a sphere.
025 *
026 * @since 2.1
027 * @version $Revision: 990655 $ $Date: 2010-08-29 23:49:40 +0200 (dim. 29 ao??t 2010) $
028 */
029
030 public class UnitSphereRandomVectorGenerator
031 implements RandomVectorGenerator {
032 /**
033 * RNG used for generating the individual components of the vectors.
034 */
035 private final RandomGenerator rand;
036 /**
037 * Space dimension.
038 */
039 private final int dimension;
040
041 /**
042 * @param dimension Space dimension.
043 * @param rand RNG for the individual components of the vectors.
044 */
045 public UnitSphereRandomVectorGenerator(final int dimension,
046 final RandomGenerator rand) {
047 this.dimension = dimension;
048 this.rand = rand;
049 }
050 /**
051 * Create an object that will use a default RNG ({@link MersenneTwister}),
052 * in order to generate the individual components.
053 *
054 * @param dimension Space dimension.
055 */
056 public UnitSphereRandomVectorGenerator(final int dimension) {
057 this(dimension, new MersenneTwister());
058 }
059
060 /** {@inheritDoc} */
061 public double[] nextVector() {
062
063 final double[] v = new double[dimension];
064
065 double normSq;
066 do {
067 normSq = 0;
068 for (int i = 0; i < dimension; i++) {
069 final double comp = 2 * rand.nextDouble() - 1;
070 v[i] = comp;
071 normSq += comp * comp;
072 }
073 } while (normSq > 1);
074
075 final double f = 1 / FastMath.sqrt(normSq);
076 for (int i = 0; i < dimension; i++) {
077 v[i] *= f;
078 }
079
080 return v;
081
082 }
083
084 }