You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

395 lines
11 KiB

package sim
import model.HHCTypes
import scala.reflect.ClassTag
import scala.collection.mutable.{ArrayBuffer, ListBuffer}
import scala.collection.immutable.ArraySeq
import model.HHCEdge2
import util.Util
import model.Customer
import scala.io.BufferedSource
import model.Coord
import scala.util.Random
class HHCSim2(
private val epsilonMax: Int = 0,
private val iterations: Int = 0,
private val WLDMax: Float = 0,
private val customers: String Either ArraySeq[Customer]
) {
import HHCSim2._
import Ordering.Double.IeeeOrdering
def go() = {
customers
.flatMap(checkEmpty)
.map(formAdjMatrix)
.map(e => mstUsingPrims(e))
.map { case (mst, epsilon) => removeEdges(mst)(epsilon) }
.map { case (mstUpdated, removed) => findClusters(mstUpdated)(removed) }
.map {
case (clusters, edgeMappings, removedEdges) =>
groupClusters(clusters, edgeMappings, removedEdges)
}
}
def go2() = {
val res = go().flatMap(value => {
val (clusters, edgeMappings, removed, clusterGroups) = value
workloadBalance(clusters, edgeMappings, removed, clusterGroups)
})
res
}
def workloadBalance[N: Numeric](
clusters: Clusters,
edgeMappings: ArraySeq[List[HHCEdge2[N]]],
removedEdges: RemovedEdges[N],
groups: ArraySeq[(Int, List[(Int, N)])]
) = {
customers.map { c =>
val k = clusters.size
val mutClusters = clusters.toArray
val worlkLoads =
mutClusters.map(_.map(j => c(j)).foldLeft(0f)((x, y) => x + y.workload))
val sortedClusters =
mutClusters.map(_.sortWith((x, y) => c(x).workload < c(y).workload))
val minWL =
c.foldLeft(c(0).workload)(_ min _.workload)
val maxWL =
c.foldLeft(0f)(_ max _.workload)
val WLD = maxWL - minWL
if (WLD > WLDMax) {
var t = Random.between(((k / 2) + 1), k)
while (!mutClusters(t).isEmpty) t = Random.between(((k / 2) + 1), k)
val Ds = groups(t)._2(0)
mutClusters.updated(Ds._1, t)
}
for (_ <- 0 until iterations) {
// val workloads = clusters.flatMap(_.map(j => c(j)))
}
}
}
def checkAveragePairwiseDistance[T](
lst: List[(Int, T)]
)(implicit num: Numeric[T]) = {
val sum = lst.foldLeft(0)((x, y) => x + num.toInt(y._2))
val avg = sum / lst.length
if (avg < epsilonMax) true else false
}
}
object HHCSim2 extends HHCTypes {
import Ordering.Implicits._
val composed = (formAdjMatrix _)
.andThen(e => mstUsingPrims(e))
.andThen { case (mst, epsilon) => removeEdges(mst)(epsilon) }
.andThen { case (mstUpdated, removed) => findClusters(mstUpdated)(removed) }
def getCustomers(
infile: BufferedSource
): String Either ArraySeq[Customer] = {
var customers: String Either ArraySeq[Customer] = Right(ArraySeq.empty)
val it = infile.getLines
@annotation.tailrec
def loop(
lst: ListBuffer[Customer],
iter: Iterator[String]
): String Either ListBuffer[Customer] = {
if (!iter.hasNext) Right(lst)
else {
val line = iter.next
val arr = line.split(",").map(_.trim)
arr match {
case Array(latitude, longitude, workLoad) => {
val cust =
Customer(
Coord(latitude.toDouble, longitude.toDouble),
workLoad.toFloat
)
loop(lst += cust, iter)
}
case _ => {
if (arr.mkString.equals(" ") || arr.mkString.contains("\n"))
Left("Error newline")
else {
Left(
"Error reading customers from" +
s" file - ${arr.mkString(", ")}"
)
}
}
}
}
}
try {
customers = loop(ListBuffer.empty, it).map(_.to(ArraySeq))
} catch {
case e: NumberFormatException =>
customers = Left(
s"Expected number but received string ${e.getMessage()}"
)
case e: NullPointerException =>
customers = Left("Input was null")
}
customers
}
def checkEmpty(
customers: IndexedSeq[Customer]
): Either[String, IndexedSeq[Customer]] =
customers.length match {
case 0 => Left("Error input was empty")
case _ => Right(customers)
}
def formAdjMatrix(customers: IndexedSeq[Customer]): GraphMatrix[Double] = {
val n = customers.length
val edges: Array[Array[Double]] = Array.ofDim(n, n)
for (i <- 0 until n) {
for (j <- i until n) {
val weight =
Util.getHaversineDistance(
customers(i).location,
customers(j).location
)
edges(i)(j) = weight
edges(j)(i) = weight
}
}
edges
}
def mstUsingPrims[T: Numeric](
edges: GraphMatrix[T]
): (Graph[T], T) = {
val num = implicitly[Numeric[T]]
val n = edges.length
val selected: Array[Boolean] = Array.fill(n)(false)
selected(0) = true
val adjList =
Array.fill(n)(ListBuffer.empty[HHCEdge2[T]])
var sum = 0
var count = 0
for (_ <- 0 until n - 1) {
var min = 999999
var x = 0
var y = 0
for (i <- 0 until n) {
if (selected(i) == true) {
for (j <- 0 until n) {
if (selected(j) == false && edges(i)(j) != 0) {
if (min > num.toInt(edges(i)(j))) {
min = num.toInt(edges(i)(j))
x = i
y = j
}
}
}
}
}
sum += num.toInt(edges(x)(y))
adjList(x) += HHCEdge2(x, y, edges(x)(y))
adjList(y) += HHCEdge2(y, x, edges(x)(y))
selected(y) = true
}
val adjList2 = adjList.map(l => {
count += 1
l.toList
})
adjList2.foreach(println)
(ArraySeq.unsafeWrapArray(adjList2), num.fromInt(sum / count))
}
def removeEdges[N: Ordering](
mst: Graph[N]
)(epsilon: N): (Graph[N], RemovedEdges[N]) = {
val removed = ListBuffer.empty[HHCEdge2[N]]
val result = ArraySeq.tabulate(mst.length) { i =>
val (filtered, rm) = mst(i)
// .view
// .filter(e => (e.fromNode <= e.toNode))
.partition(_.weight <= epsilon)
// val rm2 = rm.filter(e => (e.fromNode <= e.toNode))
removed ++= rm
filtered
}
println
result.foreach(println)
println
(result, removed.toList)
}
def DFS[T: Numeric](start: Int)(graph: Graph[T]) = {
val visited = Array.fill(graph.size)(false)
val buf = ListBuffer[Int]()
def loop(
start: Int,
graph: Graph[T],
visited: Array[Boolean]
): Unit = {
visited(start) = true
buf += start
// val iter = graph(start).iterator
// while (iter.hasNext) {
// val edge = iter.next
// if (!visited(edge.toNode))
// loop(edge.toNode, graph, visited)
// }
for (edge <- graph(start)) {
if (!visited(edge.toNode))
loop(edge.toNode, graph, visited)
}
}
loop(start, graph, visited)
buf.toList
}
def findClusters[T: Numeric](mstUpdated: Graph[T])(
removedEdges: RemovedEdges[T]
): (Clusters, ArraySeq[List[HHCEdge2[T]]], RemovedEdges[T]) = {
val visited = Array.fill[Boolean](mstUpdated.length)(false)
var removedEdges2 = removedEdges
val egdeMappings =
Array.fill(mstUpdated.length)(List.empty[HHCEdge2[T]])
val result = ArraySeq.tabulate(mstUpdated.length) { i =>
{
val buf = ListBuffer[Int]()
// mstUpdated(i).isEmpty match {
// case true => { lst += i }
// case false => {
// if (!visited(i)) {
// lst ++= DFS(i)(mstUpdated)
// for (j <- lst) visited(j) = true
// }
// }
// }
visited(i) match {
case true => {
// val (nds, rms) = assignEdges(List(i), removedEdges2)
// egdeMappings(i) = nds
// removedEdges2 = rms
}
case false if (!mstUpdated(i).isEmpty) => {
val nodes = DFS(i)(mstUpdated)
buf ++= nodes
val (nds, rms) = assignEdges(nodes, removedEdges2)
removedEdges2 = rms
egdeMappings(i) = nds
for (j <- nodes) visited(j) = true
}
case false => {
buf += i
val (nds, rms) = assignEdges(List(i), removedEdges2)
egdeMappings(i) = nds
removedEdges2 = rms
}
}
buf.toList
}
}
// println(s"Removed edges size: ${removedEdges2.size}")
// result
(result, ArraySeq.unsafeWrapArray(egdeMappings), removedEdges)
// (result.filterNot(_.isEmpty), ArraySeq.unsafeWrapArray(egdeMappings), removedEdges)
}
def assignEdges[T: Ordering](
nodes: List[Int],
removedEdges: RemovedEdges[T]
) = {
val it = nodes.iterator
def loop(
nodes: List[Int],
removedEdges: RemovedEdges[T],
iter: Iterator[Int],
edges: List[HHCEdge2[T]]
): (List[HHCEdge2[T]], RemovedEdges[T]) = {
if (!iter.hasNext) (edges, removedEdges)
else if (!edges.isEmpty) (edges, removedEdges)
else {
val node = iter.next
val (filt, rm) =
removedEdges.partition(e => e.fromNode == node)
// removedEdges.partition(e => e.toNode == node || e.fromNode == node)
loop(nodes, rm, iter, filt)
}
}
// val filtered = ListBuffer.empty[HHCEdge2[T]]
// val updated = ListBuffer.empty[HHCEdge2[T]]
// for (node <- nodes) {
// val (filt, rm) =
// removedEdges.partition(e => e.toNode == node || e.fromNode == node)
// if (!filtered.isEmpty) {
// // return (filt.toList, rm.toList)
// } else {
// filtered ++= filt
// updated ++= rm
// }
// }
// print(filtered)
// (filtered.toList, updated.toList)
val (edges, removedEdgesUpdated) =
loop(nodes, removedEdges, it, List.empty[HHCEdge2[T]])
// val edges2 = edges.sortWith {
// case (HHCEdge2(_, _, weight1), HHCEdge2(_, _, weight2)) =>
// weight1 < weight2
// }
(edges, removedEdgesUpdated)
}
def groupClusters[N: Ordering](
clusters: Clusters,
edgeMappings: ArraySeq[List[HHCEdge2[N]]],
removed: RemovedEdges[N]
) = {
var k = -1
val x = ArraySeq.tabulate(edgeMappings.size)(i => {
val buf = ListBuffer.empty[(Int, N)]
val lst = edgeMappings(i)
val y = lst.foreach(e => {
if (edgeMappings(e.toNode).isEmpty) {
// var buf = ListBuffer.empty[(Int, N)]
for (j <- 0 until clusters.size) {
for (edge <- clusters(j)) {
if (edge == e.toNode)
buf += ((j, e.weight))
}
}
// Left(buf.toList)
} else {
buf += ((e.toNode, e.weight))
}
// Right(lst.map {
// case HHCEdge2(fromNode, toNode, weight) => (toNode, weight)
// })
})
if (!clusters(i).isEmpty) k += 1
// val lst2 = lst.map {
// case HHCEdge2(fromNode, toNode, weight) => (toNode, weight)
// }
// if (buf.isEmpty) lst2 else buf.toList ::: lst2
// if (lt.isEmpty) rt else lt
(k, buf.toList.sortWith {
case ((_, weight1), (_, weight2)) =>
weight1 < weight2
})
})
(clusters, edgeMappings, removed, x)
}
}