Finished solver core
git-svn-id: svn://sunsvr01.isp.uni-luebeck.de/swproj13/trunk@428 72836036-5685-4462-b002-a69064685172
This commit is contained in:
parent
d223eaaa98
commit
fc07d3bca6
3 changed files with 106 additions and 25 deletions
|
@ -3,11 +3,13 @@ package jrummikub.ai.fdsolver;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import static jrummikub.ai.fdsolver.Satisfiability.*;
|
||||||
|
|
||||||
public class Solver {
|
public class Solver {
|
||||||
Set<Var<?>> vars = new HashSet<Var<?>>();
|
Set<Var<?>> vars = new HashSet<Var<?>>();
|
||||||
|
@ -26,6 +28,7 @@ public class Solver {
|
||||||
Map<Var<?>, HashSet<?>> invalidatedValues = new HashMap<Var<?>, HashSet<?>>();
|
Map<Var<?>, HashSet<?>> invalidatedValues = new HashMap<Var<?>, HashSet<?>>();
|
||||||
Var<?> branchVar;
|
Var<?> branchVar;
|
||||||
Object branchValue;
|
Object branchValue;
|
||||||
|
HashSet<Constraint> finishedConstraints = new HashSet<Constraint>();
|
||||||
|
|
||||||
public <T> void invalidate(Var<T> var, T invalid) {
|
public <T> void invalidate(Var<T> var, T invalid) {
|
||||||
HashSet<T> values = (HashSet<T>) invalidatedValues.get(var);
|
HashSet<T> values = (HashSet<T>) invalidatedValues.get(var);
|
||||||
|
@ -47,16 +50,19 @@ public class Solver {
|
||||||
stack.add(new StackFrame());
|
stack.add(new StackFrame());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isSolved() {
|
||||||
|
return dirtyVars.isEmpty() && unsolvedVars.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
public boolean solve() {
|
public boolean solve() {
|
||||||
do {
|
do {
|
||||||
solveStep();
|
solveStep();
|
||||||
} while (!(contradiction || (dirtyVars.isEmpty() && unsolvedVars
|
} while (!(contradiction || isSolved()));
|
||||||
.isEmpty())));
|
|
||||||
return !contradiction;
|
return !contradiction;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void solveStep() {
|
public void solveStep() {
|
||||||
if (unsolvedVars.isEmpty() && dirtyVars.isEmpty()) {
|
if (isSolved()) {
|
||||||
contradiction = true;
|
contradiction = true;
|
||||||
} else {
|
} else {
|
||||||
propagateAll();
|
propagateAll();
|
||||||
|
@ -74,17 +80,25 @@ public class Solver {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void propagateOnce() {
|
public void propagateOnce() {
|
||||||
Iterator<Var<?>> it = dirtyVars.iterator();
|
Var<?> dirtyVar = Collections.max(dirtyVars);
|
||||||
Var<?> dirtyVar = it.next();
|
dirtyVars.remove(dirtyVar);
|
||||||
it.remove();
|
outerLoop: for (Iterator<Constraint> i = dirtyVar.getConstraints().iterator(); i.hasNext();) {
|
||||||
outerLoop: for (Constraint constraint : constraints) {
|
Constraint constraint = i.next();
|
||||||
if (constraint.getWatchedVars().contains(dirtyVar)) {
|
Satisfiability sat = constraint.getSatisfiability();
|
||||||
for (Propagator propagator : constraint.getPropagators(false)) {
|
if (sat == UNSAT) {
|
||||||
if (propagator.getWatchedVars().contains(dirtyVar)) {
|
contradiction = true;
|
||||||
propagator.propagate();
|
break;
|
||||||
if (contradiction) {
|
}
|
||||||
break outerLoop;
|
if (sat == TAUT) {
|
||||||
}
|
i.remove();
|
||||||
|
finishedConstraint(constraint, dirtyVar);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (Propagator propagator : constraint.getPropagators(false)) {
|
||||||
|
if (propagator.getWatchedVars().contains(dirtyVar)) {
|
||||||
|
propagator.propagate();
|
||||||
|
if (contradiction) {
|
||||||
|
break outerLoop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,6 +123,7 @@ public class Solver {
|
||||||
|
|
||||||
for (Var<?> var : constraint.getWatchedVars()) {
|
for (Var<?> var : constraint.getWatchedVars()) {
|
||||||
var.makeDirty();
|
var.makeDirty();
|
||||||
|
var.getConstraints().add(constraint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,7 +135,14 @@ public class Solver {
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
void branchOn(Var<?> var) {
|
void branchOn(Var<?> var) {
|
||||||
Object value = var.getRange().iterator().next();
|
|
||||||
|
Set<?> range = var.getRange();
|
||||||
|
int n = (int)(Math.random() * range.size());
|
||||||
|
Iterator<?> it = range.iterator();
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
it.next();
|
||||||
|
}
|
||||||
|
Object value = it.next();
|
||||||
branchWith((Var<Object>) var, value);
|
branchWith((Var<Object>) var, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,6 +165,16 @@ public class Solver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void finishedConstraint(Constraint constraint, Var<?> currentVar) {
|
||||||
|
for (Var<?> var : constraint.getWatchedVars()) {
|
||||||
|
if (var != currentVar) {
|
||||||
|
var.getConstraints().remove(constraint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
constraints.remove(constraint);
|
||||||
|
getTopStackFrame().finishedConstraints.add(constraint);
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
// This would need rank-2 types which java lacks
|
// This would need rank-2 types which java lacks
|
||||||
private void rollback(StackFrame item) {
|
private void rollback(StackFrame item) {
|
||||||
|
@ -156,6 +188,13 @@ public class Solver {
|
||||||
} else {
|
} else {
|
||||||
unsolvedVars.remove(var);
|
unsolvedVars.remove(var);
|
||||||
}
|
}
|
||||||
|
var.makeDirty(); // TODO think a bit more about this
|
||||||
|
}
|
||||||
|
for (Constraint constraint : item.finishedConstraints) {
|
||||||
|
for (Var<?> var : constraint.getWatchedVars()) {
|
||||||
|
var.getConstraints().add(constraint);
|
||||||
|
}
|
||||||
|
constraints.add(constraint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,4 +231,16 @@ public class Solver {
|
||||||
return makeVar(Arrays.asList(range));
|
return makeVar(Arrays.asList(range));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void record() {
|
||||||
|
for (Var<?> var : vars) {
|
||||||
|
var.record();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void restore() {
|
||||||
|
for (Var<?> var : vars) {
|
||||||
|
var.restore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,13 +4,16 @@ import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
public class Var<T> {
|
public class Var<T> implements Comparable<Var<T>> {
|
||||||
private Solver solver;
|
private Solver solver;
|
||||||
private HashSet<T> range;
|
private HashSet<T> range;
|
||||||
|
private HashSet<Constraint> constraints;
|
||||||
|
private T recorded;
|
||||||
|
|
||||||
public Var(Solver solver, Collection<T> range) {
|
public Var(Solver solver, Collection<T> range) {
|
||||||
this.solver = solver;
|
this.solver = solver;
|
||||||
this.range = new HashSet<T>(range);
|
this.range = new HashSet<T>(range);
|
||||||
|
constraints = new HashSet<Constraint>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public T getValue() {
|
public T getValue() {
|
||||||
|
@ -23,7 +26,7 @@ public class Var<T> {
|
||||||
return range;
|
return range;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void choose(T value) {
|
void choose(T value) {
|
||||||
for (Iterator<T> i = this.iterator(); i.hasNext();) {
|
for (Iterator<T> i = this.iterator(); i.hasNext();) {
|
||||||
if (i.next() != value) {
|
if (i.next() != value) {
|
||||||
i.remove();
|
i.remove();
|
||||||
|
@ -31,16 +34,20 @@ public class Var<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void makeDirty() {
|
void makeDirty() {
|
||||||
this.solver.dirtyVars.add(this);
|
this.solver.dirtyVars.add(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void invalidate(T value) {
|
void invalidate(T value) {
|
||||||
range.remove(value);
|
range.remove(value);
|
||||||
solver.logInvalidation(this, value);
|
solver.logInvalidation(this, value);
|
||||||
makeDirty();
|
makeDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HashSet<Constraint> getConstraints() {
|
||||||
|
return constraints;
|
||||||
|
}
|
||||||
|
|
||||||
public Iterator<T> iterator() {
|
public Iterator<T> iterator() {
|
||||||
final Iterator<T> iterator = range.iterator();
|
final Iterator<T> iterator = range.iterator();
|
||||||
return new Iterator<T>() {
|
return new Iterator<T>() {
|
||||||
|
@ -70,9 +77,34 @@ public class Var<T> {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void record() {
|
||||||
|
recorded = getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
void restore() {
|
||||||
|
range.clear();
|
||||||
|
range.add(recorded);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Var" + range;
|
return "Var" + range;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int neighborCount() {
|
||||||
|
int count = 0;
|
||||||
|
for (Constraint constraint : constraints) {
|
||||||
|
count += constraint.getWatchedVars().size();
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(Var<T> other) {
|
||||||
|
int rangeCompare = ((Integer)range.size()).compareTo(other.range.size());
|
||||||
|
if (rangeCompare != 0)
|
||||||
|
return rangeCompare;
|
||||||
|
return ((Integer)neighborCount()).compareTo(other.neighborCount());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,14 +16,12 @@ public class SolverTest {
|
||||||
|
|
||||||
solver.addConstraint(new LessThan<Integer>(false, y, x));
|
solver.addConstraint(new LessThan<Integer>(false, y, x));
|
||||||
|
|
||||||
int lastx = 0, lasty = 0;
|
|
||||||
while (solver.solve()) {
|
while (solver.solve()) {
|
||||||
lastx = x.getValue();
|
solver.record();
|
||||||
lasty = y.getValue();
|
|
||||||
solver.addConstraint(new LessThanConst<Integer>(false, x, x.getValue()));
|
solver.addConstraint(new LessThanConst<Integer>(false, x, x.getValue()));
|
||||||
}
|
}
|
||||||
|
solver.restore();
|
||||||
assertEquals(2, lastx);
|
assertEquals(2, (int)x.getValue());
|
||||||
assertEquals(1, lasty);
|
assertEquals(1, (int)y.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue