clafer model is uploaded

clafer model is uploaded

module ferhat/Clafer

abstract sig Element {}
sig string extends Element {}
abstract sig boolean extends Element {}
one sig false,true extends boolean {}
--sig integer extends Element {}

/* Target: Clafer Metamodel*/
abstract sig CElement extends Element {}
sig Clafer extends CElement {
	isAbstract: lone boolean, -- 'abstract'
	name: lone string, -- clafer's name
	cElements: set Clafer, -- subclafers
	cSuper: lone Clafer, -- superclafer ':'  -- abstract <clafer> : <superclafer>
	cTarget: lone Clafer,
	--
	cCardinality: lone (CardInterval + CCardinality), //| ? |+ | * |  Interval
	cGroupCardinality: lone (GCardInterval + GroupCardinality), //| xor |  or | mux |  opt | Interval
}
fact {
	all c, c': Clafer |  {
		c' in c.cElements => one c'.name -- All Clafers except ClaferModel has a name
		c' in c.cElements => one c'.cCardinality and one c'.cGroupCardinality  --All Clafers except ClaferModel has Card and GCard
	}
}

one sig ClaferModel extends Clafer { }
fact {
	all m: ClaferModel | no m.cSuper --ClaferModel has no cSuperClafer
	all m: ClaferModel | no m.cTarget --ClaferModel is not a reference Clafer
	all m: ClaferModel, c: Clafer | m != c.cSuper --ClaferModel cannot be a super Clafer
	all m: ClaferModel | no m.name -- ClaferModel has no name
	all m: ClaferModel | no m.isAbstract -- ClaferModel has no isAbstract
	all m: ClaferModel | no m.cCardinality -- ClaferModel has no Card
	all m: ClaferModel | no m.cGroupCardinality -- ClaferModel has no Card
}

fact {
	no c: Clafer | c in c.^cElements --no Clafer cycles exist
	no c: Clafer | c in c.^cSuper -- no superClafer cycles exist
	Clafer in ClaferModel.*cElements --each Clafer is reachable from the ClaferModel
	all c: Clafer | lone c.~cElements --each Clafer has at most one parent
	no disj c, c': Clafer, c'': Clafer | c in c''.cElements and c' in c''.cElements and some c.name & c'.name --no overlapping Clafer names in the same level,
	all c: Clafer | c in ClaferModel.cElements => one c.isAbstract --abstract clafers are shown only in Top Level
	all c: Clafer | c !in ClaferModel.cElements => no c.isAbstract --inner Clafers cannot be defined as abstract
	all c, c': Clafer, m: ClaferModel |  c.cSuper = c' => c' in m.cElements and c'.isAbstract = true -- only super typing to top level 'abstract' Clafers
	all c, c': Clafer, m: ClaferModel |  c.cTarget = c' => c' in m.cElements --only reference to top level Clafers
	all c: Clafer, m: ClaferModel |  c in m.cElements => no c.cTarget -- Top Level Clafer can not be a reference clafer
	no c: Clafer | one c.cTarget and one c.cSuper --a clafer cannot be a reference clafer and has super type at the same time
}

abstract sig CInterval extends CElement { min, max : Int }
fact {
	all i:CInterval | {
		i.min >= 0
		i.max >= i.min || i.max = -1
		i.min = 0 => i.max != 0 or i.max = 1 or i.max = -1
		i.min = 1 => i.max = -1 or i.max >= 1 } }

abstract sig CCardinality extends CElement {}
lone sig CardLone extends CCardinality {} //? : 0..1
lone sig CardSome extends CCardinality {} //+ : 1..*
lone sig CardAny extends CCardinality {} //* : 0..*
lone sig CardEmpty extends CCardinality {} // 1..1
sig CardInterval extends CInterval {} // int .. int

abstract sig GroupCardinality extends CElement {}
lone sig GCardMux extends GroupCardinality {} //mux: 0..1
lone sig GCardOr extends GroupCardinality {} //or: 1..*
lone sig GCardOpt extends GroupCardinality {} //opt: 0..*
lone sig GCardXor extends GroupCardinality {} //xor: 1..1
sig GCardInterval extends CInterval {} // int .. int

fact realismConstraint {some Clafer}

//fact { all i:CInterval, c: Clafer | i in c.cCardinality or i in c.cGroupCardinality} -- implicit containment without an explicit relation

/* Helper Predicates*/
pred acyclic [s: set univ, r: univ->univ] { no x: s | x in x.^r }

