Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add chess_position example #266

Merged
merged 10 commits into from
Oct 23, 2023
Merged

Add chess_position example #266

merged 10 commits into from
Oct 23, 2023

Conversation

KennyVDV
Copy link
Contributor

The model makes a chess board that can be played in an actual game of chess from the probabilities of every piece and the squares where pieces are present.

@CryoCardiogram CryoCardiogram self-assigned this Apr 14, 2023
(((board[1,1] == p) & (board[1,3] == p) & (board[1,0] == p) & (board[0,2] == b)).implies(Xor([board[0,1] == r,board[0,0] == r]))),
(((board[1,4] == p) & (board[1,6] == p) & (board[1,7] == p) & (board[0,5] == b)).implies(Xor([board[0,6] == r,board[0,7] == r]))),
# If both bishops are stuck and pawns are in starting position, king and queen are also in starting position
(((board[1,1] == p) & (board[1,2] == p) & (board[1,3] == p) & (board[1,4] == p) & (board[1,5] == p) & (board[1,6] == p)).implies((board[0,3] == q) | (board[0,4] == k))),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here maybe you mean implies((board[0,3] == q) & (board[0,4] == k)))?

In the description you say that this means that both King and queen are in starting position, not at least one of them

(((board[1,4] == p) & (board[1,6] == p) & (board[1,7] == p) & (board[0,5] == b)).implies(Xor([board[0,6] == r,board[0,7] == r]))),
# If both bishops are stuck and pawns are in starting position, king and queen are also in starting position
(((board[1,1] == p) & (board[1,2] == p) & (board[1,3] == p) & (board[1,4] == p) & (board[1,5] == p) & (board[1,6] == p)).implies((board[0,3] == q) | (board[0,4] == k))),
(((board[6,1] == P) & (board[6,2] == P) & (board[6,3] == P) & (board[6,4] == P) & (board[6,5] == P) & (board[6,6] == P)).implies((board[7,3] == Q) | (board[7,4] == K))),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

# All the constraints that a chess board has to follow
model = Model(
# Both colors have only one king
(sum(board[l,c] == k for l in range(0,8) for c in range(0,8)) == 1),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be better to use a count constraint for k (and resp. K) for this?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just a
Count(board, k) == 1,
Count(board, K) == 1,
...

return dict.get(x, x)


piece_probabilities = np.array([[-1.1558e+01, -1.8940e-01, -1.0785e+01, -8.4097e+00, -1.3034e+01, -8.7986e+00, -2.6694e+00, 1.2009e+01, -3.5726e+00, -9.1412e-01, -2.0600e+00, -5.9005e-01],
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need a lot more documentation on what these are. We know from the report, but if it is added as an example in CPMpy, not everyone will have read the report. Need far more explanation on what this is, and maybe some references on what you can use to get these probabilities from an image.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, these are not probabilities. I assume it is the output of the NNs for the prediction. It is a bit weird for output, with the range of the values. It should be explained how you got them.

[-1.0578e+01, -9.6113e+00, -1.0476e+01, -6.9775e+00, -3.4868e+00, -9.2788e+00, 2.2917e-01, 1.6189e+00, -1.9423e+00, 9.8658e-01, 8.7442e+00, 1.9664e+00],
[ 1.7821e+00, 2.5520e+00, 2.3929e+00, -3.7030e-01, -3.3090e-01, 1.9798e-01, -6.8749e+00, -6.4092e+00, -5.7582e+00, -5.6637e+00, -8.7920e+00, -7.5211e+00]])

occupancy_in_board = np.array([False, False, False, False, False, False, True, False,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same for this, some more explanation (and maybe before the probabilities, as it is predicted first.

(sum(board[l,c] < 6 for l in range(0,8) for c in range(0,8)) <= 16),
(sum(((board[l,c] >= 6) & (board[l,c] < 12)) for l in range(0,8) for c in range(0,8)) <= 16),
# Both colors have maximum 8 pawns
(sum(board[l,c] == p for l in range(0,8) for c in range(0,8)) <= 8),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again,
Count(board, p) <= 8,
Count(board, P) <= 8,

(sum(board[0,c] == p for c in range(0,8)) == 0),
(sum(board[0,c] == P for c in range(0,8)) == 0),
(sum(board[7,c] == p for c in range(0,8)) == 0),
(sum(board[7,c] == P for c in range(0,8)) == 0),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general the constraints can be written in a better way, See previous comments

((board[1,1] == p) & (board[0,0] == b)).implies(sum(board[l,c] == P for l in range(0,8) for c in range(0,8)) <= 7),
)

# Put the index of the maximum value into the second row of the pieces variable
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The following 'for' is not needed, it is overcomplicated for something that can be done in a much more straightforward way, and it will make the solving process much slower too.

You try to match the probabilities with the pieces, while you already have the probabilities and you already have the pieces in different arrays, but you created new variables for the matching although it is 1 to 1.

You have 22 pieces in this example. why not match directly the 22 cells in the board that are predicted to have a piece (which you can just take by using board[occupancy_in_board]) with the 22 rows of pieces_values? You can do that in the objective function and avoid all these variables, and constraints.

model += (board[int(i/8), i%8] == pieces[1, index])
index += 1
else:
model += (board[int(i/8), i%8] == E)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The above for is not needed either.

To force the empty cells, you can just do
model += board[occupancy_in_board == False] == E

and for the non empty cells, you can link directly with the probabilities in the objective function. So, you use only the board variables.

model += (board[int(i/8), i%8] == E)

# Maximize the probabilites of the pieces to get the most likely board
model.maximize(sum(pieces[0]))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based also on my comments before, regarding the variables for pieces that are not needed, I suggest to replace with

obj = sum(lp[v] for lp, v in zip(pieces_values, board[occupancy_in_board]))
model.maximize(obj)

This way, you directly linked the probabilities in pieces_values, with the cells in the board that need to be predicted.

Already tried the above and yield to the same solution.

And importantly, from 264 seconds that were needed to solve, it dropped to less than 0.5s.

@Dimosts Dimosts self-assigned this Sep 28, 2023
@Wout4 Wout4 merged commit 51244ce into CPMpy:master Oct 23, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants