Fix Linux sigint problem
[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   for ( id = 1; id < nworker; id++ )
238     {
239 #  if defined(_WIN32)
240       pdata[id]->ptree = tlp_atree_work + id;
241       if ( ! _beginthreadex( 0, 0, parse1_worker, pdata[id], 0, 0 ) )
242         {
243           str_error = "_beginthreadex() failed.";
244           return -1;
245         }
246 #  else
247       pthread_t pt;
248
249       pdata[id]->ptree = tlp_atree_work + id;
250       if ( pthread_create( &pt, &pthread_attr, parse1_worker, pdata[id] ) )
251         {
252           str_error = "pthread_create() failed.";
253           return -1;
254         }
255 #  endif
256     }
257 #endif /* TLP */
258
259   pdata[0]->ptree = ptree;
260   parse1_worker( pdata[0] );
261
262 #if defined(TLP)
263   while ( tlp_num ) { tlp_yield(); }
264 #endif
265   
266   for ( id = 0; id < nworker; id++ )
267     {
268       if ( pdata[id]->info < 0 ) { return -1; }
269     }
270
271   for ( id = 1; id < nworker; id++ )
272     {
273       for ( i = 0; i < NUM_RESULT; i++ )
274         {
275           pdata[0]->result[i] += pdata[id]->result[i];
276         }
277       pdata[0]->num_moves_counted += pdata[id]->num_moves_counted;
278       pdata[0]->num_moves         += pdata[id]->num_moves;
279       pdata[0]->num_nodes         += pdata[id]->num_nodes;
280       pdata[0]->result_norm       += pdata[id]->result_norm;
281       pdata[0]->target            += pdata[id]->target;
282       pdata[0]->target_out_window += pdata[id]->target_out_window;
283       pdata[0]->illegal_moves     += pdata[id]->illegal_moves;
284       if ( pdata[0]->max_pos_buf < pdata[id]->max_pos_buf )
285         {
286           pdata[0]->max_pos_buf = pdata[id]->max_pos_buf;
287         }
288     }
289   if ( pdata[0]->result_norm == 0 ) { pdata[0]->result_norm = 1; }
290   if ( pdata[0]->num_moves   == 0 ) { pdata[0]->num_moves   = 1; }
291   *ptarget_out_window = pdata[0]->target_out_window;
292   *pobj_norm          = (double)pdata[0]->num_moves;
293
294   {
295     double dtemp;
296     int misc, drop, cap, mt, misc_king, cap_king;
297
298     Out( " done\n" );
299     Out( "   Number of Games : %u\n",       precord->games );
300     Out( "   Total Moves     : %"PRIu64"\n",pdata[0]->num_moves );
301     Out( "   Moves Counted   : %"PRIu64"\n",pdata[0]->num_moves_counted);
302     Out( "   Illegal Moves   : %u\n",       pdata[0]->illegal_moves );
303     Out( "   Nodes Searched  : %"PRIu64"\n",pdata[0]->num_nodes );
304     Out( "   Max pos_buf     : %x\n",       pdata[0]->max_pos_buf );
305     Out( "   Move Prediction :" );
306     for ( i = 0, dtemp = 0.0; i < NUM_RESULT; i++ )
307       {
308         dtemp += (double)pdata[0]->result[i] * 100.0;
309         Out( " %4.1f%%", dtemp / (double)pdata[0]->result_norm );
310       }
311     Out( "\n" );
312   
313     pdata[0]->target /= *pobj_norm;
314     dtemp             = *ptarget_out_window / *pobj_norm;
315     Out( "   Target          : %f (%f)\n", pdata[0]->target, dtemp );
316
317     misc      = fmg_misc      / 2;
318     drop      = fmg_drop      / 2;
319     cap       = fmg_cap       / 2;
320     mt        = fmg_mt        / 2;
321     misc_king = fmg_misc_king / 2;
322     cap_king  = fmg_cap_king  / 2;
323     Out( "   Futility        : misc=%d drop=%d cap=%d mt=%d misc(k)=%d "
324          "cap(k)=%d\n", misc, drop, cap, mt, misc_king, cap_king );
325   }
326
327   for ( id = 0; id < nworker; id++ ) { memory_free( pdata[id] ); }
328   
329   return 1;
330 }
331
332
333 #  if defined(_MSC_VER)
334 static unsigned int __stdcall parse1_worker( void *arg )
335 #  else
336 static void *parse1_worker( void *arg )
337 #endif
338 {
339   parse1_data_t *pdata;
340   tree_t *ptree;
341   unsigned int record_move;
342   int i, imove, iret;
343
344   iret  = 0;
345   pdata = (parse1_data_t *)arg;
346   ptree = pdata->ptree;
347
348 #if defined(TLP)
349   if ( pdata->nworker > 1 )
350     {
351       lock( &tlp_lock );
352       tlp_num += 1;
353       if ( pdata->id ) { Out( "hi from thread #%d\n", pdata->id ); }
354       unlock( &tlp_lock );
355       while ( tlp_num < pdata->nworker ) { tlp_yield(); }
356     }
357 #endif
358
359   for ( i = 0; i < NUM_RESULT; i++ ) { pdata->result[i] = 0; }
360   pdata->num_moves_counted = 0;
361   pdata->num_moves         = 0;
362   pdata->num_nodes         = 0;
363   pdata->max_pos_buf       = 0;
364   pdata->result_norm       = 0;
365   pdata->record_length     = 0;
366   pdata->illegal_moves     = 0;
367   pdata->info              = 0;
368   pdata->target            = 0.0;
369   pdata->target_out_window = 0.0;
370
371   for ( ;; ) {
372     /* make results */
373     pdata->pos_buf = 2U;
374     for ( imove = 0; imove < (int)pdata->record_length; imove++ )
375       {
376         record_move                    = pdata->record_moves[imove];
377
378         pdata->buf[ pdata->pos_buf++ ] = Move2S(record_move);
379
380         if ( record_move & MOVE_VOID ) { record_move &= ~MOVE_VOID; }
381         else                           { make_pv( pdata, record_move ); }
382
383         pdata->buf[ pdata->pos_buf++ ] = 0;
384
385         MakeMove( pdata->root_turn, record_move, 1 );
386         pdata->root_turn     = Flip( pdata->root_turn );
387         ptree->move_last[1]  = ptree->move_last[0];
388         ptree->nsuc_check[0] = 0;
389         ptree->nsuc_check[1]
390           = (unsigned char)( InCheck( pdata->root_turn ) ? 1U : 0 );
391       }
392
393 #if defined(TLP)
394     if ( pdata->nworker > 1 ) { lock( &tlp_lock ); }
395 #endif
396
397     /* save results */
398     if ( pdata->record_length )
399       {
400         if ( pdata->pos_buf > pdata->max_pos_buf )
401           {
402             pdata->max_pos_buf = pdata->pos_buf;
403           }
404         pdata->buf[0] = (unsigned short)( pdata->pos_buf / 0x10000U );
405         pdata->buf[1] = (unsigned short)( pdata->pos_buf % 0x10000U );
406
407         if ( fwrite( pdata->buf, sizeof(unsigned short), pdata->pos_buf,
408                      pdata->pf_tmp ) != pdata->pos_buf )
409           {
410             str_error = str_io_error;
411             iret      = -2;
412           }
413       }
414
415     /* read next game */
416     while ( iret >= 0 ) {
417       iret = read_game( pdata );
418       if ( iret == 1 )            { break; } /* end of record */
419       if ( pdata->record_length ) { break; } /* read a record */
420     }
421     
422 #if defined(TLP)
423     if ( pdata->nworker > 1 ) { unlock( &tlp_lock ); }
424 #endif
425
426     if ( iret < 0 )  { break; }
427     if ( iret == 1 ) { break; }
428   }
429
430 #if defined(TLP)
431   if ( pdata->nworker > 1 )
432     {
433       lock( &tlp_lock );
434       tlp_num -= 1;
435       unlock( &tlp_lock );
436     }
437 #endif
438
439   pdata->info = iret;
440   return 0;
441 }
442
443
444 static void
445 make_pv( parse1_data_t *pdata, unsigned int record_move )
446 {
447   double func_value;
448   tree_t *ptree;
449   unsigned int *pmove;
450   unsigned int move, pos_buf;
451   int i, imove, record_value, nth, nc, nmove_legal;
452   int value, alpha, beta, depth, ply, tt;
453
454   record_value          = INT_MIN;
455   nc                    = 0;
456   nth                   = 0;
457   depth                 = PLY_INC * SEARCH_DEPTH + PLY_INC / 2;
458   tt                    = Flip(pdata->root_turn);
459   pos_buf               = pdata->pos_buf;
460   ptree                 = pdata->ptree;
461   ptree->node_searched  = 0;
462 #if defined(TLP)
463   ptree->tlp_abort      = 0;
464 #endif
465   for ( ply = 0; ply < PLY_MAX; ply++ )
466     {
467       ptree->amove_killer[ply].no1 = ptree->amove_killer[ply].no2 = 0U;
468       ptree->killers[ply].no1 = ptree->killers[ply].no2 = 0U;
469     }
470   for ( i = 0; i < HIST_SIZE; i++ )
471     {
472       ptree->hist_good[i]  /= 256U;
473       ptree->hist_tried[i] /= 256U;
474     }
475     
476   pmove = GenCaptures     ( pdata->root_turn, pdata->amove_legal );
477   pmove = GenNoCaptures   ( pdata->root_turn, pmove );
478   pmove = GenDrop         ( pdata->root_turn, pmove );
479   pmove = GenCapNoProEx2  ( pdata->root_turn, pmove );
480   pmove = GenNoCapNoProEx2( pdata->root_turn, pmove );
481   nmove_legal = (int)( pmove - pdata->amove_legal );
482   
483   for ( i = 0; pdata->amove_legal[i] != record_move; i++ );
484   move                  = pdata->amove_legal[0];
485   pdata->amove_legal[0] = pdata->amove_legal[i];
486   pdata->amove_legal[i] = move;
487     
488   for ( imove = 0; imove < nmove_legal; imove++ ) {
489     move = pdata->amove_legal[imove];
490     if ( imove )
491       {
492         alpha = record_value - FV_WINDOW;
493         beta  = record_value + FV_WINDOW;
494         if ( alpha < root_alpha ) { alpha = root_alpha; }
495         if ( beta  > root_beta )  { beta  = root_beta; }
496       }
497     else {
498       alpha = root_alpha;
499       beta  = root_beta;
500     }
501
502     MakeMove( pdata->root_turn, move, 1 );
503     if ( InCheck(pdata->root_turn) )
504       {
505         UnMakeMove( pdata->root_turn, move, 1 );
506         continue;
507       }
508
509     if ( InCheck(tt) )
510       {
511         ptree->nsuc_check[2]
512           = (unsigned char)( ptree->nsuc_check[0] + 1U );
513       } else { ptree->nsuc_check[2] = 0; }
514
515     ptree->current_move[1] = move;
516     ptree->pv[1].type = no_rep;
517       
518     value = -search( ptree, -beta, -alpha, tt, depth, 2,
519                      node_do_mate | node_do_null | node_do_futile
520                      | node_do_recap );
521
522     UnMakeMove( pdata->root_turn, move, 1 );
523
524     if ( abs(value) > score_mate1ply )
525       {
526         out_warning( "value is larger than mate1ply!" );
527       }
528     
529     if ( imove )
530       {
531         func_value        = func( value - record_value );
532         pdata->target    += func_value;
533         pdata->num_moves += 1U;
534         if ( alpha < value && value < beta )
535           {
536             nc += 1;
537           }
538         else { pdata->target_out_window += func_value; }
539         if ( value >= record_value ) { nth += 1; }
540       }
541     else if ( alpha < value && value < beta )
542       {
543         nth          += 1;
544         record_value  = value;
545       }
546     else { break; } /* record move failed high or low. */
547
548     if ( alpha < value && value < beta )
549       {
550         pdata->buf[ pos_buf++ ] = Move2S(move);
551         for ( ply = 2; ply <= ptree->pv[1].length; ply++ )
552           {
553             pdata->buf[ pos_buf++ ] = Move2S(ptree->pv[1].a[ply]);
554           }
555         pdata->buf[ pos_buf - 1 ] |= 0x8000U;
556       }
557   }
558
559   if ( nth - 1 >= 0 )
560     {
561       pdata->result_norm += 1;
562       if ( nth-1 < NUM_RESULT ) { pdata->result[nth-1] += 1; }
563     }
564
565   if ( nc )
566     {
567       pdata->pos_buf            = pos_buf;
568       pdata->num_moves_counted += nc;
569     }
570   pdata->num_nodes += ptree->node_searched;
571 }
572
573
574 static int
575 read_game( parse1_data_t *pdata )
576 {
577   tree_t *ptree;
578   tree_t tree;
579   unsigned int record_move;
580   int istatus, iret, imove;
581
582   ptree   = & tree;
583   istatus = 0;
584   if ( pdata->precord->games == pdata->max_games ) { return 1; }
585
586   if ( pdata->precord->games == 0 ) { Out( "  Parse 1 " ); }
587
588   if ( ! ( (pdata->precord->games+1) % DOT_INTERVAL ) )
589     {
590       if ( ! ( (pdata->precord->games+1) % ( DOT_INTERVAL * 10 ) ) )
591         {
592           Out( "o" );
593           if ( ! ( (pdata->precord->games+1) % ( DOT_INTERVAL * 50 ) ) )
594             {
595               Out( "%7d\n          ", pdata->precord->games+1 );
596             }
597         }
598       else { Out( "." ); }
599     }
600
601   for ( imove = 0; imove < MAX_RECORD_LENGTH; imove++ )
602     {
603       istatus = in_CSA( ptree, pdata->precord, &record_move,
604                         flag_nomake_move | flag_detect_hang | flag_nofmargin );
605       if ( istatus < 0 )
606         {
607           pdata->illegal_moves += 1;
608           break;
609         }
610       if ( istatus >= record_eof ) { break; }
611
612       if ( ! imove
613            && ( root_turn != min_posi_no_handicap.turn_to_move
614                 || HAND_B != min_posi_no_handicap.hand_black
615                 || HAND_W != min_posi_no_handicap.hand_white
616                 || memcmp( BOARD, min_posi_no_handicap.asquare, nsquare ) ) )
617         {
618           break;
619         }
620       
621       if ( ! imove )
622         {
623           *(pdata->ptree)  = *ptree;
624           pdata->root_turn = root_turn;
625         }
626
627       if ( rep_check_learn( ptree, 1 ) == four_fold_rep
628            || ( pdata->precord->moves < MAX_BOOK_PLY
629                 && book_probe_learn( ptree, pdata->pbook_entry,
630                                      pdata->precord->moves, record_move ) ) )
631         {
632           pdata->record_moves[ imove ] = record_move | MOVE_VOID;
633         }
634       else { pdata->record_moves[ imove ] = record_move; }
635
636       iret = make_move_root( ptree, record_move, flag_rejections );
637       if ( iret < 0 ) { return iret; }
638     }
639   
640   if ( istatus != record_next && istatus != record_eof )
641     {
642       istatus = record_wind( pdata->precord );
643       if ( istatus < 0 ) { return istatus; }
644     }
645   
646   if ( ! imove && istatus == record_eof ) { return 1; }
647   pdata->record_length = imove;
648
649   return 0;
650 }
651
652
653 static int
654 learn_parse2( tree_t * restrict ptree, FILE *pf_tmp, int nsteps,
655               double target_out_window, double obj_norm, int nworker )
656 {
657   parse2_data_t *pdata[ TLP_MAX_THREADS ];
658   int istep, id;
659
660   for ( id = 0; id < nworker; id++ )
661     {
662       pdata[id] = memory_alloc( sizeof(parse2_data_t) );
663       if ( pdata[id] == NULL ) { return -1; }
664   
665       pdata[id]->ptree   = NULL;
666       pdata[id]->pf_tmp  = pf_tmp;
667       pdata[id]->id      = id;
668       pdata[id]->nworker = nworker;
669     }
670
671   Out( "  Parse 2\n" );
672
673   istep = 0;
674   for ( ;; ) {
675
676 #if defined(TLP)
677     for ( id = 1; id < nworker; id++ )
678       {
679 #  if defined(_WIN32)
680         pdata[id]->ptree = tlp_atree_work + id;
681         if ( ! _beginthreadex( 0, 0, parse2_worker, pdata[id], 0, 0 ) )
682           {
683             str_error = "_beginthreadex() failed.";
684             return -1;
685           }
686 #  else
687         pthread_t pt;
688         
689         pdata[id]->ptree = tlp_atree_work + id;
690         if ( pthread_create( &pt, &pthread_attr, parse2_worker, pdata[id] ) )
691           {
692             str_error = "pthread_create() failed.";
693             return -1;
694           }
695 #  endif
696       }
697 #endif /* TLP */
698     
699     pdata[0]->ptree = ptree;
700     parse2_worker( pdata[0] );
701
702 #if defined(TLP)
703     while ( tlp_num ) { tlp_yield(); }
704 #endif
705   
706     for ( id = 0; id < nworker; id++ )
707       {
708         if ( pdata[id]->info < 0 ) { return -1; }
709       }
710
711     for ( id = 1; id < nworker; id++ )
712       {
713         add_param( &pdata[0]->param, &pdata[id]->param );
714         pdata[0]->num_moves_counted += pdata[id]->num_moves_counted;
715         pdata[0]->target            += pdata[id]->target;
716       }
717
718     if ( ! istep )
719       {
720         double target, penalty, objective_function;
721
722         penalty = calc_penalty() / obj_norm;
723         target  = ( pdata[0]->target + target_out_window ) / obj_norm;
724         objective_function = target + penalty;
725         Out( "   Moves Counted   : %d\n", pdata[0]->num_moves_counted );
726         Out( "   Objective Func. : %f %f %f\n",
727                   objective_function, target, penalty );
728         Out( "   Steps " );
729       }
730
731     param_sym( &pdata[0]->param );
732
733     renovate_param( &pdata[0]->param );
734     istep += 1;
735     if ( istep < nsteps ) { Out( "." ); }
736     else {
737       Out( ". done\n\n" );
738       break;
739     }
740     rewind( pf_tmp );
741   }
742   for ( id = 0; id < nworker; id++ ) { memory_free( pdata[id] ); }
743
744   return out_param();
745 }
746
747
748 #  if defined(_MSC_VER)
749 static unsigned int __stdcall parse2_worker( void *arg )
750 #  else
751 static void *parse2_worker( void *arg )
752 #endif
753 {
754   parse2_data_t *pdata;
755   tree_t *ptree;
756   unsigned int record_move;
757   int iret, imove, nbuf, pos_buf, turn;
758
759   iret  = 0;
760   pdata = (parse2_data_t *)arg;
761   ptree = pdata->ptree;
762
763 #if defined(TLP)
764   if ( pdata->nworker > 1 )
765     {
766       lock( &tlp_lock );
767       tlp_num += 1;
768       unlock( &tlp_lock );
769       while ( tlp_num < pdata->nworker ) { tlp_yield(); }
770     }
771 #endif
772   
773   pdata->num_moves_counted = 0;
774   pdata->info              = 0;
775   pdata->target            = 0.0;
776   ini_param( &pdata->param );
777
778   for ( ;; ) {
779 #if defined(TLP)
780     if ( pdata->nworker > 1 ) { lock( &tlp_lock ); }
781 #endif
782     iret = read_buf( pdata->buf, pdata->pf_tmp );
783 #if defined(TLP)
784     if ( pdata->nworker > 1 ) { unlock( &tlp_lock ); }
785 #endif
786
787     if ( iret <= 0 )  { break; } /* 0: eof, -2: error */
788     nbuf = iret;
789
790     iret = ini_game( ptree, &min_posi_no_handicap, flag_nofmargin,
791                      NULL, NULL );
792     if ( iret < 0 ) { break; }
793
794     turn    = black;
795     pos_buf = 2;
796     for ( imove = 0; pos_buf < nbuf; imove++ )
797       {
798         record_move = s2move( ptree, pdata->buf[pos_buf++], turn );
799
800         if ( pdata->buf[pos_buf] )
801           {
802             pos_buf = calc_deriv( pdata, pos_buf, turn );
803           }
804         pos_buf += 1;
805
806         MakeMove( turn, record_move, 1 );
807         turn                 = Flip( turn );
808         ptree->move_last[1]  = ptree->move_last[0];
809         ptree->nsuc_check[0] = 0;
810         ptree->nsuc_check[1]
811           = (unsigned char)( InCheck( turn ) ? 1U : 0 );
812       }
813   }
814
815 #if defined(TLP)
816   if ( pdata->nworker > 1 )
817     {
818       lock( &tlp_lock );
819       tlp_num -= 1;
820       unlock( &tlp_lock );
821     }
822 #endif
823
824   pdata->info = iret;
825   return 0;
826 }
827
828
829 static int
830 read_buf( unsigned short *buf, FILE *pf )
831 {
832   size_t size;
833
834   size = fread( buf, sizeof(unsigned short), 2, pf );
835   if ( ! size && feof( pf ) ) { return 0; }
836   if ( size != 2 )
837     {
838       str_error = str_io_error;
839       return -2;
840     }
841
842   size = (size_t)buf[1] + (size_t)buf[0] * 0x10000 - 2;
843   if ( fread( buf+2, sizeof(unsigned short), size, pf ) != size )
844     {
845       str_error = str_io_error;
846       return -2;
847     }
848
849   return (int)size;
850 }
851
852
853 static int
854 calc_deriv( parse2_data_t *pdata, int pos0, int turn0 )
855 {
856   double target, dT, sum_dT;
857   tree_t * restrict ptree;
858   const unsigned short *buf;
859   unsigned int nc;
860   int ply, turn, pv_length, pos, record_value, value;
861
862   ptree  = pdata->ptree;
863   buf    = pdata->buf;
864   nc     = 0;
865   turn   = turn0;
866   pos    = pos0;
867   target = 0.0;
868   sum_dT = 0.0;
869
870   ply  = 1;
871   for ( ;; ) {
872     pdata->pv[ply] = s2move( ptree, buf[ pos+ply-1 ] & 0x7fffU, turn );
873     MakeMove( turn, pdata->pv[ply], ply );
874     turn = Flip( turn );
875     if ( buf[ pos+ply-1 ] & 0x8000U ) { break; }
876     ply += 1;
877   }
878   pv_length = ply;
879
880   record_value = evaluate( ptree, ply+1, turn );
881   if ( turn != turn0 ) { record_value = -record_value; }
882
883   for ( ;; ) {
884     turn  = Flip( turn );
885     UnMakeMove( turn, pdata->pv[ply], ply );
886     if ( ply == 1 ) { break; }
887     ply -= 1;
888   }
889   pos += pv_length;
890
891   while ( buf[ pos ] ) {
892     ply  = 1;
893     for ( ;; ) {
894       pdata->pv[ply] = s2move( ptree, buf[ pos+ply-1 ] & 0x7fffU, turn );
895       MakeMove( turn, pdata->pv[ply], ply );
896       turn = Flip( turn );
897       if ( buf[ pos+ply-1 ] & 0x8000U ) { break; }
898       ply += 1;
899     }
900     pv_length = ply;
901
902     value = evaluate( ptree, ply+1, turn );
903     if ( turn != turn0 ) { value = -value; }
904     target += func( value - record_value );
905           
906     dT = dfunc( value - record_value );
907     if ( turn0 ) { dT = -dT; }
908     sum_dT += dT;
909     inc_param( ptree, &pdata->param, -dT );
910
911     for ( ;; ) {
912       turn  = Flip( turn );
913       UnMakeMove( turn, pdata->pv[ply], ply );
914       if ( ply == 1 ) { break; }
915       ply -= 1;
916     }
917
918     pos += pv_length;
919     nc  += 1;
920   }
921
922   ply  = 1;
923   for ( ;; ) {
924     pdata->pv[ply] = s2move( ptree, buf[ pos0+ply-1 ] & 0x7fffU, turn );
925     MakeMove( turn, pdata->pv[ply], ply );
926     turn = Flip( turn );
927     if ( buf[ pos0+ply-1 ] & 0x8000U ) { break; }
928     ply += 1;
929   }
930
931   inc_param( ptree, &pdata->param, sum_dT );
932
933   for ( ;; ) {
934     turn  = Flip( turn );
935     UnMakeMove( turn, pdata->pv[ply], ply );
936     if ( ply == 1 ) { break; }
937     ply -= 1;
938   }
939
940   pdata->num_moves_counted += nc;
941   pdata->target            += target;
942
943   return pos;
944 }
945
946
947 static double
948 func( double x )
949 {
950   const double delta = (double)FV_WINDOW / 7.0;
951   double d;
952   
953   if      ( x < -FV_WINDOW ) { x = -FV_WINDOW; }
954   else if ( x >  FV_WINDOW ) { x =  FV_WINDOW; }
955   d = 1.0 / ( 1.0 + exp(-x/delta) );
956
957   return d;
958 }
959
960
961 static double
962 dfunc( double x )
963 {
964   const double delta = (double)FV_WINDOW / 7.0;
965   double dd, dn, dtemp, dret;
966
967   if      ( x <= -FV_WINDOW ) { dret = 0.0; }
968   else if ( x >=  FV_WINDOW ) { dret = 0.0; }
969   else {
970     dn    = exp( - x / delta );
971     dtemp = dn + 1.0;
972     dd    = delta * dtemp * dtemp;
973     dret  = dn / dd;
974   }
975   
976   return dret;
977 }
978
979
980 static unsigned int
981 s2move( const tree_t * restrict ptree, unsigned int move, int tt )
982 {
983   int from, to;
984
985   from = I2From(move);
986   if ( from < nsquare )
987     {
988       to = I2To(move);
989       move |= tt ? (Piece2Move(-BOARD[from])|Cap2Move( BOARD[to]))
990                  : (Piece2Move( BOARD[from])|Cap2Move(-BOARD[to]));
991     }
992   return move;
993 }
994
995
996 static void
997 ini_book( book_entry_t *pbook_entry )
998 {
999   int i, j;
1000   
1001   for ( i = 0; i < NumBookEntry; i++ )
1002     for ( j = 0; j < NumBookCluster; j++ ) {
1003       pbook_entry[i].cluster[j].a = (uint64_t)0;
1004       pbook_entry[i].cluster[j].b = (uint64_t)0x1ffU << 41;
1005     }
1006 }
1007
1008
1009 /*
1010 a: key     64   0
1011
1012 b: ply      9  41
1013    move    19  22
1014    turn     1  21
1015    hand    21   0
1016 */
1017 static int
1018 book_probe_learn( const tree_t * restrict ptree,
1019                   book_entry_t *pbook_entry,
1020                   int ply, unsigned int move )
1021 {
1022   book_entry_t *p;
1023   int i, j;
1024
1025   move &= 0x7ffffU;
1026   p = pbook_entry
1027     + ((unsigned int)HASH_KEY & (unsigned int)(NumBookEntry-1));
1028
1029   for ( i = 0; i < NumBookCluster; i++ )
1030     if ( p->cluster[i].a == HASH_KEY
1031          && ((unsigned int)p->cluster[i].b & 0x1fffffU) == HAND_B
1032          && ( (((unsigned int)p->cluster[i].b>>21) & 0x1U)
1033               == (unsigned int)root_turn )
1034          && ((unsigned int)(p->cluster[i].b>>22) & 0x7ffffU) == move ) {
1035       return 1;
1036     }
1037   
1038   for ( i = 0; i < NumBookCluster; i++ )
1039     if ( ( (unsigned int)( p->cluster[i].b >> 41 ) & 0x1ffU )
1040          > (unsigned int)ply ) { break; }
1041
1042   if ( i < NumBookCluster ) {
1043     for ( j = NumBookCluster-1; j > i; j-- ) {
1044       p->cluster[j].a = p->cluster[j-1].a;
1045       p->cluster[j].b = p->cluster[j-1].b;
1046     }
1047
1048     p->cluster[i].a = HASH_KEY;
1049     p->cluster[i].b
1050       = ( (uint64_t)move<<22 ) | ( (uint64_t)ply << 41 )
1051       | (uint64_t)( (root_turn<<21) | HAND_B );
1052   }
1053
1054   return 0;
1055 }
1056
1057
1058 static int
1059 rep_check_learn( tree_t * restrict ptree, int ply )
1060 {
1061   int n, i, imin;
1062
1063   n    = root_nrep + ply - 1;
1064   imin = n - REP_MAX_PLY;
1065   if ( imin < 0 ) { imin = 0; }
1066
1067   for ( i = n-2; i >= imin; i -= 2 )
1068     if ( ptree->rep_board_list[i] == HASH_KEY
1069          && ptree->rep_hand_list[i] == HAND_B ) { return four_fold_rep; }
1070
1071   return no_rep;
1072 }
1073
1074 #endif /* no MINIMUM */