/*
* Copyright © 2011 by Oleg Kovarik. All Rights Reserved
*/
package cz.cvut.felk.cig.jcop.problem.tspfast;
import cz.cvut.felk.cig.jcop.problem.Configuration;
import cz.cvut.felk.cig.jcop.problem.Operation;
import cz.cvut.felk.cig.jcop.problem.OperationHistory;
import java.util.ArrayList;
import java.util.List;
/**
* Inverts subtour and optimize with 3-OPT local optimization.
*
* @author Oleg Kovarik
*/
public class FastInvertSubtourOperation implements Operation {
/**
* Source index to find switched city on.
*/
protected int sourceIndex;
/**
* Destination index to find switched city on.
*/
protected int destinationIndex;
/**
* Matrix of distances between cities
*/
protected int[][] distances;
/**
* Matrix of nearest neighbors (city, i-th nearest neighbor)
*/
protected int[][] nearestNeighbors;
/**
* Number of available nearest neighbors
*/
protected int nn;
public FastInvertSubtourOperation(int sourceIndex, int destinationIndex, int[][] distances, int[][] nearestNeighbors) {
this.destinationIndex = destinationIndex;
this.sourceIndex = sourceIndex;
this.distances = distances;
this.nearestNeighbors = nearestNeighbors;
this.nn = nearestNeighbors[0].length;
}
public Configuration execute(Configuration configuration) {
int[] result = configuration.asSimpleArray();
int si = sourceIndex;
int di = destinationIndex;
int dimension = configuration.getDimension();
if (si > di) {
di += dimension;
}
while (di > si) {
int tmp = result[si % dimension];
result[si % dimension] = result[di % dimension];
result[di % dimension] = tmp;
//newConfiguration.set(si % dimension, configuration.valueAt(di % dimension));
//newConfiguration.set(di % dimension, configuration.valueAt(si % dimension));
di--;
si++;
}
optimize(result, nn);
List<Integer> newConfiguration = new ArrayList<Integer>();
for (int i=0; i<dimension; i++) newConfiguration.add(i, new Integer(result[i]));
return new Configuration(newConfiguration, new OperationHistory(this, configuration.getOperationHistory()));
}
@Override
public String toString() {
return "FastInvertSubtourOperation{" +
"sourceIndex=" + sourceIndex +
", destinationIndex=" + destinationIndex +
'}';
}
/**
* Fast 3-OPT local search. Rewritten from C code by Thomas Stuetzle:
*
* Original code published under GPL v2 (see gpl-ACOTSP.txt).
*
* Original readme follows:
*
* ---------------------------------------------------
*
*
* AAAA CCCC OOOO TTTTTT SSSSS PPPPP
* AA AA CC OO OO TT SS PP PP
* AAAAAA CC OO OO TT SSSS PPPPP
* AA AA CC OO OO TT SS PP
* AA AA CCCC OOOO TT SSSSS PP
*
* ######################################################
* ########## ACO algorithms for the TSP ##########
* ######################################################
*
* Version: 1.0
* Author: Thomas Stuetzle
* Copyright (c) Thomas Stuetzle, 2002
*
*
* This is the README file to the software package ACOTSP.
*
* This software package was developed by Thomas Stuetzle in connection
* with the Book
*
* [DorStu04] Marco Dorigo and Thomas Stuetzle, "Ant Colony
* Optimization", MIT Press, Cambridge, MA, USA, 2004.
*
* The software package is freely available subject to the
* GNU General Public Licence, which is included in file gpl.txt.
*
* If you use ACOTSP in your research, I would appreciate a citation in
* your publication(s). Please cite it as
*
* Thomas Stuetzle. ACOTSP, Version 1.0. Available from
* http://www.aco-metaheuristic.org/aco-code, 2004.
*
* This software package provides an implementation of various Ant Colony
* Optimization (ACO) algorithms for the symmetric Traveling
* Salesman Problem (TSP). The ACO algorithms implemented are Ant System,
* Elitist Ant System, MAX-MIN Ant System, Rank-based version of Ant
* System, Best-Worst Ant System, and Ant Colony System. This is Version
* 1.0 of ACOTSP; it is in large part identical to the software used to
* produce the results in [DorStu04], but it has been slightly adapted to
* make the code more readable, more comments were added, and a new
* command line parser was generated with opag.
*
* AIMS OF THE SOFTWARE: This software was developed to have one common
* code for the various known ACO algorithms that were at some point
* applied to the TSP in the literature. The software tries to provide a
* reasonably efficient implementation of these ACO algorithms while at
* the same time aiming for readability and understandability of the
* code.
*
*
* @param tour TSP tour to optimize
* @param nn_ls number of nearest neighbors
*/
public void optimize(int[] tour, int nn_ls) {
//TODO: rewrite
/* In case a 2-opt move should be performed, we only need to store opt2_move = TRUE,
as h1, .. h4 are used in such a way that they store the indices of the correct move */
int c1, c2, c3; /* cities considered for an exchange */
int s_c1, s_c2, s_c3; /* successors of these cities */
int p_c1, p_c2, p_c3; /* predecessors of these cities */
int pos_c1, pos_c2, pos_c3; /* positions of cities c1, c2, c3 */
int i, j, h, g, l;
boolean improvement_flag;
int help;
int h1 = 0, h2 = 0, h3 = 0, h4 = 0, h5 = 0, h6 = 0; /* memorize cities involved in a move */
int diffs, diffp;
boolean between = false;
boolean opt2_flag; /* = TRUE: perform 2-opt move, otherwise none or 3-opt move */
int move_flag; /*
move_flag = 0 --> no 3-opt move
move_flag = 1 --> between_move (c3 between c1 and c2)
move_flag = 2 --> not_between with successors of c2 and c3
move_flag = 3 --> not_between with predecessors of c2 and c3
move_flag = 4 --> cyclic move
*/
int gain, move_value, radius, add1, add2;
int decrease_breaks; /* Stores decrease by breaking two edges (a,b) (c,d) */
int[] val;
int n1, n2, n3;
int[] pos; /* positions of cities in tour */
boolean[] dlb; /* vector containing don't look bits */
boolean dlb_flag = true;
int[] h_tour; /* help vector for performing exchange move */
int[] hh_tour; /* help vector for performing exchange move */
int[] random_vector;
int n = tour.length;
random_vector = new int[n];
pos = new int[n];
dlb = new boolean[n];
h_tour = new int[n];
hh_tour = new int[n];
val = new int[3];
for (i = 0; i < n; i++) {
pos[tour[i]] = i;
dlb[i] = false;
}
improvement_flag = true;
TSPPaths.randomPathFast(random_vector, random_vector.length);
//System.out.println("Warning: fast 3 opt used");
while (improvement_flag) {
move_value = 0;
improvement_flag = false;
for (l = 0; l < n; l++) {
c1 = random_vector[l];
if (dlb_flag && dlb[c1])
continue;
opt2_flag = false;
move_flag = 0;
pos_c1 = pos[c1];
s_c1 = tour[(pos_c1 + 1)%n];
if (pos_c1 > 0)
p_c1 = tour[pos_c1 - 1];
else
p_c1 = tour[n - 1];
h = 0; /* Search for one of the h-nearest neighbours */
labelNNsearch:
while (h < nn_ls) {
c2 = nearestNeighbors[c1][h]; /* second city, determine its position */
pos_c2 = pos[c2];
s_c2 = tour[(pos_c2 + 1)%n];
if (pos_c2 > 0)
p_c2 = tour[pos_c2 - 1];
else
p_c2 = tour[n - 1];
diffs = 0;
diffp = 0;
radius = distances[c1][s_c1];
add1 = distances[c1][c2];
/* Here a fixed radius neighbour search is performed */
if (radius > add1) {
decrease_breaks = -radius - distances[c2][s_c2];
diffs = decrease_breaks + add1 + distances[s_c1][s_c2];
diffp = -radius - distances[c2][p_c2] +
distances[c1][p_c2] + distances[s_c1][c2];
} else
break;
if (p_c2 == c1) /* in case p_c2 == c1 no exchange is possible */
diffp = 0;
if ((diffs < move_value) || (diffp < move_value)) {
improvement_flag = true;
if (diffs <= diffp) {
h1 = c1;
h2 = s_c1;
h3 = c2;
h4 = s_c2;
move_value = diffs;
opt2_flag = true;
move_flag = 0;
/* goto exchange; */
} else {
h1 = c1;
h2 = s_c1;
h3 = p_c2;
h4 = c2;
move_value = diffp;
opt2_flag = true;
move_flag = 0;
/* goto exchange; */
}
}
/* Now perform the innermost search */
g = 0;
while (g < nn_ls) {
c3 = nearestNeighbors[s_c1][g];
pos_c3 = pos[c3];
s_c3 = tour[(pos_c3 + 1)%n];
if (pos_c3 > 0)
p_c3 = tour[pos_c3 - 1];
else
p_c3 = tour[n - 1];
if (c3 == c1) {
g++;
continue;
} else {
add2 = distances[s_c1][c3];
/* Perform fixed radius neighbour search for innermost search */
if (decrease_breaks + add1 < add2) {
if (pos_c2 > pos_c1) {
if (pos_c3 <= pos_c2 && pos_c3 > pos_c1)
between = true;
else
between = false;
} else if (pos_c2 < pos_c1)
if (pos_c3 > pos_c1 || pos_c3 < pos_c2)
between = true;
else
between = false;
else {
System.out.println(" Strange !!, pos_1 " + pos_c1 + " == pos_2 " + pos_c2);
}
if (between) {
/* We have to add edges (c1,c2), (c3,s_c1), (p_c3,s_c2) to get
valid tour; it's the only possibility */
gain = decrease_breaks - distances[c3][p_c3] +
add1 + add2 +
distances[p_c3][s_c2];
/* check for improvement by move */
if (gain < move_value) {
improvement_flag = true; /* g = neigh_ls + 1; */
move_value = gain;
opt2_flag = false;
move_flag = 1;
/* store nodes involved in move */
h1 = c1;
h2 = s_c1;
h3 = c2;
h4 = s_c2;
h5 = p_c3;
h6 = c3;
break labelNNsearch;
//goto exchange;
}
} else { /* not between(pos_c1,pos_c2,pos_c3) */
/* We have to add edges (c1,c2), (s_c1,c3), (s_c2,s_c3) */
gain = decrease_breaks - distances[c3][s_c3] +
add1 + add2 +
distances[s_c2][s_c3];
if (pos_c2 == pos_c3) {
gain = 20000;
}
/* check for improvement by move */
if (gain < move_value) {
improvement_flag = true; /* g = neigh_ls + 1; */
move_value = gain;
opt2_flag = false;
move_flag = 2;
/* store nodes involved in move */
h1 = c1;
h2 = s_c1;
h3 = c2;
h4 = s_c2;
h5 = c3;
h6 = s_c3;
break labelNNsearch;
//goto exchange;
}
/* or add edges (c1,c2), (s_c1,c3), (p_c2,p_c3) */
gain = -radius - distances[p_c2][c2]
- distances[p_c3][c3] +
add1 + add2 +
distances[p_c2][p_c3];
if (c3 == c2 || c2 == c1 || c1 == c3 || p_c2 == c1) {
gain = 2000000;
}
if (gain < move_value) {
improvement_flag = true;
move_value = gain;
opt2_flag = false;
move_flag = 3;
h1 = c1;
h2 = s_c1;
h3 = p_c2;
h4 = c2;
h5 = p_c3;
h6 = c3;
break labelNNsearch;
// goto exchange;
}
/* Or perform the 3-opt move where no subtour inversion is necessary
i.e. delete edges (c1,s_c1), (c2,p_c2), (c3,s_c3) and
add edges (c1,c2), (c3,s_c1), (p_c2,s_c3) */
gain = -radius - distances[p_c2][c2] -
distances[c3][s_c3]
+ add1 + add2 + distances[p_c2][s_c3];
/* check for improvement */
if (gain < move_value) {
improvement_flag = true;
move_value = gain;
opt2_flag = false;
move_flag = 4;
improvement_flag = true;
/* store nodes involved in move */
h1 = c1;
h2 = s_c1;
h3 = p_c2;
h4 = c2;
h5 = c3;
h6 = s_c3;
break labelNNsearch;
//goto exchange;
}
}
} else
g = nn_ls + 1;
}
g++;
}
h++;
}
if (move_flag > 0 || opt2_flag) {
exchange:
move_value = 0;
/* Now make the exchange */
if (move_flag > 0) {
dlb[h1] = false;
dlb[h2] = false;
dlb[h3] = false;
dlb[h4] = false;
dlb[h5] = false;
dlb[h6] = false;
pos_c1 = pos[h1];
pos_c2 = pos[h3];
pos_c3 = pos[h5];
if (move_flag == 4) {
if (pos_c2 > pos_c1)
n1 = pos_c2 - pos_c1;
else
n1 = n - (pos_c1 - pos_c2);
if (pos_c3 > pos_c2)
n2 = pos_c3 - pos_c2;
else
n2 = n - (pos_c2 - pos_c3);
if (pos_c1 > pos_c3)
n3 = pos_c1 - pos_c3;
else
n3 = n - (pos_c3 - pos_c1);
/* n1: length h2 - h3, n2: length h4 - h5, n3: length h6 - h1 */
val[0] = n1;
val[1] = n2;
val[2] = n3;
/* Now order the partial tours */
h = 0;
help = Integer.MIN_VALUE;
for (g = 0; g <= 2; g++) {
if (help < val[g]) {
help = val[g];
h = g;
}
}
/* order partial tours according length */
if (h == 0) {
/* copy part from pos[h4] to pos[h5]
direkt kopiert: Teil von pos[h6] to pos[h1], it
remains the part from pos[h2] to pos[h3] */
j = pos[h4];
h = pos[h5];
i = 0;
h_tour[i] = tour[j];
n1 = 1;
while (j != h) {
i++;
j++;
if (j >= n)
j = 0;
h_tour[i] = tour[j];
n1++;
}
/* First copy partial tour 3 in new position */
j = pos[h4];
i = pos[h6];
tour[j] = tour[i];
pos[tour[i]] = j;
while (i != pos_c1) {
i++;
if (i >= n)
i = 0;
j++;
if (j >= n)
j = 0;
tour[j] = tour[i];
pos[tour[i]] = j;
}
/* Now copy stored part from h_tour */
j++;
if (j >= n)
j = 0;
for (i = 0; i < n1; i++) {
tour[j] = h_tour[i];
pos[h_tour[i]] = j;
j++;
if (j >= n)
j = 0;
}
//tour[n] = tour[0];
} else if (h == 1) {
/* copy part from pos[h6] to pos[h1]
direkt kopiert: Teil von pos[h2] to pos[h3], it
remains the part from pos[h4] to pos[h5] */
j = pos[h6];
h = pos[h1];
i = 0;
h_tour[i] = tour[j];
n1 = 1;
while (j != h) {
i++;
j++;
if (j >= n)
j = 0;
h_tour[i] = tour[j];
n1++;
}
/* First copy partial tour 3 in new position */
j = pos[h6];
i = pos[h2];
tour[j] = tour[i];
pos[tour[i]] = j;
while (i != pos_c2) {
i++;
if (i >= n)
i = 0;
j++;
if (j >= n)
j = 0;
tour[j] = tour[i];
pos[tour[i]] = j;
}
/* Now copy stored part from h_tour */
j++;
if (j >= n)
j = 0;
for (i = 0; i < n1; i++) {
tour[j] = h_tour[i];
pos[h_tour[i]] = j;
j++;
if (j >= n)
j = 0;
}
//tour[n] = tour[0];
} else if (h == 2) {
/* copy part from pos[h2] to pos[h3]
direkt kopiert: Teil von pos[h4] to pos[h5], it
remains the part from pos[h6] to pos[h1] */
j = pos[h2];
h = pos[h3];
i = 0;
h_tour[i] = tour[j];
n1 = 1;
while (j != h) {
i++;
j++;
if (j >= n)
j = 0;
h_tour[i] = tour[j];
n1++;
}
/* First copy partial tour 3 in new position */
j = pos[h2];
i = pos[h4];
tour[j] = tour[i];
pos[tour[i]] = j;
while (i != pos_c3) {
i++;
if (i >= n)
i = 0;
j++;
if (j >= n)
j = 0;
tour[j] = tour[i];
pos[tour[i]] = j;
}
/* Now copy stored part from h_tour */
j++;
if (j >= n)
j = 0;
for (i = 0; i < n1; i++) {
tour[j] = h_tour[i];
pos[h_tour[i]] = j;
j++;
if (j >= n)
j = 0;
}
//tour[n] = tour[0];
}
} else if (move_flag == 1) {
if (pos_c3 < pos_c2)
n1 = pos_c2 - pos_c3;
else
n1 = n - (pos_c3 - pos_c2);
if (pos_c3 > pos_c1)
n2 = pos_c3 - pos_c1 + 1;
else
n2 = n - (pos_c1 - pos_c3 + 1);
if (pos_c2 > pos_c1)
n3 = n - (pos_c2 - pos_c1 + 1);
else
n3 = pos_c1 - pos_c2 + 1;
/* n1: length h6 - h3, n2: length h5 - h2, n2: length h1 - h3 */
val[0] = n1;
val[1] = n2;
val[2] = n3;
/* Now order the partial tours */
h = 0;
help = Integer.MIN_VALUE;
for (g = 0; g <= 2; g++) {
if (help < val[g]) {
help = val[g];
h = g;
}
}
/* order partial tours according length */
if (h == 0) {
/* copy part from pos[h5] to pos[h2]
(inverted) and from pos[h4] to pos[h1] (inverted)
it remains the part from pos[h6] to pos[h3] */
j = pos[h5];
h = pos[h2];
i = 0;
h_tour[i] = tour[j];
n1 = 1;
while (j != h) {
i++;
j--;
if (j < 0)
j = n - 1;
h_tour[i] = tour[j];
n1++;
}
j = pos[h1];
h = pos[h4];
i = 0;
hh_tour[i] = tour[j];
n2 = 1;
while (j != h) {
i++;
j--;
if (j < 0)
j = n - 1;
hh_tour[i] = tour[j];
n2++;
}
j = pos[h4];
for (i = 0; i < n2; i++) {
tour[j] = hh_tour[i];
pos[hh_tour[i]] = j;
j++;
if (j >= n)
j = 0;
}
/* Now copy stored part from h_tour */
for (i = 0; i < n1; i++) {
tour[j] = h_tour[i];
pos[h_tour[i]] = j;
j++;
if (j >= n)
j = 0;
}
//tour[n] = tour[0];
} else if (h == 1) {
/* copy part from h3 to h6 (wird inverted) erstellen : */
j = pos[h3];
h = pos[h6];
i = 0;
h_tour[i] = tour[j];
n1 = 1;
while (j != h) {
i++;
j--;
if (j < 0)
j = n - 1;
h_tour[i] = tour[j];
n1++;
}
j = pos[h6];
i = pos[h4];
tour[j] = tour[i];
pos[tour[i]] = j;
while (i != pos_c1) {
i++;
j++;
if (j >= n)
j = 0;
if (i >= n)
i = 0;
tour[j] = tour[i];
pos[tour[i]] = j;
}
/* Now copy stored part from h_tour */
j++;
if (j >= n)
j = 0;
i = 0;
tour[j] = h_tour[i];
pos[h_tour[i]] = j;
while (j != pos_c1) {
j++;
if (j >= n)
j = 0;
i++;
tour[j] = h_tour[i];
pos[h_tour[i]] = j;
}
//tour[n] = tour[0];
} else if (h == 2) {
/* copy part from pos[h2] to pos[h5] and
from pos[h3] to pos[h6] (inverted), it
remains the part from pos[h4] to pos[h1] */
j = pos[h2];
h = pos[h5];
i = 0;
h_tour[i] = tour[j];
n1 = 1;
while (j != h) {
i++;
j++;
if (j >= n)
j = 0;
h_tour[i] = tour[j];
n1++;
}
j = pos_c2;
h = pos[h6];
i = 0;
hh_tour[i] = tour[j];
n2 = 1;
while (j != h) {
i++;
j--;
if (j < 0)
j = n - 1;
hh_tour[i] = tour[j];
n2++;
}
j = pos[h2];
for (i = 0; i < n2; i++) {
tour[j] = hh_tour[i];
pos[hh_tour[i]] = j;
j++;
if (j >= n)
j = 0;
}
/* Now copy stored part from h_tour */
for (i = 0; i < n1; i++) {
tour[j] = h_tour[i];
pos[h_tour[i]] = j;
j++;
if (j >= n)
j = 0;
}
//tour[n] = tour[0];
}
} else if (move_flag == 2) {
if (pos_c3 < pos_c1)
n1 = pos_c1 - pos_c3;
else
n1 = n - (pos_c3 - pos_c1);
if (pos_c3 > pos_c2)
n2 = pos_c3 - pos_c2;
else
n2 = n - (pos_c2 - pos_c3);
if (pos_c2 > pos_c1)
n3 = pos_c2 - pos_c1;
else
n3 = n - (pos_c1 - pos_c2);
val[0] = n1;
val[1] = n2;
val[2] = n3;
/* Determine which is the longest part */
h = 0;
help = Integer.MIN_VALUE;
for (g = 0; g <= 2; g++) {
if (help < val[g]) {
help = val[g];
h = g;
}
}
/* order partial tours according length */
if (h == 0) {
/* copy part from pos[h3] to pos[h2]
(inverted) and from pos[h5] to pos[h4], it
remains the part from pos[h6] to pos[h1] */
j = pos[h3];
h = pos[h2];
i = 0;
h_tour[i] = tour[j];
n1 = 1;
while (j != h) {
i++;
j--;
if (j < 0)
j = n - 1;
h_tour[i] = tour[j];
n1++;
}
j = pos[h5];
h = pos[h4];
i = 0;
hh_tour[i] = tour[j];
n2 = 1;
while (j != h) {
i++;
j--;
if (j < 0)
j = n - 1;
hh_tour[i] = tour[j];
n2++;
}
j = pos[h2];
for (i = 0; i < n1; i++) {
tour[j] = h_tour[i];
pos[h_tour[i]] = j;
j++;
if (j >= n)
j = 0;
}
for (i = 0; i < n2; i++) {
tour[j] = hh_tour[i];
pos[hh_tour[i]] = j;
j++;
if (j >= n)
j = 0;
}
//tour[n] = tour[0];
/* getchar(); */
} else if (h == 1) {
/* copy part from pos[h2] to pos[h3] and
from pos[h1] to pos[h6] (inverted), it
remains the part from pos[h4] to pos[h5] */
j = pos[h2];
h = pos[h3];
i = 0;
h_tour[i] = tour[j];
n1 = 1;
while (j != h) {
i++;
j++;
if (j >= n)
j = 0;
h_tour[i] = tour[j];
n1++;
}
j = pos[h1];
h = pos[h6];
i = 0;
hh_tour[i] = tour[j];
n2 = 1;
while (j != h) {
i++;
j--;
if (j < 0)
j = n - 1;
hh_tour[i] = tour[j];
n2++;
}
j = pos[h6];
for (i = 0; i < n1; i++) {
tour[j] = h_tour[i];
pos[h_tour[i]] = j;
j++;
if (j >= n)
j = 0;
}
for (i = 0; i < n2; i++) {
tour[j] = hh_tour[i];
pos[hh_tour[i]] = j;
j++;
if (j >= n)
j = 0;
}
//tour[n] = tour[0];
} else if (h == 2) {
/* copy part from pos[h1] to pos[h6]
(inverted) and from pos[h4] to pos[h5],
it remains the part from pos[h2] to
pos[h3] */
j = pos[h1];
h = pos[h6];
i = 0;
h_tour[i] = tour[j];
n1 = 1;
while (j != h) {
i++;
j--;
if (j < 0)
j = n - 1;
h_tour[i] = tour[j];
n1++;
}
j = pos[h4];
h = pos[h5];
i = 0;
hh_tour[i] = tour[j];
n2 = 1;
while (j != h) {
i++;
j++;
if (j >= n)
j = 0;
hh_tour[i] = tour[j];
n2++;
}
j = pos[h4];
/* Now copy stored part from h_tour */
for (i = 0; i < n1; i++) {
tour[j] = h_tour[i];
pos[h_tour[i]] = j;
j++;
if (j >= n)
j = 0;
}
/* Now copy stored part from h_tour */
for (i = 0; i < n2; i++) {
tour[j] = hh_tour[i];
pos[hh_tour[i]] = j;
j++;
if (j >= n)
j = 0;
}
//tour[n] = tour[0];
}
} else if (move_flag == 3) {
if (pos_c3 < pos_c1)
n1 = pos_c1 - pos_c3;
else
n1 = n - (pos_c3 - pos_c1);
if (pos_c3 > pos_c2)
n2 = pos_c3 - pos_c2;
else
n2 = n - (pos_c2 - pos_c3);
if (pos_c2 > pos_c1)
n3 = pos_c2 - pos_c1;
else
n3 = n - (pos_c1 - pos_c2);
/* n1: length h6 - h1, n2: length h4 - h5, n2: length h2 - h3 */
val[0] = n1;
val[1] = n2;
val[2] = n3;
/* Determine which is the longest part */
h = 0;
help = Integer.MIN_VALUE;
for (g = 0; g <= 2; g++) {
if (help < val[g]) {
help = val[g];
h = g;
}
}
/* order partial tours according length */
if (h == 0) {
/* copy part from pos[h2] to pos[h3]
(inverted) and from pos[h4] to pos[h5]
it remains the part from pos[h6] to pos[h1] */
j = pos[h3];
h = pos[h2];
i = 0;
h_tour[i] = tour[j];
n1 = 1;
while (j != h) {
i++;
j--;
if (j < 0)
j = n - 1;
h_tour[i] = tour[j];
n1++;
}
j = pos[h2];
h = pos[h5];
i = pos[h4];
tour[j] = h4;
pos[h4] = j;
while (i != h) {
i++;
if (i >= n)
i = 0;
j++;
if (j >= n)
j = 0;
tour[j] = tour[i];
pos[tour[i]] = j;
}
j++;
if (j >= n)
j = 0;
for (i = 0; i < n1; i++) {
tour[j] = h_tour[i];
pos[h_tour[i]] = j;
j++;
if (j >= n)
j = 0;
}
//tour[n] = tour[0];
} else if (h == 1) {
/* copy part from pos[h3] to pos[h2]
(inverted) and from pos[h6] to pos[h1],
it remains the part from pos[h4] to pos[h5] */
j = pos[h3];
h = pos[h2];
i = 0;
h_tour[i] = tour[j];
n1 = 1;
while (j != h) {
i++;
j--;
if (j < 0)
j = n - 1;
h_tour[i] = tour[j];
n1++;
}
j = pos[h6];
h = pos[h1];
i = 0;
hh_tour[i] = tour[j];
n2 = 1;
while (j != h) {
i++;
j++;
if (j >= n)
j = 0;
hh_tour[i] = tour[j];
n2++;
}
j = pos[h6];
for (i = 0; i < n1; i++) {
tour[j] = h_tour[i];
pos[h_tour[i]] = j;
j++;
if (j >= n)
j = 0;
}
for (i = 0; i < n2; i++) {
tour[j] = hh_tour[i];
pos[hh_tour[i]] = j;
j++;
if (j >= n)
j = 0;
}
//tour[n] = tour[0];
} else if (h == 2) {
/* copy part from pos[h4] to pos[h5]
(inverted) and from pos[h6] to pos[h1] (inverted)
it remains the part from pos[h2] to pos[h3] */
j = pos[h5];
h = pos[h4];
i = 0;
h_tour[i] = tour[j];
n1 = 1;
while (j != h) {
i++;
j--;
if (j < 0)
j = n - 1;
h_tour[i] = tour[j];
n1++;
}
j = pos[h1];
h = pos[h6];
i = 0;
hh_tour[i] = tour[j];
n2 = 1;
while (j != h) {
i++;
j--;
if (j < 0)
j = n - 1;
hh_tour[i] = tour[j];
n2++;
}
j = pos[h4];
/* Now copy stored part from h_tour */
for (i = 0; i < n1; i++) {
tour[j] = h_tour[i];
pos[h_tour[i]] = j;
j++;
if (j >= n)
j = 0;
}
/* Now copy stored part from h_tour */
for (i = 0; i < n2; i++) {
tour[j] = hh_tour[i];
pos[hh_tour[i]] = j;
j++;
if (j >= n)
j = 0;
}
// tour[n] = tour[0];
}
} else {
System.out.println(" Some very strange error must have occurred !!!");
System.exit(0);
}
}
if (opt2_flag) {
/* Now perform move */
dlb[h1] = false;
dlb[h2] = false;
dlb[h3] = false;
dlb[h4] = false;
if (pos[h3] < pos[h1]) {
help = h1;
h1 = h3;
h3 = help;
help = h2;
h2 = h4;
h4 = help;
}
if (pos[h3] - pos[h2] < n / 2 + 1) {
/* reverse inner part from pos[h2] to pos[h3] */
i = pos[h2];
j = pos[h3];
while (i < j) {
c1 = tour[i];
c2 = tour[j];
tour[i] = c2;
tour[j] = c1;
pos[c1] = j;
pos[c2] = i;
i++;
j--;
}
} else {
/* reverse outer part from pos[h4] to pos[h1] */
i = pos[h1];
j = pos[h4];
if (j > i)
help = n - (j - i) + 1;
else
help = (i - j) + 1;
help = help / 2;
for (h = 0; h < help; h++) {
c1 = tour[i];
c2 = tour[j];
tour[i] = c2;
tour[j] = c1;
pos[c1] = j;
pos[c2] = i;
i--;
j++;
if (i < 0)
i = n - 1;
if (j >= n)
j = 0;
}
// tour[n] = tour[0];
}
}
} else {
dlb[c1] = true;
}
}
}
}
}