1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package org.apache.commons.rng.sampling; 19 20 import org.apache.commons.rng.UniformRandomProvider; 21 import org.apache.commons.rng.sampling.distribution.NormalizedGaussianSampler; 22 import org.apache.commons.rng.sampling.distribution.ZigguratNormalizedGaussianSampler; 23 24 /** 25 * Generate vectors <a href="http://mathworld.wolfram.com/SpherePointPicking.html"> 26 * isotropically located on the surface of a sphere</a>. 27 * 28 * @since 1.1 29 */ 30 public class UnitSphereSampler { 31 /** Sampler used for generating the individual components of the vectors. */ 32 private final NormalizedGaussianSampler sampler; 33 /** Space dimension. */ 34 private final int dimension; 35 36 /** 37 * @param dimension Space dimension. 38 * @param rng Generator for the individual components of the vectors. 39 * A shallow copy will be stored in this instance. 40 */ 41 public UnitSphereSampler(int dimension, 42 UniformRandomProvider rng) { 43 this.dimension = dimension; 44 sampler = new ZigguratNormalizedGaussianSampler(rng); 45 } 46 47 /** 48 * @return a random normalized Cartesian vector. 49 */ 50 public double[] nextVector() { 51 final double[] v = new double[dimension]; 52 53 // Pick a point by choosing a standard Gaussian for each element, 54 // and then normalize to unit length. 55 double normSq = 0; 56 for (int i = 0; i < dimension; i++) { 57 final double comp = sampler.sample(); 58 v[i] = comp; 59 normSq += comp * comp; 60 } 61 62 final double f = 1 / Math.sqrt(normSq); 63 for (int i = 0; i < dimension; i++) { 64 v[i] *= f; 65 } 66 67 return v; 68 } 69 }