illust

illust

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

// 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 5 int


Finished slashing condition [ii]

Finished slashing condition [ii]


puzzle 3

puzzle 3

enum Person {A, B, C, D, E}

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

abstract sig Constrain{}

sig is_liar extends Constrain {
	by: one Person,
	who: one Person
}{
	by not in who
}

sig is_coward extends Constrain {
	by: one Person,
	who: one Person
}{
	by not in who
}

pred satisfy(cs: Constrain, a, b, c, d, e: BoolBool){
  let
		bb = (A -> a) + (B -> b) + (C -> c) + (D -> d) + (E -> e),
		b0 = bb.(TT -> T + TF -> T + FT -> F + FF -> F),
  	b1 = bb.(TT -> T + TF -> F + FT -> T + FF -> F)
  {
		// b0: Person -> Bool // 正直
		// b1: Person -> Bool // 小心
		// 嘘つきの人数を指定
		#{b0.F} = 2
		// 小心者の人数を指定
		#{b1.T} = 2
		// 嘘つき小心者の人数を指定
		//#{b0.F & b1.T} > 0
/*
		all p: b0.F & b1.T{ // 嘘つき小心者は2個以上の解答をしている
			plus[#(is_coward <: by).p, #(is_liar <: by).p] > 1
		}
*/
		// すべての嘘つき発言について、発言者が正直なら充足される
		all c: cs & is_liar{
			(c.by.b0 = T) => (c.who.b0 = F)
		}
		// すべての小心者発言について、発言者が正直なら充足される
		all c: cs & is_coward{
			(c.by.b0 = T) => (c.who.b1 = T)
		}
		// すべてのnot小心な嘘つきについて
/*
		all p: b0.F & b1.F {
			// 全て正直ではない:
			plus[
				#{c: (is_coward <: by).p | c.who.b1 = T}
				#{c: (is_liar <: by).p | c.who.b0 = F}
			] > 0
		}
*/
		// すべての小心な嘘つきについて
		all p: b0.F & b1.T {
			// 一つしか嘘をつかない:
			plus[
				#{c: (is_coward <: by).p | c.who.b1 = F},
				#{c: (is_liar <: by).p | c.who.b0 = T}
			] = 1
		}
  }
}

run {
  let answers = {
    a, b, c, d, e: BoolBool |
    satisfy[Constrain, a, b, c, d, e]}
    {

    one answers

    all x: Constrain {
      not one {
        a, b, c, d, e: BoolBool |
        satisfy[Constrain - x, a, b, c, d, e]
      }
    }

  }
} for exactly 10 Constrain

enum Person {P0, P1, P2, P3, P4}

enum Bool {T, F}

abstract sig Constrain{}

sig is_liar extends Constrain {
	by: one Person,
	who: one Person
}{
	by not in who
}

sig is_coward extends Constrain {
	by: one Person,
	who: one Person
}{
	by not in who
}

pred satisfy(cs: Constrain, p0_0, p0_1, p1_0, p1_1, p2_0, p2_1, p3_0, p3_1, p4_0, p4_1: Bool){
  let
		b0 = (P0 -> p0_0) + (P1 -> p1_0) + (P2 -> p2_0) + (P3 -> p3_0) + (P4 -> p4_0),
  	b1 = (P0 -> p0_1) + (P1 -> p1_1) + (P2 -> p2_1) + (P3 -> p3_1) + (P4 -> p4_1)
  {
		// b0: Person -> Bool // 正直
		// b1: Person -> Bool // 小心
		// 嘘つきの人数を指定
		#{b0.F} = 3
		// すべての嘘つき発言について、発言者が正直なら充足される
		all c: cs & is_liar{
			(c.by.b0 = T) => (c.who.b0 = F)
		}
		// すべての小心者発言について、発言者が正直なら充足される
		all c: cs & is_coward{
			(c.by.b0 = T) => (c.who.b1 = T)
		}
		// すべてのnot小心な嘘つきについて
		all p: b0.F & b1.F {
			// 全て正直ではない:
			(not
			all c: (is_coward <: by).p {
				c.who.b1 = T
			})or(
			not all c: (is_liar <: by).p {
				c.who.b0 = F
			})

		}

  }
}

run {
  let answers = {
    p0_0, p0_1, p1_0, p1_1, p2_0, p2_1, p3_0, p3_1, p4_0, p4_1: Bool |
    satisfy[Constrain, p0_0, p0_1, p1_0, p1_1, p2_0, p2_1, p3_0, p3_1, p4_0, p4_1]}
    {

    one answers

    all x: Constrain {
      not one {
        p0_0, p0_1, p1_0, p1_1, p2_0, p2_1, p3_0, p3_1, p4_0, p4_1: Bool |
        satisfy[Constrain - x, p0_0, p0_1, p1_0, p1_1, p2_0, p2_1, p3_0, p3_1, p4_0, p4_1]
      }
    }
  }
}


Generating more tests that distinguish the Lidbury-Donaldson model.

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

sig E {}

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

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

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

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

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

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

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

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

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

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

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

sig E {}

run {
  some X:Exec_C {
    not (M1/consistent[X])
    dead[X]
    M2/consistent[X]

    // just simplifying the solution:
    no_RMWs[X]
	no X.(ad+cd+dd)
    #(X.W) = #(X.R)
  }
} for 1 Exec, 4 E, 3 Int expect 1

// This example shows that if you run
//
// store(x,1,RLX); || r0 = load(y,SC);
// store(y,1,SC);  || r1 = load(x,SC);
//
// then in the "original" C11 model you are
// allowed to observe r0==1&&r1==0, but in the
// Lidbury-Donaldson simplified model, you
// cannot observe that outcome.


misunderstand whether can marry or not

misunderstand whether can marry or not

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

pred can_marry_think (from, to: Person){
	to not in from.^parent_think
	from not in to.^parent_think
	to not in from.parent_think.~parent_think
}

pred can_marry_bio (from, to: Person){
	to not in from.^parent_bio
	from not in to.^parent_bio
	to not in from.parent_bio.~parent_bio
}

run {
	some parent_bio
	some p1: Man, p2: Woman {
//		p.parent_bio & Man != p.parent_think & Man
//		one p.parent_think & Man
		can_marry_think[p1, p2] and not can_marry_bio[p1, p2]
	}
} 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]
		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


refactored

refactored

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

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


refactor: Row and Col have index:Int

refactor: Row and Col have index:Int

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

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

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

enum Color { Black, White }

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

-- about rows
pred blackHeadInRow (c: Col, r: Row) {
  c in first or cell[c.prev, r] in White
  cell[c, r] in Black
}

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

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

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

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

fun Row2Int (r: Row): Int {
	r.index
}

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

-- about cols
// c, rがブロックの先頭であるかどうか
pred blackHeadInCol (c: Col, r: Row) {
	// 最初のRowであるか、または前のRowのセルが白い
  r in first or cell[c, r.prev] = White
	// このセルは黒い
  cell[c, r] in Black
}

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

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

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

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

fun Col2Int (c: Col): Int {
	c.index
}

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

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

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

abstract sig Region {}
sig Col extends Region {
  cell: Row -> Cell
}
sig Row extends Region {}
enum Cell { Black, White }

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

-- about rows
pred blackHeadInRow (c: Col, r: Row) {
  c in first or cell[c.prev, r] in White
  cell[c, r] in Black
}

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

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

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

fun Int2Row (i: Int): Row {
  {r: Row | #(r.prevs) = i}
}

fun Row2Int (r: Row): Int {
  #(r.prevs)
}

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

-- about cols
// c, rがブロックの先頭であるかどうか
pred blackHeadInCol (c: Col, r: Row) {
	// 最初のRowであるか、または前のRowのセルが白い
  r in first or cell[c, r.prev] = White
	// このセルは黒い
  cell[c, r] in Black
}

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

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

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

fun Int2Col (i: Int): Col {
  {c: Col | #(c.prevs) = i}
}

fun Col2Int (c: Col): Int {
  #(c.prevs)
}

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

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


Add solutions from the tutorial

Add solutions from the 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

some sig Final extends State { } { no successors }

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

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

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

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

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

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

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

fact { {s: State | no s.successors} in Final}

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

fact { State in Initial.*successors }

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

fact { all s: Black | Initial in s.^successors }

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

fact { all s: Yellow | some Final & s.^successors }

// *** 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 { all s: State | some Final & s.*successors }

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

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

fact { no Final & Black.^(successors - (State -> Initial)) }

// Additional requirement: a yellow state has a successor as a final state
fact { some Yellow & successors.Final }

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

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

sig State {
	successors: set State
}

// There is exactly one initial state

one sig Initial extends State { }

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

sig Final extends State { } { no successors }

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

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

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

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

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

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

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

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

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

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

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

assert  finishable { }

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

check finishable for 1

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

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


Final Version of FSE2017 Submission

Final Version of FSE2017 Submission

module TraceabilityModel
open util/relation

abstract sig Artifact {
	requires: set Artifact,	refines: set Artifact,
	contains: set Artifact,	conflicts: set Artifact}

-- Locate@File
sig Specification extends Artifact {}

-- Locate@Text
sig Requirement extends Artifact { equals: set Requirement}

-- Locate@Text
sig LowLevelReq, HighLevelReq extends Requirement { }

abstract sig Implementation extends Artifact {
	satisfies: set Requirement}

-- Locate@Code
sig Code extends Implementation {}

-- Locate@Model
sig Model extends Implementation {}

fact {injective[contains, Artifact]}
fact {irreflexive[requires + refines + contains + conflicts]}
fact {antisymmetric[requires + refines + contains]}

-- Reason@Artifact.conflicts
fact {all a,b,c: Artifact |
		b in a.(requires + refines + contains) and
					c in b.conflicts => c in a.conflicts
	symmetric[conflicts]}

-- Reason@Implementation.satisfies
fact {all a,b,c : Artifact {
		b in a.refines and b in c.satisfies =>
										a in c.satisfies
		b in a.refines and c in b.satisfies =>
										c in a.satisfies }}
-- Reason@Artifact.requires
fact {all a,b,c: Artifact {
		b in a.requires and c in b.(refines + contains) and
		   c !in a.(refines + contains) => c in a.requires
		b in a.(refines + contains) and c in b.requires and
		   c !in a.(refines + contains) => c in a.requires}}

fact {no conflicts &
		(requires + refines + satisfies + contains)}

error: pathspec 'eu.modelwriter.datasets.traceability/ModelWriter/TraceabilityModel.als' did not match any file(s) known to git


Added standard welcome

Added standard welcome

      Welcome to ALS Prolog (Standard Edition)!
      =========================================

Contents:
   - LICENSE
   - WARRANTY
   - CD ORGANIZATION
   - MANUAL
   - COPYING ALS

LICENSE
=======
Applied Logic Systems, Inc., provides this program and licenses
its use.  Use of this program is prohibited without a valid
license.  You may:
a)  Use this program on a single machine at any given time;
    (To install this program on a server, you must obtain a
     separate server license from Applied Logic Systems.)
b)  Copy the program for backup purposes;
c)  Transfer the program and license to another person if the
    other person agrees to accept the terms of this license.
No other uses of program are permitted.

WARRANTY
========
This program is provided "as is " without warranty of any kind,
either expressed or implied, including, but not limited to,
implied warranties of merchantability and fitness for a
particular purpose.  You assume the entire risk as to the
selection of this program to achieve your intended results and
for the installation, use, performance, and results obtained
through the use of this program.

CD ORGANIZATION
===============
The ALS Prolog Standard Edition CD contains the following file
and directories:

     ALS Prolog 3.1 Installer (file)
     ALS Prolog (directory)
     Acrobat (directory)

The directory "ALS Prolog" is an expanded version of the
installer.  That is, "ALS Prolog 3.1 Installer" will create
an installation directory identical to "ALS Prolog".  You
can run ALS Prolog directly from the CD.  To install ALS Prolog on
your hard drive, simply double-click on the icon for

     ALS Prolog 3.1 Installer

and follow the simple directions.

MANUAL
======
The manual for the standard edition of ALS Prolog is provided
by the file

    ALS Prolog Manual.pdf

in the installation directory ALS Prolog.  This is an Adobe
Acrobat(r) file.  A copy of an installer for Acrobat is included in
the Acrobat directory.  To install Acrobat, change directory into the
Acrobat subdirectory, and double-click on "setup.exe".  Follow the
directions for the installation.  After Acrobat is installed, just
double-click on the icon for

    ALS Prolog Manual.pdf

to read the ALS Prolog documentation.

COPYING ALS
===========
Most of the source files distributed with ALS Prolog are governed
by the license contained in the file "COPYING ALS" which
is included with this distribution.

   = = = = = = = = = = = = = = = = = = = = = = = = = = = =

       Applied Logic Systems, Inc.
       PO Box 400175, Cambridge, MA 02140 USA
       Email: support@als.com   Web: http://www.als.com
       Fax: (617) 497-3963 Tel: (617) 497-0100

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


alloy model updated

alloy model updated

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

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 {
//	day: Int,
	hour: Int,
	minute: Int
} {
//	day >= 0
//	day =< 60 // For efficiency reasons
	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 minutesDifference[t, t': Time]: Int {
	add[sub[60, t'.minute], t.minute]
}

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' <= 1h

pred isLessThanOneHourAhead[t, t': Time] {
	areEqual[t, t']
	or
//	(t.day = t'.day
//		implies (
			(t.hour = t'.hour and t.minute > t'.minute)
			or
			(t.hour = add[t'.hour,1] and minutesDifference[t, t'] < 60)
/*		)
		else (
			(t.day = add[t'.day, 1] and t.hour = 0 and t'.hour = 23 and minutesDifference[t, t'] < 60)
		)
	)*/
}

// Returns true if t >= t'

pred comesAfterOrEqual[t, t': Time] {
//	t.day = t'.day
//	implies (
		t.hour = t'.hour
		implies t.minute >= t'.minute
		else t.hour >= t'.hour
//	)
//	else t.day >= t'.day
}

// Returns true if t == t'

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

// 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] <= 5
	else
		sub[l'.latitude, l.latitude] <= 5)
	and
	(l.longitude >= l'.longitude implies
		sub[l.longitude, l'.longitude] <= 5
	else
		sub[l'.longitude, l.longitude] <= 5)
}

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

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

fact carAvailableCondition {
	all c: Car |
		c.available = True
		iff
		(no res: Reservation |
			res.car = c and isActive[res]
		)
}

// 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 costOfAReservation {
	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]
			)
		)
	)
}
// ------------- 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
	all r: Reservation | r.expired = False
	#User = 1
	#Car = 2
	#Reservation = 3
//	some c: Car | c.unlocked = True
//	some c: Car | c.unlocked = False

}

//run show for 8 Int

run show for 7 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


add comment etc

add comment etc

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

abstract sig Region {}
sig Col extends Region {
  cell: Row -> Cell
}
sig Row extends Region {}
enum Cell { Black, White }

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

-- about rows
pred blackHeadInRow (c: Col, r: Row) {
  c in first or cell[c.prev, r] in White
  cell[c, r] in Black
}

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

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

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

fun Int2Row (i: Int): Row {
  {r: Row | #(r.prevs) = i}
}

fun Row2Int (r: Row): Int {
  #(r.prevs)
}

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

-- about cols
// c, rがブロックの先頭であるかどうか
pred blackHeadInCol (c: Col, r: Row) {
	// 最初のRowであるか、または前のRowのセルが白い
  r in first or cell[c, r.prev] = White
	// このセルは黒い
  cell[c, r] in Black
}

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

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

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

fun Int2Col (i: Int): Col {
  {c: Col | #(c.prevs) = i}
}

fun Col2Int (c: Col): Int {
  #(c.prevs)
}

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

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

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

abstract sig Region {}
sig Col extends Region {
  cell: Row -> Cell
}
sig Row extends Region {}
enum Cell { Black, White }

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

-- about rows
pred blackHeadInRow (c: Col, r: Row) {
  c in first or cell[c.prev, r] in White
  cell[c, r] in Black
}

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

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

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

fun Int2Row (i: Int): Row {
  {r: Row | #(r.prevs) = i}
}

fun Row2Int (r: Row): Int {
  #(r.prevs)
}

pred rowHint (j: Int, sizes: seq Int) {
  let r = Int2Row[j] | some cs: seq Col {
    #sizes = #cs
    headsSeqInRow [r, cs]
    all i: sizes.inds |
      let start = cs [i], end = Int2Col [plus [Col2Int [start], minus[sizes [i], 1] ]] {
       some end
       all c: start.*cols/next - end.^cols/next | cell [c, r] in Black
       no end.next or cell [end.next, r] in White
     }
  }
}

-- about cols
pred blackHeadInCol (c: Col, r: Row) {
  r in first or cell[c, r.prev] in White
  cell[c, r] in Black
}

fun headsInCol (c: Col): set Row {
  { r: Row | blackHeadInCol[c, r] }
}

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

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

fun Int2Col (i: Int): Col {
  {c: Col | #(c.prevs) = i}
}

fun Col2Int (c: Col): Int {
  #(c.prevs)
}

pred colHint (j: Int, sizes: seq Int) {
  let c = Int2Col[j] | some rs: seq Row {
    #sizes = #rs
    headsSeqInCol [c, rs]
    all i: sizes.inds |
      let start = rs [i], end = Int2Row [plus [Row2Int [start], minus[sizes [i], 1] ]] {
       some end
       all r: start.*rows/next - 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


remove noOtherHeadsIn* because they are not used

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

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

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

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

enum Color { Black, White }

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

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

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

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

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

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

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

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

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

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

				// endが存在する
				some end
				// startからendまで全部黒
				all c: range[start, end, cols/next] | cell [c, r] in Black
				// endの次がないか、または白
				no end.next or cell [end.next, r] in White
			}
		}
	}
}
pred colHint (j: Int, sizes: seq Int) {
	let c = IntTo[j, Col] | some rs: seq Row {
		#sizes = #rs
		headsSeqInCol [c, rs]
		all i: sizes.inds {
			let start = rs [i], end = Row & get_block_end[start, sizes[i]] {
				some end
				all r: range[start, end, rows/next] | cell [c, r] in Black
				no end.next or cell [c, end.next] in White
			}
		}
	}
}
-- riddle from http://homepage1.nifty.com/sabo10/rulelog/illust.html
solve: run {
	rowHint [0, 0 -> 3]
	rowHint [1, 0 -> 2 + 1 -> 2]
	rowHint [2, 0 -> 1 + 1 -> 1 + 2 -> 1]
	rowHint [3, 0 -> 3 + 1 -> 3]
	rowHint [4, 0 -> 5]
	rowHint [5, 0 -> 7]
	rowHint [6, 0 -> 7]
	rowHint [7, 0 -> 7]
	rowHint [8, 0 -> 7]
	rowHint [9, 0 -> 5]

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


spaces to tabs

spaces to tabs

open util/ordering[Time]

sig Time {}

sig Person {
	state: State -> Time,
}

enum State {Married, NotMarried}

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

pred step (t, t': Time) {
	some disj p1, p2 : Person {
		{
			// 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
		}
	}
}

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

run {} for exactly 3 Person, 5 Time