com.github.k0zka.finder4j.backtrack.Backtrack Maven / Gradle / Ivy
package com.github.k0zka.finder4j.backtrack;
import java.util.Deque;
import java.util.Iterator;
import java.util.LinkedList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Backtrack {
static final class BackTrackState> {
private final X state;
private final Iterator steps;
public BackTrackState(final X state, final Iterator steps) {
super();
this.state = state;
this.steps = steps;
}
public X getState() {
return state;
}
public Iterator getSteps() {
return steps;
}
}
private static final Logger logger = LoggerFactory
.getLogger(Backtrack.class);
/**
* Run a backtracking algorithm on a problem
*
* @param state
* @param factory
* @param terminationStrategy
* @param listener
* @param step
*/
public static > void backtrack(
final X state, final StepFactory factory,
final TerminationStrategy terminationStrategy,
final SolutionListener listener) {
backtrack(state, factory, terminationStrategy, listener, null);
}
/**
* Run a backtracking algorithm on a problem
*
* @param state
* @param factory
* @param terminationStrategy
* @param listener
* @param step
* @param parallelTrack
*/
public static > void backtrack(
final X state, final StepFactory factory,
final TerminationStrategy terminationStrategy,
final SolutionListener listener,
final ParallelTrack parallelTrack) {
logger.debug("Starting backtrack");
final Deque> stack = new LinkedList>();
X head = state;
// initial state
BackTrackState btState = new BackTrackState(state, factory
.produce(state).iterator());
while (!terminationStrategy.stop(btState.getState())) {
if (btState.getSteps().hasNext()) {
// take next step
final Step step = btState.getSteps().next();
// just a short check if the other's have enough to do.
// if taking multiple steps is enabled
if (parallelTrack != null) {
Iterator steps = btState.getSteps();
fork(factory, terminationStrategy, listener, parallelTrack,
head, steps);
}
logger.debug("Taking step {}", step);
// save the state for possible return
stack.push(btState);
// create new state
head = step.take(head);
// move to new state
btState = new BackTrackState(head, factory.produce(head)
.iterator());
logger.debug("Step ahead to {}");
// check if new state is complete, notify if so
if (head.isComplete()) {
listener.onSolution(head);
}
} else {
// no steps available, try to step back
if (stack.isEmpty()) {
// if stepping back is not possible, there is no solution
logger.debug("no (more) solution possible, exiting");
return;
} else {
// step back
btState = stack.pop();
head = btState.getState();
logger.debug("Steping back to {}", head);
}
}
}
logger.debug("termination strategy decided to stop, exiting backtrack");
}
private static > void fork(
final StepFactory factory,
final TerminationStrategy terminationStrategy,
final SolutionListener listener,
final ParallelTrack parallelTrack, final X head,
final Iterator steps) {
// as long as
// there are possible next steps
// and computing resources available
while (steps.hasNext() && parallelTrack.available()) {
// get the next step
final Step parallelStep = steps.next();
// take a next step
final X forkedStep = parallelStep.take(head);
// leave the parallel process running
parallelTrack.start(forkedStep, factory, terminationStrategy,
listener);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy