public static LinearLinkage Apply(IRandom random, LinearLinkage p1, LinearLinkage p2) {
   var length = p1.Length;
   var child = new LinearLinkage(length);
   var endNodes = new HashSet<int>();
   for (var i = 0; i < length; i++) {
     if ((p1[i] == i && p2[i] == i)
       || ((p1[i] == i || p2[i] == i) && random.NextDouble() < 0.5)) {
       child[i] = i;
       endNodes.Add(i);
     }
   }
   for (var i = 0; i < length; i++) {
     if (endNodes.Contains(i)) continue;
     var p1End = endNodes.Contains(p1[i]);
     var p2End = endNodes.Contains(p2[i]);
     if ((p1End && p2End) || (!p1End && !p2End)) {
       child[i] = random.NextDouble() < 0.5 ? p1[i] : p2[i];
     } else if (p1End) {
       child[i] = p1[i];
     } else {
       child[i] = p2[i];
     }
   }
   child.LinearizeTreeStructures();
   return child;
 }
    /// <summary>
    /// Performs a breeder genetic algorithm manipulation on the given <paramref name="vector"/>.
    /// </summary>
    /// <param name="random">A random number generator.</param>
    /// <param name="vector">The real vector to manipulate.</param>
    /// <param name="bounds">The lower and upper bound (1st and 2nd column) of the positions in the vector. If there are less rows than dimensions, the rows are cycled.</param>
    /// <param name="searchIntervalFactor">The factor determining the size of the search interval.</param>
    public static void Apply(IRandom random, RealVector vector, DoubleMatrix bounds, DoubleValue searchIntervalFactor) {
      int length = vector.Length;
      double prob, value;
      do {
        value = Sigma(random);
      } while (value == 0);

      prob = 1.0 / (double)length;
      bool wasMutated = false;

      for (int i = 0; i < length; i++) {
        if (random.NextDouble() < prob) {
          double range = bounds[i % bounds.Rows, 1] - bounds[i % bounds.Rows, 0];
          if (random.NextDouble() < 0.5) {
            vector[i] = vector[i] + value * searchIntervalFactor.Value * range;
          } else {
            vector[i] = vector[i] - value * searchIntervalFactor.Value * range;
          }
          wasMutated = true;
        }
      }

      // make sure at least one gene was mutated
      if (!wasMutated) {
        int pos = random.Next(length);
        double range = bounds[pos % bounds.Rows, 1] - bounds[pos % bounds.Rows, 0];
        if (random.NextDouble() < 0.5) {
          vector[pos] = vector[pos] + value * searchIntervalFactor.Value * range;
        } else {
          vector[pos] = vector[pos] - value * searchIntervalFactor.Value * range;
        }
      }
    }
    /// <summary>Returns a random point on the surface of a cylinder</summary>
    /// <param name="randomNumberGenerator">Random number generator that will be used</param>
    /// <param name="orientation">Orientation of the cylinder</param>
    /// <param name="radius">Radius of the cylinder</param>
    /// <param name="length">Length of the cylinder</param>
    /// <returns>A random point on the volume's surface</returns>
    public static Vector3 GenerateRandomPointOnSurface(
      IRandom randomNumberGenerator,
      Matrix orientation, float radius, float length
    ) {

      // Calculate the surface areas of the three sections our cylinder has:
      // Upper cap, side and lower cap
      float capArea = MathHelper.Pi * (radius * radius);
      float sideArea = 2.0f * MathHelper.Pi * radius * length;
      float capAndSideArea = capArea + sideArea;

      // We need a phi value (angle of the random point) in any of the cases
      float phi = (float)randomNumberGenerator.NextDouble() * MathHelper.TwoPi;

      // Choose the section that the random point will be generated on in relation
      // to its surface area so the probability is constant on the entire surface
      float section = (float)randomNumberGenerator.NextDouble() * (capArea * 2.0f + sideArea);

      // Depending on the section, these two values are calculated differently
      float randomRadius;
      float randomZ;

      // Upper cap: Generate a random radius
      if(section < capArea) {
        randomZ = length / 2.0f;
        randomRadius = (float)Math.Sqrt(randomNumberGenerator.NextDouble()) * radius;

      // Side: Generate a random height
      } else if(section < capAndSideArea) {
        randomZ = ((float)randomNumberGenerator.NextDouble() - 0.5f) * length;
        randomRadius = radius;

      // Lower cap: Generate a random radius
      } else {
        randomZ = -length / 2.0f;
        randomRadius = (float)Math.Sqrt(randomNumberGenerator.NextDouble()) * radius;
      }

      // Now transform the point to cartesian coordinates and rotate it into
      // the global coordinate frame
      return Vector3.Transform(
        new Vector3(
          randomRadius * (float)Math.Cos(phi),
          randomRadius * (float)Math.Sin(phi),
          randomZ
        ),
        orientation
      );

    }
 private DoubleArray Randomize(IRandom random, int length, DoubleMatrix bounds) {
   var result = new DoubleArray(length);
   for (int i = 0; i < length; i++) {
     result[i] = random.NextDouble() * bounds[i % bounds.Rows, 1] - bounds[i % bounds.Rows, 0];
   }
   return result;
 }
 /// <summary>
 /// Performs the some positions bitflip mutation on a binary vector.
 /// </summary>
 /// <param name="random">The random number generator to use.</param>
 /// <param name="vector">The vector that should be manipulated.</param>
 /// <param name="pm">The probability a bit is flipped.</param>
 public static void Apply(IRandom random, BinaryVector vector, DoubleValue pm) {
   for (int i = 0; i < vector.Length; i++) {
     if (random.NextDouble() < pm.Value) {
       vector[i] = !vector[i];
     }
   }
 }
    protected static int SelectRandomTourBiasedByLength(IRandom random, PotvinEncoding individual, IVRPProblemInstance instance) {
      int tourIndex = -1;

      double sum = 0.0;
      double[] probabilities = new double[individual.Tours.Count];
      for (int i = 0; i < individual.Tours.Count; i++) {
        probabilities[i] = 1.0 / ((double)individual.Tours[i].Stops.Count / (double)instance.Cities.Value);
        sum += probabilities[i];
      }

      for (int i = 0; i < probabilities.Length; i++)
        probabilities[i] = probabilities[i] / sum;

      double rand = random.NextDouble();
      double cumulatedProbabilities = 0.0;
      int index = 0;
      while (tourIndex == -1 && index < probabilities.Length) {
        if (cumulatedProbabilities <= rand && rand <= cumulatedProbabilities + probabilities[index])
          tourIndex = index;

        cumulatedProbabilities += probabilities[index];
        index++;
      }

      return tourIndex;
    }
Example #7
0
 public override void ShakeLocalParameters(IRandom random, double shakingFactor) {
   // mutation
   var d = random.NextDouble() * 2.0 - 1.0;
   value += shakingFactor * d;
   if (value < 0.1) value = 0.1;
   if (value > 3) value = 3;
 }
    /// <summary>Returns a random point within a disc</summary>
    /// <param name="randomNumberGenerator">Random number generator that will be used</param>
    /// <param name="radius">Radius of the disc</param>
    /// <returns>A random point within the disc</returns>
    public static Vector2 GenerateRandomPointWithin(
      IRandom randomNumberGenerator, float radius
    ) {

      // Choose a random angle for the point
      float phi = (float)randomNumberGenerator.NextDouble() * MathHelper.Pi * 2.0f;

      // Get a random radius with compensated probability for the outer regions of the disc
      float r = (float)Math.Sqrt(randomNumberGenerator.NextDouble()) * radius;

      // Calculate the final position of the point in world space
      return new Vector2(
        r * (float)Math.Cos(phi),
        r * (float)Math.Sin(phi));

    }
Example #9
0
 public virtual void Randomize(IRandom random, int startIndex, int length, double min, double max) {
   double delta = max - min;
   if (length > 0) {
     for (int i = 0; i < length; i++)
       array[startIndex + i] = min + delta * random.NextDouble();
     OnReset();
   }
 }
    /// <summary>Returns a random point on the surface of a box</summary>
    /// <param name="randomNumberGenerator">Random number generator that will be used</param>
    /// <param name="extents">Extents of the box</param>
    /// <returns>A random point on the box' surface</returns>
    /// <remarks>
    ///   The performance of this algorithm varies slightly depending on the face
    ///   that is chosen for the random point because a different number of
    ///   comparisons and subtractions will be performed.
    /// </remarks>
    public static Vector3 GenerateRandomPointOnSurface(
      IRandom randomNumberGenerator, Vector3 extents
    ) {

      // For this task, we also need the dimensions of the box
      Vector3 dimensions = extents * 2.0f;

      // Determine the area covered by the sides of the box
      float leftRightArea = dimensions.Z * dimensions.Y;
      float topBottomArea = dimensions.X * dimensions.Z;
      float frontBackArea = dimensions.X * dimensions.Y;

      // Choose which face of the box the point is going be on
      float side = (float)randomNumberGenerator.NextDouble() *
        (leftRightArea * 2.0f) * (topBottomArea * 2.0f) * (frontBackArea * 2.0f);

      // Now obtain were the point will be located
      float u = (float)randomNumberGenerator.NextDouble() * 2.0f - 1.0f;
      float v = (float)randomNumberGenerator.NextDouble() * 2.0f - 1.0f;

      // Calculate the final world space coordinates of the point
      side -= leftRightArea;
      if(side < 0.0)
        return new Vector3(-extents.X, v * extents.Y, u * extents.Z);

      side -= leftRightArea;
      if(side < 0.0)
        return new Vector3(+extents.X, v * extents.Y, u * extents.Z);

      side -= topBottomArea;
      if(side < 0.0)
        return new Vector3(u * extents.X, +extents.Y, v * extents.Z);

      side -= topBottomArea;
      if(side < 0.0)
        return new Vector3(u * extents.X, -extents.Y, v * extents.Z);

      side -= frontBackArea;
      if(side < 0.0)
        return new Vector3(u * extents.X, v * extents.Y, -extents.Z);

      else
        return new Vector3(u * extents.X, v * extents.Y, +extents.Z);
    }
