⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 permuteseveralsublistsofcities.java

📁 经典的货郎担问题解决办法
💻 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 + -