diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/bicreater/BiCreaterAppend.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/bicreater/BiCreaterAppend.java index 1be74c3b79d7e25211a65dcdf32873dd348d79b6..0ff5fd3b501cd5fd2dcfe3132d96400d02647492 100644 --- a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/bicreater/BiCreaterAppend.java +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/bicreater/BiCreaterAppend.java @@ -33,7 +33,10 @@ public class BiCreaterAppend extends AbstractBoundaryBiCreater<AbstractGrowingBo if (b1 instanceof BooleanBoundary) { return createrBoolean((BooleanBoundary) b1, (BooleanBoundary) b2); } - if (b1 instanceof IntegerBoundary || b1 instanceof LongBoundary) { + if (b1 instanceof IntegerBoundary) { + return createrInt(b1, b2); + } + if (b1 instanceof LongBoundary) { return createrLong(b1, b2); } if (b1.getUpperBound().equals(b2.getLowerBound()) @@ -57,6 +60,34 @@ public class BiCreaterAppend extends AbstractBoundaryBiCreater<AbstractGrowingBo return Optional.empty(); } + private Optional<AbstractGrowingBoundary> createrInt( + AbstractGrowingBoundary b1, AbstractGrowingBoundary b2) { + int b1L = (int) b1.getLowerBound(); + int b1U = (int) b1.getUpperBound(); + int b2L = (int) b1.getLowerBound(); + int b2U = (int) b1.getUpperBound(); + if (b1U + 1 == b2L + && b1.getUpperBoundType() == INCLUSIVE + && b2.getLowerBoundType() == INCLUSIVE) { + return Optional.of( + b1.getCopy( + b1.getLowerBound(), + b2.getUpperBound(), + b1.getLowerBoundType(), + b2.getUpperBoundType())); + } else if (b2U + 1 == b1L + && b2.getUpperBoundType() == INCLUSIVE + && b1.getLowerBoundType() == INCLUSIVE) { + return Optional.of( + b1.getCopy( + b2.getLowerBound(), + b1.getUpperBound(), + b2.getLowerBoundType(), + b1.getUpperBoundType())); + } + return Optional.empty(); + } + private Optional<AbstractGrowingBoundary> createrLong( AbstractGrowingBoundary b1, AbstractGrowingBoundary b2) { long b1L = (long) b1.getLowerBound(); diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/bicreater/BiCreaterBetween.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/bicreater/BiCreaterBetween.java index 3c9f40a3320a49d17ee9c692a39b7089f78c423a..b49e845040179b0f5f961cc1274e8e91d1faea4d 100644 --- a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/bicreater/BiCreaterBetween.java +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/bicreater/BiCreaterBetween.java @@ -39,11 +39,11 @@ public class BiCreaterBetween extends AbstractBoundaryBiCreater<AbstractGrowingB && !b2.getUpperBound().equals(b1.getLowerBound())) { return Optional.empty(); } - if (b1 instanceof DoubleBoundary || b1 instanceof IntegerBoundary) { - long b1L = (long) b1.getLowerBound(); - long b1U = (long) b1.getUpperBound(); - long b2L = (long) b1.getLowerBound(); - long b2U = (long) b1.getUpperBound(); + if (b1 instanceof IntegerBoundary) { + int b1L = (int) b1.getLowerBound(); + int b1U = (int) b1.getUpperBound(); + int b2L = (int) b1.getLowerBound(); + int b2U = (int) b1.getUpperBound(); if (b1U + 1 == b2L && b1.getUpperBoundType() == INCLUSIVE && b2.getLowerBoundType() == INCLUSIVE @@ -53,6 +53,20 @@ public class BiCreaterBetween extends AbstractBoundaryBiCreater<AbstractGrowingB return Optional.empty(); } } + if (b1 instanceof DoubleBoundary) { + long b1L = (long) b1.getLowerBound(); + long b1U = (long) b1.getUpperBound(); + long b2L = (long) b1.getLowerBound(); + long b2U = (long) b1.getUpperBound(); + if (b1U + 1 == b2L + && b1.getUpperBoundType() == INCLUSIVE + && b2.getLowerBoundType() == INCLUSIVE + || b2U + 1 == b1L + && b2.getUpperBoundType() == INCLUSIVE + && b1.getLowerBoundType() == INCLUSIVE) { + return Optional.empty(); + } + } if (b1.getLowerBound().compareTo(b2.getUpperBound()) < 0) { return Optional.of( b1.getCopy( diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/domain/vdmn/utils/VDmnFunctions.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/domain/vdmn/utils/VDmnFunctions.java index 03a6c6c58ae1dd473d9637a574a56de8da03bcf8..4b034a65ed77e1400465fd4710a5a019b50c734f 100644 --- a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/domain/vdmn/utils/VDmnFunctions.java +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/domain/vdmn/utils/VDmnFunctions.java @@ -69,7 +69,7 @@ public class VDmnFunctions { .collect(Collectors.toList()); } - public boolean differentConclusions(List<VDmnRule> rules) { + public static boolean differentConclusions(List<VDmnRule> rules) { if (rules.size() == 0) { return false; } @@ -82,7 +82,7 @@ public class VDmnFunctions { return false; } - public boolean differentConclusions(VDmnRule oneRule, VDmnRule otherRule) { + public static boolean differentConclusions(VDmnRule oneRule, VDmnRule otherRule) { if (oneRule.getDmnOutputValues().size() != otherRule.getDmnOutputValues().size()) { return true; } @@ -98,23 +98,25 @@ public class VDmnFunctions { return false; } - public List<List<VDmnRule>> getRuleClustersWithIdenticalOutput( + public static List<List<VDmnRule>> getRuleClustersWithIdenticalOutput( VDmnDecisionTable dmnDecisionTable) { List<List<VDmnRule>> clusters = new ArrayList<>(); List<VDmnRule> remainingRules = new ArrayList<>(dmnDecisionTable.getRules()); for (int i = 0; i < remainingRules.size(); i++) { List<VDmnRule> newCluster = new ArrayList<>(); - newCluster.add(remainingRules.get(i)); - remainingRules.set(i, null); - for (int u = i + 1; u < remainingRules.size(); u++) { - if (remainingRules.get(u) != null - && !differentConclusions(newCluster.get(0), remainingRules.get(u))) { - newCluster.add(remainingRules.get(u)); - remainingRules.set(u, null); + if (remainingRules.get(i) != null) { + newCluster.add(remainingRules.get(i)); + remainingRules.set(i, null); + for (int u = i + 1; u < remainingRules.size(); u++) { + if (remainingRules.get(u) != null + && !differentConclusions(newCluster.get(0), remainingRules.get(u))) { + newCluster.add(remainingRules.get(u)); + remainingRules.set(u, null); + } + } + if (newCluster.size() > 1) { + clusters.add(newCluster); } - } - if (newCluster.size() > 1) { - clusters.add(newCluster); } } return clusters; diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/PartialReductionVerifier.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/PartialReductionVerifier.java index 6074a1196105f3e47211b9ba162774b412ee231a..ce56c450de75f31b01b74ba0fbdf1d94d9220abd 100644 --- a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/PartialReductionVerifier.java +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/PartialReductionVerifier.java @@ -1,9 +1,22 @@ package de.unikoblenz.fgbks.core.dmn.verification.verifier.impl; +import static de.unikoblenz.fgbks.base.utils.boundary.bicreater.BoundaryBiCreaterType.COMBINE; +import static de.unikoblenz.fgbks.base.utils.boundary.checker.BoundaryCheckType.IS_EQUAL; + +import de.unikoblenz.fgbks.core.dmn.domain.vdmn.VDmnDecision; +import de.unikoblenz.fgbks.core.dmn.domain.vdmn.VDmnDecisionTable; +import de.unikoblenz.fgbks.core.dmn.domain.vdmn.VDmnInputColumn; +import de.unikoblenz.fgbks.core.dmn.domain.vdmn.VDmnInputValue; +import de.unikoblenz.fgbks.core.dmn.domain.vdmn.VDmnRule; +import de.unikoblenz.fgbks.core.dmn.domain.vdmn.utils.VDmnFunctions; +import de.unikoblenz.fgbks.core.dmn.verification.result.VerificationResultEntry.VerificationClassification; +import de.unikoblenz.fgbks.core.dmn.verification.result.VerificationResultEntryElement; import de.unikoblenz.fgbks.core.dmn.verification.verifier.AbstractVerifier; import de.unikoblenz.fgbks.core.dmn.verification.verifier.DmnVerifier; import de.unikoblenz.fgbks.core.dmn.verification.verifier.config.DefaultConfiguration; import de.unikoblenz.fgbks.core.dmn.verification.verifier.types.PartialReductionVerification; +import java.util.ArrayList; +import java.util.List; @DmnVerifier( verifierType = PartialReductionVerification.class, @@ -11,5 +24,79 @@ import de.unikoblenz.fgbks.core.dmn.verification.verifier.types.PartialReduction public class PartialReductionVerifier extends AbstractVerifier { @Override - protected void doVerification() {} + protected void doVerification() { + for (VDmnDecision decision : dmnObjectContainer.getVDmnDefinition().getDmnDecisions()) { + findPartialReduction(decision.getDmnDecisionTable()); + } + } + + private void findPartialReduction(VDmnDecisionTable dmnDecisionTable) { + List<List<VDmnRule>> identicalOutputCluster = VDmnFunctions + .getRuleClustersWithIdenticalOutput(dmnDecisionTable); + List<VDmnInputColumn> inColumns = dmnDecisionTable.getInputColumns(); + identicalOutputCluster.stream() // do: parallelStream() ? + .forEach(c -> findPartialReduction(inColumns, 0, c, false)); + } + + private void findPartialReduction(List<VDmnInputColumn> inColumns, int i, + List<VDmnRule> clusterRules, + boolean hasCombination) { + if (i == inColumns.size()) { + if (hasCombination) { + clusterRules.forEach( + rule -> + vreFactory.addElement( + VerificationResultEntryElement.create(inColumns.get(0).getDmnDecisionTable()) + .withIdentifier(rule.getRuleId()))); + vreFactory.addToEntry(VerificationClassification.WARNING, "PartialReduction"); + } + } else { + List<VDmnInputValue> rules = VDmnFunctions + .getColumnValuesInRules(inColumns.get(i), clusterRules); + List<List<VDmnRule>> nClusters = new ArrayList<>(); + List<Boolean> combinationCluster = new ArrayList<>(); + for (int i1 = 0; i1 < rules.size(); i1++) { + VDmnInputValue currentRule = rules.get(i1); + // 1. Find combinations + if (!hasCombination) { + for (int i2 = i1 + 1; i2 < rules.size(); i2++) { + VDmnInputValue currentRuleInner = rules.get(i2); + if (currentRule != currentRuleInner) { + if (currentRule + .getBoundary() + .createBi(COMBINE, currentRuleInner.getBoundary()) + .isPresent()) { + List<VDmnRule> cluster = new ArrayList<>(); + cluster.add(currentRule.getDmnRule()); + cluster.add(currentRuleInner.getDmnRule()); + nClusters.add(cluster); + combinationCluster.add(true); + } + } + } + } + // 2. Find equal values + for (int i2 = i1 + 1; i2 < rules.size(); i2++) { + VDmnInputValue currentRuleInner = rules.get(i2); + if (currentRule != currentRuleInner) { + if (currentRule.getBoundary().checkWith(IS_EQUAL, currentRuleInner.getBoundary())) { + List<VDmnRule> cluster = new ArrayList<>(); + cluster.add(currentRule.getDmnRule()); + cluster.add(currentRuleInner.getDmnRule()); + nClusters.add(cluster); + combinationCluster.add(false); + } + } + } + } + // nex col + for (int x = 0; x < combinationCluster.size(); x++) { + if (nClusters.get(x).size() > 1) { + findPartialReduction( + inColumns, i + 1, nClusters.get(x), combinationCluster.get(x) || hasCombination); + } + } + } + } + }