/*******************************************************************************
* 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.srl;
import java.io.BufferedReader;
import java.io.PrintStream;
import java.io.StringReader;
import java.util.Collection;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import edu.tum.cs.util.FileUtil;
/**
* Represents a standard relational database (that can be used as training or evidence data)
* with string-valued variables.
* @author Dominik Jain
*/
public class Database extends GenericDatabase<Variable, String> {
public Database(RelationalModel model) throws Exception {
super(model);
}
public String getVariableValue(String varName, boolean closedWorld) throws Exception {
String lowerCaseName = varName.toLowerCase();
Variable var = this.entries.get(lowerCaseName);
// if we have the value, return it
if(var != null)
return var.getValue();
// otherwise, get the signature
int braceIndex = varName.indexOf('(');
String functionName = varName.substring(0, braceIndex);
Signature sig = model.getSignature(functionName);
// if it's a logically determined predicate, use prolog to retrieve a value
if(sig.isLogical) {
if(!sig.isBoolean())
throw new Exception("Value for logical/evidence variable '" + varName + "' not found in the database and cannot use Prolog to retrieve a value for non-Boolean functions"); // TODO could allow Prolog via a logical coupling
if(this.isFinalized())
return BooleanDomain.False;
else {
String[] args = varName.substring(braceIndex+1, varName.length()-1).split("\\s*,\\s*");
return getPrologValue(sig, args, false) ? BooleanDomain.True : BooleanDomain.False;
}
}
// if we are making the closed assumption return the default value of
// false for boolean predicates or raise an exception for non-boolean
// functions
if(closedWorld) {
if(sig.isBoolean())
return BooleanDomain.False;
else {
throw new Exception("Missing database value of " + varName + " - cannot apply closed-world assumption because domain is not boolean: " + sig.returnType);
}
}
return null;
}
@Override
protected Variable readEntry(String line) {
Pattern re_entry = Pattern.compile("(\\w+)\\(([^\\)]+)\\)\\s*=\\s*([^;]*);?");
Matcher matcher = re_entry.matcher(line);
if(matcher.matches()) {
// String key = matcher.group(1) + "(" +
// matcher.group(2).replaceAll("\\s*", "") + ")";
Variable var = makeVar(matcher.group(1), matcher.group(2).split("\\s*,\\s*"), matcher.group(3)); // new Variable(matcher.group(1), matcher.group(2).split("\\s*,\\s*"), matcher.group(3), model);
// System.out.println(var.toString());
return var;
}
return null;
}
/**
*
* */
public void readMLNDB(String databaseFilename, boolean ignoreUndefinedNodes) throws Exception {
boolean verbose = false;
// read file content
if(verbose)
System.out.printf("reading contents of %s...\n", databaseFilename);
String dbContent = FileUtil.readTextFile(databaseFilename);
// remove comments
// if (verbose) System.out.println(" removing comments...");
Pattern comments = Pattern.compile("//.*?$|/\\*.*?\\*/", Pattern.MULTILINE | Pattern.DOTALL);
Matcher matcher = comments.matcher(dbContent);
dbContent = matcher.replaceAll("");
// read lines
// if (verbose) System.out.println(" reading items...");
String arg = "\\w+";
String argList = "\\s*" + arg + "\\s*(?:,\\s*" + arg + "\\s*)*";
Pattern re_entry = Pattern.compile("(!?\\w+)\\((" + argList + ")\\)");
Pattern re_domDecl = Pattern.compile("(\\w+)\\s*=\\s*\\{(" + argList + ")\\}");
BufferedReader br = new BufferedReader(new StringReader(dbContent));
String line;
Variable var;
while((line = br.readLine()) != null) {
line = line.trim();
// parse variable assignment
matcher = re_entry.matcher(line);
if(matcher.matches()) {
if(matcher.group(1).startsWith("!"))
var = new Variable(matcher.group(1).substring(1), matcher.group(2).trim().split("\\s*,\\s*"), "False", model);
else
var = new Variable(matcher.group(1), matcher.group(2).trim().split("\\s*,\\s*"), "True", model);
addVariable(var, ignoreUndefinedNodes, true);
// if (++numVars % 100 == 0 && verbose)
// System.out.println(" " + numVars + " vars read\r");
continue;
}
// parse domain extension
matcher = re_domDecl.matcher(line);
if(matcher.matches()) { // parse
String domNam = matcher.group(1);
String[] constants = matcher.group(2).trim().split("\\s*,\\s*");
for(String c : constants)
fillDomain(domNam, c);
continue;
}
// something else
if(line.length() != 0)
System.err.println("Line could not be read: " + line);
}
}
/**
* @return the values of this database as an array of String[2] arrays,
* where the first element of each is the name of the variable, and
* the second is the value
* @throws Exception
*/
public String[][] getEntriesAsArray() throws Exception {
Collection<Variable> vars = getEntries();
String[][] ret = new String[entries.size()][2];
int i = 0;
for(Variable var : vars) {
ret[i][0] = var.getKeyString();
ret[i][1] = var.getValue();
i++;
}
return ret;
}
@Override
protected Variable makeVar(String functionName, String[] args, String value) {
return new Variable(functionName, args, value, model);
}
/**
*
* @param databaseFilename
* @throws java.lang.Exception
*/
public void readMLNDB(String databaseFilename) throws Exception {
readMLNDB(databaseFilename, false);
}
@Override
public void fillDomain(String domName, Variable var) throws Exception {
fillDomain(domName, var.value);
}
@Override
public String getSingleVariableValue(String varName, boolean closedWorld) throws Exception {
return getVariableValue(varName, closedWorld);
}
public void writeMLNDatabase(PrintStream out) throws Exception {
for(Variable var : this.getEntries()) {
out.println(var.getPredicate());
}
}
}