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

mgo.tools.metric.ClosedCrowdingDistance.scala Maven / Gradle / Ivy

/*
 * Copyright (C) 03/03/2014 Guillaume Chérel
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */

package mgo.tools.metric

import cats._

/**
 * Modification of the crowding distance to avoid infinite values for the first and last
 * point in each domain. The crowding for the second and last element of each domain is instead
 * the distance between the first and second (or last and second but last).
 *
 * Crowding distance computation see Deb, K., Agrawal, S., Pratap, A. & Meyarivan, T.
 * A fast elitist non-dominated sorting genetic algorithm for multi-objective
 * optimization: NSGA-II. Lecture notes in computer science 1917, 849–858 (2000).
 */
object ClosedCrowdingDistance {

  /**
   * Compute the closed crowding distance
   *
   * @param data the set of point
   * @return the crowding distance of each point in the same order as the input
   * sequence
   */
  def apply(data: Seq[Seq[Double]]): Seq[Later[Double]] = {
    if (data.size < 2) data.map(d => Later(Double.PositiveInfinity))
    else {
      class CrowdingInfo(val d: Seq[Double], var crowding: Double = 0.0)

      val crowding = data.map(new CrowdingInfo(_))

      // for each objective
      for (curDim <- 0 until data.head.size) {

        val curCrowding = crowding.sortBy(_.d(curDim))

        val firstCrowdingInfo = curCrowding.head
        val secondCrowdingInfo = curCrowding(1)
        val secondButLastCrowdingInfo = curCrowding(curCrowding.size - 2)
        val lastCrowdingInfo = curCrowding.last

        val first = firstCrowdingInfo.d
        val second = secondCrowdingInfo.d
        val secondButLast = secondButLastCrowdingInfo.d
        val last = lastCrowdingInfo.d

        val min = first(curDim)
        val max = last(curDim)

        val maxMinusMin = max - min

        firstCrowdingInfo.crowding += (second(curDim) - first(curDim)) * 2 / maxMinusMin
        lastCrowdingInfo.crowding += (last(curDim) - secondButLast(curDim)) * 2 / maxMinusMin

        val itOpod = curCrowding.iterator
        var ptMinus1 = itOpod.next
        var pt = itOpod.next

        while (itOpod.hasNext) {
          val ptPlus1 = itOpod.next
          pt.crowding += (ptPlus1.d(curDim) - ptMinus1.d(curDim)) / maxMinusMin
          ptMinus1 = pt
          pt = ptPlus1
        }
      }

      crowding.map(c => Later(c.crowding))
    }
  }

  /**
   * Compute the closed crowding distance of the i-th point in the data points
   *
   * @param point the point
   * @param data the set of point
   * @return the closed crowding distance of the point relative to the data
   */

  def of(i: Int, data: Seq[Seq[Double]]): Later[Double] = {
    if (data.size < 2) Later(Double.PositiveInfinity)
    else {
      var crowdingOfI: Double = 0.0

      // for each objective
      for (curDim <- 0 until data.head.size) {

        val curSortedIdx = data.indices.sortBy(data(_)(curDim))

        val first = data(curSortedIdx.head)
        val last = data(curSortedIdx.last)

        val min = first(curDim)
        val max = last(curDim)

        val maxMinusMin = max - min

        if (i == curSortedIdx.head) crowdingOfI += (data(curSortedIdx(1))(curDim) - first(curDim)) * 2 / maxMinusMin
        else if (i == curSortedIdx.last) crowdingOfI += (last(curDim) - data(curSortedIdx(curSortedIdx.size - 2))(curDim)) * 2 / maxMinusMin
        else {
          var j = 1
          while (curSortedIdx(j) != i) {
            j += 1
          }
          val ptMinus1 = data(curSortedIdx(j - 1))
          val ptPlus1 = data(curSortedIdx(j + 1))
          crowdingOfI += (ptPlus1(curDim) - ptMinus1(curDim)) / maxMinusMin
        }
      }

      Later(crowdingOfI)
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy