B* Probability Search (long)

Discussion of chess software programming and technical issues.

Moderator: Ras

Antonio Torrecillas
Posts: 92
Joined: Sun Nov 02, 2008 4:43 pm
Location: Madrid
Full name: Antonio Torrecillas

B* Probability Search (long)

Post by Antonio Torrecillas »

Sorry in advance for my spanglish and a so long first post.

I’m looking to do some try on B* Search. As I'm entering terra incognita some comment/advise are welcome.

Right now I have some code to mimic the point 3.6 A Search Example from the paper: “B* Probability Based Search” Hans Berliner, Chris McConnell 22 June 1995.

If somebody else is interested in, I publish this code “as is”. (Quick & dirty implementation) I think the tree code need complete rewrite...

If there is some interest in publish it as a companion code for the paper, say in CPW (Gerd?) feel free to point me the improvement/ correction /comment needed. I’ll rewrite it to get a smarter code for such an “official release”.

Code: Select all

// algebar.cpp : 
// Companion code for "B* probability based Search" -> 3.6 A Search Example
// Hans Berliner
// Chris McDonnell
// 22 June 1995
//


#include "stdio.h"
#include "assert.h"
#include "memory.h"

// 0 optval 1 realval
int Datos[22][2] = {
	{0,0},{100,20},{40,18},{25,10},{0,20},{40,60},
	{-80,80},{76,34},{36,12},{32,16},{0,80},{0,60},
	{0,50},{10,20},{15,30},{20,34},{0,55},{0,32},{0,20},
	{4,82},{11,70},{16,40}
};

#define INFINITY 99999
#define UNDEFINED 999

#define MAXNODES 0x100
#define MAXMOVES 0x100

#define PLAYER 0
#define OPPONENT 1

#define ROOTNODE 0

double MinAct = 0.15;
int TargetVal;
int BestMoveAtRoot;
int RealValBest;
int OptVal2ndBest;

typedef struct _nodes {
	int		depth;		// depth of this node related to root 0 = root ...
	int		OptVal;		//optimistic value of the node for the side-on-move
	int		RealVal;	//best estimate of the true value of the node
	int		PessVal;	//optimistic value for the side-not-on-move, backed up from its subtree
	double	OptPrb;		//probability that a certain target value can be achieved
//	int toMoves;		// 
	int ParentNode;
	int toNext;
	int MoveCount;
} NODE;

NODE nodes[MAXNODES];
int next[MAXMOVES];		// parent child1,child2..parent, child1,child2...

int FreeNode = 1;
int FreeMove = 1;
int TimeLimit = 1000;	// Time limit if needed

// rutinas que acceden a los datos
int GetOptVal(int i)
{
	assert(i > 0);
	assert(i < 22);
	// DoNullMove();
	// PVS(DEPTHEVAL,...);
	// UnDoNullMove();
	return Datos[i][0];
}

int GetRealVal(int i)
{
	assert(i > 0);
	assert(i < 22);
	// PVS(DEPTHEVAL,...);
	return Datos[i][1];
}

void Dumptree()
{
	int i;
	printf("Node Depth OptVal RealVal PessVal TargetVal OptPrb\n");
	printf("==================================================\n");
	for(i =1;i < FreeNode;i++)
	{
		printf("%c     %1d/%c   %3d     %3d    %3d      %3d      %.3lf\n",
			'A'+i-1,nodes[i].depth,
			nodes[i].ParentNode == 0 ? ' ': 'A'+ nodes[i].ParentNode-1,
			nodes[i].OptVal,nodes[i].RealVal,nodes[i].PessVal,
			TargetVal,	nodes[i].OptPrb 
		);
	}
	printf("==================================================\n");
	getchar();
}

// best for opponent -> minimize
int GetRealValBest(int n)
{
	int MaxValue,NumMoves,i,StartPos,pos,B;
	NumMoves = nodes[n].MoveCount;
	B = StartPos = nodes[n].toNext;
	MaxValue = INFINITY;
	for(i = 0; i < NumMoves;i++)
	{
		pos = next[StartPos+i];
		if(nodes[pos].RealVal < MaxValue)
		{
			MaxValue = nodes[pos].RealVal;
			B = StartPos+i;
		}
	}
	return B;
}
// Best for player -> maximize
int GetRealValBestVerify(int n)
{
	int MaxValue,NumMoves,i,StartPos,pos,B;
	NumMoves = nodes[n].MoveCount;
	B = StartPos = nodes[n].toNext;
	MaxValue = -INFINITY;
	for(i = 0; i < NumMoves;i++)
	{
		pos = next[StartPos+i];
		if(nodes[pos].RealVal > MaxValue)
		{
			MaxValue = nodes[pos].RealVal;
			B = StartPos+i;
		}
	}
	return B;
}
// max.
int GetRealValBestAtRoot()
{
	int MaxValue = -INFINITY;
	int NumMoves,i,StartPos,pos;
	StartPos = nodes[ROOTNODE].toNext;
	NumMoves = nodes[ROOTNODE].MoveCount;
	for(i = 0; i < NumMoves;i++)
	{
		pos = next[StartPos+i];
		if(nodes[pos].RealVal > MaxValue)
		{
			MaxValue = nodes[pos].RealVal;
			BestMoveAtRoot = StartPos+i;
		}
	}
	RealValBest = MaxValue;
	return MaxValue;
}

// Best OptVal but not BestAtRoot
int OptValAnyOtherMoveAtRoot()
{
	int MaxValue = -INFINITY;
	int NumMoves,i,StartPos,pos;
	NumMoves = nodes[ROOTNODE].MoveCount;
	StartPos = nodes[ROOTNODE].toNext;
	for(i = 0; i < NumMoves;i++)
	{
		pos = next[StartPos+i];
		if(nodes[pos].OptVal > MaxValue && StartPos+i != BestMoveAtRoot)
		{
			MaxValue = nodes[pos].OptVal;
		}
	}
	OptVal2ndBest = MaxValue;
	return MaxValue;
}

void RecalProb(int pos)
{
	nodes[pos].OptPrb = (nodes[pos].OptVal - TargetVal)*1.0/(nodes[pos].OptVal-nodes[pos].RealVal);
	if(nodes[pos].OptPrb  > 1.0)
		nodes[pos].OptPrb  = 1.0;
	if(nodes[pos].OptPrb  < 0.0)
		nodes[pos].OptPrb  = 0;
}

int GetBestOptPrb(int parent)
{
	int B;
	double MaxValue = 0.0;
	int NumMoves,i,StartPos,pos;
	NumMoves = nodes[parent].MoveCount;
	B = StartPos = nodes[parent].toNext;
	for(i = 0; i < NumMoves;i++)
	{
		pos = next[StartPos+i];
		RecalProb(pos);
		if(nodes[pos].OptPrb > MaxValue)
		{
			MaxValue = nodes[pos].OptPrb;
			B = StartPos+i;
		}
	}
	return B;
}
double GetBestChildOptPrb(NODE &parent)
{
	double MaxValue = 0.0;
	int NumMoves,i,StartPos,pos;
	NumMoves = parent.MoveCount;
	StartPos = parent.toNext;
	for(i = 0; i < NumMoves;i++)
	{
		pos = next[StartPos+i];
		if(nodes[pos].OptPrb > MaxValue)
		{
			MaxValue = nodes[pos].OptPrb;
		}
	}
	return MaxValue;
}

int GetBestOptPrbVerify(int parent)
{
	double MaxValue = 0.0;
	int NumMoves,i,StartPos,pos,B;
	NumMoves = nodes[parent].MoveCount;
	B = StartPos = nodes[parent].toNext;
	for(i = 0; i < NumMoves;i++)
	{
		pos = next[StartPos+i];
		if(nodes[pos].OptPrb > MaxValue)
		{
			MaxValue = nodes[pos].OptPrb;
			B = StartPos+i;
		}
	}
	return B;
}

double SecondRootOptPrb()
{
	double MaxValue = 0.0;
	int NumMoves,i,StartPos,pos;
	NumMoves = nodes[ROOTNODE].MoveCount;
	StartPos = nodes[ROOTNODE].toNext;
	for(i = 0; i < NumMoves;i++)
	{
		pos = next[StartPos+i];
		RecalProb(pos);
		if(nodes[pos].OptPrb > MaxValue && pos != BestMoveAtRoot)
		{
			MaxValue = nodes[pos].OptPrb;
		}
	}
	return MaxValue ;
}
//			Trace down the child subtree selecting
//			For Player-to-Move nodes, child with largest OptPrb
//			For Opponent-to-Move nodes, child with best RealVal
//			Until arriving at a leaf node;
int TraceDown(int a)
{
	int SelectedNode,m;

	SelectedNode = next[a];
	while( nodes[SelectedNode].toNext != 0)
	{
		if((nodes[SelectedNode].depth%2) == 1)
		{
			m = GetBestOptPrb(SelectedNode);
			SelectedNode = next[m];
		}
		else
		{
			m = GetRealValBest(SelectedNode);
			SelectedNode = next[m];
		}
	}
	return SelectedNode;
}

//			Trace down the child subtree selecting
//			For Opponent-to-Move nodes, child with largest OptPrb
//			For Player-to-Move nodes, child with best RealVal
//			Until arriving at a leaf node;

int TraceDownVerify(int a)
{
	int SelectedNode,m;
	SelectedNode = next[a];
	while( nodes[SelectedNode].toNext != 0)
	{
		if((nodes[SelectedNode].depth%2) == 0)
		{
			m = GetBestOptPrbVerify(SelectedNode);
			SelectedNode = next[m];
		}
		else
		{
			m = GetRealValBestVerify(SelectedNode);
			SelectedNode = next[m];
		}
	}
	return SelectedNode;
}
void CalcVerifPrb(NODE &nodo)
{
	if(nodo.depth == 0)
	{
		nodo.OptPrb = 0.999;
		return;
	}
	if(TargetVal >= nodo.RealVal)
		nodo.OptPrb = 1.0;
	else
	{
		if(nodo.OptVal > TargetVal && nodo.RealVal >nodo.OptVal)
			nodo.OptPrb = 0.0;
		else
		{
			if(nodo.RealVal >nodo.OptVal)
			{
				nodo.OptPrb = (1.0*(TargetVal - nodo.OptVal ))/(nodo.RealVal - nodo.OptVal);
			}
			else
			{
				nodo.OptPrb = (1.0*(TargetVal - nodo.PessVal  ))/(nodo.RealVal - nodo.PessVal);
			}
		}
	}
	if(nodo.OptPrb > 1.0)
		nodo.OptPrb = 1.0;
	if(nodo.OptPrb < 0.0)
		nodo.OptPrb = 0.0;
}

//			Get RealVal for each Child Node of this leaf;
//			If it is a Player-to-Move node get OptVals for each Child;
void Expand(int SelectedNode,int modo)
{
	int nodo,EvalOpt;
	int NumMoves = 3;//= T.GeneraJugadas(pMoves);
	nodes[SelectedNode].MoveCount = NumMoves;
	nodes[SelectedNode].toNext = FreeMove;
	EvalOpt = ((nodes[SelectedNode].depth+1) %2 ) == modo;
	for(int i = 0;i < NumMoves;i++)
	{
//		DoMove();
		// reservamos un nodo por cada Jugada
		// Reserve a node for each move
		nodo = next[FreeMove+i] = FreeNode++;
		// Calculamos el valor real y el optimista.
		// Get Real and optimistic value.
		nodes[nodo].RealVal = GetRealVal(nodo);
		nodes[nodo].depth = nodes[SelectedNode].depth + 1;
		nodes[nodo].OptVal = UNDEFINED;
		nodes[nodo].PessVal = nodes[SelectedNode].OptVal;
		nodes[nodo].ParentNode = SelectedNode;
		if(EvalOpt)
			nodes[nodo].OptVal = GetOptVal(nodo);
		else
			if(modo == OPPONENT)
				nodes[nodo].OptVal = nodes[SelectedNode].PessVal ;
	}
	FreeMove += NumMoves;
}

void CalcVerifPrbP(int parent)
{
	int NumMoves,StartPos,pos,i;
	NumMoves = nodes[parent].MoveCount;
	StartPos = nodes[parent].toNext;
	for(i = 0; i < NumMoves;i++)
	{
		pos = next[StartPos+i];
		CalcVerifPrb(nodes[pos]);
	}
}

double Product(NODE &parent,int modo)
{
	double product = 1.0;
	// calculate OptPrb for child nodes
	int NumMoves,StartPos,pos,i;
	NumMoves = parent.MoveCount;
	StartPos = parent.toNext;
	for(i = 0; i < NumMoves;i++)
	{
		pos = next[StartPos+i];
		if(modo == 0)
			nodes[pos].OptPrb = (nodes[pos].PessVal  - TargetVal)*1.0/(nodes[pos].PessVal -nodes[pos].RealVal);
		else
			if(nodes[pos].toNext == 0)
				CalcVerifPrb(nodes[pos]);
		if(nodes[pos].OptPrb  > 1.0)
			nodes[pos].OptPrb  = 1.0;
		if(nodes[pos].OptPrb  < 0.0)
			nodes[pos].OptPrb  = 0;
		product *= nodes[pos].OptPrb;
	}
	return product;
}

void Propagate1(NODE &nodo,NODE &parent,int mode)
{
	if(mode == PLAYER)
	{
		if((nodo.depth % 2) == 1)
		{
			parent.OptVal = nodo.PessVal;
			parent.OptPrb = Product(parent,0);
		}
		else
		{
			parent.PessVal = nodo.OptVal;
			parent.OptPrb = GetBestChildOptPrb(parent);
		}
		parent.RealVal = nodo.RealVal;
	}
	else
	{
		if((nodo.depth % 2) == 0)
		{
			parent.OptVal = nodo.PessVal;
			parent.OptPrb = Product(parent,1);
		}
		else
		{
			if(nodo.OptPrb == 0)
			{   // calcular OptPrb
				CalcVerifPrbP(nodo.ParentNode);
			}   // Get the best Prb.
			parent.PessVal = nodo.OptVal;
			parent.OptPrb = GetBestChildOptPrb(parent);
		}
	}
}

void PropagatePrb1(NODE &nodo,NODE &parent)
{
	if((nodo.depth % 2) == 1)
		parent.OptPrb = Product(parent,0);
	else
		parent.OptPrb = GetBestChildOptPrb(parent);
}

void Backup(int mode,int node)
{
	while(nodes[node].ParentNode)
	{
		Propagate1(nodes[node],nodes[nodes[node].ParentNode],mode);
		node = nodes[node].ParentNode;
	}
}

void BackupPrb(int node)
{
	while(nodes[node].ParentNode)
	{
		PropagatePrb1(nodes[node],nodes[nodes[node].ParentNode]);
		node = nodes[node].ParentNode;
	}
}

int RealVal2ndBstMoveAtRoot()
{
	int Val2Max = -INFINITY;
	int NumMoves,i,StartPos,pos;
	NumMoves = nodes[ROOTNODE].MoveCount;
	StartPos = nodes[ROOTNODE].toNext;
	for(i = 0; i < NumMoves;i++)
	{
		pos = next[StartPos+i];
		if(nodes[pos].RealVal > Val2Max && pos != BestMoveAtRoot)
			Val2Max = nodes[pos].RealVal;
	}
	return Val2Max;
}

void PropagateDown(int parent)
{
	int NumMoves,i,StartPos,pos;
	NumMoves = nodes[parent].MoveCount;
	StartPos = nodes[parent].toNext;
	for(i = 0; i < NumMoves;i++)
	{
		pos = next[StartPos+i];
		nodes[pos].PessVal = nodes[parent].OptVal;
	}
}

// Compute OptVal for all Opp nodes and calc OptPrb
void VerifyInit()
{
	int i;
	for(i = 1; i < FreeNode;i++)
	{
		if((nodes[i].depth %2) == 1)
		{
			nodes[i].OptVal = GetOptVal(i);
			// propagate to children Press
			PropagateDown(i);
		}
		CalcVerifPrb(nodes[i]);
	}
}

int IsOver(int a)
{
	int NumMoves,i,StartPos,pos;
	// see if all children < MinAct
	int SelectedNode = next[a];
	NumMoves = nodes[SelectedNode].MoveCount;
	StartPos = nodes[SelectedNode].toNext;
	for(i = 0; i < NumMoves;i++)
	{
		pos = next[StartPos+i];
		if(nodes[pos].OptPrb > MinAct)
			return 0; // still thing to look at
	}
	return 1;	// game over
}

long GetMicroTime(){	return 0; } // time do not elapse on this demo ;-) ... 

void BStar()
{
	int a;
	long ini = GetMicroTime();
	for(;;)
	{
		printf("SELECT Step\n");
		while (GetRealValBestAtRoot() < OptValAnyOtherMoveAtRoot())
		{
			TargetVal = (OptVal2ndBest+RealValBest)/2;
//			Select Root Node with greatest OptPrb;
			a = GetBestOptPrb(ROOTNODE);
//			Trace down the child subtree selecting
//			For Player-to-Move nodes, child with largest OptPrb
//			For Opponent-to-Move nodes, child with best RealVal
//			Until arriving at a leaf node;
			int SelectedNode = TraceDown(a);
			Dumptree();	
			if(SecondRootOptPrb() < MinAct)
				break;
			printf("Selected node %c\n",'A'+SelectedNode-1);
//			Get RealVal for each Child Node of this leaf;
//			If it is a Player-to-Move node get OptVals for each Child;
			Expand(SelectedNode,PLAYER);
			// search path down to new expanded
			a = TraceDown(a);
//			Back up Values;
			Backup(PLAYER,a);
			// calculate new TargetVal
			TargetVal = (nodes[BestMoveAtRoot].RealVal +OptValAnyOtherMoveAtRoot())/2;
			// BackUp OptPrb
			BackupPrb(a);
			if ((GetMicroTime()-ini) >= TimeLimit) break; // EffortLimitsExceeded
		}
		printf("End od Select step\n");
		TargetVal = RealVal2ndBstMoveAtRoot() - 1;
		printf("VERIFY Step\n");
		VerifyInit();
		while(GetRealValBestAtRoot() >= TargetVal)
		{
//			Select Reply Node with greatest OptPrb;
//			a = GetBestOptPrb(ROOTNODE,OPPONENT);
//			Select reply Node with Greatest RealVal
			a = BestMoveAtRoot;
//			Trace down the child subtree selecting
//			For Opponent-to-Move nodes, child with largest OptPrb
//			For Player-to-Move nodes, child with best RealVal
//			Until arriving at a leaf node;
			int SelectedNode = TraceDownVerify(a);
			Dumptree();
			if(IsOver(a))
				return;	// Solved
			printf("Selected node %c\n",'A'+SelectedNode-1);
//			Get RealVal for each Child Node of this leaf;
//			If it is an Opponent-to-Move node get OptVals for each Child;
			Expand(SelectedNode,OPPONENT);
			a = TraceDownVerify(a); // Search leaf node 
			Backup(OPPONENT,a);			    // and Back up Values;
			if ((GetMicroTime()-ini) >= TimeLimit) return; // EffortLimitsExceeded
		}
	}
}

void LaunchBStar()
{
	printf("expand root\n");
	nodes[ROOTNODE].depth = -1;
	Expand(ROOTNODE,PLAYER);
	BStar();
}

int main(int argc, char* argv[])
{
	LaunchBStar();
	return 0;
}
Gerd Isenberg
Posts: 2251
Joined: Wed Mar 08, 2006 8:47 pm
Location: Hattingen, Germany

Re: B* Probability Search (long)

Post by Gerd Isenberg »

Antonio Torrecillas wrote:Sorry in advance for my spanglish and a so long first post.

I’m looking to do some try on B* Search. As I'm entering terra incognita some comment/advise are welcome.

Right now I have some code to mimic the point 3.6 A Search Example from the paper: “B* Probability Based Search” Hans Berliner, Chris McConnell 22 June 1995.

If somebody else is interested in, I publish this code “as is”. (Quick & dirty implementation) I think the tree code need complete rewrite...

If there is some interest in publish it as a companion code for the paper, say in CPW (Gerd?) feel free to point me the improvement/ correction /comment needed. I’ll rewrite it to get a smarter code for such an “official release”.
Hi Antonio,

I had some swift reads of the Berliner McConnell paper, and I have to admit, to only have a vague understanding on how B* works so far. So your code is interesting and appreciated and may help me (and others) to better understand how it works and to make own experience.

It would be great to write something about B* based on your code in CPW.

Btw. your spanglish seems better than my denglish - i can only survive with online translators and spell checkers ;-)

Cheers,
Gerd
Harald Johnsen

Re: B* Probability Search (long)

Post by Harald Johnsen »

It compiles and runs fine, thank Antonio.

I'll play with exotic search once I have a stable engine. I need to try pn search too.

HJ.
Antonio Torrecillas
Posts: 92
Joined: Sun Nov 02, 2008 4:43 pm
Location: Madrid
Full name: Antonio Torrecillas

Re: B* Probability Search (long)

Post by Antonio Torrecillas »

Gerd Isenberg wrote:
It would be great to write something about B* based on your code in CPW.
Hi Gerd,
I'll put my two cents on CPW about B* but as i'm not a "connaisseur" don't expext too much...
I started with this, reading, then coding a bit to try to understand, and ended with 600 lines of code.
This paper is referenced offen but nobody seems to have repeated/used this algorithm. Sound like there is a general mystic believe on them. Or it is just trust on the author.

As I progress I'll inform off issues and goodies, if any.

Antonio.
Antonio Torrecillas
Posts: 92
Joined: Sun Nov 02, 2008 4:43 pm
Location: Madrid
Full name: Antonio Torrecillas

First results with B* (WAC Test)

Post by Antonio Torrecillas »

First the performance with PVS, just to get a point of comparison for the search.
Engine with iterative deepening PVS, cache, futility ,razoring, null move R=3 and LMR.

Reference PVS
Depth Results
1 -> 69
2 -> 99
3 -> 139
4 -> 187
5 -> 211
6 -> 241
7 -> 260
8 -> 272
9 -> 282
10 -> 289
11 -> 294

B* without time limit, node expand limits 500 select phase + 500 verify phase, all ending search criteria was disabled.

Probe Depth Results
1 -> 154
2 -> 222
3 -> 244
4 -> 251

The engine go useless deep, more time/nodes beyond a threshold does not improve results.
Lets go brute...

B* with dithering formula: OptPrb Corrected = OptPrb /(1 + subtree size)
0 -> 216
1 -> 256
2 -> 268
3 -> 274

Multiple Select+Verify phases (40+10 nodes slice)
Probe depth
0 -> 228
1 -> 262
2 -> 260
3 -> 276

Adding separation criteria MinAct = 0.15
OptVal correction formula: Mate in X threat = 1000 – 75 * X (instead of 30000 – X)
As there is a target value defined as an average between a real value and a OptVal, a Mate in X and a Mate in X+1 goes to the same average value, but a Mate in X is far bigger threat than a Mate in X+1. That what I try to correct.
The formula above need revision as a +800 evaluation is not impossible...and a Mate must be far bigger...
The final shape of the evaluation need some additional work...to be continued...
The second correction is the bias introduced by the null move, a small threat is not really a threat.
if( abs(RealVal – OptVal) < NULLMOVEBIAS)
OptVal = RealVal;

Depth Result
0 -> 222
1 -> 269
2 -> 272
3 -> 281

That's all for now
Dann Corbit
Posts: 12781
Joined: Wed Mar 08, 2006 8:57 pm
Location: Redmond, WA USA

Re: B* Probability Search (long)

Post by Dann Corbit »

Gerd Isenberg wrote:
Antonio Torrecillas wrote:Sorry in advance for my spanglish and a so long first post.

I’m looking to do some try on B* Search. As I'm entering terra incognita some comment/advise are welcome.

Right now I have some code to mimic the point 3.6 A Search Example from the paper: “B* Probability Based Search” Hans Berliner, Chris McConnell 22 June 1995.

If somebody else is interested in, I publish this code “as is”. (Quick & dirty implementation) I think the tree code need complete rewrite...

If there is some interest in publish it as a companion code for the paper, say in CPW (Gerd?) feel free to point me the improvement/ correction /comment needed. I’ll rewrite it to get a smarter code for such an “official release”.
Hi Antonio,

I had some swift reads of the Berliner McConnell paper, and I have to admit, to only have a vague understanding on how B* works so far. So your code is interesting and appreciated and may help me (and others) to better understand how it works and to make own experience.

It would be great to write something about B* based on your code in CPW.

Btw. your spanglish seems better than my denglish - i can only survive with online translators and spell checkers ;-)

Cheers,
Gerd
Here is a flow chart of B*:
http://books.google.com/books?id=uBkOAA ... #PPA191,M1
Antonio Torrecillas
Posts: 92
Joined: Sun Nov 02, 2008 4:43 pm
Location: Madrid
Full name: Antonio Torrecillas

Re: B* Probability Search (long)

Post by Antonio Torrecillas »

Thanks Dann.
Just to complete the picture, here is an example of a searched tree:

Code: Select all

Probe depth 3, Select Nodes Limit 40, Verify Nodes limit 10
Time used 9906 Nodes Expanded 137
Root 8/7p/5k2/5p2/p1p2P2/Pr1pPK2/1P1R3P/8 b - - bm Rxb2; id "WAC.002"

       +---+---+---+---+---+---+---+---+
    8  | . |   | . |   | . |   | . |   |
       +---+---+---+---+---+---+---+---+
    7  |   | . |   | . |   | . |   |-P-|
       +---+---+---+---+---+---+---+---+
    6  | . |   | . |   | . |-R-| . |   |
       +---+---+---+---+---+---+---+---+
    5  |   | . |   | . |   |-P-|   | . |
       +---+---+---+---+---+---+---+---+
    4  |-P-|   |-P-|   | . |<P>| . |   |
       +---+---+---+---+---+---+---+---+
    3  |<P>|-T-|   |-P-|<P>|<R>|   | . |
       +---+---+---+---+---+---+---+---+
    2  | . |<P>| . |<T>| . |   | . |<P>|
       +---+---+---+---+---+---+---+---+
    1  |   | . |   | . |   | . |   | . |
       +---+---+---+---+---+---+---+---+
         a   b   c   d   e   f   g   h


Selected move b3b2

Root Node Value:      -253 Opt 286 Pess -415 Prb 0.957
      b3c3 b2c3 551 Opt 523 Pess 523 Prb 0.000
                h7h6 d2b2 565 Opt 338 Pess 532 Prb 0.000
                f6e7 551 Opt 530 Pess 9999999 Prb 0.000
      c4c3 b2c3 -159 Opt -658 Pess -268 Prb 0.073
                b3b2 d2b2 838 Opt 962 Pess 750 Prb 0.000
                          d3d2 b2d2 962 Opt 962 Pess 962 Prb 0.000
                                    h7h6 d2d6 987 Opt 963 Pess 963 Prb 0.000
                                    f6e7 962 Opt 962 Pess 9999999 Prb 0.000
                          f6e6 838 Opt 750 Pess 9999999 Prb 0.000
                h7h6 d2d3 b3a3 e3e4 122 Opt 963 Pess 73 Prb 0.000
                h7h5 d2d3 b3a3 102 Opt 63 Pess 9999999 Prb 0.000
                f6e6 d2d3 b3a3 e3e4 89 Opt 963 Pess 37 Prb 0.000
                b3a3 d2d3 85 Opt -658 Pess -658 Prb 0.536
                          a3a1 d3d6 139 Opt 286 Pess 61 Prb 0.000
                          f6e6 85 Opt 37 Pess 9999999 Prb 0.000
                b3c3 d2b2 c3a3 b2b6 -159 Opt -240 Pess -240 Prb 0.000
                                    f6f7 b6b7 -150 Opt 286 Pess -232 Prb 0.000
                                    f6e7 b6b7 -159 Opt 286 Pess -226 Prb 0.000
      b3b2 d2b2 -253 Opt 105 Pess -415 Prb 0.957
                d3d2 b2d2 642 Opt 105 Pess 105 Prb 0.000
                          c4c3 d2d6 732 Opt 338 Pess 105 Prb 0.000
                          f6e6 642 Opt 642 Pess 9999999 Prb 0.000
                c4c3 -253 Opt -415 Pess 338 Prb 0.957
                     b2b6 f6e7 -253 Opt -415 Pess 338 Prb 0.957
                               b6b7 -253 Opt 338 Pess -415 Prb 0.957
                                    e7e6 0 Opt -415 Pess 338 Prb 0.373
                                         b7b6 0 Opt 286 Pess -415 Prb 0.241
                                              e6d5 b6b5 285 Opt 338 Pess -1053 Prb 0.593
                                                        d5e6 b5b6 373 Opt 338 Pess -437 Prb 0.000
                                                        d5c6 b5f5 371 Opt 338 Pess -1111 Prb 0.574
                                                                  d3d2 f3e2 532 Opt 338 Pess -1111 Prb 0.000
                                                                  c3c2 371 Opt -481 Pess 338 Prb 0.259
                                                        d5d6 b5b6 285 Opt 338 Pess -415 Prb 0.000
                                                        d5c4 285 Opt -1053 Pess 338 Prb 0.593
                                                             b5b4 285 Opt 338 Pess -1053 Prb 0.000
                                                             b5f5 0 Opt 338 Pess -1274 Prb 0.796
                                                                  d3d2 f3e2 453 Opt 338 Pess -1274 Prb 0.000
                                                                  c3c2 f5f8 0 Opt 338 Pess -868 Prb 0.000
                                              e6d7 228 Opt -415 Pess 286 Prb 0.241
                                                   b6b5 228 Opt 286 Pess -1053 Prb 0.569
                                                        d7c6 b5f5 371 Opt 286 Pess -1053 Prb 0.557
                                                        c3c2 228 Opt -481 Pess 286 Prb 0.312
                                                   b6b7 0 Opt -2056 Pess -1036 Prb 0.595
                                                        d7c8 b7b1 c3c2 b1c1 279 Opt 286 Pess -2056 Prb 0.769
                                                        d7c6 268 Opt -1036 Pess -1025 Prb 0.595
                                                             b7b8 c3c2 268 Opt -490 Pess 9999999 Prb 0.303
                                                             b7b1 d3d2 -108 Opt -1010 Pess 9999999 Prb 0.831
                                                        d7e6 0 Opt 0 Pess 9999999 Prb 0.000
                                                   b6b4 c3c2 -303 Opt -415 Pess 9999999 Prb 1.000
                                              e6e7 0 Opt 0 Pess 9999999 Prb 0.000
                                         b7c7 -265 Opt -1050 Pess -1050 Prb 1.000
                                              e6d6 c7c3 724 Opt 338 Pess -1050 Prb 0.445
                                              d3d2 f3e2 698 Opt 338 Pess -1030 Prb 0.000
                                              c3c2 e3e4 -265 Opt 338 Pess -441 Prb 0.000
                                         f3f2 c3c2 -422 Opt -625 Pess 9999999 Prb 1.000
                                         f3g2 c3c2 -430 Opt -636 Pess 338 Prb 1.000
                                    e7d6 -253 Opt -415 Pess 338 Prb 0.957
                                         b7b6 -253 Opt -1036 Pess -1045 Prb 0.991
                                              d6d5 b6b5 285 Opt -1053 Pess -1053 Prb 0.578
                                                        d5c6 b5f5 371 Opt 9999999 Pess -1053 Prb 0.557
                                                        d5d6 285 Opt -415 Pess 9999999 Prb 0.221
                                              d6d7 b6b7 d7c6 284 Opt -1036 Pess 9999999 Prb 0.588
                                              d6c5 240 Opt -1045 Pess 338 Prb 0.611
                                                   b6e6 c3c2 240 Opt -673 Pess 338 Prb 0.452
                                                   b6b8 c3c2 240 Opt -380 Pess 338 Prb 0.194
                                                   b6a6 0 Opt 338 Pess -1295 Prb 0.613
                                                        d3d2 f3e2 393 Opt 338 Pess -1295 Prb 0.000
                                                        c5b5 a6a8 253 Opt 338 Pess -1020 Prb 0.000
                                                        c3c2 a6a8 0 Opt 338 Pess -619 Prb 0.000
                                                   b6b1 d3d2 -117 Opt -746 Pess 9999999 Prb 0.773
                                              d6c7 -253 Opt -1045 Pess 338 Prb 0.991
                                                   b6b1 -253 Opt 338 Pess -2075 Prb 0.996
                                                        d3d2 b1d1 c7b6 127 Opt -393 Pess 338 Prb 0.256
                                                        c3c2 -253 Opt -2075 Pess 338 Prb 0.996
                                                             b1c1 c7d6 -253 Opt -447 Pess 338 Prb 0.964
                                                             b1g1 d3d2 -608 Opt -1159 Pess 338 Prb 1.000
                                                             b1h1 d3d2 -642 Opt -1159 Pess 338 Prb 1.000
                                                   b6b4 c3c2 -253 Opt -740 Pess 338 Prb 0.986
                                                   b6f6 c3c2 -389 Opt -602 Pess 338 Prb 1.000
                                                   b6b5 c3c2 -395 Opt -602 Pess 338 Prb 1.000
                                         b7b4 c3c2 -303 Opt -415 Pess 338 Prb 1.000
                                         b7a7 c3c2 -303 Opt -520 Pess 338 Prb 1.000
                                         b7b8 -401 Opt 338 Pess -1034 Prb 1.000
                                              d3d2 f3e2 396 Opt 338 Pess -1034 Prb 0.000
                                              d6c7 b8b1 286 Opt 338 Pess -1017 Prb 0.581
                                              c3c2 b8d8 -401 Opt 338 Pess -490 Prb 0.000
                                         b7f7 c3c2 -409 Opt -635 Pess 338 Prb 1.000
                                         h2h3 c3c2 -416 Opt -622 Pess 338 Prb 1.000
                                         f3f2 c3c2 -424 Opt -630 Pess 338 Prb 1.000
                               b6a6 c3c2 -303 Opt -512 Pess 338 Prb 1.000
                               b6c6 -319 Opt -1058 Pess -1058 Prb 1.000
                                    e7d7 c6c3 724 Opt 338 Pess -1058 Prb 0.448
                                    d3d2 f3e2 706 Opt 338 Pess -1027 Prb 0.000
                                    c3c2 f3f2 -319 Opt 338 Pess -437 Prb 0.000
                               e3e4 c3c2 -405 Opt -554 Pess 9999999 Prb 1.000
                               f3g2 c3c2 -422 Opt -632 Pess 9999999 Prb 1.000
                     b2b5 -382 Opt 338 Pess -566 Prb 1.000
                          f6e6 b5b6 373 Opt 963 Pess -437 Prb 0.000
                          c3c2 -382 Opt -566 Pess 338 Prb 1.000
                               b5d5 -382 Opt 338 Pess -566 Prb 0.000
                               h2h3 d3d2 -623 Opt -1549 Pess 338 Prb 1.000
                               f3f2 c2c1q -630 Opt -926 Pess 338 Prb 1.000
                     b2b8 -382 Opt -437 Pess -566 Prb 1.000
                          f6e6 b8b6 373 Opt 963 Pess -415 Prb 0.000
                          f6e7 b8b7 e7d6 285 Opt -415 Pess 9999999 Prb 0.221
                          c3c2 -382 Opt -566 Pess 338 Prb 1.000
                               b8d8 -382 Opt 338 Pess -566 Prb 0.000
                               b8a8 c2c1q -520 Opt -1255 Pess 338 Prb 1.000
                               h2h4 c2c1q -618 Opt -1031 Pess 338 Prb 1.000
                               h2h3 d3d2 -623 Opt -1563 Pess 338 Prb 1.000
                               f3f2 c2c1q -630 Opt -874 Pess 338 Prb 1.000
                               f3g2 c2c1q -640 Opt -874 Pess 338 Prb 1.000
                     b2b7 c3c2 b7d7 -407 Opt 963 Pess -566 Prb 0.000
                     b2b4 -407 Opt 338 Pess -566 Prb 1.000
                          f6e6 b4b6 373 Opt 963 Pess -415 Prb 0.000
                          f6e7 b4b7 356 Opt 963 Pess -407 Prb 0.000
                          c3c2 -407 Opt -566 Pess 338 Prb 1.000
                               b4d4 -407 Opt 338 Pess -566 Prb 0.000
                               h2h3 c2c1q -622 Opt -1030 Pess 338 Prb 1.000
                               f3f2 c2c1q -630 Opt -928 Pess 338 Prb 1.000
                               f3g2 c2c1q -640 Opt -928 Pess 338 Prb 1.000
                     b2b1 c3c2 -426 Opt -1351 Pess 9999999 Prb 1.000
Even though B* will not be competitive, maybe as an analysis tool.
:)
diep
Posts: 1822
Joined: Thu Mar 09, 2006 11:54 pm
Location: The Netherlands

Re: B* Probability Search (long)

Post by diep »

Hi,

non-brute force searching attempts are very interesting to do. I did do a B* attempt using CNS-I (conspiracy number search - must be appealing name to most people here).

Things i stumbled upon:

a) when giving emails to others who tried CNS and/or invented different forms of it (CNS-2) like Ulf Lorenz, i got 0 replies back. I just wanted to compare how diep using CNS search did do versus P.Conners, for example. There is just 0 communication with university researchers. They keep results for themselves (same thing with parallel speedups at supercomputers, yet i can explain why you get back 0 data there, whereas my logfiles at supercomputer i consider public so if you request 'em you get them by returning email).

It is very difficult to be busy with a non-brute force searcher if you can't compare with anyone.

b) Nullmove is a big winner algorithm and CAN get used in CNS. Idemdito in other non-brute force searching attempts. A nullmove simply gives a high confidence level that a path is no good to explore further. This really speeded up my CNS attempt

c) it is very complicated to get an accurate mainline, yes even the best move is very complicated to get. I tend to remember P.Conners wanted 2 different lines with each line above a certain bound in order to call something its mainline. That was quite expensive when i tried, as changing the search window is simply really expensive and it also has the big problem of that you lose significance in your evaluation function. There is really no alternative sometimes other than to recapture a piece that was captured by your opponent.

If you expand a node somewhere in the tree, that INSTANTLY has an effect at which move you pick in the root now, the score of the mainline and what the mainline is.

d) Most disappointing is the fact that you really burn a lot of nodes to hopeless lines where in brute force search you simply get a cutoff.
If a line is silly and far away from our root window, yes even if it is 0.2 pawn, i want to give a cutoff. Yet as we have each time a flipping mainline and score belonging to it, we burn a lot of extra nodes

e) total search depth is disappointing. It is true that forced lines you can see right to the end and instantly. Great for specific tricks. Of course i started testing simple tricks first.

A trick that Diep finds with CNS without burning a lot of nodes is Rxc5 from the Larsen100 testset. Brute force it burns up really a lot more nodes.

3r1rk1/1pq1nppp/p7/2pB3Q/P4P2/1P2P3/6PP/2RR2K1 w - - bm Rxc5; id "GMG1.092";
c1c5

Yet this was the only 'victory' i could speak about.
All kind of other tricks, real simple ones, were really complicated to find, despite burning way more nodes.

f) memory management is expensive. I used a memory buffer of 400MB, lotta RAM for those days for a single processor. brute force search is much easier. For CNS i had implemented a big tree concept WITH transpositions.
Maintaining that is not so easy. My solution was a stupid one, just to experiment with it, i simply searched until the RAM was completely filled.
then search stopped.

Now as a replacement scheme that is NOT very clever.

All this slows down search bigtime.

A few years ago i didn't find that very acceptable.

It is here where brute force total annihilates all other forms of search most. The combination of more overhead into silly nodes with more efficient search is deadly.

Selectivity you can get in brute force search by forward pruning, reductions and extensions. That's much easier than doing everything in a non-brute force manner.

Amazingly now if you go play games with it, you will typically see that you aren't gonna lose many games based upon missing tactics. It is relative easy to avoid MISSING tactics.

The real problem what loses you game after game is the idiocy that happens around your mainline. It keeps nonstop doubting and changing its mainline. That is really BAD.

This where in a brute force search, the search really corrects diep's bad tuned eval (note i'm busy with a big project with Renze Steenhuisen to improve its tuning a tad at a processor or 40, that will weed out hopefully some historic idiocy from 10+ years ago in diep's eval).

This is however not true for all evaluations. In ancient times, search was simply not needed for fine grained positional corrections. You can see that in rybka also. If you have a real well tuned evaluatoin function, you can risk doing dubious hard forward pruning last 7 ply or so.

That is very complicated as soon as you already add mobility in the way Diep is doing it. Evaluation doubts more. Search IS needed to correct it bigtime last few plies especially.

All this happens in brute force, and alternatives to it, that correction doesn't happen. That is a BIG eloloss.

That aside from that it wasn't capable of finding some trivial tactics which no brute force search misses.

There is ways around finding tactics i tend to believe. Some clever extension here or there. There is no way to compensate for positional eloloss.

Vincent
Antonio Torrecillas
Posts: 92
Joined: Sun Nov 02, 2008 4:43 pm
Location: Madrid
Full name: Antonio Torrecillas

Re: B* Probability Search (long)

Post by Antonio Torrecillas »

Hi Vincent, thanks for your answer,
My experience till now with the algorithm is different , maybe we are speaking about different things. I use B* on top of a standard alpha-beta/PVS search in the same way as quiesce is used in alpha-beta.
Null move in B* probability search is not used as a pruning method, but as a threat detector.
The main line looks pretty stable but as I just do tactical tests...
Memory management is not an issue here...For GMG1.092 you need to expand 1386 nodes with a probe depth of 3, 111 nodes with a probe depth of 4 and just 34 expands with a probe depth = 5.

The big slow down is the cost for each expand. Each nodes are evaluated with a PVS(probe_depth) as real value, and a second PVS(probe_depth) as optimistic evaluation. Two open window search for each node.

The results I have are also mixed, a few simple problems aren't found and other complexes are.To say something, with probe search = 3 you miss tactics in 5 but you find Wac.002 (12-13 ply for my engine).

I'm still debugging the thing but I don't expect it to be competitive.

A+, Antonio.
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: B* Probability Search (long)

Post by bob »

diep wrote:Hi,

non-brute force searching attempts are very interesting to do. I did do a B* attempt using CNS-I (conspiracy number search - must be appealing name to most people here).

Things i stumbled upon:

a) when giving emails to others who tried CNS and/or invented different forms of it (CNS-2) like Ulf Lorenz, i got 0 replies back. I just wanted to compare how diep using CNS search did do versus P.Conners, for example. There is just 0 communication with university researchers. They keep results for themselves (same thing with parallel speedups at supercomputers, yet i can explain why you get back 0 data there, whereas my logfiles at supercomputer i consider public so if you request 'em you get them by returning email).
Just to be clear, not _all_ university researchers keep results to themselves. I publish everything I do, both here and in the ICGA (among other places). Others do so also.


It is very difficult to be busy with a non-brute force searcher if you can't compare with anyone.

b) Nullmove is a big winner algorithm and CAN get used in CNS. Idemdito in other non-brute force searching attempts. A nullmove simply gives a high confidence level that a path is no good to explore further. This really speeded up my CNS attempt

c) it is very complicated to get an accurate mainline, yes even the best move is very complicated to get. I tend to remember P.Conners wanted 2 different lines with each line above a certain bound in order to call something its mainline. That was quite expensive when i tried, as changing the search window is simply really expensive and it also has the big problem of that you lose significance in your evaluation function. There is really no alternative sometimes other than to recapture a piece that was captured by your opponent.

If you expand a node somewhere in the tree, that INSTANTLY has an effect at which move you pick in the root now, the score of the mainline and what the mainline is.

d) Most disappointing is the fact that you really burn a lot of nodes to hopeless lines where in brute force search you simply get a cutoff.
If a line is silly and far away from our root window, yes even if it is 0.2 pawn, i want to give a cutoff. Yet as we have each time a flipping mainline and score belonging to it, we burn a lot of extra nodes

e) total search depth is disappointing. It is true that forced lines you can see right to the end and instantly. Great for specific tricks. Of course i started testing simple tricks first.

A trick that Diep finds with CNS without burning a lot of nodes is Rxc5 from the Larsen100 testset. Brute force it burns up really a lot more nodes.

3r1rk1/1pq1nppp/p7/2pB3Q/P4P2/1P2P3/6PP/2RR2K1 w - - bm Rxc5; id "GMG1.092";
c1c5
I don't see the issue here. Crafty finds this instantly and has failed high twice on it by the time it has used 1/2 second, running on my laptop, not anything bigger...


Yet this was the only 'victory' i could speak about.
All kind of other tricks, real simple ones, were really complicated to find, despite burning way more nodes.

f) memory management is expensive. I used a memory buffer of 400MB, lotta RAM for those days for a single processor. brute force search is much easier. For CNS i had implemented a big tree concept WITH transpositions.
Maintaining that is not so easy. My solution was a stupid one, just to experiment with it, i simply searched until the RAM was completely filled.
then search stopped.

Now as a replacement scheme that is NOT very clever.

All this slows down search bigtime.

A few years ago i didn't find that very acceptable.

It is here where brute force total annihilates all other forms of search most. The combination of more overhead into silly nodes with more efficient search is deadly.

Selectivity you can get in brute force search by forward pruning, reductions and extensions. That's much easier than doing everything in a non-brute force manner.

Amazingly now if you go play games with it, you will typically see that you aren't gonna lose many games based upon missing tactics. It is relative easy to avoid MISSING tactics.

The real problem what loses you game after game is the idiocy that happens around your mainline. It keeps nonstop doubting and changing its mainline. That is really BAD.

This where in a brute force search, the search really corrects diep's bad tuned eval (note i'm busy with a big project with Renze Steenhuisen to improve its tuning a tad at a processor or 40, that will weed out hopefully some historic idiocy from 10+ years ago in diep's eval).

This is however not true for all evaluations. In ancient times, search was simply not needed for fine grained positional corrections. You can see that in rybka also. If you have a real well tuned evaluatoin function, you can risk doing dubious hard forward pruning last 7 ply or so.

That is very complicated as soon as you already add mobility in the way Diep is doing it. Evaluation doubts more. Search IS needed to correct it bigtime last few plies especially.

All this happens in brute force, and alternatives to it, that correction doesn't happen. That is a BIG eloloss.

That aside from that it wasn't capable of finding some trivial tactics which no brute force search misses.

There is ways around finding tactics i tend to believe. Some clever extension here or there. There is no way to compensate for positional eloloss.

Vincent