net.sourceforge.cilib.math.Maths Maven / Gradle / Ivy
/** __ __
* _____ _/ /_/ /_ Computational Intelligence Library (CIlib)
* / ___/ / / / __ \ (c) CIRG @ UP
* / /__/ / / / /_/ / http://cilib.net
* \___/_/_/_/_.___/
*/
package net.sourceforge.cilib.math;
import static com.google.common.base.Preconditions.checkArgument;
import fj.F;
import static fj.data.List.*;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import net.sourceforge.cilib.math.random.generator.Rand;
import net.sourceforge.cilib.type.types.container.Vector;
import net.sourceforge.cilib.util.functions.Numerics;
/**
* This class provides helper functions in addition to the standard java.lang.Math
* class.
*
* These utility functions further are necessary for the various distributions and selections
* required within CIlib as a whole.
*
*/
public final class Maths {
public static final double EPSILON = 1.0E-15d;
private Maths() {
}
/**
* Generate the required factorial of the number x
.
* @param x The number to generate the factorial from.
* @return The factorial of x
.
*/
public static int factorial(int x) {
checkArgument(x >= 0, "x must be a positive integer");
checkArgument(x < 20, "The size of the factorial will result in a overflow. Please consider using Maths.largeFactorial() instead");
if (x == 0 || x == 1) {
return 1;
}
return x * factorial(x-1);
}
/**
* Generate the required factorial of {@code x}. Additionally, this
* method is not affected by data type overflow.
* @param x The value to calculate the factorial of.
* @return A {@link BigInteger} representing the factorial.
*/
public static BigInteger largeFactorial(int x) {
checkArgument(x >= 0, "x must be a positive integer");
BigInteger n = BigInteger.ONE;
for (int i = 1; i < x; i++) {
n = n.multiply(BigInteger.valueOf(i));
}
return n;
}
/**
* Return the combination of n
and r
.
* @param n The total elements from which the combination is performed.
* @param r The {@code r}-combinations (of size {@code r}) to select.
* @return The combination of n
and r
.
*/
public static int combination(int n, int r) {
checkArgument(n >= r, "Combination violation: n >= r");
checkArgument(r >= 0, "Combination violation: r >= 0");
return permutation(n, r) / factorial(r);
}
/**
* This is a convenience method providing an alias to combination
.
* @param n The number of elements available for selection.
* @param r The {@code r}-combinations (of size {@code r}) to select.
* @return The value of the operation "n
choose x
".
*/
public static double choose(int n, int r) {
return combination(n, r);
}
/**
* In combinatorics, a permutation is usually understood to be a sequence
* containing each element from a finite set once, and only once.
* @param n The number of elements available for selection.
* @param r The number of elements to be selected {@code (0 <= r <= n)}.
* @return The number of permutations.
*/
public static int permutation(int n, int r) {
checkArgument(n >= r, "Permutations violation: n >= r");
checkArgument(r >= 0, "Permutations violation: r >= 0");
return factorial(n) / factorial(n-r);
}
public static Iterator> permutation(final List input, final int number) {
return new Iterator>() {
private List internalList = new ArrayList(input); // Keep our own copy
private int n = input.size();
private int m = number;
private int[] index = initialise();
private boolean hasMore = true;
@Override
public boolean hasNext() {
return this.hasMore;
}
@Override
public List next() {
if (!this.hasMore){
return null;
}
List list = new ArrayList(this.m);
for (int i = 0; i < this.m; i++) {
int thisIndexI = this.index[i];
T element = internalList.get(thisIndexI);
list.add(element);
}
moveIndex();
return list;
}
@Override
public void remove() {
throw new UnsupportedOperationException("Not supported yet.");
}
private int[] initialise() {
if (!(this.n >= m && m >= 0)) {
throw new IllegalStateException("Permutation error! n >= m");
}
int[] tmp = new int[this.n];
for (int i = 0; i < this.n; i++) {
tmp[i] = i;
}
reverseAfter(tmp, m - 1);
return tmp;
}
/**
* Reverse the index elements to the right of the specified index.
*/
private void reverseAfter(int[] indicies, int i) {
int start = i + 1;
int end = this.n - 1;
while (start < end) {
int t = indicies[start];
indicies[start] = indicies[end];
indicies[end] = t;
start++;
end--;
}
}
private void moveIndex(){
// find the index of the first element that dips
int i = rightmostDip();
if (i < 0) {
this.hasMore = false;
return;
}
// find the least greater element to the right of the dip
int leastToRightIndex = i + 1;
for (int j = i + 2; j < this.n; j++){
if (this.index[j] < this.index[leastToRightIndex] && this.index[j] > this.index[i]) {
leastToRightIndex = j;
}
}
// switch dip element with least greater element to its right
int t = this.index[i];
this.index[i] = this.index[leastToRightIndex];
this.index[leastToRightIndex] = t;
if (this.m - 1 > i) {
// reverse the elements to the right of the dip
reverseAfter(this.index, i);
// reverse the elements to the right of m - 1
reverseAfter(this.index, this.m - 1);
}
}
private int rightmostDip() {
for (int i = this.n - 2; i >= 0; i--){
if (this.index[i] < this.index[i+1]){
return i;
}
}
return -1;
}
};
}
/**
* Determine if a "flip" would occur given the provided probability value.
* @param probability The provided probability value. This value must be in [0,1]
* @return 1 - if a "flip" occurred, 0 otherwise.
*/
public static int flip(double probability) {
checkArgument(probability >= 0 && probability <= 1, "Illegal input: valid range is [0,1]");
if (Rand.nextDouble() <= probability) {
return 1;
}
return 0;
}
/**
* Determine the log of the specified value
with the provided base
.
* @param base The base of the log operation.
* @param value The value to determine the log of.
* @return The log value of value
using the base value of base
.
* @see java.lang.Math#log(double).
*/
public static double log(double base, double value) {
return Math.log(value) / Math.log(base);
}
private static fj.data.List combinations(final fj.data.List input, final int i) {
if (i == input.length()) {
return list(Vector.of());
}
final fj.data.List recursive = combinations(input, i + 1);
final Vector current = input.index(i);
return fj.data.List.join(iterableList(current).map(Numerics.doubleValue())
.map(new F>() {
@Override
public fj.data.List f(final Double a) {
return recursive.map(new F() {
@Override
public Vector f(Vector b) {
return Vector.newBuilder().copyOf(b).add(a).build();
}
});
}
}));
}
public static fj.data.List combinations(final fj.data.List input) {
return combinations(input, 0);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy