Added Init_d to the deny

Added Init_d to the deny

// Relational version of history

module histRelat
open c11Relat

pred preexecWF [ dom : set Action,
                 kind : Action -> Kind,
                 gloc : Action -> Glob,
                 lloc1, lloc2 : Action -> Thr,
                 sb : Action -> Action ] {
  SBwf[dom, kind, sb]
  locWF[dom, kind, gloc, lloc1, lloc2]

  lloc1 in Intern -> Thr
  lloc2 in Intern -> Thr

  // Assumptions don't turn up in the environment
  no kind.AssmEq & Extern

  // External actions are unordered in sb
  no sb & ((Extern -> Action) + (Action -> Extern))

  // Internal actions are totally ordered in sb
  all disj a1, a2 : (dom & Intern) |
    a1 -> a2 in (^sb + ^(~sb))

  // Call / Return bracket internal actions
  all c : dom & Call, r : dom & Ret | {
    (c -> r) in ^sb
    all i : dom |
      i in Intern iff (c -> i) + (i -> r) in ^sb
  }
}

fun HBvsMO_d [ dom : set Action, kind : Action -> Kind,
               loc : Action -> Loc, wv, rv : Action -> Val,
               hb, sb, mo, rf : Action -> Action ]
                  : (Action -> Action) {
  { u : (Extern + Ret), v : (Extern + Call) |
    some disj w1, w2 : (dom <: loc.Atomic) |
    {
      (w2 -> w1) in mo
      (w1 -> u) + (v -> w2) in (iden + hb)
    }
  }
}

fun CoWR_d [ dom : set Action, kind : Action -> Kind,
             loc : Action -> Loc, wv, rv : Action -> Val,
             hb, sb, mo, rf : Action -> Action ]
                : (Action -> Action) {
  { u : (Extern + Ret), v : (Extern + Call) |
    disj [u,v] and
    some w1, w2 : kind.Write & (dom <: loc.Atomic),
               r : kind.Read & (dom <: loc.Atomic)   |
    {
      disj [w1, w2, r]
      (w1 -> r) in rf
      (w1 -> w2) in mo
      (w2 -> u) in iden + hb
      (v -> r) in iden + hb
    }
  }
}

fun HBacyc_d [ dom : set Action,
               kind : Action -> Kind,
               loc : Action -> Loc,
               wv, rv : Action -> Val,
               hb, sb, mo, rf : Action -> Action ]
                 : (Action -> Action) {
  { u : (Extern + Ret), v : (Extern + Call) |
    disj [u,v]
   and
    (v -> u) in hb
  }
}

fun Init_d [ dom : set Action,
             kind : Action -> Kind,
             gloc : Action -> Glob,
             wv, rv : Action -> Val,
             hb, sb, mo, rf : Action -> Action ]
                : (Action -> Action) {
  { u : (Extern + Ret), v : (Extern + Call) |
    some w : dom & kind.(Write + RMW) & gloc.Atomic,
         r : dom & kind.Read & gloc.Atomic | {
      no rf.r  // Read the init value
      (w -> u) in iden + hb
      (v -> r) in iden + hb
      w.gloc = r.gloc
    }
  }
}

fun getguar[ dom : Action, hb : Action -> Action ] : Action -> Action {
  hb & ((Extern -> Extern) + (Call -> Extern) +  (Extern -> Ret))
}

fun getdeny[ dom : set Action, kind : Action -> Kind,
             loc : Action -> Loc, wv, rv : Action -> Val,
             hb, sb, mo, rf : Action -> Action ]
                 : Action -> Action {
    CoWR_d[dom, kind, loc, wv, rv, ^hb, sb, mo, rf]
     +
    HBvsMO_d[dom, kind, loc, wv, rv, ^hb, sb, mo, rf]
     +
    HBacyc_d[dom, kind, loc, wv, rv, ^hb, sb, mo, rf]
     +
    Init_d[dom, kind, loc, wv, rv, ^hb, sb, mo, rf]

   // // Note: removed Ret -> Call deny because it's already enforced by sb
   //      - (Ret -> Call)
}

/*************************************************/
/* Cutting Predicates                            */
/*************************************************/

pred cutR[ dom : set Action, kind : Action -> Kind,
           loc : Action -> Loc, wv, rv : Action -> Val,
           hb, sb, mo, rf : Action -> Action ] {
  all r : Extern & kind.Read & loc.Atomic & dom |
  some w : Intern & dom | {
    (w -> r) in rf
    no (w.rf & Extern) - r
  }
}

fun vizAct[ dom : set Action, rf : Action -> Action ] : Action  {
  // Internal actions
  (dom & Intern) +
  // External actions that are read or read from internal actions
  { a : dom & Extern |
    some a' : dom & Intern | some ((a -> a') + (a' -> a)) & rf }
}

pred cutW[ dom : set Action, kind : Action -> Kind,
            loc : Action -> Loc, wv, rv : Action -> Val,
            hb, sb, mo, rf : Action -> Action ] {
  all disj w, w' : Extern & dom | {
    {(w.loc = w'.loc) and (no (w + w') & vizAct[dom, rf])}
       implies
    some w'' : vizAct[dom, rf] |
       (w -> w'') + (w'' -> w') in mo
  }
}

// Relational version of history

module histRelat
open c11Relat

pred preexecWF [ dom : set Action,
                 kind : Action -> Kind,
                 gloc : Action -> Glob,
                 lloc1, lloc2 : Action -> Thr,
                 sb : Action -> Action ] {
  SBwf[dom, kind, sb]
  locWF[dom, kind, gloc, lloc1, lloc2]

  lloc1 in Intern -> Thr
  lloc2 in Intern -> Thr

  // Assumptions don't turn up in the environment
  no kind.AssmEq & Extern

  // External actions are unordered in sb
  no sb & ((Extern -> Action) + (Action -> Extern))

  // Internal actions are totally ordered in sb
  all disj a1, a2 : (dom & Intern) |
    a1 -> a2 in (^sb + ^(~sb))

  // Call / Return bracket internal actions
  all c : dom & Call, r : dom & Ret | {
    (c -> r) in ^sb
    all i : dom |
      i in Intern iff (c -> i) + (i -> r) in ^sb
  }
}

fun HBvsMO_d [ dom : set Action, kind : Action -> Kind,
               loc : Action -> Loc, wv, rv : Action -> Val,
               hb, sb, mo, rf : Action -> Action ]
                  : (Action -> Action) {
  { u : (Extern + Ret), v : (Extern + Call) |
    some disj w1, w2 : (dom <: loc.Atomic) |
    {
      (w2 -> w1) in mo
      (w1 -> u) + (v -> w2) in (iden + hb)
    }
  }
}

fun CoWR_d [ dom : set Action, kind : Action -> Kind,
             loc : Action -> Loc, wv, rv : Action -> Val,
             hb, sb, mo, rf : Action -> Action ]
                : (Action -> Action) {
  { u : (Extern + Ret), v : (Extern + Call) |
    disj [u,v] and
    some w1, w2 : kind.Write & (dom <: loc.Atomic),
               r : kind.Read & (dom <: loc.Atomic)   |
    {
      disj [w1, w2, r]
      (w1 -> r) in rf
      (w1 -> w2) in mo
      (w2 -> u) in iden + hb
      (v -> r) in iden + hb
    }
  }
}

fun HBacyc_d [ dom : set Action, kind : Action -> Kind,
               loc : Action -> Loc, wv, rv : Action -> Val,
               hb, sb, mo, rf : Action -> Action ]
                 : (Action -> Action) {
  { u : (Extern + Ret), v : (Extern + Call) |
    disj [u,v]
   and
    (v -> u) in hb
  }
}

fun getguar[ dom : Action, hb : Action -> Action ] : Action -> Action {
  hb & ((Extern -> Extern) + (Call -> Extern) +  (Extern -> Ret))
}

fun getdeny[ dom : set Action, kind : Action -> Kind,
             loc : Action -> Loc, wv, rv : Action -> Val,
             hb, sb, mo, rf : Action -> Action ]
                 : Action -> Action {
   // Note: removed Ret -> Call deny because it's already enforced by sb
   (CoWR_d[dom, kind, loc, wv, rv, ^hb, sb, mo, rf]
     +
    HBvsMO_d[dom, kind, loc, wv, rv, ^hb, sb, mo, rf]
     +
    HBacyc_d[dom, kind, loc, wv, rv, ^hb, sb, mo, rf])
        - (Ret -> Call)
}

/*************************************************/
/* Cutting Predicates                            */
/*************************************************/

pred cutR[ dom : set Action, kind : Action -> Kind,
           loc : Action -> Loc, wv, rv : Action -> Val,
           hb, sb, mo, rf : Action -> Action ] {
  all r : Extern & kind.Read & loc.Atomic & dom |
  some w : Intern & dom | {
    (w -> r) in rf
    no (w.rf & Extern) - r
  }
}

fun vizAct[ dom : set Action, rf : Action -> Action ] : Action  {
  // Internal actions
  (dom & Intern) +
  // External actions that are read or read from internal actions
  { a : dom & Extern |
    some a' : dom & Intern | some ((a -> a') + (a' -> a)) & rf }
}

pred cutW[ dom : set Action, kind : Action -> Kind,
            loc : Action -> Loc, wv, rv : Action -> Val,
            hb, sb, mo, rf : Action -> Action ] {
  all disj w, w' : Extern & dom | {
    {(w.loc = w'.loc) and (no (w + w') & vizAct[dom, rf])}
       implies
    some w'' : vizAct[dom, rf] |
       (w -> w'') + (w'' -> w') in mo
  }
}


use Scope to specify maze's size.

use Scope to specify maze's size.

module maze_maker/simple_maze

open util/ordering[Col] as cols
open util/ordering[Row] as rows

// 隣接する Cell
fun adjacent (col: Col, row: Row) : Col -> Row {
  col.prev -> row +
  col.next -> row +
  col -> row.prev +
  col -> row.next
}

sig Col {
  paths: Row -> Col -> Row
} {
  // 自分自身との接続はなし
  all row: Row | no (this -> row) & row.paths
  // 接続先は必ず隣接する(4近傍の) Cell
  all row: Row | row.paths in adjacent[this, row]
}
sig Row {}

one sig entrance_x extends Col {}
one sig entrance_y extends Row {}
one sig exit_x extends Col {}
one sig exit_y extends Row {}

//  位置が盤の端
pred edge (col: Col, row: Row) {
  col = cols/first or col = cols/last or row = rows/first or row = rows/last
}

fact {
  // 全ての位置が paths に含まれている
  all col: Col, row: Row | (col -> row) in paths[Col, Row]
  // paths の連結は反射的
  all c1, c2: Col, r1, r2: Row | (c1 -> r1 -> c2 -> r2) in paths => (c2 -> r2 -> c1 -> r1) in paths
  // 入口と出口はいずれも盤面の端に位置する
  edge[entrance_x, entrance_y]
  edge[exit_x, exit_y]
}

run {} for exactly 10 Col, exactly 10 Row

module maze_maker/simple_maze

open util/ordering[Col] as cols
open util/ordering[Row] as rows

// 迷路のサイズ
fun height : Int {
  10
}
fun width: Int {
  10
}

// 隣接する Cell
fun adjacent (col: Col, row: Row) : Col -> Row {
  col.prev -> row +
  col.next -> row +
  col -> row.prev +
  col -> row.next
}

sig Col {
  paths: Row -> Col -> Row
} {
  // 自分自身との接続はなし
  all row: Row | no (this -> row) & row.paths
  // 接続先は必ず隣接する(4近傍の) Cell
  all row: Row | row.paths in adjacent[this, row]
}
sig Row {}

one sig entrance_x extends Col {}
one sig entrance_y extends Row {}
one sig exit_x extends Col {}
one sig exit_y extends Row {}

//  位置が盤の端
pred edge (col: Col, row: Row) {
  col = cols/first or col = cols/last or row = rows/first or row = rows/last
}

fact {
  // 全ての位置が paths に含まれている
  all col: Col, row: Row | (col -> row) in paths[Col, Row]
  // paths の連結は反射的
  all c1, c2: Col, r1, r2: Row | (c1 -> r1 -> c2 -> r2) in paths => (c2 -> r2 -> c1 -> r1) in paths
  // 入口と出口はいずれも盤面の端に位置する
  edge[entrance_x, entrance_y]
  edge[exit_x, exit_y]
}

run {
  #Col = width[]
  #Row = height[]
} for 10


Fixed mismatch between ballots and votes.

-- (c) 2010, Dermot Cochran, IT University of Copenhagen
-- http://www.kindsoftware.com/about/people/dc
-- http://www.itu.dk/people/dero

module Voting

open util/integer

-- A individual person standing for election
sig Candidate {
    identifier:       Int,             -- Unique identifier for this candidate
    votes: 			  set Ballot, 	-- First preference ballots assigned to this candidate
	transfers: 	      set Ballot,   -- Ballots received by transfer from another candidate
	surplus: 		  set Ballot, 	-- Ballots given to another candidate (on election or elimination)
	outcome: 		  Event
} {
	no b: Ballot | b in votes & transfers
	all b: Ballot | b in votes + transfers => this in b.assignees
	surplus in votes + transfers
	Election.method = Plurality implies #surplus = 0 and #transfers = 0
    0 < identifier
}

-- A digital or paper artifact which accurately records the intentions of the voter
sig Ballot {
  identifier:		Int,				    -- Unique identifier for this ballot
  assignees: 		set Candidate,  -- Candidates to which this ballot has been assigned
  preferences: 	seq Candidate
} {
	assignees in preferences.elems
    not preferences.hasDups
	preferences.elems in Election.candidates
	preferences.first in assignees
	Election.method = Plurality implies #preferences = 1
    0 < #preferences
    0 < identifier
    some v: Vote | v.ballot = identifier and v.candidate = preferences.first.identifier and v.ranking = 1
    some v: Vote | v.ballot = identifier and v.candidate = preferences.last.identifier and v.ranking = #preferences
    all v: Vote | v.ballot = identifier implies v.candidate = preferences.subseq[v.ranking-1,v.ranking].first.identifier
}

-- Table of fragments of Votes used for encoding of results
sig Vote {
	ballot:			Int,		-- Ballot identifier
    candidate: 	Int,		-- Candidate identifier
    ranking: 		Int		-- Ranking of candidate on ballot paper (e.g. 1,2,3,...)
} {
	0 < ranking and ranking <= #Election.candidates
    some b: Ballot | b.identifier = ballot and ranking <= #b.preferences
    some c: Candidate | c.identifier = candidate
}

-- An election result
one sig Scenario {
   	losers: 				set Candidate,
   	winners: 			set Candidate,
	eliminated: 		set Candidate, 		-- Candidates excluded under STV rules
	threshold: 		Int, 						-- Minimum number of votes for a Loser or EarlyLoser
	quota: 				Int						-- Minimum number of votes for a STV Winner or QuotaWinner
}
{
 	winners + losers = Election.candidates
 	#winners = Election.seats
 	no c: Candidate | c in losers & winners
 	0 < #losers
 	all w: Candidate | all l: Candidate | l in losers and w in winners implies
		#l.votes + #l.transfers <= #w.votes + #w.transfers
	0 <= threshold
	threshold < quota
	Election.method = Plurality implies #eliminated = 0
	eliminated in losers
	all c: Candidate | c in losers implies Election.method = Plurality or #c.votes + #c.transfers < quota
}

/*
	There are four winner-outcomes and six loser-outcomes:

	Winner: 						(W1) elected in the first round of counting either by quota or plurality,
	QuotaWinner: 				(W2) elected with transfers from another candidate (STV only),
	CompromiseWinner: 	(W3) elected on the last round of counting without quota (STV only),
	TiedWinner:					(W4) elected by tie breaker,
	TiedLoser:					(L1) loses only by tie breaker but reaches the threshold,
	Loser:			 				(L2) defeated on last round but reaches the minimum threshold of votes,
    TiedEarlyLoser:			(L3) reaches threshold but eliminated by tie breaker (STV only),
	EarlyLoser:					(L4) reaches threshold but is eliminated before last round (STV only),
	TiedSoreLoser:				(L5) loses only by tie breaker but does not reach threshold,
	SoreLoser: 					(L6) does not even reach the mimimum threshold of votes
*/
enum Event {Winner, QuotaWinner, CompromiseWinner, TiedWinner,
	TiedLoser, Loser, TiedEarlyLoser, EarlyLoser, TiedSoreLoser, SoreLoser}

enum Method {Plurality, STV}

-- An Election Constituency
one sig Election {
  candidates: 	set Candidate,
  seats: 				Int,
  method: 			Method
}
{
 	0 < seats
 	seats < #candidates
 	all c: Candidate | c in candidates
}

-- Independent (or Fundamental) Axioms
fact uniqueCandidateID {
  no disj a,b: Candidate | a.identifier = b.identifier
}

fact uniqueBallotID {
  no disj a,b: Ballot | a.identifier = b.identifier
}

fact nonDuplicationOfVotes {
  no disj a,b: Vote | a.ballot = b.ballot and a.candidate = b.candidate
}

fact integrity {
  all c: Candidate | all b: Ballot | b in c.votes implies c in b.assignees
}

fact pluralityEvents {
	all c: Candidate | Election.method = Plurality implies
		(c.outcome = Loser or c.outcome = SoreLoser or c.outcome = Winner or
		c.outcome = TiedWinner or c.outcome = TiedLoser)
}

fact winnerSTV {
	all c: Candidate | Election.method = STV implies (
		c.outcome = Winner iff Scenario.quota <= #c.votes)
}

fact transferWinner {
	all c: Candidate | c.outcome = QuotaWinner iff
		#c.votes < Scenario.quota and Scenario.quota <= #c.votes + #c.transfers
}

fact closeWinner {
	all c: Candidate | c.outcome = CompromiseWinner or c.outcome = TiedWinner iff
		c in Scenario.winners and #c.votes + #c.transfers < Scenario.quota
}

fact soreLoser {
	all c: Candidate | (c.outcome = SoreLoser or c.outcome = TiedSoreLoser) iff
		#c.votes + #c.transfers < Scenario.threshold
}

fact loser {
	all c: Candidate | (c.outcome = Loser or c.outcome = TiedLoser or c.outcome = TiedSoreLoser) iff
		c in Scenario.losers - Scenario.eliminated
}

fact earlyLoser {
	all c: Candidate | c.outcome = EarlyLoser or c.outcome = TiedEarlyLoser iff
		(c in Scenario.losers & Scenario.eliminated and Scenario.threshold <= #c.votes + #c.transfers)
}

fact winners {
	all c: Candidate | c in Scenario.winners iff
		c.outcome = Winner or c.outcome = QuotaWinner or c.outcome = CompromiseWinner or
		c.outcome = TiedWinner
}

fact losers {
	all c: Candidate | c in Scenario.losers iff
		(c.outcome = Loser or c.outcome = EarlyLoser or c.outcome = SoreLoser or
		c.outcome = TiedLoser or c.outcome = TiedEarlyLoser or c.outcome = TiedSoreLoser)
}

-- Non-Independent Axioms for Ballot Integrity
fact transfers {
	all c: Candidate | 0 < #c.transfers implies Election.method = STV
}

fact onlyWinnersAndQuotaWinnersHaveSurplus {
	all c: Candidate | 0 < #c.surplus implies
		c.outcome = Winner or c.outcome = QuotaWinner
}

fact winnersNeedNoTransfers {
		all c: Candidate | c.outcome = Winner implies 0 = #c.transfers
}

fact firstPreference {
	all b: Ballot | all c: Candidate | b.preferences.first = c iff b in c.votes
}

fact sizeOfSurplus {
	all c: Candidate | (c in Scenario.winners and Election.method = STV and 0 < #c.surplus) implies
		#c.surplus = #c.votes + #c.transfers - Scenario.quota
}

fact transferToNextPreference {
	all b: Ballot | all disj donor,receiver: Candidate |
		(donor + receiver in b.assignees and
		b in receiver.transfers and b in donor.surplus implies
		b.preferences.idxOf[donor] < b.preferences.idxOf[receiver] and
		receiver in b.preferences.rest.elems)
}

fact pluralityWinner {
	all disj a, b: Candidate | (Election.method = Plurality and Election.seats = 1) and
		a.outcome = Winner implies #b.votes <= #a.votes
}

fact transferToNextContinuingCandidate {
	all disj skipped, receiving: Candidate | all b: Ballot |
		b.preferences.idxOf[skipped] < b.preferences.idxOf[receiving] and
		receiving in b.assignees and (not skipped in b.assignees) implies
		(skipped in Scenario.eliminated or skipped.outcome = Winner or
		skipped.outcome = QuotaWinner)
}

// All ballots transfers are associated with the last candidate to receive the transfer
fact ownership {
	all disj c,d: Candidate | all b: Ballot | b in c.transfers implies c in b.assignees and
		(d not in b.assignees or b.preferences.idxOf[d] < b.preferences.idxOf[c])
}

// Lowest candidate is eliminated first
fact lowestElimination {
	all disj c,d: Candidate | c in Scenario.eliminated and d not in Scenario.eliminated implies
		#c.votes + #c.transfers <= #d.votes + #d.transfers
}

// All ties involve equality between at least one winner and at least one loser on either original votes or
// on transfers plus original votes
fact equalityOfTiedWinner {
   all w: Candidate | some l: Candidate | w.outcome = TiedWinner and
	 	(l.outcome = TiedLoser or l.outcome = TiedSoreLoser or l.outcome = TiedEarlyLoser) implies
		(#l.votes = #w.votes) or (#l.votes + #l.transfers = #w.votes + #w.transfers)
}

fact equalityOfTiedLosers {
  all s: Candidate | some w: Candidate | w.outcome = TiedWinner and
       (s.outcome = SoreLoser or s.outcome = TiedLoser or s.outcome = TiedEarlyLoser) implies
       (#s.votes = #w.votes) or (#s.votes + #s.transfers = #w.votes + #w.transfers)
}

// Ranking of votes on ballots
fact firstPreference {
	all v: Vote | some b: Ballot | v.ballot = b.identifier and
		v.ranking = 1 implies b.preferences.first.identifier = v.candidate
}

fact rankingOfVotes {
   	all v: Vote | some b: Ballot | some c: Candidate | Election.method = STV and
		v.ballot = b.identifier and v.candidate = c.identifier implies
	    c in b.preferences.elems and v.ranking = b.preferences.idxOf[c] + 1
}

-- Scenario Validity Axioms
// When there is a tied sore loser then there are no non-sore losers
fact typeOfTiedLoser {
   no disj a,b: Candidate | a.outcome = TiedSoreLoser and
        (b.outcome = TiedLoser or b.outcome = TiedEarlyLoser or
         b.outcome=Loser or b.outcome=EarlyLoser)
}

fact tieBreaker {
	all w: Candidate | some l: Candidate | w.outcome = TiedWinner implies
		(l.outcome = TiedLoser or l.outcome = TiedSoreLoser or l.outcome = TiedEarlyLoser)
}

fact validTieBreaker {
	all l: Candidate | some w: Candidate |
    (l.outcome = TiedLoser or l.outcome = TiedSoreLoser or l.outcome = TiedEarlyLoser) implies
    w.outcome = TiedWinner
}

-- Axioms for the recording of vote fragments
fact allVotesRecorded {
   all b: Ballot | some v: Vote | v.ballot = b.identifier and v.ranking = #b.preferences
}

// All vote fragments are recorded for each ballot
fact lowerRankings {
   all v: Vote | some w: Vote | 1 < v.ranking implies w.ranking + 1 = v.ranking and
	v.ballot = w.ballot and not v.candidate = w.candidate
}

// Well formed ranking of candidates in ballots
fact wellFormedRanking {
	no disj v,w: Vote | v.ballot = w.ballot and Election.method = STV
		implies v.candidate = w.candidate or v.ranking = w.ranking
}

// Compromise winner must have more votes than any tied winners
fact compromiseNotTied {
	all disj c,t: Candidate | (c.outcome = CompromiseWinner and t.outcome = TiedWinner) implies
		#t.votes + #t.transfers < #c.votes + #t.transfers
}

// Equal losers are tied
fact equalityofTiedWinnersAndLosers {
	all disj w,l: Candidate | w in Scenario.winners and l in Scenario.losers and
		#w.votes = #l.votes and #w.transfers = #l.transfers implies
			w.outcome = TiedWinner and
			(l.outcome = TiedLoser or l.outcome = TiedEarlyLoser or l.outcome = TiedSoreLoser)
}

// Highest winner has a quota
fact highestWinner {
   some c: Candidate | Election.method = STV implies
		Scenario.quota <= #c.votes + #c.transfers
}

-- Basic Lemmas
assert honestCount {
	  all c: Candidate | all b: Ballot | b in c.votes + c.transfers implies c in b.assignees
}
check honestCount for 15 but 6 int

assert atLeastOneLoser {
	0 < #Scenario.losers
}
check atLeastOneLoser for 15 but 6 int

assert atLeastOneWinner {
	0 < #Scenario.winners
}
check atLeastOneWinner for 14 but 6 int

assert wellFormednessOfBallots {
	all b: Ballot | b.assignees in Election.candidates
}
check wellFormednessOfBallots for 18 but 6 int

assert plurality {
	all c: Candidate | all b: Ballot | b in c.votes and
		Election.method = Plurality implies c in b.preferences.first
}
check plurality for 18 but 6 int

assert wellFormedTieBreaker {
	some w,l : Candidate | (w in Scenario.winners and l in Scenario.losers and
		#w.votes = #l.votes and #w.transfers = #l.transfers) implies
		w.outcome = TiedWinner and
		(l.outcome = TiedLoser or l.outcome = TiedSoreLoser or l.outcome=TiedEarlyLoser)
}
check wellFormedTieBreaker for 18 but 6 int

assert validSurplus {
	all c: Candidate | 0 < #c.surplus implies (c.outcome = Winner or c.outcome = QuotaWinner or
		c in Scenario.eliminated)
}
check validSurplus for 16 but 6 int

assert wellFormedVote {
	all v: Vote | 0 < v.ballot and 0 < v.candidate
}
check wellFormedVote for 4 but 6 int

-- Advanced Lemmas
// No lost votes during counting
assert accounting {
	all b: Ballot | one c: Candidate | b in c.votes and c in b.assignees
}
check accounting for 16 but 6 int

// Cannot have tie breaker with both tied sore loser and non-sore loser
assert tiedWinnerLoserTiedSoreLoser {
	no disj c,w,l: Candidate | c.outcome = TiedSoreLoser and
	   w.outcome = TiedWinner and (l.outcome = Loser or l.outcome = TiedLoser)
}
check tiedWinnerLoserTiedSoreLoser for 6 int

// Compromise winner must have at least one vote
assert validCompromise {
	all c: Candidate | c.outcome = CompromiseWinner implies 0 < #c.votes + #c.transfers
}
check validCompromise for 6 int

-- Sample scenarios
pred TwoCandidatePlurality {
	Election.method = Plurality
	Election.seats = 1
	#Election.candidates = 2
}
run TwoCandidatePlurality for 10 but 1 Ballot, 6 int

pred PluralityTiedWinner {
	Election.method = Plurality
	Election.seats = 1
	some disj a,b: Candidate | a.outcome = TiedWinner and b.outcome = TiedLoser
}
run PluralityTiedWinner for 10 but 2 Ballot, 6 int

pred ThreeCandidatePlurality {
	Election.method = Plurality
	Election.seats = 1
	#Election.candidates = 3
}
run ThreeCandidatePlurality for 6 int

pred Plurality {
	Election.method = Plurality
	Election.seats = 1
	3 < #Election.candidates
}
run Plurality for 5 but 6 int

pred TenCandidatePluralityWithTwoSeats {
	Election.method = Plurality
	Election.seats = 2
	#Election.candidates = 10
}
run TenCandidatePluralityWithTwoSeats for 10 but 6 int

pred InstantRunoffVoting {
	Election.method = STV
	Election.seats = 1
	3 < #Election.candidates
}
run InstantRunoffVoting for 10 but 6 int

pred STV3 {
	Election.method = STV
	Election.seats = 3
}
run STV3 for 5 but 6 int

pred ThreeWinnersOneLoser {
    Election.method = STV
	some disj a,b,d: Candidate | a.outcome = Winner
   	  and b.outcome = QuotaWinner or b.outcome = CompromiseWinner
	  and d in Scenario.losers
}
run ThreeWinnersOneLoser for 6 but 6 int

pred LoserAndEarlyLoser {
	one d: Candidate | d.outcome = Loser
	one e: Candidate | e.outcome = EarlyLoser
}
run LoserAndEarlyLoser for 5 but 6 int

pred OneWinnerNineLosers {
	#Scenario.winners = 1
	#Scenario.losers = 9
}
run OneWinnerNineLosers for 16 but 6 int

pred ThreeWayTie {
	#Election.candidates = 3
    Election.method = Plurality
	some disj a,b,c: Candidate | a.outcome = TiedWinner and
		b.outcome = TiedLoser and
		c.outcome = TiedLoser
}
run ThreeWayTie for 5 but 6 int

pred FiveWayTie {
	some disj a,b,c,d,e: Candidate | a.outcome = TiedWinner and
	 b.outcome = TiedLoser and
		c.outcome = TiedLoser and d.outcome = TiedLoser and e.outcome = TiedWinner
}
run FiveWayTie for 7 but 6 int

pred ScenarioLWW {
	some disj a, b,c: Candidate | a in Scenario.losers and b.outcome = Winner and
		c in Scenario.winners
    #Election.candidates = 3
}
run ScenarioLWW for 6 but 7 int

pred LongBallot {
	some b: Ballot | #b.preferences = 7
}
run LongBallot for 7 but 7 seq, 6 int

-- (c) 2010, Dermot Cochran, IT University of Copenhagen
-- http://www.kindsoftware.com/about/people/dc
-- http://www.itu.dk/people/dero

module Voting

open util/integer

-- A person standing for election
sig Candidate {
    identifier:       Int,             -- Unique identifier for this candidate
    votes: 			  set Ballot, 	-- First preference ballots assigned to this candidate
	transfers: 	      set Ballot,   -- Ballots received by transfer from another candidate
	surplus: 		  set Ballot, 	-- Ballots given to another candidate (on election or elimination)
	outcome: 		  Event
} {
	no b: Ballot | b in votes & transfers
	all b: Ballot | b in votes + transfers => this in b.assignees
	surplus in votes + transfers
	Election.method = Plurality implies #surplus = 0 and #transfers = 0
    0 < identifier
}

-- A digital or paper artifact which accurately records the intentions of the voter
sig Ballot {
  identifier:		Int,				    -- Unique identifier for this ballot
  assignees: 		set Candidate,  -- Candidates to which this ballot has been assigned
  preferences: 	seq Candidate
} {
	assignees in preferences.elems
    not preferences.hasDups
	preferences.elems in Election.candidates
	preferences.first in assignees
	Election.method = Plurality implies #preferences = 1
    0 < #preferences
    0 < identifier
    some v: Vote | v.ballot = identifier and v.candidate = preferences.first.identifier and v.ranking = 1
}

-- Table of fragments of Votes used for encoding of results
sig Vote {
	ballot:			Int,		-- Ballot identifier
    candidate: 	Int,		-- Candidate identifier
    ranking: 		Int		-- Ranking of candidate on ballot paper (e.g. 1,2,3,...)
} {
	0 < ranking and ranking <= #Election.candidates
    some b: Ballot | b.identifier = ballot and ranking <= #b.preferences
    some c: Candidate | c.identifier = candidate
}

-- An election result
one sig Scenario {
   	losers: 				set Candidate,
   	winners: 			set Candidate,
	eliminated: 		set Candidate, 		-- Candidates excluded under STV rules
	threshold: 		Int, 						-- Minimum number of votes for a Loser or EarlyLoser
	quota: 				Int						-- Minimum number of votes for a STV Winner or QuotaWinner
}
{
 	winners + losers = Election.candidates
 	#winners = Election.seats
 	no c: Candidate | c in losers & winners
 	0 < #losers
 	all w: Candidate | all l: Candidate | l in losers and w in winners implies
		#l.votes + #l.transfers <= #w.votes + #w.transfers
	0 <= threshold
	threshold < quota
	Election.method = Plurality implies #eliminated = 0
	eliminated in losers
	all c: Candidate | c in losers implies Election.method = Plurality or #c.votes + #c.transfers < quota
}

/*
	There are four winner-outcomes and six loser-outcomes:

	Winner: 						(W1) elected in the first round of counting either by quota or plurality,
	QuotaWinner: 				(W2) elected with transfers from another candidate (STV only),
	CompromiseWinner: 	(W3) elected on the last round of counting without quota (STV only),
	TiedWinner:					(W4) elected by tie breaker,
	TiedLoser:					(L1) loses only by tie breaker but reaches the threshold,
	Loser:			 				(L2) defeated on last round but reaches the minimum threshold of votes,
    TiedEarlyLoser:			(L3) reaches threshold but eliminated by tie breaker (STV only),
	EarlyLoser:					(L4) reaches threshold but is eliminated before last round (STV only),
	TiedSoreLoser:				(L5) loses only by tie breaker but does not reach threshold,
	SoreLoser: 					(L6) does not even reach the mimimum threshold of votes
*/
enum Event {Winner, QuotaWinner, CompromiseWinner, TiedWinner,
	TiedLoser, Loser, TiedEarlyLoser, EarlyLoser, TiedSoreLoser, SoreLoser}

enum Method {Plurality, STV}

-- An Election Constituency
one sig Election {
  candidates: 	set Candidate,
  seats: 				Int,
  method: 			Method
}
{
 	0 < seats
 	seats < #candidates
 	all c: Candidate | c in candidates
}

-- Independent (or Fundamental) Axioms
fact uniqueCandidateID {
  no disj a,b: Candidate | a.identifier = b.identifier
}

fact uniqueBallotID {
  no disj a,b: Ballot | a.identifier = b.identifier
}

fact nonDuplicationOfVotes {
  no disj a,b: Vote | a.ballot = b.ballot and a.candidate = b.candidate
}

fact integrity {
  all c: Candidate | all b: Ballot | b in c.votes implies c in b.assignees
}

fact pluralityEvents {
	all c: Candidate | Election.method = Plurality implies
		(c.outcome = Loser or c.outcome = SoreLoser or c.outcome = Winner or
		c.outcome = TiedWinner or c.outcome = TiedLoser)
}

fact winnerSTV {
	all c: Candidate | Election.method = STV implies (
		c.outcome = Winner iff Scenario.quota <= #c.votes)
}

fact transferWinner {
	all c: Candidate | c.outcome = QuotaWinner iff
		#c.votes < Scenario.quota and Scenario.quota <= #c.votes + #c.transfers
}

fact closeWinner {
	all c: Candidate | c.outcome = CompromiseWinner or c.outcome = TiedWinner iff
		c in Scenario.winners and #c.votes + #c.transfers < Scenario.quota
}

fact soreLoser {
	all c: Candidate | (c.outcome = SoreLoser or c.outcome = TiedSoreLoser) iff
		#c.votes + #c.transfers < Scenario.threshold
}

fact loser {
	all c: Candidate | (c.outcome = Loser or c.outcome = TiedLoser or c.outcome = TiedSoreLoser) iff
		c in Scenario.losers - Scenario.eliminated
}

fact earlyLoser {
	all c: Candidate | c.outcome = EarlyLoser or c.outcome = TiedEarlyLoser iff
		(c in Scenario.losers & Scenario.eliminated and Scenario.threshold <= #c.votes + #c.transfers)
}

fact winners {
	all c: Candidate | c in Scenario.winners iff
		c.outcome = Winner or c.outcome = QuotaWinner or c.outcome = CompromiseWinner or
		c.outcome = TiedWinner
}

fact losers {
	all c: Candidate | c in Scenario.losers iff
		(c.outcome = Loser or c.outcome = EarlyLoser or c.outcome = SoreLoser or
		c.outcome = TiedLoser or c.outcome = TiedEarlyLoser or c.outcome = TiedSoreLoser)
}

-- Non-Independent Axioms for Ballot Integrity
fact transfers {
	all c: Candidate | 0 < #c.transfers implies Election.method = STV
}

fact onlyWinnersAndQuotaWinnersHaveSurplus {
	all c: Candidate | 0 < #c.surplus implies
		c.outcome = Winner or c.outcome = QuotaWinner
}

fact winnersNeedNoTransfers {
		all c: Candidate | c.outcome = Winner implies 0 = #c.transfers
}

fact firstPreference {
	all b: Ballot | all c: Candidate | b.preferences.first = c iff b in c.votes
}

fact sizeOfSurplus {
	all c: Candidate | (c in Scenario.winners and Election.method = STV and 0 < #c.surplus) implies
		#c.surplus = #c.votes + #c.transfers - Scenario.quota
}

fact transferToNextPreference {
	all b: Ballot | all disj donor,receiver: Candidate |
		(donor + receiver in b.assignees and
		b in receiver.transfers and b in donor.surplus implies
		b.preferences.idxOf[donor] < b.preferences.idxOf[receiver] and
		receiver in b.preferences.rest.elems)
}

fact pluralityWinner {
	all disj a, b: Candidate | (Election.method = Plurality and Election.seats = 1) and
		a.outcome = Winner implies #b.votes <= #a.votes
}

fact transferToNextContinuingCandidate {
	all disj skipped, receiving: Candidate | all b: Ballot |
		b.preferences.idxOf[skipped] < b.preferences.idxOf[receiving] and
		receiving in b.assignees and (not skipped in b.assignees) implies
		(skipped in Scenario.eliminated or skipped.outcome = Winner or
		skipped.outcome = QuotaWinner)
}

// All ballots transfers are associated with the last candidate to receive the transfer
fact ownership {
	all disj c,d: Candidate | all b: Ballot | b in c.transfers implies c in b.assignees and
		(d not in b.assignees or b.preferences.idxOf[d] < b.preferences.idxOf[c])
}

// Lowest candidate is eliminated first
fact lowestElimination {
	all disj c,d: Candidate | c in Scenario.eliminated and d not in Scenario.eliminated implies
		#c.votes + #c.transfers <= #d.votes + #d.transfers
}

// All ties involve equality between at least one winner and at least one loser on either original votes or
// on transfers plus original votes
fact equalityOfTiedWinner {
   all w: Candidate | some l: Candidate | w.outcome = TiedWinner and
	 	(l.outcome = TiedLoser or l.outcome = TiedSoreLoser or l.outcome = TiedEarlyLoser) implies
		(#l.votes = #w.votes) or (#l.votes + #l.transfers = #w.votes + #w.transfers)
}

fact equalityOfTiedLosers {
  all s: Candidate | some w: Candidate | w.outcome = TiedWinner and
       (s.outcome = SoreLoser or s.outcome = TiedLoser or s.outcome = TiedEarlyLoser) implies
       (#s.votes = #w.votes) or (#s.votes + #s.transfers = #w.votes + #w.transfers)
}

// Ranking of votes on ballots
fact firstPreference {
	all v: Vote | some b: Ballot | v.ballot = b.identifier and
		v.ranking = 1 implies b.preferences.first.identifier = v.candidate
}

fact rankingOfVotes {
   	all v: Vote | some b: Ballot | some c: Candidate | Election.method = STV and
		v.ballot = b.identifier and v.candidate = c.identifier implies
	    c in b.preferences.elems and v.ranking = b.preferences.idxOf[c]
}

-- Scenario Validity Axioms
// When there is a tied sore loser then there are no non-sore losers
fact typeOfTiedLoser {
   no disj a,b: Candidate | a.outcome = TiedSoreLoser and
        (b.outcome = TiedLoser or b.outcome = TiedEarlyLoser or
         b.outcome=Loser or b.outcome=EarlyLoser)
}

fact tieBreaker {
	all w: Candidate | some l: Candidate | w.outcome = TiedWinner implies
		(l.outcome = TiedLoser or l.outcome = TiedSoreLoser or l.outcome = TiedEarlyLoser)
}

fact validTieBreaker {
	all l: Candidate | some w: Candidate |
    (l.outcome = TiedLoser or l.outcome = TiedSoreLoser or l.outcome = TiedEarlyLoser) implies
    w.outcome = TiedWinner
}

-- Axioms for the recording of vote fragments
fact allVotesRecorded {
   all b: Ballot | some v: Vote | v.ballot = b.identifier and v.ranking = #b.preferences
}

// All vote fragments are recorded for each ballot
fact lowerRankings {
   all v: Vote | some w: Vote | 1 < v.ranking implies w.ranking + 1 = v.ranking and
	v.ballot = w.ballot and not v.candidate = w.candidate
}

// Well formed ranking of candidates in ballots
fact wellFormedRanking {
	no disj v,w: Vote | v.ballot = w.ballot and Election.method = STV
		implies v.candidate = w.candidate or v.ranking = w.ranking
}

// Compromise winner must have more votes than any tied winners
fact compromiseNotTied {
	all disj c,t: Candidate | (c.outcome = CompromiseWinner and t.outcome = TiedWinner) implies
		#t.votes + #t.transfers < #c.votes + #t.transfers
}

// Equal losers are tied
fact equalityofTiedWinnersAndLosers {
	all disj w,l: Candidate | w in Scenario.winners and l in Scenario.losers and
		#w.votes = #l.votes and #w.transfers = #l.transfers implies
			w.outcome = TiedWinner and
			(l.outcome = TiedLoser or l.outcome = TiedEarlyLoser or l.outcome = TiedSoreLoser)
}

// Highest winner has a quota
fact highestWinner {
   some c: Candidate | Election.method = STV implies
		Scenario.quota <= #c.votes + #c.transfers
}

-- Basic Lemmas
assert honestCount {
	  all c: Candidate | all b: Ballot | b in c.votes + c.transfers implies c in b.assignees
}
check honestCount for 15 but 6 int

assert atLeastOneLoser {
	0 < #Scenario.losers
}
check atLeastOneLoser for 15 but 6 int

assert atLeastOneWinner {
	0 < #Scenario.winners
}
check atLeastOneWinner for 14 but 6 int

assert wellFormednessOfBallots {
	all b: Ballot | b.assignees in Election.candidates
}
check wellFormednessOfBallots for 18 but 6 int

assert plurality {
	all c: Candidate | all b: Ballot | b in c.votes and
		Election.method = Plurality implies c in b.preferences.first
}
check plurality for 18 but 6 int

assert wellFormedTieBreaker {
	some w,l : Candidate | (w in Scenario.winners and l in Scenario.losers and
		#w.votes = #l.votes and #w.transfers = #l.transfers) implies
		w.outcome = TiedWinner and
		(l.outcome = TiedLoser or l.outcome = TiedSoreLoser or l.outcome=TiedEarlyLoser)
}
check wellFormedTieBreaker for 18 but 6 int

assert validSurplus {
	all c: Candidate | 0 < #c.surplus implies (c.outcome = Winner or c.outcome = QuotaWinner or
		c in Scenario.eliminated)
}
check validSurplus for 16 but 6 int

assert wellFormedVote {
	all v: Vote | 0 < v.ballot and 0 < v.candidate
}
check wellFormedVote for 4 but 6 int

-- Advanced Lemmas
// No lost votes during counting
assert accounting {
	all b: Ballot | one c: Candidate | b in c.votes and c in b.assignees
}
check accounting for 16 but 6 int

// Cannot have tie breaker with both tied sore loser and non-sore loser
assert tiedWinnerLoserTiedSoreLoser {
	no disj c,w,l: Candidate | c.outcome = TiedSoreLoser and
	   w.outcome = TiedWinner and (l.outcome = Loser or l.outcome = TiedLoser)
}
check tiedWinnerLoserTiedSoreLoser for 6 int

// Compromise winner must have at least one vote
assert validCompromise {
	all c: Candidate | c.outcome = CompromiseWinner implies 0 < #c.votes + #c.transfers
}
check validCompromise for 6 int

-- Sample scenarios
pred TwoCandidatePlurality {
	Election.method = Plurality
	Election.seats = 1
	#Election.candidates = 2
}
run TwoCandidatePlurality for 10 but 1 Ballot, 6 int

pred PluralityTiedWinner {
	Election.method = Plurality
	Election.seats = 1
	some disj a,b: Candidate | a.outcome = TiedWinner and b.outcome = TiedLoser
}
run PluralityTiedWinner for 10 but 2 Ballot, 6 int

pred ThreeCandidatePlurality {
	Election.method = Plurality
	Election.seats = 1
	#Election.candidates = 3
}
run ThreeCandidatePlurality for 6 int

pred Plurality {
	Election.method = Plurality
	Election.seats = 1
	3 < #Election.candidates
}
run Plurality for 5 but 6 int

pred TenCandidatePluralityWithTwoSeats {
	Election.method = Plurality
	Election.seats = 2
	#Election.candidates = 10
}
run TenCandidatePluralityWithTwoSeats for 10 but 6 int

pred InstantRunoffVoting {
	Election.method = STV
	Election.seats = 1
	3 < #Election.candidates
}
run InstantRunoffVoting for 10 but 6 int

pred STV3 {
	Election.method = STV
	Election.seats = 3
}
run STV3 for 5 but 6 int

pred ThreeWinnersOneLoser {
    Election.method = STV
	some disj a,b,d: Candidate | a.outcome = Winner
   	  and b.outcome = QuotaWinner or b.outcome = CompromiseWinner
	  and d in Scenario.losers
}
run ThreeWinnersOneLoser for 6 but 6 int

pred LoserAndEarlyLoser {
	one d: Candidate | d.outcome = Loser
	one e: Candidate | e.outcome = EarlyLoser
}
run LoserAndEarlyLoser for 5 but 6 int

pred OneWinnerNineLosers {
	#Scenario.winners = 1
	#Scenario.losers = 9
}
run OneWinnerNineLosers for 16 but 6 int

pred ThreeWayTie {
	#Election.candidates = 3
    Election.method = Plurality
	some disj a,b,c: Candidate | a.outcome = TiedWinner and
		b.outcome = TiedLoser and
		c.outcome = TiedLoser
}
run ThreeWayTie for 5 but 6 int

pred FiveWayTie {
	some disj a,b,c,d,e: Candidate | a.outcome = TiedWinner and
	 b.outcome = TiedLoser and
		c.outcome = TiedLoser and d.outcome = TiedLoser and e.outcome = TiedWinner
}
run FiveWayTie for 7 but 6 int

pred ScenarioLWW {
	some disj a, b,c: Candidate | a in Scenario.losers and b.outcome = Winner and
		c in Scenario.winners
    #Election.candidates = 3
}
run ScenarioLWW for 6 but 7 int

pred LongBallot {
	some b: Ballot | #b.preferences = 7
}
run LongBallot for 7 but 7 seq, 6 int


Incomplete - task : Coverage profiling of universal tests - 91% code coverage

-- (c) 2010-2011, Dermot Cochran, IT University of Copenhagen
-- http://www.kindsoftware.com/about/people/dc
-- http://www.itu.dk/people/dero

module Voting

open util/integer

-- Note that all axioms should be expressed as facts appended to signatures
-- Standalone facts will be ignored by the API, but not by the analyser

/*
	There are 8 winner-outcomes and 8 loser-outcomes:

  WinnerNonTransferable:
                    elected on first round with at least one non-transferable surplus vote (STV)
	 SurplusWinner:		  elected on first round with at least one surplus vote (STV),
	 Winner: 				      elected in the first round of counting either by quota or plurality,
  AboveQuotaWinner: elected with surplus votes after receipt of transfers (STV),
  QuotaWinnerNonTransferable:
				                elected with at least one non-transferable surplus vote,
  QuotaWinner: 		   elected with quota after transfers from another candidate (STV only),
	 CompromiseWinner: elected on the last round of counting without quota (STV only),
	 TiedWinner:			    elected by tie breaker,
	 TiedLoser:			     loses only by tie breaker but reaches the threshold,
	 Loser:			 		      defeated on last round but reaches the minimum threshold of votes,
  TiedEarlyLoser:	  reaches threshold but eliminated by tie breaker (STV only),
  EarlyLoserNonTransferable:
                    reaches threshold bit is eliminated with some non-transferable votes,
	 EarlyLoser:		     reaches threshold but is eliminated before last round (STV only),
	 TiedSoreLoser:		  loses only by tie breaker but does not reach threshold,
  SoreLoserNonTransferable:
																				below threshold and eliminated with some non-transferable votes
	 SoreLoser: 			    does not even reach the mimimum threshold of votes.
*/
enum Event {SurplusWinner,
            WinnerNonTransferable,
            Winner,
            AboveQuotaWinner,
            QuotaWinnerNonTransferable,
            QuotaWinner,
            CompromiseWinner,
	           TiedWinner,
            TiedLoser,
            Loser,
            TiedEarlyLoser,
            EarlyLoser,
            TiedSoreLoser,
            SoreLoser,
	           EarlyLoserNonTransferable,
            SoreLoserNonTransferable}

enum Method {Plurality, STV}

-- An individual person standing for election
sig Candidate {
  votes: 			  set Ballot, 	-- First preference ballots assigned to this candidate
	 transfers: 	set Ballot,  -- Second and subsequent preferences received
	 surplus: 		 set Ballot, 	-- Ballots tranferred to another candidate
														             -- after election or elimination
  wasted:		 	 set Ballot,	 -- Surplus ballots non-transferable
														             -- due to exhaustion of preferences
	 outcome: 		 Event,		     -- Path through which the candidate either won or lost
  distributions: set Distribution, -- allocation of surplus votes
} {
     0 < #distributions implies (0 < #surplus and #wasted < #surplus)
     0 < #wasted implies (outcome = WinnerNonTransferable or
                          outcome = QuotaWinnerNonTransferable or
                          outcome = EarlyLoserNonTransferable or
	                         outcome = SoreLoserNonTransferable)
     wasted in surplus
	    no b: Ballot | b in votes & transfers
	    all b: Ballot | b in votes + transfers implies this in b.assignees
	    surplus in votes + transfers
	    Election.method = Plurality implies #surplus = 0 and #transfers = 0
    	0 < #transfers implies Election.method = STV
     ((outcome = Winner and Election.method = STV) or (
       outcome = SurplusWinner or outcome = WinnerNonTransferable)) implies
       Scenario.quota + #surplus = #votes
    	(outcome = Winner or outcome = SurplusWinner or
      outcome = WinnerNonTransferable) implies #transfers = 0
    	(outcome = QuotaWinner or outcome = AboveQuotaWinner or
      outcome = QuotaWinnerNonTransferable) implies surplus in transfers
    	(outcome = QuotaWinner or outcome = AboveQuotaWinner or
      outcome = QuotaWinnerNonTransferable) implies
		    Scenario.quota + #surplus = #votes + #transfers
    	all b: Ballot | b in votes implies this in b.assignees
    	0 < #surplus iff (outcome = SurplusWinner or outcome = AboveQuotaWinner)
    	(outcome = EarlyLoser or outcome = TiedEarlyLoser) iff
		     (this in Scenario.eliminated and not (#votes + #transfers < Scenario.threshold))
    	// All non-sore losers are at or above the threshold
     outcome = TiedLoser implies Scenario.threshold <= #votes + #transfers
     outcome = Loser implies Scenario.threshold <= #votes + #transfers
     outcome = EarlyLoser implies Scenario.threshold <= #votes + #transfers
     outcome = EarlyLoserNonTransferable implies Scenario.threshold <= #votes + #transfers
     outcome = TiedEarlyLoser implies Scenario.threshold <= #votes + #transfers
    	// Plurality outcomes
    	Election.method = Plurality implies
		   (outcome = Loser or outcome = SoreLoser or outcome = Winner or
		    outcome = TiedWinner or outcome = TiedLoser or outcome = TiedSoreLoser)
    	// PR-STV Winner has at least a quota of first preference votes
    	(Election.method = STV and outcome = Winner) implies
       Scenario.quota = #votes
     (outcome = SurplusWinner or outcome = WinnerNonTransferable) implies
       Scenario.quota < #votes
     // Quota Winner has a least a quota of votes after transfers
	    outcome = QuotaWinner implies
	      Scenario.quota = #votes + #transfers
     (outcome = AboveQuotaWinner or outcome = QuotaWinnerNonTransferable)
       implies
	      Scenario.quota < #votes + #transfers
     // Quota Winner does not have a quota of first preference votes
	    (outcome = QuotaWinner or outcome = AboveQuotaWinner or
       outcome = QuotaWinnerNonTransferable) implies
		     not Scenario.quota <= #votes
     // Compromise winners do not have a quota of votes
	    outcome = CompromiseWinner  implies
		     not (Scenario.quota <= #votes + #transfers)
    // STV Tied Winners have less than a quota of votes
	   (Election.method = STV and outcome = TiedWinner) implies
		     not (Scenario.quota <= #votes + #transfers)
    // Sore Losers have less votes than the threshold
	   (outcome = SoreLoser or outcome = SoreLoserNonTransferable) implies
		    #votes + #transfers < Scenario.threshold
    // Tied Sore Losers have less votes than the threshold
	   outcome = TiedSoreLoser implies
		    #votes + #transfers < Scenario.threshold
    // Size of surplus for each STV Winner and Quota Winner
	   (outcome = SurplusWinner or outcome = WinnerNonTransferable)
      implies ((#surplus = #votes - Scenario.quota) and #transfers = 0)
    (outcome = AboveQuotaWinner or outcome = QuotaWinnerNonTransferable)
      implies (#surplus = #votes + #transfers - Scenario.quota)
    // Fair distribution of transfers
    all d: Distribution | all b: Ballot |
      d in distributions and b in d.ballots implies
      (b in surplus and (not b in wasted))
    sum #distributions.ballots = #surplus - #wasted
}

/* Proportional distribution of transfers:
 * The surplus is a representative sample of the available transferable votes,
 * taken from the last set received in the case of an AboveQuotaWinner and from
	* the full set of ballots in the case of a SurplusWinner
 */
sig Distribution {
  receiver: Candidate,
  ballots: set Ballot
}
{
  not receiver.outcome = Winner
  not receiver.outcome = SurplusWinner
  not receiver.outcome = WinnerNonTransferable
  all b: Ballot | b in ballots implies receiver in b.assignees
		receiver in Scenario.winners or receiver in Scenario.losers
}

-- A digital or paper artifact which accurately records the intentions of the voter
sig Ballot {
  assignees: 		set Candidate,  -- Candidates to which this ballot has been assigned
  preferences: 	seq Candidate  -- Ranking of candidates
} {
	 assignees in preferences.elems
  not preferences.hasDups
	 preferences.first in assignees
	 Election.method = Plurality implies #preferences <= 1
  0 <= #preferences
  // First preference
  all c: Candidate | preferences.first = c iff this in c.votes
  // Second and subsequent preferences
  all disj donor,receiver: Candidate |
		  (donor + receiver in assignees and
		  this in receiver.transfers and this in donor.surplus) implies
		  (preferences.idxOf[donor] < preferences.idxOf[receiver] and
		  receiver in preferences.rest.elems)
  // All ballot transfers are associated with the last candidate to receive the transfer
	 all disj c,d: Candidate | this in c.transfers implies c in assignees and
		  (d not in assignees or preferences.idxOf[d] < preferences.idxOf[c])
  // Transfers to next continuing candidate
	 all disj skipped, receiving: Candidate |
		  preferences.idxOf[skipped] < preferences.idxOf[receiving] and
		  receiving in assignees and (not skipped in assignees) implies
		  (skipped in Scenario.eliminated or skipped.outcome = SurplusWinner or
		  skipped.outcome = AboveQuotaWinner)
}

-- An election result
one sig Scenario {
  losers: 				set Candidate,
  winners: 			set Candidate,
	 eliminated: set Candidate, -- Early and Sore Losers under STV rules
	 threshold: 	Int, 					     -- Minimum number of votes for a Loser or Early Loser
	 quota: 				 Int,					      -- Minimum number of votes for a STV Winner or Quota Winner
  fullQuota:		Int					       -- Quota if all constituency seats were vacant
} {
 	all c: Candidate | c in winners + losers
 	#winners = Election.seats
 	no c: Candidate | c in losers & winners
 	0 < #losers
 	all w: Candidate | all l: Candidate | l in losers and w in winners implies
		  (#l.votes + #l.transfers <= #w.votes + #w.transfers)
  Election.method = STV implies threshold = 1 + fullQuota.div[4]
	 eliminated in losers
  // All PR-STV losers have less votes than the quota
	 all c: Candidate | (c in losers and Election.method = STV) implies
       #c.votes + #c.transfers < quota
    // Winners have more votes than all non-tied losers
    all disj c,d: Candidate | c in winners and
       (d.outcome = SoreLoser or d.outcome = EarlyLoser or d.outcome = Loser) implies
	   (#d.votes + #d.transfers) < (#c.votes + #c.transfers)
   // Losers have less votes than all non-tied winners
   all disj c,d: Candidate |
	  (c.outcome = CompromiseWinner or c.outcome = QuotaWinner or c.outcome = Winner
		or c.outcome = SurplusWinner or c.outcome = AboveQuotaWinner) and
	  d in losers implies
	  #d.votes + #d.transfers < #c.votes + #c.transfers
   // Lowest candidate is eliminated first
	all disj c,d: Candidate | c in eliminated and d not in eliminated implies
		#c.votes + #c.transfers <= #d.votes + #d.transfers
    // A non-sore plurality loser must have received at least five percent of the total vote
	Election.method = Plurality implies threshold = 1 + BallotBox.size.div[20]
    // Winning outcomes
	all c: Candidate | c in winners iff
		(c.outcome = Winner or c.outcome = QuotaWinner or
		c.outcome = CompromiseWinner or
		c.outcome = TiedWinner or c.outcome = SurplusWinner or
		c.outcome = AboveQuotaWinner or
  c.outcome = WinnerNonTransferable or
  c.outcome = QuotaWinnerNonTransferable)
    // Losing outcomes
	all c: Candidate | c in losers iff
		(c.outcome = Loser or c.outcome = EarlyLoser or c.outcome = SoreLoser or
		c.outcome = TiedLoser or c.outcome = TiedEarlyLoser or c.outcome = TiedSoreLoser)
    // STV election quotas
    Election.method = STV implies quota = 1 + BallotBox.size.div[Election.seats+1] and
    	fullQuota = 1 + BallotBox.size.div[Election.constituencySeats + 1]
    Election.method = Plurality implies quota = 1 and fullQuota = 1
 // All ties involve equality between at least one winner and at least one loser
    all w: Candidate | some l: Candidate | w.outcome = TiedWinner and
	 	(l.outcome = TiedLoser or l.outcome = TiedSoreLoser or l.outcome = TiedEarlyLoser) implies
		(#l.votes + #l.transfers = #w.votes + #w.transfers)
  all s: Candidate | some w: Candidate | w.outcome = TiedWinner and
       (s.outcome = SoreLoser or s.outcome = TiedLoser or s.outcome = TiedEarlyLoser) implies
       (#s.votes = #w.votes) or (#s.votes + #s.transfers = #w.votes + #w.transfers)
   // When there is a tied sore loser then there are no non-sore losers
   no disj a,b: Candidate | a.outcome = TiedSoreLoser and
        (b.outcome = TiedLoser or b.outcome = TiedEarlyLoser or
         b.outcome=Loser or b.outcome=EarlyLoser)
    // For each Tied Winner there is a Tied Loser
	all w: Candidate | some l: Candidate | w.outcome = TiedWinner implies
		(l.outcome = TiedLoser or l.outcome = TiedSoreLoser or l.outcome = TiedEarlyLoser)
    // Tied Winners and Tied Losers have an equal number of votes
	all disj l,w: Candidate |
    ((l.outcome = TiedLoser or l.outcome = TiedSoreLoser or l.outcome = TiedEarlyLoser) and
    w.outcome = TiedWinner) implies #w.votes + #w.transfers = #l.votes + #l.transfers
    // Compromise winner must have more votes than any tied winners
	all disj c,t: Candidate | (c.outcome = CompromiseWinner and t.outcome = TiedWinner)
		implies
		#t.votes + #t.transfers < #c.votes + #c.transfers
    // Winners have more votes than non-tied losers
	all w,l: Candidate | w.outcome = Winner and
      (l.outcome = Loser or l.outcome = EarlyLoser or l.outcome = SoreLoser) implies
     ((#l.votes < #w.votes) or (#l.votes + #l.transfers < #w.votes + #w.transfers))
    // For each Tied Loser there is at least one Tied Winner
   all c: Candidate | some w: Candidate |
   (c.outcome = TiedLoser or c.outcome = TiedSoreLoser or c.outcome = TiedEarlyLoser)
		implies w.outcome = TiedWinner
}

-- The Ballot Box
one sig BallotBox {
  spoiltBallots:		set Ballot,		-- empty ballots excluded from count
  nonTransferables: 	set Ballot,		-- surplus ballots for which preferences are exhausted
  size:					Int 			-- number of unspolit ballots
}
{
    0 <= size
    	size = #Ballot - #spoiltBallots
	all b: Ballot | b in spoiltBallots iff #b.preferences = 0
    	// All non-transferable ballots belong to an undistributed surplus or eliminated candidate
    	all b: Ballot | some c: Candidate | b in nonTransferables implies b in c.wasted
	all b: Ballot | no c: Candidate | b in nonTransferables and b in c.transfers
}

-- An Electoral Constituency
one sig Election {
  seats: 				        Int,		 -- number of seats to be filled in this election
  constituencySeats:	Int,		 -- full number of seats in this constituency
  method: 				       Method	-- type of election; PR-STV or plurality
}
{
 	0 < seats and seats <= constituencySeats
 	seats < #Candidate
}

-- Version Control for changes to model
one sig Version {
   year, month, day: Int
} {
  year = 11
  month = 02
  day = 25
}

-- (c) 2010-2011, Dermot Cochran, IT University of Copenhagen
-- http://www.kindsoftware.com/about/people/dc
-- http://www.itu.dk/people/dero

module Voting

open util/integer

-- Note that all axioms should be expressed as facts appended to signatures
-- Standalone facts will be ignored by the API, but not by the analyser

/*
	There are 8 winner-outcomes and 8 loser-outcomes:

  WinnerNonTransferable:
                    elected on first round with at least one non-transferable surplus vote (STV)
	 SurplusWinner:		  elected on first round with at least one surplus vote (STV),
	 Winner: 				      elected in the first round of counting either by quota or plurality,
  AboveQuotaWinner: elected with surplus votes after receipt of transfers (STV),
  QuotaWinnerNonTransferable:
				                elected with at least one non-transferable surplus vote,
  QuotaWinner: 		   elected with quota after transfers from another candidate (STV only),
	 CompromiseWinner: elected on the last round of counting without quota (STV only),
	 TiedWinner:			    elected by tie breaker,
	 TiedLoser:			     loses only by tie breaker but reaches the threshold,
	 Loser:			 		      defeated on last round but reaches the minimum threshold of votes,
  TiedEarlyLoser:	  reaches threshold but eliminated by tie breaker (STV only),
  EarlyLoserNonTransferable:
                    reaches threshold bit is eliminated with some non-transferable votes,
	 EarlyLoser:		     reaches threshold but is eliminated before last round (STV only),
	 TiedSoreLoser:		  loses only by tie breaker but does not reach threshold,
  SoreLoserNonTransferable:
																				below threshold and eliminated with some non-transferable votes
	 SoreLoser: 			    does not even reach the mimimum threshold of votes.
*/
enum Event {SurplusWinner,
            WinnerNonTransferable,
            Winner,
            AboveQuotaWinner,
            QuotaWinnerNonTransferable,
            QuotaWinner,
            CompromiseWinner,
	           TiedWinner,
            TiedLoser,
            Loser,
            TiedEarlyLoser,
            EarlyLoser,
            TiedSoreLoser,
            SoreLoser,
	           EarlyLoserNonTransferable,
            SoreLoserNonTransferable}

enum Method {Plurality, STV}

-- An individual person standing for election
sig Candidate {
  votes: 			  set Ballot, 	-- First preference ballots assigned to this candidate
	 transfers: 	set Ballot,  -- Second and subsequent preferences received
	 surplus: 		 set Ballot, 	-- Ballots tranferred to another candidate
														             -- after election or elimination
  wasted:		 	 set Ballot,	 -- Surplus ballots non-transferable
														             -- due to exhaustion of preferences
	 outcome: 		 Event,		     -- Path through which the candidate either won or lost
  distributions: set Distribution, -- allocation of surplus votes
} {
     0 < #distributions implies (0 < #surplus and #wasted < #surplus)
     0 < #wasted implies (outcome = WinnerNonTransferable or
                          outcome = QuotaWinnerNonTransferable or
                          outcome = EarlyLoserNonTransferable or
	                         outcome = SoreLoserNonTransferable)
     wasted in surplus
	    no b: Ballot | b in votes & transfers
	    all b: Ballot | b in votes + transfers implies this in b.assignees
	    surplus in votes + transfers
	    Election.method = Plurality implies #surplus = 0 and #transfers = 0
    	0 < #transfers implies Election.method = STV
     ((outcome = Winner and Election.method = STV) or (
       outcome = SurplusWinner or outcome = WinnerNonTransferable)) implies
       Scenario.quota + #surplus = #votes
    	(outcome = Winner or outcome = SurplusWinner or
      outcome = WinnerNonTransferable) implies #transfers = 0
    	(outcome = QuotaWinner or outcome = AboveQuotaWinner or
      outcome = QuotaWinnerNonTransferable) implies surplus in transfers
    	(outcome = QuotaWinner or outcome = AboveQuotaWinner or
      outcome = QuotaWinnerNonTransferable) implies
		    Scenario.quota + #surplus = #votes + #transfers
    	all b: Ballot | b in votes implies this in b.assignees
    	0 < #surplus iff (outcome = SurplusWinner or outcome = AboveQuotaWinner)
    	(outcome = EarlyLoser or outcome = TiedEarlyLoser) iff
		     (this in Scenario.eliminated and not (#votes + #transfers < Scenario.threshold))
    	// All non-sore losers are at or above the threshold
     outcome = TiedLoser implies Scenario.threshold <= #votes + #transfers
     outcome = Loser implies Scenario.threshold <= #votes + #transfers
     outcome = EarlyLoser implies Scenario.threshold <= #votes + #transfers
     outcome = EarlyLoserNonTransferable implies Scenario.threshold <= #votes + #transfers
     outcome = TiedEarlyLoser implies Scenario.threshold <= #votes + #transfers
    	// Plurality outcomes
    	Election.method = Plurality implies
		   (outcome = Loser or outcome = SoreLoser or outcome = Winner or
		    outcome = TiedWinner or outcome = TiedLoser or outcome = TiedSoreLoser)
    	// PR-STV Winner has at least a quota of first preference votes
    	(Election.method = STV and outcome = Winner) implies
       Scenario.quota = #votes
     (outcome = SurplusWinner or outcome = WinnerNonTransferable) implies
       Scenario.quota < #votes
     // Quota Winner has a least a quota of votes after transfers
	    outcome = QuotaWinner implies
	      Scenario.quota = #votes + #transfers
     (outcome = AboveQuotaWinner or outcome = QuotaWinnerNonTransferable) implies
	      Scenario.quota < #votes + #transfers
     // Quota Winner does not have a quota of first preference votes
	    (outcome = QuotaWinner or outcome = AboveQuotaWinner or
       outcome = QuotaWinnerNonTransferable) implies
		     not Scenario.quota <= #votes
     // Compromise winners do not have a quota of votes
	    outcome = CompromiseWinner  implies
		     not (Scenario.quota <= #votes + #transfers)
    // STV Tied Winners have less than a quota of votes
	   (Election.method = STV and outcome = TiedWinner) implies
		     not (Scenario.quota <= #votes + #transfers)
    // Sore Losers have less votes than the threshold
	   (outcome = SoreLoser or outcome = SoreLoserNonTransferable) implies
		    #votes + #transfers < Scenario.threshold
    // Tied Sore Losers have less votes than the threshold
	   outcome = TiedSoreLoser implies
		    #votes + #transfers < Scenario.threshold
    // Size of surplus for each STV Winner and Quota Winner
	   (outcome = AboveQuotaWinner or outcome = SurplusWinner or
      outcome = WinnerNonTransferable or outcome = QuotaWinnerNonTransferable)
      implies (#surplus = #votes + #transfers - Scenario.quota)
    // Fair distribution of transfers
    all d: Distribution | all b: Ballot | d in distributions and b in d.ballots implies
      (b in surplus and (not b in wasted))
    sum #distributions.ballots = #surplus - #wasted
				all d: Distribution | not this = d.receiver
}

/* Proportional distribution of transfers:
 * The surplus is a representative sample of the available transferable votes,
 * taken from the last set received in the case of an AboveQuotaWinner and from
	* the full set of ballots in the case of a SurplusWinner
 */
sig Distribution {
  receiver: Candidate,
  ballots: set Ballot
}
{
  not receiver.outcome = Winner
  not receiver.outcome = SurplusWinner
  not receiver.outcome = WinnerNonTransferable
  all b: Ballot | b in ballots implies receiver in b.assignees
		receiver in Scenario.winners or receiver in Scenario.losers
}

-- A digital or paper artifact which accurately records the intentions of the voter
sig Ballot {
  assignees: 		set Candidate,  -- Candidates to which this ballot has been assigned
  preferences: 	seq Candidate  -- Ranking of candidates
} {
	 assignees in preferences.elems
  not preferences.hasDups
	 preferences.first in assignees
	 Election.method = Plurality implies #preferences <= 1
  0 <= #preferences
  // First preference
  all c: Candidate | preferences.first = c iff this in c.votes
  // Second and subsequent preferences
  all disj donor,receiver: Candidate |
		  (donor + receiver in assignees and
		  this in receiver.transfers and this in donor.surplus) implies
		  (preferences.idxOf[donor] < preferences.idxOf[receiver] and
		  receiver in preferences.rest.elems)
  // All ballot transfers are associated with the last candidate to receive the transfer
	 all disj c,d: Candidate | this in c.transfers implies c in assignees and
		  (d not in assignees or preferences.idxOf[d] < preferences.idxOf[c])
  // Transfers to next continuing candidate
	 all disj skipped, receiving: Candidate |
		  preferences.idxOf[skipped] < preferences.idxOf[receiving] and
		  receiving in assignees and (not skipped in assignees) implies
		  (skipped in Scenario.eliminated or skipped.outcome = SurplusWinner or
		  skipped.outcome = AboveQuotaWinner)
}

-- An election result
one sig Scenario {
  losers: 				set Candidate,
  winners: 			set Candidate,
	 eliminated: set Candidate, -- Early and Sore Losers under STV rules
	 threshold: 	Int, 					     -- Minimum number of votes for a Loser or Early Loser
	 quota: 				 Int,					      -- Minimum number of votes for a STV Winner or Quota Winner
  fullQuota:		Int					       -- Quota if all constituency seats were vacant
} {
 	all c: Candidate | c in winners + losers
 	#winners = Election.seats
 	no c: Candidate | c in losers & winners
 	0 < #losers
 	all w: Candidate | all l: Candidate | l in losers and w in winners implies
		  (#l.votes + #l.transfers <= #w.votes + #w.transfers)
  Election.method = STV implies threshold = 1 + fullQuota.div[4]
	 eliminated in losers
  // All PR-STV losers have less votes than the quota
	 all c: Candidate | (c in losers and Election.method = STV) implies
       #c.votes + #c.transfers < quota
    // Winners have more votes than all non-tied losers
    all disj c,d: Candidate | c in winners and
       (d.outcome = SoreLoser or d.outcome = EarlyLoser or d.outcome = Loser) implies
	   (#d.votes + #d.transfers) < (#c.votes + #c.transfers)
   // Losers have less votes than all non-tied winners
   all disj c,d: Candidate |
	  (c.outcome = CompromiseWinner or c.outcome = QuotaWinner or c.outcome = Winner
		or c.outcome = SurplusWinner or c.outcome = AboveQuotaWinner) and
	  d in losers implies
	  #d.votes + #d.transfers < #c.votes + #c.transfers
   // Lowest candidate is eliminated first
	all disj c,d: Candidate | c in eliminated and d not in eliminated implies
		#c.votes + #c.transfers <= #d.votes + #d.transfers
    // A non-sore plurality loser must have received at least five percent of the total vote
	Election.method = Plurality implies threshold = 1 + BallotBox.size.div[20]
    // Winning outcomes
	all c: Candidate | c in winners iff
		(c.outcome = Winner or c.outcome = QuotaWinner or
		c.outcome = CompromiseWinner or
		c.outcome = TiedWinner or c.outcome = SurplusWinner or
		c.outcome = AboveQuotaWinner or
  c.outcome = WinnerNonTransferable or
  c.outcome = QuotaWinnerNonTransferable)
    // Losing outcomes
	all c: Candidate | c in losers iff
		(c.outcome = Loser or c.outcome = EarlyLoser or c.outcome = SoreLoser or
		c.outcome = TiedLoser or c.outcome = TiedEarlyLoser or c.outcome = TiedSoreLoser)
    // STV election quotas
    Election.method = STV implies quota = 1 + BallotBox.size.div[Election.seats+1] and
    	fullQuota = 1 + BallotBox.size.div[Election.constituencySeats + 1]
    Election.method = Plurality implies quota = 1 and fullQuota = 1
 // All ties involve equality between at least one winner and at least one loser
    all w: Candidate | some l: Candidate | w.outcome = TiedWinner and
	 	(l.outcome = TiedLoser or l.outcome = TiedSoreLoser or l.outcome = TiedEarlyLoser) implies
		(#l.votes + #l.transfers = #w.votes + #w.transfers)
  all s: Candidate | some w: Candidate | w.outcome = TiedWinner and
       (s.outcome = SoreLoser or s.outcome = TiedLoser or s.outcome = TiedEarlyLoser) implies
       (#s.votes = #w.votes) or (#s.votes + #s.transfers = #w.votes + #w.transfers)
   // When there is a tied sore loser then there are no non-sore losers
   no disj a,b: Candidate | a.outcome = TiedSoreLoser and
        (b.outcome = TiedLoser or b.outcome = TiedEarlyLoser or
         b.outcome=Loser or b.outcome=EarlyLoser)
    // For each Tied Winner there is a Tied Loser
	all w: Candidate | some l: Candidate | w.outcome = TiedWinner implies
		(l.outcome = TiedLoser or l.outcome = TiedSoreLoser or l.outcome = TiedEarlyLoser)
    // Tied Winners and Tied Losers have an equal number of votes
	all disj l,w: Candidate |
    ((l.outcome = TiedLoser or l.outcome = TiedSoreLoser or l.outcome = TiedEarlyLoser) and
    w.outcome = TiedWinner) implies #w.votes + #w.transfers = #l.votes + #l.transfers
    // Compromise winner must have more votes than any tied winners
	all disj c,t: Candidate | (c.outcome = CompromiseWinner and t.outcome = TiedWinner)
		implies
		#t.votes + #t.transfers < #c.votes + #c.transfers
    // Winners have more votes than non-tied losers
	all w,l: Candidate | w.outcome = Winner and
      (l.outcome = Loser or l.outcome = EarlyLoser or l.outcome = SoreLoser) implies
     ((#l.votes < #w.votes) or (#l.votes + #l.transfers < #w.votes + #w.transfers))
    // For each Tied Loser there is at least one Tied Winner
   all c: Candidate | some w: Candidate |
   (c.outcome = TiedLoser or c.outcome = TiedSoreLoser or c.outcome = TiedEarlyLoser)
		implies w.outcome = TiedWinner
}

-- The Ballot Box
one sig BallotBox {
  spoiltBallots:		set Ballot,		-- empty ballots excluded from count
  nonTransferables: 	set Ballot,		-- surplus ballots for which preferences are exhausted
  size:					Int 			-- number of unspolit ballots
}
{
    	0 <= size
    	size = #Ballot - #spoiltBallots
	all b: Ballot | b in spoiltBallots iff #b.preferences = 0
    	// All non-transferable ballots belong to an undistributed surplus or eliminated candidate
    	all b: Ballot | some c: Candidate | b in nonTransferables implies b in c.wasted
	all b: Ballot | no c: Candidate | b in nonTransferables and b in c.transfers
}

-- An Electoral Constituency
one sig Election {
  seats: 				Int,		-- number of seats to be filled in this election
  constituencySeats:	Int,		-- full number of seats in this constituency
  method: 				Method	-- type of election; PR-STV or plurality
}
{
 	0 < seats and seats <= constituencySeats
 	seats < #Candidate
}

-- Version Control for changes to model
one sig Version {
   year, month, day: Int
} {
  year = 11
  month = 02
  day = 25
}