net.sourceforge.jabm.init.RandomVariateInitialiser.java Source code

Java tutorial

Introduction

Here is the source code for net.sourceforge.jabm.init.RandomVariateInitialiser.java

Source

/*
 * JABM - Java Agent-Based Modeling Toolkit
 * Copyright (C) 2013 Steve Phelps
 *
 * 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 the Free Software Foundation; either version 3 of
 * the License, or (at your option) any later version.
 *
 * This program 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.
 */
package net.sourceforge.jabm.init;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedHashMap;

import net.sourceforge.jabm.EventScheduler;
import net.sourceforge.jabm.Simulation;
import net.sourceforge.jabm.SimulationController;
import net.sourceforge.jabm.SpringSimulationController;
import net.sourceforge.jabm.event.RandomVariateInitialisedEvent;
import net.sourceforge.jabm.util.Properties;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.PropertyOverrideConfigurer;

import bsh.EvalError;
import bsh.Interpreter;
import cern.jet.random.engine.RandomEngine;

/**
 * <p>
 * A simulation factory which initialises the values of pre-specified
 * Spring bean properties by drawing randomly from the specified probability
 * distribution.  The bean properties are designated as random variates 
 * by creating a configuration file which specifies the mapping between
 * each variate and its corresponding distribution.
 * </p>  
 * 
 * <p>
 * Currently the following distributions are supported.
 * </p>
 * 
 * <table border="1">
 * <tr>
 * <td><code>N</code></td> <td>Normal distribution</td>
 * </tr>
 * <tr>
 * <td><code>U</code></td> <td>Uniform distribution</td>
 * </tr>
 * </table>
 * 
 * <p>
 * The parameters of the distribution are specified in brackets after
 * the abbreviation.  For example the following configuration:
 * </p>
 * 
 *  <code>
 *  agent.epsilon = U(0.2, 0.5)<br>
 *  agent.wealth = N(200.0, 10.0)<br>
 *  </code>
 *  
 * <p>
 * specifies that the agent's epsilon parameter is uniformly distributed 
 * between 0.2 and 0.5 and the agent's wealth is normally distributed with
 * mean 200 and standard deviation 10. 
 * </p>
 *  
 * @author Steve Phelps
 * @see java.util.Properties
 * @see cern.jet.random.AbstractDistribution
 *
 */
public class RandomVariateInitialiser extends SpringSimulationFactory implements InitializingBean {

    protected Object configFileNamePrefix = "";

    protected String configFileName = "config/random-variate.properties";

    protected RandomEngine prng;

    protected HashMap<String, String> expressionBindings;

    protected EventScheduler eventScheduler;

    static Logger logger = Logger.getLogger(RandomVariateInitialiser.class);

    public RandomVariateInitialiser() {
        super();
    }

    @Override
    public Simulation initialise(SimulationController simulationController) {
        this.eventScheduler = simulationController;
        java.util.Properties variateBindings = new java.util.Properties();
        for (String variable : expressionBindings.keySet()) {
            Number value = evaluate(expressionBindings.get(variable), variateBindings);
            variateBindings.put(variable, value + "");
            logger.info(variable + " = " + value);
            fireEvent(variable, value);
        }
        PropertyOverrideConfigurer configurer = new PropertyOverrideConfigurer();
        configurer.setProperties(variateBindings);
        configurer.setLocalOverride(true);
        configurer.postProcessBeanFactory(
                (ConfigurableListableBeanFactory) ((SpringSimulationController) simulationController)
                        .getBeanFactory());
        return super.initialise(simulationController);
    }

    public void parseConfigFile() throws FileNotFoundException, IOException {
        expressionBindings = new LinkedHashMap<String, String>();
        File f = new File(configFileNamePrefix + configFileName);
        Properties properties = new Properties();
        properties.load(new FileInputStream(f));
        for (Object property : properties.keySet()) {
            String expression = (String) properties.get(property);
            expressionBindings.put(property.toString(), expression);
        }
    }

    public Number evaluate(String expression, java.util.Properties variateBindings) {
        try {
            Interpreter bsh = initialiseBeanShell(variateBindings);
            logger.debug("Evalating " + expression);
            return (Number) bsh.eval(expression);
        } catch (EvalError e) {
            throw new RuntimeException(e);
        }
    }

    public Interpreter initialiseBeanShell(java.util.Properties variateBindings) throws EvalError {

        Interpreter bsh = new Interpreter();

        bsh.set("prng", this.prng);

        bsh.eval("double N(double mean, double std) "
                + "{ return new cern.jet.random.Normal(mean,std,prng).nextDouble(); }");

        bsh.eval("double U(double min, double max) "
                + "{ return new cern.jet.random.Uniform(min,max,prng).nextDouble(); }");

        for (Object variate : variateBindings.keySet()) {
            String var = variate.toString();
            bsh.set(var, Double.parseDouble(variateBindings.get(var).toString()));
        }
        return bsh;
    }

    protected void fireEvent(String variableName, Number value) {
        if (eventScheduler != null) {
            eventScheduler.fireEvent(new RandomVariateInitialisedEvent(variableName, value.doubleValue()));
        }
    }

    public String getConfigFileName() {
        return configFileName;
    }

    /**
     * The name of the configuration file which specifies which
     * bean properties are to be treated as random variates and their 
     * corresponding distribution.  This file is in the standard 
     * format for a Properties file.
     * 
     * @param configFileName
     * @see java.util.Properties
     */
    @Required
    public void setConfigFileName(String configFileName) {
        this.configFileName = configFileName;
    }

    public RandomEngine getPrng() {
        return prng;
    }

    /**
     * The pseudo-random number generator to be used for drawing all
     * variates drawn by this initialiser.
     * 
     * @param prng
     */
    @Required
    public void setPrng(RandomEngine prng) {
        this.prng = prng;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        parseConfigFile();
    }

    public EventScheduler getEventScheduler() {
        return eventScheduler;
    }

    /**
     * If this property is set then the initialiser will fire
     * a RandomVariateInitialisedEvent each time a 
     * random variate is initialised.
     * 
     * @param eventScheduler  The scheduler used to manage the event queue.
     * 
     * @see net.sourceforge.jabm.event.RandomVariateInitialisedEvent
     * @see net.sourceforge.jabm.EventScheduler
     */
    public void setEventScheduler(EventScheduler eventScheduler) {
        this.eventScheduler = eventScheduler;
    }

    public Object getConfigFileNamePrefix() {
        return configFileNamePrefix;
    }

    public void setConfigFileNamePrefix(Object configFileNamePrefix) {
        this.configFileNamePrefix = configFileNamePrefix;
    }

}