View Javadoc
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    *      https://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  /*
19   * This is not the original file distributed by the Apache Software Foundation
20   * It has been modified by the Hipparchus project
21   */
22  package org.hipparchus.random;
23  
24  import org.hipparchus.util.FastMath;
25  import org.junit.jupiter.api.Test;
26  
27  import static org.junit.jupiter.api.Assertions.assertEquals;
28  import static org.junit.jupiter.api.Assertions.assertTrue;
29  
30  class UnitSphereRandomVectorGeneratorTest {
31      /**
32       * Test the distribution of points from {@link UnitSphereRandomVectorGenerator#nextVector()}
33       * in two dimensions.
34       */
35      @Test
36      void test2DDistribution() {
37  
38          RandomGenerator rg = new JDKRandomGenerator();
39          rg.setSeed(17399225432l);
40          UnitSphereRandomVectorGenerator generator = new UnitSphereRandomVectorGenerator(2, rg);
41  
42          // In 2D, angles with a given vector should be uniformly distributed
43          int[] angleBuckets = new int[100];
44          int steps = 1000000;
45          for (int i = 0; i < steps; ++i) {
46              final double[] v = generator.nextVector();
47              assertEquals(2, v.length);
48              assertEquals(1, length(v), 1e-10);
49              // Compute angle formed with vector (1,0)
50              // Cosine of angle is their dot product, because both are unit length
51              // Dot product here is just the first element of the vector by construction
52              final double angle = FastMath.acos(v[0]);
53              final int bucket = (int) (angleBuckets.length * (angle / FastMath.PI));
54              ++angleBuckets[bucket];
55          }
56  
57          // Simplistic test for roughly even distribution
58          final int expectedBucketSize = steps / angleBuckets.length;
59          for (int bucket : angleBuckets) {
60              assertTrue(FastMath.abs(expectedBucketSize - bucket) < 350,
61                                "Bucket count " + bucket + " vs expected " + expectedBucketSize);
62          }
63      }
64  
65      /**
66       * @return length (L2 norm) of given vector
67       */
68      private static double length(double[] vector) {
69          double total = 0;
70          for (double d : vector) {
71              total += d * d;
72          }
73          return FastMath.sqrt(total);
74      }
75  }