Skip to content

Commit

Permalink
Revert "Store principal continuations in static arrays rather than li…
Browse files Browse the repository at this point in the history
…sts, to reduce memory overhead."

This reverts commit 45a0e23.
  • Loading branch information
cjbolt committed Apr 26, 2022
1 parent 145d8d2 commit 93e60a7
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 61 deletions.
12 changes: 5 additions & 7 deletions EubosChess/src/main/java/eubos/search/PlySearcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import java.util.IntSummaryStatistics;
import java.util.List;
import java.util.stream.Collectors;
import java.util.Arrays;

import eubos.board.Piece;
Expand Down Expand Up @@ -84,7 +83,7 @@ public void report() {

private volatile boolean terminate = false;

private int[] lastPc;
private List<Integer> lastPc;
private ITranspositionAccessor tt;
private SearchMetricsReporter sr;
private KillerList killers;
Expand Down Expand Up @@ -219,7 +218,7 @@ int searchRoot(int depth) {

// This move is only valid for the principal continuation, for the rest of the search, it is invalid. It can also be misleading in iterative deepening?
// It will deviate from the hash move when we start updating the hash during iterative deepening.
prevBestMove[0] = ((lastPc != null) && (lastPc.length > 0)) ? lastPc[0] : Move.NULL_MOVE;
prevBestMove[0] = ((lastPc != null) && (lastPc.size() > 0)) ? lastPc.get(0) : Move.NULL_MOVE;
prevBestMove[0] = Move.clearBest(prevBestMove[0]);
if (EubosEngineMain.ENABLE_UCI_INFO_SENDING) pc.clearContinuationBeyondPly(0);

Expand All @@ -238,7 +237,7 @@ int searchRoot(int depth) {
if (trans != 0L) {
evaluateTransposition(trans, depth);
if (isCutOff[0]) {
sm.setPrincipalVariationDataFromHash(0, (short)hashScore[0]);
sm.setPrincipalVariationDataFromHash(0, pc.toPvList(0), (short)hashScore[0]);
sr.reportPrincipalVariation(sm);
return hashScore[0];
}
Expand Down Expand Up @@ -348,7 +347,7 @@ int search(int depth, boolean nullCheckEnabled) {

// This move is only valid for the principal continuation, for the rest of the search, it is invalid. It can also be misleading in iterative deepening?
// It will deviate from the hash move when we start updating the hash during iterative deepening.
prevBestMove[currPly] = ((lastPc != null) && (lastPc.length > currPly)) ? lastPc[currPly] : Move.NULL_MOVE;
prevBestMove[currPly] = ((lastPc != null) && (lastPc.size() > currPly)) ? lastPc.get(currPly) : Move.NULL_MOVE;
prevBestMove[currPly] = Move.clearBest(prevBestMove[currPly]);
if (EubosEngineMain.ENABLE_UCI_INFO_SENDING) pc.clearContinuationBeyondPly(currPly);

Expand Down Expand Up @@ -722,8 +721,7 @@ private boolean checkForRepetitionDueToPositionInSearchTree(int move) {

private void reportPv(short positionScore) {
if (EubosEngineMain.ENABLE_UCI_INFO_SENDING) {
List<Integer> list = Arrays.stream(pc.toPvList(0)).boxed().collect(Collectors.toList());
sm.setPrincipalVariationData(extendedSearchDeepestPly, list, positionScore);
sm.setPrincipalVariationData(extendedSearchDeepestPly, pc.toPvList(0), positionScore);
sr.reportPrincipalVariation(sm);
extendedSearchDeepestPly = 0;
}
Expand Down
107 changes: 65 additions & 42 deletions EubosChess/src/main/java/eubos/search/PrincipalContinuation.java
Original file line number Diff line number Diff line change
@@ -1,105 +1,128 @@
package eubos.search;

import eubos.main.EubosEngineMain;
import java.util.ArrayList;
import java.util.List;

import eubos.position.Move;
import it.unimi.dsi.fastutil.ints.IntArrays;

public class PrincipalContinuation {

private int [][] pc;
private int [] length;
private List<List<Integer>> pc;
private SearchDebugAgent sda;

public PrincipalContinuation(int searchDepth, SearchDebugAgent sda) {
// Create the pc list at each ply
pc = new int[EubosEngineMain.SEARCH_DEPTH_IN_PLY][];
for (int i = 0; i < EubosEngineMain.SEARCH_DEPTH_IN_PLY; i++) {
pc[i] = new int[EubosEngineMain.SEARCH_DEPTH_IN_PLY];
pc = new ArrayList<List<Integer>>(searchDepth);
for (int i=0; i<searchDepth; i++) {
pc.add(new ArrayList<Integer>(searchDepth));
}
length = new int[EubosEngineMain.SEARCH_DEPTH_IN_PLY];
this.sda = sda;
}

public int getBestMove(byte currPly) {
if (currPly < EubosEngineMain.SEARCH_DEPTH_IN_PLY) {
if (length[currPly] != 0)
return pc[currPly][0];
if (currPly < pc.size()) {
List<Integer> plyList = pc.get(currPly);
if (!plyList.isEmpty())
return plyList.get(0);
}
return Move.NULL_MOVE;
}

public String toString() {
StringBuilder output = new StringBuilder();
for (int currPly = 0; currPly < length[0]; currPly++) {
for (int currPly = 0; currPly < pc.size(); currPly++) {
output.append(String.format("Ply %d (%s) ,", currPly, toStringAt(currPly)));
}
return output.toString();
}

public String toStringAt(int currPly) {
StringBuilder output = new StringBuilder();
if (currPly < EubosEngineMain.SEARCH_DEPTH_IN_PLY) {
if (length[currPly] != 0) {
for (int i=0; i<length[currPly]; i++) {
int currMove = pc[currPly][i];
if (EubosEngineMain.ENABLE_ASSERTS) {
assert currMove != Move.NULL_MOVE;
}
output.append(Move.toString(currMove));
if (currPly < pc.size()) {
List<Integer> plyList = pc.get(currPly);
if (!plyList.isEmpty()) {
for (int currMove : plyList) {
//assert currMove != Move.NULL_MOVE;
output.append((Move.toString(currMove)));
output.append(' ');
}
}
}
return output.toString();
}

public int [] toPvList(int currPly) {
if (currPly < EubosEngineMain.SEARCH_DEPTH_IN_PLY) {
int [] pv = IntArrays.trim(pc[currPly], length[currPly]);
return pv;
public static String pvToString(List<Integer> pv) {
StringBuilder output = new StringBuilder();
if (pv != null && !pv.isEmpty()) {
for (int currMove : pv) {
//assert currMove != Move.NULL_MOVE;
output.append((Move.toString(currMove)));
output.append(' ');
}
}
return output.toString();
}

public List<Integer> toPvList(int currPly) {
List<Integer> mv = new ArrayList<Integer>(pc.size());
if (currPly < pc.size()) {
for (int currMove : pc.get(currPly)) {
mv.add(currMove);
}
}
return null;
return mv;
}

void initialise(int currPly, int currMove) {
if (currPly < EubosEngineMain.SEARCH_DEPTH_IN_PLY) {
length[currPly] = 1;
pc[currPly][0] = currMove;
if (currPly < pc.size()) {
List<Integer> plyToUpdatePc = pc.get(currPly);
plyToUpdatePc.clear();
plyToUpdatePc.add(currMove);
}
}

// Bring down a pv from node further down the tree, with curr move added at the head
void update(int currPly, int currMove) {
if (currPly < EubosEngineMain.SEARCH_DEPTH_IN_PLY) {
length[currPly] = 1;
pc[currPly][0] = currMove;
if (currPly < pc.size()) {
List<Integer> plyToUpdatePc = pc.get(currPly);
plyToUpdatePc.clear();
plyToUpdatePc.add(currMove);
int nextPly = currPly+1;
if (nextPly < EubosEngineMain.SEARCH_DEPTH_IN_PLY) {
if (nextPly < pc.size()) {
// Bring down, if possible
for (int i=0; i<length[nextPly]; i++) {
pc[currPly][i+1] = pc[nextPly][i];
length[currPly] += 1;
}
plyToUpdatePc.addAll(pc.get(nextPly));
}
if (SearchDebugAgent.DEBUG_ENABLED) sda.printPrincipalContinuation(this);
}
}

// Update a principal continuation from a Transposition hit where we don't have onwards pv
void set(int currPly, int currMove) {
if (currPly < EubosEngineMain.SEARCH_DEPTH_IN_PLY) {
length[currPly] = 1;
pc[currPly][0] = currMove;
if (currPly < pc.size()) {
List<Integer> plyToUpdatePc = pc.get(currPly);
plyToUpdatePc.clear();
plyToUpdatePc.add(currMove);
clearContinuationBeyondPly(currPly);
if (SearchDebugAgent.DEBUG_ENABLED) sda.printPrincipalContinuation(this);
}
}

// Update a principal continuation from a Transposition hit where we do have an onwards pv
public void update(int currPly, List<Integer> onwards_pv) {
if (currPly < pc.size()) {
List<Integer> plyToUpdatePc = pc.get(currPly);
plyToUpdatePc.clear();
if (onwards_pv != null) {
plyToUpdatePc.addAll(onwards_pv);
}
clearContinuationBeyondPly(currPly);
}
}

// Clear all downstream pv's, from the current ply
void clearContinuationBeyondPly(int currPly) {
int nextPly = currPly+1;
if (nextPly < EubosEngineMain.SEARCH_DEPTH_IN_PLY) {
length[nextPly] = 0;
if (nextPly < pc.size()) {
pc.get(nextPly).clear();
}
}
}
2 changes: 1 addition & 1 deletion EubosChess/src/main/java/eubos/search/SearchMetrics.java
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ synchronized void setPrincipalVariationData(int extendedSearchDeepestPly, List<I
isScoreBackedUpFromSearch = true;
}

synchronized void setPrincipalVariationDataFromHash(int extendedSearchDeepestPly, short positionScore) {
synchronized void setPrincipalVariationDataFromHash(int extendedSearchDeepestPly, List<Integer> pc, short positionScore) {
setCpScore(positionScore);
this.cpScore = positionScore;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import eubos.board.Piece;
import eubos.main.EubosEngineMain;
Expand Down Expand Up @@ -90,8 +87,7 @@ public SearchResult findMove(
SearchMetricsReporter sr) {
boolean foundMate = false;
sm.setDepth(searchDepth);
List<Integer> list = Arrays.stream(pc.toPvList(0)).boxed().collect(Collectors.toList());
sm.setPrincipalVariation(list);
sm.setPrincipalVariation(pc.toPvList(0));
ps = new PlySearcher(tta, pc, sm, sr, searchDepth, pm, pos, pe, killers, sda, ml);
// Descend the plies in the search tree, to full depth, updating board and scoring positions
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@

import static org.junit.Assert.*;

import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import org.junit.Before;
import org.junit.Ignore;
Expand Down Expand Up @@ -37,7 +36,7 @@ public void test_update() throws IllegalNotationException {
classUnderTest.update(2, Move.valueOf(Position.d2, Piece.WHITE_PAWN, Position.d4, Piece.NONE ));
classUnderTest.update(1, Move.valueOf(Position.e7, Piece.BLACK_PAWN, Position.e5, Piece.NONE ));
classUnderTest.update(0, Move.valueOf(Position.a2, Piece.WHITE_PAWN, Position.a3, Piece.NONE ));
List<Integer> pv = Arrays.stream(classUnderTest.toPvList(0)).boxed().collect(Collectors.toList());
List<Integer> pv = classUnderTest.toPvList(0);
assertEquals(Move.valueOf(Position.a2, Piece.WHITE_PAWN, Position.a3, Piece.NONE ),(int) pv.get(0));
assertEquals(Move.valueOf(Position.e7, Piece.BLACK_PAWN, Position.e5, Piece.NONE ),(int) pv.get(1));
assertEquals(Move.valueOf(Position.d2, Piece.WHITE_PAWN, Position.d4, Piece.NONE ), (int)pv.get(2));
Expand All @@ -52,19 +51,33 @@ public void test_clearContinuationBeyondPly() throws IllegalNotationException {
classUnderTest.update(1, Move.valueOf(Position.e7, Piece.BLACK_PAWN, Position.e5, Piece.NONE ));
classUnderTest.update(0, Move.valueOf(Position.a2, Piece.WHITE_PAWN, Position.a3, Piece.NONE ));
classUnderTest.clearContinuationBeyondPly(1);
List<Integer> pv = Arrays.stream(classUnderTest.toPvList(0)).boxed().collect(Collectors.toList());
List<Integer> pv = classUnderTest.toPvList(0);
assertEquals(Move.valueOf(Position.a2, Piece.WHITE_PAWN, Position.a3, Piece.NONE ),(int) pv.get(0));
assertEquals(Move.valueOf(Position.e7, Piece.BLACK_PAWN, Position.e5, Piece.NONE ),(int) pv.get(1));
assertEquals(2, pv.size());
}

@Test
public void testToPvList_InitialState() {
List<Integer> pv = Arrays.stream(classUnderTest.toPvList(0)).boxed().collect(Collectors.toList());
List<Integer> pv = classUnderTest.toPvList(0);
assertTrue(pv != null);
assertTrue(pv.isEmpty());
}

@Test
public void testUpdateFromHashHit(){
List<Integer> source_pc = new ArrayList<Integer>();
source_pc.add(Move.valueOf(Position.e2, Piece.NONE, Position.e4, Piece.NONE ));
source_pc.add(Move.valueOf(Position.e7, Piece.NONE, Position.e5, Piece.NONE ));
source_pc.add(Move.valueOf(Position.d2, Piece.NONE, Position.d4, Piece.NONE ));
source_pc.add(Move.valueOf(Position.e5, Piece.NONE, Position.d4, Piece.NONE ));
classUnderTest.update(3, source_pc);
classUnderTest.update(2, Move.valueOf(Position.a7, Piece.NONE, Position.a6, Piece.NONE ));
List<Integer> updated_pc = classUnderTest.toPvList(2);
assertEquals(source_pc, updated_pc.subList(1, updated_pc.size()));
assertEquals((int)Move.valueOf(Position.a7, Piece.NONE, Position.a6, Piece.NONE ), (int)updated_pc.get(0));
}

@Test
@Ignore
public void testClearAfter() {
Expand All @@ -74,7 +87,7 @@ public void testClearAfter() {
@Test
public void testUpdateAtPly0WhenEnpty() {
classUnderTest.update(0, Move.valueOf(Position.e2, Piece.NONE, Position.e4, Piece.NONE ));
List<Integer> updated_pc = Arrays.stream(classUnderTest.toPvList(0)).boxed().collect(Collectors.toList());
List<Integer> updated_pc = classUnderTest.toPvList(0);
assertFalse(updated_pc.isEmpty());
assertEquals((int)Move.valueOf(Position.e2, Piece.NONE, Position.e4, Piece.NONE ), (int)updated_pc.get(0));
}
Expand Down

0 comments on commit 93e60a7

Please sign in to comment.