Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
08/01/11 17:48:53 (13 years ago)
Author:
mkommend
Message:

#1479: Integrated trunk changes.

Location:
branches/GP.Grammar.Editor/HeuristicLab.Problems.VehicleRouting/3.3/Encodings
Files:
1 added
17 edited
2 copied

Legend:

Unmodified
Added
Removed
  • branches/GP.Grammar.Editor/HeuristicLab.Problems.VehicleRouting/3.3/Encodings/Alba/Crossovers/AlbaPermutationCrossover.cs

    r5445 r6618  
    4848
    4949    protected override AlbaEncoding Crossover(IRandom random, AlbaEncoding parent1, AlbaEncoding parent2) {
    50       //note - the inner crossover is called here and the result is converted to an alba representation
     50      //note - the inner crossover is called here and the solution is converted to an alba representation
    5151      //some refactoring should be done here in the future - the crossover operation should be called directly
    5252
    53       InnerCrossoverParameter.ActualValue.ParentsParameter.ActualName = ParentsParameter.ActualName;
    54       IAtomicOperation op = this.ExecutionContext.CreateOperation(
    55         InnerCrossoverParameter.ActualValue, this.ExecutionContext.Scope);
    56       op.Operator.Execute((IExecutionContext)op, CancellationToken);
     53      if (parent1.Length == parent2.Length) {
     54        InnerCrossoverParameter.ActualValue.ParentsParameter.ActualName = ParentsParameter.ActualName;
     55        IAtomicOperation op = this.ExecutionContext.CreateOperation(
     56          InnerCrossoverParameter.ActualValue, this.ExecutionContext.Scope);
     57        op.Operator.Execute((IExecutionContext)op, CancellationToken);
    5758
    58       string childName = InnerCrossoverParameter.ActualValue.ChildParameter.ActualName;
    59       if (ExecutionContext.Scope.Variables.ContainsKey(childName)) {
    60         Permutation permutation = ExecutionContext.Scope.Variables[childName].Value as Permutation;
    61         ExecutionContext.Scope.Variables.Remove(childName);
     59        string childName = InnerCrossoverParameter.ActualValue.ChildParameter.ActualName;
     60        if (ExecutionContext.Scope.Variables.ContainsKey(childName)) {
     61          Permutation permutation = ExecutionContext.Scope.Variables[childName].Value as Permutation;
     62          ExecutionContext.Scope.Variables.Remove(childName);
    6263
    63         return new AlbaEncoding(permutation, Cities);
    64       } else
    65         return null;
     64          return new AlbaEncoding(permutation, Cities);
     65        } else
     66          return null;
     67      } else {
     68        return parent1.Clone() as AlbaEncoding;
     69      }
    6670    }
    6771  }
  • branches/GP.Grammar.Editor/HeuristicLab.Problems.VehicleRouting/3.3/Encodings/Alba/Moves/LambdaInterchange/AlbaExhaustiveLambdaInterchangeMoveGenerator.cs

    r5445 r6618  
    3939    }
    4040
    41     protected override AlbaLambdaInterchangeMove[] GenerateMoves(AlbaEncoding individual, int lambda) {
     41    public static AlbaLambdaInterchangeMove[] GenerateAllMoves(AlbaEncoding individual, int lambda) {
    4242      List<AlbaLambdaInterchangeMove> moves = new List<AlbaLambdaInterchangeMove>();
    4343
     
    6666      return moves.ToArray();
    6767    }
     68
     69    protected override AlbaLambdaInterchangeMove[] GenerateMoves(AlbaEncoding individual, int lambda) {
     70      return GenerateAllMoves(individual, lambda);
     71    }
    6872  }
    6973}
  • branches/GP.Grammar.Editor/HeuristicLab.Problems.VehicleRouting/3.3/Encodings/Alba/Moves/LambdaInterchange/AlbaStochasticLambdaInterchangeMutliMoveGenerator.cs

    r5445 r6618  
    5050      return new AlbaStochasticLambdaInterchangeMultiMoveGenerator(this, cloner);
    5151    }
    52     protected override AlbaLambdaInterchangeMove[] GenerateMoves(AlbaEncoding individual, int lambda) {
    53       int sampleSize = SampleSizeParameter.ActualValue.Value;
    5452
     53    public static AlbaLambdaInterchangeMove[] GenerateAllMoves(AlbaEncoding individual, int lambda, int sampleSize, IRandom random) {
    5554      AlbaLambdaInterchangeMove[] moves = new AlbaLambdaInterchangeMove[sampleSize];
    5655      for (int i = 0; i < sampleSize; i++) {
    5756        moves[i] = AlbaStochasticLambdaInterchangeSingleMoveGenerator.Apply(
    58           individual, Cities, lambda, RandomParameter.ActualValue);
     57          individual, individual.Cities, lambda, random);
    5958      }
    6059
    6160      return moves;
    6261    }
     62
     63    protected override AlbaLambdaInterchangeMove[] GenerateMoves(AlbaEncoding individual, int lambda) {
     64      int sampleSize = SampleSizeParameter.ActualValue.Value;
     65
     66      return GenerateAllMoves(individual, lambda, sampleSize, RandomParameter.ActualValue);
     67    }
    6368  }
    6469}
  • branches/GP.Grammar.Editor/HeuristicLab.Problems.VehicleRouting/3.3/Encodings/General/Creators/PushForwardInsertionCreator.cs

    r5445 r6618  
    9191    }
    9292
    93     private double CalculateDistance(int start, int end) {
     93    private double CalculateDistance(int start, int end, DoubleMatrix coordinates) {
    9494      double distance = 0.0;
    95       DoubleMatrix coordinates = CoordinatesParameter.ActualValue;
    9695
    9796      distance =
     
    103102    }
    104103
    105     private DoubleMatrix CreateDistanceMatrix() {
    106       DoubleMatrix coordinates = CoordinatesParameter.ActualValue;
     104    private DoubleMatrix CreateDistanceMatrix(DoubleMatrix coordinates) {
    107105      DoubleMatrix distanceMatrix = new DoubleMatrix(coordinates.Rows, coordinates.Rows);
    108106
    109107      for (int i = 0; i < distanceMatrix.Rows; i++) {
    110108        for (int j = i; j < distanceMatrix.Columns; j++) {
    111           double distance = CalculateDistance(i, j);
     109          double distance = CalculateDistance(i, j, coordinates);
    112110
    113111          distanceMatrix[i, j] = distance;
     
    119117    }
    120118
    121     private double Distance(int start, int end) {
     119    private double Distance(int start, int end, DoubleMatrix coordinates, bool useDistanceMatrix) {
    122120      double distance = 0.0;
    123121
    124       if (UseDistanceMatrixParameter.ActualValue.Value) {
    125         if (DistanceMatrixParameter.ActualValue == null) {
    126           DistanceMatrixParameter.ActualValue = CreateDistanceMatrix();
    127         }
    128 
    129         distance = DistanceMatrixParameter.ActualValue[start, end];
    130       } else {
    131         distance = CalculateDistance(start, end);
     122      if (useDistanceMatrix) {
     123        distance = coordinates[start, end];
     124      } else { 
     125        distance = CalculateDistance(start, end, coordinates);
    132126      }
    133127
     
    135129    }
    136130
    137     private double TravelDistance(List<int> route, int begin) {
     131    private double TravelDistance(List<int> route, int begin, DoubleMatrix coordinates, bool useDistanceMatrix) {
    138132      double distance = 0;
    139133      for (int i = begin; i < route.Count - 1 && (i == begin || route[i] != 0); i++) {
    140         distance += Distance(route[i], route[i + 1]);
     134        distance += Distance(route[i], route[i + 1], coordinates, useDistanceMatrix);
    141135      }
    142136      return distance;
    143137    }
    144138
    145     private bool SubrouteConstraintsOK(List<int> route, int begin) {
     139    private bool SubrouteConstraintsOK(List<int> route, int begin, DoubleMatrix coordinates, bool useDistanceMatrix,
     140      DoubleArray dueTime, DoubleArray readyTime, DoubleArray serviceTime, DoubleArray demand, DoubleValue capacity) {
    146141      double t = 0.0, o = 0.0;
    147142      for (int i = begin + 1; i < route.Count; i++) {
    148         t += Distance(route[i - 1], route[i]);
     143        t += Distance(route[i - 1], route[i], coordinates, useDistanceMatrix);
    149144        if (route[i] == 0) return (t < DueTimeParameter.ActualValue[0]); // violation on capacity constraint is handled below
    150145        else {
    151           if (t > DueTimeParameter.ActualValue[route[i]]) return false;
    152           t = Math.Max(ReadyTimeParameter.ActualValue[route[i]], t);
    153           t += ServiceTimeParameter.ActualValue[route[i]];
    154           o += DemandParameter.ActualValue[route[i]];
    155           if (o > CapacityParameter.ActualValue.Value) return false; // premature exit on capacity constraint violation
     146          if (t > dueTime[route[i]]) return false;
     147          t = Math.Max(readyTime[route[i]], t);
     148          t += serviceTime[route[i]];
     149          o += demand[route[i]];
     150          if (o > capacity.Value) return false; // premature exit on capacity constraint violation
    156151        }
    157152      }
     
    159154    }
    160155
    161     private bool SubrouteTardinessOK(List<int> route, int begin) {
     156    private bool SubrouteTardinessOK(List<int> route, int begin, DoubleMatrix coordinates, bool useDistanceMatrix,
     157      DoubleArray dueTime, DoubleArray readyTime, DoubleArray serviceTime) {
    162158      double t = 0.0;
    163159      for (int i = begin + 1; i < route.Count; i++) {
    164         t += Distance(route[i - 1], route[i]);
     160        t += Distance(route[i - 1], route[i], coordinates, useDistanceMatrix);
    165161        if (route[i] == 0) {
    166           if (t < DueTimeParameter.ActualValue[0]) return true;
     162          if (t < dueTime[0]) return true;
    167163          else return false;
    168164        } else {
    169           if (t > DueTimeParameter.ActualValue[route[i]]) return false;
    170           t = Math.Max(ReadyTimeParameter.ActualValue[route[i]], t);
    171           t += ServiceTimeParameter.ActualValue[route[i]];
     165          if (t > dueTime[route[i]]) return false;
     166          t = Math.Max(readyTime[route[i]], t);
     167          t += serviceTime[route[i]];
    172168        }
    173169      }
     
    175171    }
    176172
    177     private bool SubrouteLoadOK(List<int> route, int begin) {
     173    private bool SubrouteLoadOK(List<int> route, int begin, DoubleValue capacity, DoubleArray demand) {
    178174      double o = 0.0;
    179175      for (int i = begin + 1; i < route.Count; i++) {
    180         if (route[i] == 0) return (o < CapacityParameter.ActualValue.Value);
     176        if (route[i] == 0) return (o < capacity.Value);
    181177        else {
    182           o += DemandParameter.ActualValue[route[i]];
    183         }
    184       }
    185       return (o < CapacityParameter.ActualValue.Value);
     178          o += demand[route[i]];
     179        }
     180      }
     181      return (o < capacity.Value);
    186182    }
    187183
    188184    protected override List<int> CreateSolution() {
    189       double alpha, beta, gamma;
    190       alpha = N(Alpha.Value.Value, Math.Sqrt(AlphaVariance.Value.Value), RandomParameter.ActualValue);
    191       beta = N(Beta.Value.Value, Math.Sqrt(BetaVariance.Value.Value), RandomParameter.ActualValue);
    192       gamma = N(Gamma.Value.Value, Math.Sqrt(GammaVariance.Value.Value), RandomParameter.ActualValue);
     185      //double alpha, beta, gamma;
     186      double alpha = N(Alpha.Value.Value, Math.Sqrt(AlphaVariance.Value.Value), RandomParameter.ActualValue);
     187      double beta = N(Beta.Value.Value, Math.Sqrt(BetaVariance.Value.Value), RandomParameter.ActualValue);
     188      double gamma = N(Gamma.Value.Value, Math.Sqrt(GammaVariance.Value.Value), RandomParameter.ActualValue);
    193189
    194190      double x0 = CoordinatesParameter.ActualValue[0, 0];
     
    203199      int indexOfCustomer = -1;
    204200
     201      int vehicles = VehiclesParameter.ActualValue.Value;
     202      DoubleMatrix coordinates = CoordinatesParameter.ActualValue;
     203      DoubleArray dueTime = DueTimeParameter.ActualValue;
     204      DoubleArray serviceTime = ServiceTimeParameter.ActualValue;
     205      DoubleArray readyTime = ReadyTimeParameter.ActualValue;
     206      DoubleArray demand = DemandParameter.ActualValue;
     207      DoubleValue capacity = CapacityParameter.ActualValue;
     208
     209      bool useDistanceMatrix = UseDistanceMatrixParameter.ActualValue.Value;
     210      if (useDistanceMatrix) {
     211        if (DistanceMatrixParameter.ActualValue == null) {
     212          DistanceMatrixParameter.ActualValue = CreateDistanceMatrix(coordinates);
     213        }
     214
     215        coordinates = DistanceMatrixParameter.ActualValue;
     216      }
     217
    205218      /*-----------------------------------------------------------------------------
    206219       * generate cost list
     
    208221       */
    209222      for (int i = 1; i <= Cities; i++) {
    210         distance = Distance(i, 0);
    211         if (CoordinatesParameter.ActualValue[i, 0] < x0) distance = -distance;
     223        distance = Distance(i, 0, coordinates, useDistanceMatrix);
     224        if (coordinates[i, 0] < x0) distance = -distance;
    212225        cost = -alpha * distance + // distance 0 <-> City[i]
    213226                 beta * (DueTimeParameter.ActualValue[i]) + // latest arrival time
    214                  gamma * (Math.Asin((CoordinatesParameter.ActualValue[i, 1] - y0) / distance) / 360 * distance); // polar angle
     227                 gamma * (Math.Asin((coordinates[i, 1] - y0) / distance) / 360 * distance); // polar angle
    215228
    216229        index = 0;
     
    229242      int customer = -1;
    230243      int subTourCount = 1;
    231       List<int> route = new List<int>(Cities + VehiclesParameter.ActualValue.Value - 1);
     244
     245      List<int> route = new List<int>(Cities + vehicles - 1);
    232246      minimumCost = double.MaxValue;
    233247      indexOfMinimumCost = -1;
     
    244258            route.Insert(i, (int)unroutedList[c]);
    245259            if (route[currentRoute] != 0) { throw new Exception("currentRoute not depot"); }
    246             cost = TravelDistance(route, currentRoute);
    247             if (cost < minimumCost && SubrouteConstraintsOK(route, currentRoute)) {
     260            cost = TravelDistance(route, currentRoute, coordinates, useDistanceMatrix);
     261            if (cost < minimumCost && SubrouteConstraintsOK(route, currentRoute, coordinates, useDistanceMatrix, dueTime, readyTime, serviceTime, demand, capacity)) {
    248262              minimumCost = cost;
    249263              indexOfMinimumCost = i;
     
    275289        customer = -1;
    276290      } while (unroutedList.Count > 0);
    277       while (route.Count < Cities + VehiclesParameter.ActualValue.Value - 1)
     291      while (route.Count < Cities + vehicles)
    278292        route.Add(0);
    279293
  • branches/GP.Grammar.Editor/HeuristicLab.Problems.VehicleRouting/3.3/Encodings/Potvin/Crossovers/PotvinCrossover.cs

    r5445 r6618  
    2626using HeuristicLab.Parameters;
    2727using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
     28using HeuristicLab.Data;
    2829
    2930namespace HeuristicLab.Problems.VehicleRouting.Encodings.Potvin {
     
    3334    public ILookupParameter<IRandom> RandomParameter {
    3435      get { return (LookupParameter<IRandom>)Parameters["Random"]; }
     36    }
     37
     38    public IValueParameter<BoolValue> AllowInfeasibleSolutions {
     39      get { return (IValueParameter<BoolValue>)Parameters["AllowInfeasibleSolutions"]; }
     40    }
     41
     42    [StorableHook(HookType.AfterDeserialization)]
     43    private void AfterDeserialization() {
     44      // BackwardsCompatibility3.3
     45      #region Backwards compatible code (remove with 3.4)
     46      if (!Parameters.ContainsKey("AllowInfeasibleSolutions")) {
     47        Parameters.Add(new ValueParameter<BoolValue>("AllowInfeasibleSolutions", "Indicates if infeasible solutions should be allowed.", new BoolValue(false)));
     48      }
     49      #endregion
    3550    }
    3651
     
    4358    public PotvinCrossover() {
    4459      Parameters.Add(new LookupParameter<IRandom>("Random", "The pseudo random number generator which should be used for stochastic manipulation operators."));
     60      Parameters.Add(new ValueParameter<BoolValue>("AllowInfeasibleSolutions", "Indicates if infeasible solutions should be allowed.", new BoolValue(false)));
    4561    }
    4662
    4763    protected abstract PotvinEncoding Crossover(IRandom random, PotvinEncoding parent1, PotvinEncoding parent2);
    4864
    49     protected bool FindInsertionPlace(PotvinEncoding individual, int city, out int route, out int place) {
     65    protected static bool FindInsertionPlace(PotvinEncoding individual, int city,
     66      DoubleArray dueTime, DoubleArray serviceTime, DoubleArray readyTime, DoubleArray demand,
     67      DoubleValue capacity, DistanceMatrix distMatrix, bool allowInfeasible,
     68      out int route, out int place) {
    5069      return individual.FindInsertionPlace(
    51         DueTimeParameter.ActualValue, ServiceTimeParameter.ActualValue, ReadyTimeParameter.ActualValue,
    52         DemandParameter.ActualValue, CapacityParameter.ActualValue, CoordinatesParameter.ActualValue,
    53         DistanceMatrixParameter, UseDistanceMatrixParameter.ActualValue,
    54         city, -1, out route, out place);
     70        dueTime, serviceTime, readyTime,
     71        demand, capacity, distMatrix,
     72        city, -1, allowInfeasible,
     73        out route, out place);
    5574    }
    5675
     
    6887    }
    6988
    70     protected bool Repair(IRandom random, PotvinEncoding solution, Tour newTour) {
     89    protected static bool RouteUnrouted(PotvinEncoding solution, DistanceMatrix distMatrix,
     90      DoubleArray dueTime, DoubleArray readyTime, DoubleArray serviceTime, DoubleArray demand, DoubleValue capacity, bool allowInfeasible) {
     91      bool success = true;
     92      int index = 0;
     93      while (index < solution.Unrouted.Count && success) {
     94        int unrouted = solution.Unrouted[index];
     95
     96        int route, place;
     97        if (FindInsertionPlace(solution, unrouted,
     98          dueTime, serviceTime, readyTime, demand, capacity,
     99          distMatrix, allowInfeasible,
     100          out route, out place)) {
     101          solution.Tours[route].Cities.Insert(place, unrouted);
     102        } else {
     103          success = false;
     104        }
     105
     106        index++;
     107      }
     108
     109      for (int i = 0; i < index; i++)
     110        solution.Unrouted.RemoveAt(0);
     111
     112      return success;
     113    }
     114
     115    protected static bool Repair(IRandom random, PotvinEncoding solution, Tour newTour, DistanceMatrix distmatrix,
     116      DoubleArray dueTime, DoubleArray readyTime, DoubleArray serviceTime, DoubleArray demand, DoubleValue capacity,
     117      bool allowInfeasible) {
    71118      bool success = true;
    72119
     
    104151      }
    105152
     153      if (!allowInfeasible && !newTour.Feasible(
     154        dueTime, serviceTime, readyTime, demand, capacity, distmatrix))
     155        return false;
     156
    106157      //route unrouted vehicles
    107       int index = 0;
    108       while (index < solution.Unrouted.Count && success) {
    109         int unrouted = solution.Unrouted[index];
    110 
    111         int route, place;
    112         if (FindInsertionPlace(solution, unrouted, out route, out place)) {
    113           solution.Tours[route].Cities.Insert(place, unrouted);
    114         } else {
    115           success = false;
    116         }
    117 
    118         index++;
    119       }
    120 
    121       for (int i = 0; i < index; i++)
    122         solution.Unrouted.RemoveAt(0);
     158      success = RouteUnrouted(solution, distmatrix, dueTime, readyTime, serviceTime, demand, capacity, allowInfeasible);
    123159
    124160      return success;
  • branches/GP.Grammar.Editor/HeuristicLab.Problems.VehicleRouting/3.3/Encodings/Potvin/Crossovers/PotvinRouteBasedCrossover.cs

    r5445 r6618  
    2323using HeuristicLab.Core;
    2424using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
     25using HeuristicLab.Data;
    2526
    2627namespace HeuristicLab.Problems.VehicleRouting.Encodings.Potvin {
     
    4041
    4142    protected override PotvinEncoding Crossover(IRandom random, PotvinEncoding parent1, PotvinEncoding parent2) {
     43      BoolValue useDistanceMatrix = UseDistanceMatrixParameter.ActualValue;
     44      DoubleMatrix coordinates = CoordinatesParameter.ActualValue;
     45      DistanceMatrix distMatrix = VRPUtilities.GetDistanceMatrix(coordinates, DistanceMatrixParameter, useDistanceMatrix);
     46      DoubleArray dueTime = DueTimeParameter.ActualValue;
     47      DoubleArray readyTime = ReadyTimeParameter.ActualValue;
     48      DoubleArray serviceTime = ServiceTimeParameter.ActualValue;
     49      DoubleArray demand = DemandParameter.ActualValue;
     50      DoubleValue capacity = CapacityParameter.ActualValue;
     51
     52      bool allowInfeasible = AllowInfeasibleSolutions.Value.Value;
     53
    4254      PotvinEncoding child = parent2.Clone() as PotvinEncoding;
    4355
     
    5567          child.Unrouted.Add(city);
    5668
    57       if (Repair(random, child, replacing))
     69      if (Repair(random, child, replacing, distMatrix, dueTime, readyTime, serviceTime, demand, capacity, allowInfeasible) || allowInfeasible)
    5870        return child;
    5971      else {
     
    6173          return parent1.Clone() as PotvinEncoding;
    6274        else
    63           return parent2.Clone() as PotvinEncoding;
     75          return parent2.Clone() as PotvinEncoding;   
    6476      }
    6577    }
  • branches/GP.Grammar.Editor/HeuristicLab.Problems.VehicleRouting/3.3/Encodings/Potvin/Crossovers/PotvinSequenceBasedCrossover.cs

    r5445 r6618  
    2323using HeuristicLab.Core;
    2424using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
     25using HeuristicLab.Data;
    2526
    2627namespace HeuristicLab.Problems.VehicleRouting.Encodings.Potvin {
     
    4142
    4243    protected override PotvinEncoding Crossover(IRandom random, PotvinEncoding parent1, PotvinEncoding parent2) {
     44      BoolValue useDistanceMatrix = UseDistanceMatrixParameter.ActualValue;
     45      DoubleMatrix coordinates = CoordinatesParameter.ActualValue;
     46      DistanceMatrix distMatrix = VRPUtilities.GetDistanceMatrix(coordinates, DistanceMatrixParameter, useDistanceMatrix);
     47      DoubleArray dueTime = DueTimeParameter.ActualValue;
     48      DoubleArray readyTime = ReadyTimeParameter.ActualValue;
     49      DoubleArray serviceTime = ServiceTimeParameter.ActualValue;
     50      DoubleArray demand = DemandParameter.ActualValue;
     51      DoubleValue capacity = CapacityParameter.ActualValue;
     52
     53      bool allowInfeasible = AllowInfeasibleSolutions.Value.Value;
     54
    4355      PotvinEncoding child = parent1.Clone() as PotvinEncoding;
    4456      Tour newTour = new Tour();
     
    6981          child.Unrouted.Add(city);
    7082
    71       if (Feasible(newTour) &&
    72           Repair(random, child, newTour)) {
     83      if (Repair(random, child, newTour, distMatrix, dueTime, readyTime, serviceTime, demand, capacity, allowInfeasible) || allowInfeasible) {
    7384        return child;
    7485      } else {
    75         if (random.NextDouble() < 0.5)
     86         if (random.NextDouble() < 0.5)
    7687          return parent1.Clone() as PotvinEncoding;
    7788        else
    78           return parent2.Clone() as PotvinEncoding;
     89          return parent2.Clone() as PotvinEncoding;   
    7990      }
    8091    }
  • branches/GP.Grammar.Editor/HeuristicLab.Problems.VehicleRouting/3.3/Encodings/Potvin/Manipulators/PotvinLocalSearchManipulator.cs

    r5445 r6618  
    4949
    5050    private bool FindBetterInsertionPlace(
    51       PotvinEncoding individual, int tour, int city, int length,
     51      PotvinEncoding individual, 
     52      DoubleArray dueTime, DoubleArray readyTime, DoubleArray serviceTime, DoubleArray demand,
     53      DoubleValue capacity, DistanceMatrix distMatrix,
     54      int tour, int city, int length,
    5255      out int insertionTour, out int insertionPlace) {
    5356      bool insertionFound = false;
     
    5659
    5760      List<int> toBeDeleted = individual.Tours[tour].Cities.GetRange(city, length);
    58       double distance = GetLength(individual.Tours[tour]);
     61      double distance = individual.Tours[tour].GetLength(distMatrix);
    5962      individual.Tours[tour].Cities.RemoveRange(city, length);
    60       double removalBenefit = distance - GetLength(individual.Tours[tour]);
     63      double removalBenefit = distance - individual.Tours[tour].GetLength(distMatrix);
    6164
    6265      int currentTour = 0;
     
    6467        int currentCity = 0;
    6568        while (currentCity <= individual.Tours[currentTour].Cities.Count && !insertionFound) {
    66           distance = GetLength(individual.Tours[currentTour]);
     69          distance = individual.Tours[currentTour].GetLength(distMatrix);
    6770          individual.Tours[currentTour].Cities.InsertRange(currentCity, toBeDeleted);
    68           if (Feasible(individual.Tours[currentTour])) {
     71          if (individual.Tours[currentTour].Feasible(dueTime, serviceTime, readyTime, demand, capacity, distMatrix)) {
    6972            double lengthIncrease =
    70               GetLength(individual.Tours[currentTour]) - distance;
     73              individual.Tours[currentTour].GetLength(distMatrix) - distance;
    7174            if (removalBenefit > lengthIncrease) {
    7275              insertionTour = currentTour;
     
    8386      }
    8487
    85       individual.Tours[tour].Cities.InsertRange(city, toBeDeleted);
     88      individual.Tours[tour].Cities.InsertRange(city, toBeDeleted); 
    8689
    8790      return insertionFound;
     
    8992
    9093    protected override void Manipulate(IRandom random, PotvinEncoding individual) {
     94      BoolValue useDistanceMatrix = UseDistanceMatrixParameter.ActualValue;
     95      DoubleMatrix coordinates = CoordinatesParameter.ActualValue;
     96      DistanceMatrix distMatrix = VRPUtilities.GetDistanceMatrix(coordinates, DistanceMatrixParameter, useDistanceMatrix);
     97      DoubleArray dueTime = DueTimeParameter.ActualValue;
     98      DoubleArray readyTime = ReadyTimeParameter.ActualValue;
     99      DoubleArray serviceTime = ServiceTimeParameter.ActualValue;
     100      DoubleArray demand = DemandParameter.ActualValue;
     101      DoubleValue capacity = CapacityParameter.ActualValue;
     102     
    91103      //only apply to feasible individuals
    92       if (Feasible(individual)) {
     104      bool feasible = true;
     105
     106      foreach (Tour tour in individual.Tours) {
     107        if (!tour.Feasible(dueTime, serviceTime, readyTime, demand, capacity, distMatrix)) {
     108          feasible = false;
     109          break;
     110        }
     111      }
     112
     113      if (feasible) {
    93114        bool insertionFound;
    94115        int iterations = 0;
     
    103124              while (city <= individual.Tours[tour].Cities.Count - length && !insertionFound) {
    104125                int insertionTour, insertionPlace;
    105                 if (FindBetterInsertionPlace(individual, tour, city, length,
     126                if (FindBetterInsertionPlace(individual, dueTime, readyTime, serviceTime, demand, capacity, distMatrix,
     127                  tour, city, length,
    106128                 out insertionTour, out insertionPlace)) {
    107129                  insertionFound = true;
  • branches/GP.Grammar.Editor/HeuristicLab.Problems.VehicleRouting/3.3/Encodings/Potvin/Manipulators/PotvinManipulator.cs

    r5445 r6618  
    2525using HeuristicLab.Parameters;
    2626using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
     27using HeuristicLab.Data;
    2728
    2829namespace HeuristicLab.Problems.VehicleRouting.Encodings.Potvin {
     
    3435    }
    3536
     37    public IValueParameter<BoolValue> AllowInfeasibleSolutions {
     38      get { return (IValueParameter<BoolValue>)Parameters["AllowInfeasibleSolutions"]; }
     39    }
     40
     41    [StorableHook(HookType.AfterDeserialization)]
     42    private void AfterDeserialization() {
     43      // BackwardsCompatibility3.3
     44      #region Backwards compatible code (remove with 3.4)
     45      if (!Parameters.ContainsKey("AllowInfeasibleSolutions")) {
     46        Parameters.Add(new ValueParameter<BoolValue>("AllowInfeasibleSolutions", "Indicates if infeasible solutions should be allowed.", new BoolValue(false)));
     47      }
     48      #endregion
     49    }
     50
    3651    [StorableConstructor]
    3752    protected PotvinManipulator(bool deserializing) : base(deserializing) { }
     
    4156    public PotvinManipulator() {
    4257      Parameters.Add(new LookupParameter<IRandom>("Random", "The pseudo random number generator which should be used for stochastic manipulation operators."));
     58      Parameters.Add(new ValueParameter<BoolValue>("AllowInfeasibleSolutions", "Indicates if infeasible solutions should be allowed.", new BoolValue(false)));
    4359    }
    4460
    4561    protected abstract void Manipulate(IRandom random, PotvinEncoding individual);
    4662
    47     protected int SelectRandomTourBiasedByLength(IRandom random, PotvinEncoding individual) {
     63    protected static int SelectRandomTourBiasedByLength(IRandom random, PotvinEncoding individual) {
    4864      int tourIndex = -1;
    4965
     
    5167      double[] probabilities = new double[individual.Tours.Count];
    5268      for (int i = 0; i < individual.Tours.Count; i++) {
    53         probabilities[i] = 1.0 / ((double)individual.Tours[i].Cities.Count / (double)Cities);
     69        probabilities[i] = 1.0 / ((double)individual.Tours[i].Cities.Count / (double)individual.Cities);
    5470        sum += probabilities[i];
    5571      }
     
    7288    }
    7389
    74     protected bool FindInsertionPlace(PotvinEncoding individual, int city, int routeToAvoid, out int route, out int place) {
     90    protected static bool FindInsertionPlace(PotvinEncoding individual, int city, int routeToAvoid,
     91      DoubleArray dueTime, DoubleArray serviceTime, DoubleArray readyTime, DoubleArray demand,
     92      DoubleValue capacity, DistanceMatrix distMatrix,  bool allowInfeasible,
     93      out int route, out int place) {
    7594      return individual.FindInsertionPlace(
    76         DueTimeParameter.ActualValue, ServiceTimeParameter.ActualValue, ReadyTimeParameter.ActualValue,
    77         DemandParameter.ActualValue, CapacityParameter.ActualValue, CoordinatesParameter.ActualValue,
    78         DistanceMatrixParameter, UseDistanceMatrixParameter.ActualValue,
    79         city, routeToAvoid, out route, out place);
     95        dueTime, serviceTime, readyTime,
     96        demand, capacity, distMatrix,
     97        city, routeToAvoid, allowInfeasible,
     98        out route, out place);
    8099    }
     100     
    81101
    82102    public override IOperation Apply() {
  • branches/GP.Grammar.Editor/HeuristicLab.Problems.VehicleRouting/3.3/Encodings/Potvin/Manipulators/PotvinOneLevelExchangeManipulator.cs

    r5445 r6618  
    2424using HeuristicLab.Core;
    2525using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
     26using HeuristicLab.Data;
    2627
    2728namespace HeuristicLab.Problems.VehicleRouting.Encodings.Potvin {
     
    3940    public PotvinOneLevelExchangeMainpulator() : base() { }
    4041
    41     protected override void Manipulate(IRandom random, PotvinEncoding individual) {
     42    public static void Apply(IRandom random, PotvinEncoding individual,
     43     DoubleArray dueTime, DoubleArray readyTime, DoubleArray serviceTime, DoubleArray demand,
     44      DoubleValue capacity, DistanceMatrix distMatrix, bool allowInfeasible) {
    4245      int selectedIndex = SelectRandomTourBiasedByLength(random, individual);
    4346      Tour route1 =
     
    4851        int insertedRoute, insertedPlace;
    4952
    50         if (FindInsertionPlace(individual, route1.Cities[i], selectedIndex, out insertedRoute, out insertedPlace)) {
     53        if (FindInsertionPlace(individual, route1.Cities[i], selectedIndex,
     54          dueTime, serviceTime, readyTime, demand, capacity,
     55          distMatrix, allowInfeasible,
     56          out insertedRoute, out insertedPlace)) {
    5157          individual.Tours[insertedRoute].Cities.Insert(insertedPlace, route1.Cities[i]);
    5258          replaced.Add(route1.Cities[i]);
     
    6571        individual.Tours.Remove(route1);
    6672    }
     73
     74    protected override void Manipulate(IRandom random, PotvinEncoding individual) {
     75      BoolValue useDistanceMatrix = UseDistanceMatrixParameter.ActualValue;
     76      DoubleMatrix coordinates = CoordinatesParameter.ActualValue;
     77      DistanceMatrix distMatrix = VRPUtilities.GetDistanceMatrix(coordinates, DistanceMatrixParameter, useDistanceMatrix);
     78      DoubleArray dueTime = DueTimeParameter.ActualValue;
     79      DoubleArray readyTime = ReadyTimeParameter.ActualValue;
     80      DoubleArray serviceTime = ServiceTimeParameter.ActualValue;
     81      DoubleArray demand = DemandParameter.ActualValue;
     82      DoubleValue capacity = CapacityParameter.ActualValue;
     83
     84      bool allowInfeasible = AllowInfeasibleSolutions.Value.Value;
     85
     86      Apply(random, individual, dueTime, readyTime, serviceTime, demand, capacity, distMatrix, allowInfeasible);
     87    }
    6788  }
    6889}
  • branches/GP.Grammar.Editor/HeuristicLab.Problems.VehicleRouting/3.3/Encodings/Potvin/Manipulators/PotvinTwoLevelExchangeManipulator.cs

    r5445 r6618  
    2323using HeuristicLab.Core;
    2424using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
     25using HeuristicLab.Data;
    2526
    2627namespace HeuristicLab.Problems.VehicleRouting.Encodings.Potvin {
     
    3637    public PotvinTwoLevelExchangeManipulator() : base() { }
    3738
    38     protected override void Manipulate(IRandom random, PotvinEncoding individual) {
     39    public static void Apply(IRandom random, PotvinEncoding individual,
     40      DoubleArray dueTime, DoubleArray readyTime, DoubleArray serviceTime, DoubleArray demand,
     41      DoubleValue capacity, DistanceMatrix distMatrix, bool allowInfeasible) {
    3942      int selectedIndex = SelectRandomTourBiasedByLength(random, individual);
    40       Tour route1 = individual.Tours[selectedIndex]; 
     43      Tour route1 = individual.Tours[selectedIndex];
    4144
    4245      bool performed = false;
     
    5356              //customer1 can be feasibly inserted at the location of customer2
    5457              tour.Cities[customer2Position] = customer1;
    55               if (Feasible(tour)) {
     58              if (tour.Feasible(dueTime, serviceTime, readyTime, demand, capacity, distMatrix)) {
    5659                int routeIdx, place;
    5760                if (FindInsertionPlace(individual,
    58                   customer2, selectedIndex, out routeIdx, out place)) {
    59                     individual.Tours[routeIdx].Cities.Insert(place, customer2);
    60                     route1.Cities.RemoveAt(customer1Position);
     61                  customer2, selectedIndex,
     62                  dueTime, serviceTime, readyTime, demand, capacity,
     63                  distMatrix, allowInfeasible,
     64                  out routeIdx, out place)) {
     65                  individual.Tours[routeIdx].Cities.Insert(place, customer2);
     66                  route1.Cities.RemoveAt(customer1Position);
    6167
    62                     if (route1.Cities.Count == 0)
     68                  if (route1.Cities.Count == 0)
    6369                    individual.Tours.Remove(route1);
    6470
     
    8389      }
    8490    }
     91
     92    protected override void Manipulate(IRandom random, PotvinEncoding individual) {
     93      BoolValue useDistanceMatrix = UseDistanceMatrixParameter.ActualValue;
     94      DoubleMatrix coordinates = CoordinatesParameter.ActualValue;
     95      DistanceMatrix distMatrix = VRPUtilities.GetDistanceMatrix(coordinates, DistanceMatrixParameter, useDistanceMatrix);
     96      DoubleArray dueTime = DueTimeParameter.ActualValue;
     97      DoubleArray readyTime = ReadyTimeParameter.ActualValue;
     98      DoubleArray serviceTime = ServiceTimeParameter.ActualValue;
     99      DoubleArray demand = DemandParameter.ActualValue;
     100      DoubleValue capacity = CapacityParameter.ActualValue;
     101
     102      bool allowInfeasible = AllowInfeasibleSolutions.Value.Value;
     103
     104      Apply(random, individual, dueTime, readyTime, serviceTime, demand, capacity, distMatrix, allowInfeasible);
     105    }
    85106  }
    86107}
  • branches/GP.Grammar.Editor/HeuristicLab.Problems.VehicleRouting/3.3/Encodings/Potvin/PotvinEncoding.cs

    r5445 r6618  
    6969      DoubleArray dueTimeArray,
    7070      DoubleArray serviceTimeArray, DoubleArray readyTimeArray, DoubleArray demandArray, DoubleValue capacity,
    71       DoubleMatrix coordinates, ILookupParameter<DoubleMatrix> distanceMatrix, BoolValue useDistanceMatrix,
    72       int city, int routeToAvoid, out int route, out int place) {
     71      DistanceMatrix distMatrix,
     72      int city, int routeToAvoid, bool allowInfeasible,
     73      out int route, out int place) {
    7374      route = -1;
    7475      place = -1;
    75       double minDetour = 0;
     76      bool bestFeasible = false;
     77      double minDetour = double.MaxValue;
    7678
    7779      for (int tour = 0; tour < Tours.Count; tour++) {
    7880        if (tour != routeToAvoid) {
    7981          for (int i = 0; i <= Tours[tour].Cities.Count; i++) {
    80             double length = Tours[tour].GetLength(coordinates, distanceMatrix, useDistanceMatrix);
     82            double length = Tours[tour].GetLength(distMatrix);
    8183
    8284            Tours[tour].Cities.Insert(i, city);
    8385
    84             if (Tours[tour].Feasible(dueTimeArray, serviceTimeArray, readyTimeArray, demandArray,
    85               capacity, coordinates, distanceMatrix, useDistanceMatrix)) {
    86               double newLength = Tours[tour].GetLength(coordinates, distanceMatrix, useDistanceMatrix);
     86            bool feasible = Tours[tour].Feasible(dueTimeArray, serviceTimeArray, readyTimeArray, demandArray,
     87              capacity, distMatrix);
    8788
     89            if (feasible || allowInfeasible && !bestFeasible) {
     90              double newLength = Tours[tour].GetLength(distMatrix);
    8891              double detour = newLength - length;
    8992
    90               if (route <= 0 || detour < minDetour) {
     93              if (route < 0 || detour < minDetour || feasible && !bestFeasible) {
    9194                route = tour;
    9295                place = i;
    9396                minDetour = detour;
     97
     98                if (feasible)
     99                  bestFeasible = true;
    94100              }
    95101            }
  • branches/GP.Grammar.Editor/HeuristicLab.Problems.VehicleRouting/3.3/Encodings/Prins/Crossovers/PrinsPermutationCrossover.cs

    r5445 r6618  
    4646
    4747    protected override PrinsEncoding Crossover(IRandom random, PrinsEncoding parent1, PrinsEncoding parent2) {
    48       //note - the inner crossover is called here and the result is converted to a prins representation
     48      //note - the inner crossover is called here and the solution is converted to a prins representation
    4949      //some refactoring should be done here in the future - the crossover operation should be called directly
    5050
    51       InnerCrossoverParameter.ActualValue.ParentsParameter.ActualName = ParentsParameter.ActualName;
    52       IAtomicOperation op = this.ExecutionContext.CreateOperation(
    53         InnerCrossoverParameter.ActualValue, this.ExecutionContext.Scope);
    54       op.Operator.Execute((IExecutionContext)op, CancellationToken);
     51      if (parent1.Length == parent2.Length) {
     52        InnerCrossoverParameter.ActualValue.ParentsParameter.ActualName = ParentsParameter.ActualName;
     53        IAtomicOperation op = this.ExecutionContext.CreateOperation(
     54          InnerCrossoverParameter.ActualValue, this.ExecutionContext.Scope);
     55        op.Operator.Execute((IExecutionContext)op, CancellationToken);
    5556
    56       string childName = InnerCrossoverParameter.ActualValue.ChildParameter.ActualName;
    57       if (ExecutionContext.Scope.Variables.ContainsKey(childName)) {
    58         Permutation permutation = ExecutionContext.Scope.Variables[childName].Value as Permutation;
    59         ExecutionContext.Scope.Variables.Remove(childName);
     57        string childName = InnerCrossoverParameter.ActualValue.ChildParameter.ActualName;
     58        if (ExecutionContext.Scope.Variables.ContainsKey(childName)) {
     59          Permutation permutation = ExecutionContext.Scope.Variables[childName].Value as Permutation;
     60          ExecutionContext.Scope.Variables.Remove(childName);
    6061
    61         return new PrinsEncoding(permutation, Cities,
    62           DueTimeParameter.ActualValue,
    63             ServiceTimeParameter.ActualValue,
    64             ReadyTimeParameter.ActualValue,
    65             DemandParameter.ActualValue,
    66             CapacityParameter.ActualValue,
    67             FleetUsageFactor.ActualValue,
    68             TimeFactor.ActualValue,
    69             DistanceFactor.ActualValue,
    70             OverloadPenalty.ActualValue,
    71             TardinessPenalty.ActualValue,
    72             CoordinatesParameter.ActualValue,
    73             UseDistanceMatrixParameter.ActualValue);
    74       } else
    75         return null;
     62          return new PrinsEncoding(permutation, Cities,
     63            DueTimeParameter.ActualValue,
     64              ServiceTimeParameter.ActualValue,
     65              ReadyTimeParameter.ActualValue,
     66              DemandParameter.ActualValue,
     67              CapacityParameter.ActualValue,
     68              FleetUsageFactor.ActualValue,
     69              TimeFactor.ActualValue,
     70              DistanceFactor.ActualValue,
     71              OverloadPenalty.ActualValue,
     72              TardinessPenalty.ActualValue,
     73              CoordinatesParameter.ActualValue,
     74              UseDistanceMatrixParameter.ActualValue);
     75        } else
     76          return null;
     77      } else {
     78        return parent1.Clone() as PrinsEncoding;
     79      }
    7680    }
    7781  }
  • branches/GP.Grammar.Editor/HeuristicLab.Problems.VehicleRouting/3.3/Encodings/Prins/PrinsEncoding.cs

    r5445 r6618  
    7575    public override List<Tour> GetTours(ILookupParameter<DoubleMatrix> distanceMatrix, int maxVehicles = int.MaxValue) {
    7676      List<Tour> result = new List<Tour>();
     77
     78      DistanceMatrix distMatrix = VRPUtilities.GetDistanceMatrix(coordinates, distanceMatrix, useDistanceMatrix);
    7779
    7880      //Split permutation into vector P
     
    106108            overloadPenalty,
    107109            tardinessPenalty,
    108             coordinates,
    109             distanceMatrix,
    110             useDistanceMatrix);
     110            distMatrix);
    111111
    112112          double cost = eval.Quality;
  • branches/GP.Grammar.Editor/HeuristicLab.Problems.VehicleRouting/3.3/Encodings/Tour.cs

    r5445 r6618  
    4848    public bool Feasible(DoubleArray dueTimeArray,
    4949      DoubleArray serviceTimeArray, DoubleArray readyTimeArray, DoubleArray demandArray, DoubleValue capacity,
    50       DoubleMatrix coordinates, ILookupParameter<DoubleMatrix> distanceMatrix, BoolValue useDistanceMatrix) {
     50      DistanceMatrix distMatrix) {
    5151      TourEvaluation eval = VRPEvaluator.EvaluateTour(this,
    5252        dueTimeArray,
     
    6060        new DoubleValue(1),
    6161        new DoubleValue(1),
    62         coordinates,
    63         distanceMatrix,
    64         useDistanceMatrix);
     62        distMatrix);
    6563
    6664      return eval.Overload < double.Epsilon && eval.Tardiness < double.Epsilon;
    6765    }
    6866
    69     public double GetLength(DoubleMatrix coordinates,
    70       ILookupParameter<DoubleMatrix> distanceMatrix,
    71       BoolValue useDistanceMatrix) {
     67    public double GetLength(DistanceMatrix distMatrix) {
    7268      double length = 0;
    7369
     
    8278        for (int i = 1; i < cities.Count; i++) {
    8379          length += VRPUtilities.GetDistance(
    84             cities[i - 1], cities[i], coordinates, distanceMatrix, useDistanceMatrix);
     80            cities[i - 1], cities[i], distMatrix);
    8581        }
    8682      }
  • branches/GP.Grammar.Editor/HeuristicLab.Problems.VehicleRouting/3.3/Encodings/Zhu/Crossovers/ZhuPermutationCrossover.cs

    r5445 r6618  
    4848
    4949    protected override ZhuEncoding Crossover(IRandom random, ZhuEncoding parent1, ZhuEncoding parent2) {
    50       //note - the inner crossover is called here and the result is converted to a prins representation
     50      //note - the inner crossover is called here and the solution is converted to a prins representation
    5151      //some refactoring should be done here in the future - the crossover operation should be called directly
    5252
    53       InnerCrossoverParameter.ActualValue.ParentsParameter.ActualName = ParentsParameter.ActualName;
    54       IAtomicOperation op = this.ExecutionContext.CreateOperation(
    55         InnerCrossoverParameter.ActualValue, this.ExecutionContext.Scope);
    56       op.Operator.Execute((IExecutionContext)op, CancellationToken);
     53      if (parent1.Length == parent2.Length) {
     54        InnerCrossoverParameter.ActualValue.ParentsParameter.ActualName = ParentsParameter.ActualName;
     55        IAtomicOperation op = this.ExecutionContext.CreateOperation(
     56          InnerCrossoverParameter.ActualValue, this.ExecutionContext.Scope);
     57        op.Operator.Execute((IExecutionContext)op, CancellationToken);
    5758
    58       string childName = InnerCrossoverParameter.ActualValue.ChildParameter.ActualName;
    59       if (ExecutionContext.Scope.Variables.ContainsKey(childName)) {
    60         Permutation permutation = ExecutionContext.Scope.Variables[childName].Value as Permutation;
    61         ExecutionContext.Scope.Variables.Remove(childName);
     59        string childName = InnerCrossoverParameter.ActualValue.ChildParameter.ActualName;
     60        if (ExecutionContext.Scope.Variables.ContainsKey(childName)) {
     61          Permutation permutation = ExecutionContext.Scope.Variables[childName].Value as Permutation;
     62          ExecutionContext.Scope.Variables.Remove(childName);
    6263
    63         return new ZhuEncoding(permutation, Cities,
    64           DueTimeParameter.ActualValue,
    65             ServiceTimeParameter.ActualValue,
    66             ReadyTimeParameter.ActualValue,
    67             DemandParameter.ActualValue,
    68             CapacityParameter.ActualValue,
    69             CoordinatesParameter.ActualValue,
    70             UseDistanceMatrixParameter.ActualValue);
    71       } else
    72         return null;
     64          return new ZhuEncoding(permutation, Cities,
     65            DueTimeParameter.ActualValue,
     66              ServiceTimeParameter.ActualValue,
     67              ReadyTimeParameter.ActualValue,
     68              DemandParameter.ActualValue,
     69              CapacityParameter.ActualValue,
     70              CoordinatesParameter.ActualValue,
     71              UseDistanceMatrixParameter.ActualValue);
     72        } else
     73          return null;
     74      } else {
     75        return parent1.Clone() as ZhuEncoding;
     76      }
    7377    }
    7478  }
  • branches/GP.Grammar.Editor/HeuristicLab.Problems.VehicleRouting/3.3/Encodings/Zhu/ZhuEncoding.cs

    r5445 r6618  
    6363      Tour newTour = new Tour();
    6464
     65      DistanceMatrix distMatrix = VRPUtilities.GetDistanceMatrix(coordinates, distanceMatrix, useDistanceMatrix);
     66
    6567      for (int i = 0; i < this.Length; i++) {
    6668        int city = this[i] + 1;
     
    7274          demandArray,
    7375          capacity,
    74           coordinates,
    75           distanceMatrix,
    76           useDistanceMatrix)) {
     76          distMatrix)) {
    7777          newTour.Cities.Remove(city);
    7878          if (newTour.Cities.Count > 0)
Note: See TracChangeset for help on using the changeset viewer.