Add concept of non-transferable ballots, as this path through the code has not been covered.

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 four winner-outcomes and six loser-outcomes:

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

enum Method {Plurality, STV}

-- An individual person standing for election
sig Candidate {
    votes: 			  set Ballot, 	-- First preference ballots assigned to this candidate
	transfers: 	      set Ballot,   -- Ballots received by transfer from another candidate
	surplus: 		  set Ballot, 	-- Ballots given to another candidate (on election or elimination)
	outcome: 		  Event
} {
	no b: Ballot | b in votes & transfers
	all b: Ballot | b in votes + transfers implies this in b.assignees
	surplus in votes + transfers
	Election.method = Plurality implies #surplus = 0 and #transfers = 0
    0 < #transfers implies Election.method = STV
    outcome = Winner and Election.method = STV implies
       Scenario.quota + #surplus = #votes
    outcome = Winner implies #transfers = 0
    outcome = QuotaWinner implies surplus in transfers
    outcome = QuotaWinner implies Scenario.quota + #surplus = #votes + #transfers
     all b: Ballot | b in votes implies this in b.assignees
    0 < #surplus implies (outcome = Winner or outcome = QuotaWinner)
    (outcome = EarlyLoser or outcome = TiedEarlyLoser) iff
		(this in Scenario.eliminated and not (#votes + #transfers < Scenario.threshold))
    // All non-sore losers are 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 = 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
    // Quota Winner has a least a quota of votes after transfers
	outcome = QuotaWinner implies
	   Scenario.quota <= #votes + #transfers
    // Quota Winner does not have a quota of first preference votes
	outcome = QuotaWinner 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 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 = QuotaWinner or (outcome = Winner and Election.method = STV))
       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 = 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) 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)
    // Losing outcomes
	all c: Candidate | c in losers iff
		(c.outcome = Loser or c.outcome = EarlyLoser or c.outcome = SoreLoser or
		c.outcome = TiedLoser or c.outcome = TiedEarlyLoser or c.outcome = TiedSoreLoser)
    // STV election quotas
    Election.method = STV implies quota = 1 + BallotBox.size.div[Election.seats+1] and
    	fullQuota = 1 + BallotBox.size.div[Election.constituencySeats + 1]
    Election.method = Plurality implies quota = 1 and fullQuota = 1
 // All ties involve equality between at least one winner and at least one loser
    all w: Candidate | some l: Candidate | w.outcome = TiedWinner and
	 	(l.outcome = TiedLoser or l.outcome = TiedSoreLoser or l.outcome = TiedEarlyLoser) implies
		(#l.votes + #l.transfers = #w.votes + #w.transfers)
  all s: Candidate | some w: Candidate | w.outcome = TiedWinner and
       (s.outcome = SoreLoser or s.outcome = TiedLoser or s.outcome = TiedEarlyLoser) implies
       (#s.votes = #w.votes) or (#s.votes + #s.transfers = #w.votes + #w.transfers)
   // When there is a tied sore loser then there are no non-sore losers
   no disj a,b: Candidate | a.outcome = TiedSoreLoser and
        (b.outcome = TiedLoser or b.outcome = TiedEarlyLoser or
         b.outcome=Loser or b.outcome=EarlyLoser)
    // For each Tied Winner there is a Tied Loser
	all w: Candidate | some l: Candidate | w.outcome = TiedWinner implies
		(l.outcome = TiedLoser or l.outcome = TiedSoreLoser or l.outcome = TiedEarlyLoser)
    // Tied Winners and Tied Losers have an equal number of votes
	all disj l,w: Candidate |
    ((l.outcome = TiedLoser or l.outcome = TiedSoreLoser or l.outcome = TiedEarlyLoser) and
    w.outcome = TiedWinner) implies #w.votes + #w.transfers = #l.votes + #l.transfers
    // Compromise winner must have more votes than any tied winners
	all disj c,t: Candidate | (c.outcome = CompromiseWinner and t.outcome = TiedWinner)
		implies
		#t.votes + #t.transfers < #c.votes + #c.transfers
    // Winners have more votes than non-tied losers
	all w,l: Candidate | w.outcome = Winner and
      (l.outcome = Loser or l.outcome = EarlyLoser or l.outcome = SoreLoser) implies
     ((#l.votes < #w.votes) or (#l.votes + #l.transfers < #w.votes + #w.transfers))
    // For each Tied Loser there is at least one Tied Winner
   all c: Candidate | some w: Candidate |
   (c.outcome = TiedLoser or c.outcome = TiedSoreLoser or c.outcome = TiedEarlyLoser)
		implies w.outcome = TiedWinner
}

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

-- 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
}
{
 	0 < seats and seats <= constituencySeats
 	seats < #Candidate
}

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

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

module Voting

open util/integer

-- 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 four winner-outcomes and six loser-outcomes:

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

enum Method {Plurality, STV}

-- An individual person standing for election
sig Candidate {
    votes: 			  set Ballot, 	-- First preference ballots assigned to this candidate
	transfers: 	      set Ballot,   -- Ballots received by transfer from another candidate
	surplus: 		  set Ballot, 	-- Ballots given to another candidate (on election or elimination)
	outcome: 		  Event
} {
	no b: Ballot | b in votes & transfers
	all b: Ballot | b in votes + transfers implies this in b.assignees
	surplus in votes + transfers
	Election.method = Plurality implies #surplus = 0 and #transfers = 0
    0 < #transfers implies Election.method = STV
    outcome = Winner and Election.method = STV implies
       Scenario.quota + #surplus = #votes
    outcome = Winner implies #transfers = 0
    outcome = QuotaWinner implies surplus in transfers
    outcome = QuotaWinner implies Scenario.quota + #surplus = #votes + #transfers
     all b: Ballot | b in votes implies this in b.assignees
    0 < #surplus implies (outcome = Winner or outcome = QuotaWinner)
    (outcome = EarlyLoser or outcome = TiedEarlyLoser) iff
		(this in Scenario.eliminated and not (#votes + #transfers < Scenario.threshold))
    // All non-sore losers are 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 = 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
    // Quota Winner has a least a quota of votes after transfers
	outcome = QuotaWinner implies
	   Scenario.quota <= #votes + #transfers
    // Quota Winner does not have a quota of first preference votes
	outcome = QuotaWinner 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 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 = QuotaWinner or (outcome = Winner and Election.method = STV))
       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 = 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) 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)
    // Losing outcomes
	all c: Candidate | c in losers iff
		(c.outcome = Loser or c.outcome = EarlyLoser or c.outcome = SoreLoser or
		c.outcome = TiedLoser or c.outcome = TiedEarlyLoser or c.outcome = TiedSoreLoser)
    // STV election quotas
    Election.method = STV implies quota = 1 + BallotBox.size.div[Election.seats+1] and
    	fullQuota = 1 + BallotBox.size.div[Election.constituencySeats + 1]
    Election.method = Plurality implies quota = 1 and fullQuota = 1
 // All ties involve equality between at least one winner and at least one loser
    all w: Candidate | some l: Candidate | w.outcome = TiedWinner and
	 	(l.outcome = TiedLoser or l.outcome = TiedSoreLoser or l.outcome = TiedEarlyLoser) implies
		(#l.votes + #l.transfers = #w.votes + #w.transfers)
  all s: Candidate | some w: Candidate | w.outcome = TiedWinner and
       (s.outcome = SoreLoser or s.outcome = TiedLoser or s.outcome = TiedEarlyLoser) implies
       (#s.votes = #w.votes) or (#s.votes + #s.transfers = #w.votes + #w.transfers)
   // When there is a tied sore loser then there are no non-sore losers
   no disj a,b: Candidate | a.outcome = TiedSoreLoser and
        (b.outcome = TiedLoser or b.outcome = TiedEarlyLoser or
         b.outcome=Loser or b.outcome=EarlyLoser)
    // For each Tied Winner there is a Tied Loser
	all w: Candidate | some l: Candidate | w.outcome = TiedWinner implies
		(l.outcome = TiedLoser or l.outcome = TiedSoreLoser or l.outcome = TiedEarlyLoser)
    // Tied Winners and Tied Losers have an equal number of votes
	all disj l,w: Candidate |
    ((l.outcome = TiedLoser or l.outcome = TiedSoreLoser or l.outcome = TiedEarlyLoser) and
    w.outcome = TiedWinner) implies #w.votes + #w.transfers = #l.votes + #l.transfers
    // Compromise winner must have more votes than any tied winners
	all disj c,t: Candidate | (c.outcome = CompromiseWinner and t.outcome = TiedWinner)
		implies
		#t.votes + #t.transfers < #c.votes + #c.transfers
    // Winners have more votes than non-tied losers
	all w,l: Candidate | w.outcome = Winner and
      (l.outcome = Loser or l.outcome = EarlyLoser or l.outcome = SoreLoser) implies
     ((#l.votes < #w.votes) or (#l.votes + #l.transfers < #w.votes + #w.transfers))
    // For each Tied Loser there is at least one Tied Winner
   all c: Candidate | some w: Candidate |
   (c.outcome = TiedLoser or c.outcome = TiedSoreLoser or c.outcome = TiedEarlyLoser)
		implies w.outcome = TiedWinner
}

-- The Ballot Box
one sig BallotBox {
  spoiltBallots:	set Ballot,		-- empty ballots excluded from count
  size:				Int 				-- number of ballots counted
}
{
    size = #Ballot - #spoiltBallots
	all b: Ballot | b in spoiltBallots iff #b.preferences = 0
}

-- 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
}
{
 	0 < seats and seats <= constituencySeats
 	seats < #Candidate
}

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


more experimental results from ee-benjamin

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

module c11_txn_strengthening[E]

pred apply_map[X,X':Exec_C] {

  X.EV = X'.EV

  X.R = X'.R
  X.W = X'.W
  X.F = X'.F

  X.sb = X'.sb
  X.cd = X'.cd
  X.ad = X'.ad
  X.dd = X'.dd
  X.rf = X'.rf
  X.co = X'.co
  X.sloc = X'.sloc
  X.sthd = X'.sthd
  X.atom = X'.atom

  X.A = X'.A
  X.ACQ = X'.ACQ
  X.REL = X'.REL
  X.SC = X'.SC
  X.NAL = X'.NAL

  X.stxn in X'.stxn

}

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

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

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

  apply_map[X,X']

  X.EV = E
}

run p for 2 Exec, 6 E // none found in 60310s on benjamin (=17 hours)

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

module c11_txn_strengthening[E]

pred apply_map[X,X':Exec_C] {

  X.EV = X'.EV

  X.R = X'.R
  X.W = X'.W
  X.F = X'.F

  X.sb = X'.sb
  X.cd = X'.cd
  X.ad = X'.ad
  X.dd = X'.dd
  X.rf = X'.rf
  X.co = X'.co
  X.sloc = X'.sloc
  X.sthd = X'.sthd
  X.atom = X'.atom

  X.A = X'.A
  X.ACQ = X'.ACQ
  X.REL = X'.REL
  X.SC = X'.SC
  X.NAL = X'.NAL

  X.stxn in X'.stxn

}

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

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

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

  apply_map[X,X']

  X.EV = E
}

run p for 2 Exec, 6 E // started on benjamin at 1228 on fri 3 nov


add first version (not work)

add first version (not work)

// Illust Logic
abstract sig Cell {
  color: Color,
  hnext: lone Cell,
  vnext: lone Cell
}

enum Color {Black, White}

fun range(start, end : Cell, r: Cell -> Cell): Cell{
  (start + start.^r) & (end.^(~r) + end)
}

pred all_black(cells : Cell, size: Int){
  #cells = size
  all c: cells{
    c.color = Black
  }
}

pred all_white(cells : Cell){
  all c: cells{
    c.color = White
  }
}

fun from(start: Cell, next: Cell -> Cell): Cell{
  start + start.^next
}

one sig Cell_0_0 extends Cell {}
one sig Cell_0_1 extends Cell {}
one sig Cell_0_2 extends Cell {}
one sig Cell_0_3 extends Cell {}
one sig Cell_0_4 extends Cell {}
one sig Cell_0_5 extends Cell {}
one sig Cell_0_6 extends Cell {}
one sig Cell_0_7 extends Cell {}
one sig Cell_0_8 extends Cell {}
one sig Cell_0_9 extends Cell {}
one sig Cell_1_0 extends Cell {}
one sig Cell_1_1 extends Cell {}
one sig Cell_1_2 extends Cell {}
one sig Cell_1_3 extends Cell {}
one sig Cell_1_4 extends Cell {}
one sig Cell_1_5 extends Cell {}
one sig Cell_1_6 extends Cell {}
one sig Cell_1_7 extends Cell {}
one sig Cell_1_8 extends Cell {}
one sig Cell_1_9 extends Cell {}
one sig Cell_2_0 extends Cell {}
one sig Cell_2_1 extends Cell {}
one sig Cell_2_2 extends Cell {}
one sig Cell_2_3 extends Cell {}
one sig Cell_2_4 extends Cell {}
one sig Cell_2_5 extends Cell {}
one sig Cell_2_6 extends Cell {}
one sig Cell_2_7 extends Cell {}
one sig Cell_2_8 extends Cell {}
one sig Cell_2_9 extends Cell {}
one sig Cell_3_0 extends Cell {}
one sig Cell_3_1 extends Cell {}
one sig Cell_3_2 extends Cell {}
one sig Cell_3_3 extends Cell {}
one sig Cell_3_4 extends Cell {}
one sig Cell_3_5 extends Cell {}
one sig Cell_3_6 extends Cell {}
one sig Cell_3_7 extends Cell {}
one sig Cell_3_8 extends Cell {}
one sig Cell_3_9 extends Cell {}
one sig Cell_4_0 extends Cell {}
one sig Cell_4_1 extends Cell {}
one sig Cell_4_2 extends Cell {}
one sig Cell_4_3 extends Cell {}
one sig Cell_4_4 extends Cell {}
one sig Cell_4_5 extends Cell {}
one sig Cell_4_6 extends Cell {}
one sig Cell_4_7 extends Cell {}
one sig Cell_4_8 extends Cell {}
one sig Cell_4_9 extends Cell {}
one sig Cell_5_0 extends Cell {}
one sig Cell_5_1 extends Cell {}
one sig Cell_5_2 extends Cell {}
one sig Cell_5_3 extends Cell {}
one sig Cell_5_4 extends Cell {}
one sig Cell_5_5 extends Cell {}
one sig Cell_5_6 extends Cell {}
one sig Cell_5_7 extends Cell {}
one sig Cell_5_8 extends Cell {}
one sig Cell_5_9 extends Cell {}
one sig Cell_6_0 extends Cell {}
one sig Cell_6_1 extends Cell {}
one sig Cell_6_2 extends Cell {}
one sig Cell_6_3 extends Cell {}
one sig Cell_6_4 extends Cell {}
one sig Cell_6_5 extends Cell {}
one sig Cell_6_6 extends Cell {}
one sig Cell_6_7 extends Cell {}
one sig Cell_6_8 extends Cell {}
one sig Cell_6_9 extends Cell {}
one sig Cell_7_0 extends Cell {}
one sig Cell_7_1 extends Cell {}
one sig Cell_7_2 extends Cell {}
one sig Cell_7_3 extends Cell {}
one sig Cell_7_4 extends Cell {}
one sig Cell_7_5 extends Cell {}
one sig Cell_7_6 extends Cell {}
one sig Cell_7_7 extends Cell {}
one sig Cell_7_8 extends Cell {}
one sig Cell_7_9 extends Cell {}
one sig Cell_8_0 extends Cell {}
one sig Cell_8_1 extends Cell {}
one sig Cell_8_2 extends Cell {}
one sig Cell_8_3 extends Cell {}
one sig Cell_8_4 extends Cell {}
one sig Cell_8_5 extends Cell {}
one sig Cell_8_6 extends Cell {}
one sig Cell_8_7 extends Cell {}
one sig Cell_8_8 extends Cell {}
one sig Cell_8_9 extends Cell {}
one sig Cell_9_0 extends Cell {}
one sig Cell_9_1 extends Cell {}
one sig Cell_9_2 extends Cell {}
one sig Cell_9_3 extends Cell {}
one sig Cell_9_4 extends Cell {}
one sig Cell_9_5 extends Cell {}
one sig Cell_9_6 extends Cell {}
one sig Cell_9_7 extends Cell {}
one sig Cell_9_8 extends Cell {}
one sig Cell_9_9 extends Cell {}
fact matrix_adj {
  Cell_0_0.vnext = Cell_0_1
  Cell_0_1.vnext = Cell_0_2
  Cell_0_2.vnext = Cell_0_3
  Cell_0_3.vnext = Cell_0_4
  Cell_0_4.vnext = Cell_0_5
  Cell_0_5.vnext = Cell_0_6
  Cell_0_6.vnext = Cell_0_7
  Cell_0_7.vnext = Cell_0_8
  Cell_0_8.vnext = Cell_0_9
  no Cell_0_9.vnext
  Cell_1_0.vnext = Cell_1_1
  Cell_1_1.vnext = Cell_1_2
  Cell_1_2.vnext = Cell_1_3
  Cell_1_3.vnext = Cell_1_4
  Cell_1_4.vnext = Cell_1_5
  Cell_1_5.vnext = Cell_1_6
  Cell_1_6.vnext = Cell_1_7
  Cell_1_7.vnext = Cell_1_8
  Cell_1_8.vnext = Cell_1_9
  no Cell_1_9.vnext
  Cell_2_0.vnext = Cell_2_1
  Cell_2_1.vnext = Cell_2_2
  Cell_2_2.vnext = Cell_2_3
  Cell_2_3.vnext = Cell_2_4
  Cell_2_4.vnext = Cell_2_5
  Cell_2_5.vnext = Cell_2_6
  Cell_2_6.vnext = Cell_2_7
  Cell_2_7.vnext = Cell_2_8
  Cell_2_8.vnext = Cell_2_9
  no Cell_2_9.vnext
  Cell_3_0.vnext = Cell_3_1
  Cell_3_1.vnext = Cell_3_2
  Cell_3_2.vnext = Cell_3_3
  Cell_3_3.vnext = Cell_3_4
  Cell_3_4.vnext = Cell_3_5
  Cell_3_5.vnext = Cell_3_6
  Cell_3_6.vnext = Cell_3_7
  Cell_3_7.vnext = Cell_3_8
  Cell_3_8.vnext = Cell_3_9
  no Cell_3_9.vnext
  Cell_4_0.vnext = Cell_4_1
  Cell_4_1.vnext = Cell_4_2
  Cell_4_2.vnext = Cell_4_3
  Cell_4_3.vnext = Cell_4_4
  Cell_4_4.vnext = Cell_4_5
  Cell_4_5.vnext = Cell_4_6
  Cell_4_6.vnext = Cell_4_7
  Cell_4_7.vnext = Cell_4_8
  Cell_4_8.vnext = Cell_4_9
  no Cell_4_9.vnext
  Cell_5_0.vnext = Cell_5_1
  Cell_5_1.vnext = Cell_5_2
  Cell_5_2.vnext = Cell_5_3
  Cell_5_3.vnext = Cell_5_4
  Cell_5_4.vnext = Cell_5_5
  Cell_5_5.vnext = Cell_5_6
  Cell_5_6.vnext = Cell_5_7
  Cell_5_7.vnext = Cell_5_8
  Cell_5_8.vnext = Cell_5_9
  no Cell_5_9.vnext
  Cell_6_0.vnext = Cell_6_1
  Cell_6_1.vnext = Cell_6_2
  Cell_6_2.vnext = Cell_6_3
  Cell_6_3.vnext = Cell_6_4
  Cell_6_4.vnext = Cell_6_5
  Cell_6_5.vnext = Cell_6_6
  Cell_6_6.vnext = Cell_6_7
  Cell_6_7.vnext = Cell_6_8
  Cell_6_8.vnext = Cell_6_9
  no Cell_6_9.vnext
  Cell_7_0.vnext = Cell_7_1
  Cell_7_1.vnext = Cell_7_2
  Cell_7_2.vnext = Cell_7_3
  Cell_7_3.vnext = Cell_7_4
  Cell_7_4.vnext = Cell_7_5
  Cell_7_5.vnext = Cell_7_6
  Cell_7_6.vnext = Cell_7_7
  Cell_7_7.vnext = Cell_7_8
  Cell_7_8.vnext = Cell_7_9
  no Cell_7_9.vnext
  Cell_8_0.vnext = Cell_8_1
  Cell_8_1.vnext = Cell_8_2
  Cell_8_2.vnext = Cell_8_3
  Cell_8_3.vnext = Cell_8_4
  Cell_8_4.vnext = Cell_8_5
  Cell_8_5.vnext = Cell_8_6
  Cell_8_6.vnext = Cell_8_7
  Cell_8_7.vnext = Cell_8_8
  Cell_8_8.vnext = Cell_8_9
  no Cell_8_9.vnext
  Cell_9_0.vnext = Cell_9_1
  Cell_9_1.vnext = Cell_9_2
  Cell_9_2.vnext = Cell_9_3
  Cell_9_3.vnext = Cell_9_4
  Cell_9_4.vnext = Cell_9_5
  Cell_9_5.vnext = Cell_9_6
  Cell_9_6.vnext = Cell_9_7
  Cell_9_7.vnext = Cell_9_8
  Cell_9_8.vnext = Cell_9_9
  no Cell_9_9.vnext
  Cell_0_0.hnext = Cell_1_0
  Cell_1_0.hnext = Cell_2_0
  Cell_2_0.hnext = Cell_3_0
  Cell_3_0.hnext = Cell_4_0
  Cell_4_0.hnext = Cell_5_0
  Cell_5_0.hnext = Cell_6_0
  Cell_6_0.hnext = Cell_7_0
  Cell_7_0.hnext = Cell_8_0
  Cell_8_0.hnext = Cell_9_0
  no Cell_9_0.hnext
  Cell_0_1.hnext = Cell_1_1
  Cell_1_1.hnext = Cell_2_1
  Cell_2_1.hnext = Cell_3_1
  Cell_3_1.hnext = Cell_4_1
  Cell_4_1.hnext = Cell_5_1
  Cell_5_1.hnext = Cell_6_1
  Cell_6_1.hnext = Cell_7_1
  Cell_7_1.hnext = Cell_8_1
  Cell_8_1.hnext = Cell_9_1
  no Cell_9_1.hnext
  Cell_0_2.hnext = Cell_1_2
  Cell_1_2.hnext = Cell_2_2
  Cell_2_2.hnext = Cell_3_2
  Cell_3_2.hnext = Cell_4_2
  Cell_4_2.hnext = Cell_5_2
  Cell_5_2.hnext = Cell_6_2
  Cell_6_2.hnext = Cell_7_2
  Cell_7_2.hnext = Cell_8_2
  Cell_8_2.hnext = Cell_9_2
  no Cell_9_2.hnext
  Cell_0_3.hnext = Cell_1_3
  Cell_1_3.hnext = Cell_2_3
  Cell_2_3.hnext = Cell_3_3
  Cell_3_3.hnext = Cell_4_3
  Cell_4_3.hnext = Cell_5_3
  Cell_5_3.hnext = Cell_6_3
  Cell_6_3.hnext = Cell_7_3
  Cell_7_3.hnext = Cell_8_3
  Cell_8_3.hnext = Cell_9_3
  no Cell_9_3.hnext
  Cell_0_4.hnext = Cell_1_4
  Cell_1_4.hnext = Cell_2_4
  Cell_2_4.hnext = Cell_3_4
  Cell_3_4.hnext = Cell_4_4
  Cell_4_4.hnext = Cell_5_4
  Cell_5_4.hnext = Cell_6_4
  Cell_6_4.hnext = Cell_7_4
  Cell_7_4.hnext = Cell_8_4
  Cell_8_4.hnext = Cell_9_4
  no Cell_9_4.hnext
  Cell_0_5.hnext = Cell_1_5
  Cell_1_5.hnext = Cell_2_5
  Cell_2_5.hnext = Cell_3_5
  Cell_3_5.hnext = Cell_4_5
  Cell_4_5.hnext = Cell_5_5
  Cell_5_5.hnext = Cell_6_5
  Cell_6_5.hnext = Cell_7_5
  Cell_7_5.hnext = Cell_8_5
  Cell_8_5.hnext = Cell_9_5
  no Cell_9_5.hnext
  Cell_0_6.hnext = Cell_1_6
  Cell_1_6.hnext = Cell_2_6
  Cell_2_6.hnext = Cell_3_6
  Cell_3_6.hnext = Cell_4_6
  Cell_4_6.hnext = Cell_5_6
  Cell_5_6.hnext = Cell_6_6
  Cell_6_6.hnext = Cell_7_6
  Cell_7_6.hnext = Cell_8_6
  Cell_8_6.hnext = Cell_9_6
  no Cell_9_6.hnext
  Cell_0_7.hnext = Cell_1_7
  Cell_1_7.hnext = Cell_2_7
  Cell_2_7.hnext = Cell_3_7
  Cell_3_7.hnext = Cell_4_7
  Cell_4_7.hnext = Cell_5_7
  Cell_5_7.hnext = Cell_6_7
  Cell_6_7.hnext = Cell_7_7
  Cell_7_7.hnext = Cell_8_7
  Cell_8_7.hnext = Cell_9_7
  no Cell_9_7.hnext
  Cell_0_8.hnext = Cell_1_8
  Cell_1_8.hnext = Cell_2_8
  Cell_2_8.hnext = Cell_3_8
  Cell_3_8.hnext = Cell_4_8
  Cell_4_8.hnext = Cell_5_8
  Cell_5_8.hnext = Cell_6_8
  Cell_6_8.hnext = Cell_7_8
  Cell_7_8.hnext = Cell_8_8
  Cell_8_8.hnext = Cell_9_8
  no Cell_9_8.hnext
  Cell_0_9.hnext = Cell_1_9
  Cell_1_9.hnext = Cell_2_9
  Cell_2_9.hnext = Cell_3_9
  Cell_3_9.hnext = Cell_4_9
  Cell_4_9.hnext = Cell_5_9
  Cell_5_9.hnext = Cell_6_9
  Cell_6_9.hnext = Cell_7_9
  Cell_7_9.hnext = Cell_8_9
  Cell_8_9.hnext = Cell_9_9
  no Cell_9_9.hnext
}
fact {
  let next = hnext {
    some c1: from[Cell_0_0, next] {
      all_white[range[from[Cell_0_0, next], c1.~next, next]]
      some c2: c1.^next {
        all_black[range[c1, c2, next], 3]
        all_white[c2.^next]
      }
    }
    some c1: from[Cell_0_1, next] {
      all_white[range[from[Cell_0_1, next], c1.~next, next]]
      some c2: c1.^next {
        all_black[range[c1, c2, next], 2]
        some c1: c2.next.^next {
          all_white[range[c2.next.^next, c1.~next, next]]
          some c2: c1.^next {
            all_black[range[c1, c2, next], 2]
            all_white[c2.^next]
          }
        }
      }
    }
    some c1: from[Cell_0_2, next] {
      all_white[range[from[Cell_0_2, next], c1.~next, next]]
      some c2: c1.^next {
        all_black[range[c1, c2, next], 1]
        some c1: c2.next.^next {
          all_white[range[c2.next.^next, c1.~next, next]]
          some c2: c1.^next {
            all_black[range[c1, c2, next], 1]
            some c1: c2.next.^next {
              all_white[range[c2.next.^next, c1.~next, next]]
              some c2: c1.^next {
                all_black[range[c1, c2, next], 1]
                all_white[c2.^next]
              }
            }
          }
        }
      }
    }
    some c1: from[Cell_0_3, next] {
      all_white[range[from[Cell_0_3, next], c1.~next, next]]
      some c2: c1.^next {
        all_black[range[c1, c2, next], 3]
        some c1: c2.next.^next {
          all_white[range[c2.next.^next, c1.~next, next]]
          some c2: c1.^next {
            all_black[range[c1, c2, next], 3]
            all_white[c2.^next]
          }
        }
      }
    }
    some c1: from[Cell_0_4, next] {
      all_white[range[from[Cell_0_4, next], c1.~next, next]]
      some c2: c1.^next {
        all_black[range[c1, c2, next], 5]
        all_white[c2.^next]
      }
    }
    some c1: from[Cell_0_5, next] {
      all_white[range[from[Cell_0_5, next], c1.~next, next]]
      some c2: c1.^next {
        all_black[range[c1, c2, next], 7]
        all_white[c2.^next]
      }
    }
    some c1: from[Cell_0_6, next] {
      all_white[range[from[Cell_0_6, next], c1.~next, next]]
      some c2: c1.^next {
        all_black[range[c1, c2, next], 7]
        all_white[c2.^next]
      }
    }
    some c1: from[Cell_0_7, next] {
      all_white[range[from[Cell_0_7, next], c1.~next, next]]
      some c2: c1.^next {
        all_black[range[c1, c2, next], 7]
        all_white[c2.^next]
      }
    }
    some c1: from[Cell_0_8, next] {
      all_white[range[from[Cell_0_8, next], c1.~next, next]]
      some c2: c1.^next {
        all_black[range[c1, c2, next], 7]
        all_white[c2.^next]
      }
    }
    some c1: from[Cell_0_9, next] {
      all_white[range[from[Cell_0_9, next], c1.~next, next]]
      some c2: c1.^next {
        all_black[range[c1, c2, next], 5]
        all_white[c2.^next]
      }
    }
  }
  let next = vnext {
    some c1: from[Cell_0_0, next] {
      all_white[range[from[Cell_0_0, next], c1.~next, next]]
      some c2: c1.^next {
        all_black[range[c1, c2, next], 4]
        all_white[c2.^next]
      }
    }
    some c1: from[Cell_1_0, next] {
      all_white[range[from[Cell_1_0, next], c1.~next, next]]
      some c2: c1.^next {
        all_black[range[c1, c2, next], 6]
        all_white[c2.^next]
      }
    }
    some c1: from[Cell_2_0, next] {
      all_white[range[from[Cell_2_0, next], c1.~next, next]]
      some c2: c1.^next {
        all_black[range[c1, c2, next], 7]
        all_white[c2.^next]
      }
    }
    some c1: from[Cell_3_0, next] {
      all_white[range[from[Cell_3_0, next], c1.~next, next]]
      some c2: c1.^next {
        all_black[range[c1, c2, next], 9]
        all_white[c2.^next]
      }
    }
    some c1: from[Cell_4_0, next] {
      all_white[range[from[Cell_4_0, next], c1.~next, next]]
      some c2: c1.^next {
        all_black[range[c1, c2, next], 2]
        some c1: c2.next.^next {
          all_white[range[c2.next.^next, c1.~next, next]]
          some c2: c1.^next {
            all_black[range[c1, c2, next], 7]
            all_white[c2.^next]
          }
        }
      }
    }
    some c1: from[Cell_5_0, next] {
      all_white[range[from[Cell_5_0, next], c1.~next, next]]
      some c2: c1.^next {
        all_black[range[c1, c2, next], 1]
        some c1: c2.next.^next {
          all_white[range[c2.next.^next, c1.~next, next]]
          some c2: c1.^next {
            all_black[range[c1, c2, next], 6]
            all_white[c2.^next]
          }
        }
      }
    }
    some c1: from[Cell_6_0, next] {
      all_white[range[from[Cell_6_0, next], c1.~next, next]]
      some c2: c1.^next {
        all_black[range[c1, c2, next], 2]
        some c1: c2.next.^next {
          all_white[range[c2.next.^next, c1.~next, next]]
          some c2: c1.^next {
            all_black[range[c1, c2, next], 4]
            all_white[c2.^next]
          }
        }
      }
    }
    some c1: from[Cell_7_0, next] {
      all_white[range[from[Cell_7_0, next], c1.~next, next]]
      some c2: c1.^next {
        all_black[range[c1, c2, next], 3]
        all_white[c2.^next]
      }
    }
    some c1: from[Cell_8_0, next] {
      all_white[range[from[Cell_8_0, next], c1.~next, next]]
      some c2: c1.^next {
        all_black[range[c1, c2, next], 1]
        all_white[c2.^next]
      }
    }
    some c1: from[Cell_9_0, next] {
      all_white[range[from[Cell_9_0, next], c1.~next, next]]
      some c2: c1.^next {
        all_black[range[c1, c2, next], 2]
        all_white[c2.^next]
      }
    }
  }
}
run{} for 1 but 5 int

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


add correct assertion

add correct assertion

open util/ordering[Time]
sig Time {}

one sig Memory {
	turn: Int -> Time,
	flag: Int -> Int -> Time
}{
	all t: Time {
		one flag[0].t
		one flag[1].t
		no flag[Int - 0 - 1].t
	}
}

one sig PC {
	proc: Int -> Int -> Time,
	current_pid: Int -> Time
}{
	all t: Time {
		one proc[0].t
		one proc[1].t
		no proc[Int - 0 - 1].t
	}
}

fact {
	// 最初はメモリはみんな0
	let t = first {
		Memory.turn.t = 0
		Memory.flag[0].t = 0
		Memory.flag[1].t = 0
		// 最初はプログラムカウンタは0
		PC.proc[0].t = 0
		PC.proc[1].t = 0
 	}
}

pred store(t: Time, target: univ -> Time, value: univ){
	one value
	target.t = value
}

pred must_wait(t: Time, pid: Int){
	let other = (0 + 1) - pid {
		Memory.flag[other].t = 1 // otherがwaitしている
		Memory.turn.t = other // otherが優先権を持っている
	}
}

pred no_change(t: Time, changable: univ -> Time){
	changable.t = changable.(t.prev)
}

pred step(t: Time) {
	// 各時刻でどちらかのプロセスが1命令実行する
	some pid: (0 + 1) {
		PC.current_pid.t = pid
		let pc = PC.proc[pid].(t.prev),
				nextpc = PC.proc[pid].t,
				other = (0 + 1) - pid
		{

			(pc = 0) => {
				// flag[0] = 1
				store[t, Memory.flag[pid], 1]
				nextpc = plus[pc, 1]
				no_change[t, Memory.turn]
			}
			(pc = 1) => {
				// flag[0] = 1
				store[t, Memory.turn, other]
				nextpc = plus[pc, 1]
				no_change[t, Memory.flag[pid]]
			}
			(pc = 2) => {
				// while( flag[1] && turn == 1 );
				must_wait[t, pid] => {
					nextpc = pc
				}else{
					nextpc = plus[pc, 1]
				}
				no_change[t, Memory.turn]
				no_change[t, Memory.flag[pid]]
			}
			(pc = 3) => {
				// flag[0] = 0
				store[t, Memory.flag[pid], 0]
				nextpc = 0
				no_change[t, Memory.turn]
			}

			// no change
			no_change[t, PC.proc[other]]
			no_change[t, Memory.flag[other]]
		}
	}
}

check MutualExclusion {
	no t: Time {
		PC.proc[0].t = 3
		PC.proc[1].t = 3
	}
} for 15 Time

check BoundedWaiting_Bad {
	no t: Time, pid: Int {
		PC.proc[pid].t = 2
		PC.proc[pid].(t.next) = 2
		PC.proc[pid].(t.next.next) = 2
		PC.proc[pid].(t.next.next.next) = 2
		PC.proc[pid].(t.next.next.next.next) = 2
	}
} for 15 Time

check BoundedWaiting {
	no t, t': Time, pid: Int {
		let range = Time - t.prevs - t'.nexts {
			// あるプロセスがずっと2(ロック待ち)で
			all t'': range | PC.proc[pid].t'' = 2
			// その間、もう片方のプロセスが2回以上3(クリティカルセクション)を実行
			#{t'': range |
				PC.proc[PC.current_pid.t''].t'' = 3
			} >= 2
		}
	}
} for 15 Time

fact {
	all t: Time - first {
		step[t]
	}
}
run {
} for exactly 20 Time

open util/ordering[Time]
sig Time {}

one sig Memory {
	turn: Int -> Time,
	flag: Int -> Int -> Time
}{
	all t: Time {
		one flag[0].t
		one flag[1].t
		no flag[Int - 0 - 1].t
	}
}

one sig PC {
	proc: Int -> Int -> Time
}{
	all t: Time {
		one proc[0].t
		one proc[1].t
		no proc[Int - 0 - 1].t
	}
}

fact {
	// 最初はメモリはみんな0
	let t = first {
		Memory.turn.t = 0
		Memory.flag[0].t = 0
		Memory.flag[1].t = 0
		// 最初はプログラムカウンタは0
		PC.proc[0].t = 0
		PC.proc[1].t = 0
 	}
}

pred store(t: Time, target: univ -> Time, value: univ){
	one value
	target.t = value
}

pred must_wait(t: Time, pid: Int){
	let other = (0 + 1) - pid {
		Memory.flag[other].t = 1 // otherがwaitしている
		Memory.turn.t = other // otherが優先権を持っている
	}
}

pred no_change(t: Time, changable: univ -> Time){
	changable.t = changable.(t.prev)
}

pred step(t: Time) {
	// 各時刻でどちらかのプロセスが1命令実行する
	some pid: (0 + 1) {
		let pc = PC.proc[pid].(t.prev),
				nextpc = PC.proc[pid].t,
				other = (0 + 1) - pid
		{

			(pc = 0) => {
				// flag[0] = 1
				store[t, Memory.flag[pid], 1]
				nextpc = plus[pc, 1]
				no_change[t, Memory.turn]
			}
			(pc = 1) => {
				// flag[0] = 1
				store[t, Memory.turn, other]
				nextpc = plus[pc, 1]
				no_change[t, Memory.flag[pid]]
			}
			(pc = 2) => {
				// while( flag[1] && turn == 1 );
				must_wait[t, pid] => {
					nextpc = pc
				}else{
					nextpc = plus[pc, 1]
				}
				no_change[t, Memory.turn]
				no_change[t, Memory.flag[pid]]
			}
			(pc = 3) => {
				// flag[0] = 0
				store[t, Memory.flag[pid], 0]
				nextpc = 0
				no_change[t, Memory.turn]
			}

			// no change
			no_change[t, PC.proc[other]]
			no_change[t, Memory.flag[other]]
		}
	}
}

check MutualExclusion {
	no t: Time {
		PC.proc[0].t = 3
		PC.proc[1].t = 3
	}
} for 25 Time

check BoundedWaiting {
	no t: Time, pid: Int {
		PC.proc[pid].t = 2
		PC.proc[pid].(t.next) = 2
		PC.proc[pid].(t.next.next) = 2
		PC.proc[pid].(t.next.next.next) = 2
		PC.proc[pid].(t.next.next.next.next) = 2
	}
} for 7 Time

fact {
	all t: Time - first {
		step[t]
	}
}
run {
} for exactly 20 Time


Minor changes

Minor changes

/** Takes a user defined signature and defines the relations according to it. */
module feature_model_2[Feature]

open util/relation

one sig Root in Feature {}

abstract sig FeatureModel {
	mandatory: Feature -> Feature,
	optional: Feature -> Feature,
	alternative: Feature -> Feature,
 	_or: Feature -> Feature,

	requires: Feature -> Feature,
	excludes: Feature -> Feature
}

/** EmptyFeatureModel is the model that has no relations, GivenFeatureModel is the model that user defines */
one sig EmptyFeatureModel, GivenFeatureModel extends FeatureModel {}

fact {
	func_definitions[GivenFeatureModel]
	NoRelations[EmptyFeatureModel]
	Root.*(FeatureModel.(mandatory + optional + alternative + _or ) )= Feature // Any feature, connected to this model, must be reachable from the root.
}

private pred func_definitions[m: FeatureModel] {
	no m.mandatory & m.optional
	no m.mandatory & m.alternative
	no m.mandatory & m._or
	no m.mandatory & m.requires
	no m.mandatory & m.excludes

	no m.optional & m.alternative
	no m.optional & m._or
	no m.optional & m.requires
	no m.optional & m.excludes

	no m.alternative & m._or
	no m.alternative & m.requires
	no m.alternative & m.excludes

	no m._or & m.requires
	no m._or& m.excludes

	no m.requires & m.excludes

	no m.mandatory & ~(m.optional)
	no m.mandatory & ~(m.alternative)
	no m.mandatory & ~(m._or)
	no m.mandatory & ~(m.requires)
	no m.mandatory & ~(m.excludes)

	no m.optional & ~(m.alternative)
	no m.optional & ~(m._or)
	no m.optional & ~(m.requires)
	no m.optional & ~(m.excludes)

	no m.alternative & ~(m._or)
	no m.alternative & ~(m.requires)
	no m.alternative & ~(m.excludes)

	no m._or & ~(m.requires)
	no m._or & ~(m.excludes)

	no m.requires & ~(m.excludes)

	irreflexive[m.mandatory]
	irreflexive[m.optional]
	irreflexive[m.alternative]
	irreflexive[m._or]
	irreflexive[m.requires]
	irreflexive[m.excludes]
	antisymmetric[m.mandatory]
	antisymmetric[m.optional]
	antisymmetric[m.alternative]
	antisymmetric[m._or]
	antisymmetric[m.requires]
}

/** Possible Extensions for Configuration */

// There are instances that includes features.
sig Instance {
	includes: set Feature
}

// All configurations are unique
fact all_instances_unique {
--	all disj i, i': Instance | i.includes != i'.includes
	all i, i': Instance | i !=i' implies i.includes != i'.includes
}

fact configuration_rules {
	all i: Instance {
		Root in i.includes																																														/** root */
		all f1: Feature, f2: f1.(FeatureModel.optional) | f2 in i.includes => f1 in i.includes 																				/** optional */
		all f1: Feature, f2: f1.(FeatureModel.mandatory) | f2 in i.includes <=> f1 in i.includes 																			/** mandatory */
		all f1: Feature | f1 in i.includes and some f1.(FeatureModel._or) <=> some f1.(FeatureModel._or) & i.includes 								/** or */
		all f1: Feature | f1 in i.includes and some f1.(FeatureModel.alternative) <=> some f1.(FeatureModel.alternative) & i.includes			/** alternative (1) */
		all f1: i.includes, f2: f1.(FeatureModel.alternative), f3: f1.(FeatureModel.alternative) - f2 | !(f2 in i.includes and f3 in i.includes) 		/** alternative (2) */
		all f1: Feature, f2: f1.(FeatureModel.requires) | f1 in i.includes => f2 in i.includes																				/** requires */
		all f1: Feature, f2: f1.(FeatureModel.excludes) | !(f1 in i.includes and f2 in i.includes) 																			/** excludes */
	}
}
/** Possible Instances Extension */

pred Root[f: Feature] {
	Root = f
}

pred Mandatory[f1, f2: one Feature] {
	f1 -> f2 in GivenFeatureModel.mandatory
}

pred Optional[f1, f2: Feature] {
	f1 -> f2 in GivenFeatureModel.optional
}

pred Alternative[f1: Feature, f2: Feature] {
	f1 -> f2 in GivenFeatureModel.alternative
}

pred Or[f1, f2: Feature] {
	f1 -> f2 in GivenFeatureModel._or
}

pred Requires[f1, f2: Feature] {
	f1 -> f2 in GivenFeatureModel.requires
}

pred Excludes[f1, f2: Feature] {
	f1 -> f2 in GivenFeatureModel.excludes
}

pred Mandatory[r: Feature -> Feature] {
	r = GivenFeatureModel.mandatory
}

pred Optional[r: Feature -> Feature] {
	r = GivenFeatureModel.optional
}

pred Alternative[r: Feature -> Feature] {
	r = GivenFeatureModel.alternative
}

pred Or[r: Feature -> Feature] {
	r = GivenFeatureModel._or
}

pred Requires[r: Feature -> Feature] {
	r = GivenFeatureModel.requires
}

pred Excludes[r: Feature -> Feature] {
	r + ~r = GivenFeatureModel.excludes
}

pred NoMandatory {
	no GivenFeatureModel.mandatory
}

pred NoOptional {
	no GivenFeatureModel.optional
}

pred NoAlternative {
	no GivenFeatureModel.alternative
}

pred NoOr {
	no GivenFeatureModel._or
}

pred NoRequires {
	no GivenFeatureModel.requires
}

pred NoExcludes {
	no GivenFeatureModel.excludes
}

pred NoRelations[m: FeatureModel] {
	no m.excludes
	no m.requires
	no m._or
	no m.alternative
	no m.mandatory
	no m.optional
}

/** Takes a user defined signature and defines the relations according to it. */
module feature_model_2[Feature]

open util/relation

one sig Root in Feature {}

abstract sig FeatureModel {
	mandatory: Feature -> Feature,
	optional: Feature -> Feature,
	alternative: Feature -> Feature,
 	_or: Feature -> Feature,

	requires: Feature -> Feature,
	excludes: Feature -> Feature
}

/** EmptyFeatureModel is the model that has no relations, GivenFeatureModel is the model that user defines */
one sig EmptyFeatureModel, GivenFeatureModel extends FeatureModel {}

fact {
	func_definitions[GivenFeatureModel]
	NoRelations[EmptyFeatureModel]
	all f: ran[FeatureModel.(requires + excludes)] | some f.~(FeatureModel.(mandatory + optional + alternative + _or))
	let rel = FeatureModel.(mandatory + optional + alternative + _or + requires + excludes) | Root.*rel = ran[rel] + dom[rel] // Any feature, connected to this model, must be reachable from the root.
}

private pred func_definitions[m: FeatureModel] {
	no m.mandatory & m.optional
	no m.mandatory & m.alternative
	no m.mandatory & m._or
	no m.mandatory & m.requires
	no m.mandatory & m.excludes

	no m.optional & m.alternative
	no m.optional & m._or
	no m.optional & m.requires
	no m.optional & m.excludes

	no m.alternative & m._or
	no m.alternative & m.requires
	no m.alternative & m.excludes

	no m._or & m.requires
	no m._or& m.excludes

	no m.requires & m.excludes

	no m.mandatory & ~(m.optional)
	no m.mandatory & ~(m.alternative)
	no m.mandatory & ~(m._or)
	no m.mandatory & ~(m.requires)
	no m.mandatory & ~(m.excludes)

	no m.optional & ~(m.alternative)
	no m.optional & ~(m._or)
	no m.optional & ~(m.requires)
	no m.optional & ~(m.excludes)

	no m.alternative & ~(m._or)
	no m.alternative & ~(m.requires)
	no m.alternative & ~(m.excludes)

	no m._or & ~(m.requires)
	no m._or & ~(m.excludes)

	no m.requires & ~(m.excludes)

	irreflexive[m.mandatory]
	irreflexive[m.optional]
	irreflexive[m.alternative]
	irreflexive[m._or]
	irreflexive[m.requires]
	irreflexive[m.excludes]
	antisymmetric[m.mandatory]
	antisymmetric[m.optional]
	antisymmetric[m.alternative]
	antisymmetric[m._or]
	antisymmetric[m.requires]
}

/** Possible Instances Extension */
// There are instances that includes features.
sig Instance {
	includes: set Feature
}

// There are not two equal instances.
fact all_instances_unique {
	all i: Instance, i': Instance-i | i.includes != i'.includes
}

fact diversity_rules {
	all i: Instance {
		 Root in i.includes																																														/** root */
		all f1: Feature, f2: f1.(FeatureModel.optional) | f2 in i.includes => f1 in i.includes 																				/** optional */
		all f1: Feature, f2: f1.(FeatureModel.mandatory) | f2 in i.includes <=> f1 in i.includes 																			/** mandatory */
		all f1: Feature | f1 in i.includes and some f1.(FeatureModel._or) <=> some f1.(FeatureModel._or) & i.includes 								/** or */
		all f1: Feature | f1 in i.includes and some f1.(FeatureModel.alternative) <=> some f1.(FeatureModel.alternative) & i.includes			/** alternative (1) */
		all f1: i.includes, f2: f1.(FeatureModel.alternative), f3: f1.(FeatureModel.alternative) - f2 | !(f2 in i.includes and f3 in i.includes) 		/** alternative (2) */
		all f1: Feature, f2: f1.(FeatureModel.requires) | f1 in i.includes => f2 in i.includes																				/** requires */
		all f1: Feature, f2: f1.(FeatureModel.excludes) | !(f1 in i.includes and f2 in i.includes) 																			/** excludes */
	}
}
/** Possible Instances Extension */

pred Root[f: Feature] {
	Root = f
}

pred Mandatory[f1, f2: one Feature] {
	f1 -> f2 in GivenFeatureModel.mandatory
}

pred Optional[f1, f2: Feature] {
	f1 -> f2 in GivenFeatureModel.optional
}

pred Alternative[f1: Feature, f2: Feature] {
	f1 -> f2 in GivenFeatureModel.alternative
}

pred Or[f1, f2: Feature] {
	f1 -> f2 in GivenFeatureModel._or
}

pred Requires[f1, f2: Feature] {
	f1 -> f2 in GivenFeatureModel.requires
}

pred Excludes[f1, f2: Feature] {
	f1 -> f2 in GivenFeatureModel.excludes
}

pred Mandatory[r: Feature -> Feature] {
	r = GivenFeatureModel.mandatory
}

pred Optional[r: Feature -> Feature] {
	r = GivenFeatureModel.optional
}

pred Alternative[r: Feature -> Feature] {
	r = GivenFeatureModel.alternative
}

pred Or[r: Feature -> Feature] {
	r = GivenFeatureModel._or
}

pred Requires[r: Feature -> Feature] {
	r = GivenFeatureModel.requires
}

pred Excludes[r: Feature -> Feature] {
	r + ~r = GivenFeatureModel.excludes
}

pred NoMandatory {
	no GivenFeatureModel.mandatory
}

pred NoOptional {
	no GivenFeatureModel.optional
}

pred NoAlternative {
	no GivenFeatureModel.alternative
}

pred NoOr {
	no GivenFeatureModel._or
}

pred NoRequires {
	no GivenFeatureModel.requires
}

pred NoExcludes {
	no GivenFeatureModel.excludes
}

pred NoRelations[m: FeatureModel] {
	no m.excludes
	no m.requires
	no m._or
	no m.alternative
	no m.mandatory
	no m.optional
}


misunderstand who is father

misunderstand who is father

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

sig Time {
	event: lone Event
}

fact {
	no first.event
	all t: Time - first {one t.event}
}

abstract sig Person {
	state: State -> Time,
	partner: Person -> Time,
	parent_bio: set Person,
  parent_think: set Person
}{
	all t: Time | one state.t
	all t: Time | lone partner.t
	let p = parent_bio {
		no p or born_in_scope
  }
	let p = parent_think {
		no p or born_in_scope
  }
}

pred born_in_scope(p: Person){
	p.state.first = NotExist
	p.state.last != NotExist
}

abstract sig Man, Woman extends Person {}

enum State {NotExist, Married, NotMarried}

enum Event {Marriage, Divorce, Birth}

pred init (t: Time) {
	all p: Person | p.state.t in NotMarried + NotExist
	all p: Person | p.partner.t = none
}

pred change_state (
	target : Person,
	t, t': Time,
	before, after : State){
		some target
		all p: target {
			p.state.t = before
			p.state.t' = after
		}
		// others don't change their state
		all other: (Person - target) {
			other.state.t = other.state.t'
		}
}

pred keep_partner(others: Person, t, t': Time){
	all other: others {
		other.partner.t = other.partner.t'
	}
}
pred step (t, t': Time) {
	{some disj p1 : Man, p2 : Woman {
		{
			t'.event = Marriage
			change_state[p1 + p2, t, t', NotMarried, Married]
			p1.partner.t' = p2
			p2.partner.t' = p1
			keep_partner[Person - p1 - p2, t, t']
		} or {
			t'.event = Divorce
			change_state[p1 + p2, t, t', Married, NotMarried]
			p1.partner.t' = none
			p2.partner.t' = none
			keep_partner[Person - p1 - p2, t, t']
		}
	}}
	or
	some p: Person {
		// birth
		t'.event = Birth
		change_state[p, t, t', NotExist, NotMarried]
		let father = p.parent_bio & Man {
			one father
			father.state.t != NotExist
		}
		let mother = p.parent_bio & Woman {
			one mother
			mother.state.t != NotExist
			let hasband = mother.partner.t {
				// p always think his biological mother is his mother
				// if mother married, p think mother's hasband is his father
				// no other person is tought as parent
				p.parent_think = mother + hasband
			}
		}
		keep_partner[Person, t, t']
	}
}

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

run {
	some parent_bio
	some p: Person {
		p.parent_bio & Man != p.parent_think & Man
		one p.parent_think & Man
	}
} for exactly 4 Person, 4 Time

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

sig Time {
	event: lone Event
}

fact {
	no first.event
	all t: Time - first {one t.event}
}

abstract sig Person {
	state: State -> Time,
	partner: Person -> Time,
	parent_bio: set Person,
  parent_think: set Person
}{
	all t: Time | one state.t
	all t: Time | lone partner.t
	let p = parent_bio {
		no p or born_in_scope
  }
	let p = parent_think {
		no p or born_in_scope
  }
}

pred born_in_scope(p: Person){
	p.state.first = NotExist
	p.state.last != NotExist
}

abstract sig Man, Woman extends Person {}

enum State {NotExist, Married, NotMarried}

enum Event {Marriage, Divorce, Birth}

pred init (t: Time) {
	all p: Person | p.state.t in NotMarried + NotExist
	all p: Person | p.partner.t = none
}

pred change_state (
	target : Person,
	t, t': Time,
	before, after : State){
		some target
		all p: target {
			p.state.t = before
			p.state.t' = after
		}
		// others don't change their state
		all other: (Person - target) {
			other.state.t = other.state.t'
		}
}

pred keep_partner(others: Person, t, t': Time){
	all other: others {
		other.partner.t = other.partner.t'
	}
}
pred step (t, t': Time) {
	{some disj p1 : Man, p2 : Woman {
		{
			t'.event = Marriage
			change_state[p1 + p2, t, t', NotMarried, Married]
			p1.partner.t' = p2
			p2.partner.t' = p1
			keep_partner[Person - p1 - p2, t, t']
		} or {
			t'.event = Divorce
			change_state[p1 + p2, t, t', Married, NotMarried]
			p1.partner.t' = none
			p2.partner.t' = none
			keep_partner[Person - p1 - p2, t, t']
		}
	}}
	or
	some p: Person {
		// birth
		t'.event = Birth
		change_state[p, t, t', NotExist, NotMarried]
		some father: p.parent_bio & Man {
			one father
			father.state.t != NotExist
		}
		some mother: p.parent_bio & Woman {
			one mother
			mother.state.t != NotExist
			let hasband = mother.partner.t {
				// p always think his biological mother is his mother
				// if mother married, p think mother's hasband is his father
				// no other person is tought as parent
				p.parent_think = mother + hasband
			}
		}
		keep_partner[Person, t, t']
	}
}

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

run {
	some parent_bio
	some p: Person {p.parent_bio & Man != p.parent_think & Man}
} for exactly 4 Person, 4 Time


refactor and fix bug

refactor and fix bug

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

sig Time {}

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

abstract sig Man, Woman extends Person {}

enum State {Married, NotMarried}

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

pred change_state (
	p1 : Man, p2 : Woman,
	t, t': Time,
	before, after : State){
		p1.state.t = before
		p2.state.t = before
		p1.state.t' = after
		p2.state.t' = after
		// others don't change their state
		all other: (Person - p1 - p2) {
			other.state.t = other.state.t'
		}
}

pred step (t, t': Time) {
	some disj p1 : Man, p2 : Woman {
		change_state[p1, p2, t, t', NotMarried, Married]
		or
		change_state[p1, p2, t, t', Married, NotMarried]
	}
}

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

run {} for exactly 4 Person, 4 Time

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

sig Time {}

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

abstract sig Man, Woman extends Person {}

enum State {Married, NotMarried}

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

pred step (t, t': Time) {
	some disj p1 : Man, p2 : Woman {
		{{
			// marrige
			p1.state.t = NotMarried and p2.state.t = NotMarried
			p1.state.t' = Married and p2.state.t' = Married
		} or {
			// divorce
			p1.state.t = Married and p2.state.t = Married
			p1.state.t' = NotMarried and p2.state.t' = NotMarried
		}}
		// others don't change their state
		let others = (Person - p1 - p2) {
			others.state.t = others.state.t'
		}
	}
}

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

run {} for 3 Person, 5 Time


alloy updated again

alloy updated again

open util/boolean

// Car, User

sig Car {
	id: Int,
	available: Bool,
	location: Location,
	unlocked: Bool,
	battery_level: Int
} {
	id>0
	battery_level >= 0
	battery_level <= 100
}

sig User {
	credential: Credential,
	payment_info: Payment_Info,
	location: Location
}
sig Credential {}

sig Payment_Info {}

// Reservation, Ride

sig Reservation {
	user: User,
	car: Car,
	start_area: Safe_Area,
	start_time: Time,
	current_cost: Int,
	final_discharged_cost: lone Int,
	expired: Bool,
	ride: lone Ride
} {
	current_cost >= 0
	final_discharged_cost >= 0
}

sig Ride {
	reservation: Reservation,
	passengers: Int,
	pickup_time: Time,
	release_time: lone Time,
	release_battery_level: lone Int,
	release_area: lone Safe_Area,
	release_plugged: lone Bool
} {
	passengers >= 1
	passengers <= 4
	release_battery_level >= 0
	release_battery_level <= 100
	not areEqual[pickup_time, release_time]
}

// Time and CurrentTime

sig Time {
	hour: Int,
	minute: Int
} {
	hour >= 0
	hour =< 23
	minute >= 0
	minute =< 59
}

sig CurrentTime extends Time {}

// Location, Areas

sig Location {
	latitude: Int,
	longitude: Int
}
sig Area {
	center: Location,
//	radius: Int
} {
//	radius > 0
}
sig Safe_Area extends Area {}
sig Special_Safe_Area extends Safe_Area {}

/* ----------- Functions ------------ */
fun minutesDiff[t, t': Time]:Int {
	t.minute>t'.minute
	implies
		sub[t.minute, t'.minute]
	else
		sub[t'.minute, t.minute]
}

fun hoursDiff[t, t': Time]: Int {
	t.hour>=t'.hour
	implies(
		sub[t.hour, t'.hour]
	) else (
		sub[t'.hour, t.hour]
	)
}

//Return the cost for a ride from time t to time t'
fun cost[t, t': Time]: Int {
		t.hour = t'.hour
		implies (
			minutesDiff[t, t']
		)
		else (
			t.hour>t'.hour
			implies(
				add[add[sub[60, t'.minute], mul[sub[hoursDiff[t,t'], 1], 60]], t.minute]   //(60-t'.minute) + (t'.hour-t.hour-1)*60 + t.minute
			)
			else(
				add[add[sub[60, t.minute], mul[sub[hoursDiff[t,t'], 1], 60]], t'.minute]   //(60-t.minute) + (t.hour-t'.hour-1)*60 + t'.minute
			)
		)
}
// ----------- Predicates -----------

// Returns true if t == t'
pred areEqual[t, t': Time] {
	t.hour = t'.hour and t.minute = t'.minute
}

// Returns true if t - t' <= 1h
pred isLessThanOneHourAhead[t, t': Time] {
	areEqual[t, t']
	or
		(t.hour = t'.hour and t.minute > t'.minute)
	or
		(t.hour = add[t'.hour,1] and add[sub[60, t'.minute], t.minute] < 60)
}

// Returns true if t >= t'
pred comesAfterOrEqual[t, t': Time] {
		t.hour = t'.hour
		implies t.minute >= t'.minute
		else t.hour >= t'.hour
}

// Returns true if the max distance between latitudes and longitudes is 5
pred isNear[l, l': Location] {
	(l.latitude >= l'.latitude implies
		sub[l.latitude, l'.latitude] <= 4
	else
		sub[l'.latitude, l.latitude] <= 4)
	and
	(l.longitude >= l'.longitude implies
		sub[l.longitude, l'.longitude] <= 4
	else
		sub[l'.longitude, l.longitude] <= 4)
}

pred isFarFromSpecialSafeArea[area: Safe_Area] {
			all ssa: Special_Safe_Area |(
			(int ssa.center.latitude >= int area.center.latitude
			implies
				sub[ssa.center.latitude, area.center.latitude] > 15
			else
				sub[area.center.latitude, ssa.center.latitude] > 15
			)
			and
			(int ssa.center.longitude >= int area.center.longitude implies
				sub[ssa.center.longitude, area.center.longitude] > 15
			else
				sub[area.center.longitude, ssa.center.longitude] > 15)
	)
}
// Reservation r is open <=> r is not expired and "it has not a ride yet or its ride has no release_time"
pred isActive[r: Reservation] {
	r.expired = False and (
		no r.ride
		or
		no r.ride.release_time
	)
}

// ----------- Facts -------------

// There's only a current time
fact currentTimeForeverAlone {
	#CurrentTime = 1
}

//There are no different Time with the same time
/*fact alwaysDifferent {
	all t, t': Time | t!=t' implies (not areEqual[t, t'])
}*/

// CurrentTime is after all the times in the model
fact currentTimeIsAlwaysAhead {
	all t: Time |
		all ct: CurrentTime |
			comesAfterOrEqual[ct, t]
}

// Each credential/password/payment info is used for a user
fact eachCredentialCorrespondToAUser {
	User.credential=Credential
}

fact eachPaymentInfoCorrespondToAUser {
	User.payment_info=Payment_Info
}

// Different users <=> different credentials
fact noUsersWithSameCredentials {
	all u1, u2: User |
		u1 != u2
		iff
		u1.credential != u2.credential
}

// Different cars <=> different IDs
fact noCarsWithSameIDs {
	all c1, c2: Car |
		c1 != c2
		iff
		c1.id != c2.id
}

// If a ride has a reservation, then that reservation has that ride.
fact ridesAndReservationRelation {
	all rid: Ride | (
		rid = rid.reservation.ride
	) and
	all res: Reservation | (
		one res.ride
		implies
			res=res.ride.reservation
	)
}

// There can't be two reservations made by the same user both open
// COMMENT: Actually it's possible that a user makes a wrong reservation and he lets it expires, while he makes another one
/*
fact noConsecutiveReservations {
	all r, r': Reservation | (
		r.user = r'.user
		implies not (
			isOpen[r] and isOpen[r']
		)
	)
}*/

// There can't be two reservations r1 and r2 for the same car overlapping.

fact carsCanBeReservedByOneUserAtOnce {
	all c: Car | (
		all r, r': Reservation | (
			(r.car = c and r'.car = c and r != r' and comesAfterOrEqual[r'.start_time, r.start_time])
			implies (
					(some r.ride and some r.ride.release_time and comesAfterOrEqual[r'.start_time, r.ride.release_time])
					or
					(r.expired = True and not isLessThanOneHourAhead[r'.start_time, r.start_time])
			)
		)
	)
}

// A car is available if it has no reservations open and has enough battery
fact carAvailableCondition {
	all c: Car |
		c.available = True
		iff(
		(no res: Reservation |
			res.car = c and isActive[res])
		 and  c.battery_level>80
		)
}

// A reservation is expired if there's is not a ride whose pickup_time is less than one hour after the
//    reservation start_time.
fact reservationExpiredCondition {
	all res: Reservation |
		res.expired = True
		iff
		(all currentTime: CurrentTime |
			not isLessThanOneHourAhead[currentTime, res.start_time]
		)
		and
		no res.ride
}

// The pickup time of a ride should be in one hour from its reservation start_time
fact pickupTimeConstraint {
	all rid: Ride | (
		isLessThanOneHourAhead[rid.pickup_time, rid.reservation.start_time]
	)
}

// release_time is always after pickup_time
fact releaseTimeIsAfterPickupTime {
	all rid: Ride | (
		no rid.release_time
		or
		comesAfterOrEqual[rid.release_time, rid.pickup_time]
	)
}

// A car is unlocked if there's a reservation not expired between a user and that car,
//    such user is near it and
//    he hasn't finished the ride (the ride associated with that reservation
//    doesn't have a release_time).
fact carUnlockedConstraint {
	all c: Car | (
		c.unlocked = True
		iff
		some r: Reservation | (
			r.car = c and isActive[r] and isNear[c.location, r.user.location]
		)
	)
}

//If there is a release time, there are also a release release_battery and a release_area
fact releaseInfoConstraint{
	all rid: Ride| (
		(some rid.release_time
		iff
		some rid.release_battery_level) and
		(some rid.release_area
		iff
		some rid.release_time) and
		(some rid.release_time
		 iff
		some rid.release_plugged)
	)
}

fact feeConstraint {
	all r: Reservation | (
		r.expired = True
		implies
		r.current_cost = 10 and r.final_discharged_cost = 10
	)
}

//The actual cost of a reservation is proportional to minutes spent in the car
fact costOfAReservationConstraint {
	all res: Reservation | (
		res.expired = False
		implies (
			no res.ride
			implies
				res.current_cost=0
			else(
				no res.ride.release_time
				implies(
					all ct : CurrentTime |
						res.current_cost=cost[ct, res.ride.pickup_time]
				)
				else
					res.current_cost=cost[res.ride.release_time, res.ride.pickup_time]
			)
		)
	)
}

//Passengers discount of 10%
fact passengersDiscount{
	all res: Reservation | (
		res.expired = False and one res.ride.release_time and res.ride.passengers>2
		implies(
			res.final_discharged_cost=div[mul[res.current_cost, 9],10]
		)
	)
}

//Non-empty battery discount of 20%
fact nonEmptyBatteryDiscount{
	all res: Reservation | (
		res.expired = False and res.ride.release_battery_level>=50
		implies(
			res.final_discharged_cost=div[mul[res.current_cost, 4],5]
		)
	)
}

//Car released charging discount of 30%
fact chargingDiscount{
	all res: Reservation | (
	res.expired = False and (res.ride.release_area in Special_Safe_Area) and res.ride.release_plugged = True
		implies(
			res.final_discharged_cost=div[mul[res.current_cost, 7],10]
		)
	)
}

//Car released far and with low battery extra-charging of 30%
fact lowBatteryExtraFee{
	all res: Reservation | (
		res.expired = False and res.ride.release_battery_level<20 and isFarFromSpecialSafeArea[res.ride.release_area]
		implies(
			res.final_discharged_cost=div[mul[res.current_cost, 13],10]
		)
	)
}
// ------------- Assertions ---------------

// car available => car locked

assert availableEntailsLocked {
	all c: Car | c.available = True implies c.unlocked = False
}

// car unlocked => car not available

assert unlockedEntailsNotAvailable {
	all c: Car | c.unlocked = True implies c.available = False
}

// reservation expired => no ride

assert expiredEntailsNoRide {
	all r: Reservation | r.expired = True implies no r.ride
}

// reservation active => car not available

assert activeEntailsNotAvailable {
	all r: Reservation | isActive[r] implies r.car.available = False
}

// FALSE

assert falseByPurpose {
	all r: Reservation | r.start_time = r.ride.release_time
	or
	all ride: Ride |  all ct: CurrentTime| ride.release_time=ct
}

// ------------ Show world! --------------

pred show {
	#User = 1
	#Reservation = 1
	some r: Reservation | (r.ride.release_battery_level>=50)
	some c: Car | c.available = True
//	some c: Car | c.unlocked = False

}

run show for 8 Int
//check availableEntailsLocked for 7 Int
//check unlockedEntailsNotAvailable for 7 Int
//check expiredEntailsNoRide for 7 Int
//check activeEntailsNotAvailable for 7 Int
//check falseByPurpose for 8 Int

open util/boolean

// Car, User

sig Car {
	id: Int,
	available: Bool,
	location: Location,
	unlocked: Bool,
	battery_level: Int
} {
	id>0
	battery_level >= 0
	battery_level <= 10
}

sig User {
	credential: Credential,
	payment_info: Payment_Info,
	location: Location
}
sig Credential {}

sig Payment_Info {}

// Reservation, Ride

sig Reservation {
	user: User,
	car: Car,
	start_area: Safe_Area,
	start_time: Time,
	current_cost: Int,
	final_discharged_cost: lone Int,
	expired: Bool,
	ride: lone Ride
} {
	current_cost >= 0
	final_discharged_cost >= 0
}

sig Ride {
	reservation: Reservation,
	passengers: Int,
	pickup_time: Time,
	release_time: lone Time,
	release_battery_level: lone Int,
	release_area: lone Safe_Area,
	release_plugged: lone Bool
} {
	passengers >= 1
	passengers <= 4
	release_battery_level >= 0
	release_battery_level <= 10
	not areEqual[pickup_time, release_time]
}

// Time and CurrentTime

sig Time {
	hour: Int,
	minute: Int
} {
	hour >= 0
	hour =< 23
	minute >= 0
	minute =< 59
}

sig CurrentTime extends Time {}

// Location, Areas

sig Location {
	latitude: Int,
	longitude: Int
}
sig Area {
	center: Location,
//	radius: Int
} {
//	radius > 0
}
sig Safe_Area extends Area {}
sig Special_Safe_Area extends Safe_Area {}

/* ----------- Functions ------------ */
fun minutesDiff[t, t': Time]:Int {
	t.minute>t'.minute
	implies
		sub[t.minute, t'.minute]
	else
		sub[t'.minute, t.minute]
}

fun hoursDiff[t, t': Time]: Int {
	t.hour>=t'.hour
	implies(
		sub[t.hour, t'.hour]
	) else (
		sub[t'.hour, t.hour]
	)
}

//Return the cost for a ride from time t to time t'
fun cost[t, t': Time]: Int {
		t.hour = t'.hour
		implies (
			minutesDiff[t, t']
		)
		else (
			t.hour>t'.hour
			implies(
				add[add[sub[60, t'.minute], mul[sub[hoursDiff[t,t'], 1], 60]], t.minute]   //(60-t'.minute) + (t'.hour-t.hour-1)*60 + t.minute
			)
			else(
				add[add[sub[60, t.minute], mul[sub[hoursDiff[t,t'], 1], 60]], t'.minute]   //(60-t.minute) + (t.hour-t'.hour-1)*60 + t'.minute
			)
		)
}
// ----------- Predicates -----------

// Returns true if t == t'
pred areEqual[t, t': Time] {
	t.hour = t'.hour and t.minute = t'.minute
}

// Returns true if t - t' <= 1h
pred isLessThanOneHourAhead[t, t': Time] {
	areEqual[t, t']
	or
		(t.hour = t'.hour and t.minute > t'.minute)
	or
		(t.hour = add[t'.hour,1] and add[sub[60, t'.minute], t.minute] < 60)
}

// Returns true if t >= t'
pred comesAfterOrEqual[t, t': Time] {
		t.hour = t'.hour
		implies t.minute >= t'.minute
		else t.hour >= t'.hour
}

// Returns true if the max distance between latitudes and longitudes is 5
pred isNear[l, l': Location] {
	(l.latitude >= l'.latitude implies
		sub[l.latitude, l'.latitude] <= 4
	else
		sub[l'.latitude, l.latitude] <= 4)
	and
	(l.longitude >= l'.longitude implies
		sub[l.longitude, l'.longitude] <= 4
	else
		sub[l'.longitude, l.longitude] <= 4)
}

pred isFarFromSpecialSafeArea[area: Safe_Area] {
			all ssa: Special_Safe_Area |(
			(int ssa.location.latitude >= int area.location.latitude
			implies
				sub[ssa.location.latitude, area.location.latitude] > 15
			else
				sub[area.location.latitude, ssa.location.latitude] > 15
			)
			and
			(int ssa.location.longitude >= int area.location.longitude implies
				sub[ssa.location.longitude, area.location.longitude] > 15
			else
				sub[area.location.longitude, ssa.location.longitude] > 15)
	)
}
// Reservation r is open <=> r is not expired and "it has not a ride yet or its ride has no release_time"
pred isActive[r: Reservation] {
	r.expired = False and (
		no r.ride
		or
		no r.ride.release_time
	)
}

// ----------- Facts -------------

// There's only a current time
fact currentTimeForeverAlone {
	#CurrentTime = 1
}

//There are no different Time with the same time
/*fact alwaysDifferent {
	all t, t': Time | t!=t' implies (not areEqual[t, t'])
}*/

// CurrentTime is after all the times in the model
fact currentTimeIsAlwaysAhead {
	all t: Time |
		all ct: CurrentTime |
			comesAfterOrEqual[ct, t]
}

// Each credential/password/payment info is used for a user
fact eachCredentialCorrespondToAUser {
	User.credential=Credential
}

fact eachPaymentInfoCorrespondToAUser {
	User.payment_info=Payment_Info
}

// Different users <=> different credentials
fact noUsersWithSameCredentials {
	all u1, u2: User |
		u1 != u2
		iff
		u1.credential != u2.credential
}

// Different cars <=> different IDs
fact noCarsWithSameIDs {
	all c1, c2: Car |
		c1 != c2
		iff
		c1.id != c2.id
}

// If a ride has a reservation, then that reservation has that ride.
fact ridesAndReservationRelation {
	all rid: Ride | (
		rid = rid.reservation.ride
	) and
	all res: Reservation | (
		one res.ride
		implies
			res=res.ride.reservation
	)
}

// There can't be two reservations made by the same user both open
// COMMENT: Actually it's possible that a user makes a wrong reservation and he lets it expires, while he makes another one
/*
fact noConsecutiveReservations {
	all r, r': Reservation | (
		r.user = r'.user
		implies not (
			isOpen[r] and isOpen[r']
		)
	)
}*/

// There can't be two reservations r1 and r2 for the same car overlapping.

fact carsCanBeReservedByOneUserAtOnce {
	all c: Car | (
		all r, r': Reservation | (
			(r.car = c and r'.car = c and r != r' and comesAfterOrEqual[r'.start_time, r.start_time])
			implies (
					(some r.ride and some r.ride.release_time and comesAfterOrEqual[r'.start_time, r.ride.release_time])
					or
					(r.expired = True and not isLessThanOneHourAhead[r'.start_time, r.start_time])
			)
		)
	)
}

// A car is available if it has no reservations open and has enough battery
fact carAvailableCondition {
	all c: Car |
		c.available = True
		iff
		(no res: Reservation |
			res.car = c and isActive[res]
			and c.battery_level>80
		)
}

// A reservation is expired if there's is not a ride whose pickup_time is less than one hour after the
//    reservation start_time.
fact reservationExpiredCondition {
	all res: Reservation |
		res.expired = True
		iff
		(all currentTime: CurrentTime |
			not isLessThanOneHourAhead[currentTime, res.start_time]
		)
		and
		no res.ride
}

// The pickup time of a ride should be in one hour from its reservation start_time
fact pickupTimeConstraint {
	all rid: Ride | (
		isLessThanOneHourAhead[rid.pickup_time, rid.reservation.start_time]
	)
}

// release_time is always after pickup_time
fact releaseTimeIsAfterPickupTime {
	all rid: Ride | (
		no rid.release_time
		or
		comesAfterOrEqual[rid.release_time, rid.pickup_time]
	)
}

// A car is unlocked if there's a reservation not expired between a user and that car,
//    such user is near it and
//    he hasn't finished the ride (the ride associated with that reservation
//    doesn't have a release_time).
fact carUnlockedConstraint {
	all c: Car | (
		c.unlocked = True
		iff
		some r: Reservation | (
			r.car = c and isActive[r] and isNear[c.location, r.user.location]
		)
	)
}

//If there is a release time, there are also a release release_battery and a release_area
fact releaseInfoConstraint{
	all rid: Ride| (
		one rid.release_time
		iff
		(one rid.release_battery_level and one rid.release_area and one rid.release_plugged)
	)
}

fact feeConstraint {
	all r: Reservation | (
		r.expired = True
		implies
		r.current_cost = 10 and r.final_discharged_cost = 10
	)
}

//The actual cost of a reservation is proportional to minutes spent in the car
fact costOfAReservationConstraint {
	all res: Reservation | (
		res.expired = False
		implies (
			no res.ride
			implies
				res.current_cost=0
			else(
				no res.ride.release_time
				implies(
					all ct : CurrentTime |
						res.current_cost=cost[ct, res.ride.pickup_time]
				)
				else
					res.current_cost=cost[res.ride.release_time, res.ride.pickup_time]
			)
		)
	)
}

//Passengers discount of 10%
fact passengersDiscount{
	all res: Reservation | (
		res.expired = False and one res.ride.release_time and res.ride.passengers>2
		implies(
			res.final_discharged_cost=div[mul[res.current_cost, 9],10]
		)
	)
}

//Non-empty battery discount of 20%
fact passengersDiscount{
	all res: Reservation | (
		res.expired = False and res.ride.release_battery_level>=50
		implies(
			res.final_discharged_cost=div[mul[res.current_cost, 4],5]
		)
	)
}

//Car released charging discount of 30%
fact passengersDiscount{
	all res: Reservation | (
		res.expired = False and (res.ride.release_area in Special_Safe_Area) and release_plugged = True
		implies(
			res.final_discharged_cost=div[mul[res.current_cost, 7],10]
		)
	)
}

//Car released far and with low battery extra-charging of 30%
fact passengersDiscount{
	all res: Reservation | (
		res.expired = False and res.ride.release_battery_level<20 and isFarFromSpecialSafeArea[res.ride.release_area]
		implies(
			res.final_discharged_cost=div[mul[res.current_cost, 13],10]
		)
	)
}
// ------------- Assertions ---------------

// car available => car locked

assert availableEntailsLocked {
	all c: Car | c.available = True implies c.unlocked = False
}

// car unlocked => car not available

assert unlockedEntailsNotAvailable {
	all c: Car | c.unlocked = True implies c.available = False
}

// reservation expired => no ride

assert expiredEntailsNoRide {
	all r: Reservation | r.expired = True implies no r.ride
}

// reservation active => car not available

assert activeEntailsNotAvailable {
	all r: Reservation | isActive[r] implies r.car.available = False
}

// FALSE

assert falseByPurpose {
	all r: Reservation | r.start_time = r.ride.release_time
}

// ------------ Show world! --------------

pred show {
	#User = 1
	#Reservation = 1
	all r: Reservation | ((one r.ride.release_time) and r.ride.passengers>=3)
//	some c: Car | c.unlocked = True
//	some c: Car | c.unlocked = False

}

run show for 8 Int
//check availableEntailsLocked for 7 Int
//check unlockedEntailsNotAvailable for 7 Int
//check expiredEntailsNoRide for 7 Int
//check activeEntailsNotAvailable for 7 Int
//check falseByPurpose for 7 Int