Skip to content

Commit

Permalink
Refactoring of PolarGaussian and misc documentation updates (#144)
Browse files Browse the repository at this point in the history
* update zenodo config with arixv report

* update citation.cff with arxiv report

* Update pom.xml

* Update README.md

* updated report citation

* Update README.md

* documentation update

* fixed links

* Update CHANGELOG.md

* Update CHANGELOG.md

* refactor to reduce redundancy

* Update CHANGELOG.md
  • Loading branch information
cicirello authored May 31, 2024
1 parent 8fb45b2 commit 6658727
Show file tree
Hide file tree
Showing 11 changed files with 113 additions and 51 deletions.
20 changes: 14 additions & 6 deletions .zenodo.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,18 @@
}
],
"keywords": [
"Ziggurat",
"Gaussian",
"Java",
"normal distribution",
"pseudorandom numbers"
]
"Ziggurat",
"Gaussian",
"Java",
"normal distribution",
"pseudorandom numbers"
],
"related_identifiers": [
{
"scheme": "doi",
"identifier": "10.48550/arXiv.2405.19493",
"relation": "isDocumentedBy",
"resource_type": "publication"
}
]
}
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased] - 2023-10-01
## [Unreleased] - 2024-05-31

### Added

Expand All @@ -16,12 +16,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* Removed support for importing from JitPack.

### Fixed
* Refactored loop in PolarGaussian based on SpotBugs report.
* Refactored PolarGaussian to eliminate redundant code between Random and SplittableRandom cases.

### CI/CD
* Integrated SpotBugs into build process.
* Integrated FindSecBugs into build process.

### Other
* Updated documentation.


## [1.0.5] - 2022-12-01
Expand Down
13 changes: 9 additions & 4 deletions CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,17 @@ preferred-citation:
- family-names: "Cicirello"
given-names: "Vincent A"
orcid: "https://orcid.org/0000-0003-1072-8559"
institution: "Cicirello.org"
doi: "10.48550/arXiv.2405.19493"
month: 5
year: 2024
title: "Fast Gaussian Distributed Pseudorandom Number Generation in Java via the Ziggurat Algorithm"
url: "https://reports.cicirello.org/24/009/"
identifiers:
- type: other
value: "ALG-24-009"
description: "Technical Report"
value: "arXiv:2405.19493"
description: "arXiv preprint"
- type: doi
value: 10.48550/arXiv.2405.19493
description: "The DOI of the report"
- type: url
value: "https://reports.cicirello.org/24/009/ALG-24-009.pdf"
description: "A full-text pdf of the report"
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ number generators as well as for `SplittableRandom`. The other legacy generators
still use the slow polar method, however. This report explores how and where our
ziggurat library is still relevant in Java 17.

> Vincent A. Cicirello. 2024. [Fast Gaussian Distributed Pseudorandom Number Generation in Java via the Ziggurat Algorithm](https://reports.cicirello.org/24/009/). Technical Report ALG-24-009, Cicirello.org, May 2024. [[PDF]](https://reports.cicirello.org/24/009/ALG-24-009.pdf)
> Vincent A. Cicirello. 2024. [Fast Gaussian Distributed Pseudorandom Number Generation in Java via the Ziggurat Algorithm](https://reports.cicirello.org/24/009/). arXiv:[2405.19493](https://arxiv.org/abs/2405.19493), May 2024. doi:[10.48550/arXiv.2405.19493](https://doi.org/10.48550/arXiv.2405.19493). [[PDF]](https://reports.cicirello.org/24/009/ALG-24-009.pdf)
You can find some additional experimental data comparing the performance of a sequential
genetic algorithm (GA) using this implementation of the Ziggurat method for
Expand Down
2 changes: 1 addition & 1 deletion experiment/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ library, sample code, and other misc items, as follows.

The code in the directory [timing17](timing17) can be used to reproduce the experiments of the following paper, which among other things explores the relevance of the library for Java 17+:

> Vincent A. Cicirello. 2024. [Fast Gaussian Distributed Pseudorandom Number Generation in Java via the Ziggurat Algorithm](https://reports.cicirello.org/24/009/). Technical Report ALG-24-009, Cicirello.org, May 2024. [[PDF]](https://reports.cicirello.org/24/009/ALG-24-009.pdf)
> Vincent A. Cicirello. 2024. [Fast Gaussian Distributed Pseudorandom Number Generation in Java via the Ziggurat Algorithm](https://reports.cicirello.org/24/009/). arXiv:[2405.19493](https://arxiv.org/abs/2405.19493), May 2024. doi:[10.48550/arXiv.2405.19493](https://doi.org/10.48550/arXiv.2405.19493). [[PDF]](https://reports.cicirello.org/24/009/ALG-24-009.pdf)
## Which Gaussian Algorithm Does Java Use

Expand Down
2 changes: 1 addition & 1 deletion experiment/timing17/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

The code in this directory can be used to reproduce the experiments of the following paper:

> Vincent A. Cicirello. 2024. [Fast Gaussian Distributed Pseudorandom Number Generation in Java via the Ziggurat Algorithm](https://reports.cicirello.org/24/009/). Technical Report ALG-24-009, Cicirello.org, May 2024. [[PDF]](https://reports.cicirello.org/24/009/ALG-24-009.pdf)
> Vincent A. Cicirello. 2024. [Fast Gaussian Distributed Pseudorandom Number Generation in Java via the Ziggurat Algorithm](https://reports.cicirello.org/24/009/). arXiv:[2405.19493](https://arxiv.org/abs/2405.19493), May 2024. doi:[10.48550/arXiv.2405.19493](https://doi.org/10.48550/arXiv.2405.19493). [[PDF]](https://reports.cicirello.org/24/009/ALG-24-009.pdf)
## Building with Maven

Expand Down
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
<distribution>repo</distribution>
<comments>
Ziggurat Gaussian.
Copyright (C) 2019-2023 Vincent A. Cicirello.
Copyright (C) 2019-2024 Vincent A. Cicirello.

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -271,7 +271,7 @@
<author>true</author>
<version>false</version>
<notimestamp>true</notimestamp>
<bottom><![CDATA[Copyright &copy; 2019-2023 <a href=\"https://www.cicirello.org/\" target=_top>Vincent A. Cicirello</a>. All rights reserved.]]></bottom>
<bottom><![CDATA[Copyright &copy; 2019-2024 <a href=\"https://www.cicirello.org/\" target=_top>Vincent A. Cicirello</a>. All rights reserved.]]></bottom>
</configuration>
</plugin>
<plugin>
Expand Down
39 changes: 14 additions & 25 deletions src/main/java/org/cicirello/math/rand/PolarGaussian.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Java implementation of the Polar Method
* for generating Gaussian distributed random numbers.
*
* Copyright 2015, 2017-2020, 2022 Vincent A. Cicirello, <https://www.cicirello.org/>.
* Copyright 2015, 2017-2024 Vincent A. Cicirello, <https://www.cicirello.org/>.
*
* This program is free software: you can
* redistribute it and/or modify it under the terms of the GNU
Expand All @@ -26,6 +26,7 @@
import java.util.Random;
import java.util.SplittableRandom;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.DoubleSupplier;

/**
* This class provides methods for generating pseudorandom numbers from a Gaussian distribution
Expand Down Expand Up @@ -130,23 +131,7 @@ public static double nextGaussian() {
* @return A random number from a Gaussian distribution with mean 0 and standard deviation 1.
*/
public static double nextGaussian(Random r) {
Double next = nextG.get();
if (next != null) {
nextG.set(null);
return next;
} else {
double v1 = 0;
double v2 = 0;
double s = 0;
while (s >= 1 || s == 0) {
v1 = 2 * r.nextDouble() - 1;
v2 = 2 * r.nextDouble() - 1;
s = v1 * v1 + v2 * v2;
}
double m = StrictMath.sqrt(-2 * StrictMath.log(s) / s);
nextG.set(v2 * m);
return v1 * m;
}
return nextGaussian(r::nextDouble);
}

/**
Expand All @@ -156,19 +141,23 @@ public static double nextGaussian(Random r) {
* @return A random number from a Gaussian distribution with mean 0 and standard deviation 1.
*/
public static double nextGaussian(SplittableRandom r) {
return nextGaussian(r::nextDouble);
}

static double nextGaussian(DoubleSupplier r) {
Double next = nextG.get();
if (next != null) {
nextG.set(null);
return next;
} else {
double v1 = 0;
double v2 = 0;
double s = 0;
while (s >= 1 || s == 0) {
v1 = 2 * r.nextDouble() - 1;
v2 = 2 * r.nextDouble() - 1;
double v1;
double v2;
double s;
do {
v1 = 2 * r.getAsDouble() - 1;
v2 = 2 * r.getAsDouble() - 1;
s = v1 * v1 + v2 * v2;
}
} while (s >= 1 || s == 0);
double m = StrictMath.sqrt(-2 * StrictMath.log(s) / s);
nextG.set(v2 * m);
return v1 * m;
Expand Down
27 changes: 19 additions & 8 deletions src/main/java/org/cicirello/math/rand/ZigguratGaussian.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* of the Ziggurat method for generating Gaussian distributed
* random numbers.
*
* Copyright 2015, 2017-2022 Vincent A. Cicirello, <https://www.cicirello.org/>.
* Copyright 2015, 2017-2024 Vincent A. Cicirello, <https://www.cicirello.org/>.
*
* This program is free software: you can
* redistribute it and/or modify it under the terms of the GNU
Expand Down Expand Up @@ -62,14 +62,25 @@
* <p>This Java implementation originated as part of an effort to speed up the runtime of a parallel
* genetic algorithm (PGA). The PGA in question evolved its control parameters (i.e., crossover and
* mutation rates, etc) using Gaussian mutation. The only Gaussian implementation within the Java
* API is the polar method (nextGaussian method of the {@link Random} and {@link ThreadLocalRandom}
* classes, however the polar method is quite slow relative to other newer available alternatives,
* such as the Ziggurat method.
* API (pre-Java 17) is the polar method (nextGaussian method of the {@link Random} and {@link
* ThreadLocalRandom} classes, however the polar method is quite slow relative to other newer
* available alternatives, such as the Ziggurat method.
*
* <p>You can find some experimental data comparing the performance of a sequential genetic
* algorithm (GA) using this implementation of the Ziggurat method for Gaussian mutation vs using
* the more common polar method, as well as experimental data for the same comparison but with a
* PGA, in the following paper:
* <p>You can find information on when this ziggurat implementation is likely advantageous,
* including results of experiments in the following report:
*
* <ul>
* <li>Vincent A. Cicirello. 2024. <a href="https://reports.cicirello.org/24/009/">Fast Gaussian
* Distributed Pseudorandom Number Generation in Java via the Ziggurat Algorithm</a>. arXiv:<a
* href="https://arxiv.org/abs/2405.19493">2405.19493</a>, May 2024. doi:<a
* href="https://doi.org/10.48550/arXiv.2405.19493">10.48550/arXiv.2405.19493</a>. <a
* href="https://reports.cicirello.org/24/009/ALG-24-009.pdf">[PDF]</a>
* </ul>
*
* <p>You can find some additional experimental data comparing the performance of a sequential
* genetic algorithm (GA) using this implementation of the Ziggurat method for Gaussian mutation vs
* using the more common polar method, as well as experimental data for the same comparison but with
* a PGA, in the following paper:
*
* <ul>
* <li>V. A. Cicirello. <a href=https://www.cicirello.org/publications/cicirello2018flairs.html
Expand Down
13 changes: 12 additions & 1 deletion src/main/java/org/cicirello/math/rand/package-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
*
* <h2>org.cicirello.math.rand</h2>
*
* <p>Copyright &copy; 2015, 2017-2022 <a href="https://www.cicirello.org/" target=_top>Vincent A.
* <p>Copyright &copy; 2015, 2017-2024 <a href="https://www.cicirello.org/" target=_top>Vincent A.
* Cicirello</a>.
*
* <p><a href="https://central.sonatype.com/artifact/org.cicirello/ziggurat/"><img
Expand Down Expand Up @@ -63,6 +63,17 @@
* java.util.concurrent.ThreadLocalRandom ThreadLocalRandom} classes, however the polar method is
* quite slow relative to other newer available alternatives, such as the Ziggurat method.
*
* <p>You can find information on when this ziggurat implementation is likely advantageous,
* including results of experiments in the following report:
*
* <ul>
* <li>Vincent A. Cicirello. 2024. <a href="https://reports.cicirello.org/24/009/">Fast Gaussian
* Distributed Pseudorandom Number Generation in Java via the Ziggurat Algorithm</a>. arXiv:<a
* href="https://arxiv.org/abs/2405.19493">2405.19493</a>, May 2024. doi:<a
* href="https://doi.org/10.48550/arXiv.2405.19493">10.48550/arXiv.2405.19493</a>. <a
* href="https://reports.cicirello.org/24/009/ALG-24-009.pdf">[PDF]</a>
* </ul>
*
* <p>You can find some experimental data comparing the performance of a sequential genetic
* algorithm (GA) using the implementation of the Ziggurat method for Gaussian mutation vs using the
* more common polar method, as well as experimental data for the same comparison but with a PGA, in
Expand Down
37 changes: 36 additions & 1 deletion src/test/java/org/cicirello/math/rand/PolarGaussianTests.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* JUnit test cases for PolarGaussian.
*
* Copyright 2019-2022 Vincent A. Cicirello, <https://www.cicirello.org/>.
* Copyright 2019-2024 Vincent A. Cicirello, <https://www.cicirello.org/>.
*
* This program is free software: you can
* redistribute it and/or modify it under the terms of the GNU
Expand Down Expand Up @@ -172,6 +172,41 @@ public void testNoParamNextGaussian10() {
assertTrue(positive && negative);
}

@Test
public void testLowProbEdgeCase() {
class ForceEdgeCase extends Random {
private int count;

public ForceEdgeCase(long seed) {
super(seed);
count = 0;
}

@Override
public double nextDouble() {
if (count < 2) {
count++;
return 0.5;
}
return super.nextDouble();
}
}
Random r = new ForceEdgeCase(42);
int[] buckets = new int[20];
final int N = buckets.length * EXPECTED_SAMPLES_PER_BUCKET;
for (int i = 0; i < N; i++) {
int j = whichBucket(PolarGaussian.nextGaussian(r::nextDouble));
buckets[j]++;
}
double chi = chiSquare(buckets);
if (VERBOSE_OUTPUT) {
System.out.printf("Random, sigma=1, chi=%5.4f\n", chi);
}
assertTrue(
chi <= 30.144); // 19 degrees of freedom, 95% percentage point of chi square distribution:
// 30.144
}

private double chiSquare(int[] buckets) {
int x = 0;
for (int e : buckets) {
Expand Down

0 comments on commit 6658727

Please sign in to comment.