Skip to content

Commit d410ad1

Browse files
committed
Evolog Modules: Draft implementation of ModuleLinker, which constructs interpretations for module literals by wrapping calls to the ASP solver.
1 parent f338eeb commit d410ad1

File tree

3 files changed

+72
-7
lines changed

3 files changed

+72
-7
lines changed

alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/atoms/ExternalAtom.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import at.ac.tuwien.kr.alpha.api.common.fixedinterpretations.PredicateInterpretation;
66
import at.ac.tuwien.kr.alpha.api.programs.VariableNormalizableAtom;
7+
import at.ac.tuwien.kr.alpha.api.programs.literals.ExternalLiteral;
78
import at.ac.tuwien.kr.alpha.api.programs.terms.Term;
89

910
/**
@@ -21,4 +22,12 @@ public interface ExternalAtom extends Atom, VariableNormalizableAtom {
2122

2223
PredicateInterpretation getInterpretation();
2324

25+
@Override
26+
default ExternalLiteral toLiteral() {
27+
return toLiteral(true);
28+
}
29+
30+
@Override
31+
ExternalLiteral toLiteral(boolean positive);
32+
2433
}

alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/literals/ExternalLiteralImpl.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import at.ac.tuwien.kr.alpha.commons.substitutions.BasicSubstitution;
3838

3939
import java.util.*;
40+
import java.util.function.Predicate;
4041

4142
/**
4243
* Contains a potentially negated {@link ExternalAtom}.
@@ -128,10 +129,12 @@ public List<Substitution> getSatisfyingSubstitutions(Substitution partialSubstit
128129
substitutes.add(t.substitute(partialSubstitution));
129130
}
130131
Set<List<Term>> results = getAtom().getInterpretation().evaluate(substitutes);
131-
// TODO verify all results are ground
132132
if (results == null) {
133133
throw new NullPointerException("Predicate " + getPredicate().getName() + " returned null. It must return a Set.");
134134
}
135+
if (results.stream().anyMatch(trms -> trms.stream().anyMatch(Predicate.not(Term::isGround)))) {
136+
throw new IllegalStateException("Predicate " + getPredicate().getName() + " returned non-ground term.");
137+
}
135138

136139
if (this.isNegated()) {
137140
return this.isNegatedLiteralSatisfied(results) ? Collections.singletonList(partialSubstitution) : Collections.emptyList();

alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/ModuleLinker.java

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,34 @@
11
package at.ac.tuwien.kr.alpha.core.programs.transformation;
22

33
import at.ac.tuwien.kr.alpha.api.Alpha;
4+
import at.ac.tuwien.kr.alpha.api.AnswerSet;
5+
import at.ac.tuwien.kr.alpha.api.common.fixedinterpretations.PredicateInterpretation;
6+
import at.ac.tuwien.kr.alpha.api.programs.Predicate;
47
import at.ac.tuwien.kr.alpha.api.programs.NormalProgram;
8+
import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom;
9+
import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom;
510
import at.ac.tuwien.kr.alpha.api.programs.atoms.ExternalAtom;
611
import at.ac.tuwien.kr.alpha.api.programs.atoms.ModuleAtom;
712
import at.ac.tuwien.kr.alpha.api.programs.literals.Literal;
813
import at.ac.tuwien.kr.alpha.api.programs.literals.ModuleLiteral;
914
import at.ac.tuwien.kr.alpha.api.programs.modules.Module;
1015
import at.ac.tuwien.kr.alpha.api.programs.rules.NormalRule;
16+
import at.ac.tuwien.kr.alpha.api.programs.rules.Rule;
1117
import at.ac.tuwien.kr.alpha.api.programs.rules.heads.NormalHead;
18+
import at.ac.tuwien.kr.alpha.api.programs.terms.Term;
19+
import at.ac.tuwien.kr.alpha.commons.programs.Programs;
20+
import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms;
1221
import at.ac.tuwien.kr.alpha.commons.programs.rules.Rules;
22+
import org.apache.commons.collections4.ListUtils;
23+
import org.apache.commons.collections4.SetUtils;
1324

25+
import java.util.Collections;
1426
import java.util.List;
1527
import java.util.Map;
1628
import java.util.Set;
1729
import java.util.function.Function;
1830
import java.util.stream.Collectors;
31+
import java.util.stream.Stream;
1932

2033
/**
2134
* Program transformation that translates {@link at.ac.tuwien.kr.alpha.api.programs.literals.ModuleLiteral}s into
@@ -57,17 +70,57 @@ private NormalRule linkModuleAtoms(NormalRule rule, Map<String, Module> moduleTa
5770
return Rules.newNormalRule(newHead, newBody);
5871
}
5972

60-
private ExternalAtom translateModuleAtom(ModuleAtom moduleAtom, Map<String, Module> moduleTable) {
61-
if (!moduleTable.containsKey(moduleAtom.getModuleName())) {
62-
throw new IllegalArgumentException("Module " + moduleAtom.getModuleName() + " not found in module table.");
73+
private ExternalAtom translateModuleAtom(ModuleAtom atom, Map<String, Module> moduleTable) {
74+
if (!moduleTable.containsKey(atom.getModuleName())) {
75+
throw new IllegalArgumentException("Module " + atom.getModuleName() + " not found in module table.");
6376
}
64-
Module implementationModule = moduleTable.get(moduleAtom.getModuleName());
65-
//implementationModule.
66-
return null;
77+
Module definition = moduleTable.get(atom.getModuleName());
78+
// verify inputs
79+
Predicate inputSpec = definition.getInputSpec();
80+
if (atom.getInput().size() != inputSpec.getArity()) {
81+
throw new IllegalArgumentException("Module " + atom.getModuleName() + " expects " + inputSpec.getArity() + " inputs, but " + atom.getInput().size() + " were given.");
82+
}
83+
NormalProgram normalizedImplementation = moduleRunner.normalizeProgram(definition.getImplementation());
84+
// verify outputs
85+
Set<Predicate> outputSpec = definition.getOutputSpec();
86+
int expectedOutputTerms;
87+
if (outputSpec.isEmpty()) {
88+
expectedOutputTerms = calculateOutputPredicates(normalizedImplementation).size();
89+
} else {
90+
expectedOutputTerms = outputSpec.size();
91+
}
92+
if (atom.getOutput().size() != expectedOutputTerms) {
93+
throw new IllegalArgumentException("Module " + atom.getModuleName() + " expects " + outputSpec.size() + " outputs, but " + atom.getOutput().size() + " were given.");
94+
}
95+
// create the actual interpretation
96+
PredicateInterpretation interpretation = terms -> {
97+
BasicAtom inputAtom = Atoms.newBasicAtom(inputSpec, terms);
98+
NormalProgram program = Programs.newNormalProgram(normalizedImplementation.getRules(),
99+
ListUtils.union(List.of(inputAtom), normalizedImplementation.getFacts()), normalizedImplementation.getInlineDirectives());
100+
java.util.function.Predicate<Predicate> filter = outputSpec.isEmpty() ? p -> true : outputSpec::contains;
101+
Stream<AnswerSet> answerSets = moduleRunner.solve(program, filter);
102+
if (atom.getInstantiationMode().requestedAnswerSets().isPresent()) {
103+
answerSets = answerSets.limit(atom.getInstantiationMode().requestedAnswerSets().get());
104+
}
105+
return answerSets.map(ModuleLinker::answerSetToTerms).collect(Collectors.toSet());
106+
};
107+
return Atoms.newExternalAtom(atom.getPredicate(), interpretation, atom.getInput(), atom.getOutput());
67108
}
68109

69110
private static boolean containsModuleAtom(NormalRule rule) {
70111
return rule.getBody().stream().anyMatch(literal -> literal instanceof ModuleLiteral);
71112
}
72113

114+
private static Set<Predicate> calculateOutputPredicates(NormalProgram program) {
115+
return SetUtils.union(program.getFacts().stream().map(Atom::getPredicate).collect(Collectors.toSet()),
116+
program.getRules().stream()
117+
.filter(java.util.function.Predicate.not(Rule::isConstraint))
118+
.map(Rule::getHead).map(NormalHead::getAtom).map(Atom::getPredicate)
119+
.collect(Collectors.toSet()));
120+
}
121+
122+
private static List<Term> answerSetToTerms(AnswerSet answerSet) {
123+
return Collections.emptyList(); // TODO
124+
}
125+
73126
}

0 commit comments

Comments
 (0)