use of com.sri.ai.util.base.Triple in project aic-expresso by aic-sri-international.
the class Context method extendWith.
/**
* Extends context with index expressions, taking into account that new contextual variables may collide with existing ones.
* In this case, it renames the incoming variables to unique identifiers and replaces them in the types of remaining
* index expressions. It also renames the variables in a given expressions supposed to be in their scope (for example,
* the head and condition of an intensionally defined set).
* Returns the new context and the index expressions and expression in scope after the renaming.
* @param indexExpressions
* @param expressionInScope
* @return the new context and the index expressions and expression in scope after the renaming
*/
default default Triple<Context, ExtensionalIndexExpressionsSet, Expression> extendWith(ExtensionalIndexExpressionsSet indexExpressions, Expression expressionInScope) {
Triple<Context, ExtensionalIndexExpressionsSet, Expression> result;
if (thereExists(getIndices(indexExpressions), index -> this.containsSymbol(index))) {
// OPTIMIZATION: only kick in this entire procedure when extending with symbol in the context (previous ones could have been dealt with normally).
// the objects to be returned in the triple:
Context newContext = this;
ArrayList<Expression> newIndexExpressionsList = new ArrayList<>(indexExpressions.getList());
Expression newExpressionInScope = expressionInScope;
// Collects all existing symbols to be able to create unique symbols
Set<Expression> alreadyDefined = Util.set();
alreadyDefined.addAll(this.getSymbols());
alreadyDefined.addAll(Expressions.freeSymbols(new DefaultTuple(newIndexExpressionsList), this));
alreadyDefined.addAll(Expressions.freeSymbols(expressionInScope, this));
Predicate<Expression> isAlreadyDefined = e -> alreadyDefined.contains(e);
for (int i = 0; i != newIndexExpressionsList.size(); i++) {
Expression indexExpression = newIndexExpressionsList.get(i);
Symbol index = (Symbol) indexExpression.get(0);
Expression type = indexExpression.get(1);
PairOf<Expression> newIndexAndNewExpressionInScope = Expressions.standardizeApart(index, isAlreadyDefined, newExpressionInScope);
Expression newIndex = newIndexAndNewExpressionInScope.first;
newExpressionInScope = newIndexAndNewExpressionInScope.second;
// type should not contain the index
Expression newIndexExpression = apply(IN, newIndex, type);
newIndexExpressionsList.set(i, newIndexExpression);
alreadyDefined.add(newIndex);
for (int j = i + 1; j != newIndexExpressionsList.size(); j++) {
Expression anotherIndexExpression = newIndexExpressionsList.get(j);
Expression anotherIndex = anotherIndexExpression.get(0);
Expression anotherType = anotherIndexExpression.get(1);
Expression newAnotherType = anotherType.replaceSymbol(index, newIndex, this);
// anotherIndex is a symbols and does not contain index
Expression newAnotherIndexExpression = apply(IN, anotherIndex, newAnotherType);
newIndexExpressionsList.set(j, newAnotherIndexExpression);
}
}
ExtensionalIndexExpressionsSet newIndexExpressions = new ExtensionalIndexExpressionsSet(newIndexExpressionsList);
newContext = newContext.extendWith(newIndexExpressions);
result = triple(newContext, newIndexExpressions, newExpressionInScope);
} else {
// no collision; usual extension and the expressions do not change.
result = triple(extendWith(indexExpressions), indexExpressions, expressionInScope);
}
return result;
}
use of com.sri.ai.util.base.Triple in project aic-praise by aic-sri-international.
the class HOGModelGrounding method createRandomVariableNameToTypeSizeAndUniqueConstantsMap.
//
// PRIVATE
//
private static Map<Expression, Triple<Expression, Integer, List<Expression>>> createRandomVariableNameToTypeSizeAndUniqueConstantsMap(FactorsAndTypes factorsAndTypes) {
Map<Expression, Triple<Expression, Integer, List<Expression>>> result = new LinkedHashMap<>();
factorsAndTypes.getMapFromRandomVariableNameToTypeName().entrySet().forEach(entry -> {
Expression randomVariableName = Expressions.parse(entry.getKey());
Expression type = Expressions.parse(entry.getValue());
int size = 0;
List<Expression> uniqueConstants = new ArrayList<>();
if (Expressions.hasFunctor(type, FunctorConstants.FUNCTION_TYPE)) {
throw new UnsupportedOperationException("Relational random variables, " + randomVariableName + ", are currently not supported.");
} else if (Expressions.hasFunctor(type, HOGMSortDeclaration.IN_BUILT_INTEGER.getName()) && type.numberOfArguments() == 2) {
size = (type.get(1).intValueExact() - type.get(0).intValueExact()) + 1;
} else if (type.hasFunctor(FunctorConstants.INTEGER_INTERVAL) && type.numberOfArguments() == 2) {
size = (type.get(1).intValueExact() - type.get(0).intValueExact()) + 1;
} else {
String sizeString = factorsAndTypes.getMapFromCategoricalTypeNameToSizeString().get(type);
if (sizeString == null) {
throw new IllegalArgumentException("Size of sort " + type + " is unknown");
}
size = Integer.parseInt(sizeString);
factorsAndTypes.getMapFromUniquelyNamedConstantNameToTypeName().entrySet().stream().filter(uniqueConstantAndTypeEntry -> uniqueConstantAndTypeEntry.getValue().equals(entry.getValue())).forEach(uniqueConstantAndTypeEntry -> uniqueConstants.add(Expressions.parse(uniqueConstantAndTypeEntry.getKey())));
}
result.put(randomVariableName, new Triple<>(type, size, uniqueConstants));
});
return result;
}
use of com.sri.ai.util.base.Triple in project aic-praise by aic-sri-international.
the class HOGModelGrounding method ground.
public static void ground(FactorsAndTypes factorsAndTypes, List<Expression> evidence, Listener listener) {
if (factorsAndTypes.getMapFromNonUniquelyNamedConstantNameToTypeName().size() > 0) {
throw new IllegalArgumentException("Constants cannot be grounded");
}
Map<Expression, Triple<Expression, Integer, List<Expression>>> randomVariableNameToTypeSizeAndUniqueConstants = createRandomVariableNameToTypeSizeAndUniqueConstantsMap(factorsAndTypes);
Map<Expression, Integer> randomVariableIndexes = new LinkedHashMap<>();
AtomicInteger atomicVariableIndex = new AtomicInteger(-1);
listener.numberGroundVariables(randomVariableNameToTypeSizeAndUniqueConstants.size());
randomVariableNameToTypeSizeAndUniqueConstants.entrySet().forEach(entry -> {
randomVariableIndexes.put(entry.getKey(), atomicVariableIndex.addAndGet(1));
listener.groundVariableCardinality(atomicVariableIndex.get(), entry.getValue().second);
});
Map<Expression, List<Expression>> typeToValues = createTypeToValuesMap(factorsAndTypes, randomVariableNameToTypeSizeAndUniqueConstants);
Map<String, String> newUniqueConstantToTypeMap = createGroundedUniqueConstantToTypeMap(typeToValues);
InferenceForFactorGraphAndEvidence inferencer = makeInferencer(factorsAndTypes, newUniqueConstantToTypeMap);
Context context = inferencer.makeContextWithTypeInformation();
listener.numberFactors(factorsAndTypes.getFactors().size());
int factorIndex = 0;
for (Expression factor : factorsAndTypes.getFactors()) {
ArrayList<Expression> randomVariablesInFactor = new ArrayList<>(Expressions.getSubExpressionsSatisfying(factor, randomVariableNameToTypeSizeAndUniqueConstants::containsKey));
if (randomVariablesInFactor.size() == 0) {
throw new IllegalArgumentException("Factor contains no random variables: " + factor);
}
int[] participantVariableIndexes = new int[randomVariablesInFactor.size()];
for (int i = 0; i < randomVariablesInFactor.size(); i++) {
Expression randomVariable = randomVariablesInFactor.get(i);
participantVariableIndexes[i] = randomVariableIndexes.get(randomVariable);
}
listener.factorParticipants(factorIndex, participantVariableIndexes);
if (!useContextSensitiveGrounding) {
fullGrounding(factor, randomVariablesInFactor, listener, randomVariableNameToTypeSizeAndUniqueConstants, typeToValues, inferencer, context);
} else {
contextSensitiveGrounding(factor, randomVariablesInFactor, listener, randomVariableNameToTypeSizeAndUniqueConstants, typeToValues, inferencer, context);
}
factorIndex++;
}
// Handle the evidence
for (Expression evidenceAssignment : evidence) {
if (Expressions.isFunctionApplicationWithArguments(evidenceAssignment)) {
// TODO - add support for 'not <variable>' and 'variable = value' and 'value = variable'
throw new UnsupportedOperationException("Function application of evidence currently not supported: " + evidenceAssignment);
} else if (Expressions.isSymbol(evidenceAssignment)) {
int evidenceVariableIndex = randomVariableIndexes.get(evidenceAssignment);
int evidenceValueIndex = typeToValues.get(randomVariableNameToTypeSizeAndUniqueConstants.get(evidenceAssignment).first).indexOf(Expressions.TRUE);
listener.evidence(evidenceVariableIndex, evidenceValueIndex);
}
}
listener.groundingComplete();
}
use of com.sri.ai.util.base.Triple in project aic-expresso by aic-sri-international.
the class PolynomialSummation method sum.
/**
* Compute the sum for the summation of a polynomial.
*
* @param indexOfSummation
* the index variable of the summation.
* @param lowerBoundExclusive
* the lower bound of the summation.
* @param upperBoundInclusive
* the upper bound of the summation.
* @param summand
* the polynomial to be summed.
* @return the sum of the given summation.
*/
public static Polynomial sum(Expression indexOfSummation, Expression lowerBoundExclusive, Expression upperBoundInclusive, Polynomial summand) {
Polynomial result;
List<Expression> indexVariable = Arrays.asList(indexOfSummation);
Polynomial summandAsPolynomialOfIndex = DefaultPolynomial.make(summand, indexVariable);
int n = summandAsPolynomialOfIndex.degree();
//
// collect the t coefficients
List<Expression> tCoefficients = new ArrayList<>(n);
for (int i = 0; i <= n; i++) {
tCoefficients.add(Expressions.ZERO);
}
for (int i = 0; i < summandAsPolynomialOfIndex.numberOfTerms(); i++) {
Monomial term = summandAsPolynomialOfIndex.getOrderedSummands().get(i);
tCoefficients.set(term.getPowerOfFactor(indexOfSummation).intValue(), term.getCoefficient(indexVariable));
}
//
// compute polynomials R_i(x) = (x + l)^i for each i
Expression indexOfSummationPlusLowerBound = new DefaultFunctionApplication(PLUS_FUNCTOR, Arrays.asList(indexOfSummation, lowerBoundExclusive));
Polynomial indexOfSummationPlusLowerBoundPolynomial = DefaultPolynomial.make(indexOfSummationPlusLowerBound, indexVariable);
List<Polynomial> rPolynomials = new ArrayList<>(n);
rPolynomials.add(DefaultPolynomial.make(Expressions.ONE, indexVariable));
rPolynomials.add(indexOfSummationPlusLowerBoundPolynomial);
for (int i = 2; i <= n; i++) {
rPolynomials.add(rPolynomials.get(i - 1).times(indexOfSummationPlusLowerBoundPolynomial));
}
Map<Pair<Integer, Integer>, Expression> indexedRCoefficient = new LinkedHashMap<>();
for (int i = 0; i <= n; i++) {
Polynomial rPolynomial = rPolynomials.get(i);
for (int q = 0; q <= i; q++) {
Pair<Integer, Integer> indexKey = new Pair<>(i, q);
Monomial rqxq = rPolynomial.getSignatureTermMap().get(Arrays.asList(new Rational(q)));
if (rqxq == null) {
indexedRCoefficient.put(indexKey, Expressions.ZERO);
} else {
indexedRCoefficient.put(indexKey, rqxq.getCoefficient(indexVariable));
}
}
}
//
// compute "constants" (may contain variables other than x)
// s_i,q,j = t_i*R_{i,q}/(q+1) (-1)^j choose(q+1,j) B_j
// where R_{i,q}(x) is the coefficient in R_i(x) multiplying x^q.
Map<Triple<Integer, Integer, Integer>, Polynomial> sConstants = new LinkedHashMap<>();
for (int i = 0; i <= n; i++) {
Expression ti = tCoefficients.get(i);
for (int q = 0; q <= i; q++) {
Expression riq = indexedRCoefficient.get(new Pair<>(i, q));
Expression tiByriq = new DefaultFunctionApplication(TIMES_FUNCTOR, Arrays.asList(ti, riq));
for (int j = 0; j <= q; j++) {
Triple<Integer, Integer, Integer> indexKey = new Triple<>(i, q, j);
Expression qPlus1 = Expressions.makeSymbol(q + 1);
Expression minus1PowerJ = Expressions.makeSymbol(j % 2 == 0 ? 1 : -1);
Expression chooseQplus1J = Expressions.makeSymbol(Util.binomialCoefficient(q + 1, j));
Expression bernoulliJ = Expressions.makeSymbol(BernoulliNumber.computeFirst(j));
Expression sConstant = new DefaultFunctionApplication(TIMES_FUNCTOR, Arrays.asList(new DefaultFunctionApplication(DIVISION_FUNCTOR, Arrays.asList(tiByriq, qPlus1)), minus1PowerJ, chooseQplus1J, bernoulliJ));
sConstants.put(indexKey, DefaultPolynomial.make(sConstant, indexVariable));
}
}
}
//
// compute polynomials, for each q, j, V_{q + 1 -j} = (u - l)^{q + 1 - j}
Expression upperBoundMinusLowerBound = new DefaultFunctionApplication(MINUS_FUNCTOR, Arrays.asList(upperBoundInclusive, lowerBoundExclusive));
Polynomial upperBoundMinusLowerBoundPolynomial = DefaultPolynomial.make(upperBoundMinusLowerBound, indexVariable);
Map<Integer, Polynomial> vValues = new LinkedHashMap<>();
for (int q = 0; q <= n; q++) {
for (int j = 0; j <= q; j++) {
Integer exponent = q + 1 - j;
if (!vValues.containsKey(exponent)) {
vValues.put(exponent, upperBoundMinusLowerBoundPolynomial.exponentiate(exponent));
}
}
}
//
// Compute the w values and construct the final result.
Polynomial ws = DefaultPolynomial.make(Expressions.ZERO, indexVariable);
for (int i = 0; i <= n; i++) {
for (int q = 0; q <= i; q++) {
for (int j = 0; j <= q; j++) {
Triple<Integer, Integer, Integer> sConstantKey = new Triple<>(i, q, j);
Integer valueKey = q + 1 - j;
Polynomial sConstant = sConstants.get(sConstantKey);
Polynomial vValue = vValues.get(valueKey);
Polynomial w = sConstant.times(vValue);
ws = ws.add(w);
}
}
}
List<Expression> generalizedVariables = DefaultPolynomial.extractGeneralizedVariables(ws);
if (generalizedVariables.size() > 0) {
// Simplify in the context of the contained generalized variables
// and then return as a single constant factor (i.e. the index variable should not be present).
ws = DefaultPolynomial.make(ws, generalizedVariables);
}
result = DefaultPolynomial.make(ws, indexVariable);
return result;
}
Aggregations