minor

minor

open ../archs/exec_C[SE] as SW
open ../archs/exec_arm7[HE] as HW

/*
A C11-to-Arm7 mapping.
*/

module c11_arm7[SE,HE]

pred apply_map[X:SW/Exec_C, X':HW/Exec_Arm7, map:SE->HE] {

  // two SW events cannot be compiled to a single HW event
  map in X.EV lone -> X'.EV

  // HW reads/writes cannot be invented by the compiler
  all e : X'.(R+W) | one e.~map

  // SW reads/writes cannot be discarded by the compiler
  all e : X.(R+W) | some e.map

  // a non-atomic or relaxed read compiles to a single read
  all e : X.((R - W) - ACQ) {
    one e.map
    e.map in X'.R
  }

  // an acquire read compiles to a read followed by an isb, with
  // control dependencies inserted between the read and every
  // event that is sequenced after it
  all e : X.((R - W) & ACQ - SC) | let e1 = e.map {
    one e1
    e1 in X'.R
    e1 <: (X'.sb) in (X'.cd) & (isb[none,X'])
  }

  // an SC read compiles to a read followed by a dmb
  all e : X.((R - W) & SC) | let e1 = e.map {
    one e1
    e1 in X'.R
    e1 <: (X'.sb) in (dmb[none,X'])
  }

  // a non-atomic or relaxed write compiles to a single write
  all e : X.((W - R) - REL) {
    one e.map
    e.map in X'.W
  }

  // a release write compiles to a dmb followed by a write
  all e : X.((W - R) & REL - SC) | let e1 = e.map {
    one e1
    e1 in X'.W
    (X'.sb) :> e1 in (dmb[none,X'])
  }

  // an SC write compiles to a dmb followed by a write followed by a dmb
  all e : X.((W - R) & SC) | let e1 = e.map {
    one e1
    e1 in X'.W
    e1 <: (X'.sb) in (dmb[none,X'])
    (X'.sb) :> e1 in (dmb[none,X'])
  }

  // a relaxed RMW compiles to a read followed by a write, with
  // control dependencies inserted between the read and every
  // event that is sequenced after it
  all e : X.((R & W) - (ACQ + REL)) | some disj e1,e2 : X'.EV {
    e.map = e1+e2
    e1 in X'.R
    e2 in X'.W
    (e1 -> e2) in X'.atom & imm[X'.sb]
    e1 <: (X'.sb) in (X'.cd)
  }

  // an acquire RMW compiles to a read followed by a write,
  // followed by an isb, with control dependencies inserted
  // between the read and every event that is sequenced after it
  all e : X.((R & W & ACQ) - (REL + SC)) | some disj e1,e2 : X'.EV {
    e.map = e1+e2
    e1 in X'.R
    e2 in X'.W
    (e1 -> e2) in X'.atom & imm[X'.sb]
    e1 <: (X'.sb) in (X'.cd)
    e2 <: (X'.sb) in (isb[none,X'])
  }

  // a release RMW compiles to a dmb, followed by a read, followed by
  // a write, with control dependencies inserted between the read and
  // every event that is sequenced after it
  all e : X.((R & W & REL) - (ACQ + SC)) | some disj e1,e2 : X'.EV {
    e.map = e1+e2
    e1 in X'.R
    e2 in X'.W
    (e1 -> e2) in X'.atom & imm[X'.sb]
    (X'.sb) :> e1 in (dmb[none,X'])
    e1 <: (X'.sb) in (X'.cd)
  }

  // an acquire/release RMW compiles to a dmb, followed by a read,
  // followed by a write, followed by an isb, with control dependencies
  // inserted between the read and every event that is sequenced after
  // it
  all e : X.((R & W & REL & ACQ) - SC) | some disj e1,e2 : X'.EV {
    e.map = e1+e2
    e1 in X'.R
    e2 in X'.W
    (e1 -> e2) in X'.atom & imm[X'.sb]
    (X'.sb) :> e1 in (dmb[none,X'])
    e1 <: (X'.sb) in (X'.cd)
    e2 <: (X'.sb) in (isb[none,X'])
  }

  // an SC RMW compiles to a dmb, followed by a read, followed by
  // a write, followed by a dmb, with control dependencies inserted
  // between the read and every event that is sequenced after it
  all e : X.(R & W & SC) | some disj e1,e2 : X'.EV {
    e.map = e1+e2
    e1 in X'.R
    e2 in X'.W
    (e1 -> e2) in X'.atom & imm[X'.sb]
    (X'.sb) :> e1 in (dmb[none,X'])
    e1 <: (X'.sb) in (X'.cd)
    e2 <: (X'.sb) in (dmb[none,X'])
  }

  // release or acquire fences compile to dmbs
  all e : X.(F & (ACQ + REL) - SC) {
    (X.sb) . (stor[e]) . (X.sb) = map . (dmb[none,X']) . ~map
  }

  // SC fences compile to dmbs
  all e : X.(F & SC) {
    (X.sb) . (stor[e]) . (X.sb) = map . (dmb[none,X']) . ~map
  }

  // sb edges are preserved (but more may be introduced)
  X.sb in map . (X'.sb) . ~map

  // the mapping preserves rf
  X.rf = map . (X'.rf) . ~map

  // the mapping preserves co
  X.co = map . (X'.co) . ~map

  // the mapping preserves address dependencies
  X.ad = map . (X'.ad) . ~map

  // the mapping preserves data dependencies
  X.dd = map . (X'.dd) . ~map

  // the mapping preserves locations
  (X.sloc) = map . (X'.sloc) . ~map

  // ctrl dependencies are preserved (but more may be introduced)
  X.cd in map . (X'.cd) . ~map

  // the mapping preserves threads
  (X'.sthd) = ~map . (X.sthd) . map

}

open ../archs/exec_C[SE] as SW
open ../archs/exec_arm7[HE] as HW

/*
A C11-to-Arm7 mapping.
*/

module c11_arm7[SE,HE]

pred apply_map[X:SW/Exec_C, X':HW/Exec_Arm7, map:SE->HE] {

  // two SW events cannot be compiled to a single HW event
  map in X.EV lone -> X'.EV

  // HW reads/writes cannot be invented by the compiler
  all e : X'.(R+W) | one e.~map

  // SW reads/writes cannot be discarded by the compiler
  all e : X.(R+W) | some e.map

  // a non-atomic or relaxed read compiles to a single read
  all e : X.((R - W) - ACQ) {
    one e.map
    e.map in X'.R
  }

  // an acquire read compiles to a read followed by an isb, with
  // control dependencies inserted between the read and every
  // event that is sequenced after it
  all e : X.((R - W) & ACQ - SC) | let e1 = e.map {
    one e1
    e1 in X'.R
    e1 <: (X'.sb) in (X'.cd) & (isb[none,X'])
  }

  // an SC read compiles to a read followed by a dmb
  all e : X.((R - W) & SC) | let e1 = e.map {
    one e1
    e1 in X'.R
    e1 <: (X'.sb) in (dmb[none,X'])
  }

  // a non-atomic or relaxed write compiles to a single write
  all e : X.((W - R) - REL) {
    one e.map
    e.map in X'.W
  }

  // a release write compiles to a dmb followed by a write
  all e : X.((W - R) & REL - SC) | let e1 = e.map {
    one e1
    e1 in X'.W
    (X'.sb) :> e1 in (dmb[none,X'])
  }

  // an SC write compiles to a dmb followed by a write followed by a dmb
  all e : X.((W - R) & SC) | let e1 = e.map {
    one e1
    e1 in X'.W
    e1 <: (X'.sb) in (dmb[none,X'])
    (X'.sb) :> e1 in (dmb[none,X'])
  }

  // a relaxed RMW compiles to a read followed by a write, with
  // control dependencies inserted between the read and every
  // event that is sequenced after it
  all e : X.((R & W) - (ACQ + REL)) | some disj e1,e2 : X'.EV {
    e.map = e1+e2
    e1 in X'.R
    e2 in X'.W
    (e1 -> e2) in X'.atom & imm[X'.sb]
    e1 <: (X'.sb) in (X'.cd)
  }

  // an acquire RMW compiles to a read followed by a write,
  // followed by an isb, with control dependencies inserted
  // between the read and every event that is sequenced after it
  all e : X.((R & W & ACQ) - (REL + SC)) | some disj e1,e2 : X'.EV {
    e.map = e1+e2
    e1 in X'.R
    e2 in X'.W
    (e1 -> e2) in X'.atom & imm[X'.sb]
    e1 <: (X'.sb) in (X'.cd)
    e2 <: (X'.sb) in (isb[none,X'])
  }

  // a release RMW compiles to a dmb, followed by a read, followed by
  // a write, with control dependencies inserted between the read and
  // every event that is sequenced after it
  all e : X.((R & W & REL) - (ACQ + SC)) | some disj e1,e2 : X'.EV {
    e.map = e1+e2
    e1 in X'.R
    e2 in X'.W
    (e1 -> e2) in X'.atom & imm[X'.sb]
    (X'.sb) :> e1 in (dmb[none,X'])
    e1 <: (X'.sb) in (X'.cd)
  }

  // an acquire/release RMW compiles to a dmb, followed by a read,
  // followed by a write, followed by an isb, with control dependencies
  // inserted between the read and every event that is sequenced after
  // it
  all e : X.((R & W & REL & ACQ) - SC) | some disj e1,e2 : X'.EV {
    e.map = e1+e2
    e1 in X'.R
    e2 in X'.W
    (e1 -> e2) in X'.atom & imm[X'.sb]
    (X'.sb) :> e1 in (dmb[none,X'])
    e1 <: (X'.sb) in (X'.cd)
    e2 <: (X'.sb) in (isb[none,X'])
  }

  // an SC RMW compiles to a dmb, followed by a read, followed by
  // a write, followed by a dmb, with control dependencies inserted
  // between the read and every event that is sequenced after it
  all e : X.(R & W & SC) | some disj e1,e2 : X'.EV {
    e.map = e1+e2
    e1 in X'.R
    e2 in X'.W
    (e1 -> e2) in X'.atom & imm[X'.sb]
    (X'.sb) :> e1 in (dmb[none,X'])
    e1 <: (X'.sb) in (X'.cd)
    e2 <: (X'.sb) in (dmb[none,X'])
  }

  // release or acquire fences compile to dmbs
  all e : X.(F & (ACQ + REL) - SC) {
    (X.sb) . (stor[e]) . (X.sb) = map . (dmb[none,X']) . ~map
  }

  // SC fences compile to dmbs
  all e : X.(F & SC) {
    (X.sb) . (stor[e]) . (X.sb) = map . (dmb[none,X']) . ~map
  }

  // sb edges are preserved (but more may be introduced)
  X.sb in map . (X'.sb) . ~map

  // the mapping preserves rf
  X.rf = map . (X'.rf) . ~map

  // the mapping preserves co
  X.co = map . (X'.co) . ~map

  // the mapping preserves address dependencies
  X.ad = map . (X'.ad) . ~map

  // the mapping preserves data dependencies
  dd = map . (X'.dd) . ~map

  // the mapping preserves locations
  (X.sloc) = map . (X'.sloc) . ~map

  // ctrl dependencies are preserved (but more may be introduced)
  X.cd in map . (X'.cd) . ~map

  // the mapping preserves threads
  (X'.sthd) = ~map . (X.sthd) . map

}


Added more lemmas

Added more lemmas

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

module Lemmas

open Voting

-- Voting 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 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 pluralityNoTransfers {
  all c: Candidate | Election.method = Plurality implies 0 = #c.transfers
}
check pluralityNoTransfers for 13 but 7 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

-- Advanced Lemmas
// Equal losers are tied
assert equalityofTiedWinnersAndLosers {
	all disj w,l: Candidate | w in Scenario.winners and l in Scenario.losers and
		#w.votes + #w.transfers = #l.votes + #l.transfers implies
			w.outcome = TiedWinner and
			(l.outcome = TiedLoser or l.outcome = TiedEarlyLoser or l.outcome = TiedSoreLoser)
}
check equalityofTiedWinnersAndLosers for 13 but 7 int

// No lost votes during counting
assert accounting {
	all b: Ballot | some c: Candidate | 0 < #b.preferences implies
      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

// Quota winner needs transfers
assert quotaWinnerNeedsTransfers {
  all c: Candidate | c.outcome = QuotaWinner implies 0 < #c.transfers
}
check quotaWinnerNeedsTransfers for 7 int

// Sore losers below threshold
assert soreLoserBelowThreshold {
  all c: Candidate | c.outcome = SoreLoser implies not (Scenario.threshold <= #c.votes + #c.transfers)
}
check soreLoserBelowThreshold for 10 but 6 int

// Possible outcomes when under the threshold
assert underThresholdOutcomes {
  all c: Candidate | (#c.votes + #c.transfers < Scenario.threshold) implies
     (c.outcome = SoreLoser or c.outcome = TiedSoreLoser or c.outcome = TiedWinner or
     c.outcome = CompromiseWinner or (Election.method = Plurality and c.outcome = Winner))
}
check underThresholdOutcomes for 10 but 6 int

// Tied Winners have equality of votes and transfers
assert tiedWinnerEquality {
  all a,b: Candidate | (a.outcome = TiedWinner and b.outcome = TiedWinner) implies
	#a.votes + #a.transfers = #b.votes + #b.transfers
}
check tiedWinnerEquality for 10 but 6 int

// Non-negative threshold and quota
assert nonNegativeThresholdAndQuota {
	0 <= Scenario.threshold and 0 <= Scenario.quota
}
check nonNegativeThresholdAndQuota for 6 but 6 int

// STV threshold below quota
assert thresholdBelowQuota {
   Election.method = STV and 0 < #Ballot implies Scenario.threshold <= Scenario.quota
}
check thresholdBelowQuota for 13 but 7 int

// Plurality sore loser
assert pluralitySoreLoser {
	all c: Candidate | (c.outcome = SoreLoser and Election.method = Plurality) implies
       #c.votes < Scenario.threshold
}
check pluralitySoreLoser for 13 but 7 int

// Plurality winner for a single seat constituency
assert pluralityWinner {
all disj a, b: Candidate | (Election.method = Plurality and Election.seats = 1 and
		a.outcome = Winner) implies #b.votes <= #a.votes
}
check pluralityWinner for 2 but 7 int

// Length of PR-STV ballot does not exceed number of candidates
assert lengthOfBallot {
  all b: Ballot | Election.method = STV implies
    #b.preferences <= #Candidate
}
check lengthOfBallot for 7 int

// Quota for a full election is less than for a by-election
assert  fullQuota {
	Scenario.fullQuota <= Scenario.quota
}
check fullQuota for 7 int

// Spoilt votes are not allocated to any candidate
assert spoiltVoteDiscarded {
  no c : Candidate | no b : Ballot | b in c.votes and b in BallotBox.spoiltBallots
}
check spoiltVoteDiscarded for 7 int

// All transfers have a source either from a winner with surplus or by early elimination
// of a loser
assert transfersHaveSource {
  all b: Ballot | some disj donor, receiver : Candidate | b in receiver.transfers
   		implies b in donor.votes and
   		(donor in Scenario.winners or donor in Scenario.eliminated)
}
check transfersHaveSource for 7 int

// No missing candidates
assert noMissingCandidates {
  #Candidate = #Scenario.winners + #Scenario.losers
  }
check noMissingCandidates for 7 int

-- Sample scenarios
pred TwoCandidatePlurality {
	Election.method = Plurality
	Election.seats = 1
	#Candidate = 2
}
run TwoCandidatePlurality for 10 but 2 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 6 int

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

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

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

pred InstantRunoffVoting {
	Election.method = STV
	Election.seats = 1
	3 < #Candidate
}
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 {
	#Candidate = 3
    Election.method = Plurality
	some disj a,b,c: Candidate | a.outcome = TiedWinner and
		b.outcome = TiedLoser and
		c.outcome = TiedLoser
}
run ThreeWayTie for 10 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.outcome = Loser and b.outcome = Winner and
		c.outcome = Winner
    #Candidate = 3
	Election.method = STV
    0 < #Ballot
}
run ScenarioLWW for 7 but 7 int

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

pred MultipleBallotsUnderSTV {
	Election.method = STV
	some disj a,b,c,d: Ballot | 1 < #a.preferences and 1 < #b.preferences
	and 0 < #c.preferences and 0 < #d.preferences and
        a.preferences.first = b.preferences.last
}
run MultipleBallotsUnderSTV for 10 but 6 int

pred WinnerLoserEarlyLoser {
	some a,b,c,d : Candidate | a.outcome = Winner and b.outcome = Loser and
		c.outcome = EarlyLoser and d.outcome = SoreLoser
	Election.method = STV
}
run WinnerLoserEarlyLoser for 7 but 6 int

pred TiedScenario {
  some disj a,b: Candidate | a.outcome = TiedLoser and b.outcome = TiedWinner
     Election.method = STV
     #Candidate = 2
     #Election.seats = 1
}
run TiedScenario for 7 but 6 int

pred NoTiesAndNoSoresScenarios {
  Election.method = STV
  #Candidate > 3
  #Ballot > 6
  no c: Candidate | c.outcome = TiedLoser or c.outcome = TiedWinner or
    c.outcome = TiedEarlyLoser or c.outcome = TiedSoreLoser or c.outcome = SoreLoser
}
run NoTiesAndNoSoresScenarios for 10 but 6 int

-- Scenario tests
pred SLW {
  some disj c0,c1,d: Candidate | c0.outcome = Loser and c1.outcome = Winner and
  d.outcome = SoreLoser and
  Election.method = Plurality and #Candidate = 3
  Scenario.threshold = 1
}
run SLW for 6 but 6 int

pred SSSLW {
  some disj c0,c1,d,e,f: Candidate | c0.outcome = Loser and c1.outcome = Winner and
  d.outcome = SoreLoser and
  e.outcome = SoreLoser and
  f.outcome = SoreLoser and
  Election.method = Plurality and #Candidate = 5
}
run SSSLW for 6 but 6 int

pred SSSSLW {
  some disj c0,c1,d,e,f,g: Candidate | c0.outcome = Loser and c1.outcome = Winner and
  d.outcome = SoreLoser and
  e.outcome = SoreLoser and
  f.outcome = SoreLoser and
  g.outcome = SoreLoser and
  Election.method = Plurality and #Candidate = 6
}
run SSSSLW for 6 but 6 int

pred LW {
  some disj c0,c1: Candidate | c0.outcome = Loser and c1.outcome = Winner and
  Election.method = Plurality and 0 < #Ballot and #Candidate = 2
}
run LW for 5 but 6 int

pred LLWstv {
  some disj c0,c1,c2: Candidate | c0.outcome = Loser and c1.outcome = Winner and
  c2.outcome = Loser and
  Election.method = STV and #Candidate = 3
}
run LLWstv for 6 but 6 int

pred SW {
  some disj c0,c1: Candidate | c0.outcome = SoreLoser and c1.outcome = Winner and
  Election.method = Plurality and 1 < #Ballot and #Candidate = 2
}
run SW for 2 but 7 int

pred StWt {
  some disj c0,c1: Candidate | c0.outcome = TiedSoreLoser and
  c1.outcome = TiedWinner and
  Election.method = Plurality
}
run StWt for 2 but 7 int

pred LQ {
	some disj a,b: Candidate | a.outcome = Loser and b.outcome = QuotaWinner
    #Candidate = 2
    0 < #Ballot
}
run LQ for 10 but 6 int

pred LQQ {
	some disj a,b,c: Candidate | a.outcome = Loser and b.outcome = QuotaWinner and
       c.outcome = QuotaWinner
    #Candidate = 3
    0 < #Ballot
}
run LQQ for 10 but 6 int

pred LQW {
	some disj a,b,c: Candidate | a.outcome = Loser and b.outcome = QuotaWinner and
		c.outcome = Winner
    #Candidate = 3
    0 < #Ballot
}
run LQW for 10 but 6 int

pred LQQW {
	some disj a,b,c,d: Candidate | a.outcome = Loser and b.outcome = QuotaWinner and
		c.outcome = Winner and d.outcome = QuotaWinner
    #Candidate = 4
    0 < #Ballot
}
run LQQW for 10 but 6 int

pred SLQQW {
	some disj a,b,c,d,e: Candidate | a.outcome = Loser and b.outcome = QuotaWinner and
		c.outcome = Winner and d.outcome = QuotaWinner and e.outcome = SoreLoser
    #Candidate = 5
    0 < #Ballot
}

pred SLTT {
  some disj c1,c3,c8,c9: Candidate |
    c1.outcome = SoreLoser and c3.outcome = Loser and
    c8.outcome = TiedLoser and c9.outcome = TiedWinner and
    Election.method = Plurality and #Candidate = 4
}
run SLTT for 13 but 7 int

pred SLLTT {
  some disj c2,c3,c4,c8,c9: Candidate |
    c2.outcome = SoreLoser and c3.outcome = Loser and
    c4.outcome = Loser and c8.outcome = TiedLoser and c9.outcome = TiedWinner and
    Election.method = Plurality and #Candidate = 5
}
run SLLTT for 13 but 7 int

pred SSLTT {
  some disj c1,c2,c4,c8,c9: Candidate |
    c1.outcome = SoreLoser and c2.outcome = SoreLoser and
    c4.outcome = Loser and c8.outcome = TiedLoser and c9.outcome = TiedWinner and
    Election.method = Plurality and #Candidate = 5
}
run SSLTT for 13 but 7 int

pred SSLLTT {
  some disj c1,c2,c3,c4,c8,c9: Candidate |
    c1.outcome = SoreLoser and c2.outcome = SoreLoser and c3.outcome = Loser and
    c4.outcome = Loser and c8.outcome = TiedLoser and c9.outcome = TiedWinner and
    Election.method = Plurality and #Candidate = 6
}
run SSLLTT for 13 but 7 int

pred SSLLLTTw {
  some disj c0,c1,c3,c4,c5,c7,c8: Candidate | c0.outcome = SoreLoser and
    c1.outcome = SoreLoser and c3.outcome = Loser and
    c4.outcome = Loser and c5.outcome = Loser and
    c7.outcome = TiedLoser and c8.outcome = TiedWinner and
    Election.method = Plurality and #Candidate = 7
}
run SSLLLTTw for 13 but 7 int

pred SSSLLLTTw {
  some disj c0,s2,c1,c3,c4,c5,c7,c8: Candidate | c0.outcome = SoreLoser and
    c1.outcome = SoreLoser and s2.outcome = SoreLoser and c3.outcome = Loser and
    c4.outcome = Loser and c5.outcome = Loser and
    c7.outcome = TiedLoser and c8.outcome = TiedWinner and
    Election.method = Plurality and #Candidate = 8
}
run SSSLLLTTw for 13 but 7 int

pred LLLLTTw {
  some disj c3,c4,c5,c6,c7,c9: Candidate |
    c3.outcome = Loser and
    c4.outcome = Loser and
    c5.outcome = Loser and
    c6.outcome = Loser and
    c7.outcome = TiedLoser and
    c9.outcome = TiedWinner and
    Election.method = Plurality and
    #Candidate = 6
}
run LLLLTTw for 16 but 7 int

pred LLLLLLW {
  some disj c3,c4,c5,c6,c7,c8,c9: Candidate |
    c3.outcome = Loser and
    c4.outcome = Loser and
    c5.outcome = Loser and
    c6.outcome = Loser and
    c7.outcome = Loser and
    c8.outcome = Loser and
    c9.outcome = Winner and
    Election.method = Plurality and
    #Candidate = 7
}
run LLLLLLW for 16 but 7 int

pred LLLtLtWt {
  some disj c5,c6,c7,c8,c9: Candidate |
    c5.outcome = TiedLoser and
    c6.outcome = TiedLoser and
    c7.outcome = Loser and
    c8.outcome = Loser and
    c9.outcome = TiedWinner and
    Election.method = Plurality and
    #Candidate = 5
}
run LLLtLtWt for 16 but 7 int

pred largeSurplus {
  some c: Candidate | 0 < #c.surplus
}
run largeSurplus for 7 int

pred LWW6 {
some disj c0,c1,c2: Candidate | c0.outcome = Loser and c1.outcome = Winner
    and c2.outcome = Winner and Election.method = STV and #Candidate = 3
}
run LWW6 for 16 but 7 int


Incomplete - task : Extend unit tests for complete coverage - clarify that non-sore Losers are always above the threshold

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

-- An individual person standing for election
sig 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 implies this in b.assignees
	surplus in votes + transfers
	Election.method = Plurality implies #surplus = 0 and #transfers = 0
}

-- 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.elems in Election.candidates
	preferences.first in assignees
	Election.method = Plurality implies #preferences = 1
    0 < #preferences
}

-- 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) and (#l.votes <= #w.votes))
	0 <= threshold
	threshold <= quota
    Election.method = STV implies (threshold = 1 + quota.div[4])
	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,
  ballots:			Int -- number of ballots cast
}
{
 	0 < seats
 	seats < #candidates
 	all c: Candidate | c in candidates
    ballots = #Ballot
    Scenario.quota = 1 + ballots.div[seats+1]
}

-- Independent (or Fundamental) Axioms
fact threshold {
   Election.method = Plurality implies Scenario.threshold = Election.ballots.div[20]
}

fact surplus {
  all c: Candidate | (c.outcome = Winner and Election.method = STV) implies
     Scenario.quota + #c.surplus = #c.votes
}

fact winnersWithoutTransfers {
  all c: Candidate | (c.outcome = Winner and Election.method = STV) implies #c.transfers = 0
}

fact surplusFromTransfers {
  all c: Candidate | c.outcome = QuotaWinner implies ((surplus in transfers) and
     ((Scenario.quota + #c.surplus) = (#c.votes + #c.transfers)))
}

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 and c.outcome = Winner) implies
       Scenario.quota <= #c.votes
}

fact transferWinnerWithQuota {
	all c: Candidate | (Election.method = STV and c.outcome = QuotaWinner) implies
	   Scenario.quota <= #c.votes + #c.transfers
}

fact transferWinnerNotFirst {
	all c: Candidate |  (Election.method = STV and c.outcome = QuotaWinner) implies
		not Scenario.quota <= #c.votes
}

fact closeWinner {
	all c: Candidate | (c.outcome = CompromiseWinner or c.outcome = TiedWinner) implies
		not (Scenario.quota <= #c.votes + #c.transfers) or Election.method = Plurality
}

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

fact loser {
	all c: Candidate | (c.outcome = Loser or c.outcome = TiedLoser or c.outcome = TiedSoreLoser)
        implies 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 not #c.votes + #c.transfers < Scenario.threshold)
}

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

-- 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 and 0 < #w.votes + #w.transfers
}

// 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 + #c.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 0 < #w.votes + #w.transfers and
			(l.outcome = TiedLoser or l.outcome = TiedEarlyLoser or l.outcome = TiedSoreLoser)
}

// Highest winner has a quota
fact highestWinners {
   all c: Candidate | Election.method = STV and c.outcome = Winner implies
		Scenario.quota <= #c.votes + #c.transfers
}

// Tied Winners and Tied Losers have an equal number of votes
fact equalTies {
	all disj a,b: Candidate | a.outcome = TiedWinner and b.outcome = TiedLoser implies
		#a.votes = #b.votes and #a.transfers = #b.transfers
}

// Winners have more votes than non-tied losers
fact winnersHaveVotes {
	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))
}

// Losers above threshold
fact losersAboveThreshold {
  all c: Candidate | c.outcome = Loser implies Scenario.threshold < (#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 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

-- Advanced Lemmas
// No lost votes during counting
assert accounting {
	all b: Ballot | some 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

// Quota not more than the number of ballots cast
assert maxQuota {
  Scenario.quota <= #Ballot
}
check maxQuota for 7 int

// Quota winner needs transfers
assert quotaWinnerNeedsTransfers {
  all c: Candidate | c.outcome = QuotaWinner implies 0 < #c.transfers
}
check quotaWinnerNeedsTransfers for 7 int

-- Sample scenarios
pred TwoCandidatePlurality {
	Election.method = Plurality
	Election.seats = 1
	#Election.candidates = 2
}
run TwoCandidatePlurality for 10 but 2 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.outcome = Loser and b.outcome = Winner and
		c.outcome = Winner
    #Election.candidates = 3
	Election.method = STV
    0 < #Ballot
}
run ScenarioLWW for 7 but 7 int

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

pred MultipleBallotsUnderSTV {
	Election.method = STV
	some disj a,b,c,d: Ballot | 1 < #a.preferences and 1 < #b.preferences
	and 0 < #c.preferences and 0 < #d.preferences and
        a.preferences.first = b.preferences.last
}
run MultipleBallotsUnderSTV for 10 but 6 int

pred WinnerLoserEarlyLoser {
	some a,b,c,d : Candidate | a.outcome = Winner and b.outcome = Loser and
		c.outcome = EarlyLoser and d.outcome = SoreLoser
	Election.method = STV
}
run WinnerLoserEarlyLoser for 7 but 6 int

pred TiedScenario {
  some disj a,b: Candidate | a.outcome = TiedLoser and b.outcome = TiedWinner
     Election.method = STV
     #Election.candidates = 2
     #Election.seats = 1
}
run TiedScenario for 7 but 6 int

pred NoTiesAndNoSoresScenarios {
  Election.method = STV
  #Election.candidates > 3
  #Ballot > 6
  no c: Candidate | c.outcome = TiedLoser or c.outcome = TiedWinner or
    c.outcome = TiedEarlyLoser or c.outcome = TiedSoreLoser or c.outcome = SoreLoser
}
run NoTiesAndNoSoresScenarios for 10 but 6 int

-- Scenario tests
pred LW {
  some disj c0,c1: Candidate | c0.outcome = Winner and c1.outcome = Loser and
	Election.method = STV and #Election.candidates = 2 and #Election.seats = 1
}
run LW for 10 but 6 int

pred LQ {
	some disj a,b: Candidate | a.outcome = Loser and b.outcome = QuotaWinner
    #Election.candidates = 2
	Election.method = STV
    0 < #Ballot
}
run LQ for 10 but 6 int

pred LQQ {
	some disj a,b,c: Candidate | a.outcome = Loser and b.outcome = QuotaWinner and
       c.outcome = QuotaWinner
    #Election.candidates = 3
	Election.method = STV
    0 < #Ballot
}
run LQQ for 10 but 6 int

pred LQW {
	some disj a,b,c: Candidate | a.outcome = Loser and b.outcome = QuotaWinner and
		c.outcome = Winner
    #Election.candidates = 3
	Election.method = STV
    0 < #Ballot
}
run LQW for 10 but 6 int

pred LQQW {
	some disj a,b,c,d: Candidate | a.outcome = Loser and b.outcome = QuotaWinner and
		c.outcome = Winner and d.outcome = QuotaWinner
    #Election.candidates = 4
	Election.method = STV
    0 < #Ballot
}
run LQQW for 10 but 6 int

-- Version Control for changes to signatures and axioms, excluding lemmas and predicates
one sig Version {
   year, month, day : Int
} {
  year = 11
  month = 01
  day = 17
  -- Dermot Cochran 2011-01-17
}

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

-- An individual person standing for election
sig 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 implies this in b.assignees
	surplus in votes + transfers
	Election.method = Plurality implies #surplus = 0 and #transfers = 0
}

-- 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.elems in Election.candidates
	preferences.first in assignees
	Election.method = Plurality implies #preferences = 1
    0 < #preferences
}

-- 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) and (#l.votes <= #w.votes))
	0 <= threshold
	threshold <= quota
    Election.method = STV implies (threshold = 1 + quota.div[4])
	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,
  ballots:			Int -- number of ballots cast
}
{
 	0 < seats
 	seats < #candidates
 	all c: Candidate | c in candidates
    ballots = #Ballot
    Scenario.quota = 1 + ballots.div[seats+1]
}

-- Independent (or Fundamental) Axioms
fact threshold {
   Election.method = Plurality implies Scenario.threshold = Election.ballots.div[20]
}

fact surplus {
  all c: Candidate | (c.outcome = Winner and Election.method = STV) implies
     Scenario.quota + #c.surplus = #c.votes
}

fact winnersWithoutTransfers {
  all c: Candidate | (c.outcome = Winner and Election.method = STV) implies #c.transfers = 0
}

fact surplusFromTransfers {
  all c: Candidate | c.outcome = QuotaWinner implies ((surplus in transfers) and
     ((Scenario.quota + #c.surplus) = (#c.votes + #c.transfers)))
}

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 and c.outcome = Winner) implies
       Scenario.quota <= #c.votes
}

fact transferWinnerWithQuota {
	all c: Candidate | (Election.method = STV and c.outcome = QuotaWinner) implies
	   Scenario.quota <= #c.votes + #c.transfers
}

fact transferWinnerNotFirst {
	all c: Candidate |  (Election.method = STV and c.outcome = QuotaWinner) implies
		not Scenario.quota <= #c.votes
}

fact closeWinner {
	all c: Candidate | (c.outcome = CompromiseWinner or c.outcome = TiedWinner) implies
		not (Scenario.quota <= #c.votes + #c.transfers) or Election.method = Plurality
}

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

fact loser {
	all c: Candidate | (c.outcome = Loser or c.outcome = TiedLoser or c.outcome = TiedSoreLoser)
        implies 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 not #c.votes + #c.transfers < Scenario.threshold)
}

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

-- 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 and 0 < #w.votes + #w.transfers
}

// 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 + #c.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 0 < #w.votes + #w.transfers and
			(l.outcome = TiedLoser or l.outcome = TiedEarlyLoser or l.outcome = TiedSoreLoser)
}

// Highest winner has a quota
fact highestWinners {
   all c: Candidate | Election.method = STV and c.outcome = Winner implies
		Scenario.quota <= #c.votes + #c.transfers
}

// Tied Winners and Tied Losers have an equal number of votes
fact equalTies {
	all disj a,b: Candidate | a.outcome = TiedWinner and b.outcome = TiedLoser implies
		#a.votes = #b.votes and #a.transfers = #b.transfers
}

// Winners have more votes than non-tied losers
fact winnersHaveVotes {
	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))
}

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

-- Advanced Lemmas
// No lost votes during counting
assert accounting {
	all b: Ballot | some 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

// Quota not more than the number of ballots cast
assert maxQuota {
  Scenario.quota <= #Ballot
}
check maxQuota for 7 int

// Quota winner needs transfers
assert quotaWinnerNeedsTransfers {
  all c: Candidate | c.outcome = QuotaWinner implies 0 < #c.transfers
}
check quotaWinnerNeedsTransfers for 7 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.outcome = Loser and b.outcome = Winner and
		c.outcome = Winner
    #Election.candidates = 3
	Election.method = STV
    0 < #Ballot
}
run ScenarioLWW for 7 but 7 int

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

pred MultipleBallotsUnderSTV {
	Election.method = STV
	some disj a,b,c,d: Ballot | 1 < #a.preferences and 1 < #b.preferences
	and 0 < #c.preferences and 0 < #d.preferences and
        a.preferences.first = b.preferences.last
}
run MultipleBallotsUnderSTV for 10 but 6 int

pred WinnerLoserEarlyLoser {
	some a,b,c,d : Candidate | a.outcome = Winner and b.outcome = Loser and
		c.outcome = EarlyLoser and d.outcome = SoreLoser
	Election.method = STV
}
run WinnerLoserEarlyLoser for 7 but 6 int

pred TiedScenario {
  some disj a,b: Candidate | a.outcome = TiedLoser and b.outcome = TiedWinner
     Election.method = STV
     #Election.candidates = 2
     #Election.seats = 1
}
run TiedScenario for 7 but 6 int

pred NoTiesAndNoSoresScenarios {
  Election.method = STV
  #Election.candidates > 3
  #Ballot > 6
  no c: Candidate | c.outcome = TiedLoser or c.outcome = TiedWinner or
    c.outcome = TiedEarlyLoser or c.outcome = TiedSoreLoser or c.outcome = SoreLoser
}
run NoTiesAndNoSoresScenarios for 10 but 6 int

-- Unit Tests
pred UnitTest {
  some disj c0,c1: Candidate | c0.outcome = Winner and c1.outcome = Loser and
	Election.method = STV and #Election.candidates = 2 and #Election.seats = 1
}
run UnitTest for 10 but 6 int

-- Difficult scenarios
pred LQ {
	some disj a,b: Candidate | a.outcome = Loser and b.outcome = QuotaWinner
    #Election.candidates = 2
	Election.method = STV
    0 < #Ballot
}
run LQ for 10 but 6 int

pred LQQ {
	some disj a,b,c: Candidate | a.outcome = Loser and b.outcome = QuotaWinner and
       c.outcome = QuotaWinner
    #Election.candidates = 3
	Election.method = STV
    0 < #Ballot
}
run LQQ for 10 but 6 int

pred LQW {
	some disj a,b,c: Candidate | a.outcome = Loser and b.outcome = QuotaWinner and
		c.outcome = Winner
    #Election.candidates = 3
	Election.method = STV
    0 < #Ballot
}
run LQW for 10 but 6 int

pred LQQW {
	some disj a,b,c,d: Candidate | a.outcome = Loser and b.outcome = QuotaWinner and
		c.outcome = Winner and d.outcome = QuotaWinner
    #Election.candidates = 4
	Election.method = STV
    0 < #Ballot
}
run LQQW for 10 but 6 int

-- Version Control for changes to signatures and axioms, excluding lemmas and tests
one sig Version {
   year, month, day : Int
} {
  year = 11
  month = 01
  day = 17
  -- Dermot Cochran 2011-01-17
}


Incomplete - task : Coverage profiling of universal tests

-- (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 election
  wasted:		 	 set Ballot,	 -- Ballots non-transferable due to exhaustion of preferences
	 outcome: 		 Event		      -- Election result for candidate and associated ballots
} {
     // Non-transferable ballots
     0 < #wasted implies (outcome = WinnerNonTransferable or
                          outcome = QuotaWinnerNonTransferable or
                          outcome = EarlyLoserNonTransferable or
	                         outcome = SoreLoserNonTransferable)
     (outcome = WinnerNonTransferable or outcome = QuotaWinnerNonTransferable)
       implies wasted in surplus
     (outcome = EarlyLoserNonTransferable or outcome = SoreLoserNonTransferable)
       implies wasted in votes + transfers
     // Division of ballots into first preferences and transfers
	    no b: Ballot | b in votes & transfers
     // Division of ballots into piles for each candidate
	    all b: Ballot | b in votes + transfers implies this in b.assignees
     // Selection of surplus ballots for re-distribution
	    surplus in votes + transfers
	    Election.method = Plurality implies #surplus = 0 and #transfers = 0
    	0 < #transfers implies Election.method = STV
     // Calculation of surplus for PR-STV election
     ((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
    	0 < #surplus implies (outcome = SurplusWinner or outcome = AboveQuotaWinner or
						outcome = WinnerNonTransferable or outcome = QuotaWinnerNonTransferable)
    	(outcome = EarlyLoser or outcome = TiedEarlyLoser or
      outcome = EarlyLoserNonTransferable) 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)
}

-- 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 or skipped.outcome = WinnerNonTransferable or
    skipped.outcome = QuotaWinnerNonTransferable or skipped.outcome = Winner or
    skipped.outcome = QuotaWinner)
}

-- 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 or
       l.outcome = EarlyLoserNonTransferable or l.outcome = SoreLoserNonTransferable)
       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,		-- ballots for which preferences are exhausted
  size:					        Int 			      -- number of unspolit ballots
}
{
  no b: Ballot | b in spoiltBallots and b in nonTransferables
  size = #Ballot - #spoiltBallots
	 all b: Ballot | b in spoiltBallots iff #b.preferences = 0
  // All non-transferable ballots belong to an non-transferable surplus
  all b: Ballot | some c: Candidate | b in nonTransferables implies
    b in c.wasted
}

-- 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 = 03
  day = 03
}

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


Add Thursday's solutions

Add Thursday's solutions

// This tutorial models a certain kind of state machine in Alloy

// A state machine is a set of states.
// Each state q has a successor relation.
//     q.successors is the set of possible next states following state q

sig State {
	successors: set State
}

// There is exactly one initial state

one sig Initial extends State { }

// There is a set of final states
// Each final state has an empty set of successors

some sig Final extends State { } { no successors }

// The kind of state machine we are modelling has two other kinds of state:
// yellow states and black states.
// By using sig declarations in Alloy these sets are disjoint by default.
// We add an axiom (a "fact") asserting that every state is initial, final, yellow or black

sig Yellow extends State { }
sig Black extends State { }
fact { State = Initial + Final + Yellow + Black }

// The 0-arity predicate nontrivModel below expresses that the model is "nontrivial" in the
// sense that black, yellow and final states all exist.

pred nontrivModel { #Final > 0 && #Black > 0 && #Yellow > 0 }

// Uncomment the run command below to check to see if the predicate can be satisfied in scope 1
run nontrivModel for 5

// *** EXERCISE 1 ***
// (a) Find the smallest  scope in which nontrivModel is satisfiable
// (b) Look at the model generated by clicking on Instance
//	To improve the display of the model click on Theme
//	Click on sig Black in the left-hand menu and colour Black states black
//	Similarly colour Yellow states yellow, the initial state green and final states red
//	Click on successors and delete the label from the text box in the top left corner
//	If there is a funny $nontrivModel relation displayed click on that and set "show as arcs" to off
//	Click on Apply and then Close
// The model should now display nicely
// (c)  Look at further models by clicking on Next
//	Also run nontrivModel again in larger scope (not too large) to generate larger models

// *** EXERCISE 2 ***
// Say that a state is deadlocked if it has no successors.
// The sig declaration for Final requires final states to be deadlocked
// Add an axiom stating that only Final states can deadlock
// (You may find it useful to use a comprehension term { q: A | P }
//   which defines the subset of those q in set A that satisfy property P)
// For a good reference on the logic of Alloy look at the slides for Session 1 of:
//    http://alloy.mit.edu/alloy/tutorials/day-course/

fact { all q: State - Final | some q.successors }

// After this, and all subsequent exercises involving the addition of new facts run nontrivModel
// in suitable scope and use the Next button to again explore the range of models available

// *** EXERCISE 3 ***
// Add an axiom stating that every state is reachable from the initial state

fact { State in Initial.*successors }

// *** EXERCISE 4 ***
// Black nodes are intended to represent error states.
// When an execution reaches a black node it has to be corrected by eventually
// resetting the system by returning it to the Initial node.
// Add an axiom stating that the initial node is reachable from every black node

fact { Black in ^successors.Initial }

//*** EXERCISE 5 ***
// Yellow states are intended to represent non-error intermediate states that
// may be encountered en-route to arriving at a final state
// Add an axiom stating that every yellow state has a path to a final state

fact { Yellow in ^successors.Final }

// *** EXERCISE 6 ***
// In this exercise we use the "assert" command to state a property that we
// hope follows from the axioms.
// The property is that every state has a path to a final state
// complete the assert command below by filling in the property
// between the curly braces.

assert  finishable { State in *successors.Final }

// Uncomment and modify the check command below to check finishable in a sufficiently large scope to
// be confident whether or not the property is true.

check finishable for 5

// If the property is not true then can you fix the model to make it true?

// *** EXERCISE 7 ***
// There is one further property we want to axiomatize.
// We want to force the system to reset after a Black state.
// This can be achieved by requiring that
// every path to a final state from a black state goes through the initial state.
// Add this as an axiom.
// (Hint, you might need to use set operators to define a derived relation.)

fact { no Black.^(successors - (State -> Initial)) & Final }

// Aditional condition: no final state is successor to the initial state

fact { not Initial in successors.Final }

// This tutorial models a certain kind of state machine in Alloy

// A state machine is a set of states.
// Each state q has a successor relation.
//     q.successors is the set of possible next states following state q

sig State {
	successors: set State
}

// There is exactly one initial state

one sig Initial extends State { }

// There is a set of final states
// Each final state has an empty set of successors

sig Final extends State { } { no successors }

// The kind of state machine we are modelling has two other kinds of state:
// yellow states and black states.
// By using sig declarations in Alloy these sets are disjoint by default.
// We add an axiom (a "fact") asserting that every state is initial, final, yellow or black

sig Yellow extends State { }
sig Black extends State { }
fact { State = Initial + Final + Yellow + Black }

// The 0-arity predicate nontrivModel below expresses that the model is "nontrivial" in the
// sense that black, yellow and final states all exist.

pred nontrivModel { #Final > 0 && #Black > 0 && #Yellow > 0 }

// Uncomment the run command below to check to see if the predicate can be satisfied in scope 1
// run nontrivModel for 1

// *** EXERCISE 1 ***
// (a) Find the smallest  scope in which nontrivModel is satisfiable
// (b) Look at the model generated by clicking on Instance
//	To improve the display of the model click on Theme
//	Click on sig Black in the left-hand menu and colour Black states black
//	Similarly colour Yellow states yellow, the initial state green and final states red
//	Click on successors and delete the label from the text box in the top left corner
//	If there is a funny $nontrivModel relation displayed click on that and set "show as arcs" to off
//	Click on Apply and then Close
// The model should now display nicely
// (c)  Look at further models by clicking on Next
//	Also run nontrivModel again in larger scope (not too large) to generate larger models

// *** EXERCISE 2 ***
// Say that a state is deadlocked if it has no successors.
// The sig declaration for Final requires final states to be deadlocked
// Add an axiom stating that only Final states can deadlock
// (You may find it useful to use a comprehension term { q: A | P }
//   which defines the subset of those q in set A that satisfy property P)
// For a good reference on the logic of Alloy look at the slides for Session 1 of:
//    http://alloy.mit.edu/alloy/tutorials/day-course/

// After this, and all subsequent exercises involving the addition of new facts run nontrivModel
// in suitable scope and use the Next button to again explore the range of models available

// *** EXERCISE 3 ***
// Add an axiom stating that every state is reachable from the initial state

// *** EXERCISE 4 ***
// Black nodes are intended to represent error states.
// When an execution reaches a black node it has to be corrected by eventually
// resetting the system by returning it to the Initial node.
// Add an axiom stating that the initial node is reachable from every black node

//*** EXERCISE 5 ***
// Yellow states are intended to represent non-error intermediate states that
// may be encountered en-route to arriving at a final state
// Add an axiom stating that every yellow state has a path to a final state

// *** EXERCISE 6 ***
// In this exercise we use the "assert" command to state a property that we
// hope follows from the axioms.
// The property is that every state has a path to a final state
// complete the assert command below by filling in the property
// between the curly braces.

assert  finishable { }

// Uncomment and modify the check command below to check finishable in a sufficiently large scope to
// be confident whether or not the property is true.

// check finishable for 1

// If the property is not true then can you fix the model to make it true?

// *** EXERCISE 7 ***
// There is one further property we want to axiomatize.
// We want to force the system to reset after a Black state.
// This can be achieved by requiring that
// every path to a final state from a black state goes through the initial state.
// Add this as an axiom.
// (Hint, you might need to use set operators to define a derived relation.)


add names

add names

open util/ordering[Time]
open named_man_ja [Man]
open named_woman_ja [Woman]

sig Time {}

abstract sig Person {
	state: State -> Time,
}

abstract sig Man, Woman extends Person {}

enum State {Married, NotMarried}

pred init (t: Time) {
	all p: Person | p.state.t = NotMarried
}

pred step (t, t': Time) {
	some disj p1, p2 : Person {
		{
			// marrige
			p1.state.t = NotMarried and p2.state.t = NotMarried
			p1.state.t' = Married and p2.state.t' = Married
		} or {
			// divorce
			p1.state.t = Married and p2.state.t = Married
			p1.state.t' = NotMarried and p2.state.t' = NotMarried
		}
	}
}

fact Traces {
	init[first]
	all t: Time - last {
		step[t, t.next]
	}
}

run {} for exactly 3 Person, 5 Time

open util/ordering[Time]

sig Time {}

sig Person {
	state: State -> Time,
}

enum State {Married, NotMarried}

pred init (t: Time) {
	all p: Person | p.state.t = NotMarried
}

pred step (t, t': Time) {
	some disj p1, p2 : Person {
		{
			// marrige
			p1.state.t = NotMarried and p2.state.t = NotMarried
			p1.state.t' = Married and p2.state.t' = Married
		} or {
			// divorce
			p1.state.t = Married and p2.state.t = Married
			p1.state.t' = NotMarried and p2.state.t' = NotMarried
		}
	}
}

fact Traces {
	init[first]
	all t: Time - last {
		step[t, t.next]
	}
}

run {} for exactly 3 Person, 5 Time