/* * Copyright 2007-2013 * Licensed under GNU Lesser General Public License * * This file is part of EpochX: genetic programming software for research * * EpochX is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * EpochX 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with EpochX. If not, see <http://www.gnu.org/licenses/>. * * The latest version is available from: http://www.epochx.org */ package org.epochx.epox.math; import java.math.*; import org.epochx.RandomSequence; import org.epochx.epox.Literal; import org.epochx.epox.bool.BooleanERC; /** * Defines a double ephemeral random constant (ERC). An ERC is a literal with * a value which is randomly generated upon construction. This implementation * will generate a double value of the specified precision between the lower * and upper bounds provided. All values between the two bounds (inclusive), can * appear with equal probability. As with all nodes, instances may be * constructed in any of 3 ways: * <ul> * <li>constructor - the new instance will be initialised with a value of * <code>null</code>.</li> * <li>clone method - will return an instance with a value equal to the cloned * value.</li> * <li>newInstance method - will return a new instance with a new, randomly * generated value.</li> * </ul> * * @see BooleanERC * @see IntegerERC * * @since 2.0 */ public class DoubleERC extends Literal { private RandomSequence random; // The inclusive bounds. private double lower; private double upper; // The precision of generated values. private int precision; /** * Constructs a new <code>DoubleERC</code> with a value of <code>null</code>. The * given random number generator will be be used to generate a new value if the * <code>newInstance</code> method is used. * * @param random the random number generator to use if randomly generating a * double value. * @param lower the inclusive lower bound of values that are generated. * @param upper the inclusive upper bound of values that are generated. * @param precision the non-negative <code>int</code> precision. */ public DoubleERC(RandomSequence random, double lower, double upper, int precision) { super(null); if (random == null) { throw new IllegalArgumentException("random generator must not be null"); } this.random = random; this.lower = lower; this.upper = upper; this.precision = precision; // Set its value. setValue(generateValue()); } /** * Constructs a new <code>DoubleERC</code> node with a randomly generated * value, selected using the random number generator. The value will be * randomly selected with an equal probability from the set of values * between the lower and upper bounds and of the specified precision. * * @return a new <code>DoubleERC</code> instance with a randomly generated * value. */ @Override public DoubleERC newInstance() { DoubleERC erc = (DoubleERC) super.newInstance(); erc.setValue(generateValue()); return erc; } /** * Generates and returns a new double value for use in a new * <code>DoubleERC</code> instance. This implementation will return a value * selected randomly from the set of values between the lower and upper * bounds, inclusively. The value will be returned with the specified * precision. * * @return a double value to be used as the value of a new DoubleERC * instance. * @throws IllegalStateException if the random number generator is null. */ protected double generateValue() { if (random == null) { throw new IllegalStateException("random number generator must not be null"); } // Position random within range. double range = upper - lower; double d = (random.nextDouble() * range) + lower; // Round to the correct precision. BigDecimal big = new BigDecimal(d); big = big.round(new MathContext(precision)); return big.doubleValue(); } /** * Returns the random number generator that is currently being used to * generate double values for new <code>DoubleERC</code> instances. * * @return the random number generator */ public RandomSequence getRandomSequence() { return random; } /** * Sets the random number generator to be used for generating the double * value of new <code>DoubleERC</code> instances. * * @param random the random number generator to set */ public void setRandomSequence(RandomSequence random) { this.random = random; } /** * Returns the lower bound of the newly generated values. * * @return the lower bound of values. */ public double getLower() { return lower; } /** * Sets the inclusive lower bound for newly generated values. * * @param lower the lower bound for values. */ public void setLower(double lower) { this.lower = lower; } /** * Returns the upper bound of the newly generated values. * * @return the upper bound of values. */ public double getUpper() { return upper; } /** * Sets the inclusive upper bound for newly generated values. * * @param upper the upper bound for values. */ public void setUpper(double upper) { this.upper = upper; } /** * Returns the non-negative value precision int. * * @return the value precision. */ public int getPrecision() { return precision; } /** * Sets the non-negative value precision int. * * @param precision a non-negative precision for generated values */ public void setPrecision(int precision) { this.precision = precision; } }