All Downloads are FREE. Search and download functionalities are using the official Maven repository.

mgo.tools.benchmark.ManyObjective.scala Maven / Gradle / Ivy

There is a newer version: 3.59
Show newest version
package mgo.tools.benchmark

/**
 * Chek Cheng, R., Li, M., Tian, Y., Zhang, X., Yang, S., Jin, Y., & Yao, X. (2017). A benchmark test suite for evolutionary many-objective optimization. Complex & Intelligent Systems, 3(1), 67-81.
 */
object ManyObjective {

  /**
   * Sub function for DTLZ1 and DTLZ4
   */
  def dtlz1g(d: Int, k: Int, x: Vector[Double]): Double = ((d - k + 1) to d).map(i => math.pow(x(i - 1) - 0.5, 2.0)).sum

  /**
   * MaF1 - modified inverted DTLZ1
   *
   * @param d number of parameters
   * @param k fixes the number of objectives such that m = d - k + 1
   * @param x variable
   * @return
   */
  def maf1(d: Int, k: Int = 10)(x: Vector[Double]): Vector[Double] = {
    val m = d - k + 1
    assert(m > 0, "MAF1 must have objectives:  m = d - k + 1")
    assert(m <= d, "MAF1 must have less objectives than parameters")
    val g = dtlz1g(d, k, x)
    val prods = (1 until m).map { i =>
      (1 to m - i).map(j => x(j - 1)).product
    }
    val f1 = (1 - prods(0)) * (1 + g)
    val fm = x(0) * (1 + g)
    Vector(f1) ++ prods.tail.zip(x.dropRight(k).tail.reverse.map(xi => 1 - xi)).map { case (p, y) => (1 - p * y) * (1 + g) }.toVector ++ Vector(fm)
  }

  /**
   * MaF2 - DTLZ2BZ
   *
   * @param d number of parameters
   * @param k fixes the number of objectives such that m = d - k + 1
   * @param x variable
   * @return
   */
  def maf2(d: Int, k: Int = 10)(x: Vector[Double]): Vector[Double] = {
    val m = d - k + 1
    assert(m > 0, "MAF2 must have objectives:  m = d - k + 1")
    assert(m <= d, "MAF2 must have less objectives than parameters")
    val thetai = x.map { xi => math.Pi / 2.0 * (xi / 2.0 + 0.25) }
    val gi = (1 until m).map { i =>
      val from = (m + (i - 1) * math.floor((d - m + 1.0) / m.toDouble)).toInt
      val to = (m + i * math.floor((d - m + 1.0) / m.toDouble) - 1).toInt
      (from to to).map { j => math.pow((x(j - 1) / 2.0 + 0.25) - 0.5, 2.0) }.sum
    }
    val gm = ((m + (m - 1) * math.floor((d - m + 1.0) / m.toDouble)).toInt to d).map { j => math.pow((x(j - 1) / 2.0 + 0.25) - 0.5, 2.0) }.sum
    val trigoprods = (2 until m).map { i =>
      thetai.dropRight(k + i - 1).map(math.cos).product * math.sin(thetai(m - i))
    }.toVector
    val trigo = Vector(thetai.dropRight(k).map(math.cos).product) ++ trigoprods ++ Vector(math.sin(thetai(0)))
    val allgis = gi.toVector ++ Vector(gm)
    trigo.zip(allgis).map { case (t, g) => t * g }
  }

  /**
   * subfunction used in DTLZ3
   */
  def dtlz3g(d: Int, k: Int, x: Vector[Double]): Double =
    100.0 * (k.toDouble + ((d - k + 1) to d).map { i => math.pow(x(i - 1) - 0.5, 2.0) - math.cos(20.0 * math.Pi * (x(i - 1) - 0.5)) }.sum)

  /**
   * subfunction used in DTLZ3 and DTLZ4
   */
  def dtlz3trigo(d: Int, k: Int, x: Vector[Double], alpha: Double = 1.0): Vector[Double] = {
    val fi = (2 until d - k + 1).map { i =>
      x.dropRight(k + i - 1).map(xi => math.cos(math.Pi / 2.0 * math.pow(xi, alpha))).product * math.sin(math.Pi / 2.0 * math.pow(x(d - k + 1 - i), alpha))
    }.toVector
    val f1 = x.dropRight(k).map(xi => math.cos(math.Pi / 2.0 * math.pow(xi, alpha))).product
    val fm = math.sin(math.Pi / 2.0 * math.pow(x(0), alpha))
    Vector(f1) ++ fi ++ Vector(fm)
  }

