assert

Discussion of chess software programming and technical issues.

Moderators: hgm, Harvey Williamson, bob

User avatar
flok
Posts: 895
Joined: Fri Mar 14, 2008 1:33 pm
Location: Gouda, the Netherlands
Contact:

assert

Post by flok » Mon Nov 13, 2017 9:09 am

Hi,

I'm looking to improve my program.
For that I'm adding asserts all over the place to check input variables, outgoing values, and so on.
I've also added an assert that if we're in a null move, then beta == alpha + 1.
My question now is: what other things are there to check for?


regards

elcabesa
Posts: 638
Joined: Sun May 23, 2010 11:32 am
Contact:

Re: assert

Post by elcabesa » Mon Nov 13, 2017 9:47 am

Your program starts to be complicated and it's difficult to understand if inside the flow there are some strange bug.
Adding assert will help you finding them.
If You expect some assertion to be true in some path of code, assert them and let the program check them at runtime.
For example alpha < beta for every node. Alpha +1= beta for scout nodes.
Depth < 0 in q search. Those are generic assert.
For each function you can add assert that you think should be true

User avatar
lucasart
Posts: 2952
Joined: Mon May 31, 2010 11:29 am
Contact:

Re: assert

Post by lucasart » Mon Nov 13, 2017 9:49 am

I use assert as follows.

1/ Check (systematically) that input variables of functions are within expected range.
This goes a long way already. Start with the most frequently used functions. If you don't who they are, ask the profiler (sort results by descending number of calls). Such functions are going to be things like file_of(int s): it's used almost everywhere, directly or indirectly, so if ever an invalid square value pops up, it will endup in file_of() at some point and trigger the assert.

2/ Document the implicit assumption that the code makes
Whenever there's an implicit assumption, put an assert. For example in an else block, where reaching the else implies that the move is en-passant (let's say), assert that it's en-passant. The assert is both a bug trap, *and* documentation.
In the search, alpha/beta/PVnode relationships etc.

But assert is not enough. It's not because your variables are in range that you don't have bugs. If you're serious about debugging, you should also use Clang sanitizers, or Valgrind at least. It's truly amazing the number of invisible (or very rarely visible and not reproducible) bugs that chess engines have. Even strong engines. Undefined behaviors and subtle bugs are pervasive in C, and even more so in C++. If you're coding in a more robust language like D or C#, you shouldn't have this kind of problem.
Theory and practice sometimes clash. And when that happens, theory loses. Every single time.

Henk
Posts: 5055
Joined: Mon May 27, 2013 8:31 am

Re: assert

Post by Henk » Mon Nov 13, 2017 10:26 am

What I remember is that adding complete pre- post conditions and invariants makes the program more complex than it's original. And the more complicated the more errors.

Best is to write pure functions but that is not possible.

[throwing exceptions is similar to using goto statements ]

Henk
Posts: 5055
Joined: Mon May 27, 2013 8:31 am

Re: assert

Post by Henk » Mon Nov 13, 2017 10:44 am

lucasart wrote:I use assert as follows.

1/ Check (systematically) that input variables of functions are within expected range.
This goes a long way already. Start with the most frequently used functions. If you don't who they are, ask the profiler (sort results by descending number of calls). Such functions are going to be things like file_of(int s): it's used almost everywhere, directly or indirectly, so if ever an invalid square value pops up, it will endup in file_of() at some point and trigger the assert.

2/ Document the implicit assumption that the code makes
Whenever there's an implicit assumption, put an assert. For example in an else block, where reaching the else implies that the move is en-passant (let's say), assert that it's en-passant. The assert is both a bug trap, *and* documentation.
In the search, alpha/beta/PVnode relationships etc.

But assert is not enough. It's not because your variables are in range that you don't have bugs. If you're serious about debugging, you should also use Clang sanitizers, or Valgrind at least. It's truly amazing the number of invisible (or very rarely visible and not reproducible) bugs that chess engines have. Even strong engines. Undefined behaviors and subtle bugs are pervasive in C, and even more so in C++. If you're coding in a more robust language like D or C#, you shouldn't have this kind of problem.
Better use F# or even better Haskell if it would not be impractical.

User avatar
flok
Posts: 895
Joined: Fri Mar 14, 2008 1:33 pm
Location: Gouda, the Netherlands
Contact:

Re: assert

Post by flok » Mon Nov 13, 2017 10:50 am

Thank you all guys but I'm more looking for things like "in situation x, check if alpha > score and score < tt val" etc.
Like: in null move, check if alpha = beta - 1 and so on.

Henk
Posts: 5055
Joined: Mon May 27, 2013 8:31 am

Re: assert

Post by Henk » Mon Nov 13, 2017 10:59 am

flok wrote:Thank you all guys but I'm more looking for things like "in situation x, check if alpha > score and score < tt val" etc.
Like: in null move, check if alpha = beta - 1 and so on.
If you use fail hard you know what to check. But fail hard is slower.


mar
Posts: 1830
Joined: Fri Nov 26, 2010 1:00 pm

Re: assert

Post by mar » Mon Nov 13, 2017 11:05 am

lucasart wrote:Undefined behaviors and subtle bugs are pervasive in C, and even more so in C++. If you're coding in a more robust language like D or C#, you shouldn't have this kind of problem.
nonsense.

if you index local arrays out of bounds, that's your problem.
C# is slower compared to C/C++/D, I don't see how D is more robust than C/C++ except that it zero-initializes by default (not talking about language features).

(if you think so, maybe you should switch to D/C#)

in fact, C++ is of course more "robust" than C, you can use std::array which checks bounds in debug mode and of course more.

Valgrind/DrMemory won't catch all problems, but they're pretty good.

now back to OP: asserts are nice but they also slow your code in debug mode, so too many of them probably hurts

elcabesa
Posts: 638
Joined: Sun May 23, 2010 11:32 am
Contact:

Re: assert

Post by elcabesa » Mon Nov 13, 2017 11:24 am

You can find a lot of assert in position.h and position.cpp of Vajolet source code. It's probably not perfect but can give you some idea

Harald
Posts: 259
Joined: Thu Mar 09, 2006 12:07 am

Re: assert

Post by Harald » Mon Nov 13, 2017 12:53 pm

If you want to test only parts of your code then you can do things like this:

In an header like basics.h

Code: Select all

// Which tests should be performed
#ifdef _DEBUG
#define ASSERT_BASICS&#40;c,t&#41;              &#123; if ( !&#40;c&#41; )  throw &#40;t&#41;; &#125;
#define ASSERT_PRINCIPAL_VARIATION&#40;c,t&#41; &#123; if ( !&#40;c&#41; )  throw &#40;t&#41;; &#125;
#define ASSERT_MOVE&#40;c,t&#41;                &#123; if ( !&#40;c&#41; )  throw &#40;t&#41;; &#125;
...
#else
#define ASSERT_BASICS&#40;c,t&#41;
#define ASSERT_PRINCIPAL_VARIATION&#40;c,t&#41;
#define ASSERT_MOVE&#40;c,t&#41;
...
#endif
And in a file like move.cpp

Code: Select all

void Move&#58;&#58;set&#40; ColorType color, SquareType from, SquareType to,
                PieceType piece, PieceType capture,
                PromotionType promotion
              )
&#123;
    ASSERT_MOVE&#40; color == White || color == Black, "Error&#58; bad color in Move&#58;&#58;set&#40;)" )
    ASSERT_MOVE&#40; from >= 0 && from < 64, "Error&#58; bad from in Move&#58;&#58;set&#40;)" )
    ASSERT_MOVE&#40; to   >= 0 && to   < 64, "Error&#58; bad to in Move&#58;&#58;set&#40;)" )
    ASSERT_MOVE&#40; piece >= Pawn && piece < 8, "Error&#58; bad piece in Move&#58;&#58;set&#40;)" )
    ASSERT_MOVE&#40; capture >= NoPiece && capture != King && capture < 8, "Error&#58; bad capture in Move&#58;&#58;set&#40;)" )
    ASSERT_MOVE&#40; promotion <= PromoteToKnight, "Error&#58; bad promotion in Move&#58;&#58;set&#40;)" )
    move_ = from | &#40;to << 6&#41; | &#40;promotion << 12&#41; | &#40;piece << 14&#41; | &#40;capture << 17&#41; | &#40;color << 20&#41;;
&#125;

Post Reply