00001 package edu.tum.cs.srldb.datadict;
00002
00003 import java.io.PrintStream;
00004 import java.util.*;
00005 import java.util.Map.Entry;
00006
00007 import org.xml.sax.Attributes;
00008
00009 import edu.ksu.cis.bnj.ver3.core.BeliefNode;
00010 import edu.tum.cs.bayesnets.core.BeliefNetworkEx;
00011 import edu.tum.cs.srldb.datadict.domain.AutomaticDomain;
00012 import edu.tum.cs.srldb.datadict.domain.Domain;
00013 import edu.tum.cs.srldb.ConstantArgument;
00014 import edu.tum.cs.srldb.Database;
00015 import edu.tum.cs.srldb.IRelationArgument;
00016 import edu.tum.cs.srldb.IdentifierNamer;
00017 import edu.tum.cs.srldb.Item;
00018 import edu.tum.cs.srldb.Link;
00019 import edu.tum.cs.srldb.Object;
00020
00021 public class DataDictionary implements java.io.Serializable {
00022
00023 private static final long serialVersionUID = 1L;
00024 protected HashMap<String, DDObject> objects;
00025 protected HashMap<String, DDRelation> relations;
00026 protected HashMap<String, DDAttribute> attributes;
00030 protected HashMap<String, Domain> domains;
00031
00032 public DataDictionary() {
00033 objects = new HashMap<String, DDObject>();
00034 attributes = new HashMap<String, DDAttribute>();
00035 relations = new HashMap<String, DDRelation>();
00036 domains = new HashMap<String, Domain>();
00037 }
00038
00039 public void addObject(DDObject obj) throws DDException {
00040 objects.put(obj.getName(), obj);
00041 addAttributes(obj);
00042 }
00043
00049 protected void addAttributes(DDItem item) throws DDException {
00050 for(DDAttribute attr : item.getAttributes().values()) {
00051 addAttribute(attr);
00052 }
00053 }
00054
00063 public void addAttribute(DDAttribute attr) throws DDException {
00064 if(attributes.containsKey(attr.getName())) {
00065 throw new DDException("Duplicate attribute " + attr.getName() + "; already defined for item " + attr.getOwner().getName());
00066 }
00067 attributes.put(attr.getName(), attr);
00068 domains.put(attr.getDomain().getName(), attr.getDomain());
00069 }
00070
00071 public void addRelation(DDRelation rel) throws DDException {
00072 relations.put(rel.getName(), rel);
00073 addAttributes(rel);
00074
00075 }
00076
00077 public Collection<DDAttribute> getAttributes() {
00078 return attributes.values();
00079 }
00080
00081 public DDObject getObject(String name) throws DDException {
00082 return objects.get(name);
00083 }
00084
00085 public DDRelation getRelation(String name) {
00086 return relations.get(name);
00087 }
00088
00089 public DDAttribute getAttribute(String name) throws DDException {
00090 return attributes.get(name);
00091 }
00092
00093 public Domain getDomain(String name) {
00094 return domains.get(name);
00095 }
00096
00097 public Collection<DDObject> getObjects() {
00098 return objects.values();
00099 }
00100
00101 public Collection<DDRelation> getRelations() {
00102 return relations.values();
00103 }
00104
00105 protected class DomainData {
00106 public Domain domain;
00107 public Vector<DDAttribute> occurrences = new Vector<DDAttribute>();
00108 public String[] values;
00109 public boolean wasReplaced = false;
00110 public DomainData(Domain domain) {
00111 this.domain = domain;
00112 values = domain.getValues();
00113 }
00114 }
00115
00124 public void check() throws DDException {
00125
00126 HashMap<String, DomainData> domains = new HashMap<String,DomainData>();
00127 for(DDAttribute attrib : this.attributes.values()) {
00128 Domain domain = attrib.getDomain();
00129 String domName = domain.getName();
00130 DomainData dd;
00131 if(!domains.containsKey(domName))
00132 domains.put(domName, dd = new DomainData(domain));
00133 else
00134 dd = domains.get(domName);
00135 dd.occurrences.add(attrib);
00136 }
00137
00138 DomainData[] dd = new DomainData[domains.size()];
00139 domains.values().toArray(dd);
00140 domains = null;
00141 for(int i = 0; i < dd.length; i++) {
00142 if(dd[i].wasReplaced) continue;
00143
00144 for(int j = i+1; j < dd.length; j++) {
00145 if(dd[j].wasReplaced) continue;
00146
00147 for(int k = 0; k < dd[i].values.length; k++) {
00148
00149 if(dd[j].domain.containsString(dd[i].values[k])) {
00150 System.err.println("Warning: domain " + dd[i].domain.getName() + " already contains value '" + dd[i].values[k] + "' of domain " + dd[j].domain.getName() + "; replacing all occurrences of " + dd[j].domain.getName() + "!");
00151 for(DDAttribute attrib : dd[j].occurrences)
00152 attrib.setDomain(dd[i].domain);
00153 dd[j].wasReplaced = true;
00154
00155
00156
00157
00158
00159
00160 break;
00161 }
00162 }
00163 }
00164 }
00165
00166 Set<String> attrNames = this.attributes.keySet();
00167 Set<String> linkNames = new HashSet<String>(this.relations.keySet());
00168 linkNames.retainAll(attrNames);
00169 if(!linkNames.isEmpty()) {
00170 throw new DDException("Error: Duplicate predicate name(s); the name(s) " + linkNames.toString() + " cannot be used for attributes and links simultaneously!");
00171 }
00172 }
00173
00178 public void outputAttributeLists(PrintStream out) {
00179 for(DDObject obj : getObjects()) {
00180 obj.outputAttributeList(out);
00181 }
00182 for(DDRelation rel : getRelations()) {
00183 rel.outputAttributeList(out);
00184 }
00185 }
00186
00191 public void outputAttributeList(PrintStream out) {
00192 int i = 0;
00193 for(DDAttribute attr : this.attributes.values()) {
00194 if(attr.isDiscarded())
00195 continue;
00196 if(i++ > 0)
00197 out.print(",");
00198 out.print(Database.stdAttribName(attr.getName()));
00199 }
00200 }
00201
00202 public void checkObject(Object obj) throws DDException {
00203 DDObject ddobj = getObject(obj.objType());
00204 if(ddobj == null)
00205 throw new DDException("Unknown object type " + obj.objType() + "; not in data dictionary!");
00206 checkItemAttributes(obj, ddobj);
00207 }
00208
00209 public void checkLink(Link link) throws DDException, Exception {
00210
00211 DDRelation ddlink = getRelation(link.getName());
00212 if(ddlink == null)
00213 throw new DDException("Unknown relation " + link.getName() + "; not in data dictionary!");
00214
00215 if(link.getArguments().length != ddlink.getArguments().length)
00216 throw new DDException("The link " + link.toString() + " has the wrong number of parameters!");
00217
00218 int i = 0;
00219 for(IRelationArgument arg : link.getArguments()) {
00220 IDDRelationArgument argtype = ddlink.getArguments()[i];
00221 if(arg instanceof Object) {
00222 Object o = (Object)arg;
00223 if(o.objType() != argtype.getDomainName())
00224 throw new DDException(String.format("Type mismatch for the %dth argument of %s; should be %s!", i+1, link.toString(), argtype.getDomainName()));
00225 }
00226 else {
00227 if(!(arg instanceof ConstantArgument)) {
00228 throw new DDException(String.format("Type mismatch for argument %d of %s; expected a constant argument!", i+1, link.toString()));
00229 }
00230 DDConstantArgument ddconst = (DDConstantArgument) argtype;
00231 if(!ddconst.getDomain().contains(arg.getConstantName()))
00232 throw new DDException(String.format("Domain of argument %d of %s does not contain %s!", i+1, link.toString(), arg.getConstantName()));
00233 }
00234 i++;
00235 }
00236
00237 checkItemAttributes(link, ddlink);
00238 }
00239
00246 protected void checkItemAttributes(Item item, DDItem ddItem) throws DDException {
00247 Set<String> allowedAttributes = ddItem.getAttributes().keySet();
00248 for(Entry<String,String> attr : item.getAttributes().entrySet()) {
00249 String attribName = attr.getKey();
00250 if(!allowedAttributes.contains(attribName))
00251 throw new DDException("Undefined attribute '" + attribName + "' for item type '" + ddItem.getName() + "' or the attribute was applied to more than one type of object.");
00252 if(getAttribute(attribName).isDiscarded())
00253 continue;
00254 Domain domain = ddItem.getAttributes().get(attribName).getDomain();
00255 String value = attr.getValue();
00256 if(!domain.containsString(value))
00257 throw new DDException("Invalid value " + value + " for attribute " + attribName + " of item " + ddItem.getName() + "; not in domain " + domain.getName());
00258 }
00259 }
00260
00261 public void onCommitObject(Object o) throws DDException {}
00262
00263 public void onCommitLink(Link l) throws DDException {}
00264
00269 public void writeBasicMLN(PrintStream out) {
00270 DataDictionary datadict = this;
00271 out.println("// Markov Logic Network\n\n");
00272 IdentifierNamer idNamer = new IdentifierNamer(datadict);
00273
00274 out.println("// ***************\n// domains\n// ***************\n");
00275 HashSet<String> printedDomains = new HashSet<String>();
00276
00277 for(DDAttribute attrib : datadict.getAttributes()) {
00278 if(attrib.isDiscarded())
00279 continue;
00280 Domain domain = attrib.getDomain();
00281 if(domain == null || attrib.isBoolean() || !domain.isFinite())
00282 continue;
00283
00284 String name = domain.getName();
00285 if(!printedDomains.contains(name)) {
00286
00287 String[] values = domain.getValues();
00288 if(values.length == 0) {
00289 System.err.println("Warning: Domain " + domain.getName() + " is empty!");
00290 continue;
00291 }
00292
00293 String domIdentifier = idNamer.getLongIdentifier("domain", domain.getName());
00294 out.print(domIdentifier + " = {");
00295
00296 for(int i = 0; i < values.length; i++) {
00297 if(i > 0)
00298 out.print(", ");
00299 out.print(Database.stdAttribStringValue(values[i]));
00300 }
00301 out.println("}");
00302 printedDomains.add(name);
00303 }
00304 }
00305
00306 out.println("\n\n// *************************\n// predicate declarations\n// *************************\n");
00307 for(DDObject obj : datadict.getObjects()) {
00308 obj.MLNprintPredicateDeclarations(idNamer, out);
00309 }
00310 out.println("// Relations");
00311 for(DDRelation rel : datadict.getRelations()) {
00312 rel.MLNprintPredicateDeclarations(idNamer, out);
00313 }
00314
00315 out.println("\n\n// ******************\n// rules\n// ******************\n");
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325 out.println("\n// unit clauses");
00326 for(DDObject obj : datadict.getObjects()) {
00327 obj.MLNprintUnitClauses(idNamer, out);
00328 }
00329 for(DDRelation rel : datadict.getRelations()) {
00330 rel.MLNprintUnitClauses(idNamer, out);
00331 }
00332 }
00333
00338 public void writeBasicBLOGModel(PrintStream out) {
00339 out.println("// Advanced BLOG (ABL) Model\n\n");
00340 IdentifierNamer idNamer = new IdentifierNamer(this);
00341
00342 out.println("// ***************\n// types\n// ***************\n");
00343 for(DDObject ddo : this.getObjects())
00344 out.printf("Type %s;\n", idNamer.getLongIdentifier("domain", ddo.getDomainName()));
00345 for(DDAttribute dda : this.getAttributes())
00346 if(!dda.isDiscarded() && !dda.isBoolean())
00347 out.printf("Type %s;\n", idNamer.getLongIdentifier("domain", dda.getDomain().getName()));
00348
00349 out.println("\n// ***************\n// domains\n// ***************\n");
00350 HashSet<String> printedDomains = new HashSet<String>();
00351
00352 for(DDAttribute attrib : this.getAttributes()) {
00353 if(attrib.isDiscarded())
00354 continue;
00355 Domain<?> domain = attrib.getDomain();
00356 if(domain == null || attrib.isBoolean() || !domain.isFinite())
00357 continue;
00358
00359 String name = domain.getName();
00360 if(!printedDomains.contains(name)) {
00361
00362 String[] values = domain.getValues();
00363 if(values.length == 0) {
00364 System.err.println("Warning: Domain " + domain.getName() + " is empty!");
00365 continue;
00366 }
00367
00368 String domIdentifier = idNamer.getLongIdentifier("domain", domain.getName());
00369 out.print("guaranteed " + domIdentifier + " ");
00370
00371 for(int i = 0; i < values.length; i++) {
00372 if(i > 0)
00373 out.print(", ");
00374 out.print(Database.stdAttribStringValue(values[i]));
00375 }
00376 out.println(";");
00377 printedDomains.add(name);
00378 }
00379 }
00380
00381 out.println("\n\n// *************************\n// predicate declarations\n// *************************\n");
00382 for(DDObject obj : this.getObjects()) {
00383 obj.BLNprintPredicateDeclarations(idNamer, out);
00384 }
00385 out.println("// Relations");
00386 for(DDRelation rel : this.getRelations()) {
00387 rel.BLNprintPredicateDeclarations(idNamer, out);
00388 }
00389 }
00390
00391
00392 public static class BLNStructure {
00393 public BeliefNetworkEx bn;
00394 protected HashMap<java.lang.Object,BeliefNode> dd2node;
00395
00396 public BLNStructure(BeliefNetworkEx bn, HashMap<java.lang.Object,BeliefNode> dd2node) {
00397 this.bn = bn;
00398 this.dd2node = dd2node;
00399 }
00400
00401 public BeliefNode getNode(DDAttribute attr) {
00402 return dd2node.get(attr);
00403 }
00404
00405 public BeliefNode getNode(DDRelation rel) {
00406 return dd2node.get(rel);
00407 }
00408
00409 public void connect(java.lang.Object ddAttributeOrRelation_Parent, java.lang.Object ddAttributeOrRelation_Child) {
00410 bn.bn.connect(dd2node.get(ddAttributeOrRelation_Parent), dd2node.get(ddAttributeOrRelation_Child));
00411 }
00412
00413 public void disconnect(java.lang.Object ddAttributeOrRelation_Parent, java.lang.Object ddAttributeOrRelation_Child) {
00414 bn.bn.disconnect(dd2node.get(ddAttributeOrRelation_Parent), dd2node.get(ddAttributeOrRelation_Child));
00415 }
00416 }
00417
00418 public BLNStructure createBasicBLNStructure() {
00419 BeliefNetworkEx bn = new BeliefNetworkEx();
00420 HashMap<java.lang.Object, BeliefNode> dd2node = new HashMap<java.lang.Object, BeliefNode>();
00421 IdentifierNamer namer = new IdentifierNamer(this);
00422
00423 for(DDAttribute attr : this.getAttributes()) {
00424 if(attr.isDiscarded())
00425 continue;
00426 String nodeName = String.format("%s(%s)", attr.getName(), namer.getShortIdentifier("object", attr.getOwner().getName()));
00427 dd2node.put(attr, bn.addNode(nodeName));
00428 }
00429
00430 for(edu.tum.cs.srldb.datadict.DDRelation rel : this.getRelations()) {
00431 StringBuffer nodeName = new StringBuffer(rel.getName() + "(");
00432 IDDRelationArgument[] relargs = rel.getArguments();
00433 for(int i = 0; i < relargs.length; i++) {
00434 if(i > 0)
00435 nodeName.append(',');
00436 nodeName.append(namer.getShortIdentifier(rel.getName(), relargs[i].getDomainName()));
00437 }
00438 nodeName.append(')');
00439 dd2node.put(rel, bn.addNode(nodeName.toString()));
00440 }
00441 return new BLNStructure(bn, dd2node);
00442 }
00443
00444 public String toString() {
00445 StringBuffer sb = new StringBuffer("DataDictionary:\n");
00446 for(DDObject ddo : this.objects.values()) {
00447 sb.append(ddo);
00448 sb.append('\n');
00449 }
00450 for(DDRelation ddr : this.relations.values()) {
00451 sb.append(ddr);
00452 sb.append('\n');
00453 }
00454 return sb.toString();
00455 }
00456
00460 public void cleanUp() {
00461 domains.clear();
00462 for(DDAttribute attr : attributes.values())
00463 domains.put(attr.getDomain().getName(), attr.getDomain());
00464 }
00465 }