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

org.integratedmodelling.engine.modelling.datasources.RandomSelectDSContextualizer Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 * Copyright (C) 2007, 2015:
 * 
 * - Ferdinando Villa  - integratedmodelling.org - any
 * other authors listed in @author annotations
 *
 * All rights reserved. This file is part of the k.LAB software suite, meant to enable
 * modular, collaborative, integrated development of interoperable data and model
 * components. For details, see http://integratedmodelling.org.
 * 
 * This program is free software; you can redistribute it and/or modify it under the terms
 * of the Affero General Public License Version 3 or 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 Affero General Public License for more details.
 * 
 * You should have received a copy of the Affero General Public License along with this
 * program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite
 * 330, Boston, MA 02111-1307, USA. The license is also available at:
 * https://www.gnu.org/licenses/agpl.html
 *******************************************************************************/
package org.integratedmodelling.engine.modelling.datasources;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import org.integratedmodelling.api.data.IList;
import org.integratedmodelling.api.metadata.IMetadata;
import org.integratedmodelling.api.modelling.IAction;
import org.integratedmodelling.api.modelling.IDataSource;
import org.integratedmodelling.api.modelling.IModel;
import org.integratedmodelling.api.modelling.IObserver;
import org.integratedmodelling.api.modelling.IScale;
import org.integratedmodelling.api.modelling.IValueResolver;
import org.integratedmodelling.api.modelling.contextualization.IStateContextualizer;
import org.integratedmodelling.api.modelling.scheduling.ITransition;
import org.integratedmodelling.api.monitoring.IMonitor;
import org.integratedmodelling.api.project.IProject;
import org.integratedmodelling.api.services.annotations.Prototype;
import org.integratedmodelling.common.data.NumericInterval;
import org.integratedmodelling.common.metadata.Metadata;
import org.integratedmodelling.common.model.runtime.AbstractStateContextualizer;
import org.integratedmodelling.common.vocabulary.NS;
import org.integratedmodelling.engine.modelling.runtime.Scale;
import org.integratedmodelling.exceptions.KlabException;
import org.integratedmodelling.exceptions.KlabRuntimeException;
import org.integratedmodelling.exceptions.KlabValidationException;

/**
 * A datasource that returns the same object no matter what. Also works as an accessor so
 * it can be parameterized appropriately.
 * 
 * @author Ferd
 *
 */
@Prototype(id = "rand.select", args = {
        "values",
        Prototype.LIST,
        "distribution",
        Prototype.LIST,
        "# seed",
        Prototype.INT }, returnTypes = { NS.STATE_CONTEXTUALIZER })
public class RandomSelectDSContextualizer extends AbstractStateContextualizer implements IDataSource, IValueResolver {

    private IMetadata metadata = new Metadata();
    private Object[]  values;
    private Object[]  distribution;
    Random            rand     = new Random();

    boolean isAccessor = false;

    public RandomSelectDSContextualizer(List actions, IMonitor monitor, long seed, Object[] values,
            Object[] dist) {
        super(monitor);
        this.values = values;
        this.distribution = dist;
        isAccessor = true;
        if (seed != 0) {
            this.rand.setSeed(seed);
        }
    }

    public RandomSelectDSContextualizer(long seed, Object[] values, Object[] dist) {
        super(null);
        this.values = values;
        this.distribution = dist;
        if (seed != 0) {
            this.rand.setSeed(seed);
        }
    }
    
    // for automatic instantiation
    public RandomSelectDSContextualizer() {
    	super(null);
    }

    @Override
    public String getLabel() {
        return "randomize selection";
    }

    
    private Object draw(Map parameters) {

        double[] dd = new double[this.values.length];
        double sum = 0.0;

        for (int i = 0; i < this.values.length; i++) {
            double d = 0.0;
            if (!(this.distribution[i] instanceof Number)) {
                Object o = parameters.get(this.distribution[i].toString());
                if (o == null) {
                	return null;
                }
                if (!(o instanceof Number)) {
                    RuntimeException e = new KlabRuntimeException("cannot compute value of "
                            + this.distribution[i] + ": " + o + " is not a number");
                    if (monitor != null) {
                        monitor.error(e);
                    }
                    throw e;
                }
                d = ((Number) o).doubleValue();
                if (Double.isNaN(d)) {
                    return null;
                }
            } else {
                d = ((Number) this.distribution[i]).doubleValue();
            }

            sum += d;
            dd[i] = sum;
        }

        double thr = this.rand.nextDouble() * sum;
        for (int i = 0; i < this.values.length; i++) {
            if (thr <= dd[i]) {
                return processValue(this.values[i]);
            }
        }

        return null;
    }

    private Object processValue(Object object) {

        if (object instanceof NumericInterval) {
            // choose randomly
            NumericInterval ni = (NumericInterval) object;
            object = ni.getLowerBound()
                    + (this.rand.nextDouble() * (ni.getUpperBound() - ni.getLowerBound()));
        }
        return object;
    }

    @Override
    public IStateContextualizer getContextualizer(IScale context, IObserver observer, IMonitor monitor)
            throws KlabException {
        return this;
    }

    @Override
    public IMetadata getMetadata() {
        return metadata;
    }

    @Override
    public IScale getCoverage() {
        return new Scale();
    }

    @Override
    public String toString() {
        /*
         * FIXME do better
         */
        return "[random.select]";
    }

    @Override
    public boolean isAvailable() {
        return true;
    }

    @Override
    public void setContext(Map parameters, IModel model, IProject project) throws KlabValidationException {
    	
        Object[] distribution = null;
        Object[] values = null;

        if (parameters.containsKey("values")) {
        	
            Object _vals = parameters.get("values");
            if (!(_vals instanceof IList)) {
                throw new KlabValidationException("values in a rand.select function must be a list");
            }

            Object[] vals = new Object[((IList) _vals).length()];
            int i = 0;
            for (Object o : ((IList) _vals)) {
                vals[i] = o;
                i++;
            }
            values = vals;
            
        } else {
            throw new KlabValidationException("rand.select must contains a 'values' list to choose from");
        }

        if (parameters.containsKey("distribution")) {
            Object _dist = parameters.get("distribution");
            if (!(_dist instanceof IList)) {
                throw new KlabValidationException("distribution in a rand.select function must be a list of floating point numbers");
            }

            int i = 0;
            Object[] vals = new Object[((IList) _dist).length()];
            for (Object o : ((IList) _dist)) {
//                if (!(o instanceof Number)) {
//                    throw new KlabValidationException("distribution in a rand.select datasource must be a list of floating point numbers");
//                }
                vals[i] = o;
                i++;
            }

            distribution = vals;
        }

        long seed = 0;

        if (parameters.containsKey("seed")) {
            seed = (long) Double.parseDouble(parameters.get("seed").toString());
        }

        /*
         * uniform dist if not specified
         */
        if (distribution == null) {
            distribution = new Object[values.length];
            for (int i = 0; i < distribution.length; i++) {
                distribution[i] = 1.0 / distribution.length;
            }
        }

        if (distribution.length != values.length) {
           throw new KlabValidationException("distribution and values in rand.select must have the same number of items");
        }
        
        this.values = values;
        this.distribution = distribution;
        if (seed != 0) {
            this.rand.setSeed(seed);
        }
    }

    @Override
    public Map initialize(int index, Map inputs) throws KlabException {
        Map ret = new HashMap<>();
        for (String s : getOutputKeys()) {
            ret.put(s, draw(inputs));
        }
        return ret;
    }

    @Override
    public Map compute(int index, ITransition transition, Map inputs)
            throws KlabException {
        Map ret = new HashMap<>();
        for (String s : getOutputKeys()) {
            ret.put(s, draw(inputs));
        }
        return ret;
    }

    @Override
    public boolean isProbabilistic() {
        return false;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy