use of at.ac.tuwien.kr.alpha.api.rules.heads.Head 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.rules.heads.Head 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.rules.heads.Head 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());
}
use of at.ac.tuwien.kr.alpha.api.rules.heads.Head in project Alpha by alpha-asp.
the class LiteralBindingNonBindingVariablesTest method testPositiveComparisonLiteral_EQ_Bidirectional.
@Test
@Disabled("Literals of this kind are compiled away by VariableEqualityRemoval")
public void testPositiveComparisonLiteral_EQ_Bidirectional() {
Rule<Head> rule = parser.parse("p(X) :- q(X,Y), X = Y.").getRules().get(0);
Literal literal = rule.getBody().stream().filter((lit) -> lit.getPredicate() == ComparisonOperators.EQ.toPredicate()).findFirst().get();
assertEquals(false, literal.isNegated());
expectVariables(literal.getBindingVariables());
expectVariables(literal.getNonBindingVariables(), "X", "Y");
}
use of at.ac.tuwien.kr.alpha.api.rules.heads.Head in project Alpha by alpha-asp.
the class SubstitutionTest method groundAndPrintRule.
@Test
public void groundAndPrintRule() {
Rule<Head> rule = PARSER.parse("x :- p(X,Y), not q(X,Y).").getRules().get(0);
CompiledRule nonGroundRule = InternalRule.fromNormalRule(NormalRuleImpl.fromBasicRule(rule));
Substitution substitution1 = BasicSubstitution.specializeSubstitution(PX, PA, BasicSubstitution.EMPTY_SUBSTITUTION);
Substitution substitution2 = BasicSubstitution.specializeSubstitution(PY, PB, substitution1);
String printedString = SubstitutionTestUtil.groundAndPrintRule(nonGroundRule, substitution2);
assertEquals("x :- p(a, b), not q(a, b).", printedString);
}
Aggregations