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;
}
}