Incomplete - task : Extend unit tests for complete coverage - updated model to clarify that non-sore losers are 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)
        implies (c in Scenario.losers and c not in Scenario.eliminated)
}

fact earlyLoser {
	all c: Candidate | (c.outcome = EarlyLoser or c.outcome = TiedEarlyLoser) iff
		(c in 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 ballot 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))
}

// All non-sore losers are above the threshold
fact losersAboveThreshold {
  all c: Candidate | c.outcome = Loser implies (Scenario.threshold < #c.votes + #c.transfers)
}

fact earlyLosersAboveThreshold {
  all c: Candidate | c.outcome = EarlyLoser implies (Scenario.threshold < #c.votes + #c.transfers)
}

fact tiedLosersAboveThreshold {
  all c: Candidate | c.outcome = TiedLoser implies (Scenario.threshold < #c.votes + #c.transfers)
}

fact tiedEarlyLosersAboveThreshold {
  all c: Candidate | c.outcome = TiedEarlyLoser 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

// 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)
}
check underThresholdOutcomes for 10 but 6 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 = Loser and c1.outcome = Winner and
  Election.method = STV and 0 < #Ballot and #Election.candidates = 2
}
run LW for 5 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

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
    #Election.candidates = 5
	Election.method = STV
    0 < #Ballot
}
run SLQQW for 10 but 6 int

-- Version Control for changes to model
one sig Version {
   year, month, day : Int
} {
  year = 11
  month = 01
  day = 18
  -- Dermot Cochran 2011-01-18
}

-- (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)
        implies (c in Scenario.losers and c not in Scenario.eliminated)
}

fact earlyLoser {
	all c: Candidate | (c.outcome = EarlyLoser or c.outcome = TiedEarlyLoser) iff
		(c in 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 ballot 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))
}

