
de.rwth.swc.coffee4j.engine.conflict.ConflictDetectionManager Maven / Gradle / Ivy
package de.rwth.swc.coffee4j.engine.conflict;
import de.rwth.swc.coffee4j.engine.TestModel;
import de.rwth.swc.coffee4j.engine.TupleList;
import de.rwth.swc.coffee4j.engine.conflict.choco.ChocoModel;
import de.rwth.swc.coffee4j.engine.conflict.diagnosis.ConflictDiagnostician;
import de.rwth.swc.coffee4j.engine.conflict.explanation.*;
import de.rwth.swc.coffee4j.engine.constraint.Constraint;
import de.rwth.swc.coffee4j.engine.util.Preconditions;
import it.unimi.dsi.fastutil.ints.IntArraySet;
import it.unimi.dsi.fastutil.ints.IntSet;
import java.util.*;
import java.util.stream.Collectors;
import static java.util.stream.Collectors.groupingBy;
public class ConflictDetectionManager {
private final ConflictDetectionConfiguration configuration;
private final ConflictExplainer explainer;
private final ConflictDiagnostician diagnostician;
private final TestModelExpander expander;
private final TestModel testModel;
private final Map> partitionedConstraints;
private final ChocoModel chocoModel;
public ConflictDetectionManager(ConflictDetectionConfiguration configuration,
TestModel originalTestModel) {
Preconditions.notNull(configuration);
Preconditions.notNull(originalTestModel);
this.configuration = configuration;
this.explainer = configuration.createConflictExplainer();
this.diagnostician = configuration.createConflictDiagnostician();
this.expander = configuration.createTestModelExpander(originalTestModel);
this.testModel = expander.createExpandedTestModel();
final List constraints = new ArrayList<>();
constraints.addAll(this.testModel.getExclusionConstraints());
constraints.addAll(this.testModel.getErrorConstraints());
this.partitionedConstraints = constraints.stream()
.collect(groupingBy(constraint -> constraint.getTupleList().isMarkedAsCorrect()));
if(!partitionedConstraints.containsKey(true)) {
partitionedConstraints.put(true, Collections.emptyList());
}
this.chocoModel = new ChocoModel(this.testModel.getParameterSizes(), constraints);
}
public List detectMissingInvalidTuples() {
if(!configuration.isConflictDetectionEnabled()) {
return Collections.emptyList();
}
final ConflictDetectionResultConverter converter = new ConflictDetectionResultConverter(testModel, expander);
return testModel.getErrorTupleLists().stream()
.map(this::checkForNegatedErrorConstraint)
.flatMap(mits -> mits.stream().map(converter::convertMissingInvalidTuple))
.collect(Collectors.toList());
}
private List checkForNegatedErrorConstraint(TupleList toBeNegated) {
final List missingInvalidTuples = new ArrayList<>();
chocoModel.reset();
chocoModel.setNegationOfConstraint(toBeNegated.getId());
for(int[] tuple : toBeNegated.getTuples()) {
final IntSet background = new IntArraySet();
background.add(toBeNegated.getId());
background.addAll(partitionedConstraints.get(true).stream()
.map(constraint -> constraint.getTupleList().getId())
.collect(Collectors.toList()));
final IntSet relaxable = new IntArraySet();
relaxable.addAll(partitionedConstraints.get(false).stream()
.filter(constraint -> constraint.getTupleList().getId() != toBeNegated.getId())
.map(constraint -> constraint.getTupleList().getId())
.collect(Collectors.toList()));
final Optional optional
= checkForInvalidTuple(toBeNegated, tuple, background, relaxable);
optional.ifPresent(explanation ->
missingInvalidTuples.add(new InternalMissingInvalidTuple(
toBeNegated.getId(),
toBeNegated.getInvolvedParameters(),
tuple,
explanation)));
}
chocoModel.resetNegationOfConstraint();
return missingInvalidTuples;
}
private Optional checkForInvalidTuple(TupleList tupleList,
int[] tuple,
IntSet background,
IntSet relaxable) {
chocoModel.reset();
final int assignmentId = chocoModel.setAssignmentConstraint(tupleList.getInvolvedParameters(), tuple);
background.add(assignmentId);
try {
final Optional optional = createExplanation(background.toIntArray(), relaxable.toIntArray());
return optional.map(explanation -> {
if(configuration.isConflictDiagnosisEnabled() && explanation instanceof InternalConflictSet) {
return new InternalDiagnosisSets((InternalConflictSet) explanation, diagnostician.getMinimalDiagnoses((InternalConflictSet) explanation));
} if(explanation instanceof InternalInconsistentBackground) {
return removeAssignmentConstraintFromBackground(assignmentId, (InternalInconsistentBackground) explanation);
} else {
return explanation;
}
});
} finally {
chocoModel.clearAssignmentConstraint();
background.remove(assignmentId);
}
}
private InternalExplanation removeAssignmentConstraintFromBackground(int assignmentId,
InternalInconsistentBackground explanation) {
final int[] cleanedBackground = Arrays.stream(explanation.getBackground())
.filter(c -> c != assignmentId)
.toArray();
return new InternalInconsistentBackground(cleanedBackground, explanation.getRelaxable());
}
private Optional createExplanation(int[] background, int[] relaxable) {
if(!configuration.isConflictExplanationEnabled()) {
chocoModel.reset();
if(chocoModel.isSatisfiable()) {
return Optional.empty();
} else {
return Optional.of(
new InternalUnknownExplanation()
);
}
} else {
return explainer.getMinimalConflict(chocoModel, background, relaxable);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy