use of at.ac.tuwien.kr.alpha.api.programs.literals.Literal in project Alpha by alpha-asp.
the class MinMaxEncoder method encodeAggregateResult.
@Override
protected ASPCore2Program encodeAggregateResult(AggregateInfo aggregateToEncode) {
ST encodingTemplate = null;
if (this.getAggregateFunctionToEncode() == AggregateFunctionSymbol.MAX) {
encodingTemplate = new ST(MAX_LITERAL_ENCODING);
} else if (this.getAggregateFunctionToEncode() == AggregateFunctionSymbol.MIN) {
encodingTemplate = new ST(MIN_LITERAL_ENCODING);
} else {
// Note that this should definitely not happen due to the check in the constructor!
throw new UnsupportedOperationException("Cannot encode anything other than min/max aggregates!");
}
String id = aggregateToEncode.getId();
String resultName = aggregateToEncode.getOutputAtom().getPredicate().getName();
AggregateAtom atom = aggregateToEncode.getLiteral().getAtom();
ComparisonOperator cmpOp = atom.getLowerBoundOperator();
encodingTemplate.add("id", id);
encodingTemplate.add("aggregate_result", resultName);
if (cmpOp.equals(ComparisonOperators.EQ)) {
// Aggregate to encode binds a variable, use appropriate result rule.
ST resultRuleTemplate = new ST(BINDING_LITERAL_RESULT_RULE);
resultRuleTemplate.add("agg_func", atom.getAggregateFunction().toString().toLowerCase());
resultRuleTemplate.add("id", id);
resultRuleTemplate.add("aggregate_result", resultName);
return parser.parse(encodingTemplate.render() + resultRuleTemplate.render());
} else {
/*
* Aggregate encoding needs to compare aggregate value with another variable.
* Note that this should also use a string template for the result rule. However,
* since we need to compared to a (user-supplied) variable, we have to use a definitely
* non-conflicting variable name for the aggregate value, i.e. something prefixed with "_".
* Since the ProgramParser doesn't accept this, we need to build the result rule
* programmatically as a workaround.
*
* Result rule stringtemplate for reference:
* $aggregate_result$($args$, $cmp_term$) :-
* $cmp_term$ $cmp_op$ AGG_VAL,
* $id$_$agg_func$_element_tuple($args$, AGG_VAL),
* $dependencies;separator=\", \"$."
*/
NormalHead resultRuleHead = Heads.newNormalHead(Atoms.newBasicAtom(Predicates.getPredicate(resultName, 2), aggregateToEncode.getAggregateArguments(), atom.getLowerBoundTerm()));
List<Literal> resultRuleBody = new ArrayList<>();
VariableTerm aggregateValue = Terms.newVariable("_AGG_VAL");
ComparisonLiteral aggregateValueComparison = Literals.fromAtom(Atoms.newComparisonAtom(atom.getLowerBoundTerm(), aggregateValue, cmpOp), true);
Literal aggregateResult = Atoms.newBasicAtom(Predicates.getPredicate(id + "_" + atom.getAggregateFunction().toString().toLowerCase() + "_element_tuple", 2), aggregateToEncode.getAggregateArguments(), aggregateValue).toLiteral();
resultRuleBody.add(aggregateResult);
resultRuleBody.add(aggregateValueComparison);
resultRuleBody.addAll(aggregateToEncode.getDependencies());
InputProgram.Builder bld = InputProgram.builder(parser.parse(encodingTemplate.render()));
BasicRule resultRule = new BasicRule(resultRuleHead, resultRuleBody);
bld.addRule(resultRule);
return bld.build();
}
}
use of at.ac.tuwien.kr.alpha.api.programs.literals.Literal in project Alpha by alpha-asp.
the class ChoiceHeadToNormal method apply.
@Override
public ASPCore2Program apply(ASPCore2Program inputProgram) {
InputProgram.Builder programBuilder = InputProgram.builder();
List<Rule<Head>> additionalRules = new ArrayList<>();
List<Rule<Head>> srcRules = new ArrayList<>(inputProgram.getRules());
Iterator<Rule<Head>> ruleIterator = srcRules.iterator();
while (ruleIterator.hasNext()) {
Rule<Head> rule = ruleIterator.next();
Head ruleHead = rule.getHead();
if (!(ruleHead instanceof ChoiceHead)) {
// Rule is constraint or without choice in the head. Leave as is.
continue;
}
// Remove this rule, as it will be transformed.
ruleIterator.remove();
ChoiceHead choiceHead = (ChoiceHead) ruleHead;
// Choice rules with boundaries are not yet supported.
if (choiceHead.getLowerBound() != null || choiceHead.getUpperBound() != null) {
throw new UnsupportedOperationException("Found choice rule with bounds, which are not yet supported. Rule is: " + rule);
}
// Only rewrite rules with a choice in their head.
for (ChoiceElement choiceElement : choiceHead.getChoiceElements()) {
// Create two guessing rules for each choiceElement.
// Construct common body to both rules.
BasicAtom head = choiceElement.getChoiceAtom();
List<Literal> ruleBody = new ArrayList<>(rule.getBody());
ruleBody.addAll(choiceElement.getConditionLiterals());
if (containsIntervalTerms(head)) {
throw new RuntimeException("Program contains a choice rule with interval terms in its head. This is not supported (yet).");
}
// Construct head atom for the choice.
Predicate headPredicate = head.getPredicate();
Predicate negPredicate = Predicates.getPredicate(PREDICATE_NEGATION_PREFIX + headPredicate.getName(), headPredicate.getArity() + 1, true);
List<Term> headTerms = new ArrayList<>(head.getTerms());
// FIXME: when introducing classical negation, this is 1 for classical positive atoms and 0 for
headTerms.add(0, Terms.newConstant("1"));
// classical negative atoms.
BasicAtom negHead = Atoms.newBasicAtom(negPredicate, headTerms);
// Construct two guessing rules.
List<Literal> guessingRuleBodyWithNegHead = new ArrayList<>(ruleBody);
guessingRuleBodyWithNegHead.add(Atoms.newBasicAtom(head.getPredicate(), head.getTerms()).toLiteral(false));
additionalRules.add(new BasicRule(Heads.newNormalHead(negHead), guessingRuleBodyWithNegHead));
List<Literal> guessingRuleBodyWithHead = new ArrayList<>(ruleBody);
guessingRuleBodyWithHead.add(Atoms.newBasicAtom(negPredicate, headTerms).toLiteral(false));
additionalRules.add(new BasicRule(Heads.newNormalHead(head), guessingRuleBodyWithHead));
// TODO: when cardinality constraints are possible, process the boundaries by adding a constraint with a cardinality check.
}
}
return programBuilder.addRules(srcRules).addRules(additionalRules).addFacts(inputProgram.getFacts()).addInlineDirectives(inputProgram.getInlineDirectives()).build();
}
use of at.ac.tuwien.kr.alpha.api.programs.literals.Literal in project Alpha by alpha-asp.
the class ArithmeticTermsRewriting method rewriteRule.
/**
* Takes a normal rule and rewrites it such that {@link ArithmeticTerm}s only appear inside {@link at.ac.tuwien.kr.alpha.common.atoms.ComparisonLiteral}s.
*
* @param inputProgramRule the rule to rewrite.
* @return the rewritten rule. Note that a new {@link NormalRule} is returned for every call of this method.
*/
private NormalRule rewriteRule(NormalRule inputProgramRule) {
// Reset number of introduced variables for each rule.
numArithmeticVariables = 0;
NormalHead rewrittenHead = null;
List<Literal> rewrittenBodyLiterals = new ArrayList<>();
// Rewrite head.
if (!inputProgramRule.isConstraint()) {
BasicAtom headAtom = inputProgramRule.getHeadAtom();
if (containsArithmeticTermsToRewrite(headAtom)) {
rewrittenHead = Heads.newNormalHead((BasicAtom) rewriteAtom(headAtom, rewrittenBodyLiterals));
} else {
rewrittenHead = inputProgramRule.getHead();
}
}
// Rewrite body.
for (Literal literal : inputProgramRule.getBody()) {
if (!containsArithmeticTermsToRewrite(literal.getAtom())) {
// Keep body literal as-is if no ArithmeticTerm occurs.
rewrittenBodyLiterals.add(literal);
continue;
}
rewrittenBodyLiterals.add(rewriteAtom(literal.getAtom(), rewrittenBodyLiterals).toLiteral(!literal.isNegated()));
}
return new NormalRuleImpl(rewrittenHead, rewrittenBodyLiterals);
}
use of at.ac.tuwien.kr.alpha.api.programs.literals.Literal in project Alpha by alpha-asp.
the class EnumerationRewriting method rewriteRules.
private List<Rule<Head>> rewriteRules(List<Rule<Head>> srcRules, Predicate enumPredicate) {
List<Rule<Head>> rewrittenRules = new ArrayList<>();
for (Rule<Head> rule : srcRules) {
if (rule.getHead() != null && !(rule.getHead() instanceof NormalHead)) {
throw oops("Encountered rule whose head is not normal: " + rule);
}
if (rule.getHead() != null && ((NormalHead) rule.getHead()).getAtom().getPredicate().equals(enumPredicate)) {
throw oops("Atom declared as enumeration atom by directive occurs in head of the rule: " + rule);
}
List<Literal> modifiedBodyLiterals = new ArrayList<>(rule.getBody());
Iterator<Literal> rit = modifiedBodyLiterals.iterator();
LinkedList<Literal> rewrittenLiterals = new LinkedList<>();
while (rit.hasNext()) {
Literal literal = rit.next();
if (!(literal instanceof BasicLiteral)) {
continue;
}
BasicLiteral basicLiteral = (BasicLiteral) literal;
if (!basicLiteral.getPredicate().equals(enumPredicate)) {
continue;
}
// basicLiteral is an enumeration literal (i.e. predicate is marked as enum using directive)
rit.remove();
Term enumIdTerm = basicLiteral.getAtom().getTerms().get(0);
Term valueTerm = basicLiteral.getAtom().getTerms().get(1);
VariableTerm indexTerm = (VariableTerm) basicLiteral.getAtom().getTerms().get(2);
rewrittenLiterals.add(new EnumerationAtom(enumIdTerm, valueTerm, indexTerm).toLiteral());
}
modifiedBodyLiterals.addAll(rewrittenLiterals);
rewrittenRules.add(new BasicRule(rule.getHead(), modifiedBodyLiterals));
}
return rewrittenRules;
}
use of at.ac.tuwien.kr.alpha.api.programs.literals.Literal in project Alpha by alpha-asp.
the class VariableEqualityRemoval method findAndReplaceVariableEquality.
private Rule<Head> findAndReplaceVariableEquality(Rule<Head> rule) {
// Collect all equal variables.
HashMap<VariableTerm, HashSet<VariableTerm>> variableToEqualVariables = new LinkedHashMap<>();
HashSet<Literal> equalitiesToRemove = new HashSet<>();
for (Literal bodyElement : rule.getBody()) {
if (!(bodyElement instanceof ComparisonLiteral)) {
continue;
}
ComparisonLiteral comparisonLiteral = (ComparisonLiteral) bodyElement;
if (!comparisonLiteral.isNormalizedEquality()) {
continue;
}
if (comparisonLiteral.getTerms().get(0) instanceof VariableTerm && comparisonLiteral.getTerms().get(1) instanceof VariableTerm) {
VariableTerm leftVariable = (VariableTerm) comparisonLiteral.getTerms().get(0);
VariableTerm rightVariable = (VariableTerm) comparisonLiteral.getTerms().get(1);
HashSet<VariableTerm> leftEqualVariables = variableToEqualVariables.get(leftVariable);
HashSet<VariableTerm> rightEqualVariables = variableToEqualVariables.get(rightVariable);
if (leftEqualVariables == null && rightEqualVariables == null) {
HashSet<VariableTerm> equalVariables = new LinkedHashSet<>(Arrays.asList(leftVariable, rightVariable));
variableToEqualVariables.put(leftVariable, equalVariables);
variableToEqualVariables.put(rightVariable, equalVariables);
}
if (leftEqualVariables == null && rightEqualVariables != null) {
rightEqualVariables.add(leftVariable);
variableToEqualVariables.put(leftVariable, rightEqualVariables);
}
if (leftEqualVariables != null && rightEqualVariables == null) {
leftEqualVariables.add(rightVariable);
variableToEqualVariables.put(rightVariable, leftEqualVariables);
}
if (leftEqualVariables != null && rightEqualVariables != null) {
leftEqualVariables.addAll(rightEqualVariables);
for (VariableTerm rightEqualVariable : rightEqualVariables) {
variableToEqualVariables.put(rightEqualVariable, leftEqualVariables);
}
}
equalitiesToRemove.add(comparisonLiteral);
}
}
if (variableToEqualVariables.isEmpty()) {
// Skip rule if there is no equality between variables.
return rule;
}
List<Literal> rewrittenBody = new ArrayList<>(rule.getBody());
if (!rule.isConstraint() && rule.getHead() instanceof DisjunctiveHead) {
throw new UnsupportedOperationException("VariableEqualityRemoval cannot be applied to rule with DisjunctiveHead, yet.");
}
NormalHead rewrittenHead = rule.isConstraint() ? null : Heads.newNormalHead(((NormalHead) rule.getHead()).getAtom());
// Use substitution for actual replacement.
Unifier replacementSubstitution = new Unifier();
// For each set of equal variables, take the first variable and replace all others by it.
for (Map.Entry<VariableTerm, HashSet<VariableTerm>> variableEqualityEntry : variableToEqualVariables.entrySet()) {
VariableTerm variableToReplace = variableEqualityEntry.getKey();
VariableTerm replacementVariable = variableEqualityEntry.getValue().iterator().next();
if (variableToReplace == replacementVariable) {
continue;
}
replacementSubstitution.put(variableToReplace, replacementVariable);
}
// Replace/Substitute in each literal every term where one of the common variables occurs.
Iterator<Literal> bodyIterator = rewrittenBody.iterator();
while (bodyIterator.hasNext()) {
Literal literal = bodyIterator.next();
if (equalitiesToRemove.contains(literal)) {
bodyIterator.remove();
}
for (int i = 0; i < literal.getTerms().size(); i++) {
Term replaced = literal.getTerms().get(i).substitute(replacementSubstitution);
literal.getTerms().set(i, replaced);
}
}
// Replace variables in head.
if (rewrittenHead != null) {
Atom headAtom = rewrittenHead.getAtom();
for (int i = 0; i < headAtom.getTerms().size(); i++) {
Term replaced = headAtom.getTerms().get(i).substitute(replacementSubstitution);
headAtom.getTerms().set(i, replaced);
}
}
return new BasicRule(rewrittenHead, rewrittenBody);
}
Aggregations