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.

325 lines
7.7 KiB

package util
import model.Coord
import scala.math._
import scala.collection.mutable.ArrayBuffer
import scala.collection.mutable
import model.Customer
import scala.io.BufferedSource
import scala.reflect.ClassTag
import com.typesafe.scalalogging.Logger
import com.typesafe.scalalogging.LazyLogging
object Util extends LazyLogging {
private val r = 6471.00 // km
def toRad(num: Double): Double = {
val a = num * Pi / 180
a
}
def getHaversineDistance(c1: Coord, c2: Coord): Double = {
val x1 = c1.latitude - c2.latitude
val x2 = c1.longitude - c2.longitude
val dlat = toRad(x1)
val dlon = toRad(x2)
val a = pow(sin(dlat / 2), 2) +
cos(toRad(c1.latitude)) *
cos(toRad((c2.latitude))) *
pow(sin(dlon / 2), 2)
val c = 2 * atan2(sqrt(a), sqrt(1 - a))
val d = r * c
d
}
def getHaversineDistance(lat: Double, lon: Double): Double = {
val x1 = lat
val x2 = lon
val dlat = toRad(x1)
val dlon = toRad(x2)
val a = pow(sin(dlat / 2), 2) +
cos(toRad(x1)) *
cos(toRad((0))) *
pow(sin(dlon / 2), 2)
val c = 2 * atan2(sqrt(a), sqrt(1 - a))
val d = r * c
d
}
def primTraverse(
arr1: Array[Array[Int]],
comp: Int,
cond: (Int, Int) => Boolean,
cb: (Int, Int, Array[Array[Int]], Array[Array[Int]]) => Array[Array[Int]]
): Unit = {
val n = arr1.length
val selected = Array.ofDim[Boolean](n)
val arr2: Array[Array[Int]] = Array.ofDim(n, n)
selected(0) = true
// val mst: Array[Array[Int]] = Array.ofDim(5, 5)
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 && arr1(i)(j) != 0) {
if (cond(comp, arr1(i)(j))) {
x = i
y = j
cb(x, y, arr1, arr2)
}
}
}
}
}
// mst(x)(y) = mst(x)(y)
selected(y) = true
}
}
def mstUsingPrims[T: ClassTag](
edges: Array[Array[T]]
)(implicit num: Numeric[T]): Array[Array[T]] = {
val n = edges.length
val selected: ArrayBuffer[Boolean] = ArrayBuffer.fill(n)(false)
selected(0) = true
val mst: Array[Array[T]] = Array.ofDim[T](n, n)
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 (num.gt(num.fromInt(min), edges(i)(j))) {
min = num.toInt(edges(i)(j))
x = i
y = j
}
}
}
}
}
// println(s"Edge selected $x - $y : ${edges(x)(y)}")
mst(x)(y) = edges(x)(y)
mst(y)(x) = edges(x)(y)
selected(y) = true
}
mst
}
def findClusters[T](
mst: Array[Array[T]],
centroids: IndexedSeq[Int],
removed: IndexedSeq[(Int, Int, T)]
)(implicit num: Numeric[T]) =
(
centroids,
centroids
.map(d => {
val y = DFS(d, mst)
y(0) -> y
})
.toMap,
removed
)
def makeAdjacencyList(
mst: Array[Array[Int]],
centroids: IndexedSeq[Int]
): ArrayBuffer[ArrayBuffer[Int]] = {
val n = mst.length
// val selected: ArrayBuffer[Boolean] = ArrayBuffer.fill(n)(false)
val buf: ArrayBuffer[ArrayBuffer[Int]] =
ArrayBuffer.fill(n)(ArrayBuffer.empty)
// for (_ <- 0 until n -1) {
// }
for (i <- 0 until n) {
for (j <- 0 until n) {
if (mst(i)(j) != 0) {
// println(s" $i $j = ${mst(i)(j)}")
buf(i) += j
}
}
}
buf
}
def findCentroids[T](
mst: Array[Array[T]]
)(
implicit ev: Numeric[T]
): (Array[Array[T]], IndexedSeq[Int], IndexedSeq[(Int, Int, T)]) = {
val n = mst.length
val centroids: mutable.Set[Int] = mutable.Set.empty
val removed: ArrayBuffer[(Int, Int, T)] = ArrayBuffer.empty
for (i <- 0 until n) {
for (j <- 0 until n) {
if (ev.gt(mst(i)(j), ev.fromInt(20)) && mst(i)(j) != 0) {
// println(s" $i $j = ${mst(i)(j)}")
centroids += i
centroids += j
removed.append((i, j, mst(i)(j)))
mst(i)(j) = ev.zero
}
}
}
(mst, centroids.toIndexedSeq, removed.toIndexedSeq)
}
def DFS[T](
start: Int,
graph: Array[Array[T]]
)(implicit num: Numeric[T]): ArrayBuffer[Int] = {
val visited = Array.fill(graph.size)(false)
val buf = ArrayBuffer[Int]()
def loop(
start: Int,
graph: Array[Array[T]],
visited: Array[Boolean]
): Unit = {
visited(start) = true
buf += start
// print(s"$start ")
for (i <- 0 until graph.size) {
if (num.gt(graph(start)(i), num.fromInt(0)) && (!visited(i))) {
loop(i, graph, visited);
}
}
}
loop(start, graph, visited)
// println()
buf
}
def DFS(
start: Int,
graph: Array[Array[Int]],
num: Int,
cond: (Int, Int) => Boolean
): ArrayBuffer[Int] = {
val visited = Array.fill(graph.size)(false)
val buf = ArrayBuffer[Int]()
def loop(
start: Int,
graph: Array[Array[Int]],
visited: Array[Boolean]
): Unit = {
visited(start) = true
buf += start
// print(s"$start ")
for (i <- 0 until graph.size) {
if (graph(start)(i) > 0 && cond(graph(start)(i), num) && (!visited(i))) {
loop(i, graph, visited);
}
}
}
loop(start, graph, visited)
// println()
buf
}
def groupClusters[T](
centroids: IndexedSeq[Int],
clusters: Map[Int, ArrayBuffer[Int]],
removed: IndexedSeq[(Int, Int, T)]
)(implicit num: Numeric[T]) =
centroids
.map(c => {
val cluster = clusters(c)
val lst = removed
.filter(r => {
c == r._1
})
.sortWith((x, y) => {
num.lt(x._3, y._3)
})
.map(l => {
(l._2, l._3)
})
c -> lst
})
.toMap
def getCustomers(
infile: BufferedSource
): String Either IndexedSeq[Customer] = {
var customers: String Either IndexedSeq[Customer] = Right(IndexedSeq.empty)
val it = infile.getLines
@annotation.tailrec
def loop(
lst: IndexedSeq[Customer],
iter: Iterator[String]
): String Either IndexedSeq[Customer] = {
if (!iter.hasNext)
return Right(lst)
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 _ =>
Left(
"Error reading customers from" +
s" file - ${arr.mkString(", ")}"
)
}
}
try {
customers = loop(IndexedSeq.empty, it)
} catch {
case e: NumberFormatException =>
customers = Left(
s"Expected number but received string ${e.getMessage()}"
)
case e: NullPointerException =>
customers = Left("Input was null")
}
customers
}
def formAdjMatrix(customers: IndexedSeq[Customer]): Array[Array[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 =
getHaversineDistance(customers(i).location, customers(j).location)
edges(i)(j) = weight
edges(j)(i) = weight
}
}
edges
}
}