All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jasima.core.random.discrete.IntEmpirical Maven / Gradle / Ivy

/*******************************************************************************
 * Copyright (c) 2010-2015 Torsten Hildebrandt and jasima contributors
 *
 * This file is part of jasima, v1.2.
 *
 * jasima is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * jasima is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with jasima.  If not, see .
 *******************************************************************************/
package jasima.core.random.discrete;

import jasima.core.util.Util;

import java.util.Arrays;
import java.util.Random;

/**
 * Returns an integer in the range [0,n]. The probability of each value is
 * determined by the probabilities passed to {@link #setProbabilities(double[])}
 * , and can be arbitrary positive numbers as long as they sum up to 1.0.
 * 
 * @author Torsten Hildebrandt 
 * @version 
 *          "$Id: IntEmpirical.java 550 2015-01-23 15:07:23Z [email protected] $"
 */
public class IntEmpirical extends IntStream {

	private static final long serialVersionUID = -8591371451392742035L;

	public IntEmpirical() {
		this(null, null, null, null);
	}

	public IntEmpirical(double[] probs) {
		this(null, null, probs, null);
	}

	public IntEmpirical(Random rnd, double[] probs) {
		this(rnd, null, probs, null);
	}

	public IntEmpirical(String name, double[] probs) {
		this(null, name, probs, null);
	}

	public IntEmpirical(double[] probs, int[] values) {
		this(null, null, probs, values);
	}

	public IntEmpirical(Random rnd, double[] probs, int[] values) {
		this(rnd, null, probs, values);
	}

	public IntEmpirical(String name, double[] probs, int[] values) {
		this(null, name, probs, values);
	}

	public IntEmpirical(Random rnd, String name, double[] probs, int[] values) {
		super();
		setProbabilities(probs, values);
		setRndGen(rnd);
		setName(name);
	}

	private double[] probs = null;
	private int[] vals = null;
	private Double mean = null;

	public double[] getProbabilities() {
		return probs;
	}

	public int[] getValues() {
		return vals;
	}

	public void setProbabilities(double[] probs, int[] values) {
		if (probs != null && Math.abs(Util.sum(probs) - 1.0d) > 1e-6)
			throw new IllegalArgumentException("probabilities must add to 1: "
					+ Arrays.toString(probs) + " " + Util.sum(probs));
		if (values != null && values.length != probs.length)
			throw new IllegalArgumentException(
					"There has to be a value for each probability.");

		this.probs = probs;
		this.vals = values;
		this.mean = null;
	}

	/**
	 * Sets only probabilities. In this case {@link #nextInt()} will produce
	 * integers in the range {@code [0, probs.length-1]}.
	 */
	public void setProbabilities(double[] probs) {
		setProbabilities(probs, null);
	}

	@Override
	public int nextInt() {
		double prob = rndGen.nextDouble();

		double d = 0.0d;
		for (int i = 0; i < probs.length; i++) {
			d += probs[i];
			if (d > prob)
				return vals != null ? vals[i] : i;
		}

		throw new AssertionError(); // should never be reached
	}

	@Override
	public double getNumericalMean() {
		if (mean == null) {
			if (probs == null || probs.length == 0) {
				mean = Double.NaN;
			} else {
				mean = 0.0;
				for (int i = 0; i < probs.length; i++) {
					int value = vals == null ? i : vals[i];
					mean += probs[i] * value;
				}
			}
		}

		return mean;
	}

	@Override
	public IntEmpirical clone() throws CloneNotSupportedException {
		IntEmpirical c = (IntEmpirical) super.clone();

		if (probs != null)
			c.probs = probs.clone();
		if (vals != null)
			c.vals = vals.clone();

		return c;
	}

	@Override
	public String toString() {
		String params = "";

		StringBuilder sb = new StringBuilder();

		int n = probs != null ? probs.length : 0;
		int m = vals != null ? vals.length : 0;
		for (int i = 0; i < Math.max(n, m); i++) {
			String v = vals != null && i < vals.length ? Integer
					.toString(vals[i]) : "?";
			String p = probs != null && i < probs.length ? Double
					.toString(probs[i]) : "?";

			sb.append('<').append(v).append(',').append(p).append(">;");
		}
		if (sb.length() > 0)
			params = sb.substring(0, sb.length() - 1);

		return String.format("%s(%s)", this.getClass().getSimpleName(), params);
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy