Question

I am working on a chess engine, and am using the Gene Expression Programming approach to evolve the evaluation function.

As there is no oracle for chess, my fitness function is only capable of finding the relative fitness of two individuals (by performing a chess match).

Since I do not have an absolute fitness measure, I might end up with some individuals which are better than each other in a circular fashion ( $R_A_B(A)>R_A_B(B), R_B_C(B)>R_B_C(C), R_A_C(C)>R_A_C(A)$ )

So, what are some ways of efficiently evolving the individuals in such a scenario, and how can I avoid ending up in such circular mess? Thanks :)

Was it helpful?

Solution

The circular fashion ( R_A_B(A)>R_A_B(B), R_B_C(B)>R_B_C(C), R_A_C(C)>R_A_C(A) ) cannot be completely avoided, because chess game is a good example of a perfect NP problem and a detailed behavior of such systems cannot be evaluated with great accuracy.

lets consider a chess board position P. Lets represent variations generated by individual A form the position P in a chess board to belong the set Ap. Lets consider another set Bp where the evaluate function defined by B is used to obtain variations at that position. Lets define a function Q(x) that tests the quality of the variations provided by any individual as the game proceeds. So at P let Q(Ap) > Q(Bp) then for any other position p', Q(Bp') > Q(Ap').

Evolving an individual that generates best variations for all positions is impossible as you yourself stated that there is no oracle for chess;
enter image description here but that's not going to be a problem. here I have suggested a method that might help; Instead of trying to provided a unique rank to individuals in such a mess, why can't they be treated equally? If they are treated equally, One problem that could arise is that the first few generations could largely end up in such a circular mess (there would be too many individuals being equal in strength). So its not wrong to use a different fitness function for the first few generations to improve their efficiency enough to solve basic chess puzzles (by defining a fitness function with a simpler endpoint). Later generations would fall in this circular mess for lesser number of times and that would not be a problem. If the fitness function depends upon the result of a match played between two individuals in a particular population, then this would set the end point of this evolution as: attaining the playing strength of the hypothetical function G(x) (which is never possible). So the individuals generated would try to evolve in a broader scale, by trying to become perfect in all board situations (which would slow down the process if the individuals present in the initial generations are of weak playing strength).

The other method I would suggest would be to try to define a constant function N(x), that is made to work in a higher time complexity (i.e. evaluates longer than the individuals selected from a particular generation by checking more variations). Now we may compare the values R_A_N(A), R_B_N(B), R_C_N(C) separately to rank them in an order. It is not really necessary to create a unique constant evaluate function for this purpose, any random individual can be selected for this purpose.

Using a selective individual N (made to search for a greater depth) and then trying to find the R_A_N(A), is more like selecting a origin in a graph where only relative positions of certain points are known. Here the population is made to develop relative to the selected individual; N does not have to be a constant function with fixed parameters, it could also be one of the individuals present in this circular mess being made to run in an engine that tests more number of variations( higher search depth) . If individual A is chosen as N, and is made to play with itself run in a greater depth, then its obvious that the individual A which runs with a higher depth beats A run at a lower depth. here, we could define a fitness function that depends upon factors other than the end result of a chess match; for example,

enter image description here

so defining R_A_N(A), R_B_N(B), ... this way could avoid this circular mess.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top