// All non-sore losers are above the threshold
fact losersAboveThreshold {
  all c: Candidate | c.outcome = Loser implies (Scenario.threshold < #c.votes + #c.transfers)
}

fact earlyLosersAboveThreshold {
  all c: Candidate | c.outcome = EarlyLoser implies (Scenario.threshold < #c.votes + #c.transfers)
}

fact tiedLosersAboveThreshold {
  all c: Candidate | c.outcome = TiedLoser implies (Scenario.threshold < #c.votes + #c.transfers)
}

fact tiedEarlyLosersAboveThreshold {
  all c: Candidate | c.outcome = TiedEarlyLoser 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

// 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)
}
check underThresholdOutcomes for 10 but 6 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 and
    (Scenario.threshold < #c1.votes + #c1.transfers)
}
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

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
    #Election.candidates = 5
	Election.method = STV
    0 < #Ballot
}
run SLQQW for 10 but 6 int

-- Version Control for changes to model
one sig Version {
   year, month, day : Int
} {
  year = 11
  month = 01
  day = 18
  -- Dermot Cochran 2011-01-18
}


mappings: remove unused experiment

mappings: remove unused experiment

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

/*
A C11-to-x86 mapping that implements SC atomics using
atomic hardware events. Currently broken.
*/

module c11_x86a[SE,HE]

fun myfr_init [X:HW/Exec_X86] : HE->HE {
  ((stor[X.R]) - ((~(X.rf)) . (X.rf))) . (X.sloc) . (stor[X.W])
}

fun myfr [X:HW/Exec_X86] : HE->HE {
  (((myfr_init[X]) + ((~(X.rf)) . (X.co))) - iden)
}

pred apply_map[X:SW/Exec_C, X':HW/Exec_X86, 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 read compiles to a single non-locked read
  all e : X.(R - W) {
    one e.map
    e.map in X'.R - (X'.atom).univ
  }

  // a non-SC write compiles to a single non-locked write
  all e : X.((W - R) - SC) {
    one e.map
    e.map in X'.W - univ.(X'.atom)
  }

  // an SC write compiles to an RMW
  all e : X.((W - R) & 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]

    // read does not observe a too-late value
    (e2 -> e1) not in ((X'.co) . (X'.rf))

    // read does not observe a too-early value
    (e1 -> e2) not in ((myfr[X']) . (X'.co))
  }

  // RMWs compile to locked RMWs
  all e : X.(R & W) | 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]
  }

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

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

  // rf edges (except those entering the RMWs induced
  // by SC writes) are preserved
  let newR = X'.R & map[X.((W - R) & SC)] |
  X'.rf - (X'.EV -> newR) = ~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

  // the mapping preserves control dependencies
  X.cd in map . (X'.cd) . ~map

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

  // the mapping preserves transactions
  X.stxn = map . (X'.stxn) . ~map
  X.ftxn = map . (X'.ftxn) . ~map

}


Optimised encoding of the vote fragment table

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

module Voting

open util/integer

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

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

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

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

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

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

enum Method {Plurality, STV}

-- A collection of ballots cast in an election
one sig BallotBox {
	ballots: set Ballot
} {
    0 < #ballots
	all b: Ballot | b in ballots
}

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

-- Independent (or Fundamental) Axioms

fact uniqueCandidateID {
  no disj a,b: Candidate | a.identifier = b.identifier
}

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

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

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

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

fact wellFormedQuota {
	Election.method = STV implies
		#BallotBox.ballots < Scenario.quota.mul[Election.seats+1] and
		Scenario.quota.mul[Election.seats] <= #BallotBox.ballots
}

fact wellFormedThreshold {
	#BallotBox.ballots <= Scenario.threshold.mul[20] or
	Election.method = STV implies Scenario.quota <= Scenario.threshold.mul[4]
}

fact noStrayBallots {
	all b: Ballot | b in BallotBox.ballots
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

assert wellFormedBallotBox {
		#BallotBox.ballots = sum (#Election.candidates.votes)
}
check wellFormedBallotBox 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 | one c: Candidate | b in c.votes and c in b.assignees
}
check accounting for 16 but 6 int

// No ballots created or destroyed during counting
assert immutability {
	all c: Candidate | c.votes + c.transfers in BallotBox.ballots and c.surplus in BallotBox.ballots
}
check immutability 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

// Well formed ranking of candidates in ballots
assert wellFormedRanking {
	no disj v,w: Vote | v.ballot = w.ballot and Election.method = STV
		implies v.candidate = w.candidate
}
check wellFormedRanking for 6 but 6 int

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

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

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

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

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

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

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

pred ThreeWinnersOneLoser {
	some a: Candidate | a.outcome = Winner
   	some b: Candidate | b.outcome = QuotaWinner
	some c: Candidate | c.outcome = CompromiseWinner
	some d: Candidate | d in Scenario.losers
}
run ThreeWinnersOneLoser for 8 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 {
	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 TwentyCandidates {
	#Election.candidates = 20
	some c: Candidate | 0 < #c.votes and c in Scenario.losers
}
run TwentyCandidates for 20 but 6 int

pred Outcomes {
 	some disj a,b,c0,d,e,f,g,h,i: Candidate |
		(a.outcome = Winner and b.outcome = QuotaWinner and
		c0.outcome = CompromiseWinner and d.outcome = Loser and
		e.outcome = EarlyLoser and f.outcome = SoreLoser and
		g.outcome = TiedWinner and h.outcome = TiedLoser and i.outcome = TiedEarlyLoser)
}
run Outcomes for 10 but 6 int

pred TenDifferentBallots {
	#BallotBox.ballots = 10
	no disj a,b: Ballot | a.preferences.first = b.preferences.first and #a.preferences = #b.preferences and
		a.preferences.last = b.preferences.last and #a.assignees = #b.assignees
}
run TenDifferentBallots for 10 but 6 int

pred ScenarioLWW {
	some a: Candidate | a.outcome = Loser
	some disj b,c: Candidate | b.outcome = Winner and c.outcome = Winner
    #Election.candidates = 3
}
run ScenarioLWW for 6 int

pred AnyScenarioWithTiedSoreLoser {
	some c: Candidate | c.outcome = TiedSoreLoser
}
run AnyScenarioWithTiedSoreLoser for 6 int

pred LongBallot {
	some b: Ballot | b.length = 20
}
run LongBallot for 20 int

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

module Voting

open util/integer

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

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

-- Table of fragments of Votes used for encoding of results
sig Vote {
	ballot:	Int,			-- Ballot identifier
    candidate: Int,		-- Candidate identifier
    ranking: Int			-- Ranking of candidate on ballot paper
} {
	0 < ranking
    some b: Ballot | b.identifier = ballot and this in b.votes.elems and ranking <= b.length
    some c: Candidate | c.identifier = candidate
    ranking <= #Election.candidates
}

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

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

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

enum Method {Plurality, STV}

-- A collection of ballots cast in an election
one sig BallotBox {
	ballots: set Ballot
} {
    0 < #ballots
	all b: Ballot | b in ballots
}

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

-- Independent (or Fundamental) Axioms

fact uniqueCandidateID {
  no disj a,b: Candidate | a.identifier = b.identifier
}

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

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

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

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

fact wellFormedQuota {
	Election.method = STV implies
		#BallotBox.ballots < Scenario.quota.mul[Election.seats+1] and
		Scenario.quota.mul[Election.seats] <= #BallotBox.ballots
}

fact wellFormedThreshold {
	#BallotBox.ballots <= Scenario.threshold.mul[20] or
	Election.method = STV implies Scenario.quota <= Scenario.threshold.mul[4]
}

fact noStrayBallots {
	all b: Ballot | b in BallotBox.ballots
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

assert wellFormedBallotBox {
		#BallotBox.ballots = sum (#Election.candidates.votes)
}
check wellFormedBallotBox 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 | one c: Candidate | b in c.votes and c in b.assignees
}
check accounting for 16 but 6 int

// No ballots created or destroyed during counting
assert immutability {
	all c: Candidate | c.votes + c.transfers in BallotBox.ballots and c.surplus in BallotBox.ballots
}
check immutability 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

// Non repeating ranking in ballots
assert wellFormedRanking {
}
check wellFormedRanking for 6

-- 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 {
	some a: Candidate | a.outcome = Winner
   	some b: Candidate | b.outcome = QuotaWinner
	some c: Candidate | c.outcome = CompromiseWinner
	some d: Candidate | d in Scenario.losers
}
run ThreeWinnersOneLoser for 8 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 TwentyBallots {
	#BallotBox.ballots = 20
}
run TwentyBallots for 20 but 6 int

pred ThreeWayTie {
	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 TwentyCandidates {
	#Election.candidates = 20
	some c: Candidate | 0 < #c.votes and c in Scenario.losers
}
run TwentyCandidates for 20 but 6 int

pred Outcomes {
 	some disj a,b,c0,d,e,f,g,h,i: Candidate |
		(a.outcome = Winner and b.outcome = QuotaWinner and
		c0.outcome = CompromiseWinner and d.outcome = Loser and
		e.outcome = EarlyLoser and f.outcome = SoreLoser and
		g.outcome = TiedWinner and h.outcome = TiedLoser and i.outcome = TiedEarlyLoser)
}
run Outcomes for 10 but 6 int

pred TenDifferentBallots {
	#BallotBox.ballots = 10
	no disj a,b: Ballot | a.preferences.first = b.preferences.first and #a.preferences = #b.preferences and
		a.preferences.last = b.preferences.last and #a.assignees = #b.assignees
}
run TenDifferentBallots for 10

 but 6 int

pred ScenarioLWW {
	some a: Candidate | a.outcome = Loser
	some disj b,c: Candidate | b.outcome = Winner and c.outcome = Winner
    #Election.candidates = 3
}
run ScenarioLWW for 6 int

pred AnyScenarioWithTiedSoreLoser {
	some c: Candidate | c.outcome = TiedSoreLoser
}
run AnyScenarioWithTiedSoreLoser for 6 int

pred LongBallot {
	some b: Ballot | b.length = 20
}
run LongBallot for 20 int


lom testing

lom testing

[w۸6|^=k.c9K={ْ<q}fcӱȤ7%/<'H %n$X⃧
?6g߼pCogܯ/+/>o]s_;{ss5lv=w>v;#;}[ǥ>;p4|g<g^-OUuԻl{MwST#THw;nG?}³7(\k}OO{uK߭gwߢ%(}K]߼MIý/=&llT۸?<*W̯[y][YYbhO~TBJ^?^XWK%-kFV|lڿ~δR/笷_?`s.^zI۾]ow3ёh
#جo7حͻ!G>Z3"ժio3OdC\/Op/gwϥsN{E/=drlw+#]}'7b7^o?C>A#xt>S.x{zNJ(P*~,OFd~oG69н(PE`P|n\w+UQ~W  <_ߥM:t>'CycߑψI+]ynfIzL]HϮ|wAa4Ů7.6_l6յy}۬wYw.YeVت47)7{^K6WAC>aPC9W?]_4Q.&T=EWZdpJ\&ziDg]SS-D(]CQ\ݍHZѓq	n0}Q;n\-|2Oz#r@ԋbl7nH@`M'[6q	h4 6+
dsά،[..\?]Yyn>=XhVV
yg7i5>$N?vqˑϩE97RЋoH5|/2MR='iز~5h+0lR羧v?R%31nhE;hW~@Eea@]J"L0s0_&gZ^AFNJF&]_텂77y[l**~uH2IPN*TMU`ai>)`zgȶ5S
KT9͛U<wX%褩&:Y,:.nzmT?^rjy\vK}S}敿ahN4e9-3~F*Eꞹ{[{r3 S9
T#Stӫe/Z>i@ƊtL:`~EvwnHxx9.=w5y\E£M`Қ9.$u>
9¥RW>s0x.$K@rR	=JT5+aKz]\ߛ7i{VYk悯1	~ɀTu#?*{߭:eFޮnz(+} "dn!D.Q:Q<r.qiԬxt(^Qs2?D+[ޯy=2U*h,"ս{v|=z2<C^}>Op? iy@@|I&W5F\<{_B6wx2Qo]ԉ][<3i>K"WjH
r>ydVz		#ɘwcqC3ʄ'P*HjݸPnrOs6wġ	*?~97`^$DH䵖0~R4H?
bmXCX
jZ+Ϗ>4kq׉oo
_co9q?ר%XɣVrԷE@ixcmJ%t@ecZ,ykVt7a%t(~MHY;?A8mm
1)'{^~msHb'f7糒oi>8޸],pv0/9VZ_Ɗ
7`zٕ]9b<C*bQVA5Қ|r]`rzW|YYf)!]W*[U[*rdA!VQWAaV0T*jƑU,qdAKYPEfZ6#b{Ȃ*YEm28VQ0,e`ucK8<X@XDX!HXA(La8P݁HTݡXXhZhZصhQ_%Z-0-0-0-0-0-0-0C;Zh Zh-hh1p-	C;Zh Zh-hhhaBBXUBBYUBBsXUBBWYUBBGhhcVUwA5VUwa_ΪB7XUBBghuGD::C-t-;Z Z-Pw0@0Zhaha0@`h6Z 	M-;Z Z-pw0@0Zhaha0dh	wGD&&C-L-L;Z Z-pw0Z-Z:M-LZw0A0ZhdhuGD-,-,Zw@ZhbhuGD-,-,Zw@Zݹ2%,ha1лB6C;Z Z-haha3л
B66C;Z Z-haha30
6kТ<a`U-hah00C;Z8 Z8-ZVТ1R<a`U-Z'VТAD<a`U-ZHVТY9<a`U-ZUT"742ћ
*#T"842842"942942":42:42";42 ;42idR٠2AX!#ȳ&ʓy2<k<Y!#г&ғz2B=kb=Y!#س&ړ{2=k=Y!#&Ⓟ|2B>OĂ>
	AD,ӐO?
	D,ӐOĂ?
	D,ӐO@
	E,ԐPĂ@
	AE,Ԑ8PA
	(-ROxLgFYj,,=jQaNn+Lo02`~qJdY|#%&;&Zʕ_{ٸs]{*VU2Y?BJݪV<VdV洪'Eq2gA}f~{R ]Z7_!,X|Yt+rN?)|OHs9N2h;K`|O{ҖhJjevPj,Dj#8(uv"j[ҳ)Y
d3*uVRvT2W4UMY7nr䧟@W,-*޻x3>[K4	=F3qYRܱUܽVaKwZ?X_:З&251,\YicUu]WEQƺ/ȴ.
QWc.-2l`U5?|E&O*-_ٸ\xD8+EUNcо[a3PzK7iU('omqIYH!*}6TdT#h̵7R)yP<i#;`^I)ˌƘ[FuXS)3YE-0S,^HH"G'W0fbodaˉ9Qgj`&2FB^I(=WǴOI٢*A\me42ZL2&,DB.T*J۱tݦ@ô/+{n,H'ȕzf%Y;D^6fxXiTqW7^ř`W?>&Nsû7kW=@W:RDt2M)Q'LW?vwf)l
VeOd.xUK8}cz|J\U^8\Ag8]^~(zZw7|ƽڎϵ!t ; u kGxzv=s]gz3zx=sI^,gWy\׎Tz^kHZ=||Gjy!'NhVz]s?_wO&T9 G;$OLOCLZrZgQ}ӨyTDo&7KMfS}өT߄oF7SqHUUU3fUKr
bWЫ`n5zOp=v9Ŕ"k}ה<3ؓq	?|zG+ŉ>g5v&n⠘>W+_nv1V##Z W7ae(]v/VdP(XB0_%z3h.ᐥP
jHAgm6gz9f^A7P{(
uF%eGۣҗM:ZiKBh}ha(_
Uh5I^5#irYc&Դ)ѡl*{6Pc=%z<MZ:eX0#|zFxκ*VQ7@[	؇@s}t45%Cks{bWSK
9_zw[w2\Pڪ#}oH1Wg.q\HP8;UN9O^?6:4Ь>>2-q|LD?}/"[MzZ&x%=gKzMMwr2gt9@Kz:%=:&:@v:;2&.e)}^f!wЩ(p**E2\U
!ұeLCq+)ͦC8
=^C)r7ЪƱj'RLK)t`5E-9hKvBmL4uc۰%[_EOoזZs8DZPݓjz28,@K

6ʜ*y{؟X4vCʘۅ490)лp4aqgRaIʾX؅3iZ:%a	tWE(nC.O5(iceΤCk@aG&]80pmOm!|]v@z1ҫ.GY؅Shñ!%qLKm%_/.c݅hC-jX&hjyѕx$Mš
cIO]8C-X)cyK2NiN/}>ԖA}[ۅsl=tG>	>>X܅3谌OjNǪHKp&5XMZǱd'.c2쮨'jEǊH'+n#pP1
h]9vBSÐO0֌qXk|eumuy}7PF1}7L2qXtBm,컙tX-5qXr]UQWDw^hUXm[PF4>
di#zS]7Ci22s;&ux׍9TH9N.fn =UOx׍)7:cCƋuc
eXZ0,zv[WG08kEBkM-9ɲ8q,ձfӁt:ku"e,9jHPUPZţuslpzn"Wܮc+)ͦ8Nq'Wn&CX)ciͤPKv8Xusl5}sDsԘ.wD.{:{+t"9>eh90-֙spj.c
caP֛3덯]8Z&G&E|3*ciΤÒg('.IKҡ,9g@pzU:mڇ##Թ"uCob]xHEiie5a4uNR8:ρܞIݟClOR8?ρ8W=>9dhT#qlxsxcrar9`p9DY>D*!GSs#h,4RqQQ%bӁt<R8DXޟd89689DLH*fBj[aOi6ь9T4?Xܟ3谌jǱj'RIMVӡ8Xܟsl5}slzȎ#}rsR
BǱB'cCPhi~Μ۟S!S_CYox_ss:MDL<jCy8<2Lj:,ІqXxBm,ϙt`-ʒa	t?WE=,9d4[P;G4>

