Skip to content

Commit

Permalink
A few minor changes to some models
Browse files Browse the repository at this point in the history
  • Loading branch information
lecoutre committed Sep 29, 2024
1 parent 2ffc5fb commit da3f9c5
Show file tree
Hide file tree
Showing 13 changed files with 214 additions and 104 deletions.
4 changes: 1 addition & 3 deletions realistic/AircraftLanding/AircraftLanding.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,9 @@
For example, by introducing a new array r where r[i] is the runway ;
a new array s where s[i] is x[i]*k+r[i] where k is the number of runways
and posting new constraints (AllDifferent(s), ...).
This is something to do.
This is something to do.
2) For the 2022 competition, we used as objective for the mini-track:
Sum(erl) + Sum(trd)
3) Note that
for v in x[i].dom
is equivalent to:
Expand Down
30 changes: 10 additions & 20 deletions recreational/Amaze/Amaze.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,26 +21,16 @@
n, m, points = data # points[v] gives the pair of points for value v(+1)
points.insert(0, []) # inserting a dummy entry at index 0 to simplify correspondences later
decrement(points) # because we start indexing at 0
max_value = len(points)
Values = range(1, max_value)

# x[i][j] is the value at row i and column j (possibly 0)
x = VarArray(size=[n, m], dom=range(max_value))


# tables used for ensuring the presence of some neighbors
def T(r): # r is the number of neighbors (2, 3 or 4)
return [
tuple([0] + [ANY] * r),
*[tuple([v] + [v if k in (i, j) else ne(v) for k in range(r)]) for v in Values for i, j in combinations(r, 2)]
]
Fixed = [tuple(p) for pair in points for p in pair]
Values = range(1, len(points))

# x[i][j] is the value at row i and column j (possibly 0)
x = VarArray(size=[n, m], dom={0} | set(Values))

satisfy(
# putting two initially specified occurrences of each value on the board
[
x[i][j] == v for v in Values for i, j in points[v]
],
[x[i][j] == v for v in Values for i, j in points[v]],

# each cell with a fixed value has exactly one neighbour with the same value
[
Expand All @@ -54,8 +44,8 @@ def T(r): # r is the number of neighbors (2, 3 or 4)
[
Table(
scope=x.cross(i, j),
supports=T(len(x.beside(i, j)))
) for i in range(n) for j in range(m) if (i, j) not in [tuple(p) for pair in points for p in pair]
supports=[(0, *[ANY] * r)] + [(v, *[v if k in (p, q) else ne(v) for k in range(r)]) for v in Values for p, q in combinations(r, 2)]
) for i in range(n) for j in range(m) if (i, j) not in Fixed and (r := len(x.beside(i, j)),)
]
)

Expand All @@ -65,7 +55,7 @@ def T(r): # r is the number of neighbors (2, 3 or 4)

""" Comments
1) The table contains (hybrid) conditions, which makes, for example, code more compact than:
1) Tables contain (hybrid) conditions, which makes, for example, code more compact than:
T = ({(0, ANY, ANY, ANY, ANY)}
| {(v, v, v, v1, v2) for v in Values for v1 in range(nValues+1) for v2 in range(nValues+1) if v1 != v and v2 != v}
| {(v, v, v1, v, v2) for v in Values for v1 in range(nValues+1) for v2 in range(nValues+1) if v1 != v and v2 != v}
Expand All @@ -80,10 +70,10 @@ def T(r): # r is the number of neighbors (2, 3 or 4)
Count([x[i - 1][j], x[i + 1][j], x[i][j - 1], x[i][j + 1]], value=v) == 1
4) Note that one can write:
x.cross(i, j) in T(len(x.beside(i, j)))
x.cross(i, j) in T
instead of:
Table(
scope=x.cross(i, j),
supports=T(len(x.beside(i, j)))
supports=T
)
"""
6 changes: 2 additions & 4 deletions recreational/AnotherMagicSquare/AnotherMagicSquare.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,8 @@
)

""" Comments
1) there are 0, 8 and 0 solutions for n = 2, 3 and 4
2) for being compatible with the competition mini-track, we use:
1) There are 0, 8 and 0 solutions for n = 2, 3 and 4
2) For being compatible with the competition mini-track, we use:
# y[i,j] is the multiple used for the cell at row i and column j
y = VarArray(size=[n, n], dom=range(1, 8*(n * n) + 1))
Expand Down
8 changes: 3 additions & 5 deletions recreational/AntimagicSquare/AntimagicSquare.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,9 @@
)

""" Comments
1) it is possible to relax so as to have a COP.
minimizing the expression: Maximum(x) - Minimum(y)
2) for being compatible with the competition mini-track, we use:
1) It is possible to relax so as to have a COP.
minimizing the expression: Maximum(x) - Minimum(y)
2) For being compatible with the competition mini-track, we use:
z = VarArray(size=2*n+2, dom=range(2*n+2))
[y[z[i]] +1 == y[z[i+1]] for i in range(2*n+1)],
Expand Down
2 changes: 0 additions & 2 deletions recreational/Areas/Areas.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,9 @@ def table(k, v, w):
)

""" Comments
1) (x.cross(i, j), d.cross(i, j)) is a tuple containing two sub-tuples of variables.
This is automatically flattened (i.e., transformed into a single tuple). Of course, it is also possible to write:
(*x.cross(i, j), *d.cross(i, j))
2) cross is a method that can be called on 2-dimensional arrays/lists of variables (ListVar).
For an array t, and indexes i,j, it returns [t[i][j], t[i][j - 1], t[i][j + 1], t[i - 1][j], t[i + 1][j]]
"""
17 changes: 6 additions & 11 deletions recreational/Audrey/Audrey.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,21 +71,16 @@ def reachable(i, j):
)

""" Comments
1) the main model variant is sufficient to compute solutions.
1) The main model variant is sufficient to compute solutions.
It is the fastest model. Hence, in a complex-world application,
adding constraints for pure presentational issue should be carefully thought.
2) the variant 'display1' allows us to display the values (and not only the chaining).
adding constraints for pure presentational issue should be carefully thought.
2) The variant 'display1' allows us to display the values (and not only the chaining).
From this variant, to really get a matrix being printed, on can add:
b = VarArray(size=[n, n], dom=range(n2))
satisfy(
b[i // n][i % n] == y[i] for i in range(n2)
)
3) the variant 'display2' allows us to directly print the values in a matrix.
)
3) The variant 'display2' allows us to directly print the values in a matrix.
This involves a constraint 'ElementMatrix' whose computed value must be equal to a variable.
4) we obtain 96 solutions for n=5 with the three variants.
4) We obtain 96 solutions for n=5 with the three variants.
"""
12 changes: 4 additions & 8 deletions recreational/BinaryPuzzle/BinaryPuzzle.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,17 +74,13 @@
)

""" Comments
1) For XCSP competitions, before 2024, we needed to discard or translate in tables (calling .to_table())
the AllDifferentList constraints
2) for finding a first solution, the regular model is far more efficient (at least with default heuristics)
(a few seconds for n=50, 60 or 70)
3) for being compatible with the competition mini-track, we use for the main variant:
2) For finding a first solution, the regular model is far more efficient (at least with default heuristics)
(a few seconds for n=50, 60 or 70)
3) For being compatible with the competition mini-track, we use for the main variant:
[Sum(x[i, j:j + 3]) >= 1 for i in range(n) for j in range(n - 2)],
[Sum(x[i, j:j + 3]) <= 2 for i in range(n) for j in range(n - 2)],
4) we can write:
4) We can write:
[Sum(x[i, j:j + 3]) in {1,2} for i in range(n) for j in range(n - 2)],
"""
4 changes: 1 addition & 3 deletions recreational/Blackhole/Blackhole.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,8 @@
)

""" Comments
1) Slide is only used to have more compact XCSP3 instances
we could have written: [(x[i], x[i + 1]) in table for i in range(nCards - 1)]
we could have written: [(x[i], x[i + 1]) in table for i in range(nCards - 1)]
2) Increasing(y[pile], strict=True)
is equivalent to:
Increasing([y[j] for j in pile], strict=True)
Expand Down
3 changes: 1 addition & 2 deletions recreational/BlockedQueens/BlockedQueens.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,7 @@
)

""" Comments
1) one could also post:
1) One could also post:
# controlling no two queens on the same upward diagonal
AllDifferent(q[i] + i for i in range(n)),
Expand Down
71 changes: 46 additions & 25 deletions recreational/Blocks/Blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@
# done[t] is 1 if the goal configuration is present at time t
done = VarArray(size=horizon, dom={0, 1})

# mv[t] is a pair (v,w) indicating that w becomes the successor of v at time t
mv = VarArray(size=[horizon, 2], dom=lambda t, j: None if t == 0 else range(nCubes))
# move[t] is a pair (v,w) indicating that w becomes the successor of v at time t
move = VarArrayMultiple(size=horizon, fields={"src": lambda t: None if t == 0 else range(nCubes), "dst": lambda t: None if t == 0 else range(nCubes)})

# locked[i][t] is 1 if the ith cube is locked at time t
locked = VarArray(size=[nCubes, horizon], dom=lambda i, t: {0} if i == 0 else {0, 1})
Expand All @@ -56,7 +56,7 @@
x[:, -1] == goal,

# recording new states when moving
[mv[t][1] == x[mv[t][0]][t] for t in range(1, horizon)],
[move[t].dst == x[move[t].src][t] for t in range(1, horizon)],

