...
 
Commits (71)
import language.postfixOps
import com.github.retronym.SbtOneJar._
mainClass in(oneJar) := Some("countvotes.Main")
name := "countvotes"
organization := "AOSSIE"
version := "1.1"
version := "1.2"
scalaVersion := "2.11.7"
scalaVersion := "2.12.3"
resolvers += Resolver.sonatypeRepo("public")
resolvers += "Sonatype OSS Snapshots" at
......@@ -17,14 +15,15 @@ resolvers += "Sonatype OSS Snapshots" at
libraryDependencies ++= Seq(
"org.scala-lang.modules" %% "scala-parser-combinators" % "1.0.4",
"com.github.scopt" %% "scopt" % "3.3.0",
"org.specs2" %% "specs2-core" % "3.8.6" % "test,verification-test,bench",
"com.lihaoyi" %% "ammonite-ops" % "0.8.1",
"ch.qos.logback" % "logback-classic" % "1.1.7",
"com.typesafe.scala-logging" %% "scala-logging" % "3.5.0",
"com.github.scopt" %% "scopt" % "3.7.0",
"org.specs2" %% "specs2-core" % "3.9.5" % "test,verification-test,bench",
"com.lihaoyi" %% "ammonite-ops" % "1.0.2",
"ch.qos.logback" % "logback-classic" % "1.2.3",
"com.typesafe.scala-logging" %% "scala-logging" % "3.7.2",
"com.storm-enroute" %% "scalameter" % "0.8.2",
"com.storm-enroute" %% "scalameter-core" % "0.8.2",
"com.typesafe.play" %% "play-json" % "2.6.0"
"com.typesafe.play" %% "play-json" % "2.6.3",
"org.typelevel" %% "spire" % "0.14.1"
)
testFrameworks += new TestFramework("org.scalameter.ScalaMeterFramework")
......@@ -33,7 +32,7 @@ logBuffered := false
parallelExecution in Test := false
scalacOptions ++= Seq("-unchecked", "-deprecation", "-feature", "-optimize", "-Yinline-warnings")
scalacOptions ++= Seq("-unchecked", "-deprecation", "-feature")
scalacOptions in (Compile, doc) ++= Seq("-diagrams","-implicits")
......@@ -46,6 +45,7 @@ lazy val project = Project("agora", file("."), settings = allSettings)
.configs(Testing.configs: _*)
.settings(Testing.settings: _*)
mainClass in(oneJar) := Some("agora.Main")
licenses := Seq("CC BY-NC-SA" -> url("http://creativecommons.org/licenses/by-nc-sa/4.0/"))
......
......@@ -13,7 +13,7 @@ object Testing {
Seq(
fork in VerificationTest := false,
parallelExecution in VerificationTest := false,
scalaSource in VerificationTest := baseDirectory.value / "src/test/scala/countvotes")
scalaSource in VerificationTest := baseDirectory.value / "src/test/scala/agora")
private lazy val performanceTestSettings =
inConfig(PerformanceTest)(Defaults.testSettings) ++
......
scalacOptions ++= Seq("-unchecked", "-deprecation", "-feature", "-optimize")
scalacOptions ++= Seq("-unchecked", "-deprecation", "-feature")
package analyse
package agora
import analyse.methods.{SinglePeakAnalyser, ValueRestrictedAnalyser}
import countvotes.parsers.{CandidatesParser, PreferencesParser}
import countvotes.structures.{Candidate, WeightedBallot}
import countvotes.{Concise, ScrutinyTableFormats}
import agora.analyzer.{SinglePeakAnalyser, ValueRestrictedAnalyser}
import agora.parser.{CandidatesParser, PreferencesParser}
import agora.model.{Candidate, PreferenceBallot => Ballot, Election}
object PreferenceAnalyser {
......@@ -12,7 +11,7 @@ object PreferenceAnalyser {
ballotsfile: Option[String] = None,
method: String = "",
candidatesfile: String = "",
table: ScrutinyTableFormats = Concise)
table: VoteCounterTableFormats = Concise)
val parser = new scopt.OptionParser[PreferenceConfig]("compress") {
head("\nCommand Line Interface for Electronic Votes preference analysis\n\n ")
......@@ -49,7 +48,7 @@ object PreferenceAnalyser {
def main(args: Array[String]): Unit = {
def callMethod(c: PreferenceConfig, election: List[WeightedBallot], candidates_in_order: List[Candidate]) = {
def callMethod(c: PreferenceConfig, election: Election[Ballot], candidates_in_order: List[Candidate]) = {
c.method match {
case "single-peak" => {
......
package compare
package agora
import compare.extensions.{FishburnsExtension, KellyExtension}
import analyse.methods.{SinglePeakAnalyser, ValueRestrictedAnalyser}
import countvotes.parsers.{CandidatesParser, ParameterParser, PreferencesParser}
import countvotes.structures.{Candidate, WeightedBallot}
import countvotes.{Concise, ScrutinyTableFormats}
import agora.comparator.{FishburnsExtension, KellyExtension}
import agora.parser.{CandidatesParser, ParameterParser, PreferencesParser}
import agora.model.{Candidate, PreferenceBallot => Ballot, Election}
object SetComparator {
......@@ -13,7 +11,7 @@ object SetComparator {
method: String = "",
parameterFile: String = "",
candidatesfile: String = "",
table: ScrutinyTableFormats = Concise)
table: VoteCounterTableFormats = Concise)
val parser = new scopt.OptionParser[CompareConfig]("compress") {
head("\nCommand Line Interface for candidates set comparisons\n\n ")
......@@ -54,7 +52,7 @@ object SetComparator {
def main(args: Array[String]): Unit = {
def callMethod(c: CompareConfig, election: List[WeightedBallot], candidates_in_order: List[Candidate]) = {
def callMethod(c: CompareConfig, election: Election[Ballot], candidates_in_order: List[Candidate]) = {
c.method match {
case "Kelly" => {
......
package analyse
package agora
import countvotes.methods._
import countvotes.structures._
import scala.collection.mutable.{ArrayBuffer, ListBuffer}
import agora.votecounter._
import agora.model.{PreferenceBallot => Ballot, _ }
import scala.collection.mutable.ArrayBuffer
import scala.language.postfixOps
import scala.util.Random
import spire.math.Rational
import spire.math.Rational.apply
object StabilityAnalyser {
......@@ -13,7 +14,7 @@ object StabilityAnalyser {
def main(args: Array[String]): Unit = {
val report: Report[WeightedBallot] = new Report[WeightedBallot]
val report: Report[Ballot] = new Report[Ballot]
val (candidates, elections) = generateElections(20, 100, 5)
......@@ -21,20 +22,20 @@ object StabilityAnalyser {
val analysisArray = new ArrayBuffer[(String, Double, Double)]
analysisArray.append(analyseStability(BordaRuleMethod, electionsPairs, candidates))
analysisArray.append(analyseStability(Borda, electionsPairs, candidates))
//analyseStability(MajorityRuleMethod, electionsPairs, candidates) /*some cases there might be no majority winner*/
analysisArray.append(analyseStability(ApprovalRule, electionsPairs, candidates))
analysisArray.append(analyseStability(KemenyYoungMethod, electionsPairs, candidates))
analysisArray.append(analyseStability(KemenyYoung, electionsPairs, candidates))
analysisArray.append(analyseStability(BaldwinMethod, electionsPairs, candidates))
analysisArray.append(analyseStability(NansonMethod, electionsPairs, candidates))
analysisArray.append(analyseStability(Nanson, electionsPairs, candidates))
analysisArray.append(analyseStability(InstantRunoff2Round, electionsPairs, candidates))
analysisArray.append(analyseStability(CoombRuleMethod, electionsPairs, candidates))
analysisArray.append(analyseStability(Coomb, electionsPairs, candidates))
analysisArray.append(analyseStability(InstantExhaustiveBallot, electionsPairs, candidates))
analysisArray.append(analyseStability(ContingentMethod, electionsPairs, candidates))
analysisArray.append(analyseStability(MinimaxCondorcetMethod, electionsPairs, candidates))
analysisArray.append(analyseStability(CopelandMethod, electionsPairs, candidates))
analysisArray.append(analyseStability(Contingent, electionsPairs, candidates))
analysisArray.append(analyseStability(MinimaxCondorcet, electionsPairs, candidates))
analysisArray.append(analyseStability(Copeland, electionsPairs, candidates))
//analyseStability(UncoveredSetMethod, electionsPairs, candidates) /* in some cases the uncovered set could be empty*/
analysisArray.append(analyseStability(SmithSetMethod, electionsPairs, candidates))
analysisArray.append(analyseStability(SmithSet, electionsPairs, candidates))
analysisArray.append(analyseStability(InstantExhaustiveDropOffRule, electionsPairs, candidates))
analysisArray.append(analyseStability(PreferentialBlockVoting, electionsPairs, candidates))
analysisArray.append(analyseStability(HybridPluralityPreferentialBlockVoting, electionsPairs, candidates))
......@@ -50,7 +51,7 @@ object StabilityAnalyser {
}
def analyseStability(vcm: VoteCountingMethod[WeightedBallot], electionsPair: List[List[Election[WeightedBallot]]],
def analyseStability(vcm: VoteCounter[Ballot], electionsPair: List[List[Election[Ballot]]],
candidates: List[Candidate]): (String, Double, Double) = {
......@@ -64,7 +65,7 @@ object StabilityAnalyser {
}
def stability(vcm: VoteCountingMethod[WeightedBallot], elections: List[Election[WeightedBallot]], candidates: List[Candidate]): Double = {
def stability(vcm: VoteCounter[Ballot], elections: List[Election[Ballot]], candidates: List[Candidate]): Double = {
val winnerEA = vcm.winners(elections(0), candidates, 1)
val winnerEB = vcm.winners(elections(1), candidates, 1)
......@@ -75,25 +76,25 @@ object StabilityAnalyser {
}
// generate n random election of m voters and c candidates
def generateElections(n: Int, m: Int, c: Int): (List[Candidate], List[Election[WeightedBallot]]) = {
def generateElections(n: Int, m: Int, c: Int): (List[Candidate], List[Election[Ballot]]) = {
require(c < 26)
val candidates = ('A' to 'Z') take c map(name => new Candidate(name.toString)) toList
val election = for {
val elections = for {
i <- List.range(1, n)
} yield {
for {
Election(for {
j <- List.range(1, m)
} yield WeightedBallot(Random.shuffle(candidates), i, 1)
} yield Ballot(Random.shuffle(candidates), i, 1) )
}
(candidates,election)
(candidates,elections)
}
// calculate the kendall tau distance between two profiles
def kendallTauDistance(profile: List[Election[WeightedBallot]]): Int = {
def kendallTauDistance(profile: List[Election[Ballot]]): Int = {
var kTDistance = 0
......
package agora.analyzer
import agora.model.{PreferenceBallot => Ballot, Candidate, Election}
/**
* Created by deepeshpandey on 18/06/17.
*/
abstract class PreferenceAnalysisMethod[B <: Ballot] {
def analyse(e: agora.model.Election[B], ccandidates: List[Candidate]): Boolean
}
package analyse.methods
package agora.analyzer
import countvotes.structures.{Candidate, Election, WeightedBallot}
import agora.model.{Candidate, Election, PreferenceBallot => Ballot}
import scala.collection.mutable.ListBuffer
......@@ -8,9 +8,9 @@ import scala.collection.mutable.ListBuffer
* Please check the last page of the pdf https://drive.google.com/file/d/0B4uPp6wWiMpSZ2FaTFFneGtJSDg/view
* when preferences are single peaked there is always a unique condorcet winner
*/
object SinglePeakAnalyser extends PreferenceAnalysisMethod[WeightedBallot] {
object SinglePeakAnalyser extends PreferenceAnalysisMethod[Ballot] {
def analyse(election: Election[WeightedBallot], candidates: List[Candidate]): Boolean = {
def analyse(election: agora.model.Election[Ballot], candidates: List[Candidate]): Boolean = {
require(election.forall(b => b.preferences.size == candidates.size))
......@@ -37,7 +37,7 @@ object SinglePeakAnalyser extends PreferenceAnalysisMethod[WeightedBallot] {
* @param candidates
* @return
*/
def getSinglePeakAxis(election: Election[WeightedBallot], candidates: List[Candidate]): Option[List[Candidate]] = {
def getSinglePeakAxis(election: Election[Ballot], candidates: List[Candidate]): Option[List[Candidate]] = {
val B = election.map(_.preferences.last).distinct
......@@ -68,7 +68,7 @@ object SinglePeakAnalyser extends PreferenceAnalysisMethod[WeightedBallot] {
* @param candidates
* @return
*/
def singlePeakAxisAux(left: ListBuffer[Candidate], right: ListBuffer[Candidate], election: Election[WeightedBallot],
def singlePeakAxisAux(left: ListBuffer[Candidate], right: ListBuffer[Candidate], election: Election[Ballot],
candidates: List[Candidate]): Option[List[Candidate]] = {
if (candidates.isEmpty) {
......@@ -118,7 +118,7 @@ object SinglePeakAnalyser extends PreferenceAnalysisMethod[WeightedBallot] {
* @param candidates
* @return
*/
def existNrxl(election: Election[WeightedBallot], x: Candidate, l: Option[Candidate], r: Option[Candidate],
def existNrxl(election: Election[Ballot], x: Candidate, l: Option[Candidate], r: Option[Candidate],
candidates: List[Candidate]): Boolean = {
// get all the preferences where candidate x is last ranked
......@@ -143,7 +143,7 @@ object SinglePeakAnalyser extends PreferenceAnalysisMethod[WeightedBallot] {
* @param election - election
* @return
*/
def isCompatibleAxis(axis: List[Candidate], election : Election[WeightedBallot]): Boolean = {
def isCompatibleAxis(axis: List[Candidate], election : Election[Ballot]): Boolean = {
election.forall(b => {
......
package analyse.methods
package agora.analyzer
import countvotes.structures.{Candidate, Election, WeightedBallot}
import agora.model.{Candidate, Election, PreferenceBallot => Ballot}
/**
* This analyser analyses for Sen's Value restricted preferences
* source link : https://www.youtube.com/watch?v=F51U9Sv9QNo&t=26s
*/
object ValueRestrictedAnalyser extends PreferenceAnalysisMethod[WeightedBallot] {
object ValueRestrictedAnalyser extends PreferenceAnalysisMethod[Ballot] {
/**
* assumption : voters preference relations are complete over set of candidates.
......@@ -18,7 +18,7 @@ object ValueRestrictedAnalyser extends PreferenceAnalysisMethod[WeightedBallot]
* @param ccandidates => candidates list
* @return
*/
override def analyse(election: Election[WeightedBallot], ccandidates: List[Candidate]): Boolean = {
override def analyse(election: agora.model.Election[Ballot], ccandidates: List[Candidate]): Boolean = {
require(election forall (b => b.preferences.length == ccandidates.length))
......@@ -66,7 +66,7 @@ object ValueRestrictedAnalyser extends PreferenceAnalysisMethod[WeightedBallot]
* @param triplet a triplet of candidate against which we want to check value restructed preferences
* @param election election file
*/
def valueRestrictedTriplet(triplet: List[Candidate], election: Election[WeightedBallot]): Boolean = {
def valueRestrictedTriplet(triplet: List[Candidate], election: Election[Ballot]): Boolean = {
val tripletRankings = Array.ofDim[Int](3, 3)
......
package compare.extensions
package agora.comparator
import countvotes.structures._
import agora.model.{PreferenceBallot => Ballot, _}
import spire.math.Rational
/*
Link : https://drive.google.com/file/d/0B4uPp6wWiMpSbWh2NGNfLXdiTTA/view?usp=sharing
*/
object FishburnsExtension extends SetExtensionMethods[WeightedBallot] {
object FishburnsExtension extends SetExtensionMethods[Ballot] {
override def compare(election: Election[WeightedBallot], candidates: List[Candidate], parameters: Parameters): Set[Candidate] = {
override def compare(election: agora.model.Election[Ballot], candidates: List[Candidate], parameters: Parameters): Set[Candidate] = {
// candidates in comparison sets should be consistent with the actual candidates
require(parameters.comparisonSets.isDefined && parameters.comparisonSets.get.set1.forall(c => candidates.exists(cand => cand.name == c)) &&
......
package compare.extensions
package agora.comparator
import com.typesafe.scalalogging.LazyLogging
import countvotes.structures._
import agora.model.{PreferenceBallot => Ballot, _}
import spire.math.Rational
/*
Link : https://drive.google.com/file/d/0B4uPp6wWiMpScEM2Q21kT2x1N3M/view?usp=sharing
*/
object KellyExtension extends SetExtensionMethods[WeightedBallot] with LazyLogging {
object KellyExtension extends SetExtensionMethods[Ballot] with LazyLogging {
override def compare(election: Election[WeightedBallot], candidates: List[Candidate], parameters: Parameters): Set[Candidate] = {
override def compare(election: agora.model.Election[Ballot], candidates: List[Candidate], parameters: Parameters): Set[Candidate] = {
// require that the sets are consistent with the candidates list
require(parameters.comparisonSets.isDefined && parameters.comparisonSets.get.set1.forall(c => candidates.exists(cand => cand.name == c)) &&
parameters.comparisonSets.get.set2.forall(c => candidates.exists(cand => cand.name == c)))
......
package compare.extensions
package agora.comparator
import countvotes.structures._
import agora.model.{PreferenceBallot => Ballot, _}
import spire.math.Rational
/**
* A proper definition of strategyproofness for irresolute social choice functions requires the
......@@ -11,13 +13,13 @@ import countvotes.structures._
* called a set extension. This implementation includes two of the natural and well studied
* set extension methods - Kellys and Fishburn's extension methods.
*/
abstract class SetExtensionMethods[B <: Ballot with Weight] {
abstract class SetExtensionMethods[B <: Ballot] {
// will return the set that is preferred over another as given in the json parameters file
def compare(election: Election[WeightedBallot], candidates: List[Candidate], parameters: Parameters): Set[Candidate]
def compare(election: agora.model.Election[Ballot], candidates: List[Candidate], parameters: Parameters): Set[Candidate]
// utility method for matrix where a[i][j] = x means candidate i has got #x votes against candidate j
def getPairwiseComparisons(election: Election[WeightedBallot], candidates: List[Candidate]): Array[Array[Rational]] = {
def getPairwiseComparisons(election: Election[Ballot], candidates: List[Candidate]): Array[Array[Rational]] = {
val zeroRational = Rational(0, 1)
val responseMatrix = Array.fill(candidates.size, candidates.size)(Rational(0, 1))
......
package agora.model
import scala.language.implicitConversions
import spire.math.Rational
abstract class Ballot(val id: Int, val weight: Rational) {
def firstVotes: Map[Candidate, Rational]
}
case class PreferenceBallot(val preferences: List[Candidate], override val id: Int, override val weight: Rational)
extends Ballot(id, weight) {
lazy val firstVotes = preferences.headOption match {
case Some(c) => Map(c -> Rational(1,1))
case None => Map()
}
}
case class ScoreBallot(scores: List[(Candidate, Rational)], override val id: Int, w: Rational)
extends Ballot(id, w) {
lazy val sortedScores = scores sortWith { (cs1, cs2) => cs1._2 > cs2._2 }
lazy val firstVotes = sortedScores.headOption match {
case Some((c,s)) => Map(c -> Rational(1,1))
case None => Map()
}
}
case class RankBallot(val ranks: List[(Candidate, Int)], override val id: Int, w: Rational)
extends Ballot(id, w) {
lazy val sortedRanks = ranks sortWith { (cs1, cs2) => cs1._2 < cs2._2 }
lazy val firstVotes = sortedRanks.headOption match {
case Some((c,s)) => Map(c -> Rational(1,1))
case None => Map()
}
}
case class ApprovalBallot(val approvals: Set[Candidate], override val id: Int, w: Rational)
extends Ballot(id, w) {
lazy val firstVotes = ???
}
// TODO: use ApprovalBallot in Approval voting
\ No newline at end of file
package agora.model
case class Candidate(val name: String, val id: Option[Int] = None, val party: Option[String] = None) {
override def toString: String = Seq(id, Some(name), party) filter{_.isDefined} map{_.get} mkString("[",",","]")
}
package countvotes.structures
package agora.model
import collection.mutable.{HashMap => Map}
import collection.mutable.{HashMap => MMap}
import spire.math.Rational
import agora.votecounter.stv.Action
class Count[B <: Ballot with Weight] {
import scala.collection.Map
private var action: Option[Actions] = None
class Count[B <: Ballot] {
private var action: Option[Action] = None
private var initiator: Option[Candidate] = None // initiator of the action
......@@ -66,11 +70,11 @@ class Count[B <: Ballot with Weight] {
}
def setAction(a: Actions): Unit = {
def setAction(a: Action): Unit = {
action = Some(a)
}
def getAction: Actions = {
def getAction: Action = {
action match {
case Some(a) => a
case None => throw new Exception("Action is not set.")
......
package agora.model
import scala.collection._
import scala.collection.generic._
import scala.collection.mutable.{Builder, ListBuffer}
import scala.collection.mutable.{HashMap => MMap, HashSet => MSet}
import scala.language.implicitConversions
import spire.math.Rational
import agora.votecounter.stv.ACTBallot
class Election[+B <: Ballot](val ballots: Seq[B])
extends Seq[B]
with SeqLike[B, Election[B]] {
override def companion = ballots.companion
def iterator = ballots.iterator
def apply(i: Int) = ballots(i)
def length = ballots.length
protected[this] override def newBuilder = Election.newBuilder
override def toString = ballots map { _.toString } mkString("\n")
def firstVotes(candidates: List[Candidate]): Map[Candidate, Rational] = {
val m = new MMap[Candidate, Rational]
for (b <- ballots; (c, t) <- b.firstVotes) m(c) = t * b.weight + m.getOrElse(c, 0)
m
}
lazy val weight = ((ballots map {_.weight}) :\ Rational(0,1)) { _ + _ }
}
object Election {
def newBuilder[B <: Ballot] = new mutable.Builder[B, Election[B]] {
private[this] val base = Seq().genericBuilder[B]
override def +=(e: B) = { base += e; this }
override def clear() = base.clear()
override def result() = new Election[B](base.result())
}
implicit def canBuildFrom[B <: Ballot] = new CanBuildFrom[Election[_], B, Election[B]] {
def apply(from: Election[_]): Builder[B, Election[B]] = newBuilder
def apply(): Builder[B, Election[B]] = newBuilder
}
//def apply[B <: Ballot](ballots: B*) = new Election(ballots)
def apply[B <: Ballot](ballots: Seq[B]) = new Election(ballots)
}
package countvotes.structures
package agora.model
import play.api.libs.functional.syntax._
import play.api.libs.json._
......
package agora.model
import java.io._
import scala.collection.mutable.{HashMap => MMap}
import spire.math.Rational
import agora.votecounter.stv.Action
import scala.collection.Map
class Report[B <: Ballot] {
private var countHistory : List[Count[B]] = Nil
//private var totals: Map[Candidate, Rational] = Map()
private var candidates : List[Candidate] = Nil
private var quota: Option[Rational] = None
private var numVacancies: Option[Int] = None
private var winners: List[(Candidate,Rational)] = Nil
private var stabilityAnalysis: List[(String, Double, Double)] = Nil
def clear: Unit = {
countHistory = Nil
candidates = Nil
quota = None
numVacancies = None
winners = Nil
}
def setLossByFractionToZero: Unit = {
countHistory.head.setLossByFraction(Rational(0,1))
}
def setLossByFraction(oldtotals: Map[Candidate, Rational], newtotals: Map[Candidate, Rational]): Unit = {
def sumTotals(totals: Map[Candidate, Rational]): Rational = {
var sum: Rational = 0
for (t <- totals) sum += t._2
sum
}
var sumoldtotals = sumTotals(oldtotals)
var sumnewtotals = sumTotals(newtotals)
//println("sumoldtotals " + sumoldtotals)
//println("sumnewtotals " + sumnewtotals)
countHistory.head.setLossByFraction(sumoldtotals-sumnewtotals)
}
def setIgnoredBallots(ignoredBallots: Election[B]): Unit = {
countHistory.head.setIgnoredBallots(ignoredBallots)
}
def setNumVacancies(n: Int): Unit = {
numVacancies = Some(n)
}
def getNumVacancies: Option[Int] = {
numVacancies
}
def setCandidates(cands: List[Candidate]): Unit = {
candidates = cands
}
def getCandidates: List[Candidate] = {
candidates
}
def setQuota(q: Rational): Unit = {
quota = Some(q)
}
def getQuota: Rational = {
quota match {
case Some(q) => q
case None => throw new Exception("quota is not set yet.")
}
}
def newCount(action: Action, initiator: Option[Candidate], relection: Option[Election[B]],
totals: Option[Map[Candidate, Rational]], winners: Option[List[(Candidate, Rational)]],
exhaustedBallots: Option[Set[B]]): Unit = {
val count = new Count[B]
count.setAction(action)
initiator match {
case Some(i) => count.setInitiator(i)
case None =>
}
relection match { // election resulting from the action
case Some(e) => // count.setElection(e)
// TODO: commented because was taking much memory. Find a better solution (make a hash table for marked ballots).
case None =>
}
totals match {
case Some(pt) => count.setTotals(pt)
case None =>
}
winners match {
case Some(w) => count.addWinners(w)
case None =>
}
exhaustedBallots match {
case Some(eb) => count.setExhaustedBallots(eb)
case None =>
}
countHistory = count :: countHistory
}
def getCountHistory: List[Count[B]] = {
countHistory
}
def setWinners(ws: List[(Candidate,Rational)] ): Unit = {
winners = ws
}
def getWinners: List[(Candidate, Rational)] = {
winners
}
def writeWinners(file: String): Unit = {
val writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file)))
//writer.write(result.getWinners.toString())
var sw = ""
println("\n WINNERS \n")
for ( w <- winners){
println(w._1 + ": " + w._2.numerator.toFloat / w._2.denominator.toFloat + "\n")
sw = sw + w._1 + ": " + w._2.numerator.toFloat / w._2.denominator.toFloat + "\n"
}
writer.write(sw)
writer.close()
}
def setStabilityAnalysis(sa: List[(String, Double, Double)]): Unit = {
stabilityAnalysis = sa
}
def writeStabilityAnalysis(file: String): Unit = {
val writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file)))
//writer.write(result.getWinners.toString())
var sw = ""
for ( analysis <- stabilityAnalysis){
sw = sw + analysis._1 + "\n" + "Average Ratio: " + analysis._2 + "\n" + "Variance Ratio: " + analysis._3 + "\n\n\n";
}
writer.write(sw)
writer.close()
}
def writeDistributionOfPreferencesACT(file: String, order: Option[List[Candidate]]): Unit = {
val writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file)))
val separator = ","
var tableorder: List[Candidate] = Nil
order match {
case Some(o) => tableorder = o
case None => tableorder = candidates
}
var countnum = 0
for (count <- countHistory.reverse ){
// println(countr.getNumVotesReceived)
countnum += 1
var line: String = countnum + separator
if (countnum == 1) {
for (c<-tableorder){
if (count.getTotals.exists(_._1 == c)) {
line += count.getTotals(c).numerator/count.getTotals(c).denominator + separator
}
else {
line += separator
}
}
writer.write(line + "\n")
countnum += 1
line = countnum + separator
}
for (c<-tableorder){
if ( count.getTotals.exists(_._1 == c)) {
line += count.getTotals(c).numerator/count.getTotals(c).denominator + separator
}
else {
line += separator
}
}
// val exhaustedBallots = count.getExhaustedBallots
// val ignoredBallots = count.getIgnoredBallots
writer.write(line + "\n")
}
//rwriter.write("Candidates: " + report.getCandidates.toString()+"\n")
//rwriter.write("Number of seats: " + report.getNumVacancies.toString()+"\n")
//rwriter.write("Quota: " + report.getQuota.toString())
writer.close
}
// scalastyle:off cyclomatic.complexity
// scalastyle:off method.length
def writeDistributionOfPreferences(file: String, order: Option[List[Candidate]]): Unit = {
val writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file)))
val separator = ","
var tableorder: List[Candidate] = Nil
order match {
case Some(o) => tableorder = o
case None => tableorder = candidates
}
writer.write( "Count" + separator)
var countnum = -1
tableorder.foreach { c => writer.write( c + separator) }
writer.write("Initiator" + separator +
"Action" + separator +
"Winners" + separator +
"~ Loss by Fraction" + separator +
"N Exhausted Ballots" + separator +
"~ Exhausted Votes" + separator +
"N Ignored Ballots" + separator +
"~ Ignored Votes"
+ "\n")
for (count <- countHistory.reverse ){
countnum += 1
var line: String = countnum + separator
for (c <-tableorder){
if (count.getTotals.exists(_._1 == c)) {
line += count.getTotals(c).numerator/count.getTotals(c).denominator + separator
}
else {
line += separator
}
}
var winners = ""
for (w <- count.getWinners if count.getWinners.nonEmpty){
winners += w._1 + " (" + w._2 + "); "
}
line += count.getInitiator + separator + count.getAction + separator + winners + separator + count.getLossByFraction.toInt + separator
val exhaustedBallots = count.getExhaustedBallots
val ignoredBallots = count.getIgnoredBallots
var exhhaustedandignored: String = ""
exhaustedBallots match {
case Some (eB) =>
var totalweighteB: Rational = 0
for (b <- eB) {
totalweighteB += b.weight
}
exhhaustedandignored += eB.size + separator + totalweighteB.toInt + separator
case None =>
exhhaustedandignored += " " + separator
}
ignoredBallots match {
case Some (iB) =>
val writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file + "IgnoredBallots_Count" + countnum + ".txt")))
var s = ""
for (b <- iB) {
s += b.toString + "\n"
}
writer.write(s)
writer.close()
var totalweightiB: Rational = 0
for (b <- iB) {
totalweightiB += b.weight
}
exhhaustedandignored += iB.size + separator + totalweightiB.toInt
case None =>
}
line += exhhaustedandignored
writer.write(line + "\n")
}
writer.close
}
}
package countvotes.structures
package agora.model
import collection.mutable.{HashMap => Map}
import collection.mutable.{HashMap => MMap}
import spire.math.Rational
import scala.collection.Map
class Result{
......@@ -82,7 +84,7 @@ import collection.mutable.{HashMap => Map}
}
def getTotalsHistoryClone: List[Map[Candidate, Rational]] = {
totalsHistory map { m => m.clone() }
totalsHistory
}
def setWinners(ws: List[(Candidate, Rational)]): Unit = {
......
package countvotes.parsers
package agora.parser
import countvotes._
import countvotes.structures._
import agora._
import agora.model._
import scala.util.parsing.combinator._
object CandidatesParser extends ElectionParser[Candidate] with RegexParsers {
object CandidatesParser extends LineParser[Candidate] {
def read(filename: String) = readLines(filename)
// the method line returns a Parser of type ACTBallotPapersDataStructure
def line : Parser[Candidate] = name ~ opt(id) ~ opt(party) ^^ {
case ~(~(name, id), party) =>
{ Candidate(name, id, party)
}
case ~(~(name, id), party) => Candidate(name, id, party)
case _ => throw new Exception
}
def string: Parser[String] = """[0-9A-Za-z\-\,\.\ \']+""".r
......@@ -19,16 +20,14 @@ object CandidatesParser extends ElectionParser[Candidate] with RegexParsers {
//obligatory semi-colon only if party present
def party = ";" ~ string ^^ {
case ~(";", string) =>
{ string.toString
}
case ~(";", string) => string
case _ => throw new Exception
}
//obligatory semi-colon only if id exists
def id : Parser[Int] = ";" ~ """[0-9]+""".r ^^ {
case ~(";", number) =>
{ number.toInt
}
case ~(";", number) => number.toInt
case _ => throw new Exception
}
}
package countvotes.parsers
package agora.parser
import countvotes.structures._
import agora.model._
import scala.io.Source
import java.io.{FileReader, FileNotFoundException, IOException}
import scala.util.parsing.combinator._
abstract class ElectionParser[T] extends RegexParsers {
abstract class ElectionParser[T <: Ballot] extends LineParser[T] {
def line: Parser[T]
def read(filename: String): List[T] = {
def read(filename: String): Election[T] = Election(readLines(filename))
}
abstract class LineParser[T] extends RegexParsers {
def line: Parser[T]
def readLines(filename: String): List[T] = {
val bufferedSource = io.Source.fromFile(filename)
val lines = bufferedSource.getLines.toList
var output = for (l <- lines) yield {
val output = for (l <- lines) yield {
parse(line, l) match {
case Success(sucLine,_) => sucLine
case _ => throw new Exception("Parsing Error")
......@@ -24,4 +30,4 @@ abstract class ElectionParser[T] extends RegexParsers {
bufferedSource.close()
output
}
}
}
\ No newline at end of file
package countvotes.parsers
package agora.parser
import countvotes.structures.Parameters
import agora.model.Parameters
import play.api.libs.json.Json
import scala.io.Source
......@@ -12,8 +12,10 @@ object ParameterParser {
def parse(fileName: String): Parameters = {
val src = Source.fromFile(fileName).getLines.mkString
Json.parse(src).as[Parameters](Parameters.methodParameterReader)
val src = Source.fromFile(fileName)
val parameters = Json.parse(src.getLines.mkString).as[Parameters](Parameters.methodParameterReader)
src.close()
parameters
}
}
package countvotes.parsers
package agora.parser
import agora.model._
import agora.model.{PreferenceBallot => Ballot}
import countvotes.structures.Rational.realToRational
import countvotes.structures._
import spire.math.Rational
import scala.util.parsing.combinator._
......@@ -23,44 +24,39 @@ trait ElectionParsers extends RegexParsers {
_.toInt
}
def score: Parser[Rational] =
"""[0-9\.]+""".r ^^ { case (value) => {
val (n, d) = realToRational(value)
Rational(n.toInt, d.toInt)
}
}
def score: Parser[Rational] = """[0-9\.]+""".r ^^ { case (value) => Rational(value) }
}
object PreferencesParser extends ElectionParser[WeightedBallot] with RegexParsers with ElectionParsers {
object PreferencesParser extends ElectionParser[Ballot] with RegexParsers with ElectionParsers {
def preferences: Parser[List[Candidate]] = repsep(candidate, ">")
def line: Parser[WeightedBallot] = id ~ weight ~ preferences ^^ {
case ~(~(i, w), prefs) => { WeightedBallot(prefs, i, w) }
def line: Parser[Ballot] = id ~ weight ~ preferences ^^ {
case ~(~(i, w), prefs) => { new Ballot(prefs, i, w) }
}
}
object PreferencesParserWithIndifference extends ElectionParser[RankedWeightedBallot] with RegexParsers with ElectionParsers {
object PreferencesParserWithIndifference extends ElectionParser[RankBallot] with RegexParsers with ElectionParsers {
def line: Parser[RankedWeightedBallot] = id ~ weight ~ preferences ^^ {
def line: Parser[RankBallot] = id ~ weight ~ preferences ^^ {
case ~(~(i, w), prefs) => {
RankedWeightedBallot(prefs, i, w)
RankBallot(prefs, i, w)
}
}
def preferences: Parser[List[(Candidate, Int)]] = {
var rank = 1
((candidate ^^ { case (cand) => List((cand, rank)) }) ~ rep((">" ~ candidate) ^^ {
((candidate ^^ { cand => List((cand, rank)) }) ~ rep((">" ~ candidate) ^^ {
case ~(">", cand) => {
rank = rank + 1
(cand, rank)
}
case _ => throw new Exception
} | ("=" ~ candidate) ^^ {
case ~("=", cand) => {
(cand, rank)
}
case ~("=", cand) => (cand, rank)
case _ => throw new Exception
})) ^^ { case ~(list1, list2) => list1 ++ list2 }
} ^^ {
case prefs => prefs sortWith {
......@@ -71,11 +67,11 @@ object PreferencesParserWithIndifference extends ElectionParser[RankedWeightedBa
}
object PreferencesParserWithScore extends ElectionParser[ScoredWeightedBallot] with RegexParsers with ElectionParsers {
object PreferencesParserWithScore extends ElectionParser[ScoreBallot] with RegexParsers with ElectionParsers {
def line: Parser[ScoredWeightedBallot] = id ~ weight ~ opt("(") ~ preferences ~ opt(")") ^^ {
def line: Parser[ScoreBallot] = id ~ weight ~ opt("(") ~ preferences ~ opt(")") ^^ {
case ~(~(~(~(i, w), _), prefs), _) => {
ScoredWeightedBallot(prefs, i, w)
ScoreBallot(prefs, i, w)
}
}
......@@ -93,11 +89,11 @@ object PreferencesParserWithScore extends ElectionParser[ScoredWeightedBallot] w
}
}
object PreferencesParserWithRank extends ElectionParser[RankedWeightedBallot] with RegexParsers with ElectionParsers {
object PreferencesParserWithRank extends ElectionParser[RankBallot] with RegexParsers with ElectionParsers {
def line: Parser[RankedWeightedBallot] = id ~ weight ~ opt("(") ~ preferences ~ opt(")") ^^ {
def line: Parser[RankBallot] = id ~ weight ~ opt("(") ~ preferences ~ opt(")") ^^ {
case ~(~(~(~(i, w), _), prefs), _) => {
RankedWeightedBallot(prefs, i, w)
RankBallot(prefs, i, w)
}
}
......
package countvotes.structures
package agora.util.matrix
// TODO: Use Breeze
/**
* 2 Dimensional matrix
......
package countvotes.util
package agora.util
import countvotes.structures.{BaseMatrix, Rational}
import agora.util.matrix.BaseMatrix
import spire.math.Rational
/**
* Created by deepeshpandey on 30/07/17.
......