45 using namespace analysis;
48 const NormalisedClause& right,
const std::vector<std::vector<unsigned int>>& permutationMatrix) {
49 size_t clauseSize = permutationMatrix.size();
51 std::vector<std::vector<unsigned int>> validMoves;
52 for (
size_t i = 0;
i < clauseSize;
i++) {
53 std::vector<unsigned int> currentRow;
54 for (
size_t j = 0;
j < clauseSize;
j++) {
55 if (permutationMatrix[
i][
j] == 1) {
56 currentRow.push_back(
j);
59 validMoves.push_back(currentRow);
63 std::vector<unsigned int> seen(clauseSize);
64 std::vector<unsigned int> currentPermutation;
65 std::stack<std::vector<unsigned int>> todoStack;
67 todoStack.push(validMoves[0]);
69 size_t currentIdx = 0;
70 while (!todoStack.empty()) {
71 if (currentIdx == clauseSize) {
73 if (isValidPermutation(left, right, currentPermutation)) {
80 if (currentIdx == 0) {
87 seen[currentPermutation[currentIdx]] = 0;
88 currentPermutation.pop_back();
95 std::vector<unsigned int> possibilities = todoStack.top();
97 if (possibilities.empty()) {
100 if (currentIdx == 0) {
106 seen[currentPermutation[currentIdx]] = 0;
107 currentPermutation.pop_back();
114 unsigned int nextNum = possibilities[0];
117 possibilities.erase(possibilities.begin());
118 todoStack.push(possibilities);
120 if (seen[nextNum] != 0u) {
126 currentPermutation.push_back(nextNum);
131 if (currentIdx < clauseSize) {
132 todoStack.push(validMoves[currentIdx]);
142 const NormalisedClause& right,
const std::vector<unsigned int>& permutation) {
143 const auto& leftElements = left.getElements();
144 const auto& rightElements = right.getElements();
146 assert(leftElements.size() == rightElements.size() &&
"clauses should have equal size");
147 size_t size = leftElements.size();
149 std::map<std::string, std::string> variableMap;
152 for (
const auto& cst : left.getConstants()) {
153 variableMap[cst] = cst;
157 for (
const auto& var : left.getVariables()) {
158 variableMap[var] =
"";
163 for (
size_t i = 0;
i <
size;
i++) {
164 const auto& leftArgs = leftElements[
i].params;
165 const auto& rightArgs = rightElements[permutation[
i]].params;
166 for (
size_t j = 0;
j < leftArgs.size();
j++) {
167 auto leftArg = leftArgs[
j];
168 auto rightArg = rightArgs[
j];
169 std::string currentMap = variableMap[leftArg];
170 if (currentMap.empty()) {
172 variableMap[leftArg] = rightArg;
173 }
else if (currentMap != rightArg) {
185 const NormalisedClause& left,
const NormalisedClause& right) {
186 const auto& leftElements = left.getElements();
187 const auto& rightElements = right.getElements();
189 const auto& leftVars = left.getVariables();
190 const auto& rightVars = right.getVariables();
193 if (!left.isFullyNormalised() || !right.isFullyNormalised()) {
198 if (leftElements.size() != rightElements.size()) {
203 if (leftElements[0].params.size() != rightElements[0].params.size()) {
208 if (leftVars.size() != rightVars.size()) {
213 if (left.getConstants() != right.getConstants()) {
218 size_t size = leftElements.size();
219 auto permutationMatrix = std::vector<std::vector<unsigned int>>(
size);
220 for (
auto&
i : permutationMatrix) {
221 i = std::vector<unsigned int>(
size);
225 for (
size_t i = 0;
i <
size;
i++) {
226 for (
size_t j = 0;
j <
size;
j++) {
227 if (leftElements[
i].name == rightElements[
j].name) {
228 permutationMatrix[
i][
j] = 1;
234 return existsValidPermutation(left, right, permutationMatrix);
238 Program& program = translationUnit.getProgram();
239 const auto& normalisations = *translationUnit.getAnalysis<analysis::ClauseNormalisationAnalysis>();
241 std::vector<Clause*> clausesToDelete;
246 std::vector<std::vector<Clause*>> equivalenceClasses;
251 for (std::vector<Clause*>& eqClass : equivalenceClasses) {
252 const auto& normedRep = normalisations.getNormalisation(eqClass[0]);
253 const auto& normedClause = normalisations.getNormalisation(clause);
254 if (areBijectivelyEquivalent(normedRep, normedClause)) {
256 eqClass.push_back(clause);
257 clausesToDelete.push_back(clause);
265 std::vector<Clause*> clauseToAdd = {clause};
266 equivalenceClasses.push_back(clauseToAdd);
272 for (
auto clause : clausesToDelete) {
273 program.removeClause(clause);
277 return !clausesToDelete.empty();
283 Program& program = translationUnit.getProgram();
284 const auto& ioTypes = *translationUnit.getAnalysis<analysis::IOTypeAnalysis>();
285 const auto& normalisations = *translationUnit.getAnalysis<analysis::ClauseNormalisationAnalysis>();
288 std::vector<Clause*> singletonRelationClauses;
292 singletonRelationClauses.push_back(clause);
297 std::set<const Clause*> redundantClauses;
300 std::map<QualifiedName, QualifiedName> canonicalName;
303 for (
size_t i = 0;
i < singletonRelationClauses.size();
i++) {
304 const auto* first = singletonRelationClauses[
i];
305 if (redundantClauses.find(first) != redundantClauses.end()) {
310 for (
size_t j =
i + 1;
j < singletonRelationClauses.size();
j++) {
311 const auto* second = singletonRelationClauses[
j];
314 const auto& normedFirst = normalisations.getNormalisation(first);
315 const auto& normedSecond = normalisations.getNormalisation(second);
316 if (areBijectivelyEquivalent(normedFirst, normedSecond)) {
317 QualifiedName firstName = first->getHead()->getQualifiedName();
318 QualifiedName secondName = second->getHead()->getQualifiedName();
319 redundantClauses.insert(second);
320 canonicalName.insert(std::pair(secondName, firstName));
326 for (
const auto* clause : redundantClauses) {
327 auto relName = clause->getHead()->getQualifiedName();
329 assert(
rel !=
nullptr &&
"relation does not exist in program");
334 struct replaceRedundantRelations :
public NodeMapper {
335 const std::map<QualifiedName, QualifiedName>& canonicalName;
337 replaceRedundantRelations(
const std::map<QualifiedName, QualifiedName>& canonicalName)
338 : canonicalName(canonicalName) {}
340 Own<Node> operator()(Own<Node> node)
const override {
344 if (
auto* atom =
dynamic_cast<Atom*
>(node.get())) {
345 auto pos = canonicalName.find(atom->getQualifiedName());
346 if (pos != canonicalName.end()) {
348 newAtom->setQualifiedName(pos->second);
356 replaceRedundantRelations update(canonicalName);
357 program.apply(update);
360 return !canonicalName.empty();
364 Program& program = translationUnit.getProgram();
365 auto isRedundant = [&](
const Clause* clause) {
366 const auto* head = clause->getHead();
367 for (
const auto* lit : clause->getBodyLiterals()) {
375 std::set<Own<Clause>> clausesToRemove;
376 for (
const auto* clause : program.getClauses()) {
377 if (isRedundant(clause)) {
382 for (
auto& clause : clausesToRemove) {
383 program.removeClause(clause.get());
385 return !clausesToRemove.empty();
389 Program& program = translationUnit.getProgram();
390 std::set<Own<Clause>> clausesToAdd;
391 std::set<Own<Clause>> clausesToRemove;
393 for (
const auto* clause : program.getClauses()) {
394 auto bodyLiterals = clause->getBodyLiterals();
395 std::set<size_t> redundantPositions;
396 for (
size_t i = 0;
i < bodyLiterals.size();
i++) {
397 for (
size_t j = 0;
j <
i;
j++) {
398 if (*bodyLiterals[
i] == *bodyLiterals[
j]) {
399 redundantPositions.insert(
j);
405 if (!redundantPositions.empty()) {
406 auto minimisedClause = mk<Clause>();
408 for (
size_t i = 0;
i < bodyLiterals.size();
i++) {
413 clausesToAdd.insert(std::move(minimisedClause));
418 for (
auto& clause : clausesToRemove) {
419 program.removeClause(clause.get());
421 for (
auto& clause : clausesToAdd) {
425 return !clausesToAdd.empty();
429 bool changed =
false;
430 changed |= reduceClauseBodies(translationUnit);
431 if (changed) translationUnit.invalidateAnalyses();
432 changed |= removeRedundantClauses(translationUnit);
433 if (changed) translationUnit.invalidateAnalyses();
434 changed |= reduceLocallyEquivalentClauses(translationUnit);
435 if (changed) translationUnit.invalidateAnalyses();
436 changed |= reduceSingletonRelations(translationUnit);