00001 package edu.tum.cs.rpt;
00002 import kdl.prox3.db.ProxDB;
00003 import kdl.prox3.model.classifiers.*;
00004 import kdl.prox3.script.ItemModelAttr;
00005 import kdl.prox3.model.features.*;
00006 import java.util.*;
00007 import kdl.prox3.model.estimators.*;
00008 import java.io.*;
00009 import java.util.regex.*;
00010
00011
00012 public class RPT2Logic {
00013
00014 protected String coreItemName, coreItemVar, attribute;
00015 protected Vector<Path> paths;
00016 protected HashMap<String, ObjectType> objects;
00017 protected HashMap<String, RelationType> relations;
00018 protected ObjectType coreObject;
00019 protected boolean walkRecursive;
00020 protected String precondition = "";
00024 protected double totalSamplesInTree;
00028 protected String currentNodeObjectVar;
00029
00036 public RPT2Logic(String attribute, String coreObjectName, String coreObjectVar) {
00037 objects = new HashMap<String, ObjectType>();
00038 paths = new Vector<Path>();
00039 relations = new HashMap<String, RelationType>();
00040 this.coreItemName = coreObjectName;
00041 this.coreItemVar = coreObjectVar;
00042 this.attribute = attribute;
00043 this.coreObject = new ObjectType(coreObjectName, coreObjectVar, null, null);
00044 }
00045
00051 public RPT2Logic(String attribute, String coreRelationName) {
00052 objects = new HashMap<String, ObjectType>();
00053 paths = new Vector<Path>();
00054 relations = new HashMap<String, RelationType>();
00055 this.coreItemName = coreRelationName;
00056 this.attribute = attribute;
00057 this.coreObject = null;
00058 }
00059
00060 public ObjectType getCoreObject() {
00061 return coreObject;
00062 }
00063
00064 public void setCoreItemVar(String var) {
00065 this.coreItemVar = var;
00066 if(coreObject != null)
00067 this.coreObject.setVarName(var);
00068 }
00069
00075 public void walkTree(RPNode root) {
00076
00077 DiscreteEstimator de = root.getClassLabelDistribution();
00078 ProbDistribution dist = de.getProbDistribution();
00079 this.totalSamplesInTree = dist.getTotalNumValues();
00080
00081 walkTree(root, new Path());
00082 }
00083
00084 protected class DistributionValue implements Comparable {
00085 public String value;
00086 public double probability;
00087
00088 public DistributionValue(String value, Double count, double total) {
00089 this.value = value;
00090 this.probability = count/total;
00091 }
00092
00093 public int compareTo(Object o) {
00094 return (int)-Math.signum(probability - ((DistributionValue)o).probability);
00095 }
00096 }
00097
00098 protected boolean isBooleanValue(String value) {
00099 return value.equals("True") || value.equals("False");
00100 }
00101
00102 protected class Path implements Cloneable {
00107 public Vector<String> items;
00108 public HashSet<ObjectType> precondition;
00112 protected double support;
00116 protected double accuracy;
00117
00118 public Path() {
00119 precondition = new HashSet<ObjectType>();
00120 items = new Vector<String>();
00121 }
00122
00123 public Path clone() {
00124 Path p = new Path();
00125 p.items = (Vector<String>)items.clone();
00126 p.precondition = (HashSet<ObjectType>)precondition.clone();
00127 return p;
00128 }
00129
00130 public String toString() {
00131 return items.toString();
00132 }
00133 }
00134
00135 protected String getAtom(Path path, String predicate, String item, String value) {
00136
00137 String atom = predicate + "(";
00138
00139 RelationType li = this.relations.get(item);
00140 if(li != null) {
00141 atom += li.from.varName + ", " + li.to.varName;
00142 path.precondition.add(li.from);
00143 path.precondition.add(li.to);
00144
00145 if(!this.isBooleanValue(value)) {
00146 System.err.println(" Warning: only boolean value allowed as link attribute value - got " + value);
00147 walkRecursive = false;
00148 }
00149 }
00150 else {
00151
00152 if(item.equals(coreItemName))
00153 atom += (this.currentNodeObjectVar = coreItemVar);
00154
00155 else {
00156 ObjectType rel = this.objects.get(item);
00157 if(rel != null) {
00158 atom += (this.currentNodeObjectVar = rel.varName);
00159 path.precondition.add(rel);
00160 }
00161 else {
00162
00163 System.err.println(" Warning: unhandled link/relation to " + item);
00164 walkRecursive = false;
00165 }
00166 }
00167 }
00168 if(isBooleanValue(value))
00169 atom = (value.equals("False") ? "!" : "") + atom + ")";
00170 else
00171 atom += ", " + value + ")";
00172 return atom;
00173 }
00174
00175 protected void walkTree(RPNode node, Path path) {
00176 walkRecursive = true;
00177
00178
00179 if(node.isLeaf()) {
00180
00181 DiscreteEstimator de = node.getClassLabelDistribution();
00182 ProbDistribution dist = de.getProbDistribution();
00183 Map distMap = dist.getDistributionMap();
00184 Iterator iEntry = distMap.entrySet().iterator();
00185 TreeSet<DistributionValue> sortedVals = new TreeSet<DistributionValue>();
00186 while(iEntry.hasNext()) {
00187 Map.Entry entry = (Map.Entry) iEntry.next();
00188 sortedVals.add(new DistributionValue((String)entry.getKey(), (Double)entry.getValue(), dist.getTotalNumValues()));
00189 }
00190
00191 path.support = dist.getTotalNumValues() / this.totalSamplesInTree;
00192
00193 int numDisjuncts = 1;
00194 Iterator<DistributionValue> iter = sortedVals.iterator();
00195 DistributionValue mode = iter.next();
00196 double prob = mode.probability;
00197 path.accuracy = prob;
00198 String formula = getAtom(path, this.attribute, this.coreItemName, mode.value);
00199
00200 while(iter.hasNext()) {
00201 DistributionValue v = iter.next();
00202 if(v.probability > prob*0.6666) {
00203 formula += " v " + getAtom(path, this.attribute, this.coreItemName, v.value);
00204 numDisjuncts++;
00205 path.accuracy += v.probability;
00206 }
00207 else
00208 break;
00209 prob = v.probability;
00210 }
00211
00212 if(numDisjuncts == sortedVals.size()) {
00213 System.err.println(" Note: trivial clause for path " + path);
00214 return;
00215 }
00216
00217 path.items.add(formula);
00218
00219 paths.add(path);
00220
00221 return;
00222 }
00223
00224
00225 ItemModelAttr attr = node.getNodeAttr();
00226 FeatureSetting featureSetting = node.getBestFeature();
00227 Feature feature = featureSetting.getFeature();
00228 String featureSig = feature.getShortSignature();
00229 String attrName = attr.getAttrName();
00230 String operator = feature.getOperator();
00231 String item = featureSetting.getItem();
00232 Double threshold = Double.parseDouble(featureSetting.getThreshold());
00233 String value = featureSetting.getValue();
00234 String atom = getAtom(path, attrName, item, value);
00235
00236
00237 String formula = new String();
00238 if(featureSig.equals("Count")) {
00239 if(operator.equals(">=")) {
00240 if(threshold == 1.0) {
00241 formula = atom;
00242 }
00243 else {
00244 System.err.println(" Warning: unsupported threshold " + threshold + " for feature type " + featureSig);
00245 return;
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265 }
00266 }
00267 else {
00268 System.err.println(" Warning: unsupported operator " + operator + " for feature type " + featureSig);
00269 return;
00270 }
00271 }
00272 else {
00273 System.err.println(" Warning: unsupported feature type " + featureSig + " (" + path + ")");
00274 return;
00275 }
00276
00277
00278 if(walkRecursive) {
00279 Path path2 = (Path) path.clone();
00280 path.items.add(formula);
00281 walkTree(node.getYesSubtree(), path);
00282 String negatedFormula = formula.charAt(0) == '!' ? formula.substring(1) : "!" + formula;
00283 path2.items.add(negatedFormula);
00284 walkTree(node.getNoSubtree(), path2);
00285 }
00286 }
00287
00288 public String createImplication(Path path, int idx, boolean bConsequentIdx) {
00289 String formula = new String();
00290
00291
00292 String precondition = this.precondition;
00293
00294 if(!path.precondition.isEmpty()) {
00295 Iterator<ObjectType> iRelation = path.precondition.iterator();
00296 while(iRelation.hasNext()) {
00297 ObjectType rel = iRelation.next();
00298 String precondition2 = rel.getPrecondition(path.precondition);
00299 if(!precondition2.equals("")) {
00300 if(!precondition.equals(""))
00301 precondition += " ^ ";
00302 precondition += precondition2;
00303 }
00304 }
00305 }
00306
00307 if(relations.containsKey(coreItemName)) {
00308 RelationType rel = relations.get(coreItemName);
00309 String precondition2 = this.coreItemName + "(" + rel.from.varName + ", " + rel.to.varName + ")";
00310
00311 if(!precondition.contains(precondition2)) {
00312 if(!precondition.equals(""))
00313 precondition += " ^ ";
00314 precondition += precondition2;
00315 }
00316 }
00317
00318 if(!precondition.equals(""))
00319 formula += precondition + " => (";
00320
00321 if(!bConsequentIdx)
00322 formula += path.items.get(idx) + " => ";
00323 boolean empty = true;
00324 for(int i = 0; i < path.items.size(); i++) {
00325 if(i != idx) {
00326 if(!empty)
00327 formula += " ^ ";
00328 formula += path.items.get(i);
00329 empty = false;
00330 }
00331 }
00332 if(bConsequentIdx)
00333 formula += " => " + path.items.get(idx);
00334
00335 if(!precondition.equals(""))
00336 formula += ")";
00337
00338 return formula;
00339 }
00340
00341 public Vector<String> getFormulas(boolean calculateWeights, boolean addReverseImplications) {
00342 Vector<String> formulas = new Vector<String>();
00343 Iterator<Path> iPaths = paths.iterator();
00344 while(iPaths.hasNext()) {
00345 Path path = iPaths.next();
00346 String prefix = "";
00347 if(calculateWeights) {
00348 double prob = path.accuracy * path.support + (1-path.support);
00349 if(prob == 1.0)
00350 prob = 0.999999;
00351 double weight = Math.log(prob/(1-prob));
00352 prefix = String.format("%.6f ", weight);
00353 }
00354 formulas.add(prefix + createImplication(path, path.items.size()-1, true));
00355 if(!calculateWeights && addReverseImplications)
00356 formulas.add(createImplication(path, path.items.size()-1, false));
00357 }
00358 return formulas;
00359 }
00360
00366 public class ObjectType {
00367 public String objName, varName;
00368 protected String precondition;
00369 protected ObjectType[] referencedObjects;
00370
00377 ObjectType(String objName, String varName, String precondition, ObjectType[] referencedRelations) {
00378 this.objName = objName;
00379 this.varName = varName;
00380 this.precondition = precondition;
00381 this.referencedObjects = referencedRelations;
00382 }
00383
00384 public String getPrecondition() {
00385 return getPrecondition(new HashSet<ObjectType>());
00386 }
00387
00388 public String getPrecondition(Set<ObjectType> excludedReferences) {
00389 String ret = "";
00390 int preconditions = 0;
00391 if(precondition != null) {
00392 ret = precondition;
00393 preconditions++;
00394 }
00395 if(referencedObjects != null) {
00396 for(int i = 0; i < referencedObjects.length; i++) {
00397 if(!excludedReferences.contains(referencedObjects[i])) {
00398 if(preconditions > 0)
00399 ret += " ^ ";
00400 ret += referencedObjects[i].getPrecondition(excludedReferences);
00401 }
00402 }
00403 }
00404 return ret;
00405 }
00406
00407 public void setVarName(String varName) {
00408 this.varName = varName;
00409 }
00410 }
00411
00412 public ObjectType setObjectType(String objName, String varName, String precondition, ObjectType[] referencedRelations) {
00413 ObjectType rel = new ObjectType(objName, varName, precondition, referencedRelations);
00414 objects.put(objName, rel);
00415 return rel;
00416 }
00417
00418 public class RelationType {
00419 public ObjectType from, to;
00420 public RelationType(ObjectType from, ObjectType to) {
00421 this.to = to;
00422 this.from = from;
00423 }
00424 }
00425
00432 public void setRelationType(String itemName, ObjectType from, ObjectType to) {
00433 relations.put(itemName, new RelationType(from, to));
00434 }
00435
00436 public void setPrecondition(String precond) {
00437 this.precondition = precond;
00438 }
00439 }