Я пытаюсь запрограммировать быстрый алгоритм без допорядной сортировки (NDS) Deb, используемый в NSGA2, неизменным способом, используя Scala.
Но проблема кажется более сложной, чем я думаю, поэтому я упрощаю здесь проблему создания MWE.
Представьте себе совокупность Seq[A]
, и каждый элемент A
будет decoratedA
со списком, который содержит указатели на другие элементы популяции Seq[A]
.
Функция evalA(a:decoratedA)
принимает список linkedA
, который содержит и уменьшает значение каждого из них.
Далее я возьму список подмножеств decoratedAPopulation
популяции A и вызовет evalA
для каждого. У меня проблема, потому что между каждой итерацией по элементу в этом списке подмножеств decoratedAPopulation
мне нужно обновить мою популяцию A
новым decoratedA
и обновленным linkedA
содержать...
Более проблематично, каждый элемент популяции нуждается в обновлении "linkedA", чтобы заменить связанный элемент, если он изменится...
Hum, как вы можете видеть, кажется сложным поддерживать синхронизированный синхронизируемый список таким образом. Я предлагаю другое решение внизу, которое, вероятно, нуждается в рекурсии, чтобы вернуть после каждого evalA
новую группу с замененным элементом.
Как я могу сделать это правильно неизменным способом?
Легко закодировать в изменчивом виде, но я не могу найти хороший способ сделать это непреложным способом, у вас есть путь или идея сделать это?
object test extends App{
case class A(value:Int) {def decrement()= new A(value - 1)}
case class decoratedA(oneAdecorated:A, listOfLinkedA:Seq[A])
// We start algorithm loop with A element with value = 0
val population = Seq(new A(0), new A(0), new A(8), new A(1))
val decoratedApopulation = Seq(new decoratedA(population(1),Seq(population(2),population(3))),
new decoratedA(population(2),Seq(population(1),population(3))))
def evalA(a:decoratedA) = {
val newListOfLinked = a.listOfLinkedA.map{e => e.decrement()
new decoratedA(a.oneAdecorated,newListOfLinked)}
}
def run()= {
//decoratedApopulation.map{
// ?
//}
}
}
Обновление 1:
О вводе/выводе исходного алгоритма.
Первая часть алгоритма Deb (Шаг 1 до Шаг 3) анализирует список Individual и вычисляет для каждого A: (a) кол-во подсчетов, число of A, которые доминируют во мне (атрибут value
A) (b) список A я доминирует (listOfLinkedA
).
Таким образом, он возвращает полностью заполненную совокупность decoratedA
, а для входа в Шаг 4 (моя проблема) я беру первый не доминируемый фронт, ср. подмножество элементов decoratedA
с A
значением = 0.
Моя проблема начинается здесь, со списком decoratedA
с A
значением = 0; и я просматриваю следующий фронт в этом списке, вычисляя каждый listOfLinkedA
каждого из этих A
На каждой итерации между шагами с 4 по 6 нужно вычислить новый B
список подмножеств decoratedA
с A
значением = 0. Для каждого, я уменьшаю сначала атрибут count доминирования каждого элемента в listOfLinkedA
, затем я фильтрую, чтобы получить элемент равным 0. A конец шага 6, B сохраняется в списке List[Seq[DecoratedA]]
, затем я перезапускаю до шага 4 с B и вычисляю новый C
и т.д..
Что-то вроде этого в моем коде, я вызываю explore()
для каждого элемента B
, а Q
равен концу нового подмножества decoratedA
с value
(пригодность здесь) = 0:
case class PopulationElement(popElement:Seq[Double]){
implicit def poptodouble():Seq[Double] = {
popElement
}
}
class SolutionElement(values: PopulationElement, fitness:Double, dominates: Seq[SolutionElement]) {
def decrement()= if (fitness == 0) this else new SolutionElement(values,fitness - 1, dominates)
def explore(Q:Seq[SolutionElement]):(SolutionElement, Seq[SolutionElement])={
// return all dominates elements with fitness - 1
val newSolutionSet = dominates.map{_.decrement()}
val filteredSolution:Seq[SolutionElement] = newSolutionSet.filter{s => s.fitness == 0.0}.diff{Q}
filteredSolution
}
}
A конец алгоритма, у меня есть окончательный список seq decoratedA
List[Seq[DecoratedA]]
, который содержит все мои фронты, вычисленные.
Обновление 2
Образец значения, извлеченный из этого примера. Я беру только фронт парето (красный) и следующий {f, h, l} следующий фронт с преобладанием count = 1.
case class p(x: Int, y: Int)
val a = A(p(3.5, 1.0),0)
val b = A(p(3.0, 1.5),0)
val c = A(p(2.0, 2.0),0)
val d = A(p(1.0, 3.0),0)
val e = A(p(0.5, 4.0),0)
val f = A(p(0.5, 4.5),1)
val h = A(p(1.5, 3.5),1)
val l = A(p(4.5, 1.0),1)
case class A(XY:p, value:Int) {def decrement()= new A(XY, value - 1)}
case class ARoot(node:A, children:Seq[A])
val population = Seq(
ARoot(a,Seq(f,h,l),
ARoot(b,Seq(f,h,l)),
ARoot(c,Seq(f,h,l)),
ARoot(d,Seq(f,h,l)),
ARoot(e,Seq(f,h,l)),
ARoot(f,Nil),
ARoot(h,Nil),
ARoot(l,Nil))
Возврат алгоритма List(List(a,b,c,d,e), List(f,h,l))
Обновление 3
Через 2 часа и некоторые проблемы с сопоставлением шаблонов (Ahum...) я возвращаюсь с полным примером, который автоматически вычисляет счетчик с преобладанием и дети каждого ARoot.
Но у меня такая же проблема, вычисление списка моих детей не совсем правильно, потому что каждый элемент A, возможно, является общим членом другого дочернего списка ARoot, поэтому мне нужно подумать о вашем ответе, чтобы изменить его:/В это время я только вычисляет список детей Seq[p]
, и мне нужен список Seq[A]
case class p(x: Double, y: Double){
def toSeq():Seq[Double] = Seq(x,y)
}
case class A(XY:p, dominatedCounter:Int) {def decrement()= new A(XY, dominatedCounter - 1)}
case class ARoot(node:A, children:Seq[A])
case class ARootRaw(node:A, children:Seq[p])
object test_stackoverflow extends App {
val a = new p(3.5, 1.0)
val b = new p(3.0, 1.5)
val c = new p(2.0, 2.0)
val d = new p(1.0, 3.0)
val e = new p(0.5, 4.0)
val f = new p(0.5, 4.5)
val g = new p(1.5, 4.5)
val h = new p(1.5, 3.5)
val i = new p(2.0, 3.5)
val j = new p(2.5, 3.0)
val k = new p(3.5, 2.0)
val l = new p(4.5, 1.0)
val m = new p(4.5, 2.5)
val n = new p(4.0, 4.0)
val o = new p(3.0, 4.0)
val p = new p(5.0, 4.5)
def isStriclyDominated(p1: p, p2: p): Boolean = {
(p1.toSeq zip p2.toSeq).exists { case (g1, g2) => g1 < g2 }
}
def sortedByRank(population: Seq[p]) = {
def paretoRanking(values: Set[p]) = {
//comment from @dk14: I suppose order of values isn't matter here, otherwise use SortedSet
values.map { v1 =>
val t = (values - v1).filter(isStriclyDominated(v1, _)).toSeq
val a = new A(v1, values.size - t.size - 1)
val root = new ARootRaw(a, t)
println("Root value ", root)
root
}
}
val listOfARootRaw = paretoRanking(population.toSet)
//From @dk14: Here is convertion from Seq[p] to Seq[A]
val dominations: Map[p, Int] = listOfARootRaw.map(a => a.node.XY -> a.node.dominatedCounter) //From @dk14: It a map with dominatedCounter for each point
val listOfARoot = listOfARootRaw.map(raw => ARoot(raw.node, raw.children.map(p => A(p, dominations.getOrElse(p, 0)))))
listOfARoot.groupBy(_.node.dominatedCounter)
}
//Get the first front, a subset of ARoot, and start the step 4
println(sortedByRank(Seq(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)).head)
}