summaryrefslogtreecommitdiffstats
path: root/src/jrummikub/ai/fdsolver/constraint/IndexConstraint.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/jrummikub/ai/fdsolver/constraint/IndexConstraint.java')
-rw-r--r--src/jrummikub/ai/fdsolver/constraint/IndexConstraint.java134
1 files changed, 134 insertions, 0 deletions
diff --git a/src/jrummikub/ai/fdsolver/constraint/IndexConstraint.java b/src/jrummikub/ai/fdsolver/constraint/IndexConstraint.java
new file mode 100644
index 0000000..999924f
--- /dev/null
+++ b/src/jrummikub/ai/fdsolver/constraint/IndexConstraint.java
@@ -0,0 +1,134 @@
+package jrummikub.ai.fdsolver.constraint;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+
+import jrummikub.ai.fdsolver.Constraint;
+import jrummikub.ai.fdsolver.Propagator;
+import jrummikub.ai.fdsolver.Satisfiability;
+import jrummikub.ai.fdsolver.Var;
+
+public class IndexConstraint<T> implements Constraint {
+ Var<T> target;
+ Var<Integer> index;
+ List<Var<T>> list;
+ Collection<Var<?>> vars = new ArrayList<Var<?>>();
+ Collection<Var<?>> varsNoTarget = new ArrayList<Var<?>>();
+ Collection<Var<?>> varsNoIndex = new ArrayList<Var<?>>();
+
+ public IndexConstraint(Var<T> target, Var<Integer> index, List<Var<T>> list) {
+ this.target = target;
+ this.index = index;
+ this.list = list;
+ vars.addAll(list);
+ vars.add(index);
+ vars.add(target);
+ varsNoTarget.addAll(list);
+ varsNoTarget.add(index);
+ varsNoIndex.addAll(list);
+ varsNoIndex.add(target);
+ }
+
+ @Override
+ public Collection<Var<?>> getWatchedVars() {
+ return vars;
+ }
+
+ private class UnionProp implements Propagator {
+ @Override
+ public Collection<Var<?>> getWatchedVars() {
+ return varsNoTarget;
+ }
+
+ @Override
+ public void propagate() {
+ HashSet<T> union = new HashSet<T>();
+ for (int i : index.getRange()) {
+ union.addAll(list.get(i).getRange());
+ }
+ for (Iterator<T> i = target.iterator(); i.hasNext();) {
+ T val = i.next();
+ if (!union.contains(val)) {
+ i.remove();
+ }
+ }
+ };
+ }
+
+ private class IndexProp implements Propagator {
+ @Override
+ public Collection<Var<?>> getWatchedVars() {
+ return varsNoIndex;
+ }
+
+ @Override
+ public void propagate() {
+ for (Iterator<Integer> i = index.iterator(); i.hasNext();) {
+ int id = i.next();
+ HashSet<T> range = new HashSet<T>(target.getRange());
+ range.retainAll(list.get(id).getRange());
+ if (range.isEmpty()) {
+ i.remove();
+ }
+ }
+ }
+ }
+
+ private class VarProp implements Propagator {
+ @Override
+ public Collection<Var<?>> getWatchedVars() {
+ return Arrays.asList(target, index);
+ }
+
+ @Override
+ public void propagate() {
+ if (index.getRange().size() != 1)
+ return;
+ int id = index.getValue();
+ Var<T> var = list.get(id);
+ for(Iterator<T> i = var.iterator(); i.hasNext();) {
+ if (!target.getRange().contains(i.next())) {
+ i.remove();
+ }
+ }
+ }
+
+ }
+
+ @Override
+ public Collection<Propagator> getPropagators(boolean negate) {
+ if (negate) {
+ return Collections.emptyList();
+ }
+ return Arrays.<Propagator> asList(new UnionProp(), new IndexProp(), new VarProp());
+ }
+
+ @Override
+ public Satisfiability getSatisfiability() {
+ HashSet<T> union = new HashSet<T>();
+ for (int i : index.getRange()) {
+ union.addAll(list.get(i).getRange());
+ }
+ boolean isSat = false;
+ for (T val : target.getRange()) {
+ if (union.contains(val)) {
+ isSat = true;
+ break;
+ }
+ }
+ if (!isSat) {
+ return Satisfiability.UNSAT;
+ } else {
+ if (union.size() == 1 && target.getRange().size() == 1) {
+ return Satisfiability.TAUT;
+ } else {
+ return Satisfiability.SAT;
+ }
+ }
+ }
+}