# computing the number of times cubes occur in configurations
[
Expand All @@ -70,16 +70,16 @@
Increasing(done),

# when finished, no more move
[done[t - 1] == (mv[t][0] == 0) for t in range(1, horizon)],
[done[t - 1] == (move[t].src == 0) for t in range(1, horizon)],

# handling how cubes move
[
If(
done[t - 1],
Then=[(x[i][t - 1] == x[i][t]) for i in range(1, nCubes)],
Then=x[1:, t - 1] == x[1:, t],
Else=[
[(x[i][t - 1] != x[i][t]) == (i == mv[t][0]) for i in range(nCubes)],
nb[mv[t][0]][t - 1] == 0
[(x[i][t - 1] != x[i][t]) == (i == move[t].src) for i in range(nCubes)],
nb[move[t].src][t - 1] == 0
]
) for t in range(1, horizon)
],
Expand All @@ -88,28 +88,28 @@
[
# bounding the number of moves per cube
[
[Sum(x[i][t - 1] != x[i][t] for t in range(1, horizon)) >= 1 for i in range(1, nCubes) if start[i] != goal[i]],
[Sum(x[i][t - 1] != x[i][t] for t in range(1, horizon)) <= nPiles for i in range(1, nCubes)]
[Hamming(x[i][:-1], x[i][1:]) >= 1 for i in range(1, nCubes) if start[i] != goal[i]],
[Hamming(x[i][:-1], x[i][1:]) <= nPiles for i in range(1, nCubes)]
],

# preventing do-undo moves
[
If(
~done[t],
Then=[
mv[t][0] != mv[t + 1][0],
mv[t][1] != mv[t + 1][0],
mv[t][1] != mv[t + 1][1],
mv[t][0] != mv[t][1]
move[t].src != move[t + 1].src,
move[t].dst != move[t + 1].src,
move[t].dst != move[t + 1].dst,
move[t].src != move[t].dst
]
) for t in range(1, horizon - 1)
],

# computing locked cubes
[
locked[i][t] == (
x[i][t] == 0 if goal[i] == 0
else both(x[i][t] == goal[i], locked[goal[i]][t])
locked[i][t] == both(
x[i][t] == goal[i],
locked[goal[i]][t] if goal[i] != 0 else None
) for i in range(1, nCubes) for t in range(horizon)
],

Expand All @@ -119,7 +119,7 @@
locked[i][t],
Then=[
x[i][t + 1] == goal[i],
mv[t + 1][0] != i
move[t + 1].src != i
]
) for i in range(1, nCubes) for t in range(horizon - 1)
],
Expand All @@ -134,14 +134,26 @@
],

# computing the objective value
z == horizon - Sum(done)
z == horizon - Sum(done),
)

minimize(
# minimizing the number of steps to achieve the goal
z
)

""" Comments
1) [done[i] == (x[1:, i] == goal) for i in range(horizon)]
is equivalent to:
[done[i] == conjunction(x[j, i] == goal[j - 1] for j in range(1, n + 1)) for i in range(horizon)]
2) The constraints about objective lower bound seems penalizing
3) x[1:, t - 1] == x[1:, t]
is equivalent to [(x[i][t - 1] == x[i][t]) for i in range(1, nCubes)]
4) Hamming(x[i][:-1], x[i][1:]) >= 1
is equivalent to
[Sum(x[i][t - 1] != x[i][t] for t in range(1, horizon)) >= 1
"""

# # when finished, the configuration remains the same
# [(done[t - 1] == 0) | (x[i][t - 1] == x[i][t]) for t in range(1, horizon) for i in range(1, nCubes)],
#
Expand All @@ -154,12 +166,21 @@
# # when finished, the state remains equal to the goal configuration
# [done[t] == (x[1:, t] == goal) for t in range(horizon)],

# locked[i][t] == (
# x[i][t] == 0 if goal[i] == 0
# else both(x[i][t] == goal[i], locked[goal[i]][t])
# ) for i in range(1, nCubes) for t in range(horizon)

""" Comments
# testing with tables as below?

1) [done[i] == (x[1:, i] == goal) for i in range(horizon)]
is equivalent to:
[done[i] == conjunction(x[j, i] == goal[j - 1] for j in range(1, n + 1)) for i in range(horizon)]
2) the constraints about objective lower bound seems penalizing
"""
# def table(i):
# tbl = []
# tbl.extend([(1, v, v, ANY) for v in range(nCubes)])
# for j in range(nCubes):
# if j != i:
# tbl.extend([(0, v, v, j) for v in range(nCubes)])
# else:
# tbl.extend([(0, v, w, j) for v in range(nCubes) for w in range(nCubes) if v != w])
# return tbl

# [(done[t - 1], x[i][t - 1], x[i][t], move[t].src) in table(i) for t in range(1, horizon) for i in range(nCubes)],
13 changes: 9 additions & 4 deletions recreational/Blocks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,24 @@ The model, below, is close to (can be seen as the close translation of) the one
The MZN model was proposed by Mats Carlsson, under the MIT Licence.

## Data Example
16-4-05.json

16-4-05.json

## Model
constraints: [Cardinality](http://pycsp.org/documentation/constraints/Cardinality), [Element](http://pycsp.org/documentation/constraints/Element)

constraints: [Cardinality](http://pycsp.org/documentation/constraints/Cardinality), [Element](http://pycsp.org/documentation/constraints/Element)

## Execution

```
python Blocks.py -data=<datafile.json>
python Blocks.py -data=<datafile.dzn> -parser=Blocks_ParserZ.py
```

## Links
- https://www.minizinc.org/challenge2022/results2022.html

- https://www.minizinc.org/challenge2022/results2022.html

## Tags
recreational, mzn22

recreational, mzn22
Loading

0 comments on commit da3f9c5

Please sign in to comment.