Search in sources :

Example 6 with InputProgram

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();
}
Also used : AbstractAggregateEncoder(at.ac.tuwien.kr.alpha.core.programs.transformation.aggregates.encoders.AbstractAggregateEncoder) Head(at.ac.tuwien.kr.alpha.api.rules.heads.Head) ComparisonOperator(at.ac.tuwien.kr.alpha.api.ComparisonOperator) Set(java.util.Set) ArrayList(java.util.ArrayList) AggregateFunctionSymbol(at.ac.tuwien.kr.alpha.api.programs.atoms.AggregateAtom.AggregateFunctionSymbol) ImmutablePair(org.apache.commons.lang3.tuple.ImmutablePair) Rule(at.ac.tuwien.kr.alpha.api.rules.Rule) BasicRule(at.ac.tuwien.kr.alpha.core.rules.BasicRule) Map(java.util.Map) InputProgram(at.ac.tuwien.kr.alpha.core.programs.InputProgram)

Example 7 with InputProgram

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());
}
Also used : ASPCore2Program(at.ac.tuwien.kr.alpha.api.programs.ASPCore2Program) Head(at.ac.tuwien.kr.alpha.api.rules.heads.Head) AggregateLiteral(at.ac.tuwien.kr.alpha.api.programs.literals.AggregateLiteral) AggregateElement(at.ac.tuwien.kr.alpha.api.programs.atoms.AggregateAtom.AggregateElement) ArrayList(java.util.ArrayList) Rule(at.ac.tuwien.kr.alpha.api.rules.Rule) BasicRule(at.ac.tuwien.kr.alpha.core.rules.BasicRule) InlineDirectivesImpl(at.ac.tuwien.kr.alpha.core.parser.InlineDirectivesImpl) InputProgram(at.ac.tuwien.kr.alpha.core.programs.InputProgram)

Example 8 with InputProgram

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();
}
Also used : BasicRule(at.ac.tuwien.kr.alpha.core.rules.BasicRule) ChoiceHead(at.ac.tuwien.kr.alpha.api.rules.heads.ChoiceHead) Head(at.ac.tuwien.kr.alpha.api.rules.heads.Head) ArrayList(java.util.ArrayList) Term(at.ac.tuwien.kr.alpha.api.terms.Term) IntervalTerm(at.ac.tuwien.kr.alpha.commons.terms.IntervalTerm) Predicate(at.ac.tuwien.kr.alpha.api.programs.Predicate) ChoiceElement(at.ac.tuwien.kr.alpha.api.rules.heads.ChoiceHead.ChoiceElement) ChoiceHead(at.ac.tuwien.kr.alpha.api.rules.heads.ChoiceHead) Literal(at.ac.tuwien.kr.alpha.api.programs.literals.Literal) Rule(at.ac.tuwien.kr.alpha.api.rules.Rule) BasicRule(at.ac.tuwien.kr.alpha.core.rules.BasicRule) BasicAtom(at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom) InputProgram(at.ac.tuwien.kr.alpha.core.programs.InputProgram)

Example 9 with InputProgram

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();
}
Also used : ArrayList(java.util.ArrayList) Rule(at.ac.tuwien.kr.alpha.api.rules.Rule) BasicRule(at.ac.tuwien.kr.alpha.core.rules.BasicRule) Predicate(at.ac.tuwien.kr.alpha.api.programs.Predicate) InputProgram(at.ac.tuwien.kr.alpha.core.programs.InputProgram)

Example 10 with InputProgram

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());
}
Also used : EnumerationRewriting(at.ac.tuwien.kr.alpha.core.programs.transformation.EnumerationRewriting) ST(org.stringtemplate.v4.ST) ASPCore2Program(at.ac.tuwien.kr.alpha.api.programs.ASPCore2Program) Head(at.ac.tuwien.kr.alpha.api.rules.heads.Head) InlineDirectivesImpl(at.ac.tuwien.kr.alpha.core.parser.InlineDirectivesImpl) InputProgram(at.ac.tuwien.kr.alpha.core.programs.InputProgram)

Aggregations

InputProgram (at.ac.tuwien.kr.alpha.core.programs.InputProgram)12 AnswerSet (at.ac.tuwien.kr.alpha.api.AnswerSet)6 ASPCore2Program (at.ac.tuwien.kr.alpha.api.programs.ASPCore2Program)5 BasicRule (at.ac.tuwien.kr.alpha.core.rules.BasicRule)5 Rule (at.ac.tuwien.kr.alpha.api.rules.Rule)4 Head (at.ac.tuwien.kr.alpha.api.rules.heads.Head)4 InlineDirectivesImpl (at.ac.tuwien.kr.alpha.core.parser.InlineDirectivesImpl)4 ProgramParserImpl (at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl)4 ArrayList (java.util.ArrayList)4 Alpha (at.ac.tuwien.kr.alpha.api.Alpha)3 AnswerSetBuilder (at.ac.tuwien.kr.alpha.commons.AnswerSetBuilder)3 Test (org.junit.jupiter.api.Test)3 Solver (at.ac.tuwien.kr.alpha.api.Solver)2 Predicate (at.ac.tuwien.kr.alpha.api.programs.Predicate)2 HashSet (java.util.HashSet)2 ComparisonOperator (at.ac.tuwien.kr.alpha.api.ComparisonOperator)1 SystemConfig (at.ac.tuwien.kr.alpha.api.config.SystemConfig)1 ProgramParser (at.ac.tuwien.kr.alpha.api.programs.ProgramParser)1 AggregateElement (at.ac.tuwien.kr.alpha.api.programs.atoms.AggregateAtom.AggregateElement)1 AggregateFunctionSymbol (at.ac.tuwien.kr.alpha.api.programs.atoms.AggregateAtom.AggregateFunctionSymbol)1