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

umontreal.iro.lecuyer.probdist.DistributionFactory Maven / Gradle / Ivy

Go to download

SSJ is a Java library for stochastic simulation, developed under the direction of Pierre L'Ecuyer, in the Département d'Informatique et de Recherche Opérationnelle (DIRO), at the Université de Montréal. It provides facilities for generating uniform and nonuniform random variates, computing different measures related to probability distributions, performing goodness-of-fit tests, applying quasi-Monte Carlo methods, collecting (elementary) statistics, and programming discrete-event simulations with both events and processes.

The newest version!


/*
 * Class:        DistributionFactory
 * Description:  allows the creation of distribution objects from a string
 * Environment:  Java
 * Software:     SSJ 
 * Copyright (C) 2001  Pierre L'Ecuyer and Université de Montréal
 * Organization: DIRO, Université de Montréal
 * @author       
 * @since

 * SSJ is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License (GPL) as published by the
 * Free Software Foundation, either version 3 of the License, or
 * any later version.

 * SSJ 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.

 * A copy of the GNU General Public License is available at
   GPL licence site.
 */

package umontreal.iro.lecuyer.probdist;

import java.lang.reflect.*;
import java.util.StringTokenizer;

/**
 * This class implements a string API for the package probdist.
 * It uses Java Reflection to allow the creation of probability distribution
 * objects from a string.  This permits one to obtain distribution specifications 
 * from a file or dynamically from user input during program execution.
 * This string API is similar to that of 
 * UNURAN.
 * 
 * 

* The (static) methods of this class invoke the constructor specified * in the string. For example, * *

* * d = DistributionFactory.getContinuousDistribution ("NormalDist (0.0, 2.5)"); *
*
* is equivalent to * *
* * d = NormalDist (0.0, 2.5); *
*
* *

* The string that specifies the distribution (i.e., the formal parameter * str of the methods) must be a valid call of the constructor * of a class that extends {@link ContinuousDistribution} or * {@link DiscreteDistribution}, and all parameter values must be numerical * values (variable names are not allowed). * * * *

* The distribution parameters can also be estimated from a set of observations * instead of being passed to the constructor. In that case, one passes the * vector of observations, and the constructor estimates the parameters by * the maximum likelihood method. * */ public class DistributionFactory { private DistributionFactory() {} // ???? Utile? public static Distribution getDistribution (String str) { // Extracts the name of the distribution. // If there is an open parenthesis, the name contains all the // non-space characters preceeding it.If not,the name is the full string. int i = 0; str = str.trim(); int idx = str.indexOf ('(', i); String distName; if (idx == -1) distName = str.substring (i).trim(); else distName = str.substring (i, idx).trim(); // Try to find the class in probdist package. Class distClass; if (distName.equals ("String")) throw new IllegalArgumentException ("Invalid distribution name: " + distName); try { distClass = Class.forName ("umontreal.iro.lecuyer.probdist." + distName); } catch (ClassNotFoundException e) { // Look for a fully qualified classname whose constructor // matches this string. try { distClass = Class.forName (distName); // We must check if the class implements Distribution if (Distribution.class.isAssignableFrom(distClass) == false) throw new IllegalArgumentException ("The given class is not a Probdist distribution class."); } catch (ClassNotFoundException ex) { throw new IllegalArgumentException ("Invalid distribution name: " + distName); } } String paramStr = ""; if (idx != -1) { // Get the parameters from the string. int parFrom = idx; int parTo = str.lastIndexOf (')'); // paramStr will contain the parameters without parentheses. paramStr = str.substring (parFrom + 1, parTo).trim(); if (paramStr.indexOf ('(') != -1 || paramStr.indexOf (')') != -1) //All params are numerical,so parenthesis nesting is forbidden here throw new IllegalArgumentException ("Invalid parameter string: " + paramStr); } if (paramStr.equals ("")) { // No parameter is given to the constructor. try { return (Distribution) distClass.newInstance(); } catch (IllegalAccessException e) { throw new IllegalArgumentException ("Default parameters not available"); } catch (InstantiationException e) { throw new IllegalArgumentException ("Default parameters not available"); } } // Find the number of parameters and try to find a matching constructor. // Within probdist, there are no constructors with the same // number of arguments but with different types. // This simplifies the constructor selection scheme. StringTokenizer paramTok = new StringTokenizer (paramStr, ","); int nparams = paramTok.countTokens(); Constructor[] cons = distClass.getConstructors(); Constructor distCons = null; Class[] paramTypes = null; // Find a public constructor with the correct number of parameters. for (i = 0; i < cons.length; i++) { if (Modifier.isPublic (cons[i].getModifiers()) && ((paramTypes = cons[i].getParameterTypes()).length == nparams)) { distCons = cons[i]; break; } } if (distCons == null) throw new IllegalArgumentException ("Invalid parameter number"); // Create the parameters for the selected constructor. Object[] instParams = new Object[nparams]; for (i = 0; i < nparams; i++) { String par = paramTok.nextToken().trim(); try { // We only need a limited set of parameter types here. if (paramTypes[i] == int.class) instParams[i] = new Integer (par); else if (paramTypes[i] == long.class) instParams[i] = new Long (par); else if (paramTypes[i] == float.class) { if (par.equalsIgnoreCase ("infinity") || par.equalsIgnoreCase ("+infinity")) instParams[i] = new Float (Float.POSITIVE_INFINITY); else if (par.equalsIgnoreCase ("-infinity")) instParams[i] = new Float (Float.NEGATIVE_INFINITY); else instParams[i] = new Float (par); } else if (paramTypes[i] == double.class) { if (par.equalsIgnoreCase ("infinity") || par.equalsIgnoreCase ("+infinity")) instParams[i] = new Double (Double.POSITIVE_INFINITY); else if (par.equalsIgnoreCase ("-infinity")) instParams[i] = new Double (Double.NEGATIVE_INFINITY); else instParams[i] = new Double (par); } else throw new IllegalArgumentException ("Parameter " + (i+1) + " type " + paramTypes[i].getName() + "not supported"); } catch (NumberFormatException e) { throw new IllegalArgumentException ("Parameter " + (i+1) + " of type " + paramTypes[i].getName()+" could not be converted from String"); } } // Try to instantiate the distribution class. try { return (Distribution) distCons.newInstance (instParams); } catch (IllegalAccessException e) { return null; } catch (InstantiationException e) { return null; } catch (InvocationTargetException e) { return null; } } @SuppressWarnings("unchecked") /** * Uses the Java Reflection API to construct a {@link ContinuousDistribution} * object by estimating parameters of the distribution using the maximum likelihood * method based on the n observations in table x[i], * i = 0, 1,…, n - 1. * * @param distName the name of the distribution to instanciate * * @param x the list of observations to use to evaluate parameters * * @param n the number of observations to use to evaluate parameters * * */ public static ContinuousDistribution getDistributionMLE (String distName, double[] x, int n) { Class distClass; try { distClass = Class.forName ("umontreal.iro.lecuyer.probdist." + distName); } catch (ClassNotFoundException e) { try { distClass = Class.forName (distName); } catch (ClassNotFoundException ex) { throw new IllegalArgumentException ("Invalid distribution name: " + distName); } } return getDistributionMLE ((Class)distClass, x, n); } @SuppressWarnings("unchecked") /** * Uses the Java Reflection API to construct a {@link DiscreteDistributionInt} * object by estimating parameters of the distribution using the maximum likelihood * method based on the n observations in table x[i], * i = 0, 1,…, n - 1. * * @param distName the name of the distribution to instanciate * * @param x the list of observations to use to evaluate parameters * * @param n the number of observations to use to evaluate parameters * * */ public static DiscreteDistributionInt getDistributionMLE (String distName, int[] x, int n) { Class distClass; try { distClass = Class.forName ("umontreal.iro.lecuyer.probdist." + distName); } catch (ClassNotFoundException e) { try { distClass = Class.forName (distName); } catch (ClassNotFoundException ex) { throw new IllegalArgumentException ("Invalid distribution name: " + distName); } } return getDistributionMLE ((Class)distClass, x, n); } @SuppressWarnings("unchecked") /** * Uses the Java Reflection API to construct a {@link ContinuousDistribution} * object by estimating parameters of the distribution using the maximum likelihood * method based on the n observations in table x[i], * i = 0, 1,…, n - 1. * * @param distClass the class of the distribution to instanciate * * @param x the list of observations to use to evaluate parameters * * @param n the number of observations to use to evaluate parameters * * */ public static T getDistributionMLE (Class distClass, double[] x, int n) { if (ContinuousDistribution.class.isAssignableFrom(distClass) == false) throw new IllegalArgumentException ("The given class is not a Probdist distribution class."); Method m; try { m = distClass.getMethod ("getInstanceFromMLE", double[].class, int.class); } catch (NoSuchMethodException e) { throw new IllegalArgumentException ("The given class does not provide the static method getInstanceFromMLE (double[],int)"); } if (!Modifier.isStatic (m.getModifiers()) || !distClass.isAssignableFrom (m.getReturnType())) throw new IllegalArgumentException ("The given class does not provide the static method getInstanceFromMLE (double[],int)"); try { return (T)m.invoke (null, x, n); } catch (IllegalAccessException e) { return null; } catch (IllegalArgumentException e) { return null; } catch (InvocationTargetException e) { return null; } } @SuppressWarnings("unchecked") /** * Uses the Java Reflection API to construct a {@link DiscreteDistributionInt} * object by estimating parameters of the distribution using the maximum likelihood * method based on the n observations in table x[i], * i = 0, 1,…, n - 1. * * @param distClass the class of the distribution to instanciate * * @param x the list of observations to use to evaluate parameters * * @param n the number of observations to use to evaluate parameters * * */ public static T getDistributionMLE (Class distClass, int[] x, int n) { if (DiscreteDistributionInt.class.isAssignableFrom(distClass) == false) throw new IllegalArgumentException ("The given class is not a discrete distribution class over integers."); Method m; try { m = distClass.getMethod ("getInstanceFromMLE", int[].class, int.class); } catch (NoSuchMethodException e) { throw new IllegalArgumentException ("The given class does not provide the static method getInstanceFromMLE (int[],int)"); } if (!Modifier.isStatic (m.getModifiers()) || !distClass.isAssignableFrom (m.getReturnType())) throw new IllegalArgumentException ("The given class does not provide the static method getInstanceFromMLE (int[],int)"); try { return (T)m.invoke (null, x, n); } catch (IllegalAccessException e) { return null; } catch (IllegalArgumentException e) { return null; } catch (InvocationTargetException e) { return null; } } /** * Uses the Java Reflection API to construct a {@link ContinuousDistribution} * object by executing the code contained in the string str. * This code should be a valid invocation of the constructor of a * {@link ContinuousDistribution} object. * This method throws exceptions if it cannot parse the given string and * returns null if the distribution object could not be created due to * a Java-specific instantiation problem. * * @param str string that contains a call to the constructor of a continuous * distribution * * @return a continuous distribution object or null if it could not * be instantiated * @exception IllegalArgumentException if parsing problems occured * when reading str * * @exception ClassCastException if the distribution string does not represent * a continuous distribution * * */ public static ContinuousDistribution getContinuousDistribution (String str) { return (ContinuousDistribution)getDistribution (str); } /** * Same as {@link #getContinuousDistribution getContinuousDistribution}, but for discrete distributions * over the real numbers. * * @param str string that contains a call to the constructor of a discrete * distribution * * @return a discrete distribution object, or null if it could not * be instantiated * @exception IllegalArgumentException if parsing problems occured when * reading str * * @exception ClassCastException if the distribution string does not represent * a discrete distribution * * */ public static DiscreteDistribution getDiscreteDistribution (String str) { return (DiscreteDistribution)getDistribution (str); } /** * Same as {@link #getContinuousDistribution getContinuousDistribution}, but for discrete distributions * over the integers. * * @param str string that contains a call to the constructor of a discrete * distribution * * @return a discrete distribution object, or null if it could not * be instantiated * @exception IllegalArgumentException if parsing problems occured when * reading str * * @exception ClassCastException if the distribution string does not represent * a discrete distribution * */ public static DiscreteDistributionInt getDiscreteDistributionInt (String str) { return (DiscreteDistributionInt)getDistribution (str); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy