diff --git a/src/main/scala/org/scata/algorithm/CBAA.scala b/src/main/scala/org/scata/algorithm/CBAA.scala new file mode 100644 index 0000000000000000000000000000000000000000..ad01422a30d8b53729cd2246aeff0d04213d687b --- /dev/null +++ b/src/main/scala/org/scata/algorithm/CBAA.scala @@ -0,0 +1,88 @@ +// Copyright (C) Maxime MORGE, 2024 +package org.scata.algorithm + +import org.scata.core.{SingleAssignmentProblem, Task, Worker} + +/** + * The Consensus-Based Auction Algorithm (CBAA) is + * a single-assignment strategy + */ +class CBAA(pb : SingleAssignmentProblem) { + + var neighbours : Map[Worker, List[Worker]] = fullyConnected() + + var workerTaskList: Map[(Worker, Task), Boolean] = Map[(Worker, Task), Boolean]() + var winningBid : Map[(Worker, Task), Int] = Map[(Worker, Task), Int]() + + pb.workers.foreach{ worker=> + pb.tasks.foreach{ task => + workerTaskList = workerTaskList.updated((worker, task), false) + winningBid = winningBid.updated((worker, task), 0) + } + } + + /** + * Generate a fully connect communication network + */ + private def fullyConnected() : Map[Worker, List[Worker]] = { + var neighbour = Map[Worker, List[Worker]]() + pb.workers.foreach{ worker => + neighbour = neighbour.updated(worker, pb.workers.toList) + } + neighbour + } + + /** + * Checks if two workers are neighbors + * @param worker1 the first worker + * @param worker2 the second worker + * @return true if they are neighbors, false otherwise + */ + def isNeighbor(worker1: Worker, worker2: Worker): Boolean = neighbours(worker1).contains(worker2) + + + /** + * CBAA Phase 1 for worker i + * Selects the best task for the worker based on the cost + * @param i index of the worker in the workers set + * */ + def selectTask(i : Int) : Unit = { + val worker = pb.workers.toIndexedSeq(i) + // Check if the worker has no tasks assigned + if (!pb.tasks.exists(task => workerTaskList((worker, task)))) { + + // Determine valid tasks based on cost comparison + var validTasks: Map[Task, Boolean] = Map[Task, Boolean]() + pb.tasks.foreach { task => + if (pb.cost(worker, task) <= winningBid(worker, task)) { + validTasks = validTasks.updated(task, true) + } else { + validTasks = validTasks.updated(task, false) + } + } + // If there are valid tasks, select the one with the minimum cost + if (pb.tasks.exists(task => validTasks(task))) { + val bestTask = validTasks.filter(_._2).keys.minBy(task => pb.cost(worker, task)) + workerTaskList = workerTaskList.updated((worker, bestTask), true) + winningBid = winningBid.updated((worker, bestTask), pb.cost(worker, bestTask)) + } + } + } + /** + * TODO CBAA Phase 1 for worker i + * @param i index of the worker in the workers set + */ + def consensus(i: Int): Unit = { + val worker = pb.workers.toIndexedSeq(i) + // Iterate over all tasks + pb.tasks.foreach { task => + // Find the minimum winning bid among the neighbors of the worker + val minWinningBid = pb.workers + .filter(neighbor => isNeighbor(worker, neighbor)) + .map(neighbor => winningBid((neighbor, task))) + .min + // Update the winning bid for the worker and task + winningBid = winningBid.updated((worker, task), minWinningBid) + } + } +} diff --git a/src/main/scala/org/scata/core/SingleAssignmentProblem.scala b/src/main/scala/org/scata/core/SingleAssignmentProblem.scala index 939719ca7866db89a9131959e22416e95ce82947..c81de556c1b0d76b1fee6a48add63bfe4f5a3acb 100644 --- a/src/main/scala/org/scata/core/SingleAssignmentProblem.scala +++ b/src/main/scala/org/scata/core/SingleAssignmentProblem.scala @@ -12,7 +12,7 @@ import org.scata.utils.RandomUtils */ class SingleAssignmentProblem(val workers: SortedSet[Worker], val tasks : SortedSet[Task], - val cost : Map[(Worker,Task),Double]) { + val cost : Map[(Worker,Task), Int]) { /** * Returns a string describing the MASTAPlus problem @@ -43,7 +43,7 @@ object SingleAssignmentProblem{ implicit val order : Ordering[Double] = Ordering.Double.TotalOrdering // eventually Ordering.Double.IeeeOrdering - private val MAX_COST = 100 // Maximum task cost + private val MAX_COST : Int = 100 // Maximum task cost /** * Returns a random single-assignment problem instance with @@ -59,7 +59,7 @@ object SingleAssignmentProblem{ val tasks : SortedSet[Task] = collection.immutable.SortedSet[Task]() ++ (for (i <- 1 to n) yield new Task(name = "t%02d".format(i))) - var cost : Map[(Worker,Task),Double] = Map [(Worker,Task),Double]() + var cost : Map[(Worker,Task),Int] = Map [(Worker,Task),Int]() // Adjust the resource sizes workers.foreach{ worker => tasks.foreach{ task => diff --git a/src/main/scala/org/scata/core/Worker.scala b/src/main/scala/org/scata/core/Worker.scala index 931cbb0c4cab6374a78af3cc0c8864a5d852e6f7..d05a470a9f372f46ef7a6ecd6f4213f36c3d31d3 100644 --- a/src/main/scala/org/scata/core/Worker.scala +++ b/src/main/scala/org/scata/core/Worker.scala @@ -26,3 +26,4 @@ final class Worker(val name : String) extends Ordered[Worker]{ -1 } } +