This is what actually is.
A standard naming convention suggests to name a variable
with someting resembling _what_ the variable is and not
_how_ the variable is used. This normally results
in easier to read code.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
More aggressive LMR reductions.
Tested at different time controls:
- Tested with 1CPU 1+0, after 3000 games, result was +12 ELO
- Tested this with 4CPU 1+0 and got sth around 5-10 ELO increase
- Last one at long time control,after ~1000 games with 10+0 result is:
Orig - Mod: 491 - 520 (+10 elo)
A testing marathon by Joona for this important change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Master thread returns from idle_loop() when sp->cpus == 0,
but cpus is decremented by slave threads under sp->lock,
so it could happen that we return in split(), where we release
the split point, with sp->lock still held.
This patch guarantees that sp->lock is released when returning
to split().
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Almost no change and simplifies a bit the code.
After 961 games at 1+0
Mod vs Orig +156 =650 -146 +4 ELO
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Re-save the same TT entry if value is usable and allow
us to cut-off, it means that entry is valuable and
we want to keep it fresh updating the 'generation'
parameter up to the current value.
Patch suggested by J. Wesley Cleveland and better
clarified by Miguel A. Ballicora.
After 999 games at 1+0 64MB hash size
Mod vs Orig +167 =677 -155 +4 ELO
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Should be a very minor change, but there is a small
functional change because futility_margin() is used in more
places then in the pruning formula.
After 999 games at 1+0
Mod vs Orig +167 =678 -154 +5 ELO
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Revert all the patches that introduced the change and
more or less fixed the zugzwang issue.
There is a gain against last current version and we
can remove a lot of code.
After 979 games at 1+0 on my QUAD
Mod vs Orig +152 =688 -139 +5 ELO
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Real search is considered of higher quality then null
search one.
This allows to fix the zugzwang issue with a minimal
impact on ELO.
Zugzwang verified on position:
8/7P/8/8/K2b4/p7/1k6/1B6 b - -
After 999 games at 1+0 on my QUAD
Mod vs Orig(94bb196) +168 =657 -174 -2 ELO
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Is a boolean option that when set allows Stockfish
to select the best book move across the possible ones.
Feature requested by Salvo Spitaleri.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Avoid incorrect mate scores in positions like
BK5/1R4b1/2k1Np2/3p3b/2p3pq/p1rB4/n2n1p2/8 w - -
Thanks for Jouni Uski for reporting the problem
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
This is the world's fussiest compiler with +w1
Warnings reported by Richard Lloyd.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Add an UCI option "Zugzwang detection" OFF by default that
enables correct detection of zugzwang.
This is just to let 1.7.1 be 100% compatible with 1.7 and
should be removed after release.
Verified 100% functional equivalent to 1.7
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
It fails in test position:
8/7P/8/8/K2b4/p7/1k6/1B6 b - -
Not clear why but we revert because it fixes the issue.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
In this case use a normal VALUE_TYPE_LOWER TT type instead of
VALUE_TYPE_NS_LO. This allow us to TT cut-off in a bit more nodes.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
This patch fixes an issue with zugzwang well explained by Tord:
"Assume that a zugzwang position occurs at iteration N,
at a search depth d, with d < 6*OnePly. The null move search
fails high, and no verification search is done, because the
depth is too small. The position gets stored in the transposition
table with a good score and a depth of d.
Now, consider what happens when the same position occurs at iteration
N+1, this time with a depth of d+OnePly (i.e. one ply deeper than at
the previous iteration). Once again, the null move search fails
high. The point is that the verification search will also fail high,
because of an instant transposition table cutoff caused by the value
stored in the TT during the previous iteration."
With this patch we simply do not allow TT cutoffs at the root node
of a null move verification search if the TT value was found by a
null search.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Add VALUE_TYPE_NS_LO to enum ValueType and use it when
saving in TT a value from a null search.
Currently no action is performed, the next patch will enable
the new type.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Reported warning is:
warning #2514-D: pointless comparison of unsigned
integer with a negative constant
Spotted by Richard Lloyd.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Use full depth, not reduced one. This allows
to avoid to do a null search when in the same
position and at the same or bigger depth the
null search failed high.
A very small increase, if any.
After 963 games at 1+0
Mod vs Orig: +158 =657 -147 +4 ELO
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
After previous patch we don't need any more the call parameters.
This fixes a couple of warnings under MSVC.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
After 500 games at 5+0 on my QUAD (3 days) there
is no difference with old version, so probably it
is a feature that doesn't scale with search depth.
So revert for now, perhaps we should readd under a
different form.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
MSVC complains about an implicit conversion from double to int.
Also small comments tweaks.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
In the beginning use milder reduction and at the end be
more aggressive.
After 1500 games on Joona's QUAD
Mod - Orig: 791 - 720 +16 elo
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Causes very small functional change which is not observable with
our usual set of test positions.
However change is observable fx. with following position:
4k3/3r4/5Q2/6K1/8/8/8/8 w - - 0 1
go depth 24
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
If null search fails high return null value instead of beta.
With TT hash there may be a small advantage for fail-soft since
storing slightly better bounds may cause slightly more hash hits.
After 990 games at 1+0
Mod vs Orig +171 =665 -154 +6 ELO
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Array castleRightsMask[] is not static because it can
be different for different positions, so let it be
a Position member data. This allows to remove tricky
hacks to take in account that although it was defined
static it could change.
Theoretically now copying a position is a bit slower because
we need to copy also an array of 64 integers, but because in
split() we don't copy the position anymore, but just keep the
pointer, the added burden is not mesurable even in MP case.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Currently, in case of fail high/low we research with
a window increased by 2*AspirationDelta at first
attempt, this patch instead makes the research be
done with an increase of just AspirationDelta size,
in case of a consecutive fail we will widen to
2*AspirationDelta and so on.
After Joona's test:
Orig - Mod: 850 - 890
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
One for failing highs and one for failing lows, this
should reduce average window size in case of positions
that fail first high and then low (or the contrary).
After ~2000 games on Joona's quad we have:
Mod - Orig: 1012- 975 (+6 elo)
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Instead to leave uninitialized or scattered in the code
as is the case for ExtraSearchTime.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Currently we use original sorting after a fail low to
research at wider window. This patch instead sorts the
moves according to the last available move's scores.
Strangely no functional change, but should be.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Changed FutilityMarginsMatrix dimensions to be a power of two
so that compiler can produce a faster accessing code.
Introduced print_pv_info() to remove some redundant code in
root_search()
Remaining stuff is triviality and documentation tweaks.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Under Windows we use CreateThread() to setup threads and
we pass a pointer to a variable that receives the thread
identifier, but this parameter is optional and we don't
use it, so remove it.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
It happens that NULL is 0, but the conventional meaning is of
a zero pointer, so repleace with an explicit 0 integer value.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Consider sligtly negative captures as good if at low
depth and far from beta.
After 999 games at 1+0
Mod vs Orig +169 =694 -136 +11 ELO
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
It raises an assert under Windows, it is not clear why but it
happens that idle_loop() is called with incorrect threadID and
the assert triggered is:
assert(threadID >= 0 && threadID < MAX_THREADS);
So revert the patch for now, but we should understand why it
fails.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
We can't do it with full guarantee anyway because
there is always a possible race between the setting of
state to THREAD_SLEEPING and actual sleeping.
So just remove the not perfect code to avoid misunderstandings.
This reflects what we have done in wake_sleeping_threads() in
the previous patch.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Currently there is no guarantee that threads are sleeping
when calling wake_sleeping_threads() because put_threads_to_sleep()
returns without waiting for threads to actually sleep.
Assert can be easily triggered calling put_threads_to_sleep() and
wake_sleeping_threads() in a tight loop.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
This option likely has very low meaning for playing strength and style,
so I see no need to keep this configurable
No functional change
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
search() is used as a "leading star" and other routines
are modified according to it.
No functional change
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Was broken and fixing would be too messy.
Now this option is only activated in single thread mode
No functional change
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Just to avoid misunderstandings.
True staticValue is available through search stack
No functional change
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
I cannot see connection between the two.
Also add one FIXME for illogical behaviour
No functional change
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
I don't know if enumerating sections is a good idea,
but for me code is more readable this way
No functional change
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
I cannot see any reason to do this. Even this is not enough to fix
theoretical race case on Windows which doesn't seem to cause any
problems in practice anyhow
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Resurrect extra check for sleeping in POSIX code.
This necessary to prevent ugly races between
thread_broadcast and thread_cond_wait.
After thread has woken up, it marks itself as available.
Another thread must not do this, because of possible race.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
So we can use a const value instead of a pointer in
split().
Also pass NULL instead of a faked address of alpha in
case split is called from a non-PV node.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Joona says that sp_update_pv() does not pass the split point
boundaries, so there is no risk to corrupt data from another
split point. Also the race on thread_should_stop() is harmless
because of this.
So revert the patch and come back to single lock.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Joona says:
1. We should not be afraid of "AllThreadsShouldExit" flag.
Because when this is set to true we _must_not_ be searching (= All
splits must have been undone).
And if we are not searching it's impossible that some other thread
could give us work to do. So setting state to THREAD_AVAILABLE
doesn't do any harm. If you want to add check for this, you could do
it like this:
if (threads[threadID].state == THREAD_WORKISWAITING)
{
+ assert(!AllThreadsShouldExit)
threads[threadID].state = THREAD_SEARCHING;
2a. If waitSp->cpus == 0, setting state to THREAD_AVAILABLE makes
no harm either, because helpful master concept dictates that _only_
our own slave can book us. If we don't have any slaves, noone has the
right to book us.
2b. If point (2a) is not correct then your extra check only adds extra race:
In smp code checking for waitSp->cpus > 0 is not enough. It's possible that
our slave immediately exits and another thread
books us as a slave when our state is still
THREAD_AVAILABLE. So instead of adding extra level of security we have
just introduced extra race.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
When we found a cut-off then lock all the split point chain,
not only current one to avoid races in case two threads running
on different split points where one is ancestor then the other,
find a beta cut-off at the same time, in this case we want only
one to call sp_update_pv().
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
This is a per split-point request, not per-thread. When we find
a beta cut-off in current thread's split point or in or in some
ancestor of the current split point then threads should stop
immediately the search and return to idle_loop().
The check is done by thread_should_stop() that now looks only
at split point's chain.
No functional change and a good semplification.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
This is easier to follow and also reduces the points
where state changes to mainly idle_loop() and split().
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
This is because when we are below 4 * OnePly, the null move
will directly jump to qsearch and if we are below beta,
our opponent is above beta and will get immediate
stand pat cut off.
So basically this patch is just optimizing away useless
evaluation calls. dbg_hit_on() runs show that this heuristic
is correct >99% of cases. Transposition table probably causes
some inaccurary?
After 1148 games on QUAD
mod-orig: 583 - 565 +5 elo
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
In this case is dangerous because in split() we reset the flag to
false, but if it was set due to a cut-off higher in the tree we
completely miss that and go on with the full search.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Instead of other flags this is not a state flag, i.e. does
not defines a state for the thread, but a request because
after we raise 'stopRequest' flag the corresponding thread is
not stopped, but continues to run for a while until it returns
from sp_search() in idle_loop.
It is important the name reflects this.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Among them 'stop' and 'printCurrentLineRequest' could have
random value, so reset to a known state before to leave the
search.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
This is the first nice effect of previous patch !
Because thread_should_stop() should be declared 'const' we
need to remove the setting of 'stop' flag to true that
turns out to be a bug because thread_should_stop() is called
outside from lock protection while 'stop' flag is a volatile
shared variable so cannot be changed when not in lock.
Note that this bugs fires ONLY when we use more then 2 threads,
so commonly only in a QUAD or OCTAL machine.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Main aim of this patch is to consolidate all the thread related stuff
behind a single class interface so to avoid messing with global flags
and having thread code scattered among non-thread related stuff.
Another advantage is that now access to thread's variables is
more controlled, in particular we can differentiate between
read and write accesses by the mean of different interfaces, it
is so simpler to understand how a function is related to threads.
Lastly this rewrite is the base for future code consolidations and
semplifications that are easier now that we have only one thread's
access point.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Ensure threads are sleeping when leaving init_threads() and
the newly introduced put_threads_to_sleep().
Also ensure threads are not sleeping when leaving
wake_sleeping_threads().
As a side effect we now leave think() with all the threads
(but the main one) guaranteed to sleep. So when we enter
again in think(), after the opponent next move, we know
threads must be sleeping.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Wait inside wake_sleeping_threads() for the threads to be
effectively and reliably woken up.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Will be used by future patches. Also:
- Renamed Idle in AllThreadsShouldSleep
- Explicitly inited AllThreadsShouldExit and AllThreadsShouldSleep
in init_thread() instead of use an anonymous global initialization.
- Rewritten idle_loop() while condition to avoid a 'break' statement
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
It is an hidden bug waiting to fire. The main problem is
that ss[ply] is overwritten by search() and qsearch() called
from IID and razoring, so that we cannot hold a pointer to a
local EvalInfo variable.
For instance if we go razoring then we overwrite the pointer
with the address of a variable local to qsearch(), when we return
from qsearch() variable goes out of scope and now ss[ply].evalInfo
holds a stale pointer !
Because we are not looking for troubles we go through the
safe route and we remove it entirely.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
In search routines we use information from previous ply
and init killers two plies ahead.
So for me it seems correct to copy 4 searchstack items
in split:
ply - 1, ply, ply + 1, ply + 2
Because
a) we do not split at root (ply == 0)
b) ply < PLY_MAX and SearchStack size is PLY_MAX_PLUS_2
there should be no risk of underflows or overflows
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
It was only used to control StopOnPonderHit variable.
Now use FailLow variable instead.
Patch has a minor effect on time management when ponder is on.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
noProblemFound condition is never true.
This was verified by running 800 games 1+0 match in 1 CPU computer.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Instead of piece-from-to, in this way it is similar
to what we already do for history.
Almost no change, but seems a bit simpler in this way.
After 995 games at 1+0
Mod vs Orig +207 =596 -192 +5 ELO
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
It seems more standard conformant. Also added a bit of
description directly from Tord.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Futility captures alone does not seem an improvment.
Perhaps is a combination of stand pat + futility that is winning,
so revert for now and continue testing starting from a standard
base until we find the correct receipe.
After 999 games at 1+0
Mod vs Orig +231 0506 -201 +10 ELO
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Not a biggie but is a reduced pruned patch that doesn't
seems to hurt, so it is welcomed ;-)
After 999 games at 1+0
Mod vs Orig +207 =601 -191 +6 ELO
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
At ply == OnePly (common case) we avoid some useless
floating point computation.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Joona new aspiration window. Main idea is to always
research aspiration fail highs/low at the same
ply and use much smaller aspiration window than previously.
Testing result is very positive.
1CPU:
953-1149
4CPU:
545 - 656
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Avoid to take the lock two times in a tight sequence, the first
in get_next_move() and the second to update sp->moves.
Do all with one lock and so retire the now useless locked version
of get_next_move().
Also fix some theorical race due to comparison sp->bestValue < sp->beta
is done out of lock protection. Finally fix another (harmless but time
waster) race that coudl occur because thread_should_stop() is also
called outside of lock protection.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
In debug run with 2 threads it happens to be following
assert after some minutes:
assert(value > -VALUE_INFINITE && value < VALUE_INFINITE);
in search(), line 1615.
I am not able to understand why, anyhow reverted for the moment.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
This avoid us to forget some very needed tests now that
futility has changed in a whole big chunk we need to fine
tuning every splitted change.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
This will be useful to use gains table in move
ordering along with history table.
No functional change and big code remove.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
With current search control system, I can see absolutely no
reason to classify fixed time search as infinite search.
So remove old dated hack
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
In less then 1% of cases value > sp->bestValue, so avoid
an useless lock in the common case. This is the same change
already applied to sp_search().
Also SplitPoint futilityValue is not volatile because
never changes after has been assigned in split()
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
When we have more then 2 threads then we do an array
access with index 'Threads[slave].activeSplitPoints - 1'
This should be >= 0 because we tested the variable just
few statements before, but because is a shared variable
it could be that the 'slave' thread set the value to zero
just after we test it, so that when we use the decremented
variable for array access we crash.
Bug spotted by Bruno Causse.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Unify start loop for master and slave threads. Also guarantee
that all the 'stop' flags are set to false before first slave
is started, should be no harm because only master thread can
reset 'stop' flag of slaves to true, so should be no race but
better safe then sorry.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Only pure blocking evasions are candidate
for pruning.
After 998 games at 1+0
Mod vs Orig +215 =596 -187 +10 ELO
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
When pondering threads are put to sleep, but when thinking
the threads are parked in idle_loop in a tight polling loop
checking for workIsWaiting falg.
So before we set the slave's flag workIsWaiting we have to
guarantee that all the slave data is already setup because
slave can start in any moment from there.
Rearrange the last loop to fix this race.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Once we have allocated our slave threads and we have removed
master from available threads we can safely remove the lock
so that the lenghty search stack copy operation will not
impact lock contention.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
A pointer is enough because after a split point has been
setup master and slaves thread end up calling sp_search() or
sp_search_pv() and here a full copy of split point position is
done again, note that even master does another copy (of itself)
and this is done before any do_move() call so that master Position
is never updated between split() and sp_search().
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
And detach splitPoint Position from the master one.
So we duplicate StateInfo only once in split() instead
of one for each thread in sp_search
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Renamed a bit the functions to be more clear what
we actually are doing when we craete a Position object
and explained how StateInfo works.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Only the previous, the current and the next ply SearchStack
are copied.
This reduces split overhead especially at low depth (high ply)
and with many threads.
Possibly no functional change (it is not easy to prove in SMP)
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
The init_eval() function corrupted the static array castleRightsMask[]
in the Position class, resulting in instant crashes in most Chess960
games. Fixed by repairing the damage directly after the function is
called. Also modified the Position::to_fen() function to display
castle rights correctly for Chess960 positions, and added sanity checks
for uncastled rook files in Position::is_ok().
It is a good programming practice to verify a system
call has indeed succeed.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
When a search fails high then sp->alpha is increased and
slave threads are requested to stop.
So we have to check for a stop request before to start a search
otherwise we could end up with sp->alpha >= sp->beta
leading to an assert in debug run in search_pv().
This patch fixes the assert and get rid of some of possible races.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
maximum depth during a "go movetime ..." search. This prevents
Stockfish from hanging forever after finding a mate in two or
three while running a test suite at a level of a few seconds
per move.
No functional change when playing games at normal time controls.
In qsearch() try to get a cutoff with the help of an
extra check if we are already very near.
Small increase in actual games but a good result in tactical
test sets where this patch makes SF more tactical.
Mod vs Orig +197 =620 -181 +6 ELO
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Value is never used un-initialized, but MSVC is not
smart enough to detect itself :-(
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Now that we have position static score we don't
need to call evaluate() a second time.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
This will allow to have wider access to attack
information, for instance from MovePicker.
Note that 'eval' field become obsolete, it is kept
just becasue when we get a position score from TT
we update 'eval' even without an EvalInfo object.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
In sp_search_pv() we do a LMR search using sp->alpha, at the end
we detect a fail high with condition (value > sp->alpha), but if
another thread has increased sp->alpha during our LMR search we
could miss to detect a fail high event becasue value will be equal
to old alpha and so smaller then new one.
This patch fixes this SMP-bug and changes also the non SMP versions
of the search to keep code style in sync.
Bug spotted by Bruno Causse.
No functional change (for single CPU case)
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
futilityValue is now calculated immediately after
staticValue, so remove small bunch of unused code
No functional change
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
MSVC raises an "use of partially uninitialized variable" for futilityValue
and staticValue but this is not rue becasue when !isCheck variables
are never used, anyhow silence the warning.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
This is less prone to bugs because now it's up to the
compiler don't forget this important initialization.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
No change in functionality signature
The only functional change is that when we reach PLY_MAX,
we now return VALUE_DRAW instead of evaluating position.
But we reach PLY_MAX only when position is dead drawn and
transposition table is filled with draw scores, so this
shouldn't matter at all.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
This way razoring is always based on exact evaluation and
follows simple formula.
Joona's test results are positive:
32-bit 1CPU:
Mod - Orig: 1073 - 993
64-bit 4CPU:
Mod - Orig: 759 - 721
Functionality Signature: 11448962
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Also retire razoring margins vector and use
a simpler formula instead.
Now that we use a more accurate static evaluation
try to avoid useless null searches when we are well
below beta. And for teh same reason increase a bit
the razoring.
After 972 games at 1+0
Mod vs Orig +224 =558 -190 +12 ELO
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
It means we have already received "stop" or "quit" commands.
This fixes an hang in tactical test in Fritz GUI. Bug
introduced by previous bug fix :-(
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
According to UCI standard once engine receives 'go infinite'
command it should search until the "stop" command and do not exit
the search without being told so, even if PLY_MAX has been reached.
Patch is quite invasive because it cleanups some hacks used
by fixed depth and fixed nodes modes, mainly during benchmarks.
Bug found by Pascal Georges.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
So to have the same layout and be as much similar as
possible. The only functional change is that now we
try ttMove as first also in PV nodes and at the end
we save the ttMove, as it happens in search. This
should have almost zero impact on ELO but it seems
the correct thing to do.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
This is an important design change because we know
compute evaluation in each node.
This is a 2.0 type change!
After 977 games at 1+0
Mod vs Orig +236 =538 -202 51.74% +12 ELO
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Try to get a position evaluation better then
the quick one with the help of the TT table.
This allows the null search conditions and
chosen reductions to be more accurate.
After 908 games at 1+0
Mod vs Orig +209 =526 -173 +14 ELO
Functionality Signature: 16627355
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Linear rule, less aggressive then Dann's one.
It seems it scales well with depth. We will need to
verify against weaker engine if it keeps the score.
After 999 games at 1+0 on my Dual Core
Mod vs Orig +232 =534 -207 +9 ELO
After 1000 games by Martin Thoresen on his QUAD at 1+0
Mod vs Orig 521/479 52.10%
Functionality Signature: 17655312
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
The most interesting thing is a bit of rewrite
and semplification in connected_moves()
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Because that's the correct meaning. Note that also the
corresponding UCI option has been renamed.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
It is not clear why is not true, even in single thread
case, but as a matter of fact it is not!
So remove it.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Instead should be read by the corresponding UCI
option "Book File".
Bug reported and fixed by Justin Blanchard (Arch Linux)
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Was a long standing hidden bug from Glaurung times,
triggered only now that we enable IID at non PV nodes.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
We want to increrase the opportunities
of doing an exclusion search.
After 999 games at 1+0
Mod vs Orig +216 =574 -209 50.35% 503.0/999 +2 ELO
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Instead decrement history value on failure.
After 999 games at 1+0
Mod vs Orig +236 =558 -204 51.60% +11 ELO
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
This way we avoid overwriting valuable TT entries which
are needed to calculate exclusion search extension for pv.
Mod - Orig: 483 - 410 (+28 elo!)
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
After 999 games we are almost equal (+2 ELO),
but we have a good result against Rybka
Rybka 2.3.2a mp 32-bit vs Mod 254.5 - 242.5 +152/-140/=205 51.21%
Rybka 2.3.2a mp 32-bit vs Orig 259.5 - 236.5 +151/-128/=217 52.32%
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Now we always try to filter out moves, we will have
more wasted evaluation calls, but also more pruned
nodes.
After 786 games
Mod vs Orig +196 =413 -177 +8 ELO
Verified also against Rybka it increases score to 50-51%
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
We might be asked to ponder mate or stalemate position.
This being the case, simply wait for stop or ponderhit.
Currently we crash.
UCI specs aren't clear on the issue, but it cost nothing to
add little check.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Now we use a formula to calculate margins on the fly.
Node count has changed because we fixed a leftover when
we still where using FutilityMargins to calculate futilityValue
in the case that we had the evaluation score in TT.
Also small indentation fix.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Increase pruning at low depths while tone downa bit at
higher depths (linearize a bit the logaritmic behaviour)
This goes togheter with IncrementalFutilityMargin decreased
to 4 compensate the bigger pruning effect.
Total pruned nodes are more or less the same. We go from 36%
of nodes after prune to 37% with this patch.
After 999 games at 1+0
Mod vs Orig +250 =526 -223 +9 ELO
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
If we arrive until the exclusion search call then
we know that move == ttMove == tte->move()
But using ttMove in search call while, during excluded search
conditions we have used tte->Move()could be a little bit suboptimal.
On the other side using tte->move() also in search call is a bit ugly
so opt for the third choice that is the most clean becasue from the
conditions the reader easily understands that we are talking of ttMove
and that we ant to exclude the move we are evaluating in that moment.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
If tte->move() != MOVE_NONE then tte->move() == ttMove
What could happen is that we have a ttMove without a tte, or,
we have a tte but tte->move() == MOVE_NONE
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Due to IID we could have a ttMove and not a tte, or,
even if we have a tte they could belong to different
searches so that the depth and type of tte don't
have the same origin of the ttMove.
To fix this we always use tte entry in excluded search
condition and, after an IID, we reprobe the TT table.
No functional change. Apart from possible crash fix.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
They gave bad results:
Mod - Orig: 361 - 404
Master is now verified to be functional equivalent with F_63
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
We already reset loseOnTime flag at the beginning of
a new game, so we can simplify a bit the ligic there.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
* New version is documented and logic should be easier to follow
* Add extra check to not use LSN with x moves / y seconds time control
* New code fixes some rear cases where old code (still) causes program to lose on time at move 1.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
* The function is called only in one place
* It must not be called elsewhere
* The function call easily replaced with simple one line condition
No functional change (tested with usual set + 2000 random positions)
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
* First one is without any documentation, code is working just fine,
so there seems to be nothing that really should be fixed.
* Second one requesting emergency measures on aspiration fail low
when we are running out of time and we are without good move.
After very long time, I've come to conclusion that this is
impossible to fix, so remove request.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Use an exponenital law instead of a linear one for
history pruning.
This should prune more at low depths and a bit less
at high depths.
After 965 games
Mod vs Orig +233 =504 -228 +2 ELO
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Correct beta by razor margin when callin qsearch
After 1019 games on Joona's QUAD
Mod - Orig: 524 - 495 (+10 elo)
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Call directly 'perft 6' to search up to depth 6*OnePly
instead of the old 'perft depth 6'.
It is more in line to what other engines do. Also a bit
of cleanup while there.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>