Command lines args and railway pattern
This commit is contained in:
parent
a6e0377816
commit
69a0c3ce63
20
Input.txt
Normal file
20
Input.txt
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
9.46, 0.90, 82.88
|
||||||
|
1.79, 7.90, 21.65
|
||||||
|
5.90, 2.98, 2.66
|
||||||
|
7.70, 9.18, 88.91
|
||||||
|
2.07, 9.57, 48.59
|
||||||
|
0.61, 3.38, 33.63
|
||||||
|
3.80, 1.31, 7.02
|
||||||
|
6.50, 1.13, 42.29
|
||||||
|
8.53, 0.56, 32.25
|
||||||
|
3.20, 8.90, 5.74
|
||||||
|
7.13, 8.38, 99.00
|
||||||
|
2.40, 3.40, 34.93
|
||||||
|
0.34, 6.58, 55.81
|
||||||
|
4.26, 0.94, 72.11
|
||||||
|
9.42, 7.50, 23.83
|
||||||
|
7.12, 4.67, 55.61
|
||||||
|
9.13, 9.82, 62.38
|
||||||
|
1.60, 3.12, 67.76
|
||||||
|
7.39, 7.44, 87.71
|
||||||
|
3.41, 9.76, 11.80
|
10
build.sbt
10
build.sbt
@ -1,19 +1,15 @@
|
|||||||
name := "scala-hhc"
|
name := "scala-hhc"
|
||||||
version := "1.0"
|
version := "0.0.1"
|
||||||
scalaVersion := "2.13.1"
|
scalaVersion := "2.13.1"
|
||||||
|
|
||||||
|
|
||||||
resolvers ++= Seq(
|
resolvers ++= Seq(
|
||||||
Resolver.sonatypeRepo("releases"),
|
Resolver.sonatypeRepo("releases"),
|
||||||
Resolver.sonatypeRepo("snapshots")
|
Resolver.sonatypeRepo("snapshots")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
// https://mvnrepository.com/artifact/org.projectlombok/lombok
|
|
||||||
libraryDependencies += "org.projectlombok" % "lombok" % "1.18.10" % "provided"
|
|
||||||
libraryDependencies ++= Seq(
|
libraryDependencies ++= Seq(
|
||||||
"org.typelevel" %% "cats-core" % "2.0.0",
|
"org.typelevel" %% "cats-core" % "2.0.0",
|
||||||
"com.softwaremill.quicklens" %% "quicklens" % "1.4.12",
|
"com.softwaremill.quicklens" %% "quicklens" % "1.4.12",
|
||||||
"com.softwaremill.macwire" %% "macros" % "2.3.3",
|
"com.softwaremill.macwire" %% "macros" % "2.3.3",
|
||||||
"me.shadaj" %% "scalapy-numpy" % "0.1.0+5-ad550211"
|
"org.rogach" %% "scallop" % "3.4.0"
|
||||||
)
|
)
|
||||||
|
31
src/main/scala/HHCSim.scala
Normal file
31
src/main/scala/HHCSim.scala
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import model.Customer
|
||||||
|
import util._
|
||||||
|
class HHCSim(
|
||||||
|
private val epsilonMax: Int,
|
||||||
|
private val iterations: Int,
|
||||||
|
// private val customers: IndexedSeq[Customer],
|
||||||
|
private val WLDMax: Float
|
||||||
|
) {
|
||||||
|
// private val graph: Array[Array[T]]
|
||||||
|
def go(
|
||||||
|
customers: Either[String, IndexedSeq[Customer]]
|
||||||
|
): String Either Map[Int, IndexedSeq[(Int, Double)]] =
|
||||||
|
customers
|
||||||
|
.map(Util.formAdjMatrix)
|
||||||
|
.map(edges => Util.mstUsingPrims(edges))
|
||||||
|
.map(mst => Util.findCentroids(mst))
|
||||||
|
.map(
|
||||||
|
e =>
|
||||||
|
e match {
|
||||||
|
case (mst, centroids, removed) =>
|
||||||
|
Util.findClusters(mst, centroids, removed)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.map(
|
||||||
|
e =>
|
||||||
|
e match {
|
||||||
|
case (centroids, clusters, removed) =>
|
||||||
|
Util.groupClusters(centroids, clusters, removed)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
@ -1,11 +1,40 @@
|
|||||||
import model.Coord
|
import model.Coord
|
||||||
import model.Customer
|
import model.Customer
|
||||||
import model.HHCEdge
|
import model.HHCEdge
|
||||||
import scala.collection.mutable._
|
import scala.collection.mutable.ArrayBuffer
|
||||||
import util.Util
|
import util.Util
|
||||||
|
import config.Conf
|
||||||
|
import java.io.File
|
||||||
object Main {
|
object Main {
|
||||||
def main(args: Array[String]): Unit = {
|
def main(args: Array[String]): Unit = {
|
||||||
|
|
||||||
|
val conf = new Conf(args.toIndexedSeq)
|
||||||
|
|
||||||
|
val bufferedSource = io.Source.fromFile(conf.infile())
|
||||||
|
|
||||||
|
val customers = Util.getCustomers(bufferedSource)
|
||||||
|
bufferedSource.close()
|
||||||
|
// customers.map(println(_))
|
||||||
|
|
||||||
|
// val edges3 = customers.map(Util.formAdjMatrix)
|
||||||
|
|
||||||
|
// val fnl2 = go(customers)
|
||||||
|
|
||||||
|
// fnl2 match {
|
||||||
|
// case Left(value) => println(value)
|
||||||
|
// case Right(value) => println(value)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// edges3 match {
|
||||||
|
// case Right(e) =>
|
||||||
|
// e.foreach { d =>
|
||||||
|
// d.foreach(g => print(f"$g%.2f, "))
|
||||||
|
// println()
|
||||||
|
// }
|
||||||
|
// case Left(e) =>
|
||||||
|
// println(s"Oops, an error occured. The error message was: $e")
|
||||||
|
// }
|
||||||
|
|
||||||
val coord1 = Coord(3, 4)
|
val coord1 = Coord(3, 4)
|
||||||
println(s"Distance from origin = ${coord1.distance}")
|
println(s"Distance from origin = ${coord1.distance}")
|
||||||
|
|
||||||
@ -128,14 +157,14 @@ object Main {
|
|||||||
// 0, 0, 51, 0 , 31
|
// 0, 0, 51, 0 , 31
|
||||||
// 0, 0, 0 , 0 , 0
|
// 0, 0, 0 , 0 , 0
|
||||||
|
|
||||||
val (centr, removed) = Util.findCentroids(mst)
|
val (mst2, centr, removed) = Util.findCentroids(mst)
|
||||||
// val (centr2, eds2) = Util.findCentroids(edges2)
|
// val (centr2, eds2) = Util.findCentroids(edges2)
|
||||||
|
|
||||||
println()
|
println()
|
||||||
println(s"Centroids: \n$centr")
|
println(s"Centroids: \n$centr")
|
||||||
println(s"Removed: \n$removed")
|
println(s"Removed: \n$removed")
|
||||||
|
|
||||||
val clust = Util.findClusters(mst, centr)
|
val (_, clust, _) = Util.findClusters(mst, centr, removed)
|
||||||
val adjList = Util.makeAdjacencyList(edges, centr)
|
val adjList = Util.makeAdjacencyList(edges, centr)
|
||||||
|
|
||||||
println(s"Clusters:")
|
println(s"Clusters:")
|
||||||
@ -156,28 +185,28 @@ object Main {
|
|||||||
// Output
|
// Output
|
||||||
//
|
//
|
||||||
// Initial graph:
|
// Initial graph:
|
||||||
// 0, 9, 75, 0, 0,
|
// 0, 9, 75, 0, 0,
|
||||||
// 9, 0, 95, 19, 42,
|
// 9, 0, 95, 19, 42,
|
||||||
// 75, 95, 0, 51, 66,
|
// 75, 95, 0, 51, 66,
|
||||||
// 0, 19, 51, 0, 31,
|
// 0, 19, 51, 0, 31,
|
||||||
// 0, 42, 66, 31, 0,
|
// 0, 42, 66, 31, 0,
|
||||||
// MST:
|
// MST:
|
||||||
// 0, 9, 0, 0, 0,
|
// 0, 9, 0, 0, 0,
|
||||||
// 9, 0, 0, 19, 0,
|
// 9, 0, 0, 19, 0,
|
||||||
// 0, 0, 0, 51, 0,
|
// 0, 0, 0, 51, 0,
|
||||||
// 0, 19, 51, 0, 31,
|
// 0, 19, 51, 0, 31,
|
||||||
// 0, 0, 0, 31, 0,
|
// 0, 0, 0, 31, 0,
|
||||||
|
|
||||||
// Centroids:
|
// Centroids:
|
||||||
// Vector(2, 3, 4)
|
// Vector(2, 3, 4)
|
||||||
// Removed:
|
// Removed:
|
||||||
// Vector((2,3,51), (3,2,51), (3,4,31), (4,3,31))
|
// Vector((2,3,51), (3,2,51), (3,4,31), (4,3,31))
|
||||||
// Clusters:
|
// Clusters:
|
||||||
// 2: -> 2
|
// 2: -> 2
|
||||||
// 3: -> 3 -> 1 -> 0
|
// 3: -> 3 -> 1 -> 0
|
||||||
// 4: -> 4
|
// 4: -> 4
|
||||||
|
|
||||||
// Final cluster groups:
|
// Final cluster groups:
|
||||||
// Map(2 -> Vector((3,51)), 3 -> Vector((4,31), (2,51)), 4 -> Vector((3,31)))
|
// Map(2 -> Vector((3,51)), 3 -> Vector((4,31), (2,51)), 4 -> Vector((3,31)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
11
src/main/scala/config/Config.scala
Normal file
11
src/main/scala/config/Config.scala
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import org.rogach.scallop._
|
||||||
|
|
||||||
|
class Conf(arguments: Seq[String]) extends ScallopConf(arguments) {
|
||||||
|
val infile =
|
||||||
|
opt[String](default = Some("Input.txt"), descr = "Input file")
|
||||||
|
val outfile =
|
||||||
|
opt[String](default = Some("Output.txt"), descr = "Output file")
|
||||||
|
verify()
|
||||||
|
}
|
@ -4,6 +4,9 @@ import model.Coord
|
|||||||
import scala.math._
|
import scala.math._
|
||||||
import scala.collection.mutable.ArrayBuffer
|
import scala.collection.mutable.ArrayBuffer
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
|
import model.Customer
|
||||||
|
import scala.io.BufferedSource
|
||||||
|
import scala.reflect.ClassTag
|
||||||
|
|
||||||
object Util {
|
object Util {
|
||||||
private val r = 6471.00 // km
|
private val r = 6471.00 // km
|
||||||
@ -85,16 +88,16 @@ object Util {
|
|||||||
selected(y) = true
|
selected(y) = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
def mstUsingPrims(
|
|
||||||
edges: Array[Array[Int]]
|
def mstUsingPrims[T: ClassTag](
|
||||||
): Array[Array[Int]] = {
|
edges: Array[Array[T]]
|
||||||
|
)(implicit num: Numeric[T]): Array[Array[T]] = {
|
||||||
val n = edges.length
|
val n = edges.length
|
||||||
val selected: ArrayBuffer[Boolean] = ArrayBuffer.fill(n)(false)
|
val selected: ArrayBuffer[Boolean] = ArrayBuffer.fill(n)(false)
|
||||||
|
|
||||||
selected(0) = true
|
selected(0) = true
|
||||||
|
|
||||||
val mst: Array[Array[Int]] = Array.ofDim(n, n)
|
val mst: Array[Array[T]] = Array.ofDim[T](n, n)
|
||||||
|
|
||||||
|
|
||||||
for (_ <- 0 until n - 1) {
|
for (_ <- 0 until n - 1) {
|
||||||
var min = 999999
|
var min = 999999
|
||||||
@ -104,8 +107,8 @@ object Util {
|
|||||||
if (selected(i) == true) {
|
if (selected(i) == true) {
|
||||||
for (j <- 0 until n) {
|
for (j <- 0 until n) {
|
||||||
if (selected(j) == false && edges(i)(j) != 0) {
|
if (selected(j) == false && edges(i)(j) != 0) {
|
||||||
if (min > edges(i)(j)) {
|
if (num.gt(num.fromInt(min), edges(i)(j))) {
|
||||||
min = edges(i)(j)
|
min = num.toInt(edges(i)(j))
|
||||||
x = i
|
x = i
|
||||||
y = j
|
y = j
|
||||||
}
|
}
|
||||||
@ -122,19 +125,21 @@ object Util {
|
|||||||
mst
|
mst
|
||||||
}
|
}
|
||||||
|
|
||||||
def findClusters(
|
def findClusters[T](
|
||||||
mst: Array[Array[Int]],
|
mst: Array[Array[T]],
|
||||||
centroids: IndexedSeq[Int]
|
centroids: IndexedSeq[Int],
|
||||||
): Map[Int, ArrayBuffer[Int]] = {
|
removed: IndexedSeq[(Int, Int, T)]
|
||||||
val n = mst.length
|
)(implicit num: Numeric[T]) =
|
||||||
val x: Map[Int, ArrayBuffer[Int]] = centroids
|
(
|
||||||
.map(d => {
|
centroids,
|
||||||
val y = DFS(d, mst)
|
centroids
|
||||||
y(0) -> y
|
.map(d => {
|
||||||
})
|
val y = DFS(d, mst)
|
||||||
.toMap
|
y(0) -> y
|
||||||
x
|
})
|
||||||
}
|
.toMap,
|
||||||
|
removed
|
||||||
|
)
|
||||||
|
|
||||||
def makeAdjacencyList(
|
def makeAdjacencyList(
|
||||||
mst: Array[Array[Int]],
|
mst: Array[Array[Int]],
|
||||||
@ -160,7 +165,9 @@ object Util {
|
|||||||
|
|
||||||
def findCentroids[T](
|
def findCentroids[T](
|
||||||
mst: Array[Array[T]]
|
mst: Array[Array[T]]
|
||||||
)(implicit ev: Numeric[T]): (IndexedSeq[Int], IndexedSeq[(Int, Int, T)]) = {
|
)(
|
||||||
|
implicit ev: Numeric[T]
|
||||||
|
): (Array[Array[T]], IndexedSeq[Int], IndexedSeq[(Int, Int, T)]) = {
|
||||||
val n = mst.length
|
val n = mst.length
|
||||||
val centroids: mutable.Set[Int] = mutable.Set.empty
|
val centroids: mutable.Set[Int] = mutable.Set.empty
|
||||||
val removed: ArrayBuffer[(Int, Int, T)] = ArrayBuffer.empty
|
val removed: ArrayBuffer[(Int, Int, T)] = ArrayBuffer.empty
|
||||||
@ -175,37 +182,26 @@ object Util {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(centroids.toIndexedSeq, removed.toIndexedSeq)
|
(mst, centroids.toIndexedSeq, removed.toIndexedSeq)
|
||||||
}
|
}
|
||||||
|
|
||||||
// def DFS(start: Int, graph: Array[Array[Int]], visited: Array[Boolean]): Unit = {
|
def DFS[T](
|
||||||
// // if(start == 0) {
|
|
||||||
// // visited = Array.fill(graph.size)(false)
|
|
||||||
// // }
|
|
||||||
// visited(start) = true
|
|
||||||
|
|
||||||
// println(s"$start ")
|
|
||||||
|
|
||||||
// for(i <- 0 until graph.size) {
|
|
||||||
// if (graph(start)(i) > 0 && graph(start)(i) < 20 && (!visited(i))) {
|
|
||||||
// DFS(i, graph, visited);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// val visited = Array.fill(mst.size)(false)
|
|
||||||
def DFS(
|
|
||||||
start: Int,
|
start: Int,
|
||||||
graph: Array[Array[Int]]
|
graph: Array[Array[T]]
|
||||||
): ArrayBuffer[Int] = {
|
)(implicit num: Numeric[T]): ArrayBuffer[Int] = {
|
||||||
val visited = Array.fill(graph.size)(false)
|
val visited = Array.fill(graph.size)(false)
|
||||||
val buf = ArrayBuffer[Int]()
|
val buf = ArrayBuffer[Int]()
|
||||||
def loop(start: Int, graph: Array[Array[Int]], visited: Array[Boolean]) {
|
def loop(
|
||||||
|
start: Int,
|
||||||
|
graph: Array[Array[T]],
|
||||||
|
visited: Array[Boolean]
|
||||||
|
): Unit = {
|
||||||
visited(start) = true
|
visited(start) = true
|
||||||
buf += start
|
buf += start
|
||||||
// print(s"$start ")
|
// print(s"$start ")
|
||||||
|
|
||||||
for (i <- 0 until graph.size) {
|
for (i <- 0 until graph.size) {
|
||||||
if (graph(start)(i) > 0 && (!visited(i))) {
|
if (num.gt(graph(start)(i), num.fromInt(0)) && (!visited(i))) {
|
||||||
loop(i, graph, visited);
|
loop(i, graph, visited);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -224,7 +220,11 @@ object Util {
|
|||||||
): ArrayBuffer[Int] = {
|
): ArrayBuffer[Int] = {
|
||||||
val visited = Array.fill(graph.size)(false)
|
val visited = Array.fill(graph.size)(false)
|
||||||
val buf = ArrayBuffer[Int]()
|
val buf = ArrayBuffer[Int]()
|
||||||
def loop(start: Int, graph: Array[Array[Int]], visited: Array[Boolean]) {
|
def loop(
|
||||||
|
start: Int,
|
||||||
|
graph: Array[Array[Int]],
|
||||||
|
visited: Array[Boolean]
|
||||||
|
): Unit = {
|
||||||
visited(start) = true
|
visited(start) = true
|
||||||
buf += start
|
buf += start
|
||||||
// print(s"$start ")
|
// print(s"$start ")
|
||||||
@ -241,12 +241,12 @@ object Util {
|
|||||||
buf
|
buf
|
||||||
}
|
}
|
||||||
|
|
||||||
def groupClusters(
|
def groupClusters[T](
|
||||||
centroids: IndexedSeq[Int],
|
centroids: IndexedSeq[Int],
|
||||||
clusters: Map[Int, ArrayBuffer[Int]],
|
clusters: Map[Int, ArrayBuffer[Int]],
|
||||||
removed: IndexedSeq[(Int, Int, Int)]
|
removed: IndexedSeq[(Int, Int, T)]
|
||||||
) = {
|
)(implicit num: Numeric[T]) =
|
||||||
val groups = centroids
|
centroids
|
||||||
.map(c => {
|
.map(c => {
|
||||||
val cluster = clusters(c)
|
val cluster = clusters(c)
|
||||||
val lst = removed
|
val lst = removed
|
||||||
@ -254,15 +254,70 @@ object Util {
|
|||||||
c == r._1
|
c == r._1
|
||||||
})
|
})
|
||||||
.sortWith((x, y) => {
|
.sortWith((x, y) => {
|
||||||
x._3 < y._3
|
num.lt(x._3, y._3)
|
||||||
})
|
})
|
||||||
.map(l => {
|
.map(l => {
|
||||||
(l._2,l._3)
|
(l._2, l._3)
|
||||||
})
|
})
|
||||||
c -> lst
|
c -> lst
|
||||||
})
|
})
|
||||||
.toMap
|
.toMap
|
||||||
groups
|
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user