Example #11
0
 public virtual void Randomize(IRandom random, int startIndex, int length, DoubleMatrix bounds) {
   if (length > 0) {
     for (int i = startIndex; i < startIndex + length; i++) {
       double min = bounds[i % bounds.Rows, 0];
       double max = bounds[i % bounds.Rows, 1];
       array[i] = min + (max - min) * random.NextDouble();
     }
     OnReset();
   }
 }
 public override void ShakeLocalParameters(IRandom random, double shakingFactor) {
   base.ShakeLocalParameters(random, shakingFactor);
   // 50% additive & 50% multiplicative
   if (random.NextDouble() < 0.5) {
     double x = NormalDistributedRandom.NextDouble(random, Symbol.ManipulatorMu, Symbol.ManipulatorSigma);
     Value = Value + x * shakingFactor;
   } else {
     double x = NormalDistributedRandom.NextDouble(random, 1.0, Symbol.MultiplicativeManipulatorSigma);
     Value = Value * x;
   }
 }
    /// <summary>
    /// Performs a random convex crossover on the two given parents.
    /// </summary>
    /// <exception cref="ArgumentException">Thrown when two parents are not of the same length.</exception>
    /// <param name="random">The random number generator.</param>
    /// <param name="parent1">The first parent vector for the crossover.</param>
    /// <param name="parent2">The second parent vector for the crossover.</param>
    /// <returns>The newly created real vector, resulting from the random convex crossover.</returns>
    public static RealVector Apply(IRandom random, RealVector parent1, RealVector parent2) {
      if (parent1.Length != parent2.Length)
        throw new ArgumentException("ERROR in RandomConvexCrossover: the two parents are not of the same length");

      int length = parent1.Length;
      double[] result = new double[length];
      double factor = random.NextDouble();

      for (int i = 0; i < length; i++)
        result[i] = (factor * parent1[i]) + ((1 - factor) * parent2[i]);
      return new RealVector(result);
    }
    /// <summary>Returns a random point within a sphere</summary>
    /// <param name="randomNumberGenerator">Random number generator that will be used</param>
    /// <param name="radius">Radius of the sphere</param>
    /// <returns>A random point with the sphere</returns>
    public static Vector3 GenerateRandomPointWithin(
      IRandom randomNumberGenerator, float radius
    ) {

      // TODO: This is just an approximation. Find the real algorithm.
      float r = (float)randomNumberGenerator.NextDouble();
      r = (float)Math.Sqrt(r * r);
      r = (float)Math.Sqrt(r * r);

      return GenerateRandomPointOnSurface(randomNumberGenerator, r);

    }
Example #15
0
    /// <summary>
    /// Perfomrs a heuristic crossover on the two given parents.
    /// </summary>
    /// <exception cref="ArgumentException">Thrown when two parents are not of the same length.</exception>
    /// <param name="random">The random number generator.</param>
    /// <param name="betterParent">The first parent for the crossover operation.</param>
    /// <param name="worseParent">The second parent for the crossover operation.</param>
    /// <returns>The newly created real vector, resulting from the heuristic crossover.</returns>
    public static RealVector Apply(IRandom random, RealVector betterParent, RealVector worseParent) {
      if (betterParent.Length != worseParent.Length)
        throw new ArgumentException("HeuristicCrossover: the two parents are not of the same length");

      int length = betterParent.Length;
      double[] result = new double[length];
      double factor = random.NextDouble();

      for (int i = 0; i < length; i++) {
        result[i] = betterParent[i] + factor * (betterParent[i] - worseParent[i]);
      }
      return new RealVector(result);
    }
    /// <summary>Returns a random point on the surface of a sphere</summary>
    /// <param name="randomNumberGenerator">Random number generator that will be used</param>
    /// <param name="radius">Radius of the sphere</param>
    /// <returns>A random point on the sphere's surface</returns>
    public static Vector3 GenerateRandomPointOnSurface(
      IRandom randomNumberGenerator, float radius
    ) {

      // Choose a random longitude for the point
      float phi = (float)randomNumberGenerator.NextDouble() * MathHelper.TwoPi;

      // The z axis goes straight through the sphere and is chosen in random.
      float z = (float)randomNumberGenerator.NextDouble() * 2.0f - 1.0f;

      // From that, we'll calculate the latitude this point will have on the
      // sphere's surface.
      float theta = (float)Math.Sqrt(1.0f - z * z);

      // Calculate the final position of the point in world space
      return new Vector3(
        radius * theta * (float)Math.Cos(phi),
        radius * theta * (float)Math.Sin(phi),
        radius * z
      );

    }
    /// <summary>Returns a random point on the perimeter of a disc</summary>
    /// <param name="randomNumberGenerator">Random number generator that will be used</param>
    /// <param name="radius">Radius of the disc</param>
    /// <returns>A random point on the disc's perimeter</returns>
    public static Vector2 GenerateRandomPointOnPerimeter(
      IRandom randomNumberGenerator, float radius
    ) {

      // Choose a random angle for the point
      float phi = (float)randomNumberGenerator.NextDouble() * MathHelper.TwoPi;

      // Calculate the final position of the point in world space
      return new Vector2(
        radius * (float)Math.Cos(phi),
        radius * (float)Math.Sin(phi)
      );

    }
    public override void ShakeLocalParameters(IRandom random, double shakingFactor) {
      base.ShakeLocalParameters(random, shakingFactor);
      // 50% additive & 50% multiplicative
      if (random.NextDouble() < 0) {
        double x = NormalDistributedRandom.NextDouble(random, Symbol.WeightManipulatorMu, Symbol.WeightManipulatorSigma);
        weight = weight + x * shakingFactor;
      } else {
        double x = NormalDistributedRandom.NextDouble(random, 1.0, Symbol.MultiplicativeWeightManipulatorSigma);
        weight = weight * x;
      }
#pragma warning disable 612, 618
      variableName = Symbol.VariableNames.SelectRandom(random);
#pragma warning restore 612, 618
    }
    /// <summary>
    /// Performs the arithmetic crossover on some positions by taking either x = alpha * p1 + (1 - alpha) * p2 or x = p1 depending on the probability for a gene to be crossed.
    /// </summary>
    /// <param name="random">The random number generator.</param>
    /// <param name="parent1">The first parent vector.</param>
    /// <param name="parent2">The second parent vector.</param>
    /// <param name="alpha">The alpha parameter (<see cref="AlphaParameter"/>).</param>
    /// <param name="probability">The probability parameter (<see cref="ProbabilityParameter"/>).</param>
    /// <returns>The vector resulting from the crossover.</returns>
    public static RealVector Apply(IRandom random, RealVector parent1, RealVector parent2, DoubleValue alpha, DoubleValue probability) {
      int length = parent1.Length;
      if (length != parent2.Length) throw new ArgumentException("UniformSomePositionsArithmeticCrossover: The parent vectors are of different length.", "parent1");
      if (alpha.Value < 0 || alpha.Value > 1) throw new ArgumentException("UniformSomePositionsArithmeticCrossover: Parameter alpha must be in the range [0;1]", "alpha");
      if (probability.Value < 0 || probability.Value > 1) throw new ArgumentException("UniformSomePositionsArithmeticCrossover: Parameter probability must be in the range [0;1]", "probability");

      RealVector result = new RealVector(length);
      for (int i = 0; i < length; i++) {
        if (random.NextDouble() < probability.Value)
          result[i] = alpha.Value * parent1[i] + (1 - alpha.Value) * parent2[i];
        else result[i] = parent1[i];
      }
      return result;
    }
    /// <summary>
    /// Changes randomly several, but at least one, positions in the given integer <paramref name="vector"/>, according to the given probabilities.
    /// </summary>
    /// <param name="random">A random number generator.</param>
    /// <param name="vector">The integer vector to manipulate.</param>
    /// <param name="bounds"> Contains the minimum value (inclusive), maximum value (exclusive), and step size of the sampling range for 
    /// the vector element to change.</param>
    /// <param name="probability">The probability for each dimension to be manipulated..</param>
    public static void Apply(IRandom random, IntegerVector vector, IntMatrix bounds, double probability) {
      if (bounds == null || bounds.Rows == 0 || bounds.Columns < 2) throw new ArgumentException("UniformSomePositionsManipulator: Invalid bounds specified", "bounds");
      bool atLeastOneManipulated = false;
      for (int index = 0; index < vector.Length; index++) {
        if (random.NextDouble() < probability) {
          atLeastOneManipulated = true;
          UniformOnePositionManipulator.Manipulate(random, vector, bounds, index);
        }
      }

      if (!atLeastOneManipulated) {
        UniformOnePositionManipulator.Manipulate(random, vector, bounds, random.Next(vector.Length));
      }
    }
    public static TwoPointFiveMove Apply(Permutation permutation, IRandom random) {
      int length = permutation.Length;
      if (length == 1) throw new ArgumentException("Stochastic 2.5-SingleMoveGenerator: There cannot be an inversion move given a permutation of length 1.", "permutation");
      int index1 = random.Next(length - 1);
      int index2 = random.Next(index1 + 1, length);
      if (permutation.PermutationType == PermutationTypes.RelativeUndirected) {
        if (length > 3) {
          while (index2 - index1 >= length - 2)
            index2 = random.Next(index1 + 1, length);
        }
      }
      bool isInvert = random.NextDouble() > 0.5;
      return new TwoPointFiveMove(index1, index2, isInvert);

    }
    /// <summary>
    /// Performs the polynomial mutation on a single position in the real vector.
    /// </summary>
    /// <param name="random">The random number generator to use.</param>
    /// <param name="vector">The vector that should be manipulated.</param>
    /// <param name="contiguity">A parameter describing the shape of the probability density function which influences the strength of the manipulation.</param>
    /// <param name="maxManipulation">The maximum strength of the manipulation.</param>
    public static void Apply(IRandom random, RealVector vector, DoubleValue contiguity, DoubleValue maxManipulation) {
      if (contiguity.Value < 0) throw new ArgumentException("PolynomialAllPositionManipulator: Contiguity value is smaller than 0", "contiguity");
      double u, delta = 0;

      for (int index = 0; index < vector.Length; index++) {
        u = random.NextDouble();
        if (u < 0.5) {
          delta = Math.Pow(2 * u, 1.0 / (contiguity.Value + 1)) - 1.0;
        } else if (u >= 0.5) {
          delta = 1.0 - Math.Pow(2.0 - 2.0 * u, 1.0 / (contiguity.Value + 1));
        }

        vector[index] += delta * maxManipulation.Value;
      }
    }
    /// <summary>
    /// Performs the simulated binary crossover on a real vector. Each position is crossed with a probability of 50% and if crossed either a contracting crossover or an expanding crossover is performed, again with equal probability.
    /// For more details refer to the paper by Deb and Agrawal.
    /// </summary>
    /// <exception cref="ArgumentException">Thrown when the parents' vectors are of unequal length or when <paramref name="contiguity"/> is smaller than 0.</exception>
    /// <remarks>
    /// The manipulated value is not restricted by the (possibly) specified lower and upper bounds. Use the <see cref="BoundsChecker"/> to correct the values after performing the crossover.
    /// </remarks>
    /// <param name="random">The random number generator to use.</param>
    /// <param name="parent1">The first parent vector.</param>
    /// <param name="parent2">The second parent vector.</param>
    /// <param name="contiguity">The contiguity value that specifies how close a child should be to its parents (larger value means closer). The value must be greater or equal than 0. Typical values are in the range [2;5].</param>
    /// <returns>The vector resulting from the crossover.</returns>
    public static RealVector Apply(IRandom random, RealVector parent1, RealVector parent2, DoubleValue contiguity) {
      if (parent1.Length != parent2.Length) throw new ArgumentException("SimulatedBinaryCrossover: Parents are of unequal length");
      if (contiguity.Value < 0) throw new ArgumentException("SimulatedBinaryCrossover: Contiguity value is smaller than 0", "contiguity");
      int length = parent1.Length;
      RealVector result = new RealVector(length);
      for (int i = 0; i < length; i++) {
        if (length == 1 || random.NextDouble() < 0.5) { // cross this variable
          double u = random.NextDouble();
          double beta = 0;
          if (u < 0.5) { // if u is smaller than 0.5 perform a contracting crossover
            beta = Math.Pow(2 * u, 1.0 / (contiguity.Value + 1));
          } else if (u > 0.5) { // otherwise perform an expanding crossover
            beta = Math.Pow(0.5 / (1.0 - u), 1.0 / (contiguity.Value + 1));
          } else if (u == 0.5)
            beta = 1;

          if (random.NextDouble() < 0.5)
            result[i] = ((parent1[i] + parent2[i]) / 2.0) - beta * 0.5 * Math.Abs(parent1[i] - parent2[i]);
          else
            result[i] = ((parent1[i] + parent2[i]) / 2.0) + beta * 0.5 * Math.Abs(parent1[i] - parent2[i]);
        } else result[i] = parent1[i];
      }
      return result;
    }
Example #24
0
    /// <summary>
    /// Performs a uniform crossover between two binary vectors.
    /// </summary>
    /// <param name="random">A random number generator.</param>
    /// <param name="parent1">The first parent for crossover.</param>
    /// <param name="parent2">The second parent for crossover.</param>
    /// <returns>The newly created binary vector, resulting from the uniform crossover.</returns>
    public static BinaryVector Apply(IRandom random, BinaryVector parent1, BinaryVector parent2) {
      if (parent1.Length != parent2.Length)
        throw new ArgumentException("UniformCrossover: The parents are of different length.");

      int length = parent1.Length;
      bool[] result = new bool[length];

      for (int i = 0; i < length; i++) {
        if (random.NextDouble() < 0.5)
          result[i] = parent1[i];
        else
          result[i] = parent2[i];
      }

      return new BinaryVector(result);
    }
    public static PotvinEncoding Apply(IRandom random, PotvinEncoding parent1, PotvinEncoding parent2, IVRPProblemInstance problemInstance, bool allowInfeasible) {
      PotvinEncoding child = parent1.Clone() as PotvinEncoding;
      Tour newTour = new Tour();

      int cities = problemInstance.Cities.Value;

      if (cities > 0) {
        int breakPoint1 = random.Next(1, cities + 1);
        Tour tour1 = FindRoute(child, breakPoint1);
        breakPoint1 = tour1.Stops.IndexOf(breakPoint1);

        for (int i = 0; i < breakPoint1; i++)
          newTour.Stops.Add(tour1.Stops[i]);

        int breakPoint2 = random.Next(1, cities + 1);
        Tour tour2 = FindRoute(parent2, breakPoint2);
        breakPoint2 = tour2.Stops.IndexOf(breakPoint2);

        for (int i = breakPoint2; i < tour2.Stops.Count; i++)
          newTour.Stops.Add(tour2.Stops[i]);

        int tour1Index = child.Tours.IndexOf(tour1);
        child.Tours.Remove(tour1);
        child.Tours.Insert(tour1Index, newTour);

        foreach (int city in tour1.Stops)
          if (FindRoute(child, city) == null && !child.Unrouted.Contains(city))
            child.Unrouted.Add(city);

        foreach (int city in tour2.Stops)
          if (FindRoute(child, city) == null && !child.Unrouted.Contains(city))
            child.Unrouted.Add(city);

        if (Repair(random, child, newTour, problemInstance, allowInfeasible) || allowInfeasible) {
          return child;
        } else {
          if (random.NextDouble() < 0.5)
            return parent1.Clone() as PotvinEncoding;
          else
            return parent2.Clone() as PotvinEncoding;
        }
      } else {
        return child;
      }
    }
    /// <summary>
    /// Performs the arithmetic crossover on some positions by taking either x = alpha * p1 + (1 - alpha) * p2 or x = p1 depending on the probability for a gene to be crossed.
    /// </summary>
    /// <param name="random">The random number generator.</param>
    /// <param name="parent1">The first parent vector.</param>
    /// <param name="parent2">The second parent vector.</param>
    /// <param name="bounds">The bounds and step size for each dimension (will be cycled in case there are less rows than elements in the parent vectors).</param>
    /// <param name="alpha">The alpha parameter (<see cref="AlphaParameter"/>).</param>
    /// <param name="probability">The probability parameter (<see cref="ProbabilityParameter"/>).</param>
    /// <returns>The vector resulting from the crossover.</returns>
    public static IntegerVector Apply(IRandom random, IntegerVector parent1, IntegerVector parent2, IntMatrix bounds, DoubleValue alpha, DoubleValue probability) {
      int length = parent1.Length;
      if (length != parent2.Length) throw new ArgumentException("RoundedUniformArithmeticCrossover: The parent vectors are of different length.", "parent1");
      if (alpha.Value < 0 || alpha.Value > 1) throw new ArgumentException("RoundedUniformArithmeticCrossover: Parameter alpha must be in the range [0;1]", "alpha");
      if (probability.Value < 0 || probability.Value > 1) throw new ArgumentException("RoundedUniformArithmeticCrossover: Parameter probability must be in the range [0;1]", "probability");

      var result = new IntegerVector(length);
      for (int i = 0; i < length; i++) {
        if (random.NextDouble() < probability.Value) {
          int min = bounds[i % bounds.Rows, 0], max = bounds[i % bounds.Rows, 1], step = 1;
          if (bounds.Columns > 2) step = bounds[i % bounds.Rows, 2];
          max = FloorFeasible(min, max, step, max - 1);
          double value = alpha.Value * parent1[i] + (1 - alpha.Value) * parent2[i];
          result[i] = RoundFeasible(min, max, step, value);
        } else result[i] = parent1[i];
      }
      return result;
    }
    /// <summary>
    /// Perfomrs a heuristic crossover on the two given parents.
    /// </summary>
    /// <exception cref="ArgumentException">Thrown when two parents are not of the same length.</exception>
    /// <param name="random">The random number generator.</param>
    /// <param name="betterParent">The first parent for the crossover operation.</param>
    /// <param name="worseParent">The second parent for the crossover operation.</param>
    /// <param name="bounds">The bounds and step size for each dimension (will be cycled in case there are less rows than elements in the parent vectors).</param>
    /// <returns>The newly created integer vector, resulting from the heuristic crossover.</returns>
    public static IntegerVector Apply(IRandom random, IntegerVector betterParent, IntegerVector worseParent, IntMatrix bounds) {
      if (betterParent.Length != worseParent.Length)
        throw new ArgumentException("HeuristicCrossover: the two parents are not of the same length");

      int length = betterParent.Length;
      var result = new IntegerVector(length);
      double factor = random.NextDouble();

      int min, max, step = 1;
      for (int i = 0; i < length; i++) {
        min = bounds[i % bounds.Rows, 0];
        max = bounds[i % bounds.Rows, 1];
        if (bounds.Columns > 2) step = bounds[i % bounds.Rows, 2];
        max = FloorFeasible(min, max, step, max - 1);
        result[i] = RoundFeasible(min, max, step, betterParent[i] + factor * (betterParent[i] - worseParent[i]));
      }
      return result;
    }
    public static Schedule Apply(IRandom random, Schedule parent1, Schedule parent2, ItemList<Job> jobData, double mutProp) {
      var child = new Schedule(parent1.Resources.Count);

      //Reset scheduled tasks in result
      foreach (Job j in jobData) {
        foreach (Task t in j.Tasks) {
          t.IsScheduled = false;
        }
      }

      //GT-Algorithm
      //STEP 0 - Compute a list of "earliest operations"
      ItemList<Task> earliestTasksList = GTAlgorithmUtils.GetEarliestNotScheduledTasks(jobData);
      while (earliestTasksList.Count > 0) {
        //STEP 1 - Get earliest not scheduled operation with minimal earliest completing time
        Task minimal = GTAlgorithmUtils.GetTaskWithMinimalEC(earliestTasksList, child);
        int conflictedResourceNr = minimal.ResourceNr;
        Resource conflictedResource = child.Resources[conflictedResourceNr];

        //STEP 2 - Compute a conflict set of all operations that can be scheduled on the conflicted resource
        ItemList<Task> conflictSet = GTAlgorithmUtils.GetConflictSetForTask(minimal, earliestTasksList, jobData, child);

        //STEP 3 - Select a task from the conflict set
        int progressOnResource = conflictedResource.Tasks.Count;
        Task selectedTask = null;
        if (random.NextDouble() < mutProp) {
          //Mutation
          selectedTask = conflictSet[random.Next(conflictSet.Count)];
        } else {
          //Crossover
          selectedTask = SelectTaskFromConflictSet(conflictSet, ((random.Next(2) == 0) ? parent1 : parent2), conflictedResourceNr, progressOnResource);
        }

        //STEP 4 - Add the selected task to the current schedule 
        selectedTask.IsScheduled = true;
        double startTime = GTAlgorithmUtils.ComputeEarliestStartTime(selectedTask, child);
        child.ScheduleTask(selectedTask.ResourceNr, startTime, selectedTask.Duration, selectedTask.JobNr);

        //STEP 5 - Back to STEP 1
        earliestTasksList = GTAlgorithmUtils.GetEarliestNotScheduledTasks(jobData);
      }

      return child;
    }
    /// <summary>
    /// Performs a local crossover on the two given parent vectors.
    /// </summary>
    /// <exception cref="ArgumentException">Thrown when two parents are not of the same length.</exception>
    /// <param name="random">The random number generator.</param>
    /// <param name="parent1">The first parent for the crossover operation.</param>
    /// <param name="parent2">The second parent for the crossover operation.</param>
    /// <returns>The newly created integer vector, resulting from the local crossover.</returns>
    public static IntegerVector Apply(IRandom random, IntegerVector parent1, IntegerVector parent2, IntMatrix bounds) {
      if (parent1.Length != parent2.Length)
        throw new ArgumentException("RoundedLocalCrossover: the two parents are not of the same length");

      double factor;
      int length = parent1.Length;
      var result = new IntegerVector(length);

      int min, max, step = 1;
      for (int i = 0; i < length; i++) {
        min = bounds[i % bounds.Rows, 0];
        max = bounds[i % bounds.Rows, 1];
        if (bounds.Columns > 2) step = bounds[i % bounds.Rows, 2];
        max = FloorFeasible(min, max, step, max - 1);
        factor = random.NextDouble();
        result[i] = RoundFeasible(min, max, step, (factor * parent1[i]) + ((1 - factor) * parent2[i]));
      }
      return result;
    }
    /// <summary>
    /// Performs the cyclic crossover on <paramref name="parent1"/> and <paramref name="parent2"/>.
    /// </summary>
    /// <exception cref="ArgumentException">Thrown when <paramref name="parent1"/> and <paramref name="parent2"/> are not of equal length.</exception>
    /// <exception cref="InvalidOperationException">Thrown if the numbers in the permutation elements are not in the range [0;N) with N = length of the permutation.</exception>
    /// <remarks>
    /// First this method randomly determines from which parent to start with equal probability.
    /// Then it copies the first cycle from the chosen parent starting from index 0 in the permutation.
    /// After the cycle is complete it copies the next cycle starting from the index closest to 0 which was not yet copied from the other parent.
    /// It continues to switch between parents for each completed cycle until no new cycle is found anymore.<br /><br />
    /// The stochasticity of this operator is rather low. There are only two possible outcomes for a given pair of parents.
    /// </remarks>
    /// <exception cref="ArgumentException">Thrown if the two parents are not of equal length.</exception>
    /// <param name="random">The random number generator.</param>
    /// <param name="parent1">The parent scope 1 to cross over.</param>
    /// <param name="parent2">The parent scope 2 to cross over.</param>
    /// <returns>The created cross over permutation as int array.</returns>
    public static Permutation Apply(IRandom random, Permutation parent1, Permutation parent2) {
      if (parent1.Length != parent2.Length) throw new ArgumentException("CyclicCrossover: The parent permutations are of unequal length.");
      int length = parent1.Length;
      int[] result = new int[length];
      bool[] indexCopied = new bool[length];
      int[] invParent1 = new int[length];
      int[] invParent2 = new int[length];

      // calculate inverse mappings (number -> index) for parent1 and parent2
      try {
        for (int i = 0; i < length; i++) {
          invParent1[parent1[i]] = i;
          invParent2[parent2[i]] = i;
        }
      }
      catch (IndexOutOfRangeException) {
        throw new InvalidOperationException("CyclicCrossover: The permutation must consist of numbers in the interval [0;N) with N = length of the permutation.");
      }

      // randomly choose whether to start copying from parent1 or parent2
      bool copyFromParent1 = ((random.NextDouble() < 0.5) ? (false) : (true));

      int j = 0;
      do {
        do {
          if (copyFromParent1) {
            result[j] = parent1[j]; // copy number at position j from parent1
            indexCopied[j] = true;
            j = invParent2[result[j]]; // set position j to the position of the copied number in parent2
          } else {
            result[j] = parent2[j]; // copy number at position j from parent2
            indexCopied[j] = true;
            j = invParent1[result[j]]; // set position j to the position of the copied number in parent1
          }
        } while (!indexCopied[j]);
        copyFromParent1 = !copyFromParent1;
        j = 0;
        while (j < length && indexCopied[j]) j++;
      } while (j < length);

      return new Permutation(parent1.PermutationType, result);
    }