ͩ#S]8Cm22s;&ux>T>O.fp =UOx.7:ncCƋޅeX0,zv[WG08.}EB}M-9ɲ8q,ձgajrH˻pc2T#T7V.vw^.c-8U3
{J fc?IE8]8Z3Ʊj'R.IMVӡq,	j
tU(z]8'j
HG+p#pP9C.h9vB80!Ϳ`eʘۅciraRwCy8<2vLj:0³a	gaʒa	tWE
%݆:}8jE'kxNk"mÙ4uhM*pG&}80p<qyu1ۇqnHz|pl}8;2^>{(iKغ:C-X&hjyѕx$MagcIO}8C-X)cyK2ۿV.v^>gM86
U3
{J fg>qU>IGe|Pv8VDXڇ3j:Ԓ3%;6[M_>ofjEǊH'+n#pt' qV@ʹ}7?0Yd!u_sn:M:L<d!uFWKn&5dd!uPn&-XK)7-buMz+d@Qh|n&vQh"m컙4uhM(Pqj
wٹ::GP'_}7ǧ!}772^2-8LK^}7,
ᡖ	8	9Zwst%	Geqࡖ8Xw3z:ԂǂHn^ZYţwslpa`p6Ɯޞ:862zJ3 Nf<yHy\U,ttX
bcN=7C-iXjcqͱΑma@APs8VD:Zكsl}ahZ߃1\=X87}_s{p:M=L<}(#OUIM%P>O=8CYr8,9.V#XեPG4B
˩#S=8PA86ܾIރci#HsEzރcȍ,GؐC8LK^=8,
j2!GS{p#h,q,ձgajǂH{p^2G7s s
86U3
{J fs=qU>IGf|CڙX)ciΤê5Ԓ5%;6[M_EwhU$wXCYXiheαw!w(3hi~ʜۅ]^x; _>_33_XDc',EtaaۏLa7E}zxj~K}JzQq=:ȼ{LޅkΗ>"Txxj=Q4Z[HYVk3q{'Wj뇪|sKTp4yeL*R///0m|KbE_ɚyHmi鏠]~hK%vU.J~?\'[OߔTSmM>[a3Ei{EC }¤/5VW䷡"X,ԥDc][0tRLOyF.ȋ"r`^3iXH/Iid.HS3Zn%Z*Kɤe9w<ۈk317|C2j{Iz,ie_(M2-CG5&}Q7&O(yJZ$-{Zrwf2VUM߁S8Gq)JyQ<*ThLوF^G'zw+%PgHW/ak<?xS
6^	sû7kWFy֜ͯ?"ϡlp6k?H&y2-BZpޱSnR*/@]^Rbqc4c&ۨdp|s]4+[h?u;2go52TdΣ=e!\YKD4NiVd\rϠs;
Sj'yJ<O)}=o§i7S&JO*}@o":Ғ*/Tjj",4=4?0Aɢ҂/*(҆5*-qGTD$^	2o0b.CiNܱm3iv<0Tx末n7;jrq潎T5Սװsk&ླྀ?ȉOf܇inyKT:qvHCapsg%|u\hrzݐg5FS|)=Ux&	KBNՕMȠfٝ餺4"`WEJTz?N؅<'~Q.ܒ޴j@)'X&%jsFnuPnt&eLOlihE#	ƄY#J5etjAqGeIM[,ry2#[qyu/KC<wa<"ύL.&ϛ-|m8oUSޚ\ת+xHE>M)Y7TJRa*}LoM5٦7TJߴS-қ,۹TiNɛ|H7^7˯U1zw+92ʇ߬nHM`tVdl%s"0uqG?^˥eU-peڊ^U&r6Rſ4U&3q	3T_,|cUYa!`!!q)Dv.dj>J'odtƛLju,Lԛr"ɛ<7Y!&7bgr4RI*}Io>M)Y+;KoM2y7Tfp*HNd҉gJ#RLNt"Gwh>d@>䜷8C&	?<{|2]ăLdڇwAvxd.>I[џ٘<
(>OC+>^lԹ1[M8UyaE߻z5K=#{Q*gr_'}X;u2IBI9P"'*}SEoM97mT^TJ,RH*}sI':Lq{E|SiD9<
عv,E&9WoO|>=c/
zV]KEt>c//l롧ozjX`'wͱpi,**XPbgF\<?BM<1:9͹\K`5??m#nw>sKO'sMg]
AZH8uTR7WU=XoUʋ: V?ۜ؂rn[vT:ho^U&IzbG;P
sn\/n7}<Zy!y33./	SɈi(lNqї{q޴Ù(F<kSs6Rſ
%ӌEEz]r7T%	ieħW"ˢ(]FpJެ(Ȕ):2%(#)NfˌM.m'7͌Mn
*R|}pBoZɡ7?T/,+*}EoƨMy":*iK.[*M2ytOӣKUuhn]2gUX9psn]srvp|n:u#
v=\tr%AS:gjZvvp\Z׽fMuZՍev*
hE#)c.H9E48Aߛɮ+^Sh]utʮ]yђEEUq,r*Μx
n@k,ezMA>vka0&	BK'vޫHcA97
VfJdXrǖA7=VfJ$Y'+{
>uǽBI҈W+4zn=_G^]5݃<?܃qt<I$ڿ۞
ҠDf~gonj--~ӨN"L[Y)eD"sI<Jٿ9\2	_R<rqDYz!n!gg:~Iz~%Ɔ;j5M:r]ד_:I08~S8uJN)};o_ytO)}>oާMiʧJ#L֓x
;;UsST<?*YTW
uf]K\Ó%Xbd
epDY!)þBcǣdXTB8%OZzGu/KPuխ^)=U(xu[9;V-Orf]#(gdmeZZg@R۵$dzwx{M]"쎰6&(SN}'ҿڏ.}^[߯?o)LvH@=yv}OW8K
QV!^W7o<{{&d+=8*].iTmt1Kw+9+TÃwG,?Aog;orO2֗`WOrMj/M^umz0?g=
G3+P(DgޮCh
جo7-ѡ҅k-Κe><<l=e>>ђ
i'(
=/#rzsӀw\U|0 ]}Sq/!޾v |H޺>7rPtmj{q%iJgZ(JS6!{iyi3x/lr=kBj3˕gtO䂿._^"ax$2]ڤC3|2>XRYI5SBgI?zL]HϮ0h]o\
cm>lfPv>#o5>rA5oRp-=jf*&MJ׬Ub5BaՏgoć5Z8'p}9,FCfelgOt[8DEŐaW:{w#Cd\#fؚ[f j-kOO}$3V}6E7	bߊbl7nH@`k^)nouCd&t%o'3+6㖋F'DwUfm~7cyfY)\{TD|շ#Stko"PFoH5|/2MR=.wdblYUVBkW
'y#J-ԞjڙJZĸ~+TQ v6
"|@Eea@]J"L0As_&gZ
߀k4c4h=l۵UHLn^(x|7ŦWH^+)ODeBN5T&pG(3o=;Gec1tM	6>h,Ě-C'u9Y,:.nzmT?^gN5>+3èќrZgT؋@=sIX?7 M~UL:FՂ2

qNJ
UqXj#_^Lo0}J~ Vtg^%e1"]|ѻ3z{>qOW2orŬ,dHcv1ksq?ܒqdA!VVWAaV0T*j=Ȃ*YEm=KYPE#dKpdAY	,";hk6sdA9G2h0C!@t@@|@ @@"@@$ @@&0@@(@@@*P@@,`@-hA-Z
-L	dDDDDDDDD-4-4Vw@ZXBmD-4-4Vw@ZXBBchauG
D-4-4vw@ZBBghawGD-t-tvwa_C[D-t-tvwAZBBghtGD-t-Nw0@0Z8`htGD--Nw0`&CGsD--Nw0@0Rphaha8hahahaha"VUw0A01;Z Z;Z Z:;Z Z;ZZɪEZ	i	uGD&C-,-,;ZX ZX-Pw@Zhaha1@bhuvIX<bhwGD66C-l-l;Z Z-pwAZhaha3fh
wG`h`0*ZwApZhahuGD--sU1hُ'EM<a`U-Zo	bhzOXC;xZIUT"742ћ
*#T"842842"942942":42:42";42 ;42dR٠2AX##ȳ&ʓy:2<k<Y##г&ғz:2B=kb=Y##س&ړ{:2=k=Y##&Ⓟ|:2B>OĂ>	AD,ӑO?	D,ӑOĂ?	D,ӑO@	E,ԑPĂ@	AE,ԑ8PA	(-;B"9z:Y" d	utt/tĴ{z
7`~qY|#%&+
sj)WzHP>zf}N2"	4ZU	d)e_KfZXfCXժ2)w٭Df渊NAlJV"~R˧.s=,Rθ_@a,f
!4R0
:Q0PE=	T4B``

d2*ѨԙJpTZJKQ9|TDd:-"Nb=˷J."<Vȅi#tb4hќܳ6srN&$2cL*FC޲WJ%A7/ä?U3mbFIҜr7,JޗfRmYiu`=ZIHIryx2#O_B~nJJz',W=XK(|޲*5#ψsGR˗_AKj3ɗG><M#OG,#PQ:Ŕby	0LI3*gCݮ&Bd@+D>!iNN$ZanZOM8GWJ;ϸƕ"s%aw@u0<ֵumvsdw5q	^g3zy=󼞉^Lg3=.kEPF5d}-i ~1?A4;!LwyϽ|NﮗW<3N]PQ?KHZ2V	HYR:T˔To7Y-MK}Sߔo7i5MM9NwS3TK
bPP8DAkCc6y[~"?x]m?9}X7/wMHM)3Tj#J.,Co.z0ݧR)Q4cF%X4P"`K¹lFn#h{dҖB/J7tNg"4ْ]^L:%ʕM؅\v$6r
FXO()AIieLB,R_QzTNdKgoW^Ji	y@_HX@rixJh24f4%eyJ^բf>e㠮.	ʚZI;=ťz.5͋?Y7t\=R4l4H)'L@sN&+
ܻ(_BA`CESQ+7?/b8gn0,פ|,x&Re<E%_xv(Sv~	>7b<`+ G1
@]s%JL][RgX;m
&C[::_
T3kc.Ȼ_,ü0EI|˰kP9HӑI¤|܈t:aal1Z6k\.S2rLKh^ߵ$Ev0J!K:9e#\-ߴ_j[WW|K6JP԰=-~t,
uREjԒ}" g[ߤ3rNޡ{_N%T˺%U{۱؊ElF6;#'XFb2SS"ZΖ
[٠R|`srJ4Μ*daCG#|bٗ[o$!
*xQg7/C@( )rPR+6ncxM%]/Ri
;aDF#j1LDƃYc5&Ӧ>c|5~bd_/U)K~Yb$_8	v}ΉsVϬܻ]<&Xޢ+_6
fCM9Ws8&po>ҵxlz	+Ql7WJDz7?xT1k~wk?'^YʘIԕdAKAd+P.HXRj׫.l
y㉫YR*W)JM$ءdj+u5XBSjVєXg5X1hO#I+|7n^{wn%6wZn*
ؠ苂sHt4n:upA]PGu:~#̩~z`os(H7]7UsnȣM94#918ژڐ9=1ՓlfXz"\!WT:1+fvԸz4c4QGH44kpL'L;"UӾﾾrw;k=	lll'
lfl_UGSsWm
^b^Z=!n0g{C2U]%kINqpeR)'-Jq1'Dlk\kb,DQGH5蓆?&]amokK-kf-B^$U;BqD5.怍]mp196}-gIA_M_hr=!
O6sRMDo}7N΍H}	y~cy7_9tsq}YXx,bE7!#$tq߼p=_
/ouvPaGHCņ;A~L9o?^^`M`M`#amp9yǏGp{[Q*bz2LENGHC76[.BOtS􎛓Jp']qkrÉ1q+^63[Mq8Lنh#qidB\c
^G91szJR:~qOsd
~%TMp
w@l9#ц+no,wJBWmJj%Ě"Ӻ.8BxzșN햓9Qsp5~9cqV)nv,~ߋGw/GunoQ
X8xBk73Rv"Bʠl ݄4E(t:*]zg"y~.'_[YYh4˥bo^~F{UXN-dVϲz`E7qDesaM[B7Zצ|[s~Y4ɵ/h5-@dCʬBRSnEnvs2ݧ3"<	h"߀t6VV+xCx}AROqo]}9IǕg$V$K_(FҌ7cv$Tqfr=
k2	eg˕gtO䂿._^"b0Z<6ti%D+:~G>$&5!܌^	}w3-4O/g5B"'}<p~vOC0bWFX/6Y~}Fyu5>rA5oRp->jf*&MZ.ټ_
h"̹)ķ湜9ZbU#l~Z]%,M``pw6=cmɌ넼1Wx̸b ibgxe9`yRPMaBi:_=?Rf3Ϭ،[..\?
2+)e'sJ28RSZļ^{+>
AΑ-(9KC&ƖeXe79R)'7G
?p;KAu1nd8*@)B*pBx:/CWEd
x&s`98/sd~-/#A+
av
:a-6D|PX<eT&U]Y+쟼#g0=fȂҝ;M2O_վͩXޭF91m߈:_vKS}h:
UF{b>_lڿ#1GNx&<Rea]-(PUw{ş]^7`z
7ٕ,Ab&%<nJ%@#+a ,x1~%̛!^2Kh3fc=WZR?,"**Bu!"*r:*Ҋ̶nB,"UօđUd:8LVQ[GT*jȂ*YEmf,"UV?X
fwh@060p0% A"$&(A*,-0UU\%LhZhZhZhZhZhZhZh1C;Zh`|h1pC;Zh Zh-hh1p:C;Z Z-hh3pvGU*
-tU-t-tU-t-tU-t-tU-t-tU-t-U--ĪfUuGDC-طIpnha0@`huGD&C-L-L;Z Z-Pw0A0Zhaha2dh	0hQ6A0Zhaha2dh	wGDC-,-,Zw@ZhbhuGD֝[X)CM)C;ZX ZX-haha3к
B66C;Z Z-haha3л
B66C;Z Z-hañ-ZVB6C;Z8 Z8-hh0лТM0*wU1h'Eb<a`U-Z	bhzCOXCix BB&W>zAep CB'W@CB'W`CB$'WƀCB4'WƠCBD'WCBT'WCBd'WDBt'V<uuAC<T#eyDy0O]FgM'ezDzPO]FgM'e{D{pO]FgM'e|D|O]F'XЧ.!Q}>X.!~B?X.!џ?X.!B@X.!Q@X .!eSRy'H$GPOK,7sOo0>X"S#pD Ey|z~R-JGGvMoFjP%(#}/%5U(Ym?VD(ή#OkU$2cct5nH%BY:^V"~R˧.s<,RθHvQk %uJP)pm5~TD
EEl*:ƢJ@&J٨G騴4GEd@*z]'<y)q>hQݸ= "+OjE6Mw\|i#tb4hќܳ`.`Tk-5SM0_;RDf:敥+K3m궮J(J|mdZRWTE%.I
&1L29@5'jrt}9«'u7,Jh;z
h}e-"т(]wDJ!YߗoCEXK5u2#\QQZ %52yF.TUG&&w*"ϓRyOj¤42<IDhYE-0S,^HH"G'W0fbodaˉ9QgZzE;+d,;șz;f迉DR*},J%#iW&yꐙf&R0-]u<F<GJ̏SyTQCecW*Jǵ4U
OUl$N<~
"gO=Y<@A^tZDet%D2||_^U']!zhNA蝽]gUVDU~Ƥ.xU'	p$kLF^ԄW@}D^q/+o\+"8]~(zw7|ǽڎ׵!v ;:;л:~%x=3)^g3z&z=3^\g3N|@q:א};DoBb0E?^;^^_:FjvBEf^/!AjɐZQ$#DgI]h̓R-SSRdo7]/MfL}S9Sߤo7m7I N|Ԏ:A	"OS-}jʟ(ABPu\K_'oTu5жaq<|߼{y7a#5sXS͢*T\*J.Zΰ}᫓_Bj<O?U"GgOVi^!c^A`\Rt7m h{I.hE*іZfK^vaZt1鼄Kүhh.lӹH[қdW]]cȈ"'K.2ʘHyEQ	:3.e^)q&L]嶛)Yļ$W	/YƜǬ𘔷T7d1O>r+Q^Fyg2RWE]WkSl]tsBwu[=tZZ֟ɬsMP#Yȑ#:jEE!(ELSUu&k
޻^BtL.*UnFn/^Qq>:Y<XaJF1<ZL0x._/J?1e)n.?Jt}!	愘={`N۰1SӚ\bswHs3/^nύ.-Xȕrk	rй.
|?vEϕl&
߹_ޥлݸ"q,i6kqQogŚFU
ʈBgPu0*]g*^ͯ.ݭP,4TL󪬿[2qh0e5&ѫ6JoG쟳~J$FmlJM[37Z3"q=s]U&J}D16A̪t/_wϥsNS~4W3	hM@qWIk}PNG4`~'Ak񷮟op%
+I8t%Siyq?mo]\噯{_FF~Ͽ[zI7^D.E蕪(V$1M=ڤ?3|2>dA"+)75Є?w\oxg~໠0bWiFX/6+ԸݯfϷ\?w#,ZYk:Isr5kkd~4t҄&t餉餉N'Mz~N-bI\![VzNҐeVy6?P|)-G*hSfSM;W\7zIE+uE(/"O3OH?k~AC,'o=kky	큊FJF&]_텂77y[l**~uH2(ZS
4KA-G3$Oaz͐;wXeh_CMоG}EG˻ۨ~:"b|-rFO#)Ped'3~(/9#Q'4:Iѩ#52agB
HwHSlAI\o7|~_CwnKݱ?fM9Wab9aj>5g\ADCPsCap+u3i蔷A\zIz	I|!Fe>wI{&mJ=3t
h@*1	zUG޺{FoBղT#o_|wRW>"dn!D(mBiזuG/
,oЬxt(^QlC/uEp~{02ot,Cx9ъT1kaenVBz> a|#5Rhyp@@|I>%T5Л\<c%}A&*e.޺+xt	gҪ}/H#\ߗ:xEh}cl!
rwdVz
y1d` v[}P*BUixҍfjm==qq[j@b/gdEWZz~_OwjCoaT׾@hsqS15~V55$6y[
BNמ`z
7~?}._et?rI/,-<մ[*stvd
Cu0{A0*eLIH3XEݳLVQ̂`?U= fu()gIH~$CK0̪5AYU2U1
N BF"t8-(	iᤠ&d$AS2NʠBFt8(A-$$?	cRé1C	DpaBBs80fh!!9B3N ZHHw-$$;cRé5k Zh-$9@ZHHrC	)5-4k Zh-$7@ZHHnh1\Bch!!BBZs
D::C	)u-tkU1*Z8 Z-hh3p::C;Z Z-hha0pC;Z Z-hahahhaMU%	aaaᰪ	XUĬhahajhaha2@dh	0@hQ6A0Zhaha2@dh	uGDC-,-,;ZX ZX-pw@Zhaha1ݹ2OAZhaha1fh
wGD66C-l-lZwAZhfhuGD-l8ւExZhahuGD--Zwp@pZ>'E3,xZ>˂'ExZ>#'E<a`U-Zo	B*	D\Z*	D\
	QD\
	D\	ќD\	D\	QD\	D\	ѝDX2<"<ԇx6FeyDy0O,#̳&Γzb5,dXFgM'2=k=Y'YB>O8O,!Q}b	aD,KDp'bXB'c??X'O@PG"%"8 P,!Qb	aE,KEY$hL,Ｔhcp#BOo0Lo
,aE8RXmrli߄TKE'PT 9خ=aN*A!	_4/AByj!'Eq6Ia}U}ȌwwёZ7_!,3J|Yt+rN?)|OHs9N"JCi[4C?k6[~@f3^}Ϲ5ksɶ5b*'2jf,fD|ʔuJkuJ:yN9s2XTzN	Q(pm r(WFawkjN,#~NP5|
[~oŧB[zsjlJz"PևLD>hJ"jym֞ZT^?VuċKPŋ5
UJUՃQp3`Te*S%x<	dJ WeKJpe)
Y@#"h)Mn/Fi"7C~f|O?$Z,-*޻xOT˗ߒo"
x$둭,U6x"/:i!5]>{ݯO|r2-ݝ[j`#o4yeL*R///0m|Fui:2&&
bKot,\+Rnm
/_\xD8P%v}"-iJۓdhߚF]wdEw/"vVePa,*iuvtKTsAJj&"eW]&1<OJY&a[tԑcLDhE4ꆥRiY$ivTo
	#[Nt)݌m0ɑޙ+azh47tz"MFiTRݠo:4}2UGїI)=~2b	>Q=DCUHu,,ݢ%tBVT#^Vov\:ȓrz4r{N8xUgcYm-WQ.|
5"8$nxfSBD'o&VQEx&B]ϧsFBF3Bs?'2sJv~<*8&Kլj%ZTvKJu1k2a\w}wgܫeF	RC8VٖV=c\j3\.{=˞	fg3d2{=̞\ɥ&@6وn͆%( gԉ%B%1yfT!|t	A%;&e0+;2>1뛙Mf}Yo~7A뛡Mh}YZ4M2OL
jWkFjZS֖Avep6WH	~d~KÏ1;g ⿇y`G7gLﰦE_!yѸwnF9Z?Dۅ4o>؀*!*$OٲV3| sU1痮fQ7<묧|=o8j
oT~|#-}kG4@BG}+Bښ|QûO8zȖ&}NU#"ֹW<k%nuG-Iǎ9jhTv!'xίp4n(	LwLDQV<.r/9vCZI!h*nYѧ[d[UKV$銇$ǆE/:Đ=4t\?<'Enta@FFWy8Q!:=antO"
窩˟?[M 0|+h`f*ǲdLMHդϡB,4Tb&5_1Eu*;J_<Z^H.jιC4dpdy!kبx6*W9S=	VTLESO"'?sv=x:_<~Wk':N`rE-@r5
ǲL`\4Gb4UݓXK?Ǌ$Xuwxj|ݹ?:Ys5rT."LȦQa"qDsts~ܸIX4N	H{~n(Va39;LAqOT).5H'tHTv08`dN?͉2_n)	w+4ŏ"\9=ĹecAz^~~{!ɤӆ
\{vAymܤG:+ITY^x=PcaV,
ճevVx"y%zOI&GǠ0
%4-//x:\qX<]
rY[а
S9ĲǠìXk	)6{g,yX =^kLLRlS8%@g)%]ld&@wMN{vJ.j?y~>=o,j<yBIM~>F'ga~LiD4|9خ=AZ
A!$bWުN4VdTe'=Eȇ!lU$0ä1J~yGMWH4KG`mm%wۋ	Ț2~%_|!d+Yɹ:'w0_]:?cG
tHWѓ$0gd>M7.ƃqn2ge1ԩ7/x|U5_ ,JTKG쟳e^?L`㰽ߺ~bTt|#W'PCGEL4!95>}@5x㭿<hi^VkB<vY7xWH
Erxm>9O(w5˟G_`#L 	cNd%fw7B\ou"}<p~vh]o\D{4:.|~
iv>#o5>rA5oRpU/ljf*&M׬U*P5
%Nj
,*=]
(YzSvDΒ/>e#c2"mvv~%kt>V:~T~-ڴ8o!MϞ591+
a
vN[l*(~uH*YT?O-+R
*'泜R%KG1$Oa:MRyNϚW84mhTޭFә/:<m/`>>>7j>{/6>a@byOt<I!갫JiR
>C%}+Qw4vh)
\Zŗ^-EROsum= y|ޮBYii`GЮ
`q֤%U^"S2(ݦ%tL˴(~E?-]~V9W].*[&]QR2X&My 5ohM}QzWV:ޢ49dEijVxs7z34*NKp֣qb(9ndQZ\#IkũriܫLJL[O+NkkPRޢvS4=@"i'mWWIjޚļK+N>!!xxũx9IpK&ԯ
*`ՠ(/V	>V<NLpe>k^mG&۰IN''2JR)H%UL+{=˞eԲgn3]L/{=̞fg3ɄY&ff#Y5͖l̓'qR?"
_	?^u<V?=ՈI3&"J0{ ˵$sLstqZRgu}Ӻy]Įof7Mfw}ӻ]o7MjXyу^3Wl{^FzOp=vd&k}]J[~΂^ث{
?|zGތP;r| bҫWhS?EZc:}o^O9[MR"1ko8ǆ
:fa|LBR5M,%:M\]&tɪG+G^=$48U?"mt9(j ۣhE NFg>R3V	ǗJhX"4^޿4"@+Gt0;:RJ>=NLV4t|<sz4{#\t.-eѣ
l9iV
eI:$z:_?
/o.C8LŲ#MOlǩLLG~t*xV`§!ݝO7Pe
nvGuw8@v*VM|*xrV܉[^9\t(x3+GN^:/Wn[$&7;zpgpyaknzoݭH]wc~nsw#-<[tw[PjY⣾E'}C6yߍn|w~1wyg陳<2fVg1hr
*84-ۚbS4sfc;X|#dMLYg`/Lr"0.+o+T:ڥ:O8BuǱOc5mW;eCXEnнיv
pk-4A_tŉ󇮖\P$MBhpjIW;Q;jF
JdUT塪4\l(Osp˚Hy>vǏ9=Cs:/ۇGt*-J-~y6c|v7Aͻxc|T=;~HC"Y77!2̷*Tlҝ
IFEϖufEYbzD2ؑ?y07/)T:,T&=EL2L2h)2sLq2U!LEv$3ʢNl~jtM|V
g߽)FbZ|ۗaSJdW)f)fQ,UA8bDL!6Sc3ۺqp|)f(g
%l8|@z$Vٍ& "P)gw9dCTr	g52|-Neɶ8ٖ'2d[fL˒2|K7{EA
l-D~-zE}=2kp&qdn^ooK>Jal[?GjkblZٛx-hgt^P2t<)5#xzޓN/
ﯷW>uPSl19}x#*AE./	g'25ݫ&uwz[м!ELWI#\'WdvOXJX|/F
h
)Dde
!	l&O3S|
t!sTk1vл2B[E*=>F.(VQ jVݣǽP%b{X=~m%K>	$*oi,Iza]I/]Kբ:[ġ׿uGJʥP0-6
ESϛMHu~x|S{hF~P֕+_eȡXŲpi7nSJK(]oAڞip`"'bs?,{7'yvV I<F>~Pfbƽގ,b)/[%K-@'<2:}cJű7ĈIq.;`i6~yD#!*vH_$֪~gGz~4,NN0^6*Jݐ[{ES=|HSLtK5S'܆].F'V%|DBfLR_w	4+!$-BZCI'ZyݍQ|?L,:'EDX3iw0'|-kexd9+Mq<仉3/3ƘD

}[w۸3WxyE,eKVkrsec6Odқd P$ŋĘ PU
n7t.vw~/7o_|ݸ? +-vssUl.-}=÷;~_mEUNͯZLWֲ8ݽb׵9Is"JO/so`nxٻ2n,*>x^yKzGN|	o[Oi[{gk;oeFf$$߻򿻛q{7]*lݬlT8?<*W*ͯ[y^:[+tyrS1W#b*Mk^m?n/u!R9eu&gL笫 }YgW^bUsy~
Pa\v*:
<eI
̧ѩno4c[
B+翰yKwxN>"
?Yznbqw.-yOcIxSH;M.7u<++I[f/~,GdP\ᑎNt.0bʚ/^z
]]PZ<ԩ.ӡ_>ʵ\`ßW*+)7sCQp$>ovb9k?_}"(fJԿFb,hU~{mk|i߸샃a)rz*:M>[l*hG#0a0ǳ7RԄj};FN DWϾxOd3TTd#b0+pI!z2-U-7ʵb>+	>|
(fBP|	1L<dKg2 o&uCxtӁ]bʙqEoBy-(@عm~7kߗXhN
&H8I5>L?vqϩEL:ɵwRoH5V|/0MR>PMTV|O`H-Ԟ*ڙJfp-b@D;H~ëH9"V"PW?+*"h<i9sPW9ru忖7`M9Ac
Mp߄酂ƷTUbe2S&@
S4	,X޷#Ӵ5CH}мYPsCQ.t_'ɢΉ[^Foo{Lj\0n3zܼO:t՚b#"u\R=<&?U4HC#Ajd~tQpzBCSTBe.xȪ#}W(#Lo0x &{q#ѫSzWLHF?wAXpF_o/' .c=8C.2[4G1_۞˔)
GTUTB+ZUҊz94ZQSGTN+j_Ȃ*2hEMYPE&w#J+қYPE6Ƒ~Ѐ`lw :
z{x@ >
z{@ B
z{@ F
z{@ J
z{@ N
z{@ R
F{@ V
F{@ Z(-hhP0*Ѣ*KP0:  Z(-hhP0ڣBh

E=Z( Z(-hhP0ۣBl
*E=Z Z-hhR0ۣ
--Tf{PAP)ZBBhaGD-T-TV{PAP)ZXBBhaG
D-4-4V{@(ZXB}- Zh-hhQڣFjE=Zh Zh-hhSۣNn::E=Z Z-hhSۣ6)Z87A)ZBBhaGD=E[n:Mj:LjUGDCUGDCUGDCUGDCUG^1hUhQ6@0LZU{0@0(ZhahaP@¤hڣ	IGDj&&E-L-L=Z Z-P{0A0)ZN)ZOA0)Z(¤hGD-,-,J{@(Z(¢hGD-,-,J{@(Z(¢hGhxc0*j{@)Z¦hGD-l-l9y(Z4N	h8'Et10*x(Z4h	h8'
.:(`TGo֨В)dtQ K+A$'WFhN,
BGX\:42
Dvbipe@:hEgU'EB<.<+<iEgE'
v4"س"ړ{]{V{ҀOϊOiw	|"iwOD>>hA'#?
;Dp'vD4 "8PPǀ"jw(PD@@h A ("AmR3wN;KL;KB;KLLo07ϭDdE|v>	r6#{&`{*FU2i?BBٽ_hTP-+3UhQ|䎰>Q}Ȍzh;b$#J|dS55d)ZYYэDtIKdw?]58GГrŏ⳥bV_@PaJ0Uԓ(LE,-.߰(A&R(G(54GId@rp"m\b4{v	Z|wolUE3r.ZUwq/ߒO$
xY͞Ú{36sr73J9L3GQN䅶4qejT
K5Kdgq%__^(f)m_J^&5hG7 h{U˥3ҵjWOT^߰(={_S%]܇+HD#^'L3mGo.^o{J~_&ub!/h,sBCElT83VUe

	~2{*@LFBOb)3*3:o*U%m:+
f(TL;0m7vr5ރt\I#WIY6VAE3wtM6c-Q+H%%#iW~萑fRR&h)+vT~^-'vTQecD#TTb
RWo|B斱#89K=Cx~uy8^!ȴH},;6Kp*!x%~yBVt]SkooIh{k?˲'2rĤ.xڋ:.$!IKܴ`Hh>qIR3ϸƥ
$s%fwzl{kB@fw;۵ w wUKzfx=S9^$g3Lzfz=S^dgמq^#0>|U&kHw;!/0E?nEpƿmr
ZY^BԐ!5H0G:$Β$'UJħJ}sRlo7_0͘L}sIS߬o7o8S3q'<cO.jJ u:C	Hz>4RJp=v/jWXGMrkΡm%/xE矾Kܛ0ᚼ)FՆUW]*.XF%\e>t]ɇ0ϝN)Q4+JLi\!}!ۆsciZFG6?.(]d+m00b)IaVh¨G.4B&+b{WQmh	Rm1	IH:B+JJ	Oq-KaDE	¶ǐ)W	XƔ(є:')b_Iޒ+#Z^~lǿxUۥ2SZY};Y+i'8Nui^'og6H*RCǜ ,0O8V\$+s5V4Æl$0˗nF!n7b8gn0,k(9cϬ$kJ"8e痛k-C
2t_aGA0ư,3vE12޻%v9L@
my
蔤S,~S+KD@ΐ<`Yyaau!wnKl UCq=riUQ(j}ҬrTlĒ2-u}xWF<E۲6ECt,9e=m_-ߤ_˪[WW|KY%`5,cIǟ]1XT".U5{XZrUM[DWL+ltX.8;}O|Q]Bψ/Ê[Ȫ]Ėld#뱳>rk'1++95Klʰ
*q+2P"pD!G0ݒe϶(HBTڣ$>hn6>9(X%p1%dr0HQZޖ1sNTm<5^C[%=AUd֏.%r~bL_/O&%ri-H8-]3'Ju=rvA)(u(籼EuWevEB9rp"+_uF0h}Lư񬏱lz	-Ql7X<gf~w7n{_Ǟ\BT"77H~I;pl^#r	Vo*rJ/YVܐ7+xyvdJ] &kVYxUc	MXEb*9DjTQP*DxZLA
绩
5wGgf92mHJ)9J`/
SU"#:솨['̡uQG{]s0 Nݠj*{.
ya:NopD4GB=0z̼ط?հ\2ˠ-:3L>iL34k´#bZ11w퍳9wߪaMP`S'`uDg}f
l<[VUv4w|EV/p{YKڡr{;WlIʫd
TnN*;R88a*e%/	Q>ua_XS&QGI|}r֬}5"fT/UZ#:5膸

'q}_AWQW_@Otp\'ܹoJNMDo}'tO΍H}'n2{}iϣw/P~1xLb0УLɢGtq߼ph=_
ݪj#MuFj 7&1M{luxz5m5QGtk'
k{Ǎ;~\8؊d+j&mTtDgƓ8\צqsEi|qcrQ	;3>e׸9kܜ\vsjyx+цgð6Dsѝמw)9uKs=+ׇ8frN#^:畢N8eѧ92wCSkMRm8X=M5z^#}%9qUSibM+QF^Cj5L;jv9{lT͎HogN^<:^2Kݿн8ߣ#|ce@V}	oHQjB:w~X3ݛl:Gu.ݍ3}Q<F/PMrXcﻛД7O{,̒s8T:Qu>*/M2VtaMX?i%';'(v5g}{Hq|ߺBDa&>>֍
nqnvs/bw9g;G] b[nrzopWIj+x::Sx |F(槵O?suFX҃J'+%ܥCn;{x̶*W%#/^z
]]"JPZ<6kti+sψJMG"+)7#筄k'I]"(fJFbͬv=t5>rAo\pksl
[ut&f[meKWAC>qs~<;hz%r&h}
el`Jhi1F+oِ
+&`6Ⓩ/}V.njϲ%yŔjj'*&uC]bqEoB9oa];~}dn|SbΦގ[Of~N-bI+ H7
u9KEnCh|v"b(.4qN#TPUr\^Y'DHa>`!MϮ-f1&oBbrB]j|MQ%`+՝2nX*L0,Մ쏿ݷ#R
ͲUCH}мYPsCQtP?:Yأts⸸Ŗ{nQdf[rSR0n3zܼO*05']9-3~F*E ꞹ{xϽM~iPa1ҠO52?UYXW(49ŹDupcB?*"`$p6z'svޥ]Ύ1̹tCc2f̓:`Թ0$ˇ;'aOJ]TZ9}<3/I.2\Dgߡ"%.^~g%f.H)HA+{g=@2w-Y.K4{>d
xg)E ݂yVW#uGKfXwcnszIQO$!+B;Tҽ/<Le8Z]U<YS{tey'}>;Op? kؑ%Rv@@|&W\<{_6<tq.D.-Lũr5+LץY|tԸkLA?"ql\6T
JƟ<	LxRZ!t@,U1ƅrK6OAk~Ĩ~7`^"%DʛH0~R4H?
l粥
bY`#Ϗ>4k<
_R#:||\/\`'
 hrz|[amG{_>?֚TZAT)旎-fɋ	.@X+χ
ބC<ZyaROPmSiⱭ!6t˯l._Doxy㜓WsY%`;_rgwyz
7uAv%0d,<DRJlDX\YV>a!z{>盻 ~'PX2 jdv1^ܞtQQkȑUhEzUE"UЊo@aiYPEiGTN+jđUdM^8LZQӰ,"V4#Ȧ5?X

f{h@06Pp0;=< =@ !=D #	=H %	=L '
=P )
=T +=X -V{P@P(ZXhQ]%(ZX	-V{P@P(ZXBBhaGD--v{P@P(ZBBhaGD-T-Tv{PAP)ZBmv*E=Z Z-hhhAh]Ij*Ej*Mj*LjUG
DMUG
DMUG
Uh Zh:=Zh Zh-P{@(ZhhQ@BBhڣNGDj::E-t-t=Z Z-P{a&EԁsD-t-tJ{A)Z(BBhGD--J{0@0(Z( hGD--J{0j%ZT:
-j{0@0(Z hGD-L-Lj{0A0)Z¤hGD-L-Lj{0A0)Zh	R:X<¤hGD-L-,Z{@(Zh¢hGD-,-,Z{@(Zh¢hGD-,8ւE;y(Z¦hGD-l-lz{A)Z4''E]x(Z4M'E}x(Z4ޏ'Erx(Z4ޢ'
.:(`TGo֨В)dtQ K+A$'WFhN,
BGX\:42
Dvbipe@:hEgU'EB<.<+<iEgE'
Իz4S"س"ړ{]{V{ҀOϊOw	|"wOD>>hA'#?
;Dp'zD4S "8PPǀ"w(PD@@h A ("Awx{L[F߲To{;mY:mYz[){z
7`\o0?xc0(\[JM瓐*)Wzr}'lT%(#$EF
"2Qe<Qg93I5Df=FkDk$#J|dS55d)ZYYэDtIKdw?]58gAs͡§璓a`LS1Ul?_mJ$UىRTd0E^ QlFj
vrڎ֣$%ޱ+o&؋єd'w^Η3򾝅[{W|gK/;/Iɐc1l=7p@;l;eAlvtvZ9QT+ѿ@jƕ+S5,E,Mŕ|Q~y(\Fa^-4X,YWdR+\F&5m~V!uh#R«'.fzT9ECnH]HB=I~KwdFw/t,We[/RDZ1W/4TH6jDA+^Ȳщ
?KF4ƸtTpi_5=*jNJ%e`*nB
72ӎa9LۍmU1e΂Z[cZ'eln,o2*i5<LX ꂥ.D(J[t"SHq_ƣ{n,UӑOőczf%Y;X^6f*1fT㧰Sqo3`=ޡw<d

Ki"`:QExƄ;Pk>wfo)l{k?˲'2ZrN.Yӗ9F|K_[
.U{%^#\<+HRKE#<j3>ׄЁJw(;ԁu\b3z&w=]g3z&y=i^q^3P="{Ul&kw;9qSӬ<O
Loj6❝svA0!wjH'>ğ&P0(B5P$ϢQ}󨾉TLo*7LͦS}	UߌoJ7*>jH ^z̪ZVMĮW+jzr)Eֈuۤo=BޖVgE矾K{ *\<v&l⠘>W+^g]Lߨqr&ϊGh]GkHEkJ
1QR7bJA)hQ&Sc+({p
P{D(<:=OIGKmC\TݧOWEʘhpBѤԗN<<2{Ccɬ2*n+9{RӺxەeSY㰩)u4iZ:aeðbJ\CYկV𜝭u#T8;GMƷ0B
1x(hfKIj'IST M=92
9_w[g2Ovv]j٪ynH1Wg.Vq\HP8;UN9O^?Ymm*hVrdC8LK^&GUܰ"Mzjh&])PKz88hd龳偖lyKzbuL4ur3Ӂlyv"eL]LEzţSGNdGADter*VXH{lxGWSMp4!Az	4rU1Si1oU;cN68jZ8ژiߣ\S,Df*|zY[6h}FXihAuO}B0-M46*s~V.ĉ؟XFg4a149J|y,
e)0dLj:,PqwBm,dLZ:e)XUQG>tnCVh'zI(V)RΤCk@a2M@!Y8|y,[*SG'_,Hs#fj,xDǆלcC8LK^,c±ա	q,r49ueqC-Xc1gӁt;mv"edp^Y|픲ptpzY8P)8R9l:YhO[\U,fL::,ӆZƱj'RF&gRӁt%;mKvBm,f[M߰<D`ލ>Ԋ>9Nn#pP>
|
˻VSc
ca5}_sy7J&G"we0Lj:0ʢa	w3iZjeXλUQWDwѲLtnAV֍h'|z*zGHKY7Ci2uٹLIκ1
4,\Hz|Y7FxD
ǆWuceX0,zIn#X8j"!GS٬+H8ZW9Ԃ9=:n&=XOZ3Ǳ\'RF6>!Ӂr:a]<ckϺ1JƑ"W\ͱfAP;zZѓŬIGe|Pv8VDdLj:dgcNŬcd#rFQvi}#}Y8P+t8VD:Z9>eh0-g@̹,܅8A=0љza1Vir0)Y8PF=#LΤÒ{('BΤkP=KN,^u+v6iu.#2eMWOl1,]qyst
>9vM&W4N@!9ˉye,?\.Iz|9x,#ʃ86d<Øq|9,jC$q,r49ueqarυIOapEX)#x8ţ968t$ƑLW\~αfAh?qEIGe|Pv8VDLj:dcNc+n"qO.?+P+t8VD:Z9>eh)0-@̹ʬ8%B;0љAzSa1Uir1)9HV2qy\eds&5dCYx8,<6s&-XKqXr],'~J-
OC/9CEsic)gԡ5uMmaBp #;0Y8P!8B<e@zUO8G6S(ؐpKm%_/iαuughC-jX$h*st%	GІZƱ'VbΤ>r>:2Y8G1
T#T7Yg^{>Tʠ>Ajp4hևW4?Xtt`7Ԫ>U;22Y8C-Xjc1j$SFSK}@	fCXh);gkeh0-g@̹,܅8A?0љz3a1Wir0)Y8PF1#LΤ,<sPY8P9KN,^u+f6iB̡9qs3iК:T9M@!y8}y<s OsA|]p ='cuY)Gplxy8P5Ӓ4غ:p	q,r49ueqXC-YXc1gӁt;kv"edp^bn>p졒q$
U3sl=tG=8vb1ga=Ԫ=U;22y8C-Xjc1j\߰fwc"gcENc-dD}<
|
˻VSc
ca]<qXk|eU:L<t
2<Lͤ,:$âjc!fҁt KrҲ.nzU_KB[̻jE&3Dqow3iК:P&B2wٹ\IͻAhN,\Hz|y7u{YȻ)Gplxy7
eZq|y7,
w	q,r4ͻ9ueq(C-)Xc1fӁt;ev"edn^YNYn>aj$Ɯ^
ԁj	|[YOi&ɬ'RǱ'W97ԡVq؉ɹt`5jNrP97V7<GbF7ѧԡVqΉtsl}RahZ֘s98qڃyOa,3:z+c.Ǭ(aRsp<mFWIM%P6OIKҡ,9m@98*VGm
PC/:iCrjic)gԁ5U*hSG&=L<p>T>O.f98Ezѻ,#u86d}(RiKsl]98P˄8	9]G:8Z3Ʊ'VbΤ1Ԃ1;298lZ'G7slpzg cAc	|[aOi6l1=XÙtt`7Ԫ1U;22y8PKv8X9ud˨]H	fCϙXih);W;e42p܅M2EEjE&,BхEh!,Bq:O\Ώ\T0q={쒁cZ.ܳ5\8_DhV}"h[-IYFwܙ}SK,%'J9L;G|DJ4qejT
K5Kdgq%__^(f)a^./VX%RTY+\mt#h{ҪR4F^WOT7Քn"V"I{ԕEC } /t9kVW.#]_,4Dc^h0t\OO~FU/"Ct"gLYŽkK#cAFȌQ5CgkTRVY
K:6CƜϴ=XFmg':.Rc.ȐRl*;dܷ*EO~+I%OIerOM&\,KOT;1y*(+x\ˣc
(t6"̨QVщ
B	T$l-{7~	VfЊ\'{|;	Zs'6 t{_C'Al|:k:NtMDnyud!)\Sn\*/
CŮKI1͸sfD>ݷ}"^^^Νwwӌ&2zlw%ceV0Tx(ɸ
K=i)<p隈I
Ԉ̱Kw0;I|'󤾩7ۓ&|RߜOI}3?o')7&R\PJ
IB	!| BA,J
T2JMXԐ8Jw0HID"u/e;wy&ǗOmHq㶳Y3\%/u\r?tCO4mJon[31mu\2*"'>	2wrFgI-Qٙ#6):1d͹^z=z;!ܫ{'Kޭpޝ+A ;IuGUUYreD]+.
9yMmJ[r܋,)geU1rơV"z8&L.^j#HВFb`ft"%fԄauf%veT5n*tKlyԝnyo/Joy7E
U3ę\u˟7xuK9ު<_mMML.k^yr||hԉ>)M)Y7RRaJ}Lo)M5٦7RߴS
қ,TNɛ|H7˯l1zw+92w+nHM`뮻U5Vja!dETnh~ʗKy&HS^˴ǽةWٜHPWK@Z̨#m%\S}EcoWâC !%'{d㷪?J'odtěL*5`w&orMV{Mޛ,ykGgr4RIJ}Io>)M)Y+;RSdJ}Lo)6%&')HZT'Dtm=|}9oq·N>!zv=d{eWx>=؛yu-|?>ykP||Sܞo9WlaIz9ߙ{QzT>9*_O>($г;I[sԉ(M٢7aRߴQz.QBJ}Ho")%4yM&(\bڱ&|w\969w/6_^qd-Dx_m/Am8+Kc1;dm[l
Bq	I47^ČP3K9s<d=bI
k~~~Fܦٓ'|N
|їTMO8:Y84;T<vƝRTo*MT4mg|vƝVo*Ҙ7`-(UmmE~&fojp^i|([ثx1(]9vO..pZѲ;!̸L)&#ieE_~3(z-({ӈguxF$1ȺHKvㆪ$!-bゕ~H|q%,һNɛLw>EF;1"dN~M̊aT*YfVʻMn
JRߴPJ}Co~(M_:(M7iRGQ:e/,M:tRC/ɣ{]ofGs9|unݜ75&nϧΦ_7z>~vȊ<kwBhJf2&]of׮67ȿ顮]{qkn6Rߐ4x+悄Nz${!8$Fxn:үLwE?ֵtdQzFnUwܽ3'<8?7p`#Ŵt"PZ9{t|؂o:cA97
fRdX6rnK}scoz,͐I7O8TY:e}{!hj&i:#x[5z,ljԻ?yɃt?N$ܿ
R'Df<ɳ7ꂻYz߆ƊiTA;\-Ȭ҃]D"׳I<Jٿٜd\.I/Qj7i5J/͘mσa4ILGWblc`
\xK2u='ܯSbsR'>h7&wRNI}<W;'I7~|ſt`JldCC&IzXb]WGҡ;UsST<?:2YTU@*VЪ
U'!fb!(E;:c
e؃BSʛ}ghǔG
)ghqY)Sovywȗ%(GwB7Z&<@=SP^-'[JӮL3͒*ei2K8wH*{
$!]l67fmRkLO{,:Ԟ\H^<:_]~'|pwٜBq>n?}Gήפd"}=}<sngCvoBBBwyTwMr|_o1|^:[+42S1W}
τ"[
3H"5?2B̻笋߰XChh
xϷ`WQOM)zOQxLn
vwWgB	]o">OҌwHi@YD&\BYY/ݸTQ$"9{Z<C*ߥKءjƗr~9<Jq~;q!朳B$ڶs݅XN ~:?E`XyF3U	ht\bA?۾|
~Wqg[_Z+lUu}t^[ْUF0SZ9W??Čy8&T0t7>]}'[y26ճ/ HTY "3E1xŕbS;'Jf

y
SĶXL~<p'>.>fO\TVBP,ioG)^I!1"*Mഇ
OcƴuwyC2DY\4
SPy-
dx5K,4O{Jż$Fhvrx*sj#r](b	_$sFnϊ/	wD3Z==U3y1ZB"iao(TÊWP"gEE_DV	@?E*?}cC[e|*>1GN̘!ìaz7!!qz!u-6|A~@HTMe6@KT$ReGv$C:LǠp維+Z5[ռ͉CTFoo"[ӌCkӑ.ܑgދO;@=s4qY5$^t^_AHa7TQ%\U=0L5yȔ@Tɖ#Kjʒj8TZ,Iђx	c$VWTEXmAYķ~G6Kc*k<-.z}pY/kwryg(1&э$^kMBCr8UW8ygWZ)-;H'7hiƿU;̋rP2j7"֡t~aEv1Z)=H~Z7ȏniQ}Iuw4ɛF:̴Z[fv$YOVsΖI)-~ԓ4_7k;҅g	v.J?d[h(ҹ(7{6ґL8GtVlϐu獔'%6"^ W*_r(Z@RT^dB0:(38\w@H0-Hgk$
Ld;SN*`Mi%֘XV&q([L.{f=˞eg3cL2{f=̞yfD[Ͻky݉f-Y7kΆ; k제1.`-V"|{4ZYFւ-	Ӳ	P
3뛚&g}Yo7C뛢&i}iZ<MIB=-VUt)_?,_/{,f1Y#ovu_6&粐vq<OXK;O_3STI{wf,i ,`̿d6m{@f<"K_uÃz䏣F5kS>̠F
ya!(&M5dvۜ&K>$	GńSH9#ky.#l1۞HhHrwFUaT2z9}cOGd,_9'6DI0V4o4E!U$a.j1
:WG:!h*.K-2MOS;#tCcE/:Đ=2:_zIx:7bZ0	Ӎoq$p~nOivTn1AO5 HEڹlhϟ|O[
Nh+W5S#+˒14EU1{$wbɈd7d@RvLl.vĝ|%>\:5VX8Wv"xӫa66Ґ$w7]M062ʞEC-O"'?w5x:_<~W2_#:'!m<V_䦛k+iVǅħaXe$V,OIS=sL۔cE{]6@xUFbrttDh:#\D4MtDbqۓh8	Hz~n(d+ [8l:'tVOTva`qr5rٮ/7'f~@|s;xyL1N8>ȇX'<̈W?¿V03sa)sR4i=x!ӯgU");2aBq5t~sC7u4GP^<7$wT.0HVYO2y=
Od>ռ\rg'$&Gm['0
%74[u.X8,nNb-[4]9ĲǠìjXk	)6{gj,yjX, ٺ^ kLҿM%[{tzĺ];g3.@@o{:M#c+!]zx<u7Xjayjc419cJHA39>[T6HbM"VxujJEVAUzx(?AmF &y;%nO%A*#hk#ݻ ,~SS_ok5~3FfLi<ۇ܅S=}Ь>O	wI
C{Ƈt*1b<V(s
N;f{<^j1YV|l0+!Cf^0?g=;y9L2ٟK!e#FE9O'>ѧ3քdל=<hɹD&r;zM7n/E2UIHA͟a*z4]~90fYI7Є?-3nwQϮ"(fJhoFh/6YsozϷ\?w}t
뵹\^k:Nsrk+[~
c2T;6TnBնjtXzvD/X@⇑(=DDE%ic~GXM/("J)R[}+[8(iqB,(o][S1rbf
		ɍn`-6|A~@HT?O[
+R*'泜R%KG1ԝtKq%H1=k^aOҼͣ
lSvOfhv>g4ޔ.U{	{{ZSo}֐h!>B*08=d"5Rۡ%pi/Zȯ%%B?kro||8s|zd!Y!nTe#hWdcsV;WN(#yZKdhDEaچiXftvE:X^ADQ8^y(nxB'}-eoJa#s=j͛:GGp xޮ-JO0ޢhFGF1?n34*>8lEFF'QQܫLJt/x,/+HP^K-Jov<sth$9WFh^y[q0ocy+>=W|/\	Jի.X6(؅21%
!'&<Y#j32لMt>y8<Q NYE*gZ3X,{=s˞egz3`0{=s̞I&24&4kQ*Yl6d<oD8ք9WI^|'HܻϷXG"GLmL1!Q9y\!k`:wkAft0;U:>&v}3]ܮor7&x}3)^oW4!σQJW5e{;F2{-&3Y#ovum6r{a)(:
_BoS;r頢Sp^O}KPk]ǎG߻s/VB/]g!
Y{WumWp=W,IosUU#KIf;,˄ ꑊqHGbr(Q%#D(6
E*GW;)LrZHh>VBΎjM0)q# TҔҜbaE{κp%9LT49_k5}#l\$'pPm-CUCY8,ɲΗϿcC曨P=SUyfNvҴ+@v
b_xWp5ۤ:jCwV-vQ}
#QmӮ
l<?6c8ۂvm
^wOҖ3劁f༽-k^g#z7.]ssLskl.ܯ:lwuwl-ܳ)`oMnw~nwݾlJ-[շh?xh?s&vߵw߯6v`1O4=s'`B& kv`uF'ȍASTiıiƦ34kۙf*(\71fľ<qYz+^x'$f_jv	}Rڎ5kWteP	n\)܄U|ixF3.9q@u~Uf5	uIMZij#j_͜BWA*X+ljWՋf.6^R98ǯt5%C},ح?v?ɀzۇGt(I$૳#qD;;N僾SgTtTԕ
chf
*t'#gC:Eա^d	vO4+%x˅-A1w
/{O2SL*SL5jG4h(08*j&Hdf$3ʢNl~rt
se>cBjw\g0F.댰)N%5N)f)f,UA8bDL!6Sc3ÛÕ>)ç(al>l_"+QhS\ȭźv$_~d3L#6y>wljAn#̢Zlԓmv-Oeɶ<ٖY'ӲE0ͣu?n@g܂@"	~/QAsJv޻C6#pz{0S+ܔ-Ed(IkA;iFǝ_ϯW>qPSt19yx#*AE.7	g'21&uw-h^ʐ"&+@%z1]P^	/]?xBl$k@DZ.`fry	<3>?ŧ?L0G柃`G6+/p<-*>=UtԃQc䂢U^`¼f~=[Ie^Ҝ.&~t{c!dJRy,D'BsElM3OC%#eaIdz"!\&gC>?lV<MV.eLhQ(2]zx;7!\f/A;ZW.}##b]\B	'ݸM2+mN.;ې=bD2OĪ6~EXbwo'yv I<F>Oc?(G3HkfqoG=tJ=@'\;<2:1.Ǳ7؈Iq.;`ɹm+8G5ꥭ#CTƻp_֪V-=0X?vecϢ,NNᢹ0^:*J#{oT3F/3~q6s)e.F;V2{^rt0j<6nO6$5s1@OqL"Ѹk?DJyx#͢K3pRA%/=v7
{H"
FZJ
°#n|7Ko$6


further distinguishing Lidbury-Donaldson model

open ../sw/c11_lidbury[E] as M1
open ../sw/c11_partial[E] as M2

sig E {}

pred distinguishes[X:Exec_C] {
  not (M1/consistent[X])
  dead[X]
  M2/consistent[X]

  // For now, omit dependencies
  no X.(ad+cd+dd)

  // For now, omit RMWs
  no X.(R&W)
}

run t1 { some X:Exec_C {
  distinguishes[X]
}} for 1 Exec, 4 E, 3 Int expect 1
// Gives:
// store(x,2,SC); || r0 = load(y,RLX);
// store(y,1,SC); || store(x,1,SC);
// { r0==1 && x==2 }

fun cycle1[X:Exec_C] : E->E {
  (stor[X.W & X.sc]) .
  (X.sb - X.sloc) .
  (stor[X.W & X.sc]) .
  (X.rf) .
  (stor[X.R & X.(A - acq)]) .
  (X.sb - X.sloc) .
  (stor[X.W & X.sc]) .
  (X.co)
}

run t2 { some X:Exec_C {
  distinguishes[X]
  irreflexive[cycle1[X]]
}} for 1 Exec, 4 E, 3 Int expect 1
// Gives:
// store(x,2,SC); || store(y,2,RLX);
// store(y,1,SC); || store(x,1,RLX);
// { x==2 && y==2 }

fun cycle2[X:Exec_C] : E->E {
  (stor[X.W & X.sc]) .
  (X.sb - X.sloc) .
  (stor[X.W & X.sc]) .
  (X.co) .
  (stor[X.W & X.(A - rel)]) .
  (X.sb - X.sloc) .
  (stor[X.W & X.(A - rel)]) .
  (X.co)
}

run t3 { some X:Exec_C {
  distinguishes[X]
  irreflexive[cycle1[X]]
  irreflexive[cycle2[X]]
}} for 1 Exec, 4 E, 3 Int expect 1
// Gives:
// store(x,2,SC);  || r0 = load(y,SC);
// store(y,1,RLX); || store(x,1,REL);
// { x==2 && r0==1 }

fun cycle3[X:Exec_C] : E->E {
  (stor[X.W & X.sc]) .
  (X.sb - X.sloc) .
  (stor[X.W & X.(A - rel)]) .
  (X.rf) .
  (stor[X.R & X.sc]) .
  (X.sb - X.sloc) .
  (stor[X.W & X.(rel - sc)]) .
  (X.co)
}

run t4 { some X:Exec_C {
  distinguishes[X]
  irreflexive[cycle1[X]]
  irreflexive[cycle2[X]]
  irreflexive[cycle3[X]]
}} for 1 Exec, 4 E, 3 Int expect 1
// Gives.......

////////////////////////////////////

run t0 { some X:Exec_C {
  distinguishes[X]
  some disj e0,e1,e2:E {
    e0 in X.(W-sc)
    e1 in X.(W&sc)
    e2 in X.(R-sc)
    (e0->e2) in X.rf
    (e0->e1) in M1/hb[X]
    (e0->e1) in X.sloc
  }
}} for 1 Exec, 5 E, 3 Int