/**
* Copyright (C) 2012, Emergya (http://www.emergya.es)
*
* @author <a href="mailto:marias@emergya.com">MarĂa Arias de Reyna</a>
*
* This file is part of GoFleet
*
* This software is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This software is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* As a special exception, if you link this library with other files to
* produce an executable, this library does not by itself cause the
* resulting executable to be covered by the GNU General Public License.
* This exception does not however invalidate any other reasons why the
* executable file might be covered by the GNU General Public License.
*/
package org.emergya.backtrackTSP;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.gofleet.openLS.tsp.TSPAlgorithm;
import org.gofleet.openLS.tsp.TSPStop;
import org.gofleet.openLS.tsp.TSPStopBag;
public class BackTrackingTSP implements TSPAlgorithm {
private static Log LOG = LogFactory.getLog(BackTrackingTSP.class);
private Boolean partialSolution = false;
private Integer seconds = 18;
private ExecutorService executor;
private ExecutorService executor2;
public BackTrackingTSP() {
}
/**
* If we cannot find a solution, do you like to get the best partial
* solution reached?
*
* @param partialSolution
*/
public BackTrackingTSP(Boolean partialSolution, Integer seconds) {
this();
if (partialSolution != null)
this.partialSolution = partialSolution;
this.seconds = seconds;
}
public List<TSPStop> order(TSPStopBag _bag) {
long time = System.currentTimeMillis();
Runtime runtime = Runtime.getRuntime();
int numthreads = runtime.availableProcessors() * 10;
executor = Executors.newFixedThreadPool(numthreads);
DistanceMatrix distances = new DistanceMatrix();
initializeMatrix(distances, _bag);
SolutionContainer solutions = new SolutionContainer(distances);
if (_bag.size() > 7) {
if (_bag.hasLast()) {
// run(executor, new AStar(_bag, distances, solutions));
run(executor, new HeuristicBacktracking(_bag, distances,
solutions));
} else {
for (TSPStop stop : _bag.getAll()) {
List<TSPStop> stops = new ArrayList<TSPStop>();
stops.addAll(_bag.getAll());
stops.remove(stop);
BacktrackStopBag bag = new BacktrackStopBag(stops,
_bag.getFirst(), stop);
// run(executor, new AStar(bag, distances, solutions));
run(executor, new HeuristicBacktracking(bag, distances,
solutions));
}
}
}
run(executor, new Backtracking(_bag, distances, solutions));
executor.shutdown();
try {
if (!executor.awaitTermination(
this.seconds - (System.currentTimeMillis() - time) / 1000,
TimeUnit.SECONDS)) {
stop();
}
} catch (InterruptedException e) {
if (!this.partialSolution) {
throw new RuntimeException(
"Timeout reached. I couldn't find a solution on a proper time. "
+ "Please, give me another chance with more time or"
+ " accept a partial solution. I won't fail you, I promise.",
e);
}
}
return getBest(solutions, distances, _bag.size());
}
private void run(final ExecutorService executor, final Runnable aStar) {
executor.execute(aStar);
}
private List<TSPStop> getBest(SolutionContainer solutions,
DistanceMatrix distances, Integer size) {
BackTrackSolution solution = solutions.getSolution();
if (solution == null)
throw new RuntimeException(
"I'm embarrased, I was unable to find a solution for you. "
+ "Please, forgive me. I am just a machine.");
return solution.getStack();
}
/**
* Initialices the distance matrix on background while tsp is running.
*
* @param distances
* @param bag
*/
private void initializeMatrix(DistanceMatrix distances, TSPStopBag bag) {
Runtime runtime = Runtime.getRuntime();
int numthreads = runtime.availableProcessors() * 3;
executor2 = Executors.newFixedThreadPool(numthreads);
List<BacktrackStop> candidates = null;
candidates = new ArrayList<BacktrackStop>();
for (TSPStop stop : bag.getAll())
candidates.add((BacktrackStop) stop);
for (BacktrackStop from : candidates) {
executor2.execute(new InitializeDistances(from, candidates,
distances));
}
executor2.shutdown();
Thread t = new Thread() {
@Override
public void run() {
try {
executor2.awaitTermination(6, TimeUnit.SECONDS);
} catch (InterruptedException e) {
LOG.error(e, e);
}
}
};
t.start();
}
@Override
public boolean stop() {
LOG.info("Shutting down backtracking");
if (executor2 != null)
executor2.shutdownNow();
if (executor != null)
executor.shutdownNow();
else
return false;
LOG.info("Backtracking shut down");
return true;
}
}
class SolutionContainer {
private BackTrackSolution solution = null;
private DistanceMatrix distances = null;
public SolutionContainer(DistanceMatrix distances) {
this.distances = distances;
}
public BackTrackSolution getSolution() {
synchronized (this) {
return this.solution;
}
}
public void add(BackTrackSolution solution) {
synchronized (this) {
if (this.solution == null)
this.solution = solution;
else {
if (this.solution.getDistance(distances) > solution
.getDistance(distances))
this.solution = solution;
}
}
}
}