  /**
   * MaF3 - convex DTLZ3
   *
   * @param d number of parameters
   * @param k fixes the number of objectives such that m = d - k + 1
   * @param x variable
   * @return
   */
  def maf3(d: Int, k: Int = 10)(x: Vector[Double]): Vector[Double] = {
    val m = d - k + 1
    assert(m > 0, "MAF3 must have objectives:  m = d - k + 1")
    assert(m <= d, "MAF3 must have less objectives than parameters")
    val g = dtlz3g(d, k, x)
    val fi = dtlz3trigo(d, k, x)
    fi.dropRight(1).map(trigo => math.pow(trigo * (1 + g), 4.0)) ++ Vector(math.pow(fi.last * (1 + g), 2.0))
  }

  /**
   * MaF4 - inverted badly scaled DTLZ3
   *
   * @param d number of parameters
   * @param k fixes the number of objectives such that m = d - k + 1
   * @param a scaling factor
   * @param x variable
   * @return
   */
  def maf4(d: Int, k: Int = 10, a: Double = 2.0)(x: Vector[Double]): Vector[Double] = {
    val m = d - k + 1
    assert(m > 0, "MAF4 must have objectives:  m = d - k + 1")
    assert(m <= d, "MAF4 must have less objectives than parameters")
    val g = dtlz3g(d, k, x)
    val fi = dtlz3trigo(d, k, x)
    (1 to m).map { i => math.pow(a, i.toDouble) }.zip(fi).map { case (apow, trigo) => apow * (1 - trigo) * (1 + g) }.toVector
  }

  /**
   * MaF5 - convex badly scaled DTLZ4
   *
   * @param d number of parameters
   * @param k fixes the number of objectives such that m = d - k + 1
   * @param a scaling factor
   * @param alpha exponent (within trigonometric functions)
   * @param x variable
   * @return
   */
  def maf5(d: Int, k: Int = 10, a: Double = 2.0, alpha: Double = 100.0)(x: Vector[Double]): Vector[Double] = {
    val m = d - k + 1
    assert(m > 0, "MAF5 must have objectives:  m = d - k + 1")
    assert(m <= d, "MAF5 must have less objectives than parameters")
    val g = dtlz1g(d, k, x)
    val fi = dtlz3trigo(d, k, x, alpha = alpha)
    (1 to m).map { i => math.pow(a, i.toDouble) }.reverse.zip(fi).map { case (apow, trigo) => apow * math.pow(trigo * (1 + g), 4.0) }.toVector
  }

  /**
   * MaF6 - DTLZ5(I,M)
   *
   * @param d number of parameters
   * @param k fixes the number of objectives such that m = d - k + 1
   * @param i dimensionality of the degenerate pareto front
   * @param x variable
   * @return
   */
  def maf6(d: Int, k: Int = 10, i: Int = 2)(x: Vector[Double]): Vector[Double] = {
    val m = d - k + 1
    assert(m > 0, "MAF6 must have objectives:  m = d - k + 1")
    assert(m <= d, "MAF6 must have less objectives than parameters")
    assert(i <= m - 1, "Incorrect Pareto front dimension in MAF6")
    val g = dtlz1g(d, k, x)
    val thetai = (1 until i).map { j => x(j - 1) }.toVector ++ (i until m).map { j => (1 + 2 * g * x(j - 1)) / (4 * (1 + g)) }
    val trigos = (2 until m).map { j =>
      thetai.dropRight(j - 1).map(math.cos).product * math.sin(thetai(m - j))
    }.toVector
    (Vector(thetai.map(math.cos).product) ++ trigos ++ Vector(math.sin(thetai(0)))).map(trig => trig * (1 + 100.0 * g))
  }

  /**
   * MaF7 - DTLZ7
   *
   * @param d number of parameters
   * @param k fixes the number of objectives such that m = d - k + 1
   * @param x variable
   * @return
   */
  def maf7(d: Int, k: Int = 20)(x: Vector[Double]): Vector[Double] = {
    val m = d - k + 1
    assert(m > 0, "MAF7 must have objectives:  m = d - k + 1")
    assert(m <= d, "MAF7 must have less objectives than parameters")
    val fi = x.dropRight(k)
    val g = 1 + 9 / k * x.drop(m - 1).sum
    val h = m - fi.map { f => f / (1 + g) * (1 + math.sin(3.0 * math.Pi * f)) }.sum
    fi ++ Vector(h * (1 + g))
  }

  /**
   * MaF8 - multi-point distance minimization problem
   *  number of parameters is always 2, number of objectives changes
   *
   * @param m number of objectives
   * @param x variable \in [-10000,10000] - always two dimensional
   * @return
   */
  def maf8(m: Int)(x: Vector[Double]): Vector[Double] = {
    // construct points at distance 1 and angle 2pi/m
    val points = (0 until m).map(i => (math.cos(2 * math.Pi * i / m), math.sin(2 * math.Pi * i / m)))
    points.map {
      case (xi, yi) =>
        math.sqrt(math.pow(xi - x(0), 2.0) + math.pow(yi - x(1), 2.0))
    }.toVector
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy