static CellCoordinate play_minmax(const IReferee<T>& referee, const T& board, PlayerId pid) { static constexpr int depth = 3; std::vector<CellCoordinate> choices = Heuristic::near_valid(referee, board, pid, 1); if (choices.size() > 64) return pick_best(choices, pid, board); MinMax::Node node( depth, pid, choices[0], static_cast<const Grid<Cell>&>(board), static_cast<const Referee<Grid<Cell>>&>(referee) ); std::size_t index = 0, i = 0; double best_value = node.get_value(); for (const CellCoordinate& coord : choices) { MinMax::Node alt_node( depth, pid, coord, static_cast<const Grid<Cell>&>(board), static_cast<const Referee<Grid<Cell>>&>(referee) ); if (alt_node.get_value() > best_value) { best_value = alt_node.get_value(); index = i; } if (alt_node.is_best(depth, best_value)) break; i += 1; } return choices.at(index); }
Move MovePicker::next_move() { Move move; switch (stage) { case MAIN_SEARCH: case EVASION: case QSEARCH_WITH_CHECKS: case QSEARCH_NO_CHECKS: case PROBCUT: ++stage; return ttMove; case CAPTURES_INIT: endBadCaptures = cur = moves; endMoves = generate<CAPTURES>(pos, cur); score<CAPTURES>(); ++stage; case GOOD_CAPTURES: while (cur < endMoves) { move = pick_best(cur++, endMoves); if (move != ttMove) { if (pos.see_ge(move, VALUE_ZERO)) return move; // Losing capture, move it to the beginning of the array *endBadCaptures++ = move; } } ++stage; move = ss->killers[0]; // First killer move if ( move != MOVE_NONE && move != ttMove && pos.pseudo_legal(move) && !pos.capture(move)) return move; case KILLERS: ++stage; move = ss->killers[1]; // Second killer move if ( move != MOVE_NONE && move != ttMove && pos.pseudo_legal(move) && !pos.capture(move)) return move; case COUNTERMOVE: ++stage; move = countermove; if ( move != MOVE_NONE && move != ttMove && move != ss->killers[0] && move != ss->killers[1] && pos.pseudo_legal(move) && !pos.capture(move)) return move; case QUIET_INIT: cur = endBadCaptures; endMoves = generate<QUIETS>(pos, cur); score<QUIETS>(); if (depth < 3 * ONE_PLY) { ExtMove* goodQuiet = std::partition(cur, endMoves, [](const ExtMove& m) { return m.value > VALUE_ZERO; }); insertion_sort(cur, goodQuiet); } else insertion_sort(cur, endMoves); ++stage; case QUIET: while (cur < endMoves) { move = *cur++; if ( move != ttMove && move != ss->killers[0] && move != ss->killers[1] && move != countermove) return move; } ++stage; cur = moves; // Point to beginning of bad captures case BAD_CAPTURES: if (cur < endBadCaptures) return *cur++; break; case EVASIONS_INIT: cur = moves; endMoves = generate<EVASIONS>(pos, cur); score<EVASIONS>(); ++stage; case ALL_EVASIONS: while (cur < endMoves) { move = pick_best(cur++, endMoves); if (move != ttMove) return move; } break; case PROBCUT_INIT: cur = moves; endMoves = generate<CAPTURES>(pos, cur); score<CAPTURES>(); ++stage; case PROBCUT_CAPTURES: while (cur < endMoves) { move = pick_best(cur++, endMoves); if ( move != ttMove && pos.see_ge(move, threshold)) return move; } break; case QCAPTURES_1_INIT: case QCAPTURES_2_INIT: cur = moves; endMoves = generate<CAPTURES>(pos, cur); score<CAPTURES>(); ++stage; case QCAPTURES_1: case QCAPTURES_2: while (cur < endMoves) { move = pick_best(cur++, endMoves); if (move != ttMove) return move; } if (stage == QCAPTURES_2) break; cur = moves; endMoves = generate<QUIET_CHECKS>(pos, cur); ++stage; case QCHECKS: while (cur < endMoves) { move = cur++->move; if (move != ttMove) return move; } break; case QSEARCH_RECAPTURES: cur = moves; endMoves = generate<CAPTURES>(pos, cur); score<CAPTURES>(); ++stage; case QRECAPTURES: while (cur < endMoves) { move = pick_best(cur++, endMoves); if (to_sq(move) == recaptureSquare) return move; } break; default: assert(false); } return MOVE_NONE; }
Move MovePicker::next_move() { Move move; while (true) { while (cur == endMoves && stage != STOP) generate_next_stage(); switch (stage) { case MAIN_SEARCH: case EVASION: case QSEARCH_WITH_CHECKS: case QSEARCH_WITHOUT_CHECKS: case PROBCUT: ++cur; return ttMove; case GOOD_CAPTURES: move = pick_best(cur++, endMoves); if (move != ttMove) { if (pos.see_sign(move) >= VALUE_ZERO) return move; // Losing capture, move it to the tail of the array *endBadCaptures-- = move; } break; case KILLERS: move = *cur++; if ( move != MOVE_NONE && move != ttMove && pos.pseudo_legal(move) && !pos.capture(move)) return move; break; case GOOD_QUIETS: case BAD_QUIETS: move = *cur++; if ( move != ttMove && move != killers[0] && move != killers[1] && move != killers[2]) return move; break; case BAD_CAPTURES: return *cur--; case ALL_EVASIONS: case QCAPTURES_1: case QCAPTURES_2: move = pick_best(cur++, endMoves); if (move != ttMove) return move; break; case PROBCUT_CAPTURES: move = pick_best(cur++, endMoves); if (move != ttMove && pos.see(move) > threshold) return move; break; case RECAPTURES: move = pick_best(cur++, endMoves); if (to_sq(move) == recaptureSquare) return move; break; case CHECKS: move = *cur++; if (move != ttMove) return move; break; case STOP: return MOVE_NONE; default: assert(false); } } }
Move MovePicker::next_move2() { #endif Move move; // 以下、caseのfall throughを駆使して書いてある。 switch (stage) { // 置換表の指し手を返すフェーズ case MAIN_SEARCH: case EVASION: case QSEARCH_WITH_CHECKS: case QSEARCH_NO_CHECKS: case PROBCUT: ++stage; return ttMove; case CAPTURES_INIT: endBadCaptures = cur = moves; endMoves = generateMoves<CAPTURES_PRO_PLUS>(pos, cur); score<CAPTURES>(); // CAPTUREの指し手の並べ替え。 ++stage; /* fallthrough */ // 置換表の指し手を返したあとのフェーズ // (killer moveの前のフェーズなのでkiller除去は不要) // SSEの符号がマイナスのものはbad captureのほうに回す。 case GOOD_CAPTURES: while (cur < endMoves) { move = pick_best(cur++, endMoves); if (move != ttMove) { // ここでSSEの符号がマイナスならbad captureのほうに回す。 // ToDo: moveは駒打ちではないからsee()の内部での駒打ちは判定不要なのだが。 if (pos.see_ge(move, VALUE_ZERO)) return move; // 損をするCAPTUREの指し手は、後回しにする。 *endBadCaptures++ = move; } } ++stage; // 1つ目のkiller move // ※ killer[]は32bit化されている(上位に移動後の駒が格納されている)と仮定している。 move = killers[0]; if ( move != MOVE_NONE && move != ttMove && pos.pseudo_legal_s<false>(move) && !pos.capture_or_pawn_promotion(move)) return move; /* fallthrough */ // killer moveを返すフェーズ // (直前に置換表の指し手を返しているし、CAPTURES_PRO_PLUSでの指し手も返しているのでそれらの指し手は除外されるべき) case KILLERS: ++stage; move = killers[1]; // 2つ目のkiller move if ( move != MOVE_NONE // ss->killer[0],[1]からコピーしただけなのでMOVE_NONEの可能性がある && move != ttMove // 置換表の指し手を重複除去しないといけない && pos.pseudo_legal_s<false>(move) // pseudo_legalでない指し手以外に歩や大駒の不成なども除外 && !pos.capture_or_pawn_promotion(move)) // 直前にCAPTURES_PRO_PLUSで生成している指し手を除外 return move; /* fallthrough */ // counter moveを返すフェーズ case COUNTERMOVE: ++stage; move = countermove; if ( move != MOVE_NONE && move != ttMove && move != killers[0] && move != killers[1] && pos.pseudo_legal_s<false>(move) && !pos.capture_or_pawn_promotion(move)) return move; /* fallthrough */ case QUIET_INIT: cur = endBadCaptures; endMoves = generateMoves<NON_CAPTURES_PRO_MINUS>(pos, cur); score<QUIETS>(); // 指し手を部分的にソートする。depthに線形に依存する閾値で。 partial_insertion_sort(cur, endMoves, -4000 * depth / ONE_PLY); ++stage; /* fallthrough */ // 捕獲しない指し手を返す。 // (置換表の指し手とkillerの指し手は返したあとなのでこれらの指し手は除外する必要がある) // ※ これ、指し手の数が多い場合、AVXを使って一気に削除しておいたほうが良いのでは.. case QUIET: while (cur < endMoves && (!skipQuiets || cur->value >= VALUE_ZERO)) { move = *cur++; if (move != ttMove && move != killers[0] && move != killers[1] && move != countermove) return move; } ++stage; // bad capturesの先頭を指すようにする。これは指し手生成バッファの先頭付近を再利用している。 cur = moves; /* fallthrough */ // see()が負の指し手を返す。 case BAD_CAPTURES: if (cur < endBadCaptures) return *cur++; break; // ここでcaseのfall throughは終わり。 // 回避手の生成 case EVASIONS_INIT: cur = moves; endMoves = generateMoves<EVASIONS>(pos, cur); score<EVASIONS>(); ++stage; /* fallthrough */ // 王手回避の指し手を返す case ALL_EVASIONS: while (cur < endMoves) { move = pick_best(cur++, endMoves); if (move != ttMove) return move; } break; case PROBCUT_INIT: cur = moves; endMoves = generateMoves<CAPTURES_PRO_PLUS>(pos, cur); score<CAPTURES>(); ++stage; /* fallthrough */ // 通常探索のProbCutの処理から呼び出されるとき用。 // 直前に捕獲された駒の価値以上のcaptureの指し手のみを生成する。 case PROBCUT_CAPTURES: while (cur < endMoves) { move = pick_best(cur++, endMoves); if (move != ttMove && pos.see_ge(move, threshold)) return move; } break; // 捕獲する指し手のみを生成 case QCAPTURES_1_INIT: case QCAPTURES_2_INIT: cur = moves; endMoves = generateMoves<CAPTURES_PRO_PLUS>(pos, cur); score<CAPTURES>(); ++stage; /* fallthrough */ // 残りの指し手を生成するフェーズ(共通処理) case QCAPTURES_1: case QCAPTURES_2: while (cur < endMoves) { move = pick_best(cur++, endMoves); if (move != ttMove) return move; } if (stage == QCAPTURES_2) break; cur = moves; // CAPTURES_PRO_PLUSで生成していたので、歩の成る指し手は除外された成る指し手+王手の指し手生成が必要。 // QUIET_CHECKS_PRO_MINUSがあれば良いのだが、実装が難しいので、このあと除外する。 endMoves = generateMoves<QUIET_CHECKS>(pos, cur); ++stage; /* fallthrough */ // 王手になる指し手を一手ずつ返すフェーズ // (置換表の指し手は返したあとなのでこの指し手は除外する必要がある) case QCHECKS: while (cur < endMoves) { move = cur++->move; if (move != ttMove && !pos.pawn_promotion(move) ) return move; } break; case QSEARCH_RECAPTURES: cur = moves; endMoves = generateMoves<RECAPTURES>(pos, moves, recaptureSquare); score<CAPTURES>(); // CAPTUREの指し手の並べ替え ++stage; /* fallthrough */ // 取り返す指し手。これはすでにrecaptureの指し手だけが生成されているのでそのまま返す。 case QRECAPTURES: while (cur < endMoves) { // recaptureの指し手が2つ以上あることは稀なのでここでオーダリングしてもあまり意味をなさないが、 // 生成される指し手自体が少ないなら、pick_best()のコストはほぼ無視できるのでこれはやらないよりはマシ。 move = pick_best(cur++, endMoves); //if (to_sq(move) == recaptureSquare) // return move; // → recaptureの指し手のみを生成しているのでこの判定は不要。 ASSERT_LV3(to_sq(move) == recaptureSquare); return move; } break; default: UNREACHABLE; return MOVE_NONE; } return MOVE_NONE; }
Move MovePicker::next_move<false>() { Move move; while (true) { while (cur == end) generate_next(); switch (phase) { case MAIN_SEARCH: case EVASION: case QSEARCH_0: case QSEARCH_1: case PROBCUT: cur++; return ttMove; case CAPTURES_S1: move = pick_best(cur++, end)->move; if (move != ttMove) { assert(captureThreshold <= 0); // Otherwise we cannot use see_sign() if (pos.see_sign(move) >= captureThreshold) return move; // Losing capture, move it to the tail of the array (endBadCaptures--)->move = move; } break; case KILLERS_S1: move = (cur++)->move; if ( move != MOVE_NONE && pos.is_pseudo_legal(move) && move != ttMove && !pos.is_capture(move)) return move; break; case QUIETS_1_S1: case QUIETS_2_S1: move = (cur++)->move; if ( move != ttMove && move != killers[0].move && move != killers[1].move) return move; break; case BAD_CAPTURES_S1: return (cur--)->move; case EVASIONS_S2: case CAPTURES_S3: case CAPTURES_S4: move = pick_best(cur++, end)->move; if (move != ttMove) return move; break; case CAPTURES_S5: move = pick_best(cur++, end)->move; if (move != ttMove && pos.see(move) > captureThreshold) return move; break; case CAPTURES_S6: move = pick_best(cur++, end)->move; if (to_sq(move) == recaptureSquare) return move; break; case QUIET_CHECKS_S3: move = (cur++)->move; if (move != ttMove) return move; break; case STOP: return MOVE_NONE; default: assert(false); } } }
Move MovePicker::next_move<false>() { Move move; while (true) { /* cur == endが成立するのは指し手が0ということ */ while (cur == end) generate_next_stage(); switch (stage) { /* ここにくるということは手を新たに生成していない、ttMoveで十分ということなのでttMoveをかえす */ case MAIN_SEARCH: case EVASION: case QSEARCH_0: case QSEARCH_1: case PROBCUT: ++cur; return ttMove; /* CAPTURES_S1で手が生成できたとき(他の指し手は生成していない)ここにくる pick_best関数でもっとも点数のよかった手を返す、 静止探索して評価値が0を下回らない(駒の取り合いに勝つか引き分け) 静止探索してマイナスになるようなら取る手の着手リストはendBadCapturesの指す 位置に移動し、最初から着手リストがなくなるまでつづける(cur == end)が成立するまで */ case CAPTURES_S1: move = pick_best(cur++, end)->move; if (move != ttMove) { if (pos.see_sign(move) >= VALUE_ZERO) return move; // Losing capture, move it to the tail of the array (endBadCaptures--)->move = move; } break; case KILLERS_S1: move = (cur++)->move; if ( move != MOVE_NONE && move != ttMove && pos.pseudo_legal(move) && !pos.capture(move)) return move; break; case QUIETS_1_S1: case QUIETS_2_S1: move = (cur++)->move; if ( move != ttMove && move != killers[0].move && move != killers[1].move && move != killers[2].move && move != killers[3].move && move != killers[4].move && move != killers[5].move) return move; break; case BAD_CAPTURES_S1: return (cur--)->move; case EVASIONS_S2: case CAPTURES_S3: case CAPTURES_S4: move = pick_best(cur++, end)->move; if (move != ttMove) return move; break; case CAPTURES_S5: move = pick_best(cur++, end)->move; if (move != ttMove && pos.see(move) > captureThreshold) return move; break; case CAPTURES_S6: move = pick_best(cur++, end)->move; if (to_sq(move) == recaptureSquare) return move; break; case QUIET_CHECKS_S3: move = (cur++)->move; if (move != ttMove) return move; break; case STOP: return MOVE_NONE; default: assert(false); } } }
static CellCoordinate play_near_d2_best(const IReferee<T>& referee, const T& board, PlayerId pid) { return pick_best(Heuristic::near_valid(referee, board, pid, 2), pid, board); }
int Zoltan_PHG_CoarsePartition( ZZ *zz, HGraph *phg, /* Input: coarse hypergraph -- distributed! */ int numPart, /* Input: number of partitions to generate. */ float *part_sizes, /* Input: array of size numPart listing target sizes (% of work) for the partitions */ Partition part, /* Input: array of initial partition assignments. Output: array of computed partition assignments. */ PHGPartParams *hgp /* Input: parameters to use. */ ) { /* * Zoltan_PHG_CoarsePartition computes a partitioning of a hypergraph. * Typically, this routine is called at the bottom level in a * multilevel scheme (V-cycle). * It gathers the distributed hypergraph to each processor and computes * a decomposition of the serial hypergraph. * It computes a different partition on each processor * using different random numbers (and possibly also * different algorithms) and selects the best. */ char *yo = "Zoltan_PHG_CoarsePartition"; int ierr = ZOLTAN_OK; int i, si, j; static PHGComm scomm; /* Serial communicator info */ static int first_time = 1; HGraph *shg = NULL; /* Serial hypergraph gathered from phg */ int *spart = NULL; /* Partition vectors for shg. */ int *new_part = NULL; /* Ptr to new partition vector. */ float *bestvals = NULL; /* Best cut values found so far */ int worst, new_cand; float bal, cut, worst_cut; int fine_timing = (hgp->use_timers > 2); struct phg_timer_indices *timer = Zoltan_PHG_LB_Data_timers(zz); int local_coarse_part = hgp->LocalCoarsePartition; /* Number of iterations to try coarse partitioning on each proc. */ /* 10 when p=1, and 1 when p is large. */ const int num_coarse_iter = 1 + 9/zz->Num_Proc; ZOLTAN_TRACE_ENTER(zz, yo); if (fine_timing) { if (timer->cpgather < 0) timer->cpgather = Zoltan_Timer_Init(zz->ZTime, 1, "CP Gather"); if (timer->cprefine < 0) timer->cprefine = Zoltan_Timer_Init(zz->ZTime, 0, "CP Refine"); if (timer->cpart < 0) timer->cpart = Zoltan_Timer_Init(zz->ZTime, 0, "CP Part"); ZOLTAN_TIMER_START(zz->ZTime, timer->cpart, phg->comm->Communicator); } /* Force LocalCoarsePartition if large global graph */ #define LARGE_GRAPH_VTX 64000 #define LARGE_GRAPH_PINS 256000 if (phg->dist_x[phg->comm->nProc_x] > LARGE_GRAPH_VTX){ /* TODO: || (global_nPins > LARGE_GRAPH_PINS) */ local_coarse_part = 1; } /* take care of all special cases first */ if (!strcasecmp(hgp->coarsepartition_str, "no") || !strcasecmp(hgp->coarsepartition_str, "none")) { /* Do no coarse partitioning. */ /* Do a sanity test and mapping to parts [0,...,numPart-1] */ int first = 1; PHGComm *hgc=phg->comm; Zoltan_Srand_Sync (Zoltan_Rand(NULL), &(hgc->RNGState_col), hgc->col_comm); if (hgp->UsePrefPart) { for (i = 0; i < phg->nVtx; i++) { /* Impose fixed vertex/preferred part constraints. */ if (phg->pref_part[i] < 0) { /* Free vertex in fixedvertex partitioning or repart */ /* randomly assigned to a part */ part[i] = Zoltan_Rand_InRange(&(hgc->RNGState_col), numPart); } else { if (phg->bisec_split < 0) /* direct k-way, use part numbers directly */ part[i] = phg->pref_part[i]; else /* recursive bisection, map to 0-1 part numbers */ part[i] = (phg->pref_part[i] < phg->bisec_split ? 0 : 1); } } } else { for (i = 0; i < phg->nVtx; i++) { if (part[i] >= numPart || part[i]<0) { if (first) { ZOLTAN_PRINT_WARN(zz->Proc, yo, "Initial part number > numParts."); first = 0; ierr = ZOLTAN_WARN; } part[i] = ((part[i]<0) ? -part[i] : part[i]) % numPart; } } } } else if (numPart == 1) { /* everything goes in the one partition */ for (i = 0; i < phg->nVtx; i++) part[i] = 0; } else if (!hgp->UsePrefPart && numPart >= phg->dist_x[phg->comm->nProc_x]) { /* more partitions than vertices, trivial answer */ for (i = 0; i < phg->nVtx; i++) part[i] = phg->dist_x[phg->comm->myProc_x]+i; } else if (local_coarse_part) { /* Apply local partitioner to each column */ ierr = local_coarse_partitioner(zz, phg, numPart, part_sizes, part, hgp, hgp->CoarsePartition); } else { /* Normal case: * Gather distributed HG to each processor; * compute different partitioning on each processor; * select the "best" result. */ ZOLTAN_PHG_COARSEPARTITION_FN *CoarsePartition; /* Select different coarse partitioners for processors here. */ CoarsePartition = hgp->CoarsePartition; if (CoarsePartition == NULL) { /* auto */ /* Select a coarse partitioner from the array of coarse partitioners */ CoarsePartition = CoarsePartitionFns[phg->comm->myProc % NUM_COARSEPARTITION_FNS]; } if (phg->comm->nProc == 1) { /* Serial and parallel hgraph are the same. */ shg = phg; } else { /* Set up a serial communication struct for gathered HG */ if (first_time) { scomm.nProc_x = scomm.nProc_y = 1; scomm.myProc_x = scomm.myProc_y = 0; scomm.Communicator = MPI_COMM_SELF; scomm.row_comm = MPI_COMM_SELF; scomm.col_comm = MPI_COMM_SELF; scomm.myProc = 0; scomm.nProc = 1; first_time = 0; } scomm.RNGState = Zoltan_Rand(NULL); scomm.RNGState_row = Zoltan_Rand(NULL); scomm.RNGState_col = Zoltan_Rand(NULL); scomm.zz = zz; /* * Gather parallel hypergraph phg to each processor, creating * serial hypergraph shg. */ if (fine_timing) { ZOLTAN_TIMER_STOP(zz->ZTime, timer->cpart, phg->comm->Communicator); ZOLTAN_TIMER_START(zz->ZTime, timer->cpgather, phg->comm->Communicator); } ierr = Zoltan_PHG_Gather_To_All_Procs(zz, phg, hgp, &scomm, &shg); if (ierr < 0) { ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Error returned from gather."); goto End; } if (fine_timing) { ZOLTAN_TIMER_STOP(zz->ZTime, timer->cpgather, phg->comm->Communicator); ZOLTAN_TIMER_START(zz->ZTime, timer->cpart, phg->comm->Communicator); } } /* * Allocate partition array spart for the serial hypergraph shg * and partition shg. */ spart = (int *) ZOLTAN_CALLOC(shg->nVtx * (NUM_PART_KEEP+1), sizeof(int)); bestvals = (float *) ZOLTAN_MALLOC((NUM_PART_KEEP+1)*sizeof(int)); if ((!spart) || (!bestvals)) { ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Out of memory."); ierr = ZOLTAN_MEMERR; goto End; } /* Compute several coarse partitionings. */ /* Keep the NUM_PART_KEEP best ones around. */ /* Currently, only the best one is used. */ /* Set RNG so different procs compute different parts. */ Zoltan_Srand(Zoltan_Rand(NULL) + zz->Proc, NULL); new_cand = 0; new_part = spart; for (i=0; i< num_coarse_iter; i++){ int savefmlooplimit=hgp->fm_loop_limit; /* Overwrite worst partition with new candidate. */ ierr = CoarsePartition(zz, shg, numPart, part_sizes, new_part, hgp); if (ierr < 0) { ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Error returned from CoarsePartition."); goto End; } /* time refinement step in coarse partitioner */ if (fine_timing) { ZOLTAN_TIMER_STOP(zz->ZTime, timer->cpart, phg->comm->Communicator); ZOLTAN_TIMER_START(zz->ZTime, timer->cprefine, phg->comm->Communicator); } /* UVCUVC: Refine new candidate: only one pass is enough. */ hgp->fm_loop_limit = 1; Zoltan_PHG_Refinement(zz, shg, numPart, part_sizes, new_part, hgp); hgp->fm_loop_limit = savefmlooplimit; /* stop refinement timer */ if (fine_timing) { ZOLTAN_TIMER_STOP(zz->ZTime, timer->cprefine, phg->comm->Communicator); ZOLTAN_TIMER_START(zz->ZTime, timer->cpart, phg->comm->Communicator); } /* Decide if candidate is in the top tier or not. */ /* Our objective is a combination of cuts and balance */ bal = Zoltan_PHG_Compute_Balance(zz, shg, part_sizes, 0, numPart, new_part); cut = Zoltan_PHG_Compute_ConCut(shg->comm, shg, new_part, numPart, &ierr); /* Use ratio-cut as our objective. There are many other options! */ bestvals[new_cand] = cut/(MAX(2.-bal, 0.0001)); /* avoid divide-by-0 */ if (ierr < 0) { ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Error returned from Zoltan_PHG_Compute_ConCut."); goto End; } if (i<NUM_PART_KEEP) new_cand = i+1; else { /* find worst partition vector, to overwrite it */ /* future optimization: keep bestvals sorted */ worst = 0; worst_cut = bestvals[0]; for (j=1; j<NUM_PART_KEEP+1; j++){ if (worst_cut < bestvals[j]){ worst_cut = bestvals[j]; worst = j; } } new_cand = worst; } new_part = spart+new_cand*(shg->nVtx); } /* Copy last partition vector such that all the best ones are contiguous starting at spart. */ for (i=0; i<shg->nVtx; i++){ new_part[i] = spart[NUM_PART_KEEP*(shg->nVtx)+i]; } /* Also update bestvals */ bestvals[new_cand] = bestvals[NUM_PART_KEEP]; /* Evaluate and select the best. */ /* For now, only pick the best one, in the future we pick the k best. */ ierr = pick_best(zz, hgp, phg->comm, shg, numPart, MIN(NUM_PART_KEEP, num_coarse_iter), spart, bestvals); if (ierr < 0) { ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Error returned from pick_best."); goto End; } if (phg->comm->nProc > 1) { /* Map gathered partition back to 2D distribution */ for (i = 0; i < phg->nVtx; i++) { /* KDDKDD Assume vertices in serial HG are ordered by GNO of phg */ si = VTX_LNO_TO_GNO(phg, i); part[i] = spart[si]; } Zoltan_HG_HGraph_Free(shg); ZOLTAN_FREE(&shg); } else { /* single processor */ for (i = 0; i < phg->nVtx; i++) part[i] = spart[i]; } ZOLTAN_FREE(&spart); ZOLTAN_FREE(&bestvals); } End: if (fine_timing) ZOLTAN_TIMER_STOP(zz->ZTime, timer->cpart, phg->comm->Communicator); ZOLTAN_TRACE_EXIT(zz, yo); return ierr; }
Move MovePicker::next_move(bool skipQuiets) { Move move; switch (stage) { case MAIN_SEARCH: case EVASION: case QSEARCH_WITH_CHECKS: case QSEARCH_NO_CHECKS: case PROBCUT: ++stage; return ttMove; case CAPTURES_INIT: endBadCaptures = cur = moves; endMoves = generate<CAPTURES>(pos, cur); score<CAPTURES>(); ++stage; /* fallthrough */ case GOOD_CAPTURES: while (cur < endMoves) { move = pick_best(cur++, endMoves); if (move != ttMove) { if (pos.see_ge(move)) return move; if ( type_of(pos.piece_on(to_sq(move))) == KNIGHT && type_of(pos.moved_piece(move)) == BISHOP && (cur-1)->value > 1090) return move; // Losing capture, move it to the beginning of the array *endBadCaptures++ = move; } } ++stage; move = killers[0]; // First killer move if ( move != MOVE_NONE && move != ttMove && pos.pseudo_legal(move) && !pos.capture(move)) return move; /* fallthrough */ case KILLERS: ++stage; move = killers[1]; // Second killer move if ( move != MOVE_NONE && move != ttMove && pos.pseudo_legal(move) && !pos.capture(move)) return move; /* fallthrough */ case COUNTERMOVE: ++stage; move = countermove; if ( move != MOVE_NONE && move != ttMove && move != killers[0] && move != killers[1] && pos.pseudo_legal(move) && !pos.capture(move)) return move; /* fallthrough */ case QUIET_INIT: cur = endBadCaptures; endMoves = generate<QUIETS>(pos, cur); score<QUIETS>(); partial_insertion_sort(cur, endMoves, -4000 * depth / ONE_PLY); ++stage; /* fallthrough */ case QUIET: while ( cur < endMoves && (!skipQuiets || cur->value >= VALUE_ZERO)) { move = *cur++; if ( move != ttMove && move != killers[0] && move != killers[1] && move != countermove) return move; } ++stage; cur = moves; // Point to beginning of bad captures /* fallthrough */ case BAD_CAPTURES: if (cur < endBadCaptures) return *cur++; break; case EVASIONS_INIT: cur = moves; endMoves = generate<EVASIONS>(pos, cur); score<EVASIONS>(); ++stage; /* fallthrough */ case ALL_EVASIONS: while (cur < endMoves) { move = pick_best(cur++, endMoves); if (move != ttMove) return move; } break; case PROBCUT_INIT: cur = moves; endMoves = generate<CAPTURES>(pos, cur); score<CAPTURES>(); ++stage; /* fallthrough */ case PROBCUT_CAPTURES: while (cur < endMoves) { move = pick_best(cur++, endMoves); if ( move != ttMove && pos.see_ge(move, threshold)) return move; } break; case QCAPTURES_1_INIT: case QCAPTURES_2_INIT: cur = moves; endMoves = generate<CAPTURES>(pos, cur); score<CAPTURES>(); ++stage; /* fallthrough */ case QCAPTURES_1: case QCAPTURES_2: while (cur < endMoves) { move = pick_best(cur++, endMoves); if (move != ttMove) return move; } if (stage == QCAPTURES_2) break; cur = moves; endMoves = generate<QUIET_CHECKS>(pos, cur); ++stage; /* fallthrough */ case QCHECKS: while (cur < endMoves) { move = cur++->move; if (move != ttMove) return move; } break; case QSEARCH_RECAPTURES: cur = moves; endMoves = generate<CAPTURES>(pos, cur); score<CAPTURES>(); ++stage; /* fallthrough */ case QRECAPTURES: while (cur < endMoves) { move = pick_best(cur++, endMoves); if (to_sq(move) == recaptureSquare) return move; } break; default: assert(false); } return MOVE_NONE; }