Wilson wrote: ↑Sat Sep 19, 2020 11:45 am
Dann Corbit wrote: ↑Sat Sep 19, 2020 11:12 am
Joost Buijs wrote: ↑Sat Sep 19, 2020 8:28 am
It would not be to difficult to add a lot of ideas from Stockfish and add NNUE evaluation to pimp it up 100 or 200 Elo, but I simply don't want to do this because it would give me the feeling that it is not my own engine anymore.
There is a word for this. I believe it is called "integrity."
This is an interesting answer Dann but I have a question: if we take a look at the sources of the top open source engines from CCRL or CEGT rating lists, we will see that the search function of every one of them is basically taken from Stockfish with some params tuning. We have, in the same order: Razoring, Reverse Futility Pruning, Null Move Pruning with Verification, ProbCut. Inside the moves loop: Late Move Pruning, Futility Pruning, SEE Pruning, Singular Extension, Late Move Reduction and so on. All with more or less the same implementation details, also for ProbCut for which papers have been published several years ago but everyone does it the Stockfish way. If we had a similarity tester for the search function, I believe we would have a similarity much higher than 70%.
So, my question: does that mean that these engines lack integrity?
Few months ago, I opened a thread asking what we were allowed to learn/take from open source engines (basically Stockfish since it's the strongest one) and I used the Singular Extension as example since that was the algorithm I was toying with at the time. In the end, I decided not to use it because I couldn't find an implementation different enough from SF's one that wasn't significantly weaker. If I had implemented SE the Stockfish way just to gain ELO points, then probably I would have went on taking things here and there and my engine wouldn't have been mine anymore. So, I prefer it to be relatively weak and to try new things. If my search was like everyone's else, I think the probability to find something new that works would be much lower.
I suppose Winter might not be considered a top engine, but I think its an interesting experiment.
Razoring: Not in Winter
Reverse Futility Pruning:
SF:
Code: Select all
// Step 8. Futility pruning: child node (~50 Elo)
if ( !PvNode
&& depth < 8
&& eval - futility_margin(depth, improving) >= beta
&& eval < VALUE_KNOWN_WIN) // Do not return unproven wins
return eval;
Winter:
Code: Select all
//Static Null Move Pruning
if (node_type == NodeType::kNW && depth <= 5) {
NScore margin = (kSNMPMargin - 60 * !strict_worsening) * depth;
if (settings::kUseScoreBasedPruning && static_eval.value() > beta.value() + margin
&& t.board.get_phase() > 1 * piece_phases[kQueen]) {
return beta;
}
}
In case you are wondering about the value() function, this is because Winter's scores are WDL scores, so we need to transform them into a scalar in order to be able to use margins more nicely.
Null Move Pruning with Verification: Winter does not do Null Move Verification. SF also has a ton of weird stats related restrictions that I haven't analyzed. Winter's implementation is very straightforward.
SF:
https://github.com/official-stockfish/S ... h.cpp#L818
Winter:
Code: Select all
//Null Move Pruning
if (static_eval >= beta && is_null_move_allowed(t.board, depth)) {
t.set_move(kNullMove);
t.board.Make(kNullMove);
const Depth R = 3 + depth / 5;
Score score = -AlphaBeta<NodeType::kNW, Mode>(t, -beta, -alpha,
depth - R, !expected_cut_node);
t.board.UnMake();
if (score >= beta) {
return score;
}
}
ProbCut: Not in Winter
Late Move Reduction, Late Move Pruning, Futility Pruning: Winter has all of these.
SF LMR and LMP:
Code: Select all
// Skip quiet moves if movecount exceeds our FutilityMoveCount threshold
moveCountPruning = moveCount >= futility_move_count(improving, depth);
// Reduced depth of the next LMR search
int lmrDepth = std::max(newDepth - reduction(improving, depth, moveCount), 0);
SF Futility:
Code: Select all
// Futility pruning: parent node (~5 Elo)
if ( lmrDepth < 7
&& !ss->inCheck
&& ss->staticEval + 283 + 170 * lmrDepth <= alpha
&& (*contHist[0])[movedPiece][to_sq(move)]
+ (*contHist[1])[movedPiece][to_sq(move)]
+ (*contHist[3])[movedPiece][to_sq(move)]
+ (*contHist[5])[movedPiece][to_sq(move)] / 2 < 27376)
continue;
Winter:
Code: Select all
if (i && !in_check && !(checking_squares[GetPieceType(t.board.get_piece(GetMoveSource(move)))]
& GetSquareBitBoard(GetMoveDestination(move)))) {
//Late Move Pruning
assert(depth > 0);
if ((size_t)depth < kLMP[0].size() && (i >= (size_t)kLMP[node_type == NodeType::kPV][depth])
&& GetMoveType(move) < kEnPassant) {
continue;
}
//Late Move Reduction factor
reduction = get_lmr_reduction<node_type>(depth, i, GetMoveType(move) > kDoublePawnMove);
assert(reduction < depth);
//Futility Pruning
if (node_type == NodeType::kNW && settings::kUseScoreBasedPruning
&& depth - reduction <= 3
&& static_eval.value() < (alpha.value() - get_futility_margin(depth - reduction, !strict_worsening))
&& GetMoveType(move) < kEnPassant) {
continue;
}
}
Note the GetMoveType(move) > kDoublePawnMove checks returns whether a move is forcing.
SEE Pruning: Not in Winter's AB search. I do SEE pruning in QSearch though.
Singular Extension: Winter does Singular extension.
SF:
https://github.com/official-stockfish/S ... .cpp#L1069
Winter:
Code: Select all
Depth e = 0;// Extensions
if (i == 0 && depth >= settings::kSingularExtensionDepth && valid_entry
&& entry.depth >= depth - 3 && !(node_type == NodeType::kPV && moves.size() == 1)
&& entry.get_bound() != kUpperBound && entry.get_score(t.board).is_static_eval()
&& get_singular_beta(entry.get_score(t.board), depth) > kMinStaticEval) {
SortMovesML(moves, t, tt_entry);
moves_sorted = true;
auto is_singular = move_is_singular(t, depth, moves, entry, expected_cut_node);
if (is_singular.first) {
e = 1;
}
else if (expected_cut_node && is_singular.second >= beta) {
return is_singular.second;
}
}
I could go into more detail, but honestly this post took long enough due to having to find where things are located in SF. Both programs are open source and I can gladly direct you through Winter's code if there is anything you want to see.
While I think there are definitely a lot of similarities in Winter and SF, I do think there are also a lot of differences. I'll let you make up your own mind if you feel Winter search is original. I also haven't really compared with any of the other engines around that level, so I couldn't tell you how similar they are or how different.