org.integratedmodelling.engine.geospace.gis.MapClassifier Maven / Gradle / Ivy
The newest version!
package org.integratedmodelling.engine.geospace.gis;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.integratedmodelling.api.knowledge.IKnowledge;
import org.integratedmodelling.api.modelling.IClassification;
import org.integratedmodelling.api.modelling.IClassifyingObserver;
import org.integratedmodelling.api.modelling.INumericObserver;
import org.integratedmodelling.api.modelling.IPresenceObserver;
import org.integratedmodelling.api.modelling.IRankingObserver;
import org.integratedmodelling.api.modelling.IScale;
import org.integratedmodelling.api.modelling.IScale.Locator;
import org.integratedmodelling.api.modelling.IState;
import org.integratedmodelling.api.monitoring.IMonitor;
import org.integratedmodelling.common.classification.Classification;
import org.integratedmodelling.common.states.States;
import org.integratedmodelling.common.utils.StringUtils;
/**
* Classifies a set of states into one map of classes corresponding to different
* configurations, discretizing each state if necessary.
*
* @author Ferd
*
*/
public class MapClassifier {
public class MapClass {
/*
* classifier N per descriptor
*/
List classifiers;
int index;
String name;
public int getIndex() {
return index;
}
@Override
public String toString() {
return index + ":" + classifiers;
}
public double getValueOf(IKnowledge k) {
MapDescriptor mds = stateIndex.get(k);
if (mds == null) {
return 0;
}
return ((Classification) mds.discretization).getNumericCode(classifiers.get(mds.index));
}
}
class MapDescriptor {
IState state;
IClassification discretization = null;
int index;
boolean useRanks = false;
Map rankMap;
public MapDescriptor(IState s, Locator... locators) {
this.state = s;
if (s.getObserver() instanceof INumericObserver
&& ((INumericObserver) s.getObserver()).getDiscretization() == null) {
if (s.getObserver() instanceof IRankingObserver
&& ((IRankingObserver) s.getObserver()).isInteger()) {
useRanks = true;
rankMap = new HashMap<>();
} else {
this.discretization = States.discretize(s, maxBinsPerState);
}
} else if (s.getObserver() instanceof INumericObserver
&& ((INumericObserver) s.getObserver()).getDiscretization() != null) {
this.discretization = ((INumericObserver) s.getObserver()).getDiscretization();
} else if (s.getObserver() instanceof IClassifyingObserver) {
this.discretization = ((IClassifyingObserver) s.getObserver()).getClassification();
} else if (s.getObserver() instanceof IPresenceObserver) {
this.discretization = Classification.createBinary();
}
}
@Override
public String toString() {
return "D/" + index + "/" + state.getObservable().getSemantics();
}
public int getClass(int offset) {
Object o = States.get(state, offset);
if (o == null) {
return -1;
}
if (useRanks) {
Integer n = o instanceof Number ? ((Number) o).intValue() : null;
if (n != null) {
if (rankMap.containsKey(n)) {
return rankMap.get(n);
} else {
int newv = rankMap.size();
rankMap.put(n, newv);
return newv;
}
} else {
return -1;
}
}
return this.discretization.classifyToIndex(o);
}
}
IScale scale;
private List states = new ArrayList<>();
private int maxBinsPerState;
int[] index;
private Locator[] locators;
Map classCatalog = new HashMap<>();
List classes = new ArrayList<>();
Map stateIndex = new HashMap<>();
/**
* Build the necessary discretizations. Check getStatesCount() before calling
* classify() to ensure we have at least the desired number of states.
*
* @param states
* @param maxBinsPerState
* @param monitor
* @param locators
*/
public MapClassifier(Collection states, int maxBinsPerState, IMonitor monitor,
Locator... locators) {
this.locators = locators;
this.maxBinsPerState = maxBinsPerState;
int i = 0;
for (IState s : states) {
MapDescriptor md = new MapDescriptor(s);
if (md.discretization != null || md.useRanks) {
this.states.add(md);
stateIndex.put(s.getObservable().getType(), md);
md.index = i++;
} else {
monitor.warn("discretizer: state " + s.getObservable().getType()
+ " could not be discretized");
}
}
if (states.size() > 0) {
this.scale = states.iterator().next().getScale();
}
}
public int getStatesCount() {
return this.states.size();
}
public int getClass(int offset) {
return index[offset];
}
public int classify() {
IScale.Index index = scale.getIndex(locators);
this.index = new int[index.size()];
// prepare the fastest int array we can use as key
List mc = new ArrayList<>();
for (int i = 0; i < states.size(); i++) {
mc.add(-1);
}
int idx = 0;
for (int offset : index) {
int i = 0;
boolean nodata = false;
for (MapDescriptor md : states) {
int n = md.getClass(offset);
if (n < 0) {
nodata = true;
break;
}
mc.set(i++, n);
}
this.index[idx++] = nodata ? 0 : getMapClass(mc);
}
return classes.size();
}
private int getMapClass(List mc) {
String nnc = StringUtils.join(mc, '|');
MapClass clas = classCatalog.get(nnc);
if (clas == null) {
clas = new MapClass();
clas.classifiers = new ArrayList<>(mc);
classes.add(clas);
clas.index = classes.size() - 1;
classCatalog.put(nnc, clas);
}
return clas.index;
}
public Collection getClasses() {
return classes;
}
/**
* Redistribute values inside a passed state. Pass the values in the same order as the
* classes.
*
* @param state
* @param values
*
*/
public void distributeResults(IState state, double[] values) {
int n = 0;
for (int i : scale.getIndex(locators)) {
if (scale.isCovered(i)) {
States.set(state, values[classes.get(index[n]).index], i);
}
n++;
}
}
}