This is what I do. I do not claim this is efficient, or anything like that. It is just the way I understand it better. At least, it shows no impact at all when I profile it.sje wrote:A PV is implemented as a list and it's not slow at all due to storage recycling; total allocation costs are too low to be measured. It's fast as well; remember that only links are changed; move data is never copied.CThinker wrote:Thanks for the code. I have already mentioned this approach. That to me is a lot of stack allocation. In most cases, you barely use a fraction of that local PV array. And if you implement that as a dynamic list, that would be slow.
variation_calloc is not a real "calloc". It just returns a pointer to a position in a buffer that is not in the stack. variation_append() and variation_copy() are self explanatory.
when I call search, a pointer returns a pv (that can be empty in non-pv nodes etc.)
Two variations are kept, "pva_curr", which is the one being examined, and pv_best.
When there is a change in subvariation, pointers are swapped.
I do not think this is too much code to pollute the search. I admit I have to have a module variation.c that contains function definitions such as variation_calloc(), variation_append() etc. etc.; but everything is hidden there. You can even limit PVs to 20 plies or whatever, change how this is implemented etc., without touching anything but "variation.c". In fact, you can even have a compiler switch to eliminate all the code in case that you want to port it to a wristwatch, but it is certainly beyond my intentions

I am just happy understanding what I do.
Everybody is welcome to find flaws on this. Please do. I mean it.
Lance: I respect your decision to design your engine as you like and I do not think you are breaking any protocol or any sacred "etiquette". However, I hope you realize that this decision implies missing a feature as important as time management. For someone who uses an engine for analysis, PV is as important as time management is for the people who uses an engine in competitions.
Miguel
Code: Select all
typedef struct {
uint32_t n;
move_t mv [ MAX_VARIATION_MOVES ];
} VARIATION;
search ( POSITION * po
, int depth_input
, int plylevel
, eval_t alpha
, eval_t beta
, VARIATION *pva <== asking for a PV
, VARIATION *pPVAR
, bool_t *timeup
, bool_t *out_rep_flag
, unsigned int sflags)
{
VARIATION * pva_best = variation_calloc (thread_id); /* ALLOCATION OF */
VARIATION * pva_curr = variation_calloc (thread_id); /* VARIATION MEMORY */
/* typical stuff here... ==> makemove, search, unmakemove etc */
value = -search (po
, depth-1
, plylevel+1
, -(alpha+1)
, -alpha
, pva_curr <= will get a PV returned
, NULL
, timeup
, &rep_flag
, sflags);
/* etc (if value > best) best = value etc. etc. */
if (best > alpha) {
alpha = best;
variation_swap (&pva_best, &pva_curr); <== swap pointers
}
/* at the end of search in PV nodes... */
if (alpha > alpha_ori) { /* improving_move_found) */
variation_append (pva_best, bestmove);
variation_copy (pva, pva_best);
}
/* before returning */
variation_free (tid, pva_curr);
variation_free (tid, pva_best);
return adjust_out(best); /* adjust to drive the checkmates */
} /* end search */