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.

506 lines
14 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. package sim
  2. import model.HHCTypes
  3. import scala.reflect.ClassTag
  4. import scala.collection.mutable.{ArrayBuffer, ListBuffer}
  5. import scala.collection.immutable.ArraySeq
  6. import model.HHCEdge2
  7. import util.Util
  8. import model.Customer
  9. import scala.io.BufferedSource
  10. import model.Coord
  11. import scala.util.Random
  12. import com.typesafe.scalalogging.LazyLogging
  13. import cats.implicits
  14. import scala.util.chaining._
  15. class HHCSim2(
  16. epsilonMax: Int = 0,
  17. iterations: Int = 0,
  18. WLDMax: Float = 0,
  19. customers: String Either ArraySeq[Customer]
  20. ) extends LazyLogging {
  21. import HHCSim2._
  22. import Ordering.Double.IeeeOrdering
  23. private var adjMatrix: Option[GraphMatrix[Double]] = None
  24. def go() = {
  25. customers
  26. .flatMap(checkEmpty)
  27. .map(formAdjMatrix)
  28. .tap(logGraph)
  29. .tap(_.foreach(e => adjMatrix = Some(e)))
  30. .map(e => mstUsingPrims(e))
  31. .tap(logMST)
  32. .map { case (mst, epsilon) => removeEdges(mst)(epsilon) }
  33. .tap(logMST2)
  34. .map { case (mstUpdated, removed) => findClusters(mstUpdated)(removed) }
  35. .map {
  36. case (mstUpdated, clusters, edgeMappings, removedEdges) =>
  37. printClusters(clusters)
  38. val e =
  39. groupClusters(mstUpdated, clusters, edgeMappings, removedEdges)
  40. printGroups(e._5)
  41. e
  42. }
  43. .flatMap(value => {
  44. val (mst, clusters, edgeMappings, removed, clusterGroups) = value
  45. balanceWorkload(clusters, clusterGroups)
  46. })
  47. }
  48. // def go2() = {
  49. // val res = go().flatMap(value => {
  50. // val (mst, clusters, edgeMappings, removed, clusterGroups) = value
  51. // balanceWorkload(mst, clusters, clusterGroups)
  52. // })
  53. // res
  54. // }
  55. def printGraph(graph: GraphMatrix[Double]) = graph.foreach { e =>
  56. e.foreach { d =>
  57. print(f"$d%.2f, ")
  58. }
  59. println
  60. }
  61. def printGraph(graph: Graph[Double]) = {
  62. for (i <- 0 until graph.size) {
  63. print(s"$i: ")
  64. for (edge <- graph(i)) {
  65. print(f"(${edge.toNode}, ${edge.weight}%.2f), ")
  66. }
  67. println
  68. }
  69. }
  70. def logGraph(maybeGraph: Either[String, GraphMatrix[Double]]): Unit =
  71. maybeGraph.foreach(
  72. graph => {
  73. logger.whenDebugEnabled {
  74. logger.debug("Graph: ")
  75. printGraph(graph)
  76. }
  77. }
  78. )
  79. def logMST(maybeMST: Either[String, (Graph[Double], Double)]): Unit =
  80. maybeMST.foreach(
  81. t => {
  82. logger.whenDebugEnabled {
  83. logger.debug(s"Epsilon = ${t._2}")
  84. logger.debug("MST: ")
  85. printGraph(graph = t._1)
  86. }
  87. }
  88. )
  89. def logMST2(it: Either[String, (Graph[Double], RemovedEdges[Double])]): Unit =
  90. it.foreach(
  91. t => {
  92. logger.whenDebugEnabled {
  93. logger.debug(s"Removed Edges = ${t._2}")
  94. logger.debug("MST: ")
  95. printGraph(graph = t._1)
  96. }
  97. }
  98. )
  99. def printClusters(clusters: Clusters) = {
  100. logger.whenDebugEnabled {
  101. logger.debug("Clusters:")
  102. var i = 0
  103. clusters.foreach(e => {
  104. print(s"Cluster-$i: ")
  105. i += 1
  106. e.foreach(f => print(s"$f "))
  107. println
  108. })
  109. }
  110. }
  111. def printClusters(clusters: Array[List[Int]]) = {
  112. logger.whenDebugEnabled {
  113. logger.debug("Clusters:")
  114. var i = 0
  115. clusters.foreach(e => {
  116. print(s"Cluster-$i: ")
  117. i += 1
  118. e.foreach(f => print(s"$f "))
  119. println
  120. })
  121. }
  122. }
  123. def printGroups(groups: ArraySeq[List[(Int, Double)]]) = {
  124. logger.whenDebugEnabled {
  125. logger.debug("Neighbours: ")
  126. var i = 0
  127. groups.foreach(e => {
  128. print(s"Cluster-$i: ")
  129. i += 1
  130. e.foreach(f => { print(f"(${f._1}%d, ${f._2}%.2f), ") })
  131. println
  132. })
  133. }
  134. }
  135. def balanceWorkload[N: Numeric](
  136. clusters: Clusters,
  137. groups: ArraySeq[List[(Int, N)]]
  138. ) = {
  139. customers.map(c => {
  140. val mutClusters =
  141. clusters.toArray
  142. val clusterOrder = (0 until clusters.length).toArray
  143. logger.debug(s"Initial order: $clusterOrder")
  144. val k = mutClusters.size
  145. for (_ <- 0 until iterations) {
  146. val WL = mutClusters.view
  147. .map(nodes => {
  148. val customers = nodes.map(node => c(node))
  149. val wl = customers.foldLeft(0f)(_ + _.workload)
  150. wl
  151. })
  152. .to(ArraySeq)
  153. logger.debug(s"$WL")
  154. clusterOrder.sortInPlaceWith((x, y) => WL(x) < WL(y))
  155. logger.debug(s"Current order $clusterOrder")
  156. val (minWL, maxWL) = WL.foldLeft((99999f, 0f))((acc, wl) => {
  157. val (currMin, currMax) = acc
  158. if (wl < currMin) (wl, currMax)
  159. else if (wl > currMax) (currMin, wl)
  160. else acc
  161. })
  162. val WLD = maxWL - minWL
  163. logger.debug(s"maxWL = $maxWL, minWL = $minWL")
  164. logger.debug(s"WLD = $WLD")
  165. if (WLD > WLDMax) {
  166. val randNum = Random.between(((k / 2) + 1), k)
  167. logger.debug(s"Rand Num=$randNum")
  168. val effectiveNum = clusterOrder(randNum)
  169. logger.debug(s"Chosen cluster = $effectiveNum")
  170. val (s, _) = groups(effectiveNum)(0)
  171. logger.debug(s"Nearest neighbour = $s")
  172. // val avg = averagePairwiseDistance(mst(s))
  173. val avg = adjMatrix
  174. .map(m => averagePairwiseDistance(m)(mutClusters(s)))
  175. .getOrElse(9999d)
  176. // if (avg < epsilonMax) true else false
  177. logger.debug(s"Pairwise average = $avg")
  178. if (avg < epsilonMax) {
  179. logger.debug("Average less than epsilonMax. Updating Clusters.")
  180. if (!mutClusters(s).contains(effectiveNum)) {
  181. mutClusters(s) = effectiveNum :: mutClusters(s)
  182. }
  183. // mutClusters.foreach(println)
  184. printClusters(mutClusters)
  185. }
  186. }
  187. }
  188. ArraySeq.unsafeWrapArray(mutClusters)
  189. })
  190. }
  191. def averagePairwiseDistance(graph: GraphMatrix[Double])(
  192. cluster: List[Int]
  193. ) = {
  194. val (sum, size) = cluster
  195. .combinations(2)
  196. .foldLeft((0d, 0))((acc, pair) => {
  197. val (sum, size) = acc
  198. val (i, j) = pair(0) -> pair(1)
  199. logger.trace(s"$i $j - ")
  200. logger.trace(s"weight = ${graph(i)(j)}")
  201. (sum + graph(i)(j), size + 1)
  202. })
  203. val n = if (size == 0) 1 else size
  204. sum / n
  205. }
  206. }
  207. object HHCSim2 extends HHCTypes {
  208. import Ordering.Implicits._
  209. val composed = (formAdjMatrix _)
  210. .andThen(e => mstUsingPrims(e))
  211. .andThen { case (mst, epsilon) => removeEdges(mst)(epsilon) }
  212. .andThen { case (mstUpdated, removed) => findClusters(mstUpdated)(removed) }
  213. def getCustomers(
  214. infile: BufferedSource
  215. ): String Either ArraySeq[Customer] = {
  216. var customers: String Either ArraySeq[Customer] = Right(ArraySeq.empty)
  217. val it = infile.getLines
  218. @annotation.tailrec
  219. def loop(
  220. lst: ListBuffer[Customer],
  221. iter: Iterator[String]
  222. ): String Either ListBuffer[Customer] = {
  223. if (!iter.hasNext) Right(lst)
  224. else {
  225. val line = iter.next
  226. val arr = line.split(",").map(_.trim)
  227. arr match {
  228. case Array(latitude, longitude, workLoad) => {
  229. val cust =
  230. for {
  231. lat <- latitude.toDoubleOption
  232. lon <- longitude.toDoubleOption
  233. coord = Coord(lat, lon)
  234. wl <- workLoad.toFloatOption
  235. } yield (Customer(coord, wl))
  236. cust match {
  237. case Some(c) => loop(lst += c, iter)
  238. case None => Left(s"Error reading customers at line - $line")
  239. }
  240. }
  241. case _ => {
  242. if (line.equals(" ") || line.contains("\n"))
  243. Left("Error newline")
  244. else {
  245. Left(
  246. "Error reading customers from" +
  247. s" file at line - $line}"
  248. )
  249. }
  250. }
  251. }
  252. }
  253. }
  254. try {
  255. customers = loop(ListBuffer.empty, it).map(_.to(ArraySeq))
  256. } catch {
  257. case e: NumberFormatException =>
  258. customers = Left(
  259. s"Expected number but received string ${e.getMessage()}"
  260. )
  261. case e: NullPointerException =>
  262. customers = Left("Input was null")
  263. }
  264. customers
  265. }
  266. def checkEmpty(
  267. customers: IndexedSeq[Customer]
  268. ): Either[String, IndexedSeq[Customer]] =
  269. customers.length match {
  270. case 0 => Left("Error input was empty")
  271. case _ => Right(customers)
  272. }
  273. def formAdjMatrix(customers: IndexedSeq[Customer]): GraphMatrix[Double] = {
  274. val n = customers.length
  275. val edges: Array[Array[Double]] = Array.ofDim(n, n)
  276. for (i <- 0 until n) {
  277. for (j <- i until n) {
  278. val weight =
  279. Util.getHaversineDistance(
  280. customers(i).location,
  281. customers(j).location
  282. )
  283. edges(i)(j) = weight
  284. edges(j)(i) = weight
  285. }
  286. }
  287. edges
  288. }
  289. def mstUsingPrims[T: Numeric](
  290. edges: GraphMatrix[T]
  291. ): (Graph[T], T) = {
  292. val num = implicitly[Numeric[T]]
  293. val n = edges.length
  294. val selected: Array[Boolean] = Array.fill(n)(false)
  295. selected(0) = true
  296. val adjList =
  297. Array.fill(n)(ListBuffer.empty[HHCEdge2[T]])
  298. var sum = 0
  299. var count = 0
  300. for (_ <- 0 until n - 1) {
  301. var min = 999999
  302. var x = 0
  303. var y = 0
  304. for (i <- 0 until n) {
  305. if (selected(i) == true) {
  306. for (j <- 0 until n) {
  307. if (selected(j) == false && edges(i)(j) != 0) {
  308. if (min > num.toInt(edges(i)(j))) {
  309. min = num.toInt(edges(i)(j))
  310. x = i
  311. y = j
  312. }
  313. }
  314. }
  315. }
  316. }
  317. sum += num.toInt(edges(x)(y))
  318. adjList(x) += HHCEdge2(x, y, edges(x)(y))
  319. adjList(y) += HHCEdge2(y, x, edges(x)(y))
  320. selected(y) = true
  321. }
  322. val adjList2 = adjList.map(l => {
  323. count += l.size
  324. l.toList
  325. })
  326. // adjList2.foreach(println)
  327. (ArraySeq.unsafeWrapArray(adjList2), num.fromInt(sum / (count / 2)))
  328. }
  329. def removeEdges[N: Ordering](
  330. mst: Graph[N]
  331. )(epsilon: N): (Graph[N], RemovedEdges[N]) = {
  332. val removed = ListBuffer.empty[HHCEdge2[N]]
  333. val result = ArraySeq.tabulate(mst.length) { i =>
  334. val (filtered, rm) = mst(i)
  335. // .view
  336. // .filter(e => (e.fromNode <= e.toNode))
  337. .partition(_.weight <= epsilon)
  338. // val rm2 = rm.filter(e => (e.fromNode <= e.toNode))
  339. removed ++= rm
  340. filtered
  341. }
  342. println
  343. // result.foreach(println)
  344. // println
  345. (result, removed.toList)
  346. }
  347. def DFS[T: Numeric](start: Int)(graph: Graph[T]) = {
  348. val visited = Array.fill(graph.size)(false)
  349. val buf = ListBuffer[Int]()
  350. def loop(
  351. start: Int,
  352. graph: Graph[T],
  353. visited: Array[Boolean]
  354. ): Unit = {
  355. visited(start) = true
  356. buf += start
  357. // val iter = graph(start).iterator
  358. // while (iter.hasNext) {
  359. // val edge = iter.next
  360. // if (!visited(edge.toNode))
  361. // loop(edge.toNode, graph, visited)
  362. // }
  363. for (edge <- graph(start)) {
  364. if (!visited(edge.toNode))
  365. loop(edge.toNode, graph, visited)
  366. }
  367. }
  368. loop(start, graph, visited)
  369. buf.toList
  370. }
  371. def findClusters[T: Numeric](mstUpdated: Graph[T])(
  372. removedEdges: RemovedEdges[T]
  373. ): (Graph[T], Clusters, ArraySeq[List[HHCEdge2[T]]], RemovedEdges[T]) = {
  374. val visited = Array.fill[Boolean](mstUpdated.length)(false)
  375. var removedEdges2 = removedEdges
  376. val egdeMappings =
  377. Array.fill(mstUpdated.length)(List.empty[HHCEdge2[T]])
  378. val nodeToClusterMappings = Array.fill(mstUpdated.length)(0)
  379. val result = ArraySeq.tabulate(mstUpdated.length) { i =>
  380. {
  381. val buf = ListBuffer[Int]()
  382. visited(i) match {
  383. case true =>
  384. case false if (!mstUpdated(i).isEmpty) => {
  385. val nodes = DFS(i)(mstUpdated)
  386. buf ++= nodes
  387. val (nds, rms) = assignEdges(nodes, removedEdges2)
  388. removedEdges2 = rms
  389. egdeMappings(i) = nds
  390. for (j <- nodes) visited(j) = true
  391. }
  392. case false => {
  393. buf += i
  394. val (nds, rms) = assignEdges(List(i), removedEdges2)
  395. egdeMappings(i) = nds
  396. removedEdges2 = rms
  397. }
  398. }
  399. buf.toList
  400. }
  401. }
  402. // println(s"Removed edges size: ${removedEdges2.size}")
  403. (
  404. mstUpdated,
  405. result.filterNot(_.isEmpty),
  406. ArraySeq.unsafeWrapArray(egdeMappings.filterNot(_.isEmpty)),
  407. removedEdges
  408. )
  409. }
  410. def assignEdges[T: Ordering](
  411. nodes: List[Int],
  412. removedEdges: RemovedEdges[T]
  413. ) = {
  414. val it = nodes.iterator
  415. @annotation.tailrec
  416. def loop(
  417. nodes: List[Int],
  418. removedEdges: RemovedEdges[T],
  419. iter: Iterator[Int],
  420. edges: List[HHCEdge2[T]]
  421. ): (List[HHCEdge2[T]], RemovedEdges[T]) = {
  422. if (!iter.hasNext) (edges, removedEdges)
  423. else if (!edges.isEmpty) (edges, removedEdges)
  424. else {
  425. val node = iter.next
  426. val (filt, rm) =
  427. removedEdges.partition(e => e.fromNode == node)
  428. loop(nodes, rm, iter, filt)
  429. }
  430. }
  431. val (edges, removedEdgesUpdated) =
  432. loop(nodes, removedEdges, it, List.empty[HHCEdge2[T]])
  433. (edges, removedEdgesUpdated)
  434. }
  435. def mapNodestoClusters[N: Ordering](mst: Graph[N], clusters: Clusters) = {
  436. val arr = Array.fill(mst.size)(0)
  437. for (i <- 0 until clusters.size) {
  438. val nodes = clusters(i)
  439. for (node <- nodes) {
  440. arr(node) = i
  441. }
  442. }
  443. ArraySeq.unsafeWrapArray(arr)
  444. }
  445. def groupClusters[N: Ordering](
  446. mst: Graph[N],
  447. clusters: Clusters,
  448. edgeMappings: ArraySeq[List[HHCEdge2[N]]],
  449. removed: RemovedEdges[N]
  450. ) = {
  451. val nodeMap = mapNodestoClusters(mst, clusters)
  452. val groups = ArraySeq.tabulate(edgeMappings.size)(i => {
  453. val buf = ListBuffer.empty[(Int, N)]
  454. val lst = edgeMappings(i)
  455. lst.foreach(e => {
  456. buf += nodeMap(e.toNode) -> e.weight
  457. })
  458. buf.sortWith {
  459. case ((_, weight1), (_, weight2)) =>
  460. weight1 < weight2
  461. }.toList
  462. })
  463. (mst, clusters, edgeMappings, removed, groups)
  464. }
  465. }