working on TDRF experiment

working on TDRF experiment

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

error: pathspec 'mappings/c11_tdrf.als' did not match any file(s) known to git


change indent

change indent

sig Person {
   love: Person
}

run {
   some x: Person {
      x.love.love = x
   }
}


alloy file added for demo.

alloy file added for demo.

module ferhat/Requirement

abstract sig Element {}

--@exclude
abstract sig State {}

abstract sig ElementState extends State {}
one sig Deleted, Changed, Created extends ElementState {}

abstract sig TaskState extends State {}
one sig Done, ToDo, Cancelled, Ready extends TaskState {}

abstract sig Requirement extends Element {
	state: one ElementState
}

sig Task extends Element {
	precede: lone Task,
	state: one TaskState
}{ all t: Task | one t.~task}

one sig Project extends Requirement {
	requirement: some ContractRequirement
}

sig ContractRequirement extends Requirement {
	system: set SystemRequirement,
	relate: set ContractRequirement
}{all c: ContractRequirement | one c.~requirement}

--@name: "System Requirement"
sig SystemRequirement extends Requirement {
	child: some Implementation
}{ all s: SystemRequirement | one s.~system}

abstract sig Implementation extends Requirement {
	task: set Task
}
{ all i: Implementation | one i.~child}

--@context.editor: "ReqIFEditor" //context'leri bir attribute ile tanıt kullanıcı dokümanlarını yaratırken bunlardan seçsin
//contenttype
sig SoftwareRequirement extends Implementation {
	test: some TestCase
}

sig HardwareRequirement extends Implementation {}

sig TestCase extends Element {
}{ all t:TestCase  | one t.~test}

fact noSelfRelation{
	no c: ContractRequirement | c in c.relate
	no t: Task | t in t.precede
}

fact noCycles{
	no t:Task | t in t.^precede
}

fact realismConstraint {
	some ContractRequirement
	some HardwareRequirement
	some SoftwareRequirement
	some precede
}

/* Counterexample Finding */

/* Instance Finding */
pred example {
	#ContractRequirement >1 and #SystemRequirement >2  and
	#SoftwareRequirement >1 and #HardwareRequirement >1 and
	#precede >1 and #task >1 #(Task <: state).Cancelled >1 and
	#(Requirement <: state).Created >4 and
	#(Requirement <: state).Changed >1 and
	#(Requirement <: state).Deleted >1
}
run example for exactly 20 Element

error: pathspec 'Source/eu.modelwriter.configuration/RequirementNoOpposite.als' did not match any file(s) known to git


shrink scope. simple_maze_tile.als can be solved 7x7 tiles with 4096MB heaps.

module maze_maker/simple_maze

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

// 隣接する Tile
fun adjacent (t: Tile) : Tile {
  let col = tile.t.Row, row = tile.t[Col] |
    tile[col.prev, row] +
    tile[col.next, row] +
    tile[col, row.prev] +
    tile[col, row.next]
}

sig Tile {
  link: some Tile
} {
  // 自分自身との接続はなし
  no this & link
  // 接続先は必ず隣接する(4近傍の) Tile
  link in adjacent[this]
}

one sig Entrance extends Tile {}
one sig Exit extends Tile {}

sig Col {
  tile: Row -> one Tile
}
sig Row {}

//  Tile が盤の端
pred edge (t: Tile) {
  let col = tile.t.Row, row = tile.t[Col] |
    col = cols/first or col = cols/last or row = rows/first or row = rows/last
}

fact {
  // tile に含まれない Tile はなし
  Tile in tile[Col, Row]
  // Row, Col の組と Tile は必ず1対1対応
  all t: Tile | one tile.t
  // link の連結は反射的
  link = ~link
  // 全ての Tile は link で繋がる
  all t: Tile | t.^link = Tile
  // 入口と出口はいずれも盤面の端に位置する
  edge[Entrance]
  edge[Exit]
}

run {
} for exactly 7 Col, exactly 7 Row, exactly 49 Tile

module maze_maker/simple_maze

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

// 隣接する Tile
fun adjacent (t: Tile) : Tile {
  let col = tile.t.Row, row = tile.t[Col] |
    tile[col.prev, row] +
    tile[col.next, row] +
    tile[col, row.prev] +
    tile[col, row.next]
}

sig Tile {
  link: some Tile
} {
  // 自分自身との接続はなし
  no this & link
  // 接続先は必ず隣接する(4近傍の) Tile
  link in adjacent[this]
}

one sig Entrance extends Tile {}
one sig Exit extends Tile {}

sig Col {
  tile: Row -> one Tile
}
sig Row {}

//  Tile が盤の端
pred edge (t: Tile) {
  let col = tile.t.Row, row = tile.t[Col] |
    col = cols/first or col = cols/last or row = rows/first or row = rows/last
}

fact {
  // tile に含まれない Tile はなし
  Tile in tile[Col, Row]
  // Row, Col の組と Tile は必ず1対1対応
  all t: Tile | one tile.t
  // link の連結は反射的
  link = ~link
  // 全ての Tile は link で繋がる
  all t: Tile | t.^link = Tile
  // 入口と出口はいずれも盤面の端に位置する
  edge[Entrance]
  edge[Exit]
}

run {
} for exactly 10 Col, exactly 10 Row, exactly 100 Tile


mystery modelling (not completed)

mystery modelling (not completed)

error: pathspec 'mystery.als' did not match any file(s) known to git


add pred sorted

add pred sorted

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

fun IntTo(i: Int, R: Region): Region{
	index.i & R
}

-- about rows or cols
fact noOtherHeadsInRow {
	no c: Col, r: Row {
		c not in { c: Col | is_black_head[c, r, cols/prev]}
		is_black_head[c, r, cols/prev]
	}
}
fact noOtherHeadsInCol {
	no c: Col, r: Row {
		r not in { r: Row | is_black_head[c, r, rows/prev]}
		is_black_head[c, r, rows/prev]
	}
}

pred headsSeqInRow (r: Row, s: seq Col) {
	sorted[
		{ c: Col | is_black_head[c, r, cols/prev]}.index,
		s.index]
}
pred headsSeqInCol (c: Col, s: seq Row) {
	sorted[
		{ r: Row | is_black_head[c, r, rows/prev]}.index,
		s.index]
}

pred sorted(xs: Int, s: seq Int){
	// sの要素はxsと同一
	s.elems = xs
	// sは単調増加
	all i: s.butlast.inds | lt [s[i], s[plus[i, 1]]]
}

pred rowHint (j: Int, sizes: seq Int) {
	let r = IntTo[j, Row] | 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 colHint (j: Int, sizes: seq Int) {
	let c = IntTo[j, Col] | 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]
}

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

fun IntTo(i: Int, R: Region): Region{
	index.i & R
}

-- about rows or cols
fact noOtherHeadsInRow {
	no c: Col, r: Row {
		c not in { c: Col | is_black_head[c, r, cols/prev]}
		is_black_head[c, r, cols/prev]
	}
}
fact noOtherHeadsInCol {
	no c: Col, r: Row {
		r not in { r: Row | is_black_head[c, r, rows/prev]}
		is_black_head[c, r, rows/prev]
	}
}

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

pred rowHint (j: Int, sizes: seq Int) {
	let r = IntTo[j, Row] | 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 colHint (j: Int, sizes: seq Int) {
	let c = IntTo[j, Col] | 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


Update the alloy axercise

Update the alloy axercise

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

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

sig State {
	successors: set State
}

// There is exactly one initial state

one sig Initial extends State { }

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

sig Final extends State { } { no successors }

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

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

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

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

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

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

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

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

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

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

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

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

assert  finishable { }

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

// check finishable for 1

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

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

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

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

sig State {
	successors: set State
}

// There is exactly one initial state

one sig Initial extends State { }

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

sig Final extends State { } { no successors }

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

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

// The 0-arity predicate findModel below expresses that there exist black, yellow and final states
pred findModel { #Final > 0 && #Black > 0 && #Yellow > 0 }

// The run command below checks to see if the predicate can be satisfied in scope 1
run findModel for 1

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

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

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

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

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

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

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

assert  finishable { }

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

check finishable for 1

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

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


Incomplete - task : First draft of Votail Journal Paper (Verification Chapter)

-- Copyright (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 winning-outcomes and 8 losing-outcomes,
  of which 2 winning-outcomes and 4 losing-outcomes are for Plurality

  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 (STV),

  AboveQuotaWinner: elected with surplus votes after receipt of transfers (STV),
  QuotaWinnerNonTransferable:
				                elected after transfers with at least one non-transferable surplus vote (STV),
  QuotaWinner: 		   elected with quota after transfers from another candidate (STV),

	 CompromiseWinner: elected on the last round of counting without quota but by plurality,
	 TiedWinner:			    elected by tie breaker in the last round,

	 TiedLoser:			     defeated only by tie breaker but reaches the threshold,
  TiedSoreLoser:		  defeated only by tie breaker but does not reach threshold,
	 Loser:			 		      defeated on last round but reaches the minimum threshold of votes,
  SoreLoser: 			    defeated,but does not even reach the mimimum threshold of votes

  EarlyLoserNonTransferable:
                    reaches threshold but is eliminated with some non-transferable votes (STV),
	 EarlyLoser:		     reaches threshold but is eliminated before last round (STV),
  EarlySoreLoser:   eliminated before last round, and below threshold (STV),
  EarlySoreLoserNonTransferable:
																				below threshold and eliminated with some non-transferable votes (STV)

*/
enum Event {SurplusWinner,
            WinnerNonTransferable,
            Winner,
            AboveQuotaWinner,
            QuotaWinnerNonTransferable,
            QuotaWinner,
            CompromiseWinner,
	           TiedWinner,
            TiedLoser,
            Loser,
            EarlyLoser,
            EarlyLoserNonTransferable,
            TiedSoreLoser,
            SoreLoser,
            EarlySoreLoser,
            EarlySoreLoserNonTransferable}

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		      -- Path to election result for each candidate
} {
     // Ballots available for transfers but without further preferences
     0 < #wasted iff (outcome = WinnerNonTransferable or
                      outcome = QuotaWinnerNonTransferable or
                      outcome = EarlyLoserNonTransferable or
	                     outcome = EarlySoreLoserNonTransferable)

     // Ballots are only counted as wasted in they belong to the surplus, or
     (outcome = WinnerNonTransferable or outcome = QuotaWinnerNonTransferable)
       implies wasted in surplus

     // ... if the ballots are from an excluded candidate
     (outcome = EarlyLoserNonTransferable or outcome = EarlySoreLoserNonTransferable)
       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

     // Losers excluded but above threshold
    	(outcome = EarlyLoser 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

    	// Plurality outcomes; 2 winning-outcomes and 4 losing-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 = EarlySoreLoserNonTransferable or
     outcome = EarlySoreLoser or outcome = EarlySoreLoserNonTransferable) 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)
    (outcome = Winner and Election.method = STV) implies
       (Scenario.quota + #surplus = #votes) and #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

     // Existance of surplus ballots
    	0 < #surplus implies (outcome = SurplusWinner or outcome = AboveQuotaWinner or
						outcome = WinnerNonTransferable or outcome = QuotaWinnerNonTransferable)
}

-- 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
} {
		/* Mutual exclusions of outcomes:
     see https://trac.ucd.ie/repos/software/evoting/V%C3%B3t%C3%A1il/src/ie/votail/model/factory/ScenarioFactory.java */
  no disj a,b: Candidate | a.outcome = TiedWinner and b.outcome = CompromiseWinner and a in winners and b in winners
  no disj a,b: Candidate | a.outcome = Loser and b.outcome = TiedSoreLoser and a in losers and b in losers
  no disj a,b: Candidate | a.outcome = EarlyLoser and b.outcome = TiedSoreLoser and a in losers and b in losers
  no disj a,b: Candidate | a.outcome = EarlyLoserNonTransferable and b.outcome = TiedSoreLoser and a in losers and b in losers
  no disj a,b: Candidate | a.outcome = TiedLoser and b.outcome = TiedSoreLoser and a in losers and b in losers
  no disj a,b: Candidate | a.outcome = TiedLoser and b.outcome = CompromiseWinner and a in losers and b in winners
  no disj a,b: Candidate | a.outcome = TiedSoreLoser and b.outcome = CompromiseWinner and a in losers and b in winners

  // Mandatory pairs of outcomes: ties between winners and losers
  all a: Candidate | some b: Candidate | (a in losers and (a.outcome = TiedLoser or a.outcome = TiedSoreLoser)) implies
                                        (b in winners and b.outcome = TiedWinner)
  all a: Candidate | some b: Candidate | (a in winners and a.outcome = TiedWinner) implies
                                        (b in losers and (b.outcome = TiedLoser or b.outcome = TiedSoreLoser))

  // Other Definitions
 	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)
  // Definition of Threshold for PR-STV
  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 or
        d.outcome = EarlySoreLoser) 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 or
     c.outcome = WinnerNonTransferable or c.outcome = QuotaWinnerNonTransferable) 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 = EarlySoreLoser or
    c.outcome = TiedSoreLoser or
    c.outcome = EarlySoreLoserNonTransferable or
    c.outcome = EarlyLoserNonTransferable)

    // 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) 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) 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=Loser or b.outcome=EarlyLoser or b.outcome = EarlyLoserNonTransferable)
    // 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)
    // Tied Winners and Tied Losers have an equal number of votes
	all disj l,w: Candidate |
    ((l.outcome = TiedLoser or l.outcome = TiedSoreLoser) 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 = EarlySoreLoser or
       l.outcome = EarlySoreLoserNonTransferable)
       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)
		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
  method = Plurality or method = STV
}

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

-- Copyright (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 winning-outcomes and 8 losing-outcomes,
  of which 2 winning-outcomes and 4 losing-outcomes are for Plurality

  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 (STV),

  AboveQuotaWinner: elected with surplus votes after receipt of transfers (STV),
  QuotaWinnerNonTransferable:
				                elected after transfers with at least one non-transferable surplus vote (STV),
  QuotaWinner: 		   elected with quota after transfers from another candidate (STV),

	 CompromiseWinner: elected on the last round of counting without quota but by plurality,
	 TiedWinner:			    elected by tie breaker in the last round,

	 TiedLoser:			     defeated only by tie breaker but reaches the threshold,
  TiedSoreLoser:		  defeated only by tie breaker but does not reach threshold,
	 Loser:			 		      defeated on last round but reaches the minimum threshold of votes,
  SoreLoser: 			    defeated, but does not even reach the mimimum threshold of votes

  EarlyLoserNonTransferable:
                    reaches threshold but is eliminated with some non-transferable votes (STV),
	 EarlyLoser:		     reaches threshold but is eliminated before last round (STV),
  EarlySoreLoser:   eliminated before last round, and below threshold (STV),
  EarlySoreLoserNonTransferable:
																				below threshold and eliminated with some non-transferable votes (STV)

*/
enum Event {SurplusWinner,
            WinnerNonTransferable,
            Winner,
            AboveQuotaWinner,
            QuotaWinnerNonTransferable,
            QuotaWinner,
            CompromiseWinner,
	           TiedWinner,
            TiedLoser,
            Loser,
            EarlyLoser,
            EarlyLoserNonTransferable,
            TiedSoreLoser,
            SoreLoser,
            EarlySoreLoser,
            EarlySoreLoserNonTransferable}

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		      -- Path to election result for each candidate
} {
     // Ballots available for transfers but without further preferences
     0 < #wasted iff (outcome = WinnerNonTransferable or
                      outcome = QuotaWinnerNonTransferable or
                      outcome = EarlyLoserNonTransferable or
	                     outcome = EarlySoreLoserNonTransferable)

     // Ballots are only counted as wasted in they belong to the surplus, or
     (outcome = WinnerNonTransferable or outcome = QuotaWinnerNonTransferable)
       implies wasted in surplus

     // ... if the ballots are from an excluded candidate
     (outcome = EarlyLoserNonTransferable or outcome = EarlySoreLoserNonTransferable)
       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

     // Losers excluded but above threshold
    	(outcome = EarlyLoser 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

    	// Plurality outcomes; 2 winning-outcomes and 4 losing-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 = EarlySoreLoserNonTransferable or
     outcome = EarlySoreLoser or outcome = EarlySoreLoserNonTransferable) 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)
    (outcome = Winner and Election.method = STV) implies
       (Scenario.quota + #surplus = #votes) and #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

     // Existance of surplus ballots
    	0 < #surplus implies (outcome = SurplusWinner or outcome = AboveQuotaWinner or
						outcome = WinnerNonTransferable or outcome = QuotaWinnerNonTransferable)
}

-- 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
} {
		/* Mutual exclusions of outcomes:
     see https://trac.ucd.ie/repos/software/evoting/V%C3%B3t%C3%A1il/src/ie/votail/model/factory/ScenarioFactory.java */
  no disj a,b: Candidate | a.outcome = TiedWinner and b.outcome = CompromiseWinner and a in winners and b in winners
  no disj a,b: Candidate | a.outcome = Loser and b.outcome = TiedSoreLoser and a in losers and b in losers
  no disj a,b: Candidate | a.outcome = EarlyLoser and b.outcome = TiedSoreLoser and a in losers and b in losers
  no disj a,b: Candidate | a.outcome = EarlyLoserNonTransferable and b.outcome = TiedSoreLoser and a in losers and b in losers
  no disj a,b: Candidate | a.outcome = TiedLoser and b.outcome = TiedSoreLoser and a in losers and b in losers
  no disj a,b: Candidate | a.outcome = TiedLoser and b.outcome = CompromiseWinner and a in losers and b in winners
  no disj a,b: Candidate | a.outcome = TiedSoreLoser and b.outcome = CompromiseWinner and a in losers and b in winners

  // Mandatory pairs of outcomes: ties between winners and losers
  all a: Candidate | some b: Candidate | (a in losers and (a.outcome = TiedLoser or a.outcome = TiedSoreLoser)) implies
                                        (b in winners and b.outcome = TiedWinner)
  all a: Candidate | some b: Candidate | (a in winners and a.outcome = TiedWinner) implies
                                        (b in losers and (b.outcome = TiedLoser or b.outcome = TiedSoreLoser))

  // Other Definitions
 	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)
  // Definition of Threshold for PR-STV
  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 or
        d.outcome = EarlySoreLoser) 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 or
     c.outcome = WinnerNonTransferable or c.outcome = QuotaWinnerNonTransferable) 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 = EarlySoreLoser or
    c.outcome = TiedSoreLoser or
    c.outcome = EarlySoreLoserNonTransferable or
    c.outcome = EarlyLoserNonTransferable)

    // 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) 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) 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=Loser or b.outcome=EarlyLoser or b.outcome = EarlyLoserNonTransferable)
    // 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)
    // Tied Winners and Tied Losers have an equal number of votes
	all disj l,w: Candidate |
    ((l.outcome = TiedLoser or l.outcome = TiedSoreLoser) 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 = EarlySoreLoser or
       l.outcome = EarlySoreLoserNonTransferable)
       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)
		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
  method = Plurality or method = STV
}

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


clean pred equal

clean pred equal

open util/ordering[Term]

some abstract sig Term {}

one sig K extends Term {}

sig Apply extends Term {
	f, g: Term
}

fact {
	all x, y: Term | (x -> y) in (f + g) => y not in (x.prevs + x)
}

pred equal_k (x, y: Term) {
	x in Apply and x.f in Apply and x.f.f = K and y = x.f.g
}
pred equal_k2 (x, y: Term) {
	one a, b: Term | x = apply[apply[K, a], b] and y = a
}
check {
	some x, y: Term | equal_k[x, y] iff equal_k2[x, y]
}

//pred equal_s (x, y: Term) {}
pred equal (x, y: Term) {
	equal_k[x, y]// or equal_s[x, y]
}

fun apply(x, y: Term): Term{
	{a: Apply | a.f = x and a.g = y }
}

fact {
	all x, y: Term | lone apply[x, y]
}

run {
	some x, y: Term | equal[x, y]
} for 5 Term

open util/ordering[Term]

some abstract sig Term {}

one sig K extends Term {}

sig Apply extends Term {
	f, g: Term
}

fact {
	all x, y: Term | (x -> y) in (f + g) => y not in (x.prevs + x)
}

pred equal (x, y: Term) {
	x in Apply and x.f in Apply and x.f.f = K and y = x.f.g
}

fun apply(x, y: Term): Term{
	{a: Apply | a.f = x and a.g = y }
}

run {
	some x, y: Term | equal[x, y]
} for 5 Term


Removed Spesh

Removed Spesh

module c11Relat
// open util/relation

// TODO: don't have non-atomic actions in this model, just NA locations.

// Disable non-atomics entirely
fact {
  no NonAtomic
}

// Locations can be local or global
abstract sig Loc {}
sig Glob, Thr extends Loc {}

// Furthermore global locations can be atomic or nonatomic
sig Atomic, NonAtomic in Glob {}
fact {
  Atomic + NonAtomic = Glob
  disj [ Atomic, NonAtomic ]
}

sig Val {}
one sig Init in Val {} // Magic initialisation value

// Actions kinds corresponding to different memory actions
abstract sig Kind {}
one sig Read, Write, RMW, AssmEq extends Kind {}

// Actions
abstract sig Action {}
sig Intern, Extern, Call, Ret extends Action {}

// Locations are associated with actions correctly
pred locWF[ dom : set Action,
            kind : Action -> Kind,
            gloc : Action -> Glob,
            lloc1, lloc2 : Intern -> Thr ] {
    kind in (dom - (Call + Ret)) -> one Kind
    no (Call + Ret).kind

    gloc in (dom - (Call + Ret)) -> lone Glob
    lloc1 in dom -> lone Thr
    lloc2 in dom -> lone Thr

    all a : dom | {
      // All reads and writes access global locations
      a in kind.(Read + Write + RMW)  iff  one a.gloc

      // Reads and writes acces one local variable
      a in kind.(Read + Write) & Intern  implies  {
        one a.lloc1 and no a.lloc2
      }

      // Assume and RMW access two local variables
      a in kind.(AssmEq + RMW) & Intern  implies  {
        one a.lloc1 and one a.lloc2
      }
    }
}

// Values are associated with actions correctly
pred valWF[ dom : set Action,
            kind : Action -> Kind,
            wv, rv : Action -> Val ] {
    wv in (dom - (Call + Ret)) -> lone Val
    rv in (dom - (Call + Ret)) -> lone Val

    // Writes have a written value, reads have a read value, RMW have both
    all a : dom - (Call + Ret) | {
      kind[a] in Write iff {
        one a.wv
        no a.rv
      }
      kind[a] in Read iff {
        one a.rv
        no a.wv
      }
      kind[a] in RMW iff {
        one a.rv
        one a.wv
      }
      // TODO: add case for no r/w?
    }
}

// No transitive edges in the relation
pred is_core [ r : Action -> Action ] {
  all a,b,c: Action |
    (a -> b) + (b -> c) in ^r  implies  not (a -> c) in r
}

// SB is acyclic
pred SBwf [ dom : set Action,
            kind : Action -> Kind,
            sb: Action -> Action ] {
  no iden & ^sb
}

// HB is acyclic
pred HBacyc [ dom : set Action, kind : Action -> Kind,
              loc : Action -> Loc, wv, rv : Action -> Val,
              hb, sb, mo, rf : Action -> Action ] {
  no iden & ^hb
}

// Find the last value written for a given local variable and action
fun lastval [ dom : set Action,
              kind : Action -> Kind,
              lloc : Action -> Loc,
              callmap : Thr -> Val,
              rv : Action -> Val,
              sb : Action -> Action,
              curr : Action,
              currloc : Loc ] : set Val {
  { v : Val |
    some r : dom & kind.Read | {
      r.rv = v
      r -> curr in ^sb
      r.lloc = currloc
      no r' : dom & kind.Read | {
        (r -> r') + (r' -> curr) in ^sb
        r'.lloc = currloc
      }
    }
  }
    +
  { v : Val | {
      v = (currloc).callmap
      (Call -> curr) in ^sb
      no r' : dom & kind.Read | {
        (Call -> r') + (r' -> curr) in ^sb
        r'.lloc = currloc
      }
    }
  }
}

// Write the value given at the call to the same local variable.
// TODO: handle internal RMW
pred RFwfLocal [ dom : set Action,
                kind : Action -> Kind,
                gloc : Action -> Loc,
                lloc1, lloc2 : Action -> Loc,
                callmap, retmap : Thr -> Val,
                wv, rv : Action -> Val,
                hb, sb, mo, rf : Action -> Action ] {
  callmap in Thr -> one Val
  retmap in Thr -> one Val

  // Assumes demand equality on local var values
  all a : dom & kind.AssmEq | {
    lastval[dom, kind, lloc1, callmap, rv, sb, a, a.lloc1] =
      lastval[dom, kind, lloc1, callmap, rv, sb, a, a.lloc2]
  }

  // Writes take the correct local var value
  all w : dom & kind.Write | {
    w.wv = lastval[dom, kind, lloc1, callmap, rv, sb, w, w.lloc1]
  }

  // The retmap takes the correct values.
  all t : Thr | {
    t.retmap = lastval[dom, kind, lloc1, callmap, rv, sb, Ret, t]
  }
}

// RF is well-formed
pred RFwf [ dom : set Action,
            kind : Action -> Kind,
            loc : Action -> Loc,
            wv, rv : Action -> Val,
            hb, sb, mo, rf : Action -> Action ] {
  // Read from at most one write
  rf in kind.(Write + RMW) lone -> kind.(Read + RMW)

  // Irreflexive
  no iden & rf

  all r : dom & kind.(Read + RMW) | {
    // Read from the same location written
    (rf.r).loc in r.loc

    // Value taken from origin write
    // TODO: decide whether to allow assignments to Init
    some rf.r implies r.rv = (rf.r).wv // and not r.rval in Init
    no rf.r implies r.rv in Init

    // Allow initialisation reads, but force actions to
    // read from an explicit write if any is hb-available
    // Note MO used here because r might be a RMW
    (some (hb + mo).r & (kind.(Write + RMW) <: loc).(r.loc) )
          implies (some rf.r)
    // TODO: Mark isn't completely convinced
  }
}

// Define hb by combining rf with hb over atomics
pred HBdef [ dom : set Action,
             kind : Action -> Kind,
             loc : Action -> Loc,
             wv, rv : Action -> Val,
             hb, sb, mo, rf : Action -> Action ] {
  let aact = (dom <: loc).Atomic |
  let sw = rf & (aact -> aact) |
  hb = ^(sw + sb)
}

// Coherence order is respected
// Note: this also covers the AtomRMW rule.
pred CoWR [ dom : set Action, kind : Action -> Kind,
            loc : Action -> Loc, wv, rv : Action -> Val,
            hb, sb, mo, rf : Action -> Action ] {
  all r : dom & kind.(Read + RMW), w1 : rf.r |
    not { (w1 -> r) in mo.(hb + mo) }
}

// Modification order is well-formed
pred MOwf [ dom : set Action, kind : Action -> Kind,
            loc : Action -> Loc, wv, rv : Action -> Val,
            hb, sb, mo, rf : Action -> Action ] {
  mo = ^mo     // transitive
  no iden & mo  // irreflexive
  mo in kind.(Write + RMW) -> kind.(Write + RMW)

  // per-location total on atomics
  all disj w1, w2 : kind.(Write + RMW) |
     (w1 -> w2) in mo + ~mo iff
       (w1.loc = w2.loc) and w1 + w2 in (dom <: loc.Atomic)
}

// HB and MO do not contradict one another
pred HBvsMO [ dom : set Action, kind : Action -> Kind,
              loc : Action -> Loc, wv, rv : Action -> Val,
              hb, sb, mo, rf : Action -> Action ] {
  no hb & ~mo
}

// // Stronger version of this axiom: rule out cycles, not loops
// pred HBMOacyc [ e : Execution ] {
//   no iden & ^(e.hb + e.mo)
// }

// Reads-from edges for NAs all follow hb
pred RFNonAtomic [ dom : set Action,
                   kind : Action -> Kind,
                   loc : Action -> Loc,
                   wv, rv : Action -> Val,
                   hb, sb, mo, rf : Action -> Action ] {
  let NA_reads = (dom <: loc).NonAtomic & kind.Read |
     (rf :> NA_reads) in hb
}

// Combine the different predicates into execution validity
pred valid [ dom : set Action,
             kind : Action -> Kind,
             gloc : Action -> Glob,
             lloc1, lloc2: Action -> Thr,
             callmap, retmap : Thr -> Val,
             wv, rv : Action -> Val,
             hb, sb, mo, rf : Action -> Action ] {
  // Sanity conditions
  hb + sb + mo + rf in (dom -> dom)

  // Pre-execution structure
  locWF[dom, kind, gloc, lloc1, lloc2]
  valWF[dom, kind, wv, rv]
  SBwf[dom, kind, sb]

  // Local variable handling
  RFwfLocal[dom, kind, gloc, lloc1, lloc2, callmap, retmap, wv, rv, hb, sb, mo, rf]
  // Axioms
  HBacyc[dom, kind, gloc, wv, rv, hb, sb, mo, rf]
  RFwf[dom, kind, gloc, wv, rv, hb, sb, mo, rf]
  HBdef[dom, kind, gloc, wv, rv, hb, sb, mo, rf]
  CoWR[dom, kind, gloc, wv, rv, hb, sb, mo, rf]
  MOwf[dom, kind, gloc, wv, rv, hb, sb, mo, rf]
  HBvsMO[dom, kind, gloc, wv, rv, hb, sb, mo, rf]
  RFNonAtomic[dom, kind, gloc, wv, rv, hb, sb, mo, rf]
}

// Test whether the execution is DRF
pred DRF [ dom : set Action,
           kind : Action -> Kind,
           loc : Action -> Loc,
           wv, rv : Action -> Val,
           hb, sb, mo, rf : Action -> Action ] {
  all l : NonAtomic |
  all disj w, a : (dom <: loc).l |
    (w in kind.Write)
    and
    (a in kind.(Write + Read))
    implies
    (w -> a) in (hb + ~hb)
}

// The execution is sequential, i.e. sb is total
pred sequential [ dom : set Action, sb : Action -> Action ] {
  all disj a1, a2 : dom |   a1 -> a2 in ^sb + ^(~sb)
}

/*************************************************/
/* Tests                                         */
/*************************************************/

// run valid_run
//   { some dom : set Action, kind : Action -> Kind,
//                gloc, lloc : Action -> Loc,
//                callmap, retmap : Thr -> Val,
//                wv, rv : Action -> Val,
//                hb, sb, mo, rf : Action -> Action | {
//      valid[dom, kind, gloc, lloc, callmap, retmap, wv, rv, ^hb, sb, mo, rf]
//      dom = Action
//      Loc = dom.(gloc + lloc)
//      is_core[hb]
//      is_core[sb]
//      no Call + Ret
//   }
// } for 6 but exactly 2 Thr, 0 Extern
//
//
// run seq_run
//   { some dom : set Action, kind : Action -> Kind,
//                gloc, lloc : Action -> Loc,
//                callmap, retmap : Thr -> Val,
//                wv, rv : Action -> Val,
//                hb, sb, mo, rf : Action -> Action | {
//      valid[dom, kind, gloc, lloc, callmap, retmap, wv, rv, ^hb, sb, mo, rf]
//      dom = Action
//      Loc = dom.(gloc + lloc)
//      is_core[hb]
//      is_core[sb]
//      // check sequential
//      sequential[dom, sb]
//      no Call + Ret
//   }
// } for 6
//

// // Executions with no non-atomics are automatically DRF
// check atomic_DRF
//   { all dom : set Action, kind : Action -> Kind,
//                loc : Action -> Loc, wv, rv : Action -> Val,
//                hb, sb, mo, rf : Action -> Action |
//     valid[dom, kind, loc, wv, rv, ^hb, sb, mo, rf]
//        implies DRF[dom, kind, loc, wv, rv, ^hb, sb, mo, rf]
//   }
//   for 30
//   but 0 NonAtomic
//
// // Sequential executions are automatically DRF
// check seq_DRF
//   { all dom : set Action, kind : Action -> Kind,
//               loc : Action -> Loc, wv, rv : Action -> Val,
//               hb, sb, mo, rf : Action -> Action |
//     valid[dom, kind, loc, wv, rv, ^hb, sb, mo, rf]
//       and sequential[dom, sb]
//     implies DRF[dom, kind, loc, wv, rv, ^hb, sb, mo, rf]
//   }
//   for 10
//
// run litmus_SB
//   { some dom : set Action, kind : Action -> Kind,
//          loc : Action -> Loc, wv, rv : Action -> Val,
//          hb, sb, mo, rf : Action -> Action | {
//       valid[dom, kind, loc, wv, rv, ^hb, sb, mo, rf]
//       DRF[dom, kind, loc, wv, rv, ^hb, sb, mo, rf]
//       dom = Action
//       Loc = dom.loc
//       is_core[hb]
//       is_core[sb]
//       // litmus test
//       code_SB[dom, kind, loc, wv, rv, ^hb, sb, mo, rf]
//     }
//   }
//   for 6
//   but 0 NonAtomic, 2 Val
//
// run litmus_IRIW
//   { some dom : set Action, kind : Action -> Kind,
//          loc : Action -> Loc, wv, rv : Action -> Val,
//          hb, sb, mo, rf : Action -> Action | {
//       valid[dom, kind, loc, wv, rv, ^hb, sb, mo, rf]
//       DRF[dom, kind, loc, wv, rv, ^hb, sb, mo, rf]
//       dom = Action
//       Loc = dom.loc
//       is_core[hb]
//       is_core[sb]
//       // litmus test
//       code_IRIW[dom, kind, loc, wv, rv, ^hb, sb, mo, rf]
//     }
//   }
//   for 10
//   but 0 NonAtomic, 2 Val
//
// /*************************************************/
// /* Litmus test code                              */
// /*************************************************/
//
// // SB litmus test without initialisation
// pred code_SB [ dom : set Action, kind : Action -> Kind,
//                loc : Action -> Loc, wv, rv : Action -> Val,
//                hb, sb, mo, rf : Action -> Action ] {
//   some disj wx, wy : kind.Write |
//   some disj rx, ry : kind.Read |  {
//     dom = (wx + wy + rx + ry)
//     (wx -> ry) + (wy -> rx) in sb // allow stronger sb
//     one wx.loc + rx.loc
//     one wy.loc + ry.loc
//     no wx.loc & wy.loc
//     no rf // read from initialisation
//   }
// }
//
// // Comment from JPW - alloy simplifies rel = ((a->b) + (c->d)...
// // Refactor this code?
//
// pred code_IRIW [ dom : set Action, kind : Action -> Kind,
//                  loc : Action -> Loc, wv, rv : Action -> Val,
//                  hb, sb, mo, rf : Action -> Action ] {
//   some disj wx, wy : kind.Write |
//   some disj r1x, r2x, r1y, r2y : kind.Read | {
//     dom = wx + wy + r1x + r2x + r1y + r2y
//     rf = ((wx -> r1x) + (wy -> r2y))
//     ((r1x -> r1y) + (r2y -> r2x)) in sb
//     one wx.loc + r1x.loc + r2x.loc
//     one wy.loc + r1y.loc + r2y.loc
//     no wx.loc & wy.loc
//   }
// }
//

module c11Relat
// open util/relation

// TODO: Get rid of spesh, restrict Call / Ret to a singleton

// TODO: don't have non-atomic actions in this model, just NA locations.

// Disable non-atomics entirely
fact {
  no NonAtomic
}

// Locations can be local or global
abstract sig Loc {}
sig Glob, Thr extends Loc {}

// Furthermore global locations can be atomic or nonatomic
sig Atomic, NonAtomic in Glob {}
fact {
  Atomic + NonAtomic = Glob
  disj [ Atomic, NonAtomic ]
}

sig Val {}
one sig Init in Val {} // Magic initialisation value

// Actions kinds corresponding to different memory actions
abstract sig Kind {}
one sig Read, Write, RMW, AssmEq, Spesh extends Kind {}

// Actions
abstract sig Action {}
sig Intern, Extern, Call, Ret extends Action {}

// Locations are associated with actions correctly
pred locWF[ dom : set Action,
            kind : Action -> Kind,
            gloc : Action -> Glob,
            lloc1, lloc2 : Intern -> Thr ] {
    kind in dom -> one Kind
    gloc in (dom - (Call + Ret)) -> lone Glob
    lloc1 in dom -> lone Thr
    lloc2 in dom -> lone Thr

    all a : dom | {
      a in (Call + Ret) iff kind[a] in Spesh

      // All reads and writes access global locations
      a in kind.(Read + Write + RMW)  iff  one a.gloc

      // Reads and writes acces one local variable
      a in kind.(Read + Write) & Intern  implies  {
        one a.lloc1 and no a.lloc2
      }

      // Assume and RMW access two local variables
      a in kind.(AssmEq + RMW) & Intern  implies  {
        one a.lloc1 and one a.lloc2
      }
    }
}

// Values are associated with actions correctly
pred valWF[ dom : set Action,
            kind : Action -> Kind,
            wv, rv : Action -> Val ] {
    wv in (dom - (Call + Ret)) -> lone Val
    rv in (dom - (Call + Ret)) -> lone Val

    // Writes have a written value, reads have a read value, RMW have both
    all a : dom - (Call + Ret) | {
      kind[a] in Write iff {
        one a.wv
        no a.rv
      }
      kind[a] in Read iff {
        one a.rv
        no a.wv
      }
      kind[a] in RMW iff {
        one a.rv
        one a.wv
      }
      // TODO: add case for no r/w?
    }
}

// No transitive edges in the relation
pred is_core [ r : Action -> Action ] {
  all a,b,c: Action |
    (a -> b) + (b -> c) in ^r  implies  not (a -> c) in r
}

// SB is acyclic
pred SBwf [ dom : set Action,
            kind : Action -> Kind,
            sb: Action -> Action ] {
  no iden & ^sb
}

// HB is acyclic
pred HBacyc [ dom : set Action, kind : Action -> Kind,
              loc : Action -> Loc, wv, rv : Action -> Val,
              hb, sb, mo, rf : Action -> Action ] {
  no iden & ^hb
}

// Find the last value written for a given local variable and action
fun lastval [ dom : set Action,
              kind : Action -> Kind,
              lloc : Action -> Loc,
              callmap : Thr -> Val,
              rv : Action -> Val,
              sb : Action -> Action,
              curr : Action,
              currloc : Loc ] : set Val {
  { v : Val |
    some r : dom & kind.Read | {
      r.rv = v
      r -> curr in ^sb
      r.lloc = currloc
      no r' : dom & kind.Read | {
        (r -> r') + (r' -> curr) in ^sb
        r'.lloc = currloc
      }
    }
  }
    +
  { v : Val | {
      v = (currloc).callmap
      (Call -> curr) in ^sb
      no r' : dom & kind.Read | {
        (Call -> r') + (r' -> curr) in ^sb
        r'.lloc = currloc
      }
    }
  }
}

// Write the value given at the call to the same local variable.
// TODO: handle internal RMW
pred RFwfLocal [ dom : set Action,
                kind : Action -> Kind,
                gloc : Action -> Loc,
                lloc1, lloc2 : Action -> Loc,
                callmap, retmap : Thr -> Val,
                wv, rv : Action -> Val,
                hb, sb, mo, rf : Action -> Action ] {
  callmap in Thr -> one Val
  retmap in Thr -> one Val

  // Assumes demand equality on local var values
  all a : dom & kind.AssmEq | {
    lastval[dom, kind, lloc1, callmap, rv, sb, a, a.lloc1] =
      lastval[dom, kind, lloc1, callmap, rv, sb, a, a.lloc2]
  }

  // Writes take the correct local var value
  all w : dom & kind.Write | {
    w.wv = lastval[dom, kind, lloc1, callmap, rv, sb, w, w.lloc1]
  }

  // The retmap takes the correct values.
  all t : Thr | {
    t.retmap = lastval[dom, kind, lloc1, callmap, rv, sb, Ret, t]
  }
}

// RF is well-formed
pred RFwf [ dom : set Action,
            kind : Action -> Kind,
            loc : Action -> Loc,
            wv, rv : Action -> Val,
            hb, sb, mo, rf : Action -> Action ] {
  // Read from at most one write
  rf in kind.(Write + RMW) lone -> kind.(Read + RMW)

  // Irreflexive
  no iden & rf

  all r : dom & kind.(Read + RMW) | {
    // Read from the same location written
    (rf.r).loc in r.loc

    // Value taken from origin write
    // TODO: decide whether to allow assignments to Init
    some rf.r implies r.rv = (rf.r).wv // and not r.rval in Init
    no rf.r implies r.rv in Init

    // Allow initialisation reads, but force actions to
    // read from an explicit write if any is hb-available
    // Note MO used here because r might be a RMW
    (some (hb + mo).r & (kind.(Write + RMW) <: loc).(r.loc) )
          implies (some rf.r)
    // TODO: Mark isn't completely convinced
  }
}

// Define hb by combining rf with hb over atomics
pred HBdef [ dom : set Action,
             kind : Action -> Kind,
             loc : Action -> Loc,
             wv, rv : Action -> Val,
             hb, sb, mo, rf : Action -> Action ] {
  let aact = (dom <: loc).Atomic |
  let sw = rf & (aact -> aact) |
  hb = ^(sw + sb)
}

// Coherence order is respected
// Note: this also covers the AtomRMW rule.
pred CoWR [ dom : set Action, kind : Action -> Kind,
            loc : Action -> Loc, wv, rv : Action -> Val,
            hb, sb, mo, rf : Action -> Action ] {
  all r : dom & kind.(Read + RMW), w1 : rf.r |
    not { (w1 -> r) in mo.(hb + mo) }
}

// Modification order is well-formed
pred MOwf [ dom : set Action, kind : Action -> Kind,
            loc : Action -> Loc, wv, rv : Action -> Val,
            hb, sb, mo, rf : Action -> Action ] {
  mo = ^mo     // transitive
  no iden & mo  // irreflexive
  mo in kind.(Write + RMW) -> kind.(Write + RMW)

  // per-location total on atomics
  all disj w1, w2 : kind.(Write + RMW) |
     (w1 -> w2) in mo + ~mo iff
       (w1.loc = w2.loc) and w1 + w2 in (dom <: loc.Atomic)
}

// HB and MO do not contradict one another
pred HBvsMO [ dom : set Action, kind : Action -> Kind,
              loc : Action -> Loc, wv, rv : Action -> Val,
              hb, sb, mo, rf : Action -> Action ] {
  no hb & ~mo
}

// // Stronger version of this axiom: rule out cycles, not loops
// pred HBMOacyc [ e : Execution ] {
//   no iden & ^(e.hb + e.mo)
// }

// Reads-from edges for NAs all follow hb
pred RFNonAtomic [ dom : set Action,
                   kind : Action -> Kind,
                   loc : Action -> Loc,
                   wv, rv : Action -> Val,
                   hb, sb, mo, rf : Action -> Action ] {
  let NA_reads = (dom <: loc).NonAtomic & kind.Read |
     (rf :> NA_reads) in hb
}

// Combine the different predicates into execution validity
pred valid [ dom : set Action,
             kind : Action -> Kind,
             gloc : Action -> Glob,
             lloc1, lloc2: Action -> Thr,
             callmap, retmap : Thr -> Val,
             wv, rv : Action -> Val,
             hb, sb, mo, rf : Action -> Action ] {
  // Sanity conditions
  hb + sb + mo + rf in (dom -> dom)

  // Pre-execution structure
  locWF[dom, kind, gloc, lloc1, lloc2]
  valWF[dom, kind, wv, rv]
  SBwf[dom, kind, sb]

  // Local variable handling
  RFwfLocal[dom, kind, gloc, lloc1, lloc2, callmap, retmap, wv, rv, hb, sb, mo, rf]
  // Axioms
  HBacyc[dom, kind, gloc, wv, rv, hb, sb, mo, rf]
  RFwf[dom, kind, gloc, wv, rv, hb, sb, mo, rf]
  HBdef[dom, kind, gloc, wv, rv, hb, sb, mo, rf]
  CoWR[dom, kind, gloc, wv, rv, hb, sb, mo, rf]
  MOwf[dom, kind, gloc, wv, rv, hb, sb, mo, rf]
  HBvsMO[dom, kind, gloc, wv, rv, hb, sb, mo, rf]
  RFNonAtomic[dom, kind, gloc, wv, rv, hb, sb, mo, rf]
}

// Test whether the execution is DRF
pred DRF [ dom : set Action,
           kind : Action -> Kind,
           loc : Action -> Loc,
           wv, rv : Action -> Val,
           hb, sb, mo, rf : Action -> Action ] {
  all l : NonAtomic |
  all disj w, a : (dom <: loc).l |
    (w in kind.Write)
    and
    (a in kind.(Write + Read))
    implies
    (w -> a) in (hb + ~hb)
}

// The execution is sequential, i.e. sb is total
pred sequential [ dom : set Action, sb : Action -> Action ] {
  all disj a1, a2 : dom |   a1 -> a2 in ^sb + ^(~sb)
}

/*************************************************/
/* Tests                                         */
/*************************************************/

// run valid_run
//   { some dom : set Action, kind : Action -> Kind,
//                gloc, lloc : Action -> Loc,
//                callmap, retmap : Thr -> Val,
//                wv, rv : Action -> Val,
//                hb, sb, mo, rf : Action -> Action | {
//      valid[dom, kind, gloc, lloc, callmap, retmap, wv, rv, ^hb, sb, mo, rf]
//      dom = Action
//      Loc = dom.(gloc + lloc)
//      is_core[hb]
//      is_core[sb]
//      no Call + Ret
//   }
// } for 6 but exactly 2 Thr, 0 Extern
//
//
// run seq_run
//   { some dom : set Action, kind : Action -> Kind,
//                gloc, lloc : Action -> Loc,
//                callmap, retmap : Thr -> Val,
//                wv, rv : Action -> Val,
//                hb, sb, mo, rf : Action -> Action | {
//      valid[dom, kind, gloc, lloc, callmap, retmap, wv, rv, ^hb, sb, mo, rf]
//      dom = Action
//      Loc = dom.(gloc + lloc)
//      is_core[hb]
//      is_core[sb]
//      // check sequential
//      sequential[dom, sb]
//      no Call + Ret
//   }
// } for 6
//

// // Executions with no non-atomics are automatically DRF
// check atomic_DRF
//   { all dom : set Action, kind : Action -> Kind,
//                loc : Action -> Loc, wv, rv : Action -> Val,
//                hb, sb, mo, rf : Action -> Action |
//     valid[dom, kind, loc, wv, rv, ^hb, sb, mo, rf]
//        implies DRF[dom, kind, loc, wv, rv, ^hb, sb, mo, rf]
//   }
//   for 30
//   but 0 NonAtomic
//
// // Sequential executions are automatically DRF
// check seq_DRF
//   { all dom : set Action, kind : Action -> Kind,
//               loc : Action -> Loc, wv, rv : Action -> Val,
//               hb, sb, mo, rf : Action -> Action |
//     valid[dom, kind, loc, wv, rv, ^hb, sb, mo, rf]
//       and sequential[dom, sb]
//     implies DRF[dom, kind, loc, wv, rv, ^hb, sb, mo, rf]
//   }
//   for 10
//
// run litmus_SB
//   { some dom : set Action, kind : Action -> Kind,
//          loc : Action -> Loc, wv, rv : Action -> Val,
//          hb, sb, mo, rf : Action -> Action | {
//       valid[dom, kind, loc, wv, rv, ^hb, sb, mo, rf]
//       DRF[dom, kind, loc, wv, rv, ^hb, sb, mo, rf]
//       dom = Action
//       Loc = dom.loc
//       is_core[hb]
//       is_core[sb]
//       // litmus test
//       code_SB[dom, kind, loc, wv, rv, ^hb, sb, mo, rf]
//     }
//   }
//   for 6
//   but 0 NonAtomic, 2 Val
//
// run litmus_IRIW
//   { some dom : set Action, kind : Action -> Kind,
//          loc : Action -> Loc, wv, rv : Action -> Val,
//          hb, sb, mo, rf : Action -> Action | {
//       valid[dom, kind, loc, wv, rv, ^hb, sb, mo, rf]
//       DRF[dom, kind, loc, wv, rv, ^hb, sb, mo, rf]
//       dom = Action
//       Loc = dom.loc
//       is_core[hb]
//       is_core[sb]
//       // litmus test
//       code_IRIW[dom, kind, loc, wv, rv, ^hb, sb, mo, rf]
//     }
//   }
//   for 10
//   but 0 NonAtomic, 2 Val
//
// /*************************************************/
// /* Litmus test code                              */
// /*************************************************/
//
// // SB litmus test without initialisation
// pred code_SB [ dom : set Action, kind : Action -> Kind,
//                loc : Action -> Loc, wv, rv : Action -> Val,
//                hb, sb, mo, rf : Action -> Action ] {
//   some disj wx, wy : kind.Write |
//   some disj rx, ry : kind.Read |  {
//     dom = (wx + wy + rx + ry)
//     (wx -> ry) + (wy -> rx) in sb // allow stronger sb
//     one wx.loc + rx.loc
//     one wy.loc + ry.loc
//     no wx.loc & wy.loc
//     no rf // read from initialisation
//   }
// }
//
// // Comment from JPW - alloy simplifies rel = ((a->b) + (c->d)...
// // Refactor this code?
//
// pred code_IRIW [ dom : set Action, kind : Action -> Kind,
//                  loc : Action -> Loc, wv, rv : Action -> Val,
//                  hb, sb, mo, rf : Action -> Action ] {
//   some disj wx, wy : kind.Write |
//   some disj r1x, r2x, r1y, r2y : kind.Read | {
//     dom = wx + wy + r1x + r2x + r1y + r2y
//     rf = ((wx -> r1x) + (wy -> r2y))
//     ((r1x -> r1y) + (r2y -> r2x)) in sb
//     one wx.loc + r1x.loc + r2x.loc
//     one wy.loc + r1y.loc + r2y.loc
//     no wx.loc & wy.loc
//   }
// }
//