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
|
@ -1,19 +1,15 @@
|
||||
name := "scala-hhc"
|
||||
version := "1.0"
|
||||
version := "0.0.1"
|
||||
scalaVersion := "2.13.1"
|
||||
|
||||
|
||||
resolvers ++= Seq(
|
||||
Resolver.sonatypeRepo("releases"),
|
||||
Resolver.sonatypeRepo("snapshots")
|
||||
)
|
||||
|
||||
|
||||
// https://mvnrepository.com/artifact/org.projectlombok/lombok
|
||||
libraryDependencies += "org.projectlombok" % "lombok" % "1.18.10" % "provided"
|
||||
libraryDependencies ++= Seq(
|
||||
"org.typelevel" %% "cats-core" % "2.0.0",
|
||||
"com.softwaremill.quicklens" %% "quicklens" % "1.4.12",
|
||||
"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.Customer
|
||||
import model.HHCEdge
|
||||
import scala.collection.mutable._
|
||||
import scala.collection.mutable.ArrayBuffer
|
||||
import util.Util
|
||||
import config.Conf
|
||||
import java.io.File
|
||||
object Main {
|
||||
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)
|
||||
println(s"Distance from origin = ${coord1.distance}")
|
||||
|
||||
@ -128,14 +157,14 @@ object Main {
|
||||
// 0, 0, 51, 0 , 31
|
||||
// 0, 0, 0 , 0 , 0
|
||||
|
||||
val (centr, removed) = Util.findCentroids(mst)
|
||||
val (mst2, centr, removed) = Util.findCentroids(mst)
|
||||
// val (centr2, eds2) = Util.findCentroids(edges2)
|
||||
|
||||
println()
|
||||
println(s"Centroids: \n$centr")
|
||||
println(s"Removed: \n$removed")
|
||||
|
||||
val clust = Util.findClusters(mst, centr)
|
||||
val (_, clust, _) = Util.findClusters(mst, centr, removed)
|
||||
val adjList = Util.makeAdjacencyList(edges, centr)
|
||||
|
||||
println(s"Clusters:")
|
||||
|
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.collection.mutable.ArrayBuffer
|
||||
import scala.collection.mutable
|
||||
import model.Customer
|
||||
import scala.io.BufferedSource
|
||||
import scala.reflect.ClassTag
|
||||
|
||||
object Util {
|
||||
private val r = 6471.00 // km
|
||||
@ -85,16 +88,16 @@ object Util {
|
||||
selected(y) = true
|
||||
}
|
||||
}
|
||||
def mstUsingPrims(
|
||||
edges: Array[Array[Int]]
|
||||
): Array[Array[Int]] = {
|
||||
|
||||
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[Int]] = Array.ofDim(n, n)
|
||||
|
||||
val mst: Array[Array[T]] = Array.ofDim[T](n, n)
|
||||
|
||||
for (_ <- 0 until n - 1) {
|
||||
var min = 999999
|
||||
@ -104,8 +107,8 @@ object Util {
|
||||
if (selected(i) == true) {
|
||||
for (j <- 0 until n) {
|
||||
if (selected(j) == false && edges(i)(j) != 0) {
|
||||
if (min > edges(i)(j)) {
|
||||
min = edges(i)(j)
|
||||
if (num.gt(num.fromInt(min), edges(i)(j))) {
|
||||
min = num.toInt(edges(i)(j))
|
||||
x = i
|
||||
y = j
|
||||
}
|
||||
@ -122,19 +125,21 @@ object Util {
|
||||
mst
|
||||
}
|
||||
|
||||
def findClusters(
|
||||
mst: Array[Array[Int]],
|
||||
centroids: IndexedSeq[Int]
|
||||
): Map[Int, ArrayBuffer[Int]] = {
|
||||
val n = mst.length
|
||||
val x: Map[Int, ArrayBuffer[Int]] = centroids
|
||||
.map(d => {
|
||||
val y = DFS(d, mst)
|
||||
y(0) -> y
|
||||
})
|
||||
.toMap
|
||||
x
|
||||
}
|
||||
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]],
|
||||
@ -160,7 +165,9 @@ object Util {
|
||||
|
||||
def findCentroids[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 centroids: mutable.Set[Int] = mutable.Set.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 = {
|
||||
// // 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(
|
||||
def DFS[T](
|
||||
start: Int,
|
||||
graph: Array[Array[Int]]
|
||||
): ArrayBuffer[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[Int]], visited: Array[Boolean]) {
|
||||
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 (graph(start)(i) > 0 && (!visited(i))) {
|
||||
if (num.gt(graph(start)(i), num.fromInt(0)) && (!visited(i))) {
|
||||
loop(i, graph, visited);
|
||||
}
|
||||
}
|
||||
@ -224,7 +220,11 @@ object Util {
|
||||
): ArrayBuffer[Int] = {
|
||||
val visited = Array.fill(graph.size)(false)
|
||||
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
|
||||
buf += start
|
||||
// print(s"$start ")
|
||||
@ -241,12 +241,12 @@ object Util {
|
||||
buf
|
||||
}
|
||||
|
||||
def groupClusters(
|
||||
def groupClusters[T](
|
||||
centroids: IndexedSeq[Int],
|
||||
clusters: Map[Int, ArrayBuffer[Int]],
|
||||
removed: IndexedSeq[(Int, Int, Int)]
|
||||
) = {
|
||||
val groups = centroids
|
||||
removed: IndexedSeq[(Int, Int, T)]
|
||||
)(implicit num: Numeric[T]) =
|
||||
centroids
|
||||
.map(c => {
|
||||
val cluster = clusters(c)
|
||||
val lst = removed
|
||||
@ -254,15 +254,70 @@ object Util {
|
||||
c == r._1
|
||||
})
|
||||
.sortWith((x, y) => {
|
||||
x._3 < y._3
|
||||
num.lt(x._3, y._3)
|
||||
})
|
||||
.map(l => {
|
||||
(l._2,l._3)
|
||||
(l._2, l._3)
|
||||
})
|
||||
c -> lst
|
||||
})
|
||||
.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