/*******************************************************************************
* Copyright (C) 2006-2012 Dominik Jain.
*
* This file is part of ProbCog.
*
* ProbCog is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ProbCog 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
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProbCog. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package probcog.srldb.datadict;
import java.util.Map.Entry;
import probcog.srldb.Database;
import probcog.srldb.IRelationArgument;
import probcog.srldb.Item;
import probcog.srldb.Link;
import probcog.srldb.Object;
import probcog.srldb.datadict.domain.AutomaticDomain;
import probcog.srldb.datadict.domain.Domain;
/**
* Represents a data dictionary that is built up automatically based on
* the data that is observed.
* @author Dominik Jain
*/
public class AutomaticDataDictionary extends DataDictionary {
private static final long serialVersionUID = 1L;
public AutomaticDataDictionary() {
super();
}
@Override
public void onCommitObject(Object o) throws DDException {
// add the object type to the data dictionary if it isn't contained yet
DDObject ddo = this.getObject(o.objType());
if(ddo == null)
addObject(ddo = new DDObject(o.objType()));
// process the attributes
onCommitItemAttributes(o, ddo);
}
protected void onCommitItemAttributes(Item item, DDItem ddi) throws DDException {
// add all attributes that aren't contained yet as attributes with automatic domains
// and extend all automatic attribute domains
for(Entry<String,String> e : item.getAttributes().entrySet()) {
String attrName = e.getKey();
DDAttribute dda = this.getAttribute(attrName);
if(dda == null) {
AutomaticDomain dom = new AutomaticDomain("dom" + Database.upperCaseString(attrName));
addAttribute(dda = new DDAttribute(attrName, dom));
ddi.addAttribute(dda);
dom.addValue(e.getValue());
}
else {
Domain<?> dom = dda.getDomain();
if(dom instanceof AutomaticDomain)
((AutomaticDomain)dom).addValue(e.getValue());
}
}
}
@Override
public void onCommitLink(Link link) throws DDException {
DDRelation ddlink = getRelation(link.getName());
if(ddlink == null) { // this relation is not yet in the data dictionary
// get a data dictionary definition for each argument
IRelationArgument[] args = link.getArguments();
IDDRelationArgument[] ddArgs = new IDDRelationArgument[args.length];
int i = 0;
for(IRelationArgument arg : args) {
// if it's an object, check if we have a definition for that type of object
if(arg instanceof Object) {
Object obj = (Object) arg;
ddArgs[i] = getObject(obj.objType());
}
// it's a constant (which is treated as an attribute value such that its domain can be collected and written appropriately)
else {
// add an attribute with an AutomaticDomain if necessary
String domName = "dom" + Database.upperCaseString(link.getName()) + i;
DDAttribute ddattr = this.attributes.get(domName);
if(ddattr == null) {
DDConstantArgument ddconst = new DDConstantArgument(link.getName() + i, new AutomaticDomain(domName));
ddArgs[i] = ddconst;
addAttribute(ddconst);
}
}
i++;
}
// create the relation definition and add it to the dictionary
ddlink = new DDRelation(link.getName(), ddArgs);
this.addRelation(ddlink);
}
// check the link's attributes (and extend their domains if necessary)
onCommitItemAttributes(link, ddlink);
// check for constant arguments (and extend the corresponding domains if necessary)
int i = 0;
for(IDDRelationArgument argtype : ddlink.getArguments()) {
if(argtype instanceof DDConstantArgument) {
Domain<?> dom = getDomain(argtype.getDomainName());
// extend the domain if applicable
IRelationArgument arg = link.getArguments()[i];
String value = arg.getConstantName();
if(!dom.containsString(value)) {
if(dom instanceof AutomaticDomain) {
((AutomaticDomain)dom).addValue(value);
}
else
throw new DDException("Argument " + (i+1) + " of " + link.toString() + " is invalid; not in domain " + dom.getName());
}
}
i++;
}
}
}