net.sourceforge.jabm.VariableBindingsIterator.java Source code

Java tutorial

Introduction

Here is the source code for net.sourceforge.jabm.VariableBindingsIterator.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;

import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import net.sourceforge.jabm.util.UntypedDouble;
import net.sourceforge.jabm.util.UntypedLong;
import net.sourceforge.jabm.util.UntypedNumber;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.BeanFactory;

class VariableBindingsIterator implements Iterator<Map<String, String>> {

    protected Map<String, VariableRange> variableRanges;

    protected ArrayList<String> variables;

    protected Bindings bindings;

    protected int currentVariableIndex;

    protected BeanFactory beanFactory;

    protected boolean hasNext;

    public static final String RANGE_REGEXP = "([0-9\\.]+)\\:([0-9\\.]+)\\:([0-9\\.]+)";

    static Pattern rangePattern = Pattern.compile(RANGE_REGEXP);

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

    public VariableBindingsIterator(String varFile, BeanFactory beanFactory) {
        try {
            this.beanFactory = beanFactory;
            parseVarFile(varFile);
            bindings = initialBindings();
            currentVariableIndex = variables.size() - 1;
            hasNext = variables.size() > 0;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public Bindings initialBindings() {
        Bindings result = new Bindings();
        for (String variable : variables) {
            UntypedNumber initialValue = variableRanges.get(variable).getMin();
            result.set(variable, initialValue);
        }
        return result;
    }

    @SuppressWarnings("rawtypes")
    public void parseVarFile(String varFile) throws IOException {
        Properties properties = new Properties();
        variableRanges = new HashMap<String, VariableRange>();
        properties.load(new FileInputStream(varFile));
        for (Object variable : properties.keySet()) {
            Class type = getType(variable.toString());
            VariableRange range = parseVariableRange(properties.get(variable).toString(), type);
            logger.debug("range = " + range);
            variableRanges.put(variable.toString(), range);
        }
        variables = new ArrayList<String>(variableRanges.keySet());
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    public Class getType(String beanProperty) {
        int dot = beanProperty.indexOf('.');
        String beanName = beanProperty.substring(0, dot);
        String attributeName = beanProperty.substring(dot + 1);
        Class beanType = beanFactory.getType(beanName);
        String getterName = "get" + Character.toUpperCase(attributeName.charAt(0)) + attributeName.substring(1);
        try {
            Method method = beanType.getMethod(getterName, new Class[] {});
            Type returnType = method.getGenericReturnType();
            if (returnType instanceof Class) {
                Class result = (Class) returnType;
                return result;
            } else {
                throw new IllegalArgumentException(beanProperty);
            }
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    public VariableRange parseVariableRange(String rangeSpecification, Class type) {
        Matcher matcher = rangePattern.matcher(rangeSpecification);
        if (matcher.matches()) {
            VariableRange result = new VariableRange();
            String minStr = matcher.group(1);
            String incrStr = matcher.group(2);
            String maxStr = matcher.group(3);
            if (type.isAssignableFrom(int.class) || type.isAssignableFrom(long.class)) {
                result.setMin(new UntypedLong(Long.parseLong(minStr)));
                result.setIncrement(new UntypedLong(Long.parseLong(incrStr)));
                result.setMax(new UntypedLong(Long.parseLong(maxStr)));
            } else if (type.isAssignableFrom(double.class) || type.isAssignableFrom(float.class)) {
                result.setMin(new UntypedDouble(Double.parseDouble(minStr)));
                result.setIncrement(new UntypedDouble(Double.parseDouble(incrStr)));
                result.setMax(new UntypedDouble(Double.parseDouble(maxStr)));
            } else {
                throw new IllegalArgumentException(type.toString());
            }
            return result;
        }
        throw new IllegalArgumentException("Could not parse range specification: " + rangeSpecification);
    }

    @Override
    public boolean hasNext() {
        return hasNext;
    }

    @Override
    public Map<String, String> next() {

        Map<String, String> result = bindings.getStringBindings();

        logger.debug(variableName(currentVariableIndex) + " = " + bindings.get(currentVariableIndex));

        if (lessThanMaximumValue(currentVariableIndex)) {
            increment(currentVariableIndex);
        } else {
            // Back
            while (currentVariableIndex >= 0 && !lessThanMaximumValue(currentVariableIndex)) {
                currentVariableIndex--;
            }
            if (currentVariableIndex < 0) {
                hasNext = false;
                return result;
            }
            increment(currentVariableIndex);
            for (int i = currentVariableIndex + 1; i < variables.size(); i++) {
                bindings.set(variableName(i), getMin(i));
            }
            currentVariableIndex = variables.size() - 1;
        }

        return result;
    }

    @Override
    public void remove() {
        throw new RuntimeException("Unsupported method");
    }

    public String variableName(int variableIndex) {
        return variables.get(variableIndex);
    }

    public void increment(int variableIndex) {
        bindings.increment(variableName(variableIndex));
    }

    public boolean lessThanMaximumValue(int variableIndex) {
        String variableName = variableName(variableIndex);
        double value = bindings.get(variableName).doubleValue();
        double max = variableRanges.get(variableName).getMax().doubleValue();
        return value < (max - 10E-9);
    }

    public UntypedNumber getMin(int variableIndex) {
        String variableName = variableName(variableIndex);
        return variableRanges.get(variableName).getMin();
    }

    class VariableRange {

        public UntypedNumber min;

        public UntypedNumber max;

        public UntypedNumber increment;

        public VariableRange(UntypedNumber min, UntypedNumber max, UntypedNumber increment) {
            super();
            this.min = min;
            this.max = max;
            this.increment = increment;
        }

        public VariableRange() {
            super();
        }

        public UntypedNumber getMin() {
            return min;
        }

        public void setMin(UntypedNumber min) {
            this.min = min;
        }

        public UntypedNumber getMax() {
            return max;
        }

        public void setMax(UntypedNumber max) {
            this.max = max;
        }

        public UntypedNumber getIncrement() {
            return increment;
        }

        public void setIncrement(UntypedNumber increment) {
            this.increment = increment;
        }

        public String toString() {
            return min + ":" + increment + ":" + max;
        }
    }

    class Bindings {

        Map<String, UntypedNumber> variableMap;

        public Bindings() {
            variableMap = new HashMap<String, UntypedNumber>();
        }

        public void set(String variable, UntypedNumber value) {
            variableMap.put(variable, value);
        }

        public void increment(String variable) {
            UntypedNumber currentValue = variableMap.get(variable);
            UntypedNumber newValue = currentValue.add(variableRanges.get(variable).getIncrement());
            set(variable, newValue);
        }

        public UntypedNumber getNextValue(String variable) {
            UntypedNumber currentValue = variableMap.get(variable);
            UntypedNumber newValue = currentValue.add(variableRanges.get(variable).getIncrement());
            return newValue;
        }

        public UntypedNumber get(String variable) {
            return variableMap.get(variable);
        }

        public UntypedNumber get(int variableIndex) {
            String variableName = variables.get(variableIndex);
            return get(variableName);
        }

        public Set<String> getVariables() {
            return variableMap.keySet();
        }

        public Map<String, String> getStringBindings() {
            HashMap<String, String> result = new HashMap<String, String>();
            for (String variable : variableMap.keySet()) {
                result.put(variable, variableMap.get(variable).toString());
            }
            return result;
        }
    }

}