temp commit

This commit is contained in:
Rohan Sircar 2020-04-21 21:42:19 +05:30
parent ab02a1e495
commit 7d045e79b6
6 changed files with 649 additions and 35 deletions

View File

@ -24,23 +24,15 @@ class HHCSim(
) )
.tap(logCentroids) .tap(logCentroids)
.tap(logRemovedEdges) .tap(logRemovedEdges)
.map( .map {
e => case (mst, centroids, removed) =>
e match { Util.findClusters(mst, centroids, removed)
case (mst, centroids, removed) => { }
printGraph(mst)
Util.findClusters(mst, centroids, removed)
}
}
)
.tap(logClusters) .tap(logClusters)
.map( .map {
e => case (centroids, clusters, removed) =>
e match { Util.groupClusters(centroids, clusters, removed)
case (centroids, clusters, removed) => }
Util.groupClusters(centroids, clusters, removed)
}
)
def checkEmpty( def checkEmpty(
customers: IndexedSeq[Customer] customers: IndexedSeq[Customer]

View File

@ -6,6 +6,7 @@ import util.Util
import config.Conf import config.Conf
import java.io.File import java.io.File
import scala.io.Source import scala.io.Source
import sim.HHCSim2
object Main { object Main {
def main(args: Array[String]): Unit = { def main(args: Array[String]): Unit = {
@ -13,25 +14,32 @@ object Main {
val bufferedSource = Source.fromFile(conf.infile()) val bufferedSource = Source.fromFile(conf.infile())
val customers = Util.getCustomers(bufferedSource) val customers = HHCSim2.getCustomers(bufferedSource)
bufferedSource.close() bufferedSource.close()
val hhc = new HHCSim(epsilonMax = 40, iterations = 10, WLDMax = 10) // import Ordering.Double.IeeeOrdering
val adjList2 = // val hhc = new HHCSim(epsilonMax = 40, iterations = 10, WLDMax = 10)
customers // val adjList2 =
.map(Util.formAdjMatrix) // customers
.map(e => Util.mstUsingPrims2(e)) // .map(Util.formAdjMatrix)
.map(_._1) // .map(e => Util.mstUsingPrims2(e))
// .map(e => Util.makeAdjacencyList2(e._1)) // .map { case (mst, eps) => Util.removeEdges(mst)(eps) }
adjList2.map(adjl => { // // .map(_._1)
for (i <- 0 until adjl.size) {
print(s"$i -> ") // // .map(e => Util.makeAdjacencyList2(e._1))
adjl(i).foreach(e => { // adjList2.map(e => {
print(f"(${e._1}, ${e._2}%.2f), ") // val (mst, rm) = e
}) // for (i <- 0 until mst.size) {
println // print(s"$i -> ")
} // mst(i).foreach(e => {
}) // print(f"(${e._1}, ${e._2}%.2f), ")
// })
// println
// }
// println(rm)
// })
// val fnl2 = hhc.go(customers) // val fnl2 = hhc.go(customers)
// customers.map(println(_)) // customers.map(println(_))
@ -61,6 +69,82 @@ object Main {
// println(s"Oops, an error occured. The error message was: $e") // println(s"Oops, an error occured. The error message was: $e")
// } // }
val hhc = new HHCSim2(
epsilonMax = 40,
iterations = 10,
WLDMax = 10,
customers = customers
)
val x = hhc.go()
x match {
case Left(value) => println(value)
case Right(value) =>
}
x.foreach(d => {
val (a, b, c, g) = d
println(c)
println
for (i <- 0 until b.length) {
if (!b(i).isEmpty) {
print(s"$i ")
print(b(i))
// edgeMappings
// b(i).foreach(e => {
// print(f"(${e.toNode}%d, ${e.weight}%.2f), ")
// })
println
}
}
println
for (i <- 0 until g.length) {
if (!g(i)._2.isEmpty) {
print(s"$i ")
print(g(i))
// edgeMappings
// b(i).foreach(e => {
// print(f"(${e.toNode}%d, ${e.weight}%.2f), ")
// })
println
}
}
println
var i = 0
a.foreach(e => {
if (!e.isEmpty) {
print(s"Cluster-$i: ")
i += 1
e.foreach(f => { print(s"$f ") })
println
}
})
})
val x2 = hhc.go2()
x2.map(_.map(println))
// x.map(e => {
// val (mst, rm) = e
// val y = HHCSim2.DFS(0)(mst)
// println(y)
// for (i <- 0 until mst.size) {
// print(s"$i -> ")
// mst(i).foreach(e => {
// print(f"(${e.toNode}, ${e.weight}%.2f), ")
// })
// println
// }
// println(rm)
// })
val coord1 = Coord(3, 4) val coord1 = Coord(3, 4)
println(s"Distance from origin = ${coord1.distance}") println(s"Distance from origin = ${coord1.distance}")

View File

@ -6,3 +6,5 @@ import util.Util
case class HHCEdge(v1: Customer, v2: Customer) { case class HHCEdge(v1: Customer, v2: Customer) {
val weight = Util.getHaversineDistance(v1.location, v2.location) val weight = Util.getHaversineDistance(v1.location, v2.location)
} }
case class HHCEdge2[T](fromNode: Int, toNode: Int, weight: T)

View File

@ -0,0 +1,29 @@
package model
import scala.collection.immutable.ArraySeq
import scala.collection.IndexedSeqView
trait HHCTypes {
/**
* Graph in mutable adjacency matrix form
*/
type GraphMatrix[T] = Array[Array[T]]
/**
* Graph in mutable adjacency list form
*/
type MutGraph[T] = Array[Array[HHCEdge2[T]]]
/**
* Graph in immutable adjacency list form
*/
type Graph[T] = ArraySeq[List[HHCEdge2[T]]]
/**
* List of removed edges
*/
type RemovedEdges[T] = List[HHCEdge2[T]]
type Clusters = ArraySeq[List[Int]]
}

View File

@ -0,0 +1,395 @@
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)
}
}

View File

@ -12,6 +12,8 @@ import com.typesafe.scalalogging.LazyLogging
import scala.collection.immutable.ArraySeq import scala.collection.immutable.ArraySeq
object Util extends LazyLogging { object Util extends LazyLogging {
type Graph[T] = IndexedSeq[Seq[(Int, T)]]
import Ordering.Implicits._
private val r = 6471.00 // km private val r = 6471.00 // km
def toRad(num: Double): Double = { def toRad(num: Double): Double = {
@ -253,6 +255,117 @@ object Util extends LazyLogging {
(mst, centroids.toIndexedSeq, removed.toIndexedSeq) (mst, centroids.toIndexedSeq, removed.toIndexedSeq)
} }
// def removeEdges[T](mst: IndexedSeq[Seq[(Int, T)]], epsilon: T)(
// implicit num: Numeric[T]
// ): (IndexedSeq[Seq[(Int, T)]], IndexedSeq[(Int, Int, T)]) = {
// // val mutMST = mst.to(Array)
// // val n = mst.length
// // val removed: mutable.ListBuffer[(Int, Int, T)] = mutable.ListBuffer.empty
// val it = mst.iterator
// @annotation.tailrec
// def loop(
// mst: IndexedSeq[Seq[(Int, T)]],
// removed: Seq[(Int, Int, T)],
// epsilon: T,
// iter: Iterator[Seq[(Int, T)]],
// index: Int
// )(
// implicit num: Numeric[T]
// ): (IndexedSeq[Seq[(Int, T)]], Seq[(Int, Int, T)]) = {
// if (!iter.hasNext) {
// return (mst, removed)
// }
// val lst = iter.next
// // val filtered = lst.filter(e => {
// // val (node, weight) = e
// // num.lt(weight, epsilon)
// // })
// // val rm = lst
// // .filter(e => {
// // val (node, weight) = e
// // num.gt(weight, epsilon)
// // })
// // .map(e => {
// // val (node, weight) = e
// // (index, node, weight)
// // })
// val (filtered, rm) = lst.partition(e => {
// val (node, weight) = e
// num.lt(weight, epsilon)
// })
// val rm2 = rm.map(e => {
// val (node, weight) = e
// (index, node, weight)
// })
// loop(
// mst.updated(index, filtered),
// removed ++ rm2,
// epsilon,
// iter,
// index + 1
// )
// }
// // for (i <- 0 until n) {
// // // for (j <- 0 until n) {
// // // val weight = mutMST(i)(j)._2
// // // if (num.gt(weight, epsilon) && weight != 0) {
// // // removed += ((i, j, weight))
// // // mutMST(i).remove(j)
// // // }
// // // }
// // // var j = 0;
// // // for ((node, weight) <- mutMST(i)) {
// // // if (num.gt(weight, epsilon) && weight != 0) {
// // // removed += ((i, j, weight))
// // // mutMST(i).remove(j)
// // // }
// // // j += 1
// // // }
// // mutMST(i) = mutMST(i).filter(e => {
// // val (node, weight) = e
// // removed += ((i, node, weight))
// // num.lt(weight, epsilon)
// // })
// // }
// // val updated = ArraySeq.unsafeWrapArray(mutMST.map(e => e.toList))
// // val updated = ArraySeq.unsafeWrapArray(mutMST)
// val (updated, removed) =
// loop(mst, Seq[(Int, Int, T)](), epsilon, it, 0)
// (updated, removed.toIndexedSeq)
// }
def removeEdges[N: Ordering](
mst: Graph[N]
)(epsilon: N): (Graph[N], List[(Int, Int, N)]) = {
import scala.collection.mutable.ListBuffer
val removed = ListBuffer.empty[(Int, Int, N)]
val result = ArraySeq.tabulate(mst.length) { i =>
val (filtered, rm) = mst(i).partitionMap {
case (node, weight) =>
if (weight <= epsilon)
Left((node, weight))
else
Right((i, node, weight))
}
removed ++= rm
filtered
}
(result, removed.toList)
}
def DFS[T]( def DFS[T](
start: Int, start: Int,
graph: Array[Array[T]] graph: Array[Array[T]]
@ -341,8 +454,7 @@ object Util extends LazyLogging {
lst: IndexedSeq[Customer], lst: IndexedSeq[Customer],
iter: Iterator[String] iter: Iterator[String]
): String Either IndexedSeq[Customer] = { ): String Either IndexedSeq[Customer] = {
if (!iter.hasNext) if (!iter.hasNext) return Right(lst)
return Right(lst)
val line = iter.next val line = iter.next
val arr = line.split(",").map(_.trim) val arr = line.split(",").map(_.trim)
arr match { arr match {