diff --git a/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/AbstractVerifier.java b/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/AbstractVerifier.java
index 1a9c78498d9993907582ca235c0e1c006bf7800d..8e15bc88477306c95eddf6ce17e2c5729c2a4e6e 100644
--- a/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/AbstractVerifier.java
+++ b/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/AbstractVerifier.java
@@ -10,7 +10,6 @@ import de.unikoblenz.fgbks.dmn.core.verifier.helper.Value;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
-import java.util.Set;
 import java.util.logging.Logger;
 import org.camunda.bpm.dmn.engine.DmnDecision;
 
@@ -61,7 +60,7 @@ public abstract class AbstractVerifier {
 
   protected boolean checkDifferentConclusion(
       String decisionKey, List<RuleIdentifier> currentRuleIdentifiers) {
-    Set<Type> outputCols =
+    List<Type> outputCols =
         ruleMap.getAllOutputTypesFromDecisionKey(Objects.requireNonNull(decisionKey));
     for (Type outputType : outputCols) {
       List<Value> values =
diff --git a/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/IdenticalRules.java b/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/IdenticalRules.java
index 3fb1237d87ad5a821f3796020ad4907d00d2d248..c3abfa77f97d3cb477d4b7ee5bf7a9067551d8dc 100644
--- a/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/IdenticalRules.java
+++ b/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/IdenticalRules.java
@@ -8,24 +8,17 @@ import de.unikoblenz.fgbks.dmn.core.verifier.helper.Value;
 import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.List;
-import java.util.Set;
-import java.util.logging.Logger;
 import java.util.stream.Collectors;
 import org.camunda.bpm.dmn.engine.DmnDecision;
 
 public class IdenticalRules extends AbstractVerifier {
 
-  private static final Logger LOGGER = Logger.getLogger(IdenticalRules.class.getSimpleName());
-  private Set<Set<String>> identicaldecicionTables;
-
   public IdenticalRules() {
     super(VerifierType.Identical);
   }
 
   @Override
-  protected void beforeVerifyDecision() {
-    identicaldecicionTables = ruleMap.getIncludingInputDefinitions();
-  }
+  protected void beforeVerifyDecision() {}
 
   @Override
   protected void verifyDecision(DmnDecision d) {
@@ -50,12 +43,12 @@ public class IdenticalRules extends AbstractVerifier {
     } else {
       List<Value> currentBounds = new ArrayList<>();
       List<Value> sortedBounds =
-          new ArrayList<>(ruleMap.getValuesFromInputType(inputs.get(i), currentRuleIdentifiers));
+          ruleMap.getValuesFromInputType(inputs.get(i), currentRuleIdentifiers);
       sortedBounds.sort(Comparator.comparing(Value::getBoundary));
       Value lastBound = null;
       for (Value currentBound : sortedBounds) {
         if (lastBound != null) {
-          if (currentBound.getBoundary().isEquals(lastBound.getBoundary())) {
+          if (currentBound.getBoundary().isEqualsTo(lastBound.getBoundary())) {
             currentBounds.add(lastBound);
           } else {
             if (currentBounds.size() > 0) {
diff --git a/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/MissingRules.java b/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/MissingRules.java
index ab8380dd306cfa8470adb3217fe6048734cd614c..66fe182a13a3354b57485ce7982f1f96061e7732 100644
--- a/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/MissingRules.java
+++ b/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/MissingRules.java
@@ -4,13 +4,13 @@ import de.unikoblenz.fgbks.dmn.core.models.RuleIdentifier;
 import de.unikoblenz.fgbks.dmn.core.models.VerificationResult;
 import de.unikoblenz.fgbks.dmn.core.models.VerifierType;
 import de.unikoblenz.fgbks.dmn.core.verifier.helper.Boundary;
-import de.unikoblenz.fgbks.dmn.core.verifier.helper.DataType;
 import de.unikoblenz.fgbks.dmn.core.verifier.helper.Type;
 import de.unikoblenz.fgbks.dmn.core.verifier.helper.Value;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
 import java.util.List;
+import java.util.Objects;
 import java.util.Optional;
 import java.util.stream.Collectors;
 import org.camunda.bpm.dmn.engine.DmnDecision;
@@ -22,24 +22,57 @@ public class MissingRules extends AbstractVerifier {
   }
 
   @Override
-  protected void beforeVerifyDecision() {
-  }
+  protected void beforeVerifyDecision() {}
 
   @Override
   protected void verifyDecision(DmnDecision d) {
     if (d.isDecisionTable()) {
       List<Type> inputs = new ArrayList<>(ruleMap.getAllInputTypesFromDecisionKey(d.getKey()));
       List<Value[]> missingIntervals = new ArrayList<>();
-      checkForMissingRules(d, inputs, 0, new Value[inputs.size()], missingIntervals);
+      checkForMissingRules(d, inputs, 0, new Value[inputs.size()], missingIntervals, false);
+      // remove duplicate rules
+      for (int i = 0; i < missingIntervals.size(); i++) {
+        if (missingIntervals.get(i) != null) {
+          inner:
+          for (int u = i + 1; u < missingIntervals.size(); u++) {
+            if (missingIntervals.get(u) != null) {
+              boolean isEqual;
+              for (int x = 0; x < missingIntervals.get(i).length; x++) {
+                if ((missingIntervals.get(i)[x].getOrgExpression() == null)
+                    ^ (missingIntervals.get(u)[x].getOrgExpression() == null)) {
+                  isEqual = false;
+                } else {
+                  isEqual =
+                      (missingIntervals.get(i)[x].getOrgExpression() == null
+                                  && missingIntervals.get(u)[x].getOrgExpression() == null
+                              || missingIntervals
+                                  .get(i)[x]
+                                  .getOrgExpression()
+                                  .equals(missingIntervals.get(u)[x].getOrgExpression()))
+                          && missingIntervals.get(i)[x].getType()
+                              == missingIntervals.get(u)[x].getType();
+                }
+                if (!isEqual) {
+                  continue inner;
+                }
+              }
+            }
+            missingIntervals.set(u, null);
+          }
+        }
+      }
+      // TODO in later state: merge rules -> like partial Reduction
       // add errors for missing intervals
-      // TODO: add duplicate rows
-      for (Value[] missingInt : missingIntervals) {
+      for (Value[] missingInt :
+          missingIntervals.stream().filter(Objects::nonNull).collect(Collectors.toList())) {
         StringBuilder sb = new StringBuilder("In table ");
         sb.append(d.getName()); // TODO: add real name
-        sb.append(" following rule is missing: ");
-        sb.append(Arrays.stream(missingInt)
-            .map(Value::getOrgExpression)
-            .collect(Collectors.joining(" / ")));
+        sb.append(" the following rule is not defined: (");
+        sb.append(
+            Arrays.stream(missingInt)
+                .map(Value::getOrgExpression)
+                .collect(Collectors.joining("), (")));
+        sb.append(")");
         addVerification(
             VerificationResult.getBuilder()
                 .addRules(
@@ -57,82 +90,99 @@ public class MissingRules extends AbstractVerifier {
       List<Type> inputs,
       int i,
       Value[] missingValues,
-      List<Value[]> missingIntervals) {
+      List<Value[]> missingIntervals,
+      boolean hasMissing) {
     if (i == inputs.size()) {
-      missingIntervals.add(missingValues.clone());
+      if (hasMissing) {
+        missingIntervals.add(missingValues.clone());
+      }
     } else {
-      List<Value> sortedBounds =
-          new ArrayList<>(ruleMap.getValuesFromInputType(inputs.get(i)));
+      List<Value> sortedBounds = ruleMap.getValuesFromInputType(inputs.get(i));
       sortedBounds.sort(Comparator.comparing(Value::getBoundary));
 
       Value lastBound = null;
       int z = 0;
       for (Value currentBound : sortedBounds) {
+        boolean currentHasMissing = false;
         z++;
         Optional<Boundary> newBoundary = Optional.empty();
         String orgExpr = "";
-        if (inputs.get(i).getDataType() == DataType.NUMBER) {
+        if (inputs.get(i).getDataType().isNumeric()) {
           if (lastBound == null) { // check current elements
             if (currentBound.getBoundary().getLowerBound() != Double.MIN_VALUE) {
               newBoundary = currentBound.getBoundary().getNewBoundaryLower();
             }
           } else {
-            newBoundary =
-                lastBound.getBoundary().getNewBoundaryBetween(currentBound.getBoundary());
+            newBoundary = lastBound.getBoundary().getNewBoundaryBetween(currentBound.getBoundary());
           }
           if (newBoundary.isPresent()) {
             orgExpr = newBoundary.get().toString();
+            currentHasMissing = true;
           }
-        } else {
-          newBoundary = Optional.of(currentBound.getBoundary());
-          orgExpr = currentBound.getOrgExpression();
         }
         if (newBoundary.isPresent()) {
-          missingValues[i] = new Value(newBoundary.get(), orgExpr,
-              RuleIdentifier.getBuilder()
-                  .withRowNumber(999)
-                  .withDecision(d)
-                  .withRuleId("newRule")
-                  .build(),
-              inputs.get(i));
-          checkForMissingRules(d, inputs, i + 1, missingValues, missingIntervals);
-          missingValues[i] = null;
-        }
-
-        // TODO: check last element
-        if (z == sortedBounds.size()) {
-          if (inputs.get(i).getDataType() == DataType.NUMBER) {
-            if (currentBound.getBoundary().getUpperBound() != Double.MAX_VALUE) {
-              newBoundary = currentBound.getBoundary().getNewBoundaryUpper();
-              orgExpr = newBoundary.get().toString();
-              missingValues[i] = new Value(newBoundary.get(), orgExpr,
+          missingValues[i] =
+              new Value(
+                  newBoundary.get(),
+                  orgExpr,
                   RuleIdentifier.getBuilder()
                       .withRowNumber(999)
                       .withDecision(d)
                       .withRuleId("newRule")
                       .build(),
                   inputs.get(i));
-              checkForMissingRules(d, inputs, i + 1, missingValues, missingIntervals);
-              missingValues[i] = null;
-            }
-          } else {
-            // not number TODO
-          }
+          checkForMissingRules(
+              d, inputs, i + 1, missingValues, missingIntervals, hasMissing || currentHasMissing);
+          missingValues[i] = null;
         }
+        // check if the current rule is has missing ranges in next columns
+        missingValues[i] = currentBound;
+        checkForMissingRules(d, inputs, i + 1, missingValues, missingIntervals, hasMissing);
+        missingValues[i] = null;
+
         // set next last bound
         if (lastBound == null
             || !lastBound
-            .getBoundary()
-            .isNumberInRange(
-                currentBound.getBoundary().getUpperBound(),
-                currentBound.getBoundary().getUpperBoundType())) {
+                .getBoundary()
+                .isNumberInRange(
+                    currentBound.getBoundary().getUpperBound(),
+                    currentBound.getBoundary().getUpperBoundType())) {
           lastBound = currentBound;
         }
+        // check last element in list
+        newBoundary = Optional.empty();
+        if (z == sortedBounds.size() && z != 1) {
+          if (inputs.get(i).getDataType().isNumeric()) {
+            if (lastBound.getBoundary().getUpperBound() != Double.MAX_VALUE) {
+              newBoundary = lastBound.getBoundary().getNewBoundaryUpper();
+              if (newBoundary.isPresent()) {
+                orgExpr = newBoundary.get().toString();
+                hasMissing = true;
+              }
+            }
+          } else {
+            newBoundary = Optional.of(lastBound.getBoundary());
+            orgExpr = lastBound.getOrgExpression();
+          }
+          if (newBoundary.isPresent()) {
+            missingValues[i] =
+                new Value(
+                    newBoundary.get(),
+                    orgExpr,
+                    RuleIdentifier.getBuilder()
+                        .withRowNumber(999)
+                        .withDecision(d)
+                        .withRuleId("newRule")
+                        .build(),
+                    inputs.get(i));
+            checkForMissingRules(d, inputs, i + 1, missingValues, missingIntervals, hasMissing);
+            missingValues[i] = null;
+          }
+        }
       }
     }
   }
 
   @Override
-  protected void afterVerifyDecision() {
-  }
+  protected void afterVerifyDecision() {}
 }
diff --git a/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/OverlappingRules.java b/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/OverlappingRules.java
index ae7765c740aee4ec7120c230aab73460a8c1dcae..eaced682b1f9fc8b471d7f52b8280977c31e4259 100644
--- a/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/OverlappingRules.java
+++ b/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/OverlappingRules.java
@@ -6,6 +6,7 @@ import de.unikoblenz.fgbks.dmn.core.models.VerifierType;
 import de.unikoblenz.fgbks.dmn.core.verifier.helper.Type;
 import de.unikoblenz.fgbks.dmn.core.verifier.helper.Value;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 import java.util.stream.Collectors;
@@ -24,12 +25,16 @@ public class OverlappingRules extends AbstractVerifier {
   protected void verifyDecision(DmnDecision d) {
     if (d.isDecisionTable()) {
       List<Type> inputs = new ArrayList<>(ruleMap.getAllInputTypesFromDecisionKey(d.getKey()));
-      checkForOverlappingRules(inputs, 0, null, false);
+      checkForOverlappingRules(inputs, 0, null, false, Collections.emptyList());
     }
   }
 
   private void checkForOverlappingRules(
-      List<Type> inputs, int i, List<RuleIdentifier> currentRuleIdentifiers, boolean hasOverlap) {
+      List<Type> inputs,
+      int i,
+      List<RuleIdentifier> currentRuleIdentifiers,
+      boolean hasOverlap,
+      List<RuleIdentifier> subsubmtionRules) {
     if (i == inputs.size()) {
       // do nothing, if there was no real overlap found prev..
       if (hasOverlap) {
@@ -47,7 +52,7 @@ public class OverlappingRules extends AbstractVerifier {
     } else {
       List<Value> currentBounds = new ArrayList<>();
       List<Value> sortedBounds =
-          new ArrayList<>(ruleMap.getValuesFromInputType(inputs.get(i), currentRuleIdentifiers));
+          ruleMap.getValuesFromInputType(inputs.get(i), currentRuleIdentifiers);
       sortedBounds.sort(Comparator.comparing(Value::getBoundary));
       int z = 0;
       boolean foundPOverlap = false;
@@ -71,26 +76,71 @@ public class OverlappingRules extends AbstractVerifier {
                 foundOverlap || currentBound.getBoundary().isOverlapping(bound.getBoundary());
           }
         }
-        if (foundNotInContact) {
+        if (foundNotInContact && currentBoundsCpy.size() > 1) {
+          List<RuleIdentifier> newSubsumtionRules = searchSubsubmtionElement(currentBoundsCpy);
           checkForOverlappingRules(
               inputs,
               i + 1,
               currentBoundsCpy.stream().map(Value::getRuleIdentifier).collect(Collectors.toList()),
-              hasOverlap || foundPOverlap);
+              hasOverlap
+                  || foundPOverlap
+                  || (newSubsumtionRules.size() > 0
+                      && subsubmtionRules.size() > 0
+                      && containsNoDuplicateRows(newSubsumtionRules, subsubmtionRules)),
+              newSubsumtionRules);
           foundPOverlap = false;
         }
         if (z == sortedBounds.size() && currentBounds.size() > 1) {
+          List<RuleIdentifier> newSubsumtionRules = searchSubsubmtionElement(currentBounds);
+          // check if
           checkForOverlappingRules(
               inputs,
               i + 1,
               currentBounds.stream().map(Value::getRuleIdentifier).collect(Collectors.toList()),
-              hasOverlap || foundOverlap);
+              hasOverlap
+                  || foundOverlap
+                  || (newSubsumtionRules.size() > 0
+                      && subsubmtionRules.size() > 0
+                      && containsNoDuplicateRows(newSubsumtionRules, subsubmtionRules)),
+              newSubsumtionRules);
         }
         foundPOverlap |= foundOverlap;
       }
     }
   }
 
+  private List<RuleIdentifier> searchSubsubmtionElement(List<Value> values) {
+    List<RuleIdentifier> subsubmtionRules = new ArrayList<>();
+    outer:
+    for (Value value : values) {
+      boolean containsSubsumption = false;
+      for (Value innerValue : values) {
+        if (value.getBoundary().subsumes(innerValue.getBoundary())) {
+          containsSubsumption = true;
+        } else if (value.getBoundary().isNotInContact(innerValue.getBoundary())
+            || value.getBoundary().isOverlapping(innerValue.getBoundary())) {
+          continue outer;
+        }
+      }
+      if (containsSubsumption) {
+        subsubmtionRules.add(value.getRuleIdentifier());
+      }
+    }
+    return subsubmtionRules;
+  }
+
+  private boolean containsNoDuplicateRows(List<RuleIdentifier> ri1, List<RuleIdentifier> ri2) {
+    for (RuleIdentifier r1 : ri1) {
+      for (RuleIdentifier r2 : ri2) {
+        if (r1.getDecisionKey().equals(r2.getDecisionKey())
+            && r1.getRowNumber().equals(r2.getRowNumber())) {
+          return false;
+        }
+      }
+    }
+    return true;
+  }
+
   @Override
   protected void afterVerifyDecision() {}
 
diff --git a/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/PartialReductionRules.java b/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/PartialReductionRules.java
index 7bd8b2a34983d1573cbcab7a3b144c3f5e98bc95..15da25ef0e73cb1cb4f95bf416830d55ade54a75 100644
--- a/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/PartialReductionRules.java
+++ b/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/PartialReductionRules.java
@@ -1,6 +1,14 @@
 package de.unikoblenz.fgbks.dmn.core.verifier;
 
+import de.unikoblenz.fgbks.dmn.core.models.RuleIdentifier;
+import de.unikoblenz.fgbks.dmn.core.models.VerificationResult;
 import de.unikoblenz.fgbks.dmn.core.models.VerifierType;
+import de.unikoblenz.fgbks.dmn.core.verifier.helper.Type;
+import de.unikoblenz.fgbks.dmn.core.verifier.helper.Value;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
 import org.camunda.bpm.dmn.engine.DmnDecision;
 
 public class PartialReductionRules extends AbstractVerifier {
@@ -13,7 +21,140 @@ public class PartialReductionRules extends AbstractVerifier {
   protected void beforeVerifyDecision() {}
 
   @Override
-  protected void verifyDecision(DmnDecision d) {}
+  protected void verifyDecision(DmnDecision d) {
+    if (d.isDecisionTable()) {
+      List<List<RuleIdentifier>> identicalOutputCluster = findIdenticalOutputs(d);
+      List<Type> inputs = new ArrayList<>(ruleMap.getAllInputTypesFromDecisionKey(d.getKey()));
+      identicalOutputCluster
+          .stream() // do: parallelStream() ?
+          .forEach(c -> findPartialReduction(d, inputs, 0, c, false));
+    }
+  }
+
+  private List<List<RuleIdentifier>> findIdenticalOutputs(DmnDecision d) {
+    List<List<RuleIdentifier>> clusters = new ArrayList<>();
+    List<Type> outputs = new ArrayList<>(ruleMap.getAllOutputTypesFromDecisionKey(d.getKey()));
+
+    List<RuleIdentifier> rowsIds =
+        ruleMap
+            .getValuesFromType(outputs.get(0))
+            .stream()
+            .map(Value::getRuleIdentifier)
+            .collect(Collectors.toList());
+    int rowsCount = ruleMap.getValuesFromType(outputs.get(0)).size();
+    for (int i = 0; i < rowsCount; i++) {
+      List<RuleIdentifier> cluster = new ArrayList<>();
+      cluster.add(rowsIds.get(i));
+      inner:
+      for (int u = i + 1; u < rowsCount; u++) {
+        for (List<RuleIdentifier> clu : clusters) {
+          if (clu.contains(rowsIds.get(u))) {
+            continue inner;
+          }
+        }
+        if (checkRulesHasIdenticalOutput(d, rowsIds.get(i), rowsIds.get(u))) {
+          cluster.add(rowsIds.get(u));
+        }
+      }
+      if (cluster.size() > 1) {
+        clusters.add(cluster);
+      }
+    }
+    return clusters;
+  }
+
+  private boolean checkRulesHasIdenticalOutput(
+      DmnDecision d, RuleIdentifier r1, RuleIdentifier r2) {
+    List<Type> outputs = new ArrayList<>(ruleMap.getAllOutputTypesFromDecisionKey(d.getKey()));
+    for (Type type : outputs) {
+      Value v1;
+      Value v2;
+      try {
+        v1 = ruleMap.getValuesFromOutputType(type, Collections.singletonList(r1)).get(0);
+        v2 = ruleMap.getValuesFromOutputType(type, Collections.singletonList(r2)).get(0);
+      } catch (Exception e) {
+        return false;
+      }
+      if (!v1.getBoundary().isEqualsTo(v2.getBoundary())) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  private void findPartialReduction(
+      DmnDecision d,
+      List<Type> inputs,
+      int i,
+      List<RuleIdentifier> identicalOutputCluster,
+      boolean hasCombination) {
+    if (i == inputs.size()) {
+      if (hasCombination) {
+        VerificationResult.Builder vBuilder =
+            VerificationResult.getBuilder().withMessage(getMessageText(identicalOutputCluster));
+        vBuilder.addRules(identicalOutputCluster);
+        addVerification(vBuilder.build());
+      }
+    } else {
+      List<Value> rules = ruleMap.getValuesFromInputType(inputs.get(i), identicalOutputCluster);
+      List<List<RuleIdentifier>> nClusters = new ArrayList<>();
+      List<Boolean> combinationCluster = new ArrayList<>();
+      for (int i1 = 0; i1 < rules.size(); i1++) {
+        Value currentRule = rules.get(i1);
+        // 1. Find combinations
+        if (!hasCombination) {
+          for (int i2 = i1 + 1; i2 < rules.size(); i2++) {
+            Value currentRuleInner = rules.get(i2);
+            if (currentRule != currentRuleInner) {
+              if (currentRule
+                  .getBoundary()
+                  .combineWith(currentRuleInner.getBoundary())
+                  .isPresent()) {
+                List<RuleIdentifier> cluster = new ArrayList<>();
+                cluster.add(currentRule.getRuleIdentifier());
+                cluster.add(currentRuleInner.getRuleIdentifier());
+                nClusters.add(cluster);
+                combinationCluster.add(true);
+              }
+            }
+          }
+        }
+        // 2. Find equal values
+        for (int i2 = i1 + 1; i2 < rules.size(); i2++) {
+          Value currentRuleInner = rules.get(i2);
+          if (currentRule != currentRuleInner) {
+            if (currentRule.getBoundary().isEqualsTo(currentRuleInner.getBoundary())) {
+              List<RuleIdentifier> cluster = new ArrayList<>();
+              cluster.add(currentRule.getRuleIdentifier());
+              cluster.add(currentRuleInner.getRuleIdentifier());
+              nClusters.add(cluster);
+              combinationCluster.add(false);
+            }
+          }
+        }
+      }
+      // nex col
+      for (int x = 0; x < combinationCluster.size(); x++) {
+        if (nClusters.get(x).size() > 1) {
+          findPartialReduction(
+              d, inputs, i + 1, nClusters.get(x), combinationCluster.get(x) || hasCombination);
+        }
+      }
+    }
+  }
+
+  private String getMessageText(List<RuleIdentifier> ruleIdentifiers) {
+    StringBuilder sb = new StringBuilder("Rules ");
+    sb.append(
+        ruleIdentifiers
+            .stream()
+            .map(c -> c.getRowNumber().toString())
+            .collect(Collectors.joining(" and ")));
+    sb.append(" in table ");
+    sb.append(ruleIdentifiers.get(0).getTableName());
+    sb.append(" can be combined.");
+    return sb.toString();
+  }
 
   @Override
   protected void afterVerifyDecision() {}
diff --git a/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/SubsumptionRules.java b/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/SubsumptionRules.java
index 57d081c87b580b1de75ac5087453418d3d8696bc..b5f219670da39634f8e39f89aee0869e58d9eeca 100644
--- a/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/SubsumptionRules.java
+++ b/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/SubsumptionRules.java
@@ -83,7 +83,7 @@ public class SubsumptionRules extends AbstractVerifier {
             foundSubsumption |= fs;
             if (fs) {
               c1.add(cb2);
-            } else if (nValue.getBoundary().isEquals(cb2.getBoundary())) {
+            } else if (nValue.getBoundary().isEqualsTo(cb2.getBoundary())) {
               c1.add(cb2);
               if (currentRootSubsumptionElements.contains(cb2)) {
                 subsumptionVals.add(cb2);
@@ -111,7 +111,7 @@ public class SubsumptionRules extends AbstractVerifier {
           }
           List<Value> subsumptionVals = new ArrayList<>();
           for (Value cb2 : selectedBounds) {
-            if (cb1.getBoundary().isEquals(cb2.getBoundary())) {
+            if (cb1.getBoundary().isEqualsTo(cb2.getBoundary())) {
               c1.add(cb2);
               if (foundSubsumption) {
                 subsumptionVals.add(cb2);
diff --git a/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/helper/Boundary.java b/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/helper/Boundary.java
index 87cd776ff35d6d599e10e4d069c327d4d640a5b9..0644d607af3c06e5531d02ddc7d6305bce8998dd 100644
--- a/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/helper/Boundary.java
+++ b/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/helper/Boundary.java
@@ -7,7 +7,7 @@ import de.unikoblenz.fgbks.base.builder.DefaultBuilder;
 import java.util.Objects;
 import java.util.Optional;
 
-/** Class for manage boundary and intervals. Can also handle String values. */
+/** Class for manage boundaries and intervals. Can also handle String values. */
 public class Boundary implements Comparable<Boundary> {
 
   public enum BoundType {
@@ -27,9 +27,11 @@ public class Boundary implements Comparable<Boundary> {
   private BoundType lowerBoundType;
   private double upperBound;
   private BoundType upperBoundType;
+  private boolean integerValue;
 
   private Boundary() {
     super();
+    this.integerValue = false;
   }
 
   public double getLowerBound() {
@@ -64,6 +66,14 @@ public class Boundary implements Comparable<Boundary> {
     this.upperBoundType = upperBoundType;
   }
 
+  public boolean isIntegerValue() {
+    return integerValue;
+  }
+
+  private void setIntegerValue(boolean integerValue) {
+    this.integerValue = integerValue;
+  }
+
   /**
    * Check, if a number is in between the current boundary
    *
@@ -131,7 +141,7 @@ public class Boundary implements Comparable<Boundary> {
    * @return true or false
    */
   public boolean isOverlapping(Boundary other) {
-    return !isEquals(other) && !isNotInContact(other) && !isSubsumption(other);
+    return !isEqualsTo(other) && !isNotInContact(other) && !isSubsumption(other);
   }
 
   /**
@@ -314,7 +324,7 @@ public class Boundary implements Comparable<Boundary> {
    * @param other Boundary to check
    * @return true or false
    */
-  public boolean isEquals(Boundary other) {
+  public boolean isEqualsTo(Boundary other) {
     return equals(other);
   }
 
@@ -362,7 +372,7 @@ public class Boundary implements Comparable<Boundary> {
   }
 
   /**
-   * Create an new boundary, witch is lover than the current <br>
+   * Create an new boundary, which is lover than the current <br>
    * >10 --> <=10
    *
    * @return An Optional of the Boundary, if the current has a possible boundary, which is lower
@@ -377,6 +387,7 @@ public class Boundary implements Comparable<Boundary> {
             .withLowerBoundType(INCLUSIVE)
             .withUpperBound(lowerBound)
             .withUpperBoundType(lowerBoundType.getOp())
+            .isInteger(isIntegerValue())
             .build());
   }
 
@@ -389,9 +400,25 @@ public class Boundary implements Comparable<Boundary> {
    *     there is no interval in between
    */
   public Optional<Boundary> getNewBoundaryBetween(Boundary other) {
-    if (!isNotInContact(Objects.requireNonNull(other))) {
+    if (isInContact(Objects.requireNonNull(other))) {
       return Optional.empty();
     }
+    // not space between the two bounds
+    if (this.upperBound == other.lowerBound && this.upperBoundType != other.lowerBoundType
+        || other.upperBound == this.lowerBound && other.upperBoundType != this.lowerBoundType) {
+      return Optional.empty();
+    }
+    // check if is integer val
+    if (isIntegerValue()) {
+      if (this.upperBound + 1 == other.lowerBound
+              && this.upperBoundType == INCLUSIVE
+              && other.lowerBoundType == INCLUSIVE
+          || other.upperBound + 1 == this.lowerBound
+              && other.upperBoundType == INCLUSIVE
+              && this.lowerBoundType == INCLUSIVE) {
+        return Optional.empty();
+      }
+    }
     if (this.upperBound < other.upperBound) {
       return Optional.of(
           getBuilder()
@@ -399,6 +426,7 @@ public class Boundary implements Comparable<Boundary> {
               .withLowerBoundType(this.upperBoundType.getOp())
               .withUpperBound(other.lowerBound)
               .withUpperBoundType(other.lowerBoundType.getOp())
+              .isInteger(isIntegerValue())
               .build());
     } else {
       return Optional.of(
@@ -407,12 +435,13 @@ public class Boundary implements Comparable<Boundary> {
               .withLowerBoundType(other.upperBoundType.getOp())
               .withUpperBound(this.lowerBound)
               .withUpperBoundType(this.lowerBoundType.getOp())
+              .isInteger(isIntegerValue())
               .build());
     }
   }
 
   /**
-   * Create a new boundary, witch begins at the upper bound of the original <br>
+   * Create a new boundary, which begins at the upper bound of the original <br>
    * <10 --> >=10
    *
    * @return An Optional of the Boundary if the current has a possible boundary, which is higher
@@ -427,45 +456,96 @@ public class Boundary implements Comparable<Boundary> {
             .withLowerBoundType(upperBoundType.getOp())
             .withUpperBound(Double.MAX_VALUE)
             .withUpperBoundType(INCLUSIVE)
+            .isInteger(isIntegerValue())
             .build());
   }
 
   /**
    * Create a new Boundary from two given ones. The Optional is empty, if the given two bounds are
-   * not direct followed by each other. <u>Example:</u><br>
+   * not direct followed by each other or current in contact<u>Example:</u><br>
    * <code>
-   * [10..20]  &  >20 --> >=10<br> [10..20]  &  <10 --> <=20<br> [10..20]  &  <=10 --> empty
-   * Optional (Boundaries are overlapping)<br>
+   * [10..20]  &  >20 --> >=10<br> [10..20]  &  <10 --> <=20<br> [10..20]  &  <=0 --> empty Optional
+   * (Boundaries are not in contact)<br> [10..20]  &  <=10 --> empty Optional (Boundaries are
+   * overlapping)<br>
    * </code>
    *
    * @param other the other boundary
    */
-  public Optional<Boundary> combineWith(Boundary other) {
+  public Optional<Boundary> appendWith(Boundary other) {
     if (isNotInContact(other)) {
-      if (this.upperBound == other.lowerBound && this.upperBoundType != other.lowerBoundType) {
+      if (this.upperBound == other.lowerBound && this.upperBoundType != other.lowerBoundType
+          || isIntegerValue()
+              && this.upperBound + 1 == other.lowerBound
+              && this.upperBoundType == INCLUSIVE
+              && other.lowerBoundType == INCLUSIVE) {
         return Optional.of(
             getBuilder()
                 .withLowerBound(this.lowerBound)
                 .withLowerBoundType(this.lowerBoundType)
                 .withUpperBound(other.upperBound)
                 .withUpperBoundType(other.getUpperBoundType())
+                .isInteger(isIntegerValue())
                 .build());
-      } else if (this.lowerBound == other.upperBound
-          && other.upperBoundType != this.lowerBoundType) {
+      } else if (this.lowerBound == other.upperBound && other.upperBoundType != this.lowerBoundType
+          || isIntegerValue()
+              && other.upperBound + 1 == this.lowerBound
+              && other.upperBoundType == INCLUSIVE
+              && this.lowerBoundType == INCLUSIVE) {
         return Optional.of(
             getBuilder()
                 .withLowerBound(other.lowerBound)
                 .withLowerBoundType(other.lowerBoundType)
                 .withUpperBound(this.upperBound)
                 .withUpperBoundType(this.getUpperBoundType())
+                .isInteger(isIntegerValue())
                 .build());
-      } else {
-        return Optional.empty();
       }
     }
     return Optional.empty();
   }
 
+  /**
+   * Create a new Boundary from two given ones. The Optional is empty, if the given two bounds are
+   * not direct followed by each other. They can be in contact <u>Example:</u><br>
+   * <code>
+   * [10..20]  &  >20 --> >=10<br> [10..20]  &  <10 --> <=20<br> [10..20]  &  <=0 --> empty Optional
+   * (Boundaries are not in contact)<br> [10..20]  &  <=10 --> <=20 <br>
+   * </code>
+   *
+   * @param other the other boundary
+   */
+  public Optional<Boundary> combineWith(Boundary other) {
+    if (isNotInContact(other)) {
+      return appendWith(other);
+    }
+    Builder builder = getBuilder().isInteger(isIntegerValue());
+    if (this.lowerBound == Double.MIN_VALUE || this.lowerBound < other.lowerBound) {
+      builder.withLowerBound(this.lowerBound).withLowerBoundType(this.lowerBoundType);
+    } else if (other.lowerBound == Double.MIN_VALUE || other.lowerBound < this.lowerBound) {
+      builder.withLowerBound(other.lowerBound).withLowerBoundType(other.lowerBoundType);
+    } else {
+      builder
+          .withLowerBound(other.lowerBound)
+          .withLowerBoundType(
+              this.lowerBoundType == INCLUSIVE || other.lowerBoundType == INCLUSIVE
+                  ? INCLUSIVE
+                  : EXCLUSIVE);
+    }
+    if (this.upperBound == Double.MAX_VALUE || this.upperBound > other.upperBound) {
+      builder.withUpperBound(this.upperBound).withUpperBoundType(this.upperBoundType);
+    } else if (other.upperBound == Double.MAX_VALUE || other.upperBound > this.upperBound) {
+      builder.withUpperBound(other.upperBound).withUpperBoundType(other.upperBoundType);
+    } else {
+      builder
+          .withUpperBound(other.upperBound)
+          .withUpperBoundType(
+              this.upperBoundType == INCLUSIVE || other.upperBoundType == INCLUSIVE
+                  ? INCLUSIVE
+                  : EXCLUSIVE);
+    }
+    return Optional.of(builder.build());
+  }
+
   @Override
   public int hashCode() {
     return Objects.hash(lowerBound, lowerBoundType, upperBound, upperBoundType);
@@ -484,7 +564,27 @@ public class Boundary implements Comparable<Boundary> {
    * @return a new Boundary object
    */
   public static Boundary parseFromNumericValue(String expr) {
+    return parseFromNumericValue(expr, false);
+  }
+
+  /**
+   * Parse a String to a boundary object.<br>
+   * <u>Possible forms:</u><br>
+   * <code>
+   * Interval: [x..y] (inclusive x and inclusive y) <br> Interval: ]x..y[ (exclusive x and exclusive
+   * y) <br> Max Val: <=x (inclusive x) <br> Max Val: &lt;x (exclusive x) <br> Min Val: >=x
+   * (inclusive x) <br> Min Val: >x (exclusive x) <br>Equal: =x (inclusive x) <br>
+   * </code>
+   *
+   * @param expr String to parse
+   * @param isIntegerValue true, if the value is a integer Value
+   * @return a new Boundary object
+   */
+  public static Boundary parseFromNumericValue(String expr, boolean isIntegerValue) {
     Builder builder = getBuilder();
+    if (isIntegerValue) {
+      builder.isInteger();
+    }
     try {
       expr = Objects.requireNonNull(expr).trim();
       if (expr.startsWith("[") || expr.startsWith("]")) {
@@ -561,7 +661,7 @@ public class Boundary implements Comparable<Boundary> {
   }
 
   /**
-   * Creats a "wildcard" boundary. [-infinity..+infinity]
+   * Creates a "wildcard" boundary. [-infinity..+infinity]
    *
    * @return a boundary
    */
@@ -586,24 +686,24 @@ public class Boundary implements Comparable<Boundary> {
       if (getUpperBoundType() == INCLUSIVE) {
         sb.append("=");
       }
-      sb.append(getUpperBound());
+      sb.append(getValAsString(getUpperBound()));
     } else if (getUpperBound() == Double.MAX_VALUE) {
       sb.append(">");
       if (getLowerBoundType() == INCLUSIVE) {
         sb.append("=");
       }
-      sb.append(getLowerBound());
+      sb.append(getValAsString(getLowerBound()));
     } else if (getLowerBound() == getUpperBound()) {
-      sb.append("=").append(getLowerBound());
+      sb.append("=").append(getValAsString(getLowerBound()));
     } else {
       if (getLowerBoundType() == INCLUSIVE) {
         sb.append("[");
       } else {
         sb.append("]");
       }
-      sb.append(getLowerBound());
+      sb.append(getValAsString(getLowerBound()));
       sb.append("..");
-      sb.append(getUpperBound());
+      sb.append(getValAsString(getUpperBound()));
       if (getUpperBoundType() == INCLUSIVE) {
         sb.append("]");
       } else {
@@ -613,6 +713,13 @@ public class Boundary implements Comparable<Boundary> {
     return sb.toString();
   }
 
+  private String getValAsString(double value) {
+    if (isIntegerValue()) {
+      return String.valueOf((new Double(value)).intValue());
+    }
+    return String.valueOf((new Double(value)));
+  }
+
   @Override
   public int compareTo(Boundary o) {
     if (o == null) {
@@ -626,6 +733,12 @@ public class Boundary implements Comparable<Boundary> {
           } else {
             return upperBoundType == EXCLUSIVE ? -1 : 1;
           }
+        } else {
+          if (this.upperBound == Double.MAX_VALUE) {
+            return -1;
+          } else if (o.upperBound == Double.MAX_VALUE) {
+            return 1;
+          }
         }
         return Double.compare(this.upperBound, o.upperBound);
       } else {
@@ -634,6 +747,8 @@ public class Boundary implements Comparable<Boundary> {
     }
     if (this.lowerBound == Double.MIN_VALUE) {
       return -1;
+    } else if (o.lowerBound == Double.MIN_VALUE) {
+      return 1;
     } else {
       return Double.compare(this.lowerBound, o.lowerBound);
     }
@@ -665,6 +780,15 @@ public class Boundary implements Comparable<Boundary> {
       return this;
     }
 
+    public Builder isInteger() {
+      return isInteger(true);
+    }
+
+    public Builder isInteger(boolean val) {
+      value.setIntegerValue(val);
+      return this;
+    }
+
     @Override
     protected void validate() {
       if (value.lowerBound == Double.MIN_VALUE) {
@@ -681,6 +805,19 @@ public class Boundary implements Comparable<Boundary> {
                 "Lower bound %f is greater than upper bound %f.",
                 value.lowerBound, value.upperBound));
       }
+      // if boundary values are declared as integer, than there should be no not int bounds
+      if (value.isIntegerValue()) {
+        if (value.lowerBound != Double.MIN_VALUE
+            && value.lowerBound != Math.floor(value.lowerBound)) {
+          throw new IllegalArgumentException(
+              String.format("Lower bound %f is no integer/long value.", value.lowerBound));
+        }
+        if (value.upperBound != Double.MAX_VALUE
+            && value.upperBound != Math.floor(value.upperBound)) {
+          throw new IllegalArgumentException(
+              String.format("Upper bound %f is no integer/long value.", value.upperBound));
+        }
+      }
     }
   }
 }
diff --git a/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/helper/DataType.java b/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/helper/DataType.java
index d88ec668c6c0b954872b89cde88a9ac9d80174a1..bbeb1c014e8b3d581abb58574d012fd9c4aab3d5 100644
--- a/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/helper/DataType.java
+++ b/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/helper/DataType.java
@@ -1,18 +1,33 @@
 package de.unikoblenz.fgbks.dmn.core.verifier.helper;
 
+import org.camunda.bpm.dmn.engine.impl.DmnExpressionImpl;
+
 public enum DataType {
-  NUMBER,
-  BOOLEAN,
-  STRING,
-  DATE,
-  UNKNOWN;
+  FLOATING(true),
+  INTEGER(true),
+  BOOLEAN(false),
+  STRING(false),
+  DATE(false),
+  UNKNOWN(false);
+
+  private boolean numeric = false;
+
+  private DataType(boolean numeric) {
+    this.numeric = numeric;
+  }
+
+  public boolean isNumeric() {
+    return numeric;
+  }
 
   public static DataType getTypeFromString(String type) {
     switch (type) {
       case "integer":
       case "long":
+        return DataType.INTEGER;
       case "double":
-        return DataType.NUMBER;
+      case "float":
+        return DataType.FLOATING;
       case "string":
         return DataType.STRING;
         // case "date":
@@ -24,4 +39,25 @@ public enum DataType {
         return DataType.UNKNOWN;
     }
   }
+
+  public Boundary getBoundaryValue(DmnExpressionImpl value) {
+    if (value.getExpression() == null) {
+      return Boundary.parseBoundaryFromNullValue();
+    }
+    switch (this) {
+      case INTEGER:
+        return Boundary.parseFromNumericValue(value.getExpression(), true);
+      case FLOATING:
+        return Boundary.parseFromNumericValue(value.getExpression());
+      case BOOLEAN:
+        return Boundary.parseFromBooleanValue(Boolean.valueOf(value.getExpression()));
+      case STRING:
+        return Boundary.parseFromStringValue(value.getExpression());
+      case DATE: // not implemented yet
+      case UNKNOWN: // not implemented yet
+      default:
+        throw new IllegalStateException(
+            String.format("Parsing boundary of value %s failed.", value.getExpression()));
+    }
+  }
 }
diff --git a/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/helper/RuleMap.java b/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/helper/RuleMap.java
index fab7017f5aebc1a952d11df50827a98473b19b3d..2e59a6b53df7d3b9ea7dd6adf260a3549ec9b340 100644
--- a/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/helper/RuleMap.java
+++ b/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/helper/RuleMap.java
@@ -25,13 +25,17 @@ public class RuleMap {
   private static final Logger LOGGER = Logger.getLogger(RuleMap.class.getSimpleName());
   private List<DmnDecision> dmnDecisions;
   private Map<InputType, List<Value>> inputs;
+  private List<InputType> inputColumns;
   private Map<OutputType, List<Value>> outputs;
+  private List<OutputType> outputColumns;
   private Set<String> dmnDecisionsKeys;
 
   private RuleMap(List<DmnDecision> dmnDecisions) {
     this.dmnDecisions = new ArrayList<>(dmnDecisions);
     this.inputs = new HashMap<>();
+    this.inputColumns = new ArrayList<>();
     this.outputs = new HashMap<>();
+    this.outputColumns = new ArrayList<>();
     this.dmnDecisionsKeys = new HashSet<>();
   }
 
@@ -51,6 +55,7 @@ public class RuleMap {
         int i = 0;
         for (DmnDecisionTableInputImpl tableInput : table.getInputs()) {
           InputType it = new InputType(d, tableInput);
+          ruleMap.inputColumns.add(it);
           ruleMap.inputs.put(it, new ArrayList<>());
           List<Value> inList = ruleMap.inputs.get(it);
           int r = 0;
@@ -64,6 +69,7 @@ public class RuleMap {
         i = 0;
         for (DmnDecisionTableOutputImpl tableOutput : table.getOutputs()) {
           OutputType ot = new OutputType(d, tableOutput);
+          ruleMap.outputColumns.add(ot);
           ruleMap.outputs.put(ot, new ArrayList<>());
           List<Value> outList = ruleMap.outputs.get(ot);
           int r = 0;
@@ -191,41 +197,39 @@ public class RuleMap {
   }
 
   /**
-   * Return a Set of input types, witch belongs to a given decisionKey
+   * Return a list of input types, which belongs to a given decisionKey
    *
    * @param decisionKey the decisionKey
-   * @return a set of Input types
+   * @return a list of Input types
    */
-  public Set<Type> getAllInputTypesFromDecisionKey(String decisionKey) {
-    return inputs
-        .keySet()
+  public List<Type> getAllInputTypesFromDecisionKey(String decisionKey) {
+    return inputColumns
         .stream()
         .filter(i -> i.getDecisionKey().equals(Objects.requireNonNull(decisionKey)))
-        .collect(Collectors.toSet());
+        .collect(Collectors.toList());
   }
 
   /**
-   * Return a Set of output types, witch belongs to a given decisionKey
+   * Return a list of output types, which belongs to a given decisionKey
    *
    * @param decisionKey the decisionKey
-   * @return a set of Output types
+   * @return a list of Output types
    */
-  public Set<Type> getAllOutputTypesFromDecisionKey(String decisionKey) {
-    return outputs
-        .keySet()
+  public List<Type> getAllOutputTypesFromDecisionKey(String decisionKey) {
+    return outputColumns
         .stream()
         .filter(i -> i.getDecisionKey().equals(decisionKey))
-        .collect(Collectors.toSet());
+        .collect(Collectors.toList());
   }
 
   /**
-   * Return a Set of input and output types, witch belongs to a given decisionKey
+   * Return a Set of input and output types, which belongs to a given decisionKey
    *
    * @param decisionKey the decisionKey
    * @return a set of output and input types
    */
-  public Set<Type> getAllTypesFromDecisionKey(String decisionKey) {
-    Set<Type> types = getAllInputTypesFromDecisionKey(decisionKey);
+  public List<Type> getAllTypesFromDecisionKey(String decisionKey) {
+    List<Type> types = getAllInputTypesFromDecisionKey(decisionKey);
     types.addAll(getAllOutputTypesFromDecisionKey(decisionKey));
     return types;
   }
@@ -234,9 +238,9 @@ public class RuleMap {
     Set<Set<String>> returnSet = new HashSet<>();
     for (String d1 : dmnDecisionsKeys) {
       Set<String> subset = new HashSet<>();
-      Set<Type> inputsD1 = getAllInputTypesFromDecisionKey(d1);
+      List<Type> inputsD1 = getAllInputTypesFromDecisionKey(d1);
       for (String d2 : dmnDecisionsKeys) {
-        Set<Type> inputsD2 = getAllInputTypesFromDecisionKey(d2);
+        List<Type> inputsD2 = getAllInputTypesFromDecisionKey(d2);
         boolean containsAll = true;
         for (Type i1 : inputsD1) {
           boolean f2 = false;
diff --git a/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/helper/Type.java b/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/helper/Type.java
index 475923744f48295eb5d7dd829df4a15bf9b0156e..0f32a066f4607aeb83e7c6ad795ea12457c0303d 100644
--- a/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/helper/Type.java
+++ b/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/helper/Type.java
@@ -38,7 +38,7 @@ public abstract class Type {
   public Value getValue(
       DmnExpressionImpl value, DmnDecision decision, int rowNumber, String ruleId) {
     return new Value(
-        getBoundaryValue(value),
+        dataType.getBoundaryValue(value),
         value.getExpression(),
         RuleIdentifier.getBuilder()
             .withDecisionName(decision.getName())
@@ -47,28 +47,8 @@ public abstract class Type {
             .withRuleId(ruleId)
             .withConditionId(value.getId())
             .withConditionName(value.getName())
-            .build(), this);
-  }
-
-  private Boundary getBoundaryValue(DmnExpressionImpl value) {
-    if (value.getExpression() == null) {
-      return Boundary.parseBoundaryFromNullValue();
-    }
-    switch (this.dataType) {
-      case NUMBER:
-        return Boundary.parseFromNumericValue(value.getExpression());
-      case BOOLEAN:
-        return Boundary.parseFromBooleanValue(Boolean.valueOf(value.getExpression()));
-      case STRING:
-        return Boundary.parseFromStringValue(value.getExpression());
-      case UNKNOWN:
-      case DATE:
-        throw new IllegalStateException(
-            String.format(
-                "Parsing boundary in table %s failed. Value: %s",
-                decisionKey, value.getExpression()));
-    }
-    return null;
+            .build(),
+        this);
   }
 
   public boolean isEqualExpression(Type type) {
diff --git a/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/helper/Value.java b/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/helper/Value.java
index dd4743fdb9d2b15ea1e51afd479677f6c955c11a..7024772760a93297e283a6ff0cd32ce20911b3af 100644
--- a/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/helper/Value.java
+++ b/dmn-verifier-app/src/main/java/de/unikoblenz/fgbks/dmn/core/verifier/helper/Value.java
@@ -54,6 +54,4 @@ public class Value {
   public String toString() {
     return orgExpression;
   }
-
-
 }
diff --git a/dmn-verifier-app/src/main/resources/sampleDMN.dmn b/dmn-verifier-app/src/main/resources/sampleDMN.dmn
index 9cc3fcae8809648e026c69926ee409b0e9f2d23f..9b2993093bb416eb6668c7d8a5eba0e63db7be80 100644
--- a/dmn-verifier-app/src/main/resources/sampleDMN.dmn
+++ b/dmn-verifier-app/src/main/resources/sampleDMN.dmn
@@ -2,7 +2,7 @@
 <definitions xmlns="http://www.omg.org/spec/DMN/20151101/dmn.xsd" xmlns:biodi="http://bpmn.io/schema/dmn/biodi/1.0" id="Definitions_1kjh9a2" name="DRD" namespace="http://camunda.org/schema/1.0/dmn">
   <decision id="Decision_13nychf" name="Identical">
     <extensionElements>
-      <biodi:bounds x="127" y="130" width="180" height="80" />
+      <biodi:bounds x="87" y="130" width="180" height="80" />
     </extensionElements>
     <decisionTable id="decisionTable_1">
       <input id="input_1">
@@ -32,7 +32,7 @@
           <text>=10</text>
         </inputEntry>
         <inputEntry id="UnaryTests_01s94by">
-          <text>"Anna"</text>
+          <text>"Nicole"</text>
         </inputEntry>
         <outputEntry id="LiteralExpression_06akk3i">
           <text></text>
@@ -75,7 +75,7 @@
   </decision>
   <decision id="Decision_1vo386g" name="Subsumption 1">
     <extensionElements>
-      <biodi:bounds x="341" y="12" width="180" height="80" />
+      <biodi:bounds x="286" y="41" width="180" height="80" />
     </extensionElements>
     <decisionTable id="DecisionTable_0tq1rr0">
       <input id="InputClause_0f5fjmn">
@@ -118,7 +118,7 @@
   </decision>
   <decision id="Decision_19xi89b" name="Subsumption 2">
     <extensionElements>
-      <biodi:bounds x="344" y="129" width="180" height="80" />
+      <biodi:bounds x="284" y="129" width="180" height="80" />
     </extensionElements>
     <decisionTable id="DecisionTable_0p3gy3p">
       <input id="InputClause_095mouf">
@@ -200,7 +200,7 @@
   </decision>
   <decision id="Decision_1883dha" name="Subsumption 3">
     <extensionElements>
-      <biodi:bounds x="345" y="239" width="180" height="80" />
+      <biodi:bounds x="284" y="221" width="180" height="80" />
     </extensionElements>
     <decisionTable id="DecisionTable_07e2svi">
       <input id="InputClause_15byi73">
@@ -249,7 +249,7 @@
   </decision>
   <decision id="Decision_1be8xb9" name="Equivalent">
     <extensionElements>
-      <biodi:bounds x="561" y="131" width="180" height="80" />
+      <biodi:bounds x="482" y="130" width="180" height="80" />
     </extensionElements>
     <decisionTable id="DecisionTable_1xebbjr">
       <input id="InputClause_0628qmg">
@@ -316,7 +316,7 @@
   </decision>
   <decision id="Decision_0daxsth" name="Overlapping 1">
     <extensionElements>
-      <biodi:bounds x="768" y="132" width="180" height="80" />
+      <biodi:bounds x="671" y="129" width="180" height="80" />
     </extensionElements>
     <decisionTable id="DecisionTable_0q2corq">
       <input id="InputClause_0l9m2o0">
@@ -365,7 +365,7 @@
   </decision>
   <decision id="Decision_1iijfl3" name="Overlapping 2">
     <extensionElements>
-      <biodi:bounds x="768" y="227" width="180" height="80" />
+      <biodi:bounds x="672" y="217" width="180" height="80" />
     </extensionElements>
     <decisionTable id="DecisionTable_0400f42">
       <input id="InputClause_0qut3rd">
@@ -412,4 +412,140 @@
       </rule>
     </decisionTable>
   </decision>
+  <decision id="Decision_1fm0nxn" name="Missing">
+    <extensionElements>
+      <biodi:bounds x="861" y="128" width="180" height="80" />
+    </extensionElements>
+    <decisionTable id="DecisionTable_1tqc0kn">
+      <input id="InputClause_14alfam">
+        <inputExpression id="LiteralExpression_0x3uzxr" typeRef="integer" />
+      </input>
+      <output id="OutputClause_0trtb1o" typeRef="string" />
+      <rule id="DecisionRule_0q3it0q">
+        <inputEntry id="UnaryTests_1ymjfs8">
+          <text>&lt;0</text>
+        </inputEntry>
+        <outputEntry id="LiteralExpression_0tko1l8">
+          <text></text>
+        </outputEntry>
+      </rule>
+      <rule id="DecisionRule_1111n0y">
+        <inputEntry id="UnaryTests_1lmu41i">
+          <text>[10..20]</text>
+        </inputEntry>
+        <outputEntry id="LiteralExpression_1mmduh8">
+          <text></text>
+        </outputEntry>
+      </rule>
+      <rule id="DecisionRule_0xq3fwu">
+        <inputEntry id="UnaryTests_10ua1fp">
+          <text>]30..40[</text>
+        </inputEntry>
+        <outputEntry id="LiteralExpression_1gzkysr">
+          <text></text>
+        </outputEntry>
+      </rule>
+      <rule id="DecisionRule_04u8jhd">
+        <inputEntry id="UnaryTests_0lqhve2">
+          <text>&gt;100</text>
+        </inputEntry>
+        <outputEntry id="LiteralExpression_0cyhmak">
+          <text></text>
+        </outputEntry>
+      </rule>
+    </decisionTable>
+  </decision>
+  <decision id="Decision_0m4xor4" name="Partial Reduction">
+    <extensionElements>
+      <biodi:bounds x="1049" y="129" width="180" height="80" />
+    </extensionElements>
+    <decisionTable id="DecisionTable_0vu5ntx">
+      <input id="InputClause_0s7lk3g">
+        <inputExpression id="LiteralExpression_1oyp20m" typeRef="integer" />
+      </input>
+      <input id="InputClause_1h59ox1">
+        <inputExpression id="LiteralExpression_0ukhram" typeRef="integer">
+          <text></text>
+        </inputExpression>
+      </input>
+      <output id="OutputClause_09bwosh" typeRef="string" />
+      <rule id="DecisionRule_1de20wv">
+        <inputEntry id="UnaryTests_1a7rjth">
+          <text>&lt;0</text>
+        </inputEntry>
+        <inputEntry id="UnaryTests_0ebttad">
+          <text></text>
+        </inputEntry>
+        <outputEntry id="LiteralExpression_1wxutjs">
+          <text>"a"</text>
+        </outputEntry>
+      </rule>
+      <rule id="DecisionRule_0w7ah79">
+        <inputEntry id="UnaryTests_0qnlz66">
+          <text>&gt;=0</text>
+        </inputEntry>
+        <inputEntry id="UnaryTests_04m969i">
+          <text></text>
+        </inputEntry>
+        <outputEntry id="LiteralExpression_0vta1px">
+          <text>"a"</text>
+        </outputEntry>
+      </rule>
+      <rule id="DecisionRule_0umjei3">
+        <inputEntry id="UnaryTests_1meeo0u">
+          <text>[10..20[</text>
+        </inputEntry>
+        <inputEntry id="UnaryTests_1x99g0s">
+          <text></text>
+        </inputEntry>
+        <outputEntry id="LiteralExpression_1wp9w6k">
+          <text>"b"</text>
+        </outputEntry>
+      </rule>
+      <rule id="DecisionRule_1imlwrg">
+        <inputEntry id="UnaryTests_07tm2f5">
+          <text>[20..30]</text>
+        </inputEntry>
+        <inputEntry id="UnaryTests_14aedcb">
+          <text></text>
+        </inputEntry>
+        <outputEntry id="LiteralExpression_1ye3xxm">
+          <text>"b"</text>
+        </outputEntry>
+      </rule>
+      <rule id="DecisionRule_1js6kse">
+        <inputEntry id="UnaryTests_15t1l7k">
+          <text>[0..10]</text>
+        </inputEntry>
+        <inputEntry id="UnaryTests_15mk7ui">
+          <text>=10</text>
+        </inputEntry>
+        <outputEntry id="LiteralExpression_1uda4py">
+          <text>"c"</text>
+        </outputEntry>
+      </rule>
+      <rule id="DecisionRule_1284m78">
+        <inputEntry id="UnaryTests_065f45f">
+          <text>&gt;10</text>
+        </inputEntry>
+        <inputEntry id="UnaryTests_0tfuv1t">
+          <text>=20</text>
+        </inputEntry>
+        <outputEntry id="LiteralExpression_16tu1vb">
+          <text>"c"</text>
+        </outputEntry>
+      </rule>
+      <rule id="DecisionRule_1magf9v">
+        <inputEntry id="UnaryTests_0io8iob">
+          <text>]10..20]</text>
+        </inputEntry>
+        <inputEntry id="UnaryTests_1l9a1l7">
+          <text>=10</text>
+        </inputEntry>
+        <outputEntry id="LiteralExpression_0to63dq">
+          <text>"c"</text>
+        </outputEntry>
+      </rule>
+    </decisionTable>
+  </decision>
 </definitions>
diff --git a/dmn-verifier-app/src/test/java/de/unikoblenz/fgbks/dmn/core/verifier/helper/BoundaryTest.java b/dmn-verifier-app/src/test/java/de/unikoblenz/fgbks/dmn/core/verifier/helper/BoundaryTest.java
index 432e08cc8f25ed8851a3bfba6f683e24d4da21ed..473266cf89a3b49c3f6b27501d30b0c2007ff969 100644
--- a/dmn-verifier-app/src/test/java/de/unikoblenz/fgbks/dmn/core/verifier/helper/BoundaryTest.java
+++ b/dmn-verifier-app/src/test/java/de/unikoblenz/fgbks/dmn/core/verifier/helper/BoundaryTest.java
@@ -236,6 +236,20 @@ class BoundaryTest {
     b2 = Boundary.parseBoundaryFromNullValue();
     assertFalse(b1.isNotInContact(b2));
     assertFalse(b2.isNotInContact(b1));
+
+    b1 = Boundary.parseFromNumericValue("<=0", true);
+    b2 = Boundary.parseFromNumericValue(">=0", true);
+    assertTrue(b1.isInContact(b2));
+    assertTrue(b2.isInContact(b1));
+    assertFalse(b1.isNotInContact(b2));
+    assertFalse(b2.isNotInContact(b1));
+
+    b1 = Boundary.parseFromNumericValue("<0", true);
+    b2 = Boundary.parseFromNumericValue(">0", true);
+    assertFalse(b1.isInContact(b2));
+    assertFalse(b2.isInContact(b1));
+    assertTrue(b1.isNotInContact(b2));
+    assertTrue(b2.isNotInContact(b1));
   }
 
   @Test
@@ -622,37 +636,94 @@ class BoundaryTest {
     Boundary b1 = Boundary.parseFromNumericValue("=10");
     Boundary b2 = Boundary.parseFromNumericValue("<10");
     Boundary b3 = Boundary.parseFromNumericValue("<=10");
-    assertEquals(b3, b1.combineWith(b2).get());
-    assertEquals(b3, b2.combineWith(b1).get());
+    assertEquals(b3, b1.appendWith(b2).get());
+    assertEquals(b3, b2.appendWith(b1).get());
 
     b1 = Boundary.parseFromNumericValue("=10");
     b2 = Boundary.parseFromNumericValue(">10");
     b3 = Boundary.parseFromNumericValue(">=10");
-    assertEquals(b3, b1.combineWith(b2).get());
-    assertEquals(b3, b2.combineWith(b1).get());
+    assertEquals(b3, b1.appendWith(b2).get());
+    assertEquals(b3, b2.appendWith(b1).get());
 
     b1 = Boundary.parseFromNumericValue("[0..10]");
     b2 = Boundary.parseFromNumericValue(">10");
     b3 = Boundary.parseFromNumericValue(">=0");
-    assertEquals(b3, b1.combineWith(b2).get());
-    assertEquals(b3, b2.combineWith(b1).get());
+    assertEquals(b3, b1.appendWith(b2).get());
+    assertEquals(b3, b2.appendWith(b1).get());
 
     b1 = Boundary.parseFromNumericValue("[0..10]");
     b2 = Boundary.parseFromNumericValue("<0");
     b3 = Boundary.parseFromNumericValue("<=10");
-    assertEquals(b3, b1.combineWith(b2).get());
-    assertEquals(b3, b2.combineWith(b1).get());
+    assertEquals(b3, b1.appendWith(b2).get());
+    assertEquals(b3, b2.appendWith(b1).get());
 
     b1 = Boundary.parseFromNumericValue("]0..10[");
     b2 = Boundary.parseFromNumericValue(">=10");
     b3 = Boundary.parseFromNumericValue(">0");
-    assertEquals(b3, b1.combineWith(b2).get());
-    assertEquals(b3, b2.combineWith(b1).get());
+    assertEquals(b3, b1.appendWith(b2).get());
+    assertEquals(b3, b2.appendWith(b1).get());
 
     b1 = Boundary.parseFromNumericValue("[0..10[");
     b2 = Boundary.parseFromNumericValue("<0");
     b3 = Boundary.parseFromNumericValue("<10");
-    assertEquals(b3, b1.combineWith(b2).get());
-    assertEquals(b3, b2.combineWith(b1).get());
+    assertEquals(b3, b1.appendWith(b2).get());
+    assertEquals(b3, b2.appendWith(b1).get());
+  }
+
+  @Test
+  void testIntegerVals() {
+    Boundary b1 = Boundary.parseFromNumericValue("<0", true);
+    Boundary b2 = Boundary.parseFromNumericValue("[5..10[", true);
+    Boundary b3 = Boundary.parseFromNumericValue(">10", true);
+
+    Boundary betw = Boundary.parseFromNumericValue("[0..5[", true);
+    assertEquals(betw, b1.getNewBoundaryBetween(b2).get());
+    assertEquals(betw, b2.getNewBoundaryBetween(b1).get());
+
+    b1 = Boundary.parseFromNumericValue("]10..20]", true);
+    b2 = Boundary.parseFromNumericValue("[5..10[", true);
+    betw = Boundary.parseFromNumericValue("=10", true);
+    assertEquals(betw, b1.getNewBoundaryBetween(b2).get());
+    assertEquals(betw, b2.getNewBoundaryBetween(b1).get());
+
+    b1 = Boundary.parseFromNumericValue(">100", true);
+    b2 = Boundary.parseFromNumericValue("[0..99[", true);
+    betw = Boundary.parseFromNumericValue("[99..100]", true);
+    assertEquals(betw, b1.getNewBoundaryBetween(b2).get());
+    assertEquals(betw, b2.getNewBoundaryBetween(b1).get());
+
+    b1 = Boundary.parseFromNumericValue(">=100", true);
+    b2 = Boundary.parseFromNumericValue("[0..99]", true);
+    assertFalse(b1.getNewBoundaryBetween(b2).isPresent());
+    assertFalse(b2.getNewBoundaryBetween(b1).isPresent());
+
+    b1 = Boundary.parseFromNumericValue("[0..5[", true);
+    b2 = Boundary.parseFromNumericValue("[5..10[", true);
+    assertFalse(b1.getNewBoundaryBetween(b2).isPresent());
+    assertFalse(b2.getNewBoundaryBetween(b1).isPresent());
+
+    b1 = Boundary.parseFromNumericValue("=10", true);
+    b2 = Boundary.parseFromNumericValue("=11", true);
+    Boundary comb = Boundary.parseFromNumericValue("[10..11]", true);
+    assertEquals(comb, b1.appendWith(b2).get());
+    assertEquals(comb, b2.appendWith(b1).get());
+
+    b1 = Boundary.parseFromNumericValue("[0..10]", true);
+    b2 = Boundary.parseFromNumericValue("=11", true);
+    comb = Boundary.parseFromNumericValue("[0..11]", true);
+    assertEquals(comb, b1.appendWith(b2).get());
+    assertEquals(comb, b2.appendWith(b1).get());
+
+    b1 = Boundary.parseFromNumericValue("=10", true);
+    b2 = Boundary.parseFromNumericValue("[11..20]", true);
+    comb = Boundary.parseFromNumericValue("[10..20]", true);
+    assertEquals(comb, b1.appendWith(b2).get());
+    assertEquals(comb, b2.appendWith(b1).get());
+
+    b1 = Boundary.parseFromNumericValue("=10", true);
+    b2 = Boundary.parseFromNumericValue("]10..20]", true);
+    comb = Boundary.parseFromNumericValue("[10..20]", true);
+    assertEquals(comb, b1.appendWith(b2).get());
+    assertEquals(comb, b2.appendWith(b1).get());
   }
 }