📄 permuteseveralsublistsofcities.java
字号:
/*
** This code was written by Kent Paul Dolan, from scratch. So far as I
** know, it is an original (though obvious) algorithm. See accompanying
** file TravellerDoc.html for status for your use.
*/
package com.well.www.user.xanthian.java.genetic.reproducers.asexual;
import com.coyotegulch.tools.*;
import com.coyotegulch.genetic.*;
import com.well.www.user.xanthian.java.genetic.*;
import com.well.www.user.xanthian.java.tools.*;
import com.well.www.user.xanthian.java.ui.*;
public class PermuteSeveralSublistsOfCities
implements AsexualReproducer
{
/*
** Because we do up to 2^(M-1) reversals as well as M! permutations, we
** cannot afford the computational burden of the global permute limit;
** support a local one as well. Unlike Optimize Near A Point, we are
** not helped particularly by favorable geometry as we approach the
** solution, either, and for large genomes, our worst case is our usual
** case.
*/
private static final int LOCAL_PERMUTE_LIMIT = 6;
private static boolean DB = false;
private static boolean VDB = false;
private static VisualDebugger m_vdb = null;
public Chromosome reproduce(Chromosome parent)
{
try
{
/*
** Debugging hook abbreviation. During development, turn on debugging
** just for this class by setting this variable to true, here. When the
** code is stable, set it to false here, and control debugging from the
** checkbox controls panel, instead. This variable is global to this
** class, so it controls debugging thoughout the class when set here at
** the top of the entry method for the class.
*/
DB = false;
if (CheckBoxControls.getState(CheckBoxControls.CBC_DEBUG_PRINTOUTS))
{
DB = true;
System.out.println
(
"Entered PermuteSeveralSublistsOfCities.reproduce( Chromosome parent)"
);
}
/*
** Rename the input to a less burdensome type.
*/
TravellerChromosome p = (TravellerChromosome) parent;
TravellerChromosome child = algorithm( p );
child.setOriginator( "PermuteSeveralSublistsOfCities" );
child.checkValidity();
return (Chromosome) child;
}
catch (Exception e)
{
System.err.println
(
"PermuteSeveralSublistsOfCities.reproduce() threw!"
);
}
/*
** This code should never be reached, it is just here to pacify javac.
*/
return parent;
}
private TravellerChromosome algorithm( TravellerChromosome parent )
{
VDB = false;
if (CheckBoxControls.getState(CheckBoxControls.CBC_DEBUG_VISUAL_WINDOWS))
{
VDB = true;
}
if (VDB)
{
if ( m_vdb == null )
{
m_vdb = new VisualDebugger( "PermuteSeveralSublistsOfCities" );
}
}
else
{
if ( m_vdb != null )
{
m_vdb.closeWindow();
m_vdb = null;
}
}
if (VDB) { m_vdb.toFront(); }
MersenneTwister mt = MersenneTwister.getTwister();
TravellerChromosome offspring = new TravellerChromosome( parent );
offspring.canonicalize();
double startingFitness = offspring.testFitness();
if (VDB) { m_vdb.setup( offspring ); }
/*
** Create a local _name_ for the input parameter; remind self not to
** scribble on it!
*/
TravellerChromosome readOnlyVersion = parent;
TravellerWorld world = offspring.getWorld();
int genomeLength = ValuatorControls.getNumberOfCities();
PermutationGenerator pg = ( new PermutationController() )
.getGenerator
(
Math.min
(
genomeLength - 1,
LOCAL_PERMUTE_LIMIT
)
);
int permuteSize = pg.getPermutationSize();
// pick cleavage points
int cleavageIndices[] = new int[permuteSize];
int sublistBeginCities[] = new int[permuteSize];
int sublistEndCities[] = new int[permuteSize];
boolean sublistFlippable[] = new boolean[permuteSize];
for (int i = 0; i < permuteSize; i++)
{
cleavageIndices[i] = -1;
sublistBeginCities[i] = -1;
sublistEndCities[i] = -1;
sublistFlippable[i] = true;
}
// fill cleavage points list with unique chromosome array indices
for (int i = 0; i < permuteSize; i++)
{
int indexCandidate = mt.nextInt(genomeLength);
while ( inList( indexCandidate, cleavageIndices ) )
{
indexCandidate = mt.nextInt(genomeLength);
}
cleavageIndices[i] = indexCandidate;
for (int j = i; j > 0; j--)
{
// Do a cheesy insertion sort, since this list has
// a single digit length.
if ( cleavageIndices[j] < cleavageIndices[j - 1] )
{
int temp = cleavageIndices[j - 1];
cleavageIndices[j - 1] = cleavageIndices[j];
cleavageIndices[j] = temp;
}
}
}
// fill in auxiliary array information. For computing
// relative fitness, we don't need the whole sublists,
// the interior lengths don't change. We just need the
// end points to connect to each other.
for (int i = 0; i < permuteSize; i++)
{
sublistBeginCities[i] = offspring.getCity(cleavageIndices[i]);
sublistEndCities[i] =
offspring.getCity
(
(
cleavageIndices[(i + 1) % permuteSize]
- 1
+ genomeLength
) % genomeLength
);
// We need not bother to reverse single entry lists,
// they look the same from either end!
if ( sublistBeginCities[i] == sublistEndCities[i] )
{
sublistFlippable[i] = false;
}
}
int bestPermutation[] = new int[permuteSize];
boolean bestFlipped[] = new boolean[permuteSize];
// Choose the original configuration as the best found,
// for a start. Create a needed power of two.
int powerOfTwo = 1;
for (int i = 0; i < permuteSize; i++)
{
bestPermutation[i] = i;
bestFlipped[i] = false;
powerOfTwo *= 2;
}
// We never need to flip some one of the sublists,
// since a TSP circuit is invariant under reversal,
// so back off by one power of two.
powerOfTwo /= 2;
// Do spooky bit twiddling magic to save unneeded
// work in the flipping loop.
int antiflipMask = 0;
for (int i = 0; i < permuteSize; i++)
{
if (!sublistFlippable[i]) { antiflipMask |= ( 1 << i ) ; }
}
double bestFitness = Double.MAX_VALUE;
Integer [] nextPermutation = null;
while ( pg.morePermutations() )
{
boolean currentFlips[] = new boolean[permuteSize];
try
{
nextPermutation = pg.getNext();
}
catch (Exception e)
{
System.out.println
(
"caught pg.getNext() throw in TravellerPermuteCitiesWithinASublist"
);
}
// Loop through the possible flips.
for (int flipWord = 0; flipWord < powerOfTwo; flipWord++)
{
// Skip work for don't flipping care subset.
if ( ( flipWord & antiflipMask ) == 0 )
{
for (int i = 0; i < permuteSize; i++)
{
currentFlips[i] = ( ( flipWord & (1 << i) ) != 0 );
}
double currentFitness = 0.0D;
for (int i = 0; i < permuteSize; i++)
{
int nextIndex = ( i + 1 ) % permuteSize;
currentFitness +=
world.getDistance
(
(
currentFlips[i]
? sublistBeginCities[nextPermutation[i].intValue()]
: sublistEndCities[nextPermutation[i].intValue()]
),
(
currentFlips[nextIndex]
? sublistEndCities[nextPermutation[nextIndex].intValue()]
: sublistBeginCities[nextPermutation[nextIndex].intValue()]
)
);
}
if (currentFitness < bestFitness)
{
bestFitness = currentFitness;
// Notice that this time we are actually capturing the
// permutation rather than what it indexes; we have a
// bunch of work to do to construct the final product
// offspring at the end of all this foolishness.
for (int i = 0; i < permuteSize; i++)
{
bestPermutation[i] = nextPermutation[i].intValue();
bestFlipped[i] = currentFlips[i];
}
}
}
}
}
// We are going to scribble on offspring, so use the local name of
// the input parameter as an unclobbered data source for city names.
// Starting at the beginning of the output chromosome, offspring,
// write the sublists in their permuted order, flipped as needed.
int writeToIndex = 0;
for (int i = 0; i < permuteSize; i++)
{
int currentCleavageIndicesIndex = bestPermutation[i];
int nextCleavageIndicesIndex =
( currentCleavageIndicesIndex + 1 ) % permuteSize;
int currentChromosomeIndex =
cleavageIndices[currentCleavageIndicesIndex];
int nextChromosomeIndex =
( cleavageIndices[nextCleavageIndicesIndex] - 1 + genomeLength )
% genomeLength;
if ( bestFlipped[i] )
{
int j = nextChromosomeIndex;
while ( true )
{
offspring.setCity( writeToIndex, readOnlyVersion.getCity(j));
writeToIndex++;
if ( j == currentChromosomeIndex ) { break; }
j = ( j - 1 + genomeLength ) % genomeLength;
}
}
else
{
int j = currentChromosomeIndex;
while ( true )
{
offspring.setCity( writeToIndex, readOnlyVersion.getCity(j));
writeToIndex++;
if ( j == nextChromosomeIndex ) { break; }
j = ( j + 1 ) % genomeLength;
}
}
}
/*
** Who knows what order the result has? Better fix it.
*/
offspring.canonicalize();
double finalFitness = offspring.testFitness();
if (VDB) { m_vdb.step( offspring ); }
/*
** We only change for the better, so if we haven't changed, we haven't
** improved. Report back so that adaptive permutation high limit can
** eventually be updated.
*/
if
(
Math.abs( finalFitness - startingFitness )
<
TravellerStatus.LITTLE_FUZZ
)
{
PermutationController.reportFailure();
}
else
{
PermutationController.reportSuccess();
}
if (VDB) { m_vdb.done( parent, offspring ); }
return offspring;
}
private boolean inList( int c, int list[] )
{
for (int i = 0; i < list.length; i++)
{
if (c == list[i]) { return true; }
}
return false;
}
private int listIndex( int c, int list[] )
{
for (int i = 0; i < list.length; i++)
{
if (c == list[i]) { return i; }
}
return -1;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -