Navigation Menu

Skip to content

Commit

Permalink
CspListener is now a function and can be implemented with lambda expr…
Browse files Browse the repository at this point in the history
…essions.
  • Loading branch information
RuedigerLunde committed May 18, 2017
1 parent 39ba97c commit 7323532
Show file tree
Hide file tree
Showing 11 changed files with 108 additions and 179 deletions.
Expand Up @@ -60,11 +60,11 @@ private Assignment<VAR, VAL> recursiveBackTrackingSearch(CSP<VAR, VAL> csp, Assi
VAR var = selectUnassignedVariable(assignment, csp); VAR var = selectUnassignedVariable(assignment, csp);
for (VAL value : orderDomainValues(var, assignment, csp)) { for (VAL value : orderDomainValues(var, assignment, csp)) {
assignment.add(var, value); assignment.add(var, value);
fireStateChanged(assignment, csp); fireStateChanged(csp, assignment);
if (assignment.isConsistent(csp.getConstraints(var))) { if (assignment.isConsistent(csp.getConstraints(var))) {
InferenceLog<VAR, VAL> log = inference(var, assignment, csp); InferenceLog<VAR, VAL> log = inference(var, assignment, csp);
if (!log.isEmpty()) if (!log.isEmpty())
fireStateChanged(csp); fireStateChanged(csp, null);
if (!log.inconsistencyFound()) { if (!log.inconsistencyFound()) {
result = recursiveBackTrackingSearch(csp, assignment); result = recursiveBackTrackingSearch(csp, assignment);
if (result != null) if (result != null)
Expand Down
49 changes: 42 additions & 7 deletions aima-core/src/main/java/aima/core/search/csp/CspListener.java
@@ -1,15 +1,50 @@
package aima.core.search.csp; package aima.core.search.csp;


import aima.core.search.framework.Metrics;

/** /**
* Interface which allows interested clients to register at a solution strategy * Interface which allows interested clients to register at a CSP solver
* and follow their progress step by step. * and follow its progress step by step.
* *
* @author Ruediger Lunde * @author Ruediger Lunde
*/ */
public interface CspListener<VAR extends Variable, VAL> { public interface CspListener<VAR extends Variable, VAL> {
/** Informs about changed assignments. */ /**
void stateChanged(Assignment<VAR, VAL> assignment, CSP<VAR, VAL> csp); * Informs about changed assignments.
*
* @param csp a CSP, possibly changed by an inference step.
* @param assignment a new assignment or null if the last processing step was an inference step.
*/
void stateChanged(CSP<VAR, VAL> csp, Assignment<VAR, VAL> assignment);

/**
* A simple CSP listener implementation which counts assignment changes and changes caused by
* inference steps and provides some metrics.
* @author Ruediger Lunde
*/
class StepCounter<VAR extends Variable, VAL> implements CspListener<VAR, VAL> {
private int assignmentCount = 0;
private int inferenceCount = 0;

@Override
public void stateChanged(CSP<VAR, VAL> csp, Assignment<VAR, VAL> assignment) {
if (assignment != null)
++assignmentCount;
else
++inferenceCount;
}

public void reset() {
assignmentCount = 0;
inferenceCount = 0;
}


/** Informs about changed domains (inferences). */ public Metrics getResults() {
void stateChanged(CSP<VAR, VAL> csp); Metrics result = new Metrics();
result.set("assignmentCount", assignmentCount);
if (inferenceCount != 0)
result.set("inferenceCount", inferenceCount);
return result;
}
}
} }
72 changes: 32 additions & 40 deletions aima-core/src/main/java/aima/core/search/csp/CspSolver.java
Expand Up @@ -8,53 +8,45 @@
* assignment, which is consistent and complete with respect to a CSP. This * assignment, which is consistent and complete with respect to a CSP. This
* abstract class provides the central interface method and additionally an * abstract class provides the central interface method and additionally an
* implementation of an observer mechanism. * implementation of an observer mechanism.
* *
* @author Ruediger Lunde * @author Ruediger Lunde
* @author Mike Stampone * @author Mike Stampone
*/ */
public abstract class CspSolver<VAR extends Variable, VAL> { public abstract class CspSolver<VAR extends Variable, VAL> {
private List<CspListener<VAR, VAL>> listeners = new ArrayList<>(); private List<CspListener<VAR, VAL>> listeners = new ArrayList<>();


/** /**
* Adds a CSP state listener to the solution strategy. * Adds a CSP listener to the solution strategy.
* *
* @param listener * @param listener a listener which follows the progress of the solution strategy
* a listener which follows the progress of the solution strategy * step-by-step.
* step-by-step. */
*/ public void addCspListener(CspListener<VAR, VAL> listener) {
public void addCspStateListener(CspListener<VAR, VAL> listener) { listeners.add(listener);
listeners.add(listener); }
}


/** /**
* Removes a CSP listener from the solution strategy. * Removes a CSP listener from the solution strategy.
* *
* @param listener * @param listener the listener to remove
* the listener to remove */
*/ public void removeCspListener(CspListener<VAR, VAL> listener) {
public void removeCspStateListener(CspListener<VAR, VAL> listener) { listeners.remove(listener);
listeners.remove(listener); }
}


protected void fireStateChanged(CSP<VAR, VAL> csp) {
for (CspListener<VAR, VAL> listener : listeners)
listener.stateChanged(csp.copyDomains());
}


protected void fireStateChanged(Assignment<VAR, VAL> assignment, CSP<VAR, VAL> csp) { /** Informs all registered listeners about a state change. */
for (CspListener<VAR, VAL> listener : listeners) protected void fireStateChanged(CSP<VAR, VAL> csp, Assignment<VAR, VAL> assignment) {
listener.stateChanged(assignment.copy(), csp.copyDomains()); for (CspListener<VAR, VAL> listener : listeners)
} listener.stateChanged(csp.copyDomains(), assignment != null ? assignment.copy() : null);
}


/** /**
* Returns a solution to the specified CSP, which specifies values for all * Computes a solution to the specified CSP, which specifies values for all
* the variables such that the constraints are satisfied. * variables of the given CSP such that all constraints are satisfied.
* *
* @param csp * @param csp a CSP to be solved.
* a CSP to solve * @return the computed solution or null if no solution was found.
* */
* @return a solution to the specified CSP, which specifies values for all public abstract Assignment<VAR, VAL> solve(CSP<VAR, VAL> csp);
* the variables such that the constraints are satisfied.
*/
public abstract Assignment<VAR, VAL> solve(CSP<VAR, VAL> csp);
} }
Expand Up @@ -59,7 +59,7 @@ public Assignment<VAR, VAL> solve(CSP<VAR, VAL> csp) {
csp = csp.copyDomains(); // do not change the original CSP! csp = csp.copyDomains(); // do not change the original CSP!
InferenceLog log = inferenceStrategy.apply(csp); InferenceLog log = inferenceStrategy.apply(csp);
if (!log.isEmpty()) { if (!log.isEmpty()) {
fireStateChanged(csp); fireStateChanged(csp, null);
if (log.inconsistencyFound()) if (log.inconsistencyFound())
return null; return null;
} }
Expand Down
Expand Up @@ -50,7 +50,7 @@ public MinConflictsSolver(int maxSteps) {


public Assignment<VAR, VAL> solve(CSP<VAR, VAL> csp) { public Assignment<VAR, VAL> solve(CSP<VAR, VAL> csp) {
Assignment<VAR, VAL> assignment = generateRandomAssignment(csp); Assignment<VAR, VAL> assignment = generateRandomAssignment(csp);
fireStateChanged(assignment, csp); fireStateChanged(csp, assignment);
for (int i = 0; i < maxSteps && !CancelableThread.currIsCanceled(); i++) { for (int i = 0; i < maxSteps && !CancelableThread.currIsCanceled(); i++) {
if (assignment.isSolution(csp)) { if (assignment.isSolution(csp)) {
return assignment; return assignment;
Expand All @@ -59,7 +59,7 @@ public Assignment<VAR, VAL> solve(CSP<VAR, VAL> csp) {
VAR var = Util.selectRandomlyFromList(vars); VAR var = Util.selectRandomlyFromList(vars);
VAL value = getMinConflictValueFor(var, assignment, csp); VAL value = getMinConflictValueFor(var, assignment, csp);
assignment.add(var, value); assignment.add(var, value);
fireStateChanged(assignment, csp); fireStateChanged(csp, assignment);
} }
} }
return null; return null;
Expand Down
Expand Up @@ -13,57 +13,28 @@
public class MapColoringCspDemo { public class MapColoringCspDemo {
public static void main(String[] args) { public static void main(String[] args) {
CSP<Variable, String> csp = new MapCSP(); CSP<Variable, String> csp = new MapCSP();
StepCounter stepCounter = new StepCounter(); CspListener.StepCounter<Variable, String> stepCounter = new CspListener.StepCounter<>();
CspSolver<Variable, String> solver; CspSolver<Variable, String> solver;


solver = new MinConflictsSolver<>(1000); solver = new MinConflictsSolver<>(1000);
solver.addCspStateListener(stepCounter); solver.addCspListener(stepCounter);
stepCounter.reset(); stepCounter.reset();
System.out.println("Map Coloring (Minimum Conflicts)"); System.out.println("Map Coloring (Minimum Conflicts)");
System.out.println(solver.solve(csp)); System.out.println(solver.solve(csp));
System.out.println(stepCounter.getResults() + "\n"); System.out.println(stepCounter.getResults() + "\n");


solver = new FlexibleBacktrackingSolver<Variable, String>().setAll(); solver = new FlexibleBacktrackingSolver<Variable, String>().setAll();
solver.addCspStateListener(stepCounter); solver.addCspListener(stepCounter);
stepCounter.reset(); stepCounter.reset();
System.out.println("Map Coloring (Backtracking + MRV & DEG + LCV + AC3)"); System.out.println("Map Coloring (Backtracking + MRV & DEG + LCV + AC3)");
System.out.println(solver.solve(csp)); System.out.println(solver.solve(csp));
System.out.println(stepCounter.getResults() + "\n"); System.out.println(stepCounter.getResults() + "\n");


solver = new FlexibleBacktrackingSolver<>(); solver = new FlexibleBacktrackingSolver<>();
solver.addCspStateListener(stepCounter); solver.addCspListener(stepCounter);
stepCounter.reset(); stepCounter.reset();
System.out.println("Map Coloring (Backtracking)"); System.out.println("Map Coloring (Backtracking)");
System.out.println(solver.solve(csp)); System.out.println(solver.solve(csp));
System.out.println(stepCounter.getResults() + "\n"); System.out.println(stepCounter.getResults() + "\n");
} }

/** Counts assignment and domain changes during CSP solving. */
protected static class StepCounter implements CspListener<Variable, String> {
private int assignmentCount = 0;
private int domainCount = 0;

@Override
public void stateChanged(Assignment<Variable, String> assignment, CSP<Variable, String> csp) {
++assignmentCount;
}

@Override
public void stateChanged(CSP<Variable, String> csp) {
++domainCount;
}

public void reset() {
assignmentCount = 0;
domainCount = 0;
}

public String getResults() {
StringBuilder result = new StringBuilder();
result.append("assignment changes: ").append(assignmentCount);
if (domainCount != 0)
result.append(", domain changes: ").append(domainCount);
return result.toString();
}
}
} }
Expand Up @@ -150,19 +150,9 @@ public void initialize() {
break; break;
} }


strategy.addCspStateListener(new CspListener<Variable, String>() { strategy.addCspListener((csp1, assignment) -> {

stepCounter++;
@Override updateStateView(csp1, assignment);
public void stateChanged(Assignment<Variable, String> assignment, CSP<Variable, String> csp) {
stepCounter++;
updateStateView(csp, assignment);
}

@Override
public void stateChanged(CSP<Variable, String> csp) {
stepCounter++;
updateStateView(csp, null);
}
}); });


stateViewCtrl.initialize(csp); stateViewCtrl.initialize(csp);
Expand Down
Expand Up @@ -8,7 +8,6 @@
import aima.core.search.csp.examples.NQueensCSP; import aima.core.search.csp.examples.NQueensCSP;
import aima.core.search.csp.inference.AC3Strategy; import aima.core.search.csp.inference.AC3Strategy;
import aima.core.search.csp.inference.ForwardCheckingStrategy; import aima.core.search.csp.inference.ForwardCheckingStrategy;
import aima.core.search.framework.Metrics;
import aima.core.util.datastructure.XYLocation; import aima.core.util.datastructure.XYLocation;
import aima.gui.fx.framework.IntegrableApplication; import aima.gui.fx.framework.IntegrableApplication;
import aima.gui.fx.framework.Parameter; import aima.gui.fx.framework.Parameter;
Expand All @@ -32,18 +31,18 @@ public static void main(String[] args) {
launch(args); launch(args);
} }


public final static String PARAM_STRATEGY = "strategy"; private final static String PARAM_STRATEGY = "strategy";
public final static String PARAM_VAR_SELECT = "varSelect"; private final static String PARAM_VAR_SELECT = "varSelect";
public final static String PARAM_VAL_SELECT = "valOrder"; private final static String PARAM_VAL_SELECT = "valOrder";
public final static String PARAM_INFERENCE = "inference"; private final static String PARAM_INFERENCE = "inference";


public final static String PARAM_BOARD_SIZE = "boardSize"; private final static String PARAM_BOARD_SIZE = "boardSize";


private NQueensViewCtrl stateViewCtrl; private NQueensViewCtrl stateViewCtrl;
private SimulationPaneCtrl simPaneCtrl; private SimulationPaneCtrl simPaneCtrl;
private CSP<Variable, Integer> csp; private CSP<Variable, Integer> csp;
private CspSolver<Variable, Integer> solver; private CspSolver<Variable, Integer> solver;
private ProgressAnalyzer progressAnalyzer = new ProgressAnalyzer(); private CspListener.StepCounter<Variable, Integer> stepCounter = new CspListener.StepCounter();


@Override @Override
public String getTitle() { public String getTitle() {
Expand Down Expand Up @@ -113,8 +112,9 @@ public void initialize() {
solver = new MinConflictsSolver<>(1000); solver = new MinConflictsSolver<>(1000);


} }
solver.addCspStateListener(progressAnalyzer); solver.addCspListener(stepCounter);
progressAnalyzer.reset(); solver.addCspListener((csp, assign) -> { if (assign != null) updateStateView(getBoard(assign));});
stepCounter.reset();
stateViewCtrl.update(new NQueensBoard(csp.getVariables().size())); stateViewCtrl.update(new NQueensBoard(csp.getVariables().size()));
simPaneCtrl.setStatus(""); simPaneCtrl.setStatus("");
} }
Expand All @@ -133,7 +133,6 @@ public void simulate() {
NQueensBoard board = getBoard(solution); NQueensBoard board = getBoard(solution);
stateViewCtrl.update(board); stateViewCtrl.update(board);
} }
simPaneCtrl.setStatus(progressAnalyzer.getResults().toString());
} }


private NQueensBoard getBoard(Assignment<Variable, Integer> assignment) { private NQueensBoard getBoard(Assignment<Variable, Integer> assignment) {
Expand All @@ -151,36 +150,8 @@ private NQueensBoard getBoard(Assignment<Variable, Integer> assignment) {
* the GUI have to be done in the GUI thread! * the GUI have to be done in the GUI thread!
*/ */
private void updateStateView(NQueensBoard board) { private void updateStateView(NQueensBoard board) {
Platform.runLater(() -> stateViewCtrl.update(board)); Platform.runLater(() -> {
stateViewCtrl.update(board); simPaneCtrl.setStatus(stepCounter.getResults().toString()); });
simPaneCtrl.waitAfterStep(); simPaneCtrl.waitAfterStep();
} }

protected class ProgressAnalyzer implements CspListener<Variable, Integer> {
private int assignmentCount = 0;
private int domainCount = 0;

@Override
public void stateChanged(Assignment<Variable, Integer> assignment, CSP<Variable, Integer> csp) {
updateStateView(getBoard(assignment));
++assignmentCount;
}

@Override
public void stateChanged(CSP<Variable, Integer> csp) {
++domainCount;
}

public void reset() {
assignmentCount = 0;
domainCount = 0;
}

public Metrics getResults() {
Metrics result = new Metrics();
result.set("assignmentChanges", assignmentCount);
if (domainCount != 0)
result.set("domainChanges", domainCount);
return result;
}
}
} }

0 comments on commit 7323532

Please sign in to comment.