use of at.ac.tuwien.kr.alpha.core.programs.InputProgram in project Alpha by alpha-asp.
the class AggregateRewriting method apply.
/**
* Rewrites all {@link AggregateLiteral}s in the given program.
* The transformation workflow is split into a preprocessing- and an encoding phase.
* During preprocessing, all aggregate literals with two comparison operators are split into two aggregate literals with
* only a "lower bound" term and operator. After literal splitting, operators are normalized, i.e. all "count" and "sum"
* literals are rewritten to use either "<=" or "=" as comparison operator.
*
* Rules containing {@link AggregateLiteral}s are registered in an {@link AggregateRewritingContext} during
* preprocessing. After preprocessing, for each rule in the context, aggregate literals in the rule body are substituted
* with normal literals of form "$id$_aggregate_result(...)". For each literal substituted this way, a set of rules
* deriving the result literal is added that is semantically equivalent to the replaced aggregate literal.
*/
@Override
public ASPCore2Program apply(ASPCore2Program inputProgram) {
AggregateRewritingContext ctx = new AggregateRewritingContext();
List<Rule<Head>> outputRules = new ArrayList<>();
for (Rule<Head> inputRule : inputProgram.getRules()) {
// Split literals with two operators.
for (Rule<Head> splitRule : AggregateLiteralSplitting.split(inputRule)) {
// Normalize operators on aggregate literals after splitting.
Rule<Head> operatorNormalizedRule = AggregateOperatorNormalization.normalize(splitRule);
boolean hasAggregate = ctx.registerRule(operatorNormalizedRule);
// Only keep rules without aggregates. The ones with aggregates are registered in the context and taken care of later.
if (!hasAggregate) {
outputRules.add(operatorNormalizedRule);
}
}
}
// Substitute AggregateLiterals with generated result literals.
outputRules.addAll(rewriteRulesWithAggregates(ctx));
InputProgram.Builder resultBuilder = InputProgram.builder().addRules(outputRules).addFacts(inputProgram.getFacts()).addInlineDirectives(inputProgram.getInlineDirectives());
// Add sub-programs deriving respective aggregate literals.
for (Map.Entry<ImmutablePair<AggregateFunctionSymbol, ComparisonOperator>, Set<AggregateInfo>> aggToRewrite : ctx.getAggregateFunctionsToRewrite().entrySet()) {
ImmutablePair<AggregateFunctionSymbol, ComparisonOperator> func = aggToRewrite.getKey();
AbstractAggregateEncoder encoder = getEncoderForAggregateFunction(func.left, func.right);
resultBuilder.accumulate(encoder.encodeAggregateLiterals(aggToRewrite.getValue()));
}
return resultBuilder.build();
}
use of at.ac.tuwien.kr.alpha.core.programs.InputProgram in project Alpha by alpha-asp.
the class AbstractAggregateEncoder method encodeAggregateLiteral.
/**
* Encodes the aggregate literal referenced by the given {@link AggregateInfo}.
*
* @param aggregateToEncode
* @return
*/
public ASPCore2Program encodeAggregateLiteral(AggregateInfo aggregateToEncode) {
AggregateLiteral literalToEncode = aggregateToEncode.getLiteral();
if (literalToEncode.getAtom().getAggregateFunction() != this.aggregateFunctionToEncode) {
throw new IllegalArgumentException("Encoder " + this.getClass().getSimpleName() + " cannot encode aggregate function " + literalToEncode.getAtom().getAggregateFunction());
}
if (!this.acceptedOperators.contains(literalToEncode.getAtom().getLowerBoundOperator())) {
throw new IllegalArgumentException("Encoder " + this.getClass().getSimpleName() + " cannot encode aggregate function " + literalToEncode.getAtom().getAggregateFunction() + " with operator " + literalToEncode.getAtom().getLowerBoundOperator());
}
String aggregateId = aggregateToEncode.getId();
ASPCore2Program literalEncoding = PredicateInternalizer.makePrefixedPredicatesInternal(encodeAggregateResult(aggregateToEncode), aggregateId);
List<Rule<Head>> elementEncodingRules = new ArrayList<>();
for (AggregateElement elementToEncode : literalToEncode.getAtom().getAggregateElements()) {
Rule<Head> elementRule = encodeAggregateElement(aggregateToEncode, elementToEncode);
elementEncodingRules.add(PredicateInternalizer.makePrefixedPredicatesInternal(elementRule, aggregateId));
}
return new InputProgram(ListUtils.union(literalEncoding.getRules(), elementEncodingRules), literalEncoding.getFacts(), new InlineDirectivesImpl());
}
use of at.ac.tuwien.kr.alpha.core.programs.InputProgram 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.core.programs.InputProgram in project Alpha by alpha-asp.
the class EnumerationRewriting method apply.
@Override
public ASPCore2Program apply(ASPCore2Program inputProgram) {
// Read enumeration predicate from directive.
String enumDirective = inputProgram.getInlineDirectives().getDirectiveValue(InlineDirectivesImpl.DIRECTIVE.enum_predicate_is);
if (enumDirective == null) {
// Directive not set, nothing to rewrite.
return inputProgram;
}
Predicate enumPredicate = Predicates.getPredicate(enumDirective, 3);
InputProgram.Builder programBuilder = InputProgram.builder().addInlineDirectives(inputProgram.getInlineDirectives());
checkFactsAreEnumerationFree(inputProgram.getFacts(), enumPredicate);
programBuilder.addFacts(inputProgram.getFacts());
List<Rule<Head>> srcRules = new ArrayList<>(inputProgram.getRules());
programBuilder.addRules(rewriteRules(srcRules, enumPredicate));
return programBuilder.build();
}
use of at.ac.tuwien.kr.alpha.core.programs.InputProgram in project Alpha by alpha-asp.
the class StringtemplateBasedAggregateEncoder method encodeAggregateResult.
@Override
protected ASPCore2Program encodeAggregateResult(AggregateInfo aggregateToEncode) {
String aggregateId = aggregateToEncode.getId();
/*
* Create a rule deriving a "bound" value for the core aggregate encoding.
* The bound is (in case of encodings for "<=" comparisons) the value that should be tested for being a lower bound, or
* else zero.
*/
Rule<Head> boundRule = null;
if (this.needsBoundRule) {
boundRule = this.buildBoundRule(aggregateToEncode);
} else {
/*
* Even if we don't have to create a bound rule because the aggregate encoding generates its own candidate values,
* we still generate a rule deriving zero as a bound, so that sums and counts over empty sets correctly return 0.
*/
boundRule = this.buildZeroBoundRule(aggregateToEncode);
}
// Generate encoding
ST coreEncodingTemplate = new ST(this.encodingTemplate);
coreEncodingTemplate.add("result_predicate", aggregateToEncode.getOutputAtom().getPredicate().getName());
coreEncodingTemplate.add("id", aggregateId);
coreEncodingTemplate.add("element_tuple", this.getElementTuplePredicateSymbol(aggregateId));
coreEncodingTemplate.add("bound", this.getBoundPredicateName(aggregateId));
String coreEncodingAsp = coreEncodingTemplate.render();
// Create the basic program
ASPCore2Program coreEncoding = new EnumerationRewriting().apply(parser.parse(coreEncodingAsp));
// Add the programatically created bound rule and return
return new InputProgram(ListUtils.union(coreEncoding.getRules(), Collections.singletonList(boundRule)), coreEncoding.getFacts(), new InlineDirectivesImpl());
}
Aggregations