use of com.sri.ai.praise.lang.grounded.common.FunctionTable in project aic-praise by aic-sri-international.
the class AbstractUAI_to_HOGMv1_Translator method translate.
// END-Translator
//
@Override
protected void translate(String inputIdentifier, UAIModel uaiModel, PrintWriter[] translatedOutputs) throws Exception {
PrintWriter hogmv1ModelWriter = translatedOutputs[0];
//
// 1. Output some comments with respect to the input model
hogmv1ModelWriter.println("// IMPORT OF: " + inputIdentifier);
hogmv1ModelWriter.println("//");
hogmv1ModelWriter.println("// #variables = " + uaiModel.numberVariables());
hogmv1ModelWriter.println("// #tables = " + uaiModel.numberTables());
hogmv1ModelWriter.println("// #unique function tables = " + uaiModel.numberUniqueFunctionTables());
hogmv1ModelWriter.println("// Largest variable cardinality = " + uaiModel.largestCardinality());
hogmv1ModelWriter.println("// Largest # entries = " + uaiModel.largestNumberOfFunctionTableEntries());
hogmv1ModelWriter.println("// Total #entries across all function tables = " + uaiModel.totalNumberEntriesForAllFunctionTables());
//
// 2. Output the sort and random variable declarations
List<String> sorts = new ArrayList<>();
List<String> randoms = new ArrayList<>();
for (int varIdx = 0; varIdx < uaiModel.numberVariables(); varIdx++) {
int varCardinality = uaiModel.cardinality(varIdx);
addSortAndRandomVariableDeclarationsRegarding(varIdx, varCardinality, sorts, randoms);
}
if (sorts.size() > 0) {
hogmv1ModelWriter.println();
hogmv1ModelWriter.println("// SORT DECLARATIONS:");
sorts.forEach(sort -> hogmv1ModelWriter.println(sort));
}
hogmv1ModelWriter.println();
hogmv1ModelWriter.println("// RANDOM VARIABLE DECLARATIONS:");
randoms.forEach(random -> hogmv1ModelWriter.println(random));
//
// 3. Output the potentials
hogmv1ModelWriter.println();
hogmv1ModelWriter.println("// RULES:");
double totalNumberUniqueEntries = 0;
double totalCompressedEntries = 0;
// i.e. none at all
double bestIndividualCompressionRatio = 100;
double worstIndividualCompressionRatio = 0;
for (int i = 0; i < uaiModel.numberUniqueFunctionTables(); i++) {
FunctionTable table = uaiModel.getUniqueFunctionTable(i);
totalNumberUniqueEntries += table.numberEntries();
Expression genericTableExpression = convertToHOGMv1Expression(table);
double compressedEntries = calculateCompressedEntries(genericTableExpression);
double compressedRatio = compressedEntries / table.numberEntries();
if (compressedRatio < bestIndividualCompressionRatio) {
bestIndividualCompressionRatio = compressedRatio;
}
if (compressedRatio > worstIndividualCompressionRatio) {
worstIndividualCompressionRatio = compressedRatio;
}
totalCompressedEntries += compressedEntries;
for (int tableIdx : uaiModel.getTableIndexes(i)) {
Expression instanceTableExpression = UAIUtil.convertGenericTableToInstance(table, genericTableExpression, uaiModel.getVariableIndexesForTable(tableIdx));
// If just a number then table is just a constant and is irrelevant
if (!Expressions.isNumber(instanceTableExpression)) {
hogmv1ModelWriter.println(instanceTableExpression.toString() + ";");
}
}
}
//
// 4. Output some stats related to the translation to potentials
hogmv1ModelWriter.println();
hogmv1ModelWriter.println("// STATS: ");
hogmv1ModelWriter.println("// Table compression ratio = " + (totalCompressedEntries / totalNumberUniqueEntries));
hogmv1ModelWriter.println("// Best individual compression ratio = " + bestIndividualCompressionRatio);
hogmv1ModelWriter.println("// Worst individual compression ratio = " + worstIndividualCompressionRatio);
}
use of com.sri.ai.praise.lang.grounded.common.FunctionTable in project aic-praise by aic-sri-international.
the class TranslationOfTableToInequalities method constructGenericTableExpressionUsingInequalities.
/**
* Returns an {@link Expression} equivalent to a given {@link FunctionTable} but in the form of a decision tree
* (so hopefully more compact) using inequalities.
* @param functionTable
* @param solverListener if not null, invoked on solver used for compilation,
* before and after compilation is performed; returned solver from "before" invocation is used (it may be the same one used as argument, of course).
* @return
*/
public static Expression constructGenericTableExpressionUsingInequalities(FunctionTable functionTable, Function<MultiIndexQuantifierEliminator, MultiIndexQuantifierEliminator> solverListener) {
// the strategy in this method is the following:
// we collect all the contiguous indices sub-sets of the function table sharing their function value.
// They are kept in a map from each value to a list of indices sub-sets with that value.
//
// Then, we sort these groups of indices sub-sets by the sum of their sizes (number of entries), from smallest to largest.
// This will help us later to create an expression that tests for the largest groups first.
//
// Finally, we create an if-then-else expression, starting from the leaf (least common value).
// For each group of indices sub-sets with the same value, we obtain an inequalities expression describing
// the conditions for a variable assignment to be in that indices sub-set of the function table.
// Each portion generates a conjunction, and the group of portions generates a disjunction.
//
// The resulting if-then-else expression is linearly organized (only else clauses have nested if-then-else expressions).
// A more balanced (and thus efficient) representation is obtained by compiling it using SGDPLL(T).
Map<Double, List<FunctionTableIndicesSubSet>> functionValuesAndCorrespondingIndicesSubSet = map();
Double currentSubSetFunctionValueIfAny = null;
List<Integer> firstIndicesOfCurrentSubSetIfAny = null;
List<Integer> previousIndices = null;
List<Integer> indices = null;
CartesianProductEnumeration<Integer> cartesianProduct = new CartesianProductEnumeration<>(UAIUtil.cardinalityValues(functionTable));
while (cartesianProduct.hasMoreElements()) {
previousIndices = indices;
indices = new ArrayList<>(cartesianProduct.nextElement());
Double functionValue = Math.round(functionTable.entryFor(indices) * 100) / 100.0;
boolean hitNewFunctionValue = currentSubSetFunctionValueIfAny == null || !functionValue.equals(currentSubSetFunctionValueIfAny);
if (hitNewFunctionValue) {
storeIndicesSubSetOnAllVariables(functionTable, firstIndicesOfCurrentSubSetIfAny, previousIndices, currentSubSetFunctionValueIfAny, functionValuesAndCorrespondingIndicesSubSet);
// get information for next indices sub-set
currentSubSetFunctionValueIfAny = functionValue;
firstIndicesOfCurrentSubSetIfAny = indices;
}
}
previousIndices = indices;
storeIndicesSubSetOnAllVariables(functionTable, firstIndicesOfCurrentSubSetIfAny, previousIndices, currentSubSetFunctionValueIfAny, functionValuesAndCorrespondingIndicesSubSet);
// we sort (by using TreeMap) lists of indices sub-set with the same function value from those with smaller to greater sizes,
// and form the final expression backwards, thus prioritizing larger sub-sets
// whose conditions will be more often satisfied and leading to greater simplifications during inference.
List<Pair<BigInteger, List<FunctionTableIndicesSubSet>>> listOfPairsOfSizeAndListsOfIndicesSubSetsWithSameFunctionValue = new ArrayList<>(functionValuesAndCorrespondingIndicesSubSet.size());
for (Map.Entry<Double, List<FunctionTableIndicesSubSet>> functionValueAndIndicesSubSet : functionValuesAndCorrespondingIndicesSubSet.entrySet()) {
List<FunctionTableIndicesSubSet> indicesSubSetsWithSameFunctionValue = functionValueAndIndicesSubSet.getValue();
BigInteger sumOfSizes = BigInteger.ZERO;
for (FunctionTableIndicesSubSet indicesSubSet : indicesSubSetsWithSameFunctionValue) {
sumOfSizes = sumOfSizes.add(indicesSubSet.size());
}
listOfPairsOfSizeAndListsOfIndicesSubSetsWithSameFunctionValue.add(Pair.make(sumOfSizes, indicesSubSetsWithSameFunctionValue));
}
Collections.sort(listOfPairsOfSizeAndListsOfIndicesSubSetsWithSameFunctionValue, (Comparator<? super Pair<BigInteger, List<FunctionTableIndicesSubSet>>>) (p1, p2) -> p1.first.compareTo(p2.first));
List<List<FunctionTableIndicesSubSet>> listsOfIndicesSubSetsWithSameFunctionValue = mapIntoList(listOfPairsOfSizeAndListsOfIndicesSubSetsWithSameFunctionValue, p -> p.second);
Iterator<List<FunctionTableIndicesSubSet>> listsOfIndicesSubSetsWithSameFunctionValueIterator = listsOfIndicesSubSetsWithSameFunctionValue.iterator();
List<FunctionTableIndicesSubSet> firstListOfIndicesSubSets = listsOfIndicesSubSetsWithSameFunctionValueIterator.next();
Double valueOfFirstListOfIndicesSubSets = getFirstOrNull(firstListOfIndicesSubSets).getFunctionValue();
Expression currentExpression = makeSymbol(valueOfFirstListOfIndicesSubSets);
while (listsOfIndicesSubSetsWithSameFunctionValueIterator.hasNext()) {
List<FunctionTableIndicesSubSet> indicesSubSetsWithSameFunctionValue = listsOfIndicesSubSetsWithSameFunctionValueIterator.next();
Expression functionValueOfIndicesSubSetsWithSameFunctionValue = makeSymbol(getFirstOrNull(indicesSubSetsWithSameFunctionValue).getFunctionValue());
Expression conditionForThisFunctionValue = Or.make(mapIntoList(indicesSubSetsWithSameFunctionValue, TranslationOfTableToInequalities::getInequalitiesExpressionForFunctionTableIndicesSubSet));
currentExpression = IfThenElse.make(conditionForThisFunctionValue, functionValueOfIndicesSubSetsWithSameFunctionValue, currentExpression);
}
return currentExpression;
}
use of com.sri.ai.praise.lang.grounded.common.FunctionTable in project aic-praise by aic-sri-international.
the class UAIUtil method constructGenericTableExpressionUsingEqualities.
/**
* Returns an {@link Expression} equivalent to a given {@link FunctionTable} but in the form of a decision tree
* (so hopefully more compact) using equalities.
* @param functionTable
* @param solverListener if not null, invoked on solver used for compilation, before and after compilation is performed; returned solver from "before" invocation is used (it may be the same one used as argument, of course).
* @return
*/
public static Expression constructGenericTableExpressionUsingEqualities(FunctionTable functionTable, Function<MultiIndexQuantifierEliminator, MultiIndexQuantifierEliminator> solverListener) {
StringBuilder table = new StringBuilder();
CartesianProductEnumeration<Integer> cartesianProduct = new CartesianProductEnumeration<>(cardinalityValues(functionTable));
int counter = 0;
while (cartesianProduct.hasMoreElements()) {
counter++;
List<Integer> values = cartesianProduct.nextElement();
Double entryValue = functionTable.entryFor(values);
if (counter == cartesianProduct.size().intValue()) {
// i.e. final value
table.append(entryValue);
} else {
table.append("if ");
for (int i = 0; i < values.size(); i++) {
if (i > 0) {
table.append(" and ");
}
String value = genericConstantValueForVariable(values.get(i), i, functionTable.cardinality(i));
if (value.equals("true")) {
table.append(genericVariableName(i));
} else if (value.equals("false")) {
table.append("not " + genericVariableName(i));
} else {
table.append(genericVariableName(i));
table.append(" = ");
table.append(value);
}
}
table.append(" then ");
table.append(entryValue);
table.append(" else ");
}
}
Expression inputExpression = Expressions.parse(table.toString());
Function<Integer, Integer> cardinalityOfIthVariable = i -> functionTable.cardinality(i);
Map<String, String> mapFromCategoricalTypeNameToSizeString = new LinkedHashMap<>();
Map<String, String> mapFromVariableNameToTypeName = new LinkedHashMap<>();
Map<String, String> mapFromUniquelyNamedConstantToTypeName = new LinkedHashMap<>();
for (int i = 0; i < functionTable.numberVariables(); i++) {
String typeName = genericTypeNameForVariable(i, cardinalityOfIthVariable.apply(i));
mapFromCategoricalTypeNameToSizeString.put(typeName, "" + cardinalityOfIthVariable.apply(i));
mapFromVariableNameToTypeName.put(genericVariableName(i), typeName);
for (int j = 0; j != functionTable.cardinality(i); j++) {
String jThConstant = genericConstantValueForVariable(j, i, functionTable.cardinality(i));
mapFromUniquelyNamedConstantToTypeName.put(jThConstant, typeName);
}
}
com.sri.ai.grinder.sgdpllt.api.Theory theory = new EqualityTheory(true, true);
Expression result = Compilation.compile(inputExpression, theory, mapFromVariableNameToTypeName, mapFromUniquelyNamedConstantToTypeName, mapFromCategoricalTypeNameToSizeString, list(), solverListener);
return result;
}
use of com.sri.ai.praise.lang.grounded.common.FunctionTable in project aic-praise by aic-sri-international.
the class UAIModel method mergeEvidenceIntoModel.
public void mergeEvidenceIntoModel() {
if (evidence.size() > 0) {
// for the assignment value and 0 for all other values.
for (Map.Entry<Integer, Integer> evidenceAssignment : evidence.entrySet()) {
Integer evidenceVarIndex = evidenceAssignment.getKey();
int evidenceValue = evidenceAssignment.getValue();
int varCardinality = varIdxToCardinality.get(evidenceVarIndex);
List<Double> entries = new ArrayList<>();
for (int i = 0; i < varCardinality; i++) {
if (i == evidenceValue) {
entries.add(1.0);
} else {
entries.add(0.0);
}
}
FunctionTable evidenceFactor = new FunctionTable(Arrays.asList(varCardinality), entries);
//
// Merge in with the other factor information
tableInstanceVariableIndexes.add(Arrays.asList(evidenceVarIndex));
tableInstanceIdxToTable.put(tableInstanceVariableIndexes.size() - 1, evidenceFactor);
}
// Ensure the unique mapping information is re-created.
computeUniqueMappings();
}
}
use of com.sri.ai.praise.lang.grounded.common.FunctionTable in project aic-praise by aic-sri-international.
the class UAIModelReader method read.
public static UAIModel read(Reader modelReader) throws IOException {
UAIModel result = null;
try (BufferedReader br = new BufferedReader(modelReader)) {
Preamble preamble = readPreamble(br);
Map<Integer, FunctionTable> tableIdxToTable = readFunctionTables(preamble, br);
result = new UAIModel(preamble.type, preamble.variableToCardinality, preamble.tableVariableIdxs, tableIdxToTable);
}
return result;
}
Aggregations