/* Counterexample Finding */
assert noMoreThanOneTopLevelClafer {#ClaferModel.cElements > 2}
check noMoreThanOneTopLevelClafer for 10 Element

assert noSubClaferExist { some c, c': Clafer | c in c'.cElements }
check noSubClaferExist for 15 Element

pred example { #Clafer > 3 and #cTarget> 1 and #cSuper> 1 and #CardInterval>0 }
run example for 20 Element

error: pathspec 'eu.modelwriter.demonstration.requirements/Clafer.als' did not match any file(s) known to git


Incomplete - task : Coverage profiling of universal tests

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

module Voting

open util/integer

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

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

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

enum Method {Plurality, STV}

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

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

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

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

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

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

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

module Voting

open util/integer

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

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

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

enum Method {Plurality, STV}

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

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

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

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

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

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


Extra synonym

Extra synonym

module exec[E]
open relations[E]

sig Exec {
  ev : set E, // domain of all events
  W, R, F : set E, // writes, reads, fences
  naL : set E, // events accessing non-atomic locations
  sb : E -> E, // sequenced before
  ad : E -> E, // address dependency
  dd : E -> E, // data dependency
  cd : E -> E, // control dependency
  sthd : E -> E, // same thread (E.R.)
  sloc : E -> E, // same location (partial E.R.)
  //////////////////////////////////////
  rf : E -> E,  // reads-from
  co : E -> E,  // coherence order
}{
  // ev captures all and only the events involved
  W + R + F + naL in ev

  // fences are disjoint from accesses
  no ((R + W) & F)

  // sequenced-before is intra-thread
  sb in sthd

  // sequenced-before is acyclic and transitive
  strict_partial_order[sb]

  // sequenced-before has the "N-free" property
  all a,b,c,d : ev | not (
	((b->d) + (a->d) + (a->c)) in sb and
      no (((a->b) + (b->c) + (c->d)) & *sb))

  // Event e2 has an "address dependency" on e1 if
  // location[e2] depends on valr[e1]. Therefore "(e1,e2) in ad"
  // only makes sense when e1 is a read and e2 is a read or a write
  // sequenced after e1.
  ad in (R -> (R + W)) & sb

  // Event e2 has a "data dependency" on e1 if valw[e2] depends
  // on valr[e1]. Therefore "(e1,e2) in data" only makes sense when
  // e1 is a read and e2 is a write sequenced after e1.
  dd in (R -> W) & sb

  // Event e2 has a "control dependency" on e1 if
  // valr[e1] is used to make a subsequent branching decision
  // and e2 follows that branch in program order. Therefore
  // "(e1,e2) in cd" only makes sense when e1 is a read and e2
  // is sequenced after e1.
  cd in (R -> E) & sb

  // Control dependencies are transitive. I don't think
  // we should necessarily say the same about other types
  // of dependencies
  //transitive[cd]

  // sthd is an equivalence relation
  is_equivalence[sthd, ev]

  // loc is an equivalence relation among reads and writes
  is_equivalence[sloc, R + W]

  // naL contains zero or more sloc-classes
  naL . sloc = naL

  rf in W lone -> R
  rf in sloc

  // co is acyclic and transitive
  strict_partial_order[co]

  // co is a union, over all atomic locations x, of strict
  // total orders on writes to x
  (co + ~co) = ((W - naL) -> (W - naL)) & sloc - iden

}

fun ev [e:E, X:Exec] : set E { X.ev - e }
fun W [e:E, X:Exec] : set E { X.W - e }
fun R [e:E, X:Exec] : set E { X.R - e }
fun F [e:E, X:Exec] : set E { X.F - e }
fun M [e:E, X:Exec] : set E { X.R + X.W - e }
fun naL [e:E, X:Exec] : set E { X.naL - e }

fun sb [e:E, X:Exec] : E->E { X.sb - (univ -> e) - (e -> univ) }
fun ad [e:E, X:Exec] : E->E { X.ad - (univ -> e) - (e -> univ) }
fun dd [e:E, X:Exec] : E->E { X.dd - (univ -> e) - (e -> univ) }
fun cd [e:E, X:Exec] : E->E { X.cd - (univ -> e) - (e -> univ) }
fun sthd [e:E, X:Exec] : E->E { X.sthd - (univ -> e) - (e -> univ) }
fun sloc [e:E, X:Exec] : E->E { X.sloc - (univ -> e) - (e -> univ) }
fun rf [e:E, X:Exec] : E->E { X.rf - (univ -> e) - (e -> univ) }
fun co [e:E, X:Exec] : E->E { X.co - (univ -> e) - (e -> univ) }

// Some synonyms
fun po [e:E, X:Exec] : E->E { sb[e,X] }
fun addr [e:E, X:Exec] : E->E { ad[e,X] }
fun ctrl [e:E, X:Exec] : E->E { cd[e,X] }
fun data [e:E, X:Exec] : E->E { dd[e,X] }
fun loc [e:E, X:Exec] : E->E { sloc[e,X] }
fun thd [e:E, X:Exec] : E->E { sthd[e,X] }
fun ext [e:E, X:Exec] : E->E { (X.ev -> X.ev) - sthd[e,X] }

fun fr_init[e:E, x:Exec] : E->E {
  (stor[R[e,x]] - (~(rf[e,x]) . (rf[e,x]))) . (sloc[e,x]) . (stor[W[e,x]])
}

fun fr[e:E, x : Exec] : E -> E {
  (fr_init[e,x] + (~(rf[e,x]) . (co[e,x]))) - iden
}

pred no_RMWs[e:E, x : Exec] {
  no (R[e,x] & W[e,x])
}

// sb, within each thread, is total
pred total_sb[e:E, x : Exec] {
  sthd[e,x] - iden in sb[e,x] + ~(sb[e,x])
}

/*
pred forced_co[e:E, x : Exec] {
  (imm[co[e,x]]) . (imm[co[e,x]]) . ~(imm[co[e,x]]) in
    (rc[rf[e,x]]) . (rc[(sb[e,x]) . (rc[~(rf[e,x])])])
}
*/

/*
pred no_if_zero[e:E, x:Exec] {
  // avoid "if(r==0)" in generated litmus test
  dom[cd[e,x]] in ran[rf[e,x]]
}
*/

/*************************/
/*      TESTS            */
/*************************/

pred messagepassing[x : Exec] {
  /*
  e1: Wx=1   e3: Ry=1
  e2: Wy=1   e4: Rx=0
  */
  some disj e1, e2, e3, e4 : E {
    x.ev = e1 + e2 + e3 + e4
    x.sb = (e1 -> e2) + (e3 -> e4)
    x.cd = (e3 -> e4)
    x.ad = none->none
    x.dd = none->none
    x.W = e1 + e2
    x.R = e3 + e4
    x.F = none
    x.sthd = sq[e1 + e2] + sq[e3 + e4]
    x.sloc = sq[e1 + e4] + sq[e2 + e3]
    x.naL = none
    x.rf = (e2 -> e3)
    x.co = none->none
  }
}

run messagepassing for 1 Exec, 4 E

module exec[E]
open relations[E]

sig Exec {
  ev : set E, // domain of all events
  W, R, F : set E, // writes, reads, fences
  naL : set E, // events accessing non-atomic locations
  sb : E -> E, // sequenced before
  ad : E -> E, // address dependency
  dd : E -> E, // data dependency
  cd : E -> E, // control dependency
  sthd : E -> E, // same thread (E.R.)
  sloc : E -> E, // same location (partial E.R.)
  //////////////////////////////////////
  rf : E -> E,  // reads-from
  co : E -> E,  // coherence order
}{
  // ev captures all and only the events involved
  W + R + F + naL in ev

  // fences are disjoint from accesses
  no ((R + W) & F)

  // sequenced-before is intra-thread
  sb in sthd

  // sequenced-before is acyclic and transitive
  strict_partial_order[sb]

  // sequenced-before has the "N-free" property
  all a,b,c,d : ev | not (
	((b->d) + (a->d) + (a->c)) in sb and
      no (((a->b) + (b->c) + (c->d)) & *sb))

  // Event e2 has an "address dependency" on e1 if
  // location[e2] depends on valr[e1]. Therefore "(e1,e2) in ad"
  // only makes sense when e1 is a read and e2 is a read or a write
  // sequenced after e1.
  ad in (R -> (R + W)) & sb

  // Event e2 has a "data dependency" on e1 if valw[e2] depends
  // on valr[e1]. Therefore "(e1,e2) in data" only makes sense when
  // e1 is a read and e2 is a write sequenced after e1.
  dd in (R -> W) & sb

  // Event e2 has a "control dependency" on e1 if
  // valr[e1] is used to make a subsequent branching decision
  // and e2 follows that branch in program order. Therefore
  // "(e1,e2) in cd" only makes sense when e1 is a read and e2
  // is sequenced after e1.
  cd in (R -> E) & sb

  // Control dependencies are transitive. I don't think
  // we should necessarily say the same about other types
  // of dependencies
  //transitive[cd]

  // sthd is an equivalence relation
  is_equivalence[sthd, ev]

  // loc is an equivalence relation among reads and writes
  is_equivalence[sloc, R + W]

  // naL contains zero or more sloc-classes
  naL . sloc = naL

  rf in W lone -> R
  rf in sloc

  // co is acyclic and transitive
  strict_partial_order[co]

  // co is a union, over all atomic locations x, of strict
  // total orders on writes to x
  (co + ~co) = ((W - naL) -> (W - naL)) & sloc - iden

}

fun ev [e:E, X:Exec] : set E { X.ev - e }
fun W [e:E, X:Exec] : set E { X.W - e }
fun R [e:E, X:Exec] : set E { X.R - e }
fun F [e:E, X:Exec] : set E { X.F - e }
fun M [e:E, X:Exec] : set E { X.R + X.W - e }
fun naL [e:E, X:Exec] : set E { X.naL - e }

fun sb [e:E, X:Exec] : E->E { X.sb - (univ -> e) - (e -> univ) }
fun ad [e:E, X:Exec] : E->E { X.ad - (univ -> e) - (e -> univ) }
fun dd [e:E, X:Exec] : E->E { X.dd - (univ -> e) - (e -> univ) }
fun cd [e:E, X:Exec] : E->E { X.cd - (univ -> e) - (e -> univ) }
fun sthd [e:E, X:Exec] : E->E { X.sthd - (univ -> e) - (e -> univ) }
fun sloc [e:E, X:Exec] : E->E { X.sloc - (univ -> e) - (e -> univ) }
fun rf [e:E, X:Exec] : E->E { X.rf - (univ -> e) - (e -> univ) }
fun co [e:E, X:Exec] : E->E { X.co - (univ -> e) - (e -> univ) }

// Some synonyms
fun po [e:E, X:Exec] : E->E { sb[e,X] }
fun addr [e:E, X:Exec] : E->E { ad[e,X] }
fun ctrl [e:E, X:Exec] : E->E { cd[e,X] }
fun data [e:E, X:Exec] : E->E { dd[e,X] }
fun loc [e:E, X:Exec] : E->E { sloc[e,X] }
fun thd [e:E, X:Exec] : E->E { sthd[e,X] }

fun fr_init[e:E, x:Exec] : E->E {
  (stor[R[e,x]] - (~(rf[e,x]) . (rf[e,x]))) . (sloc[e,x]) . (stor[W[e,x]])
}

fun fr[e:E, x : Exec] : E -> E {
  (fr_init[e,x] + (~(rf[e,x]) . (co[e,x]))) - iden
}

pred no_RMWs[e:E, x : Exec] {
  no (R[e,x] & W[e,x])
}

// sb, within each thread, is total
pred total_sb[e:E, x : Exec] {
  sthd[e,x] - iden in sb[e,x] + ~(sb[e,x])
}

/*
pred forced_co[e:E, x : Exec] {
  (imm[co[e,x]]) . (imm[co[e,x]]) . ~(imm[co[e,x]]) in
    (rc[rf[e,x]]) . (rc[(sb[e,x]) . (rc[~(rf[e,x])])])
}
*/

/*
pred no_if_zero[e:E, x:Exec] {
  // avoid "if(r==0)" in generated litmus test
  dom[cd[e,x]] in ran[rf[e,x]]
}
*/

/*************************/
/*      TESTS            */
/*************************/

pred messagepassing[x : Exec] {
  /*
  e1: Wx=1   e3: Ry=1
  e2: Wy=1   e4: Rx=0
  */
  some disj e1, e2, e3, e4 : E {
    x.ev = e1 + e2 + e3 + e4
    x.sb = (e1 -> e2) + (e3 -> e4)
    x.cd = (e3 -> e4)
    x.ad = none->none
    x.dd = none->none
    x.W = e1 + e2
    x.R = e3 + e4
    x.F = none
    x.sthd = sq[e1 + e2] + sq[e3 + e4]
    x.sloc = sq[e1 + e4] + sq[e2 + e3]
    x.naL = none
    x.rf = (e2 -> e3)
    x.co = none->none
  }
}

run messagepassing for 1 Exec, 4 E


exec: clean-up unused definitions

exec: clean-up unused definitions

module exec[E]
open relations[E]

sig Exec {
  EV : set E,      // domain of all events
  W, R, F : set E, // writes, reads, fences
  IW : set E,      // initial writes
  NAL : set E,     // events accessing non-atomic locations
  sb : E->E,       // sequenced before
  ad,cd,dd : E->E, // address, control, data dependencies
  sthd : E->E,     // same thread (partial E.R.)
  sloc : E->E,     // same location (partial E.R.)
  stxn : E -> E,   // same transaction (partial E.R.)
  ftxn : E -> E,   // failed transaction (partial E.R.)
  //////////////////////////////////////
  rf : E->E,       // reads-from
  co : E->E,       // coherence order
}{
  // EV captures all and only the events involved
  W + R + F = EV

  // some reads and writes may access "non-atomic" locations
  NAL in (R + W)

  // fences are disjoint from accesses
  no ((R + W) & F)

  // initial events are ordinary writes
  IW in W - R

  // at most one initial write per location
  (IW -> IW) & sloc in iden

  // sequenced-before is intra-thread
  sb in sthd

  // sequenced-before is acyclic and transitive
  strict_partial_order[sb]

  // sequenced-before is total within a thread
  sthd in *sb + ~*sb

  // sthd is an equivalence relation among non-initial events
  is_equivalence[sthd, EV - IW]

  // loc is an equivalence relation among reads and writes
  is_equivalence[sloc, R + W]

  // naL contains zero or more sloc-classes
  NAL . sloc = NAL

  rf in sloc

  // co is acyclic and transitive
  strict_partial_order[co]

  // co is a union of strict total orders on writes, one per location
  // except for non-atomic locations, and it avoids writes that are in
  // failed transactions
  (co + ~co) = ((W - NAL) -> (W - NAL)) & sloc - iden

  // Event e2 has an "address dependency" on e1 if
  // location[e2] depends on valr[e1]. Therefore "(e1,e2) in ad"
  // only makes sense when e1 is a read and e2 is a read or a write
  // sequenced after e1.
  ad in (R -> (R + W)) & sb

  // Event e2 has a "data dependency" on e1 if valw[e2] depends
  // on valr[e1]. Therefore "(e1,e2) in data" only makes sense when
  // e1 is a read and e2 is a write sequenced after e1.
  dd in (R -> W) & sb

  // Event e2 has a "control dependency" on e1 if
  // valr[e1] is used to make a subsequent branching decision
  // and e2 follows that branch in program order. Therefore
  // "(e1,e2) in cd" only makes sense when e1 is a read and e2
  // is sequenced after e1.
  cd in (R -> EV) & sb

  // transactions are intra-thread
  stxn in sthd
  ftxn in sthd

  // stxn is a partial equivalence relation among a subset of
  // the non-initalisation events
  stxn in (EV - IW) -> (EV - IW)
  symmetric[stxn]
  transitive[stxn]

  // ftxn is a partial equivalence relation among a subset of
  // the non-initalisation events
  ftxn in (EV - IW) -> (EV - IW)
  symmetric[ftxn]
  transitive[ftxn]

  // no overlap between stxn and ftxn
  no stxn & ftxn

  // transactions must be contiguous
  ((sb.sb & stxn) . ~sb) & sb in stxn
  ((sb.sb & ftxn) . ~sb) & sb in ftxn

  // events sequenced after an failing transaction are control-
  // dependent on all the reads inside that ftxn
  (R & dom[ftxn]) <: (sb - ftxn) in cd

  // address/data dependencies cannot escape failing transactions
  no (dom[ftxn] <: ((ad + dd) - ftxn))
}

pred withinit[X:Exec] {
  // rf connects each read to exactly one write
  X.rf in X.W one -> X.R

  // for every event that accesses a location, there is
  // exactly one initial event at the same location
  all e : X.(R+W) | one (e.(X.sloc) & X.IW)

  // initial writes have no co-predecessor
  all e : X.IW | no e.~(X.co)
}

pred withoutinit[X:Exec] {
  // rf connects each read to at most one write
  X.rf in X.W lone -> X.R

  // there are no initial writes
  no X.IW
}

fun addsb[e:PTag->E, X:Exec, F:set E] : E->E {
  *(sb[e,X]) . (stor[F]) . *(sb[e,X]) }

// Perturbation Tags are an idea due to Daniel Lustig et al.
// (ASPLOS'17, http://dl.acm.org/citation.cfm?id=3037723)
abstract sig PTag {}
one sig rm_EV extends PTag {}
one sig rm_ad extends PTag {}
one sig rm_cd extends PTag {}
one sig rm_dd extends PTag {}
one sig rm_txn extends PTag {}

fun EV [e:PTag->E, X:Exec] : set E { X.EV - e[rm_EV] }
fun W [e:PTag->E, X:Exec] : set E { X.W - e[rm_EV] }
fun IW [e:PTag->E, X:Exec] : set E { X.IW - e[rm_EV] }
fun R [e:PTag->E, X:Exec] : set E { X.R - e[rm_EV] }
fun F [e:PTag->E, X:Exec] : set E { X.F - e[rm_EV] }
fun NAL [e:PTag->E, X:Exec] : set E { X.NAL - e[rm_EV] }

fun sb [e:PTag->E, X:Exec] : E->E {
  (univ - e[rm_EV]) <: X.sb :> (univ - e[rm_EV]) }
fun ad [e:PTag->E, X:Exec] : E->E {
  (univ - e[rm_EV] - e[rm_ad]) <: X.ad :> (univ - e[rm_EV]) }
fun dd [e:PTag->E, X:Exec] : E->E {
  (univ - e[rm_EV] - e[rm_dd]) <: X.dd :> (univ - e[rm_EV]) }
fun cd [e:PTag->E, X:Exec] : E->E {
  (univ - e[rm_EV] - e[rm_cd]) <: X.cd :> (univ - e[rm_EV]) }
fun sthd [e:PTag->E, X:Exec] : E->E {
  (univ - e[rm_EV]) <: X.sthd :> (univ - e[rm_EV]) }
fun sloc [e:PTag->E, X:Exec] : E->E {
  (univ - e[rm_EV]) <: X.sloc :> (univ - e[rm_EV]) }
fun stxn[e:PTag->E, X:Exec] : E->E {
  (univ - e[rm_EV] - e[rm_txn]) <: X.stxn :> (univ - e[rm_EV] - e[rm_txn]) }
fun ftxn[e:PTag->E, X:Exec] : E->E {
  (univ - e[rm_EV] - e[rm_txn]) <: X.ftxn :> (univ - e[rm_EV] - e[rm_txn]) }
fun rf [e:PTag->E, X:Exec] : E->E {
  (univ - e[rm_EV]) <: X.rf :> (univ - e[rm_EV]) }
fun co [e:PTag->E, X:Exec] : E->E {
  (univ - e[rm_EV]) <: X.co :> (univ - e[rm_EV]) }

module exec[E]
open relations[E]

sig Exec {
  EV : set E,      // domain of all events
  W, R, F : set E, // writes, reads, fences
  IW : set E,      // initial writes
  NAL : set E,     // events accessing non-atomic locations
  sb : E->E,       // sequenced before
  ad,cd,dd : E->E, // address, control, data dependencies
  sthd : E->E,     // same thread (partial E.R.)
  sloc : E->E,     // same location (partial E.R.)
  stxn : E -> E,   // same transaction (partial E.R.)
  ftxn : E -> E,   // failed transaction (partial E.R.)
  //////////////////////////////////////
  rf : E->E,       // reads-from
  co : E->E,       // coherence order
}{
  // EV captures all and only the events involved
  W + R + F = EV

  // some reads and writes may access "non-atomic" locations
  NAL in (R + W)

  // fences are disjoint from accesses
  no ((R + W) & F)

  // initial events are ordinary writes
  IW in W - R

  // at most one initial write per location
  (IW -> IW) & sloc in iden

  // sequenced-before is intra-thread
  sb in sthd

  // sequenced-before is acyclic and transitive
  strict_partial_order[sb]

  /*
  // sequenced-before has the "N-free" property
  all a,b,c,d : EV | not (
	((b->d) + (a->d) + (a->c)) in sb and
      	no (((a->b) + (b->c) + (c->d)) & *sb))
  */

  // sequenced-before is total within a thread
  sthd in *sb + ~*sb

  // sthd is an equivalence relation among non-initial events
  is_equivalence[sthd, EV - IW]

  // loc is an equivalence relation among reads and writes
  is_equivalence[sloc, R + W]

  // naL contains zero or more sloc-classes
  NAL . sloc = NAL

  rf in sloc

  // co is acyclic and transitive
  strict_partial_order[co]

  // co is a union of strict total orders on writes, one per location
  // except for non-atomic locations, and it avoids writes that are in
  // failed transactions
  (co + ~co) = ((W - NAL) -> (W - NAL)) & sloc - iden

  // Event e2 has an "address dependency" on e1 if
  // location[e2] depends on valr[e1]. Therefore "(e1,e2) in ad"
  // only makes sense when e1 is a read and e2 is a read or a write
  // sequenced after e1.
  ad in (R -> (R + W)) & sb

  // Event e2 has a "data dependency" on e1 if valw[e2] depends
  // on valr[e1]. Therefore "(e1,e2) in data" only makes sense when
  // e1 is a read and e2 is a write sequenced after e1.
  dd in (R -> W) & sb

  // Event e2 has a "control dependency" on e1 if
  // valr[e1] is used to make a subsequent branching decision
  // and e2 follows that branch in program order. Therefore
  // "(e1,e2) in cd" only makes sense when e1 is a read and e2
  // is sequenced after e1.
  cd in (R -> EV) & sb

  // transactions are intra-thread
  stxn in sthd
  ftxn in sthd

  // stxn is a partial equivalence relation among a subset of
  // the non-initalisation events
  stxn in (EV - IW) -> (EV - IW)
  symmetric[stxn]
  transitive[stxn]

  // ftxn is a partial equivalence relation among a subset of
  // the non-initalisation events
  ftxn in (EV - IW) -> (EV - IW)
  symmetric[ftxn]
  transitive[ftxn]

  // no overlap between stxn and ftxn
  no stxn & ftxn

  // transactions must be contiguous
  ((sb.sb & stxn) . ~sb) & sb in stxn
  ((sb.sb & ftxn) . ~sb) & sb in ftxn

  // events sequenced after an failing transaction are control-
  // dependent on all the reads inside that ftxn
  (R & dom[ftxn]) <: (sb - ftxn) in cd

  // address/data dependencies cannot escape failing transactions
  no (dom[ftxn] <: ((ad + dd) - ftxn))
}

pred withinit[X:Exec] {
  // rf connects each read to exactly one write
  X.rf in X.W one -> X.R

  // for every event that accesses a location, there is
  // exactly one initial event at the same location
  all e : X.(R+W) | one (e.(X.sloc) & X.IW)

  // initial writes have no co-predecessor
  all e : X.IW | no e.~(X.co)
}

pred withoutinit[X:Exec] {
  // rf connects each read to at most one write
  X.rf in X.W lone -> X.R

  // there are no initial writes
  no X.IW
}

fun addsb[e:PTag->E, X:Exec, F:set E] : E->E {
  *(sb[e,X]) . (stor[F]) . *(sb[e,X]) }

// Perturbation Tags are an idea due to Daniel Lustig et al.
// (ASPLOS'17, http://dl.acm.org/citation.cfm?id=3037723)
abstract sig PTag {}
one sig rm_EV extends PTag {}
one sig rm_ad extends PTag {}
one sig rm_cd extends PTag {}
one sig rm_dd extends PTag {}
one sig rm_txn extends PTag {}

fun EV [e:PTag->E, X:Exec] : set E { X.EV - e[rm_EV] }
fun W [e:PTag->E, X:Exec] : set E { X.W - e[rm_EV] }
fun IW [e:PTag->E, X:Exec] : set E { X.IW - e[rm_EV] }
fun R [e:PTag->E, X:Exec] : set E { X.R - e[rm_EV] }
fun F [e:PTag->E, X:Exec] : set E { X.F - e[rm_EV] }
fun NAL [e:PTag->E, X:Exec] : set E { X.NAL - e[rm_EV] }

fun sb [e:PTag->E, X:Exec] : E->E {
  (univ - e[rm_EV]) <: X.sb :> (univ - e[rm_EV]) }
fun ad [e:PTag->E, X:Exec] : E->E {
  (univ - e[rm_EV] - e[rm_ad]) <: X.ad :> (univ - e[rm_EV]) }
fun dd [e:PTag->E, X:Exec] : E->E {
  (univ - e[rm_EV] - e[rm_dd]) <: X.dd :> (univ - e[rm_EV]) }
fun cd [e:PTag->E, X:Exec] : E->E {
  (univ - e[rm_EV] - e[rm_cd]) <: X.cd :> (univ - e[rm_EV]) }
fun sthd [e:PTag->E, X:Exec] : E->E {
  (univ - e[rm_EV]) <: X.sthd :> (univ - e[rm_EV]) }
fun sloc [e:PTag->E, X:Exec] : E->E {
  (univ - e[rm_EV]) <: X.sloc :> (univ - e[rm_EV]) }
fun stxn[e:PTag->E, X:Exec] : E->E {
  (univ - e[rm_EV] - e[rm_txn]) <: X.stxn :> (univ - e[rm_EV] - e[rm_txn]) }
fun ftxn[e:PTag->E, X:Exec] : E->E {
  (univ - e[rm_EV] - e[rm_txn]) <: X.ftxn :> (univ - e[rm_EV] - e[rm_txn]) }
fun rf [e:PTag->E, X:Exec] : E->E {
  (univ - e[rm_EV]) <: X.rf :> (univ - e[rm_EV]) }
fun co [e:PTag->E, X:Exec] : E->E {
  (univ - e[rm_EV]) <: X.co :> (univ - e[rm_EV]) }

// Well-formed transaction-order
pred wf_to[X:Exec, to:E->E] {

  // two transactional events in the same transaction
  // will *not* be ordered by "to"
  no (X.stxn & to)

  // two transactional events in different transactions
  // will be ordered (one way or t'other) by "to"
  (dom[X.stxn] -> dom[X.stxn]) - X.stxn = to + ~to

  // "to" is a strict partial order
  strict_partial_order[to]

}


Edit alloy model

Edit alloy model

module PowEnj
//SIGNATURES
sig Position{}
sig Email{}
sig Code{}

sig Plug{}

abstract sig Bool{}
sig False extends Bool{}
sig True extends Bool{}

abstract sig State{}
sig FreeState extends State{}
sig ReservedState extends State{}
sig RentedState extends State{}

sig DriverLicense{
	code:one Code,
	expiration:Int
}
{
	expiration>0
}

sig User
{
	payInfo: some PaymentMethod,
	position: one Position,
	license: one DriverLicense,
	email:one Email
}

sig Reservation{
	user:one User,
	time:Int,
	endTime:Int,
	car:one Car
}
{
	time>0
	endTime>time
}

sig Rent
{
	startTime: one  Int,
	endTime:one Int,
	endRent:one Bool,
	applyDiscount:one Int,
	applyOvertax:one Int,
	totalCost:Int,
	passengers:one  Int,
	reservation:one Reservation,
	payment:one PaymentMethod
}{
	passengers>=0
	startTime>0
	endTime>startTime
	applyOvertax>=0
	applyDiscount>=0
}

abstract sig Station{
	parkedCar:set Car,
	positoin:one Position
}

sig  Parking extends Station{
	distanceFromCharge:Int
}{
	distanceFromCharge>0
}

sig SafeArea extends Station
{
	pluggedCar: set Car,
	plugAvailable: set Plug,
}

sig PaymentMethod
{
	transactionCode: one Code
}

sig Car
{
	position:one Position,
	battery: Int,
	plate: one Code,
	state:one State,
	readyToEnd:one Bool
}{
	battery>=0 and battery<=100
}

//FACT

fact{
	//No useless paymentMethod
	User.payInfo=PaymentMethod
	//No useless Plug
	SafeArea.plugAvailable=Plug
	//No useless Email
	User.email=Email
	//No useless Position
	Car.position+User.position=Position
	//No useless Code
	Car.plate+PaymentMethod.transactionCode+DriverLicense.code=Code
	//No useless State
	Car.state=State
	//No useless Bool
	Rent.endRent=Bool
	//No useless License
	User.license=DriverLicense

	//No PaymentMethod with the same code
	all p1,p2:PaymentMethod| p1!=p2 implies p1.code!=p2.code
	//No car with the same plate
	all c1, c2: Car | c1!=c2 implies c1.plate!=c2.plate
	//No users with same email
	all u1,u2:User| u1!=u2 implies u1.email!=u2.email
	//No users with same license
	all u1,u2:User| u1!=u2 implies u1.license!=u2.license

	//No reservation for the same car in a time<1
	all r1,r2:Reservation | (r1!=r2 and r1.car=r2.car) implies (r1.time>r2.time+1 or r2.time>r1.time+1)

	//If a car is reserved is in reserved state
	all r:Reservation,c:Car,rent:Rent|  (r.car=c and  !(rent.endRent=False and rent.reservation.car=c)) implies c.state=ReservedState

	//if a car is in use is in rentedState
	all c:Car,r:Rent| r.reservation.car=c and r.endRent=False implies c.state=RentedState

	//if a car is not rented or reserved is in free state and a reservation keep going for max 1 hour
	all c:Car,rent:Rent,res:Reservation|
		//if the car is not reserved
		((res.car!=c
			or
				//or the reservation is expired
				(res.car=c and res.endTime>res.time+1))
		and
			//and there is no rent on the car
			(rent.reservation.car!=c
				or
					//or the rent is finished
					(rent.endRent=True and rent.reservation.car=c))) implies c.state=FreeState

	//A rent can be done only after a reservation
	all rent:Rent,res:Reservation| rent.reservation=res implies rent.startTime>res.time and rent.startTime<=res.time+1

	//Two different rent can't have the same reservation
	all r1,r2:Rent| r1!=r2 implies r1.reservation!=r2.reservation

	//There is just one rent not finish for each car
	all r1,r2:Rent|r1.endRent=False and r2.reservation.car=r1.reservation.car implies !(r2.endRent=False)

	//A rent can end only in a station
	all rent:Rent,c:Car,s:Station|rent.reservation.car=c and c.readyToEnd=True implies c.position=s.position

	//A rent has been concluded only in a station
	all rent:Rent,s:Station|rent.endRent=True implies rent.reservation.car.position=s.position

	//Discount for battery state applyed only if the rent in ended and the battery state is >50
	all rent:Rent| rent.reservation.car.battery>50 and rent.endRent=True implies rent.applyDiscount=20

	//Discount for passengers is applyed only if the rent is finished and more than 2 passengers were found
	all rent:Rent| rent.passengers>2 and rent.endRent=True implies rent.applyDiscount=20

	//All the cars parked are free
	all car:Car,s:Station| car.position=s.position and car.state=FreeState implies car in s.parkedCar

	//If a car is plugged is also parked
	all s:SafeArea,car:Car|car in s.pluggedCar implies car in s.parkedCar

	//the user get a discount parking and plugging the car
	all car:Car,s:SafeArea,r1,r2:Rent| car in s.parkedCar and car in s.pluggedCar implies r1.applyDiscount=30

	//Safe area overtax
	all car:Car,p:Parking, r1,r2:Rent | car in p.parkedCar and p.distanceFromCharge>3 implies r1.applyDiscount=0 and r1.applyOvertax=30

	all car:Car| car.state=FreeState implies car in Station.parkedCar

	no s:SafeArea| #s.pluggedCar>#s.parkedCar

	//Overtaxes are 0 or 30
	all rent:Rent| rent.applyOvertax=0 or rent.applyOvertax=30

	//the bill is calculate only if the rent is finish
	all rent:Rent| rent.applyOvertax>0 or rent.applyDiscount>0 implies rent.endRent=True
}

//ASSUMPTION

//A car can be reused after a rent
assert CarReused{
	all r1,r2:Rent| r1.endRent=True and r2.endRent=False and r1.reservation.car= r2.reservation.car implies r2.startTime>r1.endTime
}

//There are as many driver license as users
assert DriverForEachDocument{
	#DriverLicense = #User
	#User=#Email
}

assert UserPaymentMethod{
	#User.payInfo<=#PaymentMethod
}

//The rent with taxes can't have a discount
assert RentOverTaxes{
	all rent:Rent| rent.applyOvertax>0 implies rent.applyDiscount<rent.applyOvertax
}

//the plugged car can't be in use
assert PluggedCar{
	all rent:Rent| rent.reservation.car in SafeArea.pluggedCar implies !rent.endRent=False
}

check PluggedCar

check RentOverTaxes

check UserPaymentMethod

check CarReused for 5

check DriverForEachDocument for 5

pred SimpleWorld
{
	#User <3
	#Car < 4
	#Station< 4
	#Reservation < 4
	#Rent <3
}

pred RealWorld
{
	#User > 2
	#Car > 3
	#SafeArea> 1
	#Parking > 2
	#Reservation > 2
	#Rent > 1
}

run SimpleWorld for 6

run RealWorld for 6

module PowEnj
//SIGNATURES
sig Position{}
sig Email{}
sig Code{}

sig Plug{}

abstract sig Bool{}
sig False extends Bool{}
sig True extends Bool{}

abstract sig State{}
sig FreeState extends State{}
sig ReservedState extends State{}
sig RentedState extends State{}

sig DriverLicense{
	code:one Code,
	expiration:Int
}
{
	expiration>0
}

sig User
{
	payInfo: some PaymentMethod,
	position: one Position,
	license: one DriverLicense,
	email:one Email
}

sig Reservation{
	user:one User,
	time:Int,
	endTime:Int,
	car:one Car
}
{
	time>0
	endTime>time
}

sig Rent
{
	startTime: one  Int,
	endTime:one Int,
	endRent:one Bool,
	applyDiscount:one Int,
	applyOvertax:one Int,
	totalCost:Int,
	passengers:one  Int,
	reservation:one Reservation,
	payment:one PaymentMethod
}{
	passengers>=0
	startTime>0
	endTime>startTime
	applyOvertax>=0
	applyDiscount>=0
}

abstract sig Station{
	parkedCar:set Car,
	positoin:one Position
}

sig  Parking extends Station{
	distanceFromCharge:Int
}{
	distanceFromCharge>0
}

sig SafeArea extends Station
{
	pluggedCar: set Car,
	plugAvailable: set Plug,
}

sig PaymentMethod
{
	transactionCode: one Code
}

sig Car
{
	position:one Position,
	battery: Int,
	plate: one Code,
	state:one State,
	readyToEnd:one Bool
}{
	battery>=0 and battery<=100
}

//FACT

fact{
	//No useless paymentMethod
	User.payInfo=PaymentMethod
	//No useless Plug
	SafeArea.plugAvailable=Plug
	//No useless Email
	User.email=Email
	//No useless Position
	Car.position+User.position=Position
	//No useless Code
	Car.plate+PaymentMethod.transactionCode+DriverLicense.code=Code
	//No useless State
	Car.state=State
	//No useless Bool
	Rent.endRent=Bool
	//No useless License
	User.license=DriverLicense

	//No PaymentMethod with the same code
	all p1,p2:PaymentMethod| p1!=p2 implies p1.code!=p2.code
	//No car with the same plate
	all c1, c2: Car | c1!=c2 implies c1.plate!=c2.plate
	//No users with same email
	all u1,u2:User| u1!=u2 implies u1.email!=u2.email
	//No users with same license
	all u1,u2:User| u1!=u2 implies u1.license!=u2.license

	//No reservation for the same car in a time<1
	all r1,r2:Reservation | (r1!=r2 and r1.car=r2.car) implies (r1.time>r2.time+1 or r2.time>r1.time+1)

	//If a car is reserved is in reserved state
	all r:Reservation,c:Car,rent:Rent|  (r.car=c and  !(rent.endRent=False and rent.reservation.car=c)) implies c.state=ReservedState

	//if a car is in use is in rentedState
	all c:Car,r:Rent| r.reservation.car=c and r.endRent=False implies c.state=RentedState

	//if a car is not rented or reserved is in free state and a reservation keep going for max 1 hour
	all c:Car,rent:Rent,res:Reservation|
		//if the car is not reserved
		((res.car!=c
			or
				//or the reservation is expired
				(res.car=c and res.endTime>res.time+1))
		and
			//and there is no rent on the car
			(rent.reservation.car!=c
				or
					//or the rent is finished
					(rent.endRent=True and rent.reservation.car=c))) implies c.state=FreeState

	//A rent can be done only after a reservation
	all rent:Rent,res:Reservation| rent.reservation=res implies rent.startTime>res.time and rent.startTime<=res.time+1

	//Two different rent can't have the same reservation
	all r1,r2:Rent| r1!=r2 implies r1.reservation!=r2.reservation

	//There is just one rent not finish for each car
	all r1,r2:Rent|r1.endRent=False and r2.reservation.car=r1.reservation.car implies !(r2.endRent=False)

	//A rent can end only in a station
	all rent:Rent,c:Car,s:Station|rent.reservation.car=c and c.readyToEnd=True implies c.position=s.position

	//A rent has been concluded only in a station
	all rent:Rent,s:Station|rent.endRent=True implies rent.reservation.car.position=s.position

	//Discount for battery state applyed only if the rent in ended and the battery state is >50
	all rent:Rent| rent.reservation.car.battery>50 and rent.endRent=True implies rent.applyDiscount=20

	//Discount for passengers is applyed only if the rent is finished and more than 2 passengers were found
	all rent:Rent| rent.passengers>2 and rent.endRent=True implies rent.applyDiscount=20

	//All the cars parked are free
	all car:Car,s:Station| car.position=s.position and car.state=FreeState implies car in s.parkedCar

	//If a car is plugged is also parked
	all s:SafeArea,car:Car|car in s.pluggedCar implies car in s.parkedCar

	//the user get a discount parking and plugging the car
	all car:Car,s:SafeArea,r1,r2:Rent| car in s.parkedCar and car in s.pluggedCar implies r1.applyDiscount=30

	//Safe area overtax
	all car:Car,p:Parking, r1,r2:Rent | car in p.parkedCar and p.distanceFromCharge>3 implies r1.applyDiscount=0 and r1.applyOvertax=30

	no s:SafeArea| #s.pluggedCar>#s.parkedCar

	//Overtaxes are 0 or 30
	all rent:Rent| rent.applyOvertax=0 or rent.applyOvertax=30

	all rent:Rent| rent.applyOvertax>0 or rent.applyDiscount>0 implies rent.endRent=True
}

//ASSUMPTION

//A car can be reused after a rent
assert CarReused{
	all r1,r2:Rent| r1.endRent=True and r2.endRent=False and r1.reservation.car= r2.reservation.car implies r2.startTime>r1.endTime
}

//There are as many driver license as users
assert DriverForEachDocument{
	#DriverLicense = #User
	#User=#Email
}

assert UserPaymentMethod{
	#User.payInfo<=#PaymentMethod
}

//The rent with taxes can't have a discount
assert RentOverTaxes{
	all rent:Rent| rent.applyOvertax>0 implies rent.applyDiscount<rent.applyOvertax
}

//the plugged car can't be in use
assert PluggedCar{
	all rent:Rent| rent.reservation.car in SafeArea.pluggedCar implies !rent.endRent=False
}

check PluggedCar

check RentOverTaxes

check UserPaymentMethod

check CarReused for 5

check DriverForEachDocument for 5

pred SimpleWorld
{
	#User <3
	#Car < 4
	#Station< 4
	#Reservation < 4
	#Rent <3
}

pred RealWorld
{
	#User > 2
	#Car > 3
	#SafeArea> 1
	#Parking > 2
	#Reservation > 2
	#Rent > 1
}

run SimpleWorld for 6

run RealWorld for 6


tightened types to help the solver

tightened types to help the solver

/****************************************************/
/* Inclusion checking code.                         */
/* Template: ./alloy/checkTemplate.als              */
/****************************************************/

pred histIncl() {
  all dom, dom' : set Action,
      kind, kind' : Action -> Kind,
      gloc, gloc' : Action -> Glob,
      lloc, lloc' : Action -> Thr,
      callmap, retmap : Thr -> Val,
      wv, rv : Action -> Val,
      sb, sb' : Action -> Action,
      hb, mo, rf, guar, deny : Action -> Action
    when {
      // Optimisation definition
      optPred[dom, dom', kind, kind', gloc, gloc', lloc, lloc', ^sb, ^sb']

      // Enforce validity for LHS
      valid[dom, kind, gloc, lloc, callmap, retmap, wv, rv, ^hb, ^sb, mo, rf]

      // Interfaces are the same
      Extern & dom = Extern & dom'
      Extern <: gloc = Extern <: gloc'
      Extern <: kind = Extern <: kind'

      // Nonatomics disabled
      // DRF[dom, kind, loc, wv, rv, ^hb, ^sb, mo, rf]

      guar = getguar[dom, ^hb]
      deny = getdeny[dom, kind, gloc, wv, rv, ^hb, ^sb, mo, rf]

      // Cut irrelevant executions.
      cutR[dom, kind, gloc, wv, rv, ^hb, ^sb, mo, rf]
      cutW[dom, kind, gloc, wv, rv, ^hb, ^sb, mo, rf]

      // Sanity conditions
      Action = dom + dom'
      Loc = dom.(lloc + gloc) + dom'.(lloc' + gloc')

      // Make the relations nicer to display
      is_core[hb]
      is_core[sb]
      is_core[sb']
  } |
  some wvi, rvi : Intern -> Val,
       mo', rf' : Action -> Action | {
   let hb' = ^(sb' + rf'),
       wv' = wvi + (Extern <: wv),
       rv' = rvi + (Extern <: rv) | {

      // Enforce validity for RHS
      valid[dom', kind', gloc', lloc', callmap, retmap, wv', rv', ^hb', ^sb', mo', rf']

      // Atomics disabled
      //DRF[dom', kind', loc', wv', rv', ^hb', sb', mo', rf']

      // Histories are related
      getguar[dom', ^hb'] in guar
      getdeny[dom', kind', gloc', wv', rv', ^hb', ^sb', mo', rf'] in deny
    }
  }
}

// check { histIncl } for 7

/****************************************************/
/* Debugging code.                                  */
/* Generate LHS / RHS of the inclusion.             */
/****************************************************/

// pred histInclRun() {
//   some dom, dom' : set Action, kind, kind' : Action -> Kind,
//        gloc, gloc', lloc, lloc' : Action -> Loc,
//        callmap, retmap : Thr -> Val,
//        wv, rv : Action -> Val,
//        sb, sb' : Action -> Action,
//        hb, mo, rf, guar, deny : Action -> Action,
//        wvi, rvi : Intern -> Val,
//        mo', rf' : Action -> Action | {
//    let hb' = ^(sb' + rf'),
//        wv' = wvi + (Extern <: wv),
//        rv' = rvi + (Extern <: rv) | {
//       // Optimisation definition
//       optPred[dom, dom', kind, kind', gloc, gloc', lloc, lloc', ^sb, ^sb']
//
//       valid[dom, kind, gloc, lloc, callmap, retmap, wv, rv, ^hb, ^sb, mo, rf]
//
//       // Nonatomics disabled
//       // DRF[dom, kind, loc, wv, rv, ^hb, ^sb, mo, rf]
//
//       guar = getguar[dom, ^hb]
//       deny = getdeny[dom, kind, gloc, wv, rv, ^hb, ^sb, mo, rf]
//
//       // Cut irrelevant executions.
//       cutR[dom, kind, gloc, wv, rv, ^hb, ^sb, mo, rf]
//       cutW[dom, kind, gloc, wv, rv, ^hb, ^sb, mo, rf]
//
//       // Sanity conditions
//       Action = dom + dom'
//       Loc = dom.(lloc + gloc) + dom'.(lloc' + gloc')
//
//       // Make the relations nicer to display
//       is_core[hb]
//       is_core[sb]
//       is_core[sb']
//
//       // one Call & (dom + dom')
//       // one Ret & (dom + dom')
//
//       // // Pre-execution structure
//       // preexecWF[dom, kind, gloc, lloc, sb]
//       // preexecWF[dom', kind', gloc', lloc', ^sb']
//
//       Extern & dom = Extern & dom'
//       Extern <: gloc = Extern <: gloc'
//       Extern <: kind = Extern <: kind'
//       valid[dom', kind', gloc', lloc', callmap, retmap, wv', rv', ^hb', ^sb', mo', rf']
//
//       // Atomics disabled
//       //DRF[dom', kind', loc', wv', rv', ^hb', ^sb', mo', rf']
//
//       getguar[dom', ^hb'] in guar
//       getdeny[dom', kind', gloc', wv', rv', ^hb', ^sb', mo', rf'] in deny
//     }
//   }
// }
//
// pred histInclRunLHS() {
//   some dom : set Action, kind : Action -> Kind,
//        gloc, lloc : Action -> Loc,
//        callmap, retmap : Thr -> Val,
//        wv, rv : Action -> Val,
//        sb : Action -> Action,
//        hb, mo, rf, guar, deny : Action -> Action,
//        x: Glob, l : Thr | {
//       // Optimisation definition
//       optLHS[dom - Extern, kind, gloc, lloc, ^sb, x, l]
//       preexecWF[dom, kind, gloc, lloc, sb]
//       one Call & dom
//       one Ret & dom
//
//       valid[dom, kind, gloc, lloc, callmap, retmap, wv, rv, ^hb, ^sb, mo, rf]
//
//       // Nonatomics disabled
//       // DRF[dom, kind, loc, wv, rv, ^hb, ^sb, mo, rf]
//
//       guar = getguar[dom, ^hb]
//       deny = getdeny[dom, kind, gloc, wv, rv, ^hb, ^sb, mo, rf]
//
//       // Cut irrelevant executions.
//       cutR[dom, kind, gloc, wv, rv, ^hb, ^sb, mo, rf]
//       cutW[dom, kind, gloc, wv, rv, ^hb, ^sb, mo, rf]
//
//       // Sanity conditions
//       Action = dom
//       Loc = dom.(lloc + gloc)
//
//       // Make the relations nicer to display
//       is_core[hb]
//       is_core[sb]
//   }
// }

//run { histInclRun } for 4
//run { histInclRunLHS } for 6

/****************************************************/
/* Inclusion checking code.                         */
/* Template: ./alloy/checkTemplate.als              */
/****************************************************/

pred histIncl() {
  all dom, dom' : set Action, kind, kind' : Action -> Kind,
      gloc, gloc', lloc, lloc' : Action -> Loc,
      callmap, retmap : Thr -> Val,
      wv, rv : Action -> Val,
      sb, sb' : Action -> Action,
      hb, mo, rf, guar, deny : Action -> Action
    when {
      // Optimisation definition
      optPred[dom, dom', kind, kind', gloc, gloc', lloc, lloc', ^sb, ^sb']

      // Enforce validity for LHS
      valid[dom, kind, gloc, lloc, callmap, retmap, wv, rv, ^hb, ^sb, mo, rf]

      // Interfaces are the same
      Extern & dom = Extern & dom'
      Extern <: gloc = Extern <: gloc'
      Extern <: kind = Extern <: kind'

      // Nonatomics disabled
      // DRF[dom, kind, loc, wv, rv, ^hb, ^sb, mo, rf]

      guar = getguar[dom, ^hb]
      deny = getdeny[dom, kind, gloc, wv, rv, ^hb, ^sb, mo, rf]

      // Cut irrelevant executions.
      cutR[dom, kind, gloc, wv, rv, ^hb, ^sb, mo, rf]
      cutW[dom, kind, gloc, wv, rv, ^hb, ^sb, mo, rf]

      // Sanity conditions
      Action = dom + dom'
      Loc = dom.(lloc + gloc) + dom'.(lloc' + gloc')

      // Make the relations nicer to display
      is_core[hb]
      is_core[sb]
      is_core[sb']
  } |
  some wvi, rvi : Intern -> Val,
       mo', rf' : Action -> Action | {
   let hb' = ^(sb' + rf'),
       wv' = wvi + (Extern <: wv),
       rv' = rvi + (Extern <: rv) | {

      // Enforce validity for RHS
      valid[dom', kind', gloc', lloc', callmap, retmap, wv', rv', ^hb', ^sb', mo', rf']

      // Atomics disabled
      //DRF[dom', kind', loc', wv', rv', ^hb', sb', mo', rf']

      // Histories are related
      getguar[dom', ^hb'] in guar
      getdeny[dom', kind', gloc', wv', rv', ^hb', ^sb', mo', rf'] in deny
    }
  }
}

// check { histIncl } for 7

/****************************************************/
/* Debugging code.                                  */
/* Generate LHS / RHS of the inclusion.             */
/****************************************************/

// pred histInclRun() {
//   some dom, dom' : set Action, kind, kind' : Action -> Kind,
//        gloc, gloc', lloc, lloc' : Action -> Loc,
//        callmap, retmap : Thr -> Val,
//        wv, rv : Action -> Val,
//        sb, sb' : Action -> Action,
//        hb, mo, rf, guar, deny : Action -> Action,
//        wvi, rvi : Intern -> Val,
//        mo', rf' : Action -> Action | {
//    let hb' = ^(sb' + rf'),
//        wv' = wvi + (Extern <: wv),
//        rv' = rvi + (Extern <: rv) | {
//       // Optimisation definition
//       optPred[dom, dom', kind, kind', gloc, gloc', lloc, lloc', ^sb, ^sb']
//
//       valid[dom, kind, gloc, lloc, callmap, retmap, wv, rv, ^hb, ^sb, mo, rf]
//
//       // Nonatomics disabled
//       // DRF[dom, kind, loc, wv, rv, ^hb, ^sb, mo, rf]
//
//       guar = getguar[dom, ^hb]
//       deny = getdeny[dom, kind, gloc, wv, rv, ^hb, ^sb, mo, rf]
//
//       // Cut irrelevant executions.
//       cutR[dom, kind, gloc, wv, rv, ^hb, ^sb, mo, rf]
//       cutW[dom, kind, gloc, wv, rv, ^hb, ^sb, mo, rf]
//
//       // Sanity conditions
//       Action = dom + dom'
//       Loc = dom.(lloc + gloc) + dom'.(lloc' + gloc')
//
//       // Make the relations nicer to display
//       is_core[hb]
//       is_core[sb]
//       is_core[sb']
//
//       // one Call & (dom + dom')
//       // one Ret & (dom + dom')
//
//       // // Pre-execution structure
//       // preexecWF[dom, kind, gloc, lloc, sb]
//       // preexecWF[dom', kind', gloc', lloc', ^sb']
//
//       Extern & dom = Extern & dom'
//       Extern <: gloc = Extern <: gloc'
//       Extern <: kind = Extern <: kind'
//       valid[dom', kind', gloc', lloc', callmap, retmap, wv', rv', ^hb', ^sb', mo', rf']
//
//       // Atomics disabled
//       //DRF[dom', kind', loc', wv', rv', ^hb', ^sb', mo', rf']
//
//       getguar[dom', ^hb'] in guar
//       getdeny[dom', kind', gloc', wv', rv', ^hb', ^sb', mo', rf'] in deny
//     }
//   }
// }
//
// pred histInclRunLHS() {
//   some dom : set Action, kind : Action -> Kind,
//        gloc, lloc : Action -> Loc,
//        callmap, retmap : Thr -> Val,
//        wv, rv : Action -> Val,
//        sb : Action -> Action,
//        hb, mo, rf, guar, deny : Action -> Action,
//        x: Glob, l : Thr | {
//       // Optimisation definition
//       optLHS[dom - Extern, kind, gloc, lloc, ^sb, x, l]
//       preexecWF[dom, kind, gloc, lloc, sb]
//       one Call & dom
//       one Ret & dom
//
//       valid[dom, kind, gloc, lloc, callmap, retmap, wv, rv, ^hb, ^sb, mo, rf]
//
//       // Nonatomics disabled
//       // DRF[dom, kind, loc, wv, rv, ^hb, ^sb, mo, rf]
//
//       guar = getguar[dom, ^hb]
//       deny = getdeny[dom, kind, gloc, wv, rv, ^hb, ^sb, mo, rf]
//
//       // Cut irrelevant executions.
//       cutR[dom, kind, gloc, wv, rv, ^hb, ^sb, mo, rf]
//       cutW[dom, kind, gloc, wv, rv, ^hb, ^sb, mo, rf]
//
//       // Sanity conditions
//       Action = dom
//       Loc = dom.(lloc + gloc)
//
//       // Make the relations nicer to display
//       is_core[hb]
//       is_core[sb]
//   }
// }

//run { histInclRun } for 4
//run { histInclRunLHS } for 6


ptags

ptags

module exec[E]
open relations[E]

sig Exec {
  EV : set E,      // domain of all events
  W, R, F : set E, // writes, reads, fences
  IW : set E,      // initial writes
  NAL : set E,     // events accessing non-atomic locations
  sb : E->E,       // sequenced before
  ad,cd,dd : E->E, // address, control, data dependencies
  sthd : E->E,     // same thread (partial E.R.)
  sloc : E->E,     // same location (partial E.R.)
  //////////////////////////////////////
  rf : E->E,       // reads-from
  co : E->E,       // coherence order
}{
  // EV captures all and only the events involved
  W + R + F = EV

  // some reads and writes may access "non-atomic" locations
  NAL in (R + W)

  // fences are disjoint from accesses
  no ((R + W) & F)

  // initial events are ordinary writes
  IW in W - R

  // at most one initial write per location
  (IW -> IW) & sloc in iden

  // sequenced-before is intra-thread
  sb in sthd

  // sequenced-before is acyclic and transitive
  strict_partial_order[sb]

  /*
  // sequenced-before has the "N-free" property
  all a,b,c,d : EV | not (
	((b->d) + (a->d) + (a->c)) in sb and
      	no (((a->b) + (b->c) + (c->d)) & *sb))
  */

  // sequenced-before is total within a thread
  sthd in *sb + ~*sb

  // sthd is an equivalence relation among non-initial events
  is_equivalence[sthd, EV - IW]

  // loc is an equivalence relation among reads and writes
  is_equivalence[sloc, R + W]

  // naL contains zero or more sloc-classes
  NAL . sloc = NAL

  rf in sloc

  // co is acyclic and transitive
  strict_partial_order[co]

  // co is a union, over all atomic locations x, of strict
  // total orders on writes to x
  (co + ~co) = ((W - NAL) -> (W - NAL)) & sloc - iden

  // Event e2 has an "address dependency" on e1 if
  // location[e2] depends on valr[e1]. Therefore "(e1,e2) in ad"
  // only makes sense when e1 is a read and e2 is a read or a write
  // sequenced after e1.
  ad in (R -> (R + W)) & sb

  // Event e2 has a "data dependency" on e1 if valw[e2] depends
  // on valr[e1]. Therefore "(e1,e2) in data" only makes sense when
  // e1 is a read and e2 is a write sequenced after e1.
  dd in (R -> W) & sb

  // Event e2 has a "control dependency" on e1 if
  // valr[e1] is used to make a subsequent branching decision
  // and e2 follows that branch in program order. Therefore
  // "(e1,e2) in cd" only makes sense when e1 is a read and e2
  // is sequenced after e1.
  cd in (R -> EV) & sb

}

pred withinit[X:Exec] {
  // rf connects each read to exactly one write
  X.rf in X.W one -> X.R

  // for every event that accesses a location, there is
  // exactly one initial event at the same location
  all e : X.(R+W) | one (e.(X.sloc) & X.IW)

  // initial writes have no co-predecessor
  all e : X.IW | no e.~(X.co)
}

pred withoutinit[X:Exec] {
  // rf connects each read to at most one write
  X.rf in X.W lone -> X.R

  // there are no initial writes
  no X.IW
}

fun addsb[e:PTag->E, X:Exec, F:set E] : E->E {
  *(sb[e,X]) . (stor[F]) . *(sb[e,X]) }

// Perturbation Tags are an idea due to Daniel Lustig et al.
// (ASPLOS'17, http://dl.acm.org/citation.cfm?id=3037723)
abstract sig PTag {}
one sig rm_EV extends PTag {}
one sig rm_ad extends PTag {}
one sig rm_cd extends PTag {}
one sig rm_dd extends PTag {}

fun EV [e:PTag->E, X:Exec] : set E { X.EV - e[rm_EV] }
fun W [e:PTag->E, X:Exec] : set E { X.W - e[rm_EV] }
fun IW [e:PTag->E, X:Exec] : set E { X.IW - e[rm_EV] }
fun R [e:PTag->E, X:Exec] : set E { X.R - e[rm_EV] }
fun F [e:PTag->E, X:Exec] : set E { X.F - e[rm_EV] }
fun NAL [e:PTag->E, X:Exec] : set E { X.NAL - e[rm_EV] }

fun sb [e:PTag->E, X:Exec] : E->E {
  (univ - e[rm_EV]) <: X.sb :> (univ - e[rm_EV]) }
fun ad [e:PTag->E, X:Exec] : E->E {
  (univ - e[rm_EV] - e[rm_ad]) <: X.ad :> (univ - e[rm_EV]) }
fun dd [e:PTag->E, X:Exec] : E->E {
  (univ - e[rm_EV] - e[rm_dd]) <: X.dd :> (univ - e[rm_EV]) }
fun cd [e:PTag->E, X:Exec] : E->E {
  (univ - e[rm_EV] - e[rm_cd]) <: X.cd :> (univ - e[rm_EV]) }
fun sthd [e:PTag->E, X:Exec] : E->E {
  (univ - e[rm_EV]) <: X.sthd :> (univ - e[rm_EV]) }
fun sloc [e:PTag->E, X:Exec] : E->E {
  (univ - e[rm_EV]) <: X.sloc :> (univ - e[rm_EV]) }
fun rf [e:PTag->E, X:Exec] : E->E {
  (univ - e[rm_EV]) <: X.rf :> (univ - e[rm_EV]) }
fun co [e:PTag->E, X:Exec] : E->E {
  (univ - e[rm_EV]) <: X.co :> (univ - e[rm_EV]) }

module exec[E]
open relations[E]

sig Exec {
  EV : set E,      // domain of all events
  W, R, F : set E, // writes, reads, fences
  IW : set E,      // initial writes
  NAL : set E,     // events accessing non-atomic locations
  sb : E->E,       // sequenced before
  ad,cd,dd : E->E, // address, control, data dependencies
  sthd : E->E,     // same thread (partial E.R.)
  sloc : E->E,     // same location (partial E.R.)
  //////////////////////////////////////
  rf : E->E,       // reads-from
  co : E->E,       // coherence order
}{
  // EV captures all and only the events involved
  W + R + F = EV

  // some reads and writes may access "non-atomic" locations
  NAL in (R + W)

  // fences are disjoint from accesses
  no ((R + W) & F)

  // initial events are ordinary writes
  IW in W - R

  // at most one initial write per location
  (IW -> IW) & sloc in iden

  // sequenced-before is intra-thread
  sb in sthd

  // sequenced-before is acyclic and transitive
  strict_partial_order[sb]

  /*
  // sequenced-before has the "N-free" property
  all a,b,c,d : EV | not (
	((b->d) + (a->d) + (a->c)) in sb and
      	no (((a->b) + (b->c) + (c->d)) & *sb))
  */

  // sequenced-before is total within a thread
  sthd in *sb + ~*sb

  // sthd is an equivalence relation among non-initial events
  is_equivalence[sthd, EV - IW]

  // loc is an equivalence relation among reads and writes
  is_equivalence[sloc, R + W]

  // naL contains zero or more sloc-classes
  NAL . sloc = NAL

  rf in sloc

  // co is acyclic and transitive
  strict_partial_order[co]

  // co is a union, over all atomic locations x, of strict
  // total orders on writes to x
  (co + ~co) = ((W - NAL) -> (W - NAL)) & sloc - iden

  // Event e2 has an "address dependency" on e1 if
  // location[e2] depends on valr[e1]. Therefore "(e1,e2) in ad"
  // only makes sense when e1 is a read and e2 is a read or a write
  // sequenced after e1.
  ad in (R -> (R + W)) & sb

  // Event e2 has a "data dependency" on e1 if valw[e2] depends
  // on valr[e1]. Therefore "(e1,e2) in data" only makes sense when
  // e1 is a read and e2 is a write sequenced after e1.
  dd in (R -> W) & sb

  // Event e2 has a "control dependency" on e1 if
  // valr[e1] is used to make a subsequent branching decision
  // and e2 follows that branch in program order. Therefore
  // "(e1,e2) in cd" only makes sense when e1 is a read and e2
  // is sequenced after e1.
  cd in (R -> EV) & sb

}

pred withinit[X:Exec] {
  // rf connects each read to exactly one write
  X.rf in X.W one -> X.R

  // for every event that accesses a location, there is
  // exactly one initial event at the same location
  all e : X.(R+W) | one (e.(X.sloc) & X.IW)

  // initial writes have no co-predecessor
  all e : X.IW | no e.~(X.co)
}

pred withoutinit[X:Exec] {
  // rf connects each read to at most one write
  X.rf in X.W lone -> X.R

  // there are no initial writes
  no X.IW
}

fun addsb[e:PTag->E, X:Exec, F:set E] : E->E {
  *(sb[e,X]) . (stor[F]) . *(sb[e,X]) }

abstract sig PTag {} // Perturbation Tag
one sig rm_EV extends PTag {}
one sig rm_ad extends PTag {}
one sig rm_cd extends PTag {}
one sig rm_dd extends PTag {}

fun EV [e:PTag->E, X:Exec] : set E { X.EV - e[rm_EV] }
fun W [e:PTag->E, X:Exec] : set E { X.W - e[rm_EV] }
fun IW [e:PTag->E, X:Exec] : set E { X.IW - e[rm_EV] }
fun R [e:PTag->E, X:Exec] : set E { X.R - e[rm_EV] }
fun F [e:PTag->E, X:Exec] : set E { X.F - e[rm_EV] }
fun NAL [e:PTag->E, X:Exec] : set E { X.NAL - e[rm_EV] }

fun sb [e:PTag->E, X:Exec] : E->E {
  (univ - e[rm_EV]) <: X.sb :> (univ - e[rm_EV]) }
fun ad [e:PTag->E, X:Exec] : E->E {
  (univ - e[rm_EV] - e[rm_ad]) <: X.ad :> (univ - e[rm_EV]) }
fun dd [e:PTag->E, X:Exec] : E->E {
  (univ - e[rm_EV] - e[rm_dd]) <: X.dd :> (univ - e[rm_EV]) }
fun cd [e:PTag->E, X:Exec] : E->E {
  (univ - e[rm_EV] - e[rm_cd]) <: X.cd :> (univ - e[rm_EV]) }
fun sthd [e:PTag->E, X:Exec] : E->E {
  (univ - e[rm_EV]) <: X.sthd :> (univ - e[rm_EV]) }
fun sloc [e:PTag->E, X:Exec] : E->E {
  (univ - e[rm_EV]) <: X.sloc :> (univ - e[rm_EV]) }
fun rf [e:PTag->E, X:Exec] : E->E {
  (univ - e[rm_EV]) <: X.rf :> (univ - e[rm_EV]) }
fun co [e:PTag->E, X:Exec] : E->E {
  (univ - e[rm_EV]) <: X.co :> (univ - e[rm_EV]) }


refactor

refactor

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

abstract sig Region {
	index: Int
}
sig Col extends Region {
  cell: Row -> Color
}{
	index >= 0
	index <= 9
}
sig Row extends Region {}{
	index >= 0
	index <= 9
}

fact {
	all r: Col - last {
		add[r.index, 1] = r.next.index
	}
	all r: Row - last {
		add[r.index, 1] = r.next.index
	}
}

enum Color { Black, White }

fact {
  all c: Col, r: Row | one cell [c, r]
}

-- both Row and Col
pred prev_is_white(c: Col, r: Row, prev: Region->Region) {
	// トリック: prevがCol->ColでもRowに使ってよい
	// なぜなら空集合が返るのでin Whiteが成立するから
	cell[prev[c], r] + cell[c, prev[r]] in White
}

pred no_prev(c: Col, r: Row, prev: Region->Region) {
	// トリック: nextがCol->ColでもRowに使ってよい
	// なぜなら空集合が返るのでnoが成立するから
	no prev[c] and no prev[r]
}

// c, rがブロックの先頭であるかどうか
pred is_black_head(c: Col, r: Row, prev: Region->Region) {
	// 最初のRowであるか、または前のRowのセルが白い
  no_prev[c, r, prev] or prev_is_white[c, r, prev]
	// このセルは黒い
  cell[c, r] in Black
}
fun range(start, end: Region, next: Region -> Region): Region{
	start.*next - end.^next
}

fun get_block_end(start: Region, size: Int): Region{
	plus[start.index, minus[size, 1]][index]
}

-- about rows

fun headsInRow (r: Row): set Col {
  { c: Col | blackHeadInRow[c, r] }
}

fact noOtherHeadsInRow {
  no c: Col, r: Row | c not in headsInRow[r] and blackHeadInRow[c, r]
}

pred headsSeqInRow (r: Row, s: seq Col) {
  s.elems = headsInRow[r]
  all i: s.butlast.inds | lt [s[i], s[plus[i, 1]]]
}

fun Int2Row (i: Int): Row {
	index.i & Row
}

pred rowHint (j: Int, sizes: seq Int) {
  let r = Int2Row[j] | some cs: seq Col {
    #sizes = #cs
    // csは黒ブロックの先頭の位置のソートされたシークエンス
    headsSeqInRow [r, cs]
    all i: sizes.inds {
      // cs[i]をstart, startの位置にsize[i]を足して1を引いた位置にあるColをendと呼ぶ
      let start = cs [i], end = Col & get_block_end[start, sizes[i]] {

        // endが存在する
        some end
        // startからendまで全部黒
        all c: range[start, end, cols/next] | cell [c, r] in Black
        // endの次がないか、または白
        no end.next or cell [end.next, r] in White
      }
    }
  }
}

pred blackHeadInCol (c: Col, r: Row) {
	is_black_head[c, r, rows/prev]
}
pred blackHeadInRow (c: Col, r: Row) {
	is_black_head[c, r, cols/prev]
}

-- about cols
// Col cの中の、ブロックの頭であるRowの集合
fun headsInCol (c: Col): set Row {
  { r: Row | blackHeadInCol[c, r] }
}

fact noOtherHeadsInCol {
  no c: Col, r: Row | r not in headsInCol[c] and blackHeadInCol[c, r]
}

pred headsSeqInCol (c: Col, s: seq Row) {
	// sの要素はブロック先頭の集合と同一
  s.elems = headsInCol[c]
	// sは単調増加
  all i: s.butlast.inds | lt [s[i], s[plus[i, 1]]]
}

fun Int2Col (i: Int): Col {
	index.i & Col
}

pred colHint (j: Int, sizes: seq Int) {
  let c = Int2Col[j] | some rs: seq Row {
    #sizes = #rs
    headsSeqInCol [c, rs]
    all i: sizes.inds {
      let start = rs [i], end = Row & get_block_end[start, sizes[i]] {
      	some end
      	all r: range[start, end, rows/next] | cell [c, r] in Black
      	no end.next or cell [c, end.next] in White
    	}
		}
  }
}
-- riddle from http://homepage1.nifty.com/sabo10/rulelog/illust.html
solve: run {
  rowHint [0, 0 -> 3]
  rowHint [1, 0 -> 2 + 1 -> 2]
  rowHint [2, 0 -> 1 + 1 -> 1 + 2 -> 1]
  rowHint [3, 0 -> 3 + 1 -> 3]
  rowHint [4, 0 -> 5]
  rowHint [5, 0 -> 7]
  rowHint [6, 0 -> 7]
  rowHint [7, 0 -> 7]
  rowHint [8, 0 -> 7]
  rowHint [9, 0 -> 5]

  colHint [0, 0 -> 4]
  colHint [1, 0 -> 6]
  colHint [2, 0 -> 7]
  colHint [3, 0 -> 9]
  colHint [4, 0 -> 2 + 1 -> 7]
  colHint [5, 0 -> 1 + 1 -> 6]
  colHint [6, 0 -> 2 + 1 -> 4]
  colHint [7, 0 -> 3]
  colHint [8, 0 -> 1]
  colHint [9, 0 -> 2]
} for 10 but 5 Int

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

abstract sig Region {
	index: Int
}
sig Col extends Region {
  cell: Row -> Color
}{
	index >= 0
	index <= 9
}
sig Row extends Region {}{
	index >= 0
	index <= 9
}

fact {
	all r: Col - last {
		add[r.index, 1] = r.next.index
	}
	all r: Row - last {
		add[r.index, 1] = r.next.index
	}
}

enum Color { Black, White }

fact {
  all c: Col, r: Row | one cell [c, r]
}

-- about rows

fun headsInRow (r: Row): set Col {
  { c: Col | blackHeadInRow[c, r] }
}

fact noOtherHeadsInRow {
  no c: Col, r: Row | c not in headsInRow[r] and blackHeadInRow[c, r]
}

pred headsSeqInRow (r: Row, s: seq Col) {
  s.elems = headsInRow[r]
  all i: s.butlast.inds | lt [s[i], s[plus[i, 1]]]
}

fun Int2Row (i: Int): Row {
	index.i & Row
}

pred rowHint (j: Int, sizes: seq Int) {
  let r = Int2Row[j] | some cs: seq Col {
    #sizes = #cs
    // csは黒ブロックの先頭の位置のソートされたシークエンス
    headsSeqInRow [r, cs]
    all i: sizes.inds {
      // cs[i]をstart, startの位置にsize[i]を足して1を引いた位置にあるColをendと呼ぶ
      let start = cs [i], end = Int2Col [plus [start.index, minus[sizes [i], 1] ]] {
        // endが存在する
        some end
        // startからendまで全部黒
        all c: start.*cols/next - end.^cols/next | cell [c, r] in Black
        // endの次がないか、または白
        no end.next or cell [end.next, r] in White
      }
    }
  }
}

pred prev_is_white(c: Col, r: Row, prev: Region->Region) {
	// トリック: prevがCol->ColでもRowに使ってよい
	// なぜなら空集合が返るのでin Whiteが成立するから
	cell[prev[c], r] + cell[c, prev[r]] in White
}

pred no_prev(c: Col, r: Row, prev: Region->Region) {
	// トリック: nextがCol->ColでもRowに使ってよい
	// なぜなら空集合が返るのでnoが成立するから
	no prev[c] and no prev[r]
}

// c, rがブロックの先頭であるかどうか
pred is_black_head(c: Col, r: Row, prev: Region->Region) {
	// 最初のRowであるか、または前のRowのセルが白い
  no_prev[c, r, prev] or prev_is_white[c, r, prev]
	// このセルは黒い
  cell[c, r] in Black
}

pred blackHeadInCol (c: Col, r: Row) {
	is_black_head[c, r, rows/prev]
}
pred blackHeadInRow (c: Col, r: Row) {
	is_black_head[c, r, cols/prev]
}

-- about cols
// Col cの中の、ブロックの頭であるRowの集合
fun headsInCol (c: Col): set Row {
  { r: Row | blackHeadInCol[c, r] }
}

fact noOtherHeadsInCol {
  no c: Col, r: Row | r not in headsInCol[c] and blackHeadInCol[c, r]
}

pred headsSeqInCol (c: Col, s: seq Row) {
	// sの要素はブロック先頭の集合と同一
  s.elems = headsInCol[c]
	// sは単調増加
  all i: s.butlast.inds | lt [s[i], s[plus[i, 1]]]
}

fun Int2Col (i: Int): Col {
	index.i & Col
}

fun range(start, end: Region, next: Region -> Region): Region{
	start.*next - end.^next
}
pred colHint (j: Int, sizes: seq Int) {
  let c = Int2Col[j] | some rs: seq Row {
    #sizes = #rs
    headsSeqInCol [c, rs]
    all i: sizes.inds {
      let start = rs [i], end = Int2Row [plus [start.index, minus[sizes [i], 1] ]] {
      	some end
      	all r: range[start, end, rows/next] | cell [c, r] in Black
      	no end.next or cell [c, end.next] in White
    	}
		}
  }
}
-- riddle from http://homepage1.nifty.com/sabo10/rulelog/illust.html
solve: run {
  rowHint [0, 0 -> 3]
  rowHint [1, 0 -> 2 + 1 -> 2]
  rowHint [2, 0 -> 1 + 1 -> 1 + 2 -> 1]
  rowHint [3, 0 -> 3 + 1 -> 3]
  rowHint [4, 0 -> 5]
  rowHint [5, 0 -> 7]
  rowHint [6, 0 -> 7]
  rowHint [7, 0 -> 7]
  rowHint [8, 0 -> 7]
  rowHint [9, 0 -> 5]

  colHint [0, 0 -> 4]
  colHint [1, 0 -> 6]
  colHint [2, 0 -> 7]
  colHint [3, 0 -> 9]
  colHint [4, 0 -> 2 + 1 -> 7]
  colHint [5, 0 -> 1 + 1 -> 6]
  colHint [6, 0 -> 2 + 1 -> 4]
  colHint [7, 0 -> 3]
  colHint [8, 0 -> 1]
  colHint [9, 0 -> 2]
} for 10 but 5 Int


updating tdrf experiment for benjamin

updating tdrf experiment for benjamin

open ../archs/exec_C[E]
open ../models/c11_txn[E] as M
open ../models/tsc[E] as N

module c11_tdrf[E]

pred p[X:Exec_C] {
  withoutinit[X]

  M/consistent[none->none, X]
  M/racefree[none->none, X]

  not (N/consistent[none->none,X])

  // all transactions are atomic
  no (X.stxn - X.atxn)

  // avoid non-SC atomic operations
  no (X.A - X.SC)

  X.EV = E
}

run p for 1 Exec, 7 E // started on benjamin 1448 on fri 3 nov

open ../archs/exec_C[E]
open ../models/c11_txn[E] as M
open ../models/tsc[E] as N

module c11_tdrf[E]

pred p[X:Exec_C] {
  withoutinit[X]

  M/consistent[none->none, X]
  M/racefree[none->none, X]

  not (N/consistent[none->none,X])

  X.EV = E
}

run p for 1 Exec, 6 E