Fix force mode after setboard
[bonanza.git] / learn1.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <limits.h>
5 #include <float.h>
6 #include <math.h>
7 #if defined(_WIN32)
8 #  include <process.h>
9 #else
10 #  include <sched.h>
11 #endif
12 #include "shogi.h"
13
14 #if ! defined(MINIMUM)
15
16 #  define SEARCH_DEPTH      2
17 #  define NUM_RESULT        8
18 #  define MAX_RECORD_LENGTH 1024
19 #  define DOT_INTERVAL      10
20 #  define MAX_BOOK_PLY      64
21 #  define NumBookCluster    256
22 #  define NumBookEntry      0x1000
23 #  define SIZE_PV_BUFFER    0x100000
24 #  define MOVE_VOID         0x80000000U
25 #  define Move2S(move)      (unsigned short)((move) & 0x7fffU)
26
27
28 typedef struct {
29   struct { uint64_t a,b; } cluster[NumBookCluster];
30 } book_entry_t;
31
32 typedef struct {
33
34   /* input */
35   tree_t *ptree;
36   book_entry_t *pbook_entry;
37   FILE *pf_tmp;
38   record_t *precord;
39   unsigned int max_games, id;
40   int nworker;
41
42   /* output */
43   uint64_t result[ NUM_RESULT ];
44   uint64_t num_moves_counted, num_moves, result_norm, num_nodes;
45   double target, target_out_window;
46   unsigned int illegal_moves, max_pos_buf;
47   int info;
48
49   /* work area */
50   unsigned int record_moves[ MAX_RECORD_LENGTH ];
51   unsigned int amove_legal[ MAX_LEGAL_MOVES ];
52   unsigned int record_length, pos_buf;
53   unsigned short buf[ SIZE_PV_BUFFER ];
54   int root_turn;
55
56 } parse1_data_t;
57
58 typedef struct {
59
60   /* input */
61   tree_t *ptree;
62   FILE *pf_tmp;
63   unsigned int id;
64   int nworker;
65
66   /* output */
67   param_t param;
68   uint64_t num_moves_counted;
69   double target;
70   int info;
71
72   /* work area */
73   unsigned short buf[ SIZE_PV_BUFFER ];
74   unsigned int pv[ PLY_MAX + 2 ];
75
76 } parse2_data_t;
77
78 #  if defined(_WIN32)
79 static unsigned int __stdcall parse1_worker( void *arg );
80 static unsigned int __stdcall parse2_worker( void *arg );
81 #  else
82 static void *parse1_worker( void *arg );
83 static void *parse2_worker( void *arg );
84 #endif
85 static void ini_book( book_entry_t *pbook_entry );
86 static void make_pv( parse1_data_t *pdata, unsigned int record_move );
87 static int read_game( parse1_data_t *pdata );
88 static int read_buf( unsigned short *buf, FILE *pf );
89 static int calc_deriv( parse2_data_t *pdata, int pos_buf, int turn );
90 static int learn_parse1( tree_t * restrict ptree, book_entry_t *pbook_entry,
91                          FILE *pf_tmp, record_t *precord,
92                          unsigned int max_games, double *ptarget_out_window,
93                          double *pobj_norm, int tlp1 );
94 static int learn_parse2( tree_t * restrict ptree, FILE *pf_tmp,
95                          int nsteps, double target_out_window,
96                          double obj_norm, int tlp2 );
97 static int book_probe_learn( const tree_t * restrict ptree,
98                              book_entry_t *pbook_entry, int ply,
99                              unsigned int move );
100 static int rep_check_learn( tree_t * restrict ptree, int ply );
101 static unsigned int s2move( const tree_t * restrict ptree, unsigned int move,
102                             int tt );
103 static double func( double x );
104 static double dfunc( double x );
105
106 int
107 learn( tree_t * restrict ptree, int is_ini, int nsteps, unsigned int max_games,
108        int max_iterations, int nworker1, int nworker2 )
109 {
110   record_t record;
111   book_entry_t *pbook_entry;
112   FILE *pf_tmp;
113   double target_out_window, obj_norm;
114   int iret, niterations;
115
116   pbook_entry = memory_alloc( sizeof(book_entry_t) * NumBookEntry );
117   if ( pbook_entry == NULL ) { return -2; }
118
119   if ( is_ini )
120     {
121       fill_param_zero();
122       fmg_misc      = fmg_cap      = fmg_drop = fmg_mt = 0;
123       fmg_misc_king = fmg_cap_king = 0;
124     }
125   else {
126     fmg_misc      = FMG_MISC;
127     fmg_cap       = FMG_CAP;
128     fmg_drop      = FMG_DROP;
129     fmg_mt        = FMG_MT;
130     fmg_misc_king = FMG_MISC_KING;
131     fmg_cap_king  = FMG_CAP_KING;
132   }
133
134   game_status     |= flag_learning;
135   root_alpha       = - ( score_max_eval + 1 );
136   root_beta        = + ( score_max_eval + 1 );
137   root_abort       = 0;
138   iret             = 1;
139
140   for ( niterations = 1; niterations <= max_iterations; niterations++ )
141     {
142       Out( "\n  Iteration %03d\n", niterations );
143
144       iret = record_open( &record, "records.csa", mode_read, NULL, NULL );
145       if ( iret < 0 ) { break; }
146   
147       pf_tmp = file_open( "tmp.bin", "wb" );
148       if ( pf_tmp == NULL )
149         {
150           record_close( &record );
151           iret = -2;
152           break;
153         }
154
155       iret = learn_parse1( ptree, pbook_entry, pf_tmp, &record, max_games,
156                            &target_out_window, &obj_norm, nworker1 );
157
158       if ( iret < 0 )
159         {
160           record_close( &record );
161           file_close( pf_tmp );
162           break;
163         }
164
165       iret = file_close( pf_tmp );
166       if ( iret < 0 )
167         {
168           record_close( &record );
169           break;
170         }
171
172       pf_tmp = file_open( "tmp.bin", "rb" );
173       if ( pf_tmp == NULL )
174         {
175           record_close( &record );
176           iret = -2;
177           break;
178         }
179
180       iret = learn_parse2( ptree, pf_tmp, nsteps, target_out_window, obj_norm,
181                            nworker2 );
182       if ( iret < 0 )
183         {
184           file_close( pf_tmp );
185           record_close( &record );
186           break;
187         }
188
189       iret = file_close( pf_tmp );
190       if ( iret < 0 )
191         {
192           record_close( &record );
193           break;
194         }
195
196       iret = record_close( &record );
197       if ( iret < 0 ) { break; }
198
199       if ( ! ( game_status & flag_learning ) )
200         {
201           out_warning( "flag_learning is not set." );
202         }
203     }
204   
205   memory_free( pbook_entry );
206   game_status &= ~flag_learning;
207   
208   return iret;
209 }
210
211
212 static int
213 learn_parse1( tree_t * restrict ptree, book_entry_t *pbook_entry, FILE *pf_tmp,
214               record_t *precord, unsigned int max_games,
215               double *ptarget_out_window, double *pobj_norm, int nworker )
216 {
217   parse1_data_t *pdata[ TLP_MAX_THREADS ];
218   int i, id;
219
220   ini_book( pbook_entry );
221
222   for ( id = 0; id < nworker; id++ )
223     {
224       pdata[id] = memory_alloc( sizeof(parse1_data_t) );
225       if ( pdata[id] == NULL ) { return -1; }
226
227       pdata[id]->ptree       = NULL;
228       pdata[id]->pbook_entry = pbook_entry;
229       pdata[id]->pf_tmp      = pf_tmp;
230       pdata[id]->precord     = precord;
231       pdata[id]->max_games   = max_games;
232       pdata[id]->id          = id;
233       pdata[id]->nworker     = nworker;
234     }
235
236 #if defined(TLP)
237   tlp_num = nworker;
238   for ( id = 1; id < nworker; id++ )
239     {
240 #  if defined(_WIN32)
241       pdata[id]->ptree = tlp_atree_work + id;
242       if ( ! _beginthreadex( 0, 0, parse1_worker, pdata[id], 0, 0 ) )
243         {
244           str_error = "_beginthreadex() failed.";
245           return -1;
246         }
247 #  else
248       pthread_t pt;
249
250       pdata[id]->ptree = tlp_atree_work + id;
251       if ( pthread_create( &pt, &pthread_attr, parse1_worker, pdata[id] ) )
252         {
253           str_error = "pthread_create() failed.";
254           return -1;
255         }
256 #  endif
257     }
258 #endif /* TLP */
259
260   pdata[0]->ptree = ptree;
261   parse1_worker( pdata[0] );
262
263 #if defined(TLP)
264   while ( tlp_num ) { tlp_yield(); }
265 #endif
266   
267   for ( id = 0; id < nworker; id++ )
268     {
269       if ( pdata[id]->info < 0 ) { return -1; }
270     }
271
272   for ( id = 1; id < nworker; id++ )
273     {
274       for ( i = 0; i < NUM_RESULT; i++ )
275         {
276           pdata[0]->result[i] += pdata[id]->result[i];
277         }
278       pdata[0]->num_moves_counted += pdata[id]->num_moves_counted;
279       pdata[0]->num_moves         += pdata[id]->num_moves;
280       pdata[0]->num_nodes         += pdata[id]->num_nodes;
281       pdata[0]->result_norm       += pdata[id]->result_norm;
282       pdata[0]->target            += pdata[id]->target;
283       pdata[0]->target_out_window += pdata[id]->target_out_window;
284       pdata[0]->illegal_moves     += pdata[id]->illegal_moves;
285       if ( pdata[0]->max_pos_buf < pdata[id]->max_pos_buf )
286         {
287           pdata[0]->max_pos_buf = pdata[id]->max_pos_buf;
288         }
289     }
290   if ( pdata[0]->result_norm == 0 ) { pdata[0]->result_norm = 1; }
291   if ( pdata[0]->num_moves   == 0 ) { pdata[0]->num_moves   = 1; }
292   *ptarget_out_window = pdata[0]->target_out_window;
293   *pobj_norm          = (double)pdata[0]->num_moves;
294
295   {
296     double dtemp;
297     int misc, drop, cap, mt, misc_king, cap_king;
298
299     Out( " done\n" );
300     Out( "   Number of Games : %u\n",       precord->games );
301     Out( "   Total Moves     : %"PRIu64"\n",pdata[0]->num_moves );
302     Out( "   Moves Counted   : %"PRIu64"\n",pdata[0]->num_moves_counted);
303     Out( "   Illegal Moves   : %u\n",       pdata[0]->illegal_moves );
304     Out( "   Nodes Searched  : %"PRIu64"\n",pdata[0]->num_nodes );
305     Out( "   Max pos_buf     : %x\n",       pdata[0]->max_pos_buf );
306     Out( "   Prediction (%)  :" );
307     for ( i = 0, dtemp = 0.0; i < NUM_RESULT; i++ )
308       {
309         dtemp += (double)pdata[0]->result[i] * 100.0;
310         Out( " %4.2f", dtemp / (double)pdata[0]->result_norm );
311       }
312     Out( "\n" );
313   
314     pdata[0]->target /= *pobj_norm;
315     dtemp             = *ptarget_out_window / *pobj_norm;
316     Out( "   Target          : %f (%f)\n", pdata[0]->target, dtemp );
317
318     misc      = fmg_misc      / 2;
319     drop      = fmg_drop      / 2;
320     cap       = fmg_cap       / 2;
321     mt        = fmg_mt        / 2;
322     misc_king = fmg_misc_king / 2;
323     cap_king  = fmg_cap_king  / 2;
324     Out( "   Futility        : misc=%d drop=%d cap=%d mt=%d misc(k)=%d "
325          "cap(k)=%d\n", misc, drop, cap, mt, misc_king, cap_king );
326   }
327
328   for ( id = 0; id < nworker; id++ ) { memory_free( pdata[id] ); }
329   
330   return 1;
331 }
332
333
334 #  if defined(_MSC_VER)
335 static unsigned int __stdcall parse1_worker( void *arg )
336 #  else
337 static void *parse1_worker( void *arg )
338 #endif
339 {
340   parse1_data_t *pdata;
341   tree_t *ptree;
342   unsigned int record_move;
343   int i, imove, iret;
344
345   iret                 = 0;
346   pdata                = (parse1_data_t *)arg;
347   ptree                = pdata->ptree;
348
349   for ( i = 0; i < NUM_RESULT; i++ ) { pdata->result[i] = 0; }
350   pdata->num_moves_counted = 0;
351   pdata->num_moves         = 0;
352   pdata->num_nodes         = 0;
353   pdata->max_pos_buf       = 0;
354   pdata->result_norm       = 0;
355   pdata->record_length     = 0;
356   pdata->illegal_moves     = 0;
357   pdata->info              = 0;
358   pdata->target            = 0.0;
359   pdata->target_out_window = 0.0;
360
361   for ( ;; ) {
362     /* make pv */
363     pdata->pos_buf = 2U;
364     for ( imove = 0; imove < (int)pdata->record_length; imove++ )
365       {
366         record_move                    = pdata->record_moves[imove];
367
368         pdata->buf[ pdata->pos_buf++ ] = Move2S(record_move);
369
370         if ( record_move & MOVE_VOID ) { record_move &= ~MOVE_VOID; }
371         else                           { make_pv( pdata, record_move ); }
372
373         pdata->buf[ pdata->pos_buf++ ] = 0;
374
375         MakeMove( pdata->root_turn, record_move, 1 );
376         pdata->root_turn     = Flip( pdata->root_turn );
377         ptree->move_last[1]  = ptree->move_last[0];
378         ptree->nsuc_check[0] = 0;
379         ptree->nsuc_check[1]
380           = (unsigned char)( InCheck( pdata->root_turn ) ? 1U : 0 );
381       }
382
383 #if defined(TLP)
384     lock( &tlp_lock );
385 #endif
386
387     /* save pv */
388     if ( pdata->record_length )
389       {
390         if ( pdata->pos_buf > pdata->max_pos_buf )
391           {
392             pdata->max_pos_buf = pdata->pos_buf;
393           }
394         pdata->buf[0] = (unsigned short)( pdata->pos_buf / 0x10000U );
395         pdata->buf[1] = (unsigned short)( pdata->pos_buf % 0x10000U );
396
397         if ( fwrite( pdata->buf, sizeof(unsigned short), pdata->pos_buf,
398                      pdata->pf_tmp ) != pdata->pos_buf )
399           {
400             str_error = str_io_error;
401             iret      = -2;
402           }
403       }
404
405     /* read next game */
406     while ( iret >= 0 ) {
407       iret = read_game( pdata );
408       if ( iret == 1 )            { break; } /* end of record */
409       if ( pdata->record_length ) { break; } /* read a record */
410     }
411     
412 #if defined(TLP)
413     unlock( &tlp_lock );
414 #endif
415
416     if ( iret < 0 )  { break; }
417     if ( iret == 1 ) { break; }
418   }
419
420 #if defined(TLP)
421   lock( &tlp_lock );
422   tlp_num -= 1;
423   unlock( &tlp_lock );
424 #endif
425
426   pdata->info = iret;
427   return 0;
428 }
429
430
431 static void
432 make_pv( parse1_data_t *pdata, unsigned int record_move )
433 {
434   double func_value;
435   tree_t *ptree;
436   unsigned int *pmove;
437   unsigned int move, pos_buf;
438   int i, imove, record_value, nth, nc, nmove_legal;
439   int value, alpha, beta, depth, ply, tt, new_depth;
440
441   record_value          = INT_MIN;
442   nc                    = 0;
443   nth                   = 0;
444   depth                 = PLY_INC * SEARCH_DEPTH + PLY_INC / 2;
445   tt                    = Flip(pdata->root_turn);
446   pos_buf               = pdata->pos_buf;
447   ptree                 = pdata->ptree;
448   ptree->node_searched  = 0;
449   ptree->save_eval[0]   = INT_MAX;
450   ptree->save_eval[1]   = INT_MAX;
451 #if defined(TLP)
452   ptree->tlp_abort      = 0;
453 #endif
454   for ( ply = 0; ply < PLY_MAX; ply++ )
455     {
456       ptree->amove_killer[ply].no1 = ptree->amove_killer[ply].no2 = 0U;
457       ptree->killers[ply].no1      = ptree->killers[ply].no2      = 0U;
458     }
459   for ( i = 0; i < (int)HIST_SIZE; i++ )
460     {
461       ptree->hist_good[i]  /= 256U;
462       ptree->hist_tried[i] /= 256U;
463     }
464   evaluate( ptree, 1, pdata->root_turn );
465
466   pmove = GenCaptures     ( pdata->root_turn, pdata->amove_legal );
467   pmove = GenNoCaptures   ( pdata->root_turn, pmove );
468   pmove = GenDrop         ( pdata->root_turn, pmove );
469   pmove = GenCapNoProEx2  ( pdata->root_turn, pmove );
470   pmove = GenNoCapNoProEx2( pdata->root_turn, pmove );
471   nmove_legal = (int)( pmove - pdata->amove_legal );
472   
473   for ( i = 0; pdata->amove_legal[i] != record_move; i++ );
474   move                  = pdata->amove_legal[0];
475   pdata->amove_legal[0] = pdata->amove_legal[i];
476   pdata->amove_legal[i] = move;
477
478   for ( imove = 0; imove < nmove_legal; imove++ ) {
479
480     move = pdata->amove_legal[imove];
481     ptree->current_move[1] = move;
482     if ( imove )
483       {
484         alpha = record_value - FV_WINDOW;
485         beta  = record_value + FV_WINDOW;
486         if ( alpha < root_alpha ) { alpha = root_alpha; }
487         if ( beta  > root_beta )  { beta  = root_beta; }
488       }
489     else {
490       alpha = root_alpha;
491       beta  = root_beta;
492     }
493
494     MakeMove( pdata->root_turn, move, 1 );
495     if ( InCheck(pdata->root_turn) )
496       {
497         UnMakeMove( pdata->root_turn, move, 1 );
498         continue;
499       }
500
501     if ( InCheck(tt) )
502       {
503         new_depth = depth + PLY_INC;
504         ptree->nsuc_check[2] = (unsigned char)( ptree->nsuc_check[0] + 1U );
505       }
506     else {
507       new_depth            = depth;
508       ptree->nsuc_check[2] = 0;
509     }
510
511     ptree->current_move[1] = move;
512     ptree->pv[1].type = no_rep;
513       
514     value = -search( ptree, -beta, -alpha, tt, new_depth, 2,
515                      node_do_mate | node_do_null | node_do_futile
516                      | node_do_recap | node_do_recursion | node_do_hashcut );
517
518     UnMakeMove( pdata->root_turn, move, 1 );
519
520     if ( abs(value) > score_mate1ply )
521       {
522         out_warning( "value is larger than mate1ply!" );
523       }
524     
525     if ( imove )
526       {
527         func_value        = func( value - record_value );
528         pdata->target    += func_value;
529         pdata->num_moves += 1U;
530         if ( alpha < value && value < beta )
531           {
532             nc += 1;
533           }
534         else { pdata->target_out_window += func_value; }
535         if ( value >= record_value ) { nth += 1; }
536       }
537     else if ( alpha < value && value < beta )
538       {
539         nth          += 1;
540         record_value  = value;
541       }
542     else { break; } /* record move failed high or low. */
543
544     if ( alpha < value && value < beta )
545       {
546         pdata->buf[ pos_buf++ ] = Move2S(move);
547         for ( ply = 2; ply <= ptree->pv[1].length; ply++ )
548           {
549             pdata->buf[ pos_buf++ ] = Move2S(ptree->pv[1].a[ply]);
550           }
551         pdata->buf[ pos_buf - 1 ] |= 0x8000U;
552       }
553   }
554
555   if ( nth - 1 >= 0 )
556     {
557       pdata->result_norm += 1;
558       if ( nth-1 < NUM_RESULT ) { pdata->result[nth-1] += 1; }
559     }
560
561   if ( nc )
562     {
563       pdata->pos_buf            = pos_buf;
564       pdata->num_moves_counted += nc;
565     }
566   pdata->num_nodes += ptree->node_searched;
567 }
568
569
570 static int
571 read_game( parse1_data_t *pdata )
572 {
573   tree_t *ptree;
574   tree_t tree;
575   unsigned int record_move;
576   int istatus, iret, imove;
577
578   ptree   = & tree;
579   istatus = 0;
580   if ( pdata->precord->games == pdata->max_games ) { return 1; }
581
582   if ( pdata->precord->games == 0 ) { Out( "  Parse 1 " ); }
583
584   if ( ! ( (pdata->precord->games+1) % DOT_INTERVAL ) )
585     {
586       if ( ! ( (pdata->precord->games+1) % ( DOT_INTERVAL * 10 ) ) )
587         {
588           Out( "o" );
589           if ( ! ( (pdata->precord->games+1) % ( DOT_INTERVAL * 50 ) ) )
590             {
591               Out( "%7d\n          ", pdata->precord->games+1 );
592             }
593         }
594       else { Out( "." ); }
595     }
596
597   for ( imove = 0; imove < MAX_RECORD_LENGTH; imove++ )
598     {
599       istatus = in_CSA( ptree, pdata->precord, &record_move,
600                         flag_nomake_move | flag_detect_hang | flag_nofmargin );
601       if ( istatus < 0 )
602         {
603           pdata->illegal_moves += 1;
604           break;
605         }
606       if ( istatus >= record_eof ) { break; }
607
608       if ( ! imove
609            && ( root_turn != min_posi_no_handicap.turn_to_move
610                 || HAND_B != min_posi_no_handicap.hand_black
611                 || HAND_W != min_posi_no_handicap.hand_white
612                 || memcmp( BOARD, min_posi_no_handicap.asquare, nsquare ) ) )
613         {
614           break;
615         }
616       
617       if ( ! imove )
618         {
619           *(pdata->ptree)  = *ptree;
620           pdata->root_turn = root_turn;
621         }
622
623       if ( rep_check_learn( ptree, 1 ) == four_fold_rep
624            || ( pdata->precord->moves < MAX_BOOK_PLY
625                 && book_probe_learn( ptree, pdata->pbook_entry,
626                                      pdata->precord->moves, record_move ) ) )
627         {
628           pdata->record_moves[ imove ] = record_move | MOVE_VOID;
629         }
630       else { pdata->record_moves[ imove ] = record_move; }
631
632       iret = make_move_root( ptree, record_move, 0 );
633       if ( iret < 0 ) { return iret; }
634     }
635   
636   if ( istatus != record_next && istatus != record_eof )
637     {
638       istatus = record_wind( pdata->precord );
639       if ( istatus < 0 ) { return istatus; }
640     }
641   
642   if ( ! imove && istatus == record_eof ) { return 1; }
643   pdata->record_length = imove;
644
645   return 0;
646 }
647
648
649 static int
650 learn_parse2( tree_t * restrict ptree, FILE *pf_tmp, int nsteps,
651               double target_out_window, double obj_norm, int nworker )
652 {
653   parse2_data_t *pdata[ TLP_MAX_THREADS ];
654   int istep, id;
655
656   for ( id = 0; id < nworker; id++ )
657     {
658       pdata[id] = memory_alloc( sizeof(parse2_data_t) );
659       if ( pdata[id] == NULL ) { return -1; }
660   
661       pdata[id]->ptree   = NULL;
662       pdata[id]->pf_tmp  = pf_tmp;
663       pdata[id]->id      = id;
664       pdata[id]->nworker = nworker;
665     }
666
667   Out( "  Parse 2\n" );
668
669   istep = 0;
670   for ( ;; ) {
671
672 #if defined(TLP)
673     tlp_num = nworker;
674     for ( id = 1; id < nworker; id++ )
675       {
676 #  if defined(_WIN32)
677         pdata[id]->ptree = tlp_atree_work + id;
678         if ( ! _beginthreadex( 0, 0, parse2_worker, pdata[id], 0, 0 ) )
679           {
680             str_error = "_beginthreadex() failed.";
681             return -1;
682           }
683 #  else
684         pthread_t pt;
685         
686         pdata[id]->ptree = tlp_atree_work + id;
687         if ( pthread_create( &pt, &pthread_attr, parse2_worker, pdata[id] ) )
688           {
689             str_error = "pthread_create() failed.";
690             return -1;
691           }
692 #  endif
693       }
694 #endif /* TLP */
695     
696     pdata[0]->ptree = ptree;
697     parse2_worker( pdata[0] );
698
699 #if defined(TLP)
700     while ( tlp_num ) { tlp_yield(); }
701 #endif
702   
703     for ( id = 0; id < nworker; id++ )
704       {
705         if ( pdata[id]->info < 0 ) { return -1; }
706       }
707
708     for ( id = 1; id < nworker; id++ )
709       {
710         add_param( &pdata[0]->param, &pdata[id]->param );
711         pdata[0]->num_moves_counted += pdata[id]->num_moves_counted;
712         pdata[0]->target            += pdata[id]->target;
713       }
714
715     if ( ! istep )
716       {
717         double target, penalty, objective_function;
718
719         penalty = calc_penalty() / obj_norm;
720         target  = ( pdata[0]->target + target_out_window ) / obj_norm;
721         objective_function = target + penalty;
722         Out( "   Moves Counted   : %d\n", pdata[0]->num_moves_counted );
723         Out( "   Objective Func. : %.8f %.8f %.8f\n",
724                   objective_function, target, penalty );
725         Out( "   Steps " );
726       }
727
728     param_sym( &pdata[0]->param );
729
730     renovate_param( &pdata[0]->param );
731     istep += 1;
732     if ( istep < nsteps ) { Out( "." ); }
733     else {
734       Out( ". done\n\n" );
735       break;
736     }
737     rewind( pf_tmp );
738   }
739   for ( id = 0; id < nworker; id++ ) { memory_free( pdata[id] ); }
740
741   return out_param();
742 }
743
744
745 #  if defined(_MSC_VER)
746 static unsigned int __stdcall parse2_worker( void *arg )
747 #  else
748 static void *parse2_worker( void *arg )
749 #endif
750 {
751   parse2_data_t *pdata;
752   tree_t *ptree;
753   unsigned int record_move;
754   int iret, imove, nbuf, pos_buf, turn;
755
756   iret  = 0;
757   pdata = (parse2_data_t *)arg;
758   ptree = pdata->ptree;
759
760   pdata->num_moves_counted = 0;
761   pdata->info              = 0;
762   pdata->target            = 0.0;
763   ini_param( &pdata->param );
764
765   for ( ;; ) {
766 #if defined(TLP)
767     lock( &tlp_lock );
768 #endif
769     iret = read_buf( pdata->buf, pdata->pf_tmp );
770 #if defined(TLP)
771     unlock( &tlp_lock );
772 #endif
773
774     if ( iret <= 0 )  { break; } /* 0: eof, -2: error */
775     nbuf = iret;
776
777     iret = ini_game( ptree, &min_posi_no_handicap, flag_nofmargin,
778                      NULL, NULL );
779     if ( iret < 0 ) { break; }
780
781     turn    = black;
782     pos_buf = 2;
783     for ( imove = 0; pos_buf < nbuf; imove++ )
784       {
785         record_move = s2move( ptree, pdata->buf[pos_buf++], turn );
786
787         if ( pdata->buf[pos_buf] )
788           {
789             pos_buf = calc_deriv( pdata, pos_buf, turn );
790           }
791         pos_buf += 1;
792
793         MakeMove( turn, record_move, 1 );
794         turn                 = Flip( turn );
795         ptree->move_last[1]  = ptree->move_last[0];
796         ptree->nsuc_check[0] = 0;
797         ptree->nsuc_check[1] = (unsigned char)( InCheck( turn ) ? 1U : 0 );
798       }
799   }
800
801 #if defined(TLP)
802   lock( &tlp_lock );
803   tlp_num -= 1;
804   unlock( &tlp_lock );
805 #endif
806
807   pdata->info = iret;
808   return 0;
809 }
810
811
812 static int
813 read_buf( unsigned short *buf, FILE *pf )
814 {
815   size_t size;
816
817   size = fread( buf, sizeof(unsigned short), 2, pf );
818   if ( ! size && feof( pf ) ) { return 0; }
819   if ( size != 2 )
820     {
821       str_error = str_io_error;
822       return -2;
823     }
824
825   size = (size_t)buf[1] + (size_t)buf[0] * 0x10000 - 2;
826   if ( fread( buf+2, sizeof(unsigned short), size, pf ) != size )
827     {
828       str_error = str_io_error;
829       return -2;
830     }
831
832   return (int)size;
833 }
834
835
836 static int
837 calc_deriv( parse2_data_t *pdata, int pos0, int turn0 )
838 {
839   double target, dT, sum_dT;
840   tree_t * restrict ptree;
841   const unsigned short *buf;
842   unsigned int nc;
843   int ply, turn, pv_length, pos, record_value, value;
844
845   ptree  = pdata->ptree;
846   buf    = pdata->buf;
847   nc     = 0;
848   turn   = turn0;
849   pos    = pos0;
850   target = 0.0;
851   sum_dT = 0.0;
852
853   ply  = 1;
854   for ( ;; ) {
855     pdata->pv[ply] = s2move( ptree, buf[ pos+ply-1 ] & 0x7fffU, turn );
856     MakeMove( turn, pdata->pv[ply], ply );
857     turn = Flip( turn );
858     if ( buf[ pos+ply-1 ] & 0x8000U ) { break; }
859     ply += 1;
860   }
861   pv_length = ply;
862
863   record_value = evaluate( ptree, ply+1, turn );
864   if ( turn != turn0 ) { record_value = -record_value; }
865
866   for ( ;; ) {
867     turn  = Flip( turn );
868     UnMakeMove( turn, pdata->pv[ply], ply );
869     if ( ply == 1 ) { break; }
870     ply -= 1;
871   }
872   pos += pv_length;
873
874   while ( buf[ pos ] ) {
875     ply  = 1;
876     for ( ;; ) {
877       pdata->pv[ply] = s2move( ptree, buf[ pos+ply-1 ] & 0x7fffU, turn );
878       MakeMove( turn, pdata->pv[ply], ply );
879       turn = Flip( turn );
880       if ( buf[ pos+ply-1 ] & 0x8000U ) { break; }
881       ply += 1;
882     }
883     pv_length = ply;
884
885     value = evaluate( ptree, ply+1, turn );
886     if ( turn != turn0 ) { value = -value; }
887     target += func( value - record_value );
888           
889     dT = dfunc( value - record_value );
890     if ( turn0 ) { dT = -dT; }
891     sum_dT += dT;
892     inc_param( ptree, &pdata->param, -dT );
893
894     for ( ;; ) {
895       turn  = Flip( turn );
896       UnMakeMove( turn, pdata->pv[ply], ply );
897       if ( ply == 1 ) { break; }
898       ply -= 1;
899     }
900
901     pos += pv_length;
902     nc  += 1;
903   }
904
905   ply  = 1;
906   for ( ;; ) {
907     pdata->pv[ply] = s2move( ptree, buf[ pos0+ply-1 ] & 0x7fffU, turn );
908     MakeMove( turn, pdata->pv[ply], ply );
909     turn = Flip( turn );
910     if ( buf[ pos0+ply-1 ] & 0x8000U ) { break; }
911     ply += 1;
912   }
913
914   inc_param( ptree, &pdata->param, sum_dT );
915
916   for ( ;; ) {
917     turn  = Flip( turn );
918     UnMakeMove( turn, pdata->pv[ply], ply );
919     if ( ply == 1 ) { break; }
920     ply -= 1;
921   }
922
923   pdata->num_moves_counted += nc;
924   pdata->target            += target;
925
926   return pos;
927 }
928
929
930 static double
931 func( double x )
932 {
933   const double delta = (double)FV_WINDOW / 7.0;
934   double d;
935   
936   if      ( x < -FV_WINDOW ) { x = -FV_WINDOW; }
937   else if ( x >  FV_WINDOW ) { x =  FV_WINDOW; }
938   d = 1.0 / ( 1.0 + exp(-x/delta) );
939
940   return d;
941 }
942
943
944 static double
945 dfunc( double x )
946 {
947   const double delta = (double)FV_WINDOW / 7.0;
948   double dd, dn, dtemp, dret;
949
950   if      ( x <= -FV_WINDOW ) { dret = 0.0; }
951   else if ( x >=  FV_WINDOW ) { dret = 0.0; }
952   else {
953     dn    = exp( - x / delta );
954     dtemp = dn + 1.0;
955     dd    = delta * dtemp * dtemp;
956     dret  = dn / dd;
957   }
958   
959   return dret;
960 }
961
962
963 static unsigned int
964 s2move( const tree_t * restrict ptree, unsigned int move, int tt )
965 {
966   int from, to;
967
968   from = I2From(move);
969   if ( from < nsquare )
970     {
971       to = I2To(move);
972       move |= tt ? (Piece2Move(-BOARD[from])|Cap2Move( BOARD[to]))
973                  : (Piece2Move( BOARD[from])|Cap2Move(-BOARD[to]));
974     }
975   return move;
976 }
977
978
979 static void
980 ini_book( book_entry_t *pbook_entry )
981 {
982   int i, j;
983   
984   for ( i = 0; i < NumBookEntry; i++ )
985     for ( j = 0; j < NumBookCluster; j++ ) {
986       pbook_entry[i].cluster[j].a = (uint64_t)0;
987       pbook_entry[i].cluster[j].b = (uint64_t)0x1ffU << 41;
988     }
989 }
990
991
992 /*
993 a: key     64   0
994
995 b: ply      9  41
996    move    19  22
997    turn     1  21
998    hand    21   0
999 */
1000 static int
1001 book_probe_learn( const tree_t * restrict ptree,
1002                   book_entry_t *pbook_entry,
1003                   int ply, unsigned int move )
1004 {
1005   book_entry_t *p;
1006   int i, j;
1007
1008   move &= 0x7ffffU;
1009   p = pbook_entry
1010     + ((unsigned int)HASH_KEY & (unsigned int)(NumBookEntry-1));
1011
1012   for ( i = 0; i < NumBookCluster; i++ )
1013     if ( p->cluster[i].a == HASH_KEY
1014          && ((unsigned int)p->cluster[i].b & 0x1fffffU) == HAND_B
1015          && ( (((unsigned int)p->cluster[i].b>>21) & 0x1U)
1016               == (unsigned int)root_turn )
1017          && ((unsigned int)(p->cluster[i].b>>22) & 0x7ffffU) == move ) {
1018       return 1;
1019     }
1020   
1021   for ( i = 0; i < NumBookCluster; i++ )
1022     if ( ( (unsigned int)( p->cluster[i].b >> 41 ) & 0x1ffU )
1023          > (unsigned int)ply ) { break; }
1024
1025   if ( i < NumBookCluster ) {
1026     for ( j = NumBookCluster-1; j > i; j-- ) {
1027       p->cluster[j].a = p->cluster[j-1].a;
1028       p->cluster[j].b = p->cluster[j-1].b;
1029     }
1030
1031     p->cluster[i].a = HASH_KEY;
1032     p->cluster[i].b
1033       = ( (uint64_t)move<<22 ) | ( (uint64_t)ply << 41 )
1034       | (uint64_t)( (root_turn<<21) | HAND_B );
1035   }
1036
1037   return 0;
1038 }
1039
1040
1041 static int
1042 rep_check_learn( tree_t * restrict ptree, int ply )
1043 {
1044   int n, i, imin;
1045
1046   n    = ptree->nrep + ply - 1;
1047   imin = n - REP_MAX_PLY;
1048   if ( imin < 0 ) { imin = 0; }
1049
1050   for ( i = n-2; i >= imin; i -= 2 )
1051     if ( ptree->rep_board_list[i] == HASH_KEY
1052          && ptree->rep_hand_list[i] == HAND_B ) { return four_fold_rep; }
1053
1054   return no_rep;
1055 }
1056
1057 #endif /* no MINIMUM */