unmarried mother

unmarried mother

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

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
}{
	all t: Time | one state.t
	all t: Time | lone partner.t
	let p = parent_bio {
		no p or
		{state.first = NotExist and 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
}

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 step (t, t': Time) {
	{some disj p1 : Man, p2 : Woman {
		{
			t'.event = Marriage
			change_state[p1 + p2, t, t', NotMarried, Married]
		} or {
			t'.event = Divorce
			change_state[p1 + p2, t, t', Married, NotMarried]
		}
	}}
	or
	some p: Person {
		// birth
		//t'.event = Birth
		change_state[p, t, t', NotExist, NotMarried]
		some father: p.parent_bio & Man {father.state.t != NotExist}
		some mother: p.parent_bio & Woman {mother.state.t != NotExist}
	}
}

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

run {
	some parent_bio
} for exactly 4 Person, 4 Time


add parent

add parent

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

sig Time {}

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

abstract sig Man, Woman extends Person {}

enum State {NotExist, Married, NotMarried}

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

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 step (t, t': Time) {
	{some disj p1 : Man, p2 : Woman {
		// marriage
		change_state[p1 + p2, t, t', NotMarried, Married]
		or
		// divorce
		change_state[p1 + p2, t, t', Married, NotMarried]
	}}
	or
	some p: Person {
		// birth
		change_state[p, t, t', NotExist, NotMarried]
		some father: p.parent_bio & Man {father.state.t != NotExist}
		some mother: p.parent_bio & Woman {mother.state.t != NotExist}
	}
}

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

run {
	some parent_bio
} 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,
}{
	all t: Time | one state.t
}

abstract sig Man, Woman extends Person {}

enum State {NotExist, Married, NotMarried}

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

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 step (t, t': Time) {
	{some disj p1 : Man, p2 : Woman {
		// marriage
		change_state[p1 + p2, t, t', NotMarried, Married]
		or
		// divorce
		change_state[p1 + p2, t, t', Married, NotMarried]
	}}
	or
	some p: Person {
		// birth
		change_state[p, t, t', NotExist, NotMarried]
	}
}

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

run {} for exactly 4 Person, 4 Time


fix bug: parent works now

fix bug: parent works now

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
}{
	all t: Time | one state.t
	all t: Time | lone partner.t
	let p = parent_bio {
		no p or
		{state.first = NotExist and 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
}

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 step (t, t': Time) {
	{some disj p1 : Man, p2 : Woman {
		{
			t'.event = Marriage
			change_state[p1 + p2, t, t', NotMarried, Married]
		} or {
			t'.event = Divorce
			change_state[p1 + p2, t, t', Married, NotMarried]
		}
	}}
	or
	some p: Person {
		// birth
		//t'.event = Birth
		change_state[p, t, t', NotExist, NotMarried]
		some father: p.parent_bio & Man {father.state.t != NotExist}
		some mother: p.parent_bio & Woman {mother.state.t != NotExist}
	}
}

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

run {
	some parent_bio
} 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,
	partner: Person -> Time,
	parent_bio: set Person
}{
	all t: Time | one state.t
	all t: Time | lone partner.t
	let p = parent_bio {no p or {one p & Man and one p & Woman}}
}

abstract sig Man, Woman extends Person {}

enum State {NotExist, Married, NotMarried}

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

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 step (t, t': Time) {
	{some disj p1 : Man, p2 : Woman {
		// marriage
		change_state[p1 + p2, t, t', NotMarried, Married]
		or
		// divorce
		change_state[p1 + p2, t, t', Married, NotMarried]
	}}
	or
	some p: Person {
		// birth
		change_state[p, t, t', NotExist, NotMarried]
		some father: p.parent_bio & Man {father.state.t != NotExist}
		some mother: p.parent_bio & Woman {mother.state.t != NotExist}
	}
}

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

run {
	some parent_bio
} for exactly 4 Person, 4 Time


Making lock-elision bug search more general (the transaction need not see the initial value of lock -- it may now see any value of the lock variable except one set by a lock() method).

open ../archs/exec_arm8L[E]
open ../models/aarch64_txn[E] as M

module arm8_lock_elision[E]

pred apply_map[X,X':Exec_Arm8L, map:E->E] {

  map in (X.EV one-> X'.EV)

  // no critical sections remain
  no X'.(LkT + UkT + LkN + UkN)

  // suppose we don't have transactions in the source program
  no X.stxn

  // events in the same critical section (where the critical
  // section is one that is to be transactionalised), map to events
  // in the same transaction.
  (X.EV - X.UkT) <: scst[X] :> (X.EV - X.UkT) = map.(X'.stxn).~map

  // the set of lock-related events introduced by the mapping
  let L = map[X.(LkT + UkT + LkN + UkN)] {

    // Mildly interesting observation: transactional memory models
    // are not monotonic w.r.t. adding sequencing edges

    X'.sthd = ~map.(X.sthd).map

    all e1, e2 : X.EV |
      (some e1.map and some e2.map) implies
      ((e1 -> e2 in X.sb) iff (map[e1] -> map[e2] in X'.sb))

    X.ad =   map.((X'.EV - L) <: (X'.ad)   :> (X'.EV - L)).~map
    X.cd =   map.((X'.EV - L) <: (X'.cd)   :> (X'.EV - L)).~map
    X.dd =   map.((X'.EV - L) <: (X'.dd)   :> (X'.EV - L)).~map
    X.atom = map.((X'.EV - L) <: (X'.atom) :> (X'.EV - L)).~map
    X.rf =   map.((X'.EV - L) <: (X'.rf)   :> (X'.EV - L)).~map
    X.co =   map.((X'.EV - L) <: (X'.co)   :> (X'.EV - L)).~map

    X.R     = (X'.R     - L).~map
    X.W     = (X'.W     - L).~map
    X.F     = (X'.F     - L).~map
    X.DMBST = (X'.DMBST - L).~map
    X.DMBLD = (X'.DMBLD - L).~map
    X.ISB   = (X'.ISB   - L).~map
    X.SCACQ = (X'.SCACQ - L).~map
    X.SCREL = (X'.SCREL - L).~map

    // lock-related events in X' are on the same location
    X'.sloc = (L -> L) + ((X'.EV - L) <: ~map.(X.sloc).map :> (X'.EV - L))

    // non-call events map to non-library events
    all e : X.EV - X.LkT - X.LkN - X.UkT - X.UkN {
	  one e.map
    }

    // lock() to be transactionalised
	all e : X.LkT | some e1 : X'.EV {
      e.map = e1
      e1 in X'.R - X'.SCACQ // e1 is a lock-related read event
	  //e1 not in ran[X'.rf] // e1 sees the lock is not taken
    }

    // the transaction must not read a write that acquires the lock
    no X.LkN <: map.(X'.rf).~map :> X.LkT

	// unlock() to be transactionalised
    all e : X.UkT | no e.map

    // lock() to be kept as a normal lock
    all e : X.LkN | some disj e1, e2 : X'.EV {
      e.map = e1 + e2
      (e1 -> e2) in imm[X'.sb] & X'.atom // e1 and e2 form an RMW pair
      e1 in X'.SCACQ & X'.R // e1 is a lock-related acquire read
      e2 in X'.W // e2 is a lock-related write
    }

    // unlock() to be kept as a normal unlock
    all e : X.UkN | some e1 : X'.EV {
 	  e.map = e1
      e1 in X'.SCREL & X'.W // eL is a lock-related release write
    }

  }
}

pred consistent_critical_sections[X:Exec_Arm8L] {
  // no (po|com)-cycles among critical sections
  let com = X.rf + X.co + fr[none->none,X] |
  let scs = scst[X] + scsl[X] |
  is_acyclic[ scs . (X.sb + com - scs) . scs ]
}

pred p[X,X':Exec_Arm8L, map:E->E] {
  withoutinit[X]
  withoutinit[X']

 not {
    M/consistent[none->none, X]
    consistent_critical_sections[X]
  }

  //M/dead[none->none, X]

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

  apply_map[X,X',map]
/*
  some disj E0, E1, E2, E3, E4, E5, E6: E {
    hint_src[X,E0,E1,E2,E3,E4,E5,E6]
    hint_tgt[X',E0,E1,E2,E3,E4,E5,E6]
    map = (E0->E0) + (E1->E1) + (E3->E2) + (E3->E3) + (E4->E4) + (E5->E5) + (E6->E6)
  }*/
}

pred hint_src[X:Exec_Arm8L, E0,E1,E2,E3,E4,E5,E6:E] {
// E0:  LkT     || E3: LkN
// E1:  W x 1   || E4: R x 0
// E2:  UkT     ||     [data]
//              || E5: W x 2
//              || E6: UkN
    X.EV = E0+E1+E2+E3+E4+E5+E6
    X.R = E4
    X.W = E1+E5
    X.F = none
    X.LkT = E0
    X.UkT = E2
    X.LkN = E3
    X.UkN = E6
    X.SCACQ = none
    X.SCREL = none
    X.DMBLD = none
    X.DMBST = none
    X.co = (E1->E5)
    X.rf = none->none
    X.sloc = sq[E1+E4+E5]
    X.sthd = sq[E0+E1+E2] + sq[E3+E4+E5+E6]
    X.cd = none->none
    X.dd = E4->E5
    X.ad = none->none
    X.sb = ^((E0->E1)+(E1->E2)) + ^((E3->E4)+(E4->E5)+(E5->E6))
    X.atom = none->none
    X.stxn = none->none
}

pred hint_tgt[X:Exec_Arm8L, E0,E1,E2,E3,E4,E5,E6:E] {
//     txn {      || E2: R*[ACQ] lock 0
// E0:   R lock 0 || E3: W* lock 1
// E1:   W x 1    || E4: R x 0
//     }          ||     [data]
//                || E5: W x 2
//                || E6: W[REL] lock 2
    X.EV = E0+E1+E2+E3+E4+E5+E6
    X.R = E0+E2+E4
    X.W = E1+E3+E5+E6
    X.F = none
    X.LkT = none
    X.UkT = none
    X.LkN = none
    X.UkN = none
    X.SCACQ = E2
    X.SCREL = E6
    X.DMBLD = none
    X.DMBST = none
    X.co = (E1->E5)+(E3->E6)
    X.rf = none->none
    X.sloc = sq[E1+E4+E5] + sq[E0+E2+E3+E6]
    X.sthd = sq[E0+E1] + sq[E2+E3+E4+E5+E6]
    X.cd = none->none
    X.dd = E4->E5
    X.ad = none->none
    X.sb = (E0->E1) + ^((E2->E3)+(E3->E4)+(E4->E5)+(E5->E6))
    X.atom = (E2->E3)
    X.stxn = sq[E0+E1]
}

run p for 2 Exec, 7 E // found in 63550ms using Plingeling  on Benjamin

open ../archs/exec_arm8L[E]
open ../models/aarch64_txn[E] as M

module arm8_lock_elision[E]

pred apply_map[X,X':Exec_Arm8L, map:E->E] {

  map in (X.EV one-> X'.EV)

  // no critical sections remain
  no X'.(LkT + UkT + LkN + UkN)

  // suppose we don't have transactions in the source program
  no X.stxn

  // events in the same critical section (where the critical
  // section is one that is to be transactionalised), map to events
  // in the same transaction.
  (X.EV - X.UkT) <: scst[X] :> (X.EV - X.UkT) = map.(X'.stxn).~map

  // the set of lock-related events introduced by the mapping
  let L = map[X.(LkT + UkT + LkN + UkN)] {

    // Mildly interesting observation: transactional memory models
    // are not monotonic w.r.t. adding sequencing edges

    X'.sthd = ~map.(X.sthd).map

    all e1, e2 : X.EV |
      (some e1.map and some e2.map) implies
      ((e1 -> e2 in X.sb) iff (map[e1] -> map[e2] in X'.sb))

    X.ad =   map.((X'.EV - L) <: (X'.ad)   :> (X'.EV - L)).~map
    X.cd =   map.((X'.EV - L) <: (X'.cd)   :> (X'.EV - L)).~map
    X.dd =   map.((X'.EV - L) <: (X'.dd)   :> (X'.EV - L)).~map
    X.atom = map.((X'.EV - L) <: (X'.atom) :> (X'.EV - L)).~map
    X.rf =   map.((X'.EV - L) <: (X'.rf)   :> (X'.EV - L)).~map
    X.co =   map.((X'.EV - L) <: (X'.co)   :> (X'.EV - L)).~map

    X.R     = (X'.R     - L).~map
    X.W     = (X'.W     - L).~map
    X.F     = (X'.F     - L).~map
    X.DMBST = (X'.DMBST - L).~map
    X.DMBLD = (X'.DMBLD - L).~map
    X.ISB   = (X'.ISB   - L).~map
    X.SCACQ = (X'.SCACQ - L).~map
    X.SCREL = (X'.SCREL - L).~map

    // lock-related events in X' are on the same location
    X'.sloc = (L -> L) + ((X'.EV - L) <: ~map.(X.sloc).map :> (X'.EV - L))

    // non-call events map to non-library events
    all e : X.EV - X.LkT - X.LkN - X.UkT - X.UkN {
	  one e.map
    }

    // lock() to be transactionalised
	all e : X.LkT | some e1 : X'.EV {
      e.map = e1
      e1 in X'.R - X'.SCACQ // e1 is a lock-related read event
	  e1 not in ran[X'.rf] // e1 sees the lock is not taken
    }

	// unlock() to be transactionalised
    all e : X.UkT | no e.map

    // lock() to be kept as a normal lock
    all e : X.LkN | some disj e1, e2 : X'.EV {
      e.map = e1 + e2
      (e1 -> e2) in imm[X'.sb] & X'.atom // e1 and e2 form an RMW pair
      e1 in X'.SCACQ & X'.R // e1 is a lock-related acquire read
      e2 in X'.W // e2 is a lock-related write
    }

    // unlock() to be kept as a normal unlock
    all e : X.UkN | some e1 : X'.EV {
 	  e.map = e1
      e1 in X'.SCREL & X'.W // eL is a lock-related release write
    }

  }
}

pred consistent_critical_sections[X:Exec_Arm8L] {
  // no (po|com)-cycles among critical sections
  let com = X.rf + X.co + fr[none->none,X] |
  let scs = scst[X] + scsl[X] |
  is_acyclic[ scs . (X.sb + com - scs) . scs ]
}

pred p[X,X':Exec_Arm8L, map:E->E] {
  withoutinit[X]
  withoutinit[X']

 not {
    M/consistent[none->none, X]
    consistent_critical_sections[X]
  }

  //M/dead[none->none, X]

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

  apply_map[X,X',map]
/*
  some disj E0, E1, E2, E3, E4, E5, E6: E {
    hint_src[X,E0,E1,E2,E3,E4,E5,E6]
    hint_tgt[X',E0,E1,E2,E3,E4,E5,E6]
    map = (E0->E0) + (E1->E1) + (E3->E2) + (E3->E3) + (E4->E4) + (E5->E5) + (E6->E6)
  }*/
}

pred hint_src[X:Exec_Arm8L, E0,E1,E2,E3,E4,E5,E6:E] {
// E0:  LkT     || E3: LkN
// E1:  W x 1   || E4: R x 0
// E2:  UkT     ||     [data]
//              || E5: W x 2
//              || E6: UkN
    X.EV = E0+E1+E2+E3+E4+E5+E6
    X.R = E4
    X.W = E1+E5
    X.F = none
    X.LkT = E0
    X.UkT = E2
    X.LkN = E3
    X.UkN = E6
    X.SCACQ = none
    X.SCREL = none
    X.DMBLD = none
    X.DMBST = none
    X.co = (E1->E5)
    X.rf = none->none
    X.sloc = sq[E1+E4+E5]
    X.sthd = sq[E0+E1+E2] + sq[E3+E4+E5+E6]
    X.cd = none->none
    X.dd = E4->E5
    X.ad = none->none
    X.sb = ^((E0->E1)+(E1->E2)) + ^((E3->E4)+(E4->E5)+(E5->E6))
    X.atom = none->none
    X.stxn = none->none
}

pred hint_tgt[X:Exec_Arm8L, E0,E1,E2,E3,E4,E5,E6:E] {
//     txn {      || E2: R*[ACQ] lock 0
// E0:   R lock 0 || E3: W* lock 1
// E1:   W x 1    || E4: R x 0
//     }          ||     [data]
//                || E5: W x 2
//                || E6: W[REL] lock 2
    X.EV = E0+E1+E2+E3+E4+E5+E6
    X.R = E0+E2+E4
    X.W = E1+E3+E5+E6
    X.F = none
    X.LkT = none
    X.UkT = none
    X.LkN = none
    X.UkN = none
    X.SCACQ = E2
    X.SCREL = E6
    X.DMBLD = none
    X.DMBST = none
    X.co = (E1->E5)+(E3->E6)
    X.rf = none->none
    X.sloc = sq[E1+E4+E5] + sq[E0+E2+E3+E6]
    X.sthd = sq[E0+E1] + sq[E2+E3+E4+E5+E6]
    X.cd = none->none
    X.dd = E4->E5
    X.ad = none->none
    X.sb = (E0->E1) + ^((E2->E3)+(E3->E4)+(E4->E5)+(E5->E6))
    X.atom = (E2->E3)
    X.stxn = sq[E0+E1]
}

run p for 2 Exec, 7 E // found in 63550ms using Plingeling  on Benjamin


Add Alloy exercise for Wednesday's tutorial

// 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 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 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.)

error: pathspec 'tutorials/2017/wednesday/tutorial_questions.als' did not match any file(s) known to git


increase maze size 3x3 -> 10x10.

increase maze size 3x3 -> 10x10.

module maze_maker/simple_maze

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

// 迷路のサイズ
fun height : Int {
  10
}
fun width: Int {
  10
}

// 隣接する Cell
fun adjacent (col: Col, row: Row) : Col -> Row {
  col.prev -> row +
  col.next -> row +
  col -> row.prev +
  col -> row.next
}

sig Col {
  paths: Row -> Col -> Row
} {
  // 自分自身との接続はなし
  all row: Row | no (this -> row) & row.paths
  // 接続先は必ず隣接する(4近傍の) Cell
  all row: Row | row.paths in adjacent[this, row]
}
sig Row {}

one sig entrance_x extends Col {}
one sig entrance_y extends Row {}
one sig exit_x extends Col {}
one sig exit_y extends Row {}

//  位置が盤の端
pred edge (col: Col, row: Row) {
  col = cols/first or col = cols/last or row = rows/first or row = rows/last
}

fact {
  // 全ての位置が paths に含まれている
  all col: Col, row: Row | (col -> row) in paths[Col, Row]
  // paths の連結は反射的
  all c1, c2: Col, r1, r2: Row | (c1 -> r1 -> c2 -> r2) in paths => (c2 -> r2 -> c1 -> r1) in paths
  // 入口と出口はいずれも盤面の端に位置する
  edge[entrance_x, entrance_y]
  edge[exit_x, exit_y]
}

run {
  #Col = width[]
  #Row = height[]
} for 10

module maze_maker/simple_maze

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

// 迷路のサイズ
fun height : Int {
  3
}
fun width: Int {
  3
}

// 隣接する Cell
fun adjacent (col: Col, row: Row) : Col -> Row {
  col.prev -> row +
  col.next -> row +
  col -> row.prev +
  col -> row.next
}

sig Col {
  paths: Row -> Col -> Row
} {
  // 自分自身との接続はなし
  all row: Row | no (this -> row) & row.paths
  // 接続先は必ず隣接する(4近傍の) Cell
  all row: Row | row.paths in adjacent[this, row]
}
sig Row {}

one sig entrance_x extends Col {}
one sig entrance_y extends Row {}
one sig exit_x extends Col {}
one sig exit_y extends Row {}

//  位置が盤の端
pred edge (col: Col, row: Row) {
  col = cols/first or col = cols/last or row = rows/first or row = rows/last
}

fact {
  // 全ての位置が paths に含まれている
  all col: Col, row: Row | (col -> row) in paths[Col, Row]
  // paths の連結は反射的
  all c1, c2: Col, r1, r2: Row | (c1 -> r1 -> c2 -> r2) in paths => (c2 -> r2 -> c1 -> r1) in paths
  // 入口と出口はいずれも盤面の端に位置する
  edge[entrance_x, entrance_y]
  edge[exit_x, exit_y]
}

run {
  #Col = width[]
  #Row = height[]
} for 3


speed up

speed up

open util/ordering[SmallInt]

one sig Root{
  cell: Int -> Color -> Int
}{
  all x: cell.univ.univ | in_ten[x]
  all y: univ.(univ.cell) | in_ten[y]
  let ten = {x: Int | in_ten[x]}{
    all x, y: ten{
      one x.cell.y
    }
  }
}

pred in_ten(x: Int){
  one x
  0 <= x and x < 10  // notice: for 5 Int required
}

enum Color { Black, White }

fun getCol(i: Int): seq Color{
  ~(i.(Root.cell))
}
fun getRow(i: Int): seq Color{
  (Root.cell).i
}

// 指定されたセルが黒ブロックの先頭である
pred is_black_head(line: seq Color, pos: Int) {
  // 直前のブロックが黒でない(存在しない場合を含む)
  prev_is_not_black[line, pos]
  // このセルは存在していて黒い
  let this_ = line[pos]{
    one this_ and this_ in Black
  }
}

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

// ブロック先頭の集合
fun get_heads(line: seq Color): SmallInt{
  {i: SmallInt | is_black_head[line, i.to_int]}
}

fun get_end(start: Int, size: Int): Int{
  plus[start, minus[size, 1]]
}

pred all_black(line: seq Color, start: Int, end: Int){
  all i: Int {
    (start =< i and i =< end) => (line[i] = Black)
  }
}

// 黒でない(存在しないか白である)
pred is_not_black(c: Color){
  no c or c in White
}
// 直前のブロックが黒でない(存在しないか白である)
pred prev_is_not_black(line: seq Color, pos: Int) {
  let prev = minus[pos, 1] {
    is_not_black[line[prev]]
  }
}
// 直後のブロックが黒でない(存在しないか白である)
pred next_is_not_black(line: seq Color, pos: Int) {
  let next = plus[pos, 1]{
    is_not_black[line[next]]
  }
}

sig SmallInt{}
fun from_int (i: Int): SmallInt {
  {x: SmallInt | #(x.prevs) = i}
}

fun to_int (x: SmallInt): Int {
  #(x.prevs)
}

pred hint(line: seq Color, sizes: seq Int){
  some heads: seq SmallInt {
    #heads = #sizes
    sorted[get_heads[line], heads]
    all i: sizes.inds {
      let start = heads[i],
				end = from_int[get_end[start.to_int, sizes[i]]] {
        some line[end.to_int]
        all_black[line, start.to_int, end.to_int]
        next_is_not_black[line, end.to_int]
      }
    }
  }
}
pred colHint (i: Int, sizes: seq Int) {
  hint[getCol[i], sizes]
}
pred rowHint (i: Int, sizes: seq Int) {
  hint[getRow[i], sizes]
}

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 5 Int, exactly 10 SmallInt

one sig Root{
  cell: Int -> Color -> Int
}{
  all x: cell.univ.univ | in_ten[x]
  all y: univ.(univ.cell) | in_ten[y]
  let ten = {x: Int | in_ten[x]}{
    all x, y: ten{
      one x.cell.y
    }
  }
}

pred in_ten(x: Int){
  one x
  0 <= x and x < 10  // notice: for 5 Int required
}

enum Color { Black, White }

fun getCol(i: Int): seq Color{
  ~(i.(Root.cell))
}
fun getRow(i: Int): seq Color{
  (Root.cell).i
}

// 指定されたセルが黒ブロックの先頭である
pred is_black_head(line: seq Color, pos: Int) {
  // 直前のブロックが黒でない(存在しない場合を含む)
  prev_is_not_black[line, pos]
  // このセルは存在していて黒い
  let this_ = line[pos]{
    one this_ and this_ in Black
  }
}

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

// ブロック先頭の集合
fun get_heads(line: seq Color): Int{
  {i: Int | is_black_head[line, i]}
}

fun get_end(start: Int, size: Int): Int{
  plus[start, minus[size, 1]]
}

pred all_black(line: seq Color, start: Int, end: Int){
  all i: Int {
    (start =< i and i =< end) => (line[i] = Black)
  }
}

// 黒でない(存在しないか白である)
pred is_not_black(c: Color){
  no c or c in White
}
// 直前のブロックが黒でない(存在しないか白である)
pred prev_is_not_black(line: seq Color, pos: Int) {
  let prev = minus[pos, 1] {
    is_not_black[line[prev]]
  }
}
// 直後のブロックが黒でない(存在しないか白である)
pred next_is_not_black(line: seq Color, pos: Int) {
  let next = plus[pos, 1]{
    is_not_black[line[next]]
  }
}

pred hint(line: seq Color, sizes: seq Int){
  some heads: seq Int {
    #heads = #sizes
    sorted[get_heads[line], heads]
    all i: sizes.inds {
      let start = heads[i], end = get_end[start, sizes[i]] {
        some line[end]
        all_black[line, start, end]
        next_is_not_black[line, end]
      }
    }
  }
}
pred colHint (i: Int, sizes: seq Int) {
  hint[getCol[i], sizes]
}
pred rowHint (i: Int, sizes: seq Int) {
  hint[getRow[i], sizes]
}

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


alloy file

alloy file

module Haveksan/Requirement

abstract sig Requirement {}

sig Task {
	precede: lone Task,
}{ 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"
sig SoftwareRequirement extends Implementation {
	test: some TestCase
}

sig HardwareRequirement extends Implementation {}

sig TestCase { }{ 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
}
run example for 10

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


Checking weak isolation for all transactions

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

module c11_strong_isolation[E]

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

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

  let com = X.rf + X.co + fr[none->none,X] |
 // not (is_acyclic[weaklift[com, X.stxn, none->none, X]])
  not (is_acyclic[stronglift[com, X.atxn, none->none, X]])

  X.EV = E
}

run p for 1 Exec, 6 E

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

module c11_strong_isolation[E]

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

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

  let com = X.rf + X.co + fr[none->none,X] |
  not (is_acyclic[stronglift[com, X.atxn, none->none, X]])

  X.EV = E
}

run p for 1 Exec, 6 E


bugfix

bugfix

module exec_H[E]
open exec[E]

sig Exec_H extends Exec {
}{
  // there are no fence events (only fence relations)
  no F

  // control dependencies are defined differently in assembly
  cd.sb in cd
}

pred is_fence_rel[fence_rel:E->E, sb:E->E] {

  // Consistent with program order
  fence_rel in sb

  // Preserved by pre- or post-composition with program order
  *sb . fence_rel . *sb in fence_rel

  // Can be traced back to an immediate sb-pair
  no ((sb - fence_rel) . (sb - fence_rel)) & fence_rel

  //fence_rel in imm[sb]

}

fun mk_fence_rel[e:PTag->E, t:PTag, f:E->E, sb:E->E] : E->E {
  rm_EV_rel[e, *sb.((univ - e[t]) <: imm[f]).*sb] }

module exec_H[E]
open exec[E]

sig Exec_H extends Exec {
  atom : E -> E // atomicity relation
}{

  // the atom relation relates a consecutively-sequenced read/write pair
  atom in (R->W) & imm[sb] & sloc

  // there are no single-event RMWs
  no (R&W)

  // there are no fence events (only fence relations)
  no F

  // control dependencies are defined differently in assembly
  cd.sb in cd

  // the atom relation relates either
  // - two events in the same transaction or
  // - two events that are non-transactional
  atom in stxn + ((EV - dom[stxn]) -> (EV - dom[stxn]))
}

pred is_fence_rel[fence_rel:E->E, sb:E->E] {

  // Consistent with program order
  fence_rel in sb

  // Preserved by pre- or post-composition with program order
  *sb . fence_rel . *sb in fence_rel

  // Can be traced back to an immediate sb-pair
  no ((sb - fence_rel) . (sb - fence_rel)) & fence_rel

  //fence_rel in imm[sb]

}

fun mk_fence_rel[e:PTag->E, t:PTag, f:E->E, sb:E->E] : E->E {
  rm_EV_rel[e, *sb.((univ - e[t]) <: imm[f]).*sb] }

one sig rm_atom extends PTag {}

fun atom[e:PTag->E, X:Exec_H] : E->E {
  rm_EV_rel[e, (univ - e[rm_atom]) <: X.atom] }


remove Int2*

remove Int2*

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

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

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

enum Color { Black, White }

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

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

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

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

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

-- about rows or cols
fun headsInRow (r: Row): set Col {
  { c: Col | is_black_head[c, r, cols/prev]}
}

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

fact noOtherHeadsInRow {
  no c: Col, r: Row {
		c not in headsInRow[r] and is_black_head[c, r, cols/prev]
	}
}
fact noOtherHeadsInCol {
  no c: Col, r: Row {
		r not in headsInCol[c] and is_black_head[c, r, rows/prev]
	}
}

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

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

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 headsInRow (r: Row): set Col {
  { c: Col | is_black_head[c, r, cols/prev]}
}

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

fact noOtherHeadsInRow {
  no c: Col, r: Row {
		c not in headsInRow[r] and is_black_head[c, r, cols/prev]
	}
}
fact noOtherHeadsInCol {
  no c: Col, r: Row {
		r not in headsInCol[c] and is_black_head[c, r, rows/prev]
	}
}

-- about rows or cols

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

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

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

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

-- about cols

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

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

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


Resolving recent contradictions in model

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

module Voting

open util/integer

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

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

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

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

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

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

enum Method {Plurality, STV}

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

-- Independent (or Fundamental) Axioms
fact uniqueCandidateID {
  no disj a,b: Candidate | a.identifier = b.identifier
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

-- Axioms for the recording of vote fragments
fact allVotesRecorded {
   all b: Ballot | some v: Vote | v.ballot = b.identifier and v.ranking = #b.preferences
}

// All vote fragments are recorded for each ballot
fact lowerRankings {
   all v: Vote | some w: Vote | 1 < v.ranking implies w.ranking + 1 = v.ranking and
	v.ballot = w.ballot and not v.candidate = w.candidate
}

// Well formed ranking of candidates in ballots
fact wellFormedRanking {
	no disj v,w: Vote | v.ballot = w.ballot and Election.method = STV
		implies v.candidate = w.candidate or v.ranking = w.ranking
}

// Compromise winner must have more votes than any tied winners
fact compromiseNotTied {
	all disj c,t: Candidate | (c.outcome = CompromiseWinner and t.outcome = TiedWinner) implies
		#t.votes + #t.transfers < #c.votes + #t.transfers
}

// Equal losers are tied
fact equalityofTiedWinnersAndLosers {
	all disj w,l: Candidate | w in Scenario.winners and l in Scenario.losers and
		#w.votes = #l.votes and #w.transfers = #l.transfers implies
			w.outcome = TiedWinner and
			(l.outcome = TiedLoser or l.outcome = TiedEarlyLoser or l.outcome = TiedSoreLoser)
}

// Highest winner has a quota
fact highestWinner {
   some c: Candidate | Election.method = STV implies
		Scenario.quota <= #c.votes + #c.transfers
}

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

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

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

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

assert plurality {
	all c: Candidate | all b: Ballot | b in c.votes and
		Election.method = Plurality implies c in b.preferences.first
}
check plurality for 18 but 6 int

assert wellFormedTieBreaker {
	some w,l : Candidate | (w in Scenario.winners and l in Scenario.losers and
		#w.votes = #l.votes and #w.transfers = #l.transfers) implies
		w.outcome = TiedWinner and
		(l.outcome = TiedLoser or l.outcome = TiedSoreLoser or l.outcome=TiedEarlyLoser)
}
check wellFormedTieBreaker for 18 but 6 int

assert validSurplus {
	all c: Candidate | 0 < #c.surplus implies (c.outcome = Winner or c.outcome = QuotaWinner or
		c in Scenario.eliminated)
}
check validSurplus for 16 but 6 int

assert wellFormedVote {
	all v: Vote | 0 < v.ballot and 0 < v.candidate
}
check wellFormedVote for 4 but 6 int

-- Advanced Lemmas
// No lost votes during counting
assert accounting {
	all b: Ballot | one c: Candidate | b in c.votes and c in b.assignees
}
check accounting for 16 but 6 int

// Cannot have tie breaker with both tied sore loser and non-sore loser
assert tiedWinnerLoserTiedSoreLoser {
	no disj c,w,l: Candidate | c.outcome = TiedSoreLoser and
	   w.outcome = TiedWinner and (l.outcome = Loser or l.outcome = TiedLoser)
}
check tiedWinnerLoserTiedSoreLoser for 6 int

// Compromise winner must have at least one vote
assert validCompromise {
	all c: Candidate | c.outcome = CompromiseWinner implies 0 < #c.votes + #c.transfers
}
check validCompromise for 6 int

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

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

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

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

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

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

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

pred ThreeWinnersOneLoser {
    Election.method = STV
	some disj a,b,d: Candidate | a.outcome = Winner
   	  and b.outcome = QuotaWinner or b.outcome = CompromiseWinner
	  and d in Scenario.losers
}
run ThreeWinnersOneLoser for 6 but 6 int

pred LoserAndEarlyLoser {
	one d: Candidate | d.outcome = Loser
	one e: Candidate | e.outcome = EarlyLoser
}
run LoserAndEarlyLoser for 5 but 6 int

pred OneWinnerNineLosers {
	#Scenario.winners = 1
	#Scenario.losers = 9
}
run OneWinnerNineLosers for 16 but 6 int

pred ThreeWayTie {
	#Election.candidates = 3
    Election.method = Plurality
	some disj a,b,c: Candidate | a.outcome = TiedWinner and
		b.outcome = TiedLoser and
		c.outcome = TiedLoser
}
run ThreeWayTie for 5 but 6 int

pred FiveWayTie {
	some disj a,b,c,d,e: Candidate | a.outcome = TiedWinner and
	 b.outcome = TiedLoser and
		c.outcome = TiedLoser and d.outcome = TiedLoser and e.outcome = TiedWinner
}
run FiveWayTie for 7 but 6 int

pred ScenarioLWW {
	some disj a, b,c: Candidate | a in Scenario.losers and b.outcome = Winner and
		c in Scenario.winners
    #Election.candidates = 3
}
run ScenarioLWW for 6 but 7 int

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

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

module Voting

open util/integer

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

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

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

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

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

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

enum Method {Plurality, STV}

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

-- Independent (or Fundamental) Axioms

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

-- Axioms for the recording of vote fragments
fact allVotesRecorded {
   all b: Ballot | some v: Vote | v.ballot = b.identifier and v.ranking = #b.preferences
}

// All vote fragments are recorded for each ballot
fact lowerRankings {
   all v: Vote | some w: Vote | 1 < v.ranking implies w.ranking + 1 = v.ranking and
	v.ballot = w.ballot and not v.candidate = w.candidate
}

// Well formed ranking of candidates in ballots
fact wellFormedRanking {
	no disj v,w: Vote | v.ballot = w.ballot and Election.method = STV
		implies v.candidate = w.candidate or v.ranking = w.ranking
}

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

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

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

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

assert wellFormedBallotBox {
		#BallotBox.ballots = sum (#Election.candidates.votes)
}
check wellFormedBallotBox for 14 but 6 int

assert plurality {
	all c: Candidate | all b: Ballot | b in c.votes and
		Election.method = Plurality implies c in b.preferences.first
}
check plurality for 18 but 6 int

assert wellFormedTieBreaker {
	some w,l : Candidate | (w in Scenario.winners and l in Scenario.losers and
		#w.votes = #l.votes and #w.transfers = #l.transfers) implies
		w.outcome = TiedWinner and
		(l.outcome = TiedLoser or l.outcome = TiedSoreLoser or l.outcome=TiedEarlyLoser)
}
check wellFormedTieBreaker for 18 but 6 int

assert validSurplus {
	all c: Candidate | 0 < #c.surplus implies (c.outcome = Winner or c.outcome = QuotaWinner or
		c in Scenario.eliminated)
}
check validSurplus for 16 but 6 int

-- Advanced Lemmas
// No lost votes during counting
assert accounting {
	all b: Ballot | one c: Candidate | b in c.votes and c in b.assignees
}
check accounting for 16 but 6 int

// No ballots created or destroyed during counting
assert immutability {
	all c: Candidate | c.votes + c.transfers in BallotBox.ballots and c.surplus in BallotBox.ballots
}
check immutability for 16 but 6 int

// Cannot have tie breaker with both tied sore loser and non-sore loser
assert tiedWinnerLoserTiedSoreLoser {
	no disj c,w,l: Candidate | c.outcome = TiedSoreLoser and
	   w.outcome = TiedWinner and (l.outcome = Loser or l.outcome = TiedLoser)
}
check tiedWinnerLoserTiedSoreLoser for 6 int

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

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

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

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

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

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

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

pred ThreeWinnersOneLoser {
	some a: Candidate | a.outcome = Winner
   	some b: Candidate | b.outcome = QuotaWinner
	some c: Candidate | c.outcome = CompromiseWinner
	some d: Candidate | d in Scenario.losers
}
run ThreeWinnersOneLoser for 8 but 6 int

pred LoserAndEarlyLoser {
	one d: Candidate | d.outcome = Loser
	one e: Candidate | e.outcome = EarlyLoser
}
run LoserAndEarlyLoser for 5 but 6 int

pred OneWinnerNineLosers {
	#Scenario.winners = 1
	#Scenario.losers = 9
}
run OneWinnerNineLosers for 16 but 6 int

pred ThreeWayTie {
	some disj a,b,c: Candidate | a.outcome = TiedWinner and b.outcome = TiedLoser and
		c.outcome = TiedLoser
}
run ThreeWayTie for 5 but 6 int

pred FiveWayTie {
	some disj a,b,c,d,e: Candidate | a.outcome = TiedWinner and b.outcome = TiedLoser and
		c.outcome = TiedLoser and d.outcome = TiedLoser and e.outcome = TiedWinner
}
run FiveWayTie for 7 but 6 int

pred TwentyCandidates {
	#Election.candidates = 20
	some c: Candidate | 0 < #c.votes and c in Scenario.losers
}
run TwentyCandidates for 20 but 6 int

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

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

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

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

pred LongBallot {
	some b: Ballot | #b.preferences = 12
}
run LongBallot for 15 but 15 seq, 7 int


refactor fun range

refactor fun range

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

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

-- about rows or cols

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

fun range(R: Region, start, end: Int): Region{
	{r: R | start =< r.index and r.index =< end}
}

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[Col, start.index, end.index] | 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[Row, start.index, end.index] | 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
}

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

-- about rows or cols

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


tabify

tabify

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


mystery

mystery

open util/ordering[Time]
enum Person {A, B, C}
sig Place {}
one sig Nowhere extends Place {}
sig Time {
   visit: Person -> Place
}
fact {
   all t: Time, p: Person {
      one t.visit[p] // 人は一度に一箇所にしかいない
   }
}

enum Bool {T, F}
enum BoolBool {TT, TF, FT, FF}

abstract sig Constrain{
   by: one Person,
   who: one Person
}

sig is_honest extends Constrain {}
sig is_visit extends Constrain {
   when: Time,
   where: Place
}

pred satisfy(cs: Constrain, a, b, c: BoolBool){
   let
      bb = (A -> a) + (B -> b) + (C -> c),
      b0 = bb.(TT -> T + TF -> T + FT -> F + FF -> F),
      b1 = bb.(TT -> T + TF -> F + FT -> T + FF -> F)
   {
      // b0: Person -> Bool // 正直T 嘘をつくかもしれない人
      // b1: Person -> Bool // 犯人T
      // 正直者の人数は1人
      //#{b0.T} = 1
      // 犯人は1人
      #{b1.T} = 1

      // すべての正直発言について、
      // 発言者が正直なら対象も正直
      all c: cs & is_honest{
	 (c.by.b0 = T) => (c.who.b0 = T)
      }
      // すべての目撃情報について
      // 発言者が正直なら
      all c: cs & is_visit{
	 (c.by.b0 = T) => {
	    let t = c.when {
	       t.visit[c.who] = c.where // その時刻にそこにいる
	    }
	 }
      }
   }
}

fact {
   // 人の移動に関する制約
   all t: Time - first, p: Person {
      t.visit[p] = t.prev.visit[p] // 同じ位置にとどまる
      or t.visit[p] = Nowhere or t.prev.visit[p] = Nowhere
   }
}

run {
   let answers = {
      a, b, c: BoolBool |
    	 satisfy[Constrain, a, b, c]}
   {
//	some answers
      one answers
/*
      all x: Constrain {
	 not one {
	    a, b, c: BoolBool |
	       satisfy[Constrain - x, a, b, c]
	 }
      }
*/
   }
} for 3 Place, 3 Time, 20 Constrain