Browse Source

Command lines args and railway pattern

development
Rohan Sircar 4 years ago
parent
commit
69a0c3ce63
  1. 20
      Input.txt
  2. 10
      build.sbt
  3. 31
      src/main/scala/HHCSim.scala
  4. 71
      src/main/scala/Main.scala
  5. 11
      src/main/scala/config/Config.scala
  6. 155
      src/main/scala/util/Util.scala

20
Input.txt

@ -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

@ -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

@ -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)
}
)
}

71
src/main/scala/Main.scala

@ -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:")
@ -156,28 +185,28 @@ object Main {
// Output
//
// Initial graph:
// 0, 9, 75, 0, 0,
// 9, 0, 95, 19, 42,
// 75, 95, 0, 51, 66,
// 0, 19, 51, 0, 31,
// 0, 42, 66, 31, 0,
// MST:
// 0, 9, 0, 0, 0,
// 9, 0, 0, 19, 0,
// 0, 0, 0, 51, 0,
// 0, 19, 51, 0, 31,
// 0, 0, 0, 31, 0,
// Centroids:
// 0, 9, 75, 0, 0,
// 9, 0, 95, 19, 42,
// 75, 95, 0, 51, 66,
// 0, 19, 51, 0, 31,
// 0, 42, 66, 31, 0,
// MST:
// 0, 9, 0, 0, 0,
// 9, 0, 0, 19, 0,
// 0, 0, 0, 51, 0,
// 0, 19, 51, 0, 31,
// 0, 0, 0, 31, 0,
// Centroids:
// Vector(2, 3, 4)
// Removed:
// Removed:
// Vector((2,3,51), (3,2,51), (3,4,31), (4,3,31))
// Clusters:
// 2: -> 2
// 3: -> 3 -> 1 -> 0
// 4: -> 4
// 2: -> 2
// 3: -> 3 -> 1 -> 0
// 4: -> 4
// Final cluster groups:
// Final cluster groups:
// Map(2 -> Vector((3,51)), 3 -> Vector((4,31), (2,51)), 4 -> Vector((3,31)))
}
}

11
src/main/scala/config/Config.scala

@ -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()
}

155
src/main/scala/util/Util.scala

@ -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…
Cancel
Save