mirror of
https://github.com/opelly27/Stockfish.git
synced 2026-05-20 14:27:45 +00:00
Compare commits
400 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 68e1e9b381 | |||
| a49b3ba7ed | |||
| 48f7c74f15 | |||
| 52e84e4b46 | |||
| 02728736ed | |||
| aec8fb3fde | |||
| 6eaa1c3ecd | |||
| a68a1c1154 | |||
| a46087ee30 | |||
| 0187546275 | |||
| 32d3284df5 | |||
| 14bfec2a98 | |||
| 887bbd8b3d | |||
| 7922e07af8 | |||
| 92c949e12e | |||
| ece90bca9c | |||
| 38e61663d8 | |||
| b7ee7290b5 | |||
| 932f5a2d65 | |||
| e1dd005583 | |||
| a9a6915e08 | |||
| 54ad986768 | |||
| 373359b44d | |||
| 295f57829e | |||
| b60738e01b | |||
| 8dea070538 | |||
| ced0311890 | |||
| 5930c0defb | |||
| 6cf8d938c5 | |||
| 06186b786e | |||
| d99942f254 | |||
| 07bd8adcbc | |||
| c1fff71650 | |||
| 7e9b131efb | |||
| 7f0b19dedf | |||
| c701745cf2 | |||
| cedd73f4aa | |||
| a989aa1825 | |||
| b64c97825e | |||
| d7e72d801f | |||
| df0fb8471e | |||
| 7cd650f435 | |||
| 4b085c4777 | |||
| 4f24ee0868 | |||
| f030a1c592 | |||
| 5f7b26aaa0 | |||
| 65e2150501 | |||
| 464ebdf127 | |||
| 28442195c7 | |||
| 2429e16289 | |||
| 72d542f000 | |||
| 21d6b69f7c | |||
| 41f50b2c83 | |||
| c3ce220408 | |||
| b22a1b10bb | |||
| ba06c480a7 | |||
| d64d4ac426 | |||
| 7b9b793fd5 | |||
| c90dd38903 | |||
| f9d9c69bc3 | |||
| 96b6c0b36f | |||
| acb0d204d5 | |||
| 9829bceda9 | |||
| f66c36277f | |||
| 4ad2713e19 | |||
| 7bd23d4d04 | |||
| 1a64afb1c6 | |||
| 7a9f67747f | |||
| 2f2f45f9f4 | |||
| a5643b89fd | |||
| 6e63dd63a4 | |||
| 5d258e168f | |||
| b36d39de3d | |||
| 59f2085469 | |||
| 510aca1ef6 | |||
| a2737d8bb5 | |||
| 9a42bbdf31 | |||
| 77e2b915e1 | |||
| 1fee996999 | |||
| 6a6e32dfc8 | |||
| bc50378ff1 | |||
| 38a80c0b47 | |||
| 66bf45b99e | |||
| c3c46feebb | |||
| e8742bdab3 | |||
| 7a6fa34f5f | |||
| 3f01e3f41f | |||
| a9c26357de | |||
| 37160c4b16 | |||
| 43108a6198 | |||
| 587bc647d7 | |||
| 1b5738e0c9 | |||
| b973e40e45 | |||
| 24b37e4586 | |||
| 02e4697055 | |||
| af4b62a593 | |||
| 515b66f188 | |||
| f0556dcbe3 | |||
| 7077fbdd14 | |||
| d1e17989b5 | |||
| 55896a1384 | |||
| 78532af9dc | |||
| a48573e15f | |||
| 39da50ed23 | |||
| 6ce225bb4c | |||
| 70dfa141d5 | |||
| cdec775a15 | |||
| 3a634f5282 | |||
| 5c589142ae | |||
| 5c75c1c2fb | |||
| 876906965b | |||
| 6adbc6fa05 | |||
| 564456a6a8 | |||
| ff5a6f8df1 | |||
| 728b963614 | |||
| 98dafda6c8 | |||
| 472e726bff | |||
| 29b5ad5dea | |||
| 69639d764b | |||
| 08385527dd | |||
| 77dfcbedce | |||
| b4ad3a3c4b | |||
| 037ef3e18d | |||
| 085cace457 | |||
| 29c1e072b6 | |||
| 2c36d1e7e7 | |||
| 852330ee50 | |||
| e5f6d71b96 | |||
| 05dea2ca46 | |||
| e25bcaed3c | |||
| 8f843633db | |||
| d5817a5896 | |||
| 8d3457a996 | |||
| d2f79ff0e0 | |||
| 1cdc0f78bd | |||
| 5a30b087c3 | |||
| da8513f0ea | |||
| 3589bd008a | |||
| 7fc0f589d6 | |||
| 0827e00f10 | |||
| e4e61cd9cc | |||
| d4d1cec296 | |||
| 2f67409506 | |||
| 2167942b6e | |||
| def296670d | |||
| d3860f8d5e | |||
| 3dd0a7a7cd | |||
| 596a528c6a | |||
| a2038c1a01 | |||
| 734315ff30 | |||
| a08b8d4e97 | |||
| da5bcec481 | |||
| 3d2381d76d | |||
| 4f4e652eca | |||
| e9e7a7b83f | |||
| 5a88c5bb9b | |||
| 31acd6bab7 | |||
| fcee83810a | |||
| 4101893a28 | |||
| ea0f34120f | |||
| 9fe9ff0082 | |||
| fc5b59b88b | |||
| a6fa683418 | |||
| b60f9cc451 | |||
| be9bc420af | |||
| 258c13ba8c | |||
| f09b391ceb | |||
| 64656f8583 | |||
| b2bd8699ec | |||
| c620886181 | |||
| 20b0226462 | |||
| c2d507005c | |||
| 61ea1534ff | |||
| 3a32d3e00c | |||
| 39af98c807 | |||
| 726e90ccfa | |||
| 3659a9fda0 | |||
| 7cf93f8b71 | |||
| 5fe1fa0210 | |||
| 310928e985 | |||
| 955edf1d1d | |||
| 8f817ef082 | |||
| 3a30b478d2 | |||
| aedf0251e6 | |||
| 44ecadee10 | |||
| 9d3fd011f1 | |||
| aa603cfeeb | |||
| 74fb936dbd | |||
| cb0c7a9848 | |||
| 98965c139d | |||
| 9fc203a3d0 | |||
| e8caa6640d | |||
| 758f9c9350 | |||
| d60f5de967 | |||
| c7118fb46d | |||
| 6a6faac04d | |||
| f5a31b7e57 | |||
| 1370127fcd | |||
| 85ae65db1d | |||
| d8f3209fb4 | |||
| 3411631162 | |||
| d756d97a66 | |||
| 41c6a74d37 | |||
| 219fa2f0a7 | |||
| 6c1df553fa | |||
| a413900791 | |||
| e048d11825 | |||
| ad2aa8c06f | |||
| 61a2cb84a6 | |||
| d09653df0d | |||
| f154ed7a2d | |||
| 8333b2a94c | |||
| a5500edc55 | |||
| 4ec8945eaf | |||
| 5604b255e6 | |||
| 804394b939 | |||
| 234d2156fd | |||
| 79c5f3a692 | |||
| 9be2977da7 | |||
| d6b6360ff5 | |||
| f97a86e213 | |||
| 93f71ecfe1 | |||
| e90341f9c9 | |||
| d5271af0ee | |||
| da937e219e | |||
| 8bab09749d | |||
| f436bf77ad | |||
| 232bf19be4 | |||
| 4339a756ac | |||
| 70e51a5bc8 | |||
| 29295ecfd3 | |||
| dc0c441b7c | |||
| 154e7afed0 | |||
| 5a871e174f | |||
| 82bb21dc7a | |||
| 1591e5ac3b | |||
| 9fa258ee1d | |||
| eaf2c8207f | |||
| 5eeb96d0e7 | |||
| a4d18d23a9 | |||
| dddf8fc2b4 | |||
| 97860cb575 | |||
| 02ef1f4496 | |||
| 15ac117ac4 | |||
| 5f290352cd | |||
| 3370f69881 | |||
| 4568f6369b | |||
| 1054a483ca | |||
| 0a01dd044f | |||
| e639c45577 | |||
| 7cc929f437 | |||
| b8f4903fbb | |||
| 675f6a038b | |||
| 582c88ee94 | |||
| 18389e269d | |||
| c4a644922d | |||
| 4b4b7d1209 | |||
| 95d24b77df | |||
| 2e02dd7936 | |||
| aa18b68033 | |||
| c2aaaa65f9 | |||
| 85f8ee6199 | |||
| 442c40b43d | |||
| 5304b561ab | |||
| 4d6a11a04c | |||
| 6edc29d720 | |||
| 2d5dcf3d18 | |||
| d54b85b4bd | |||
| 00297cfef0 | |||
| 809849fa27 | |||
| 90cf8e7d2b | |||
| 7f1333ccf8 | |||
| 653bd0817c | |||
| 8fadbcf1b2 | |||
| 4c7de9e8ab | |||
| 6ede1bed89 | |||
| 1a168201bd | |||
| 48df0754bc | |||
| f7d1491b3d | |||
| cc7bcd5303 | |||
| 22b7909809 | |||
| 5372f81cc8 | |||
| c079acc26f | |||
| 9eb7b607cf | |||
| a32d2086bc | |||
| 285a79eaa0 | |||
| e1f12aa4e6 | |||
| e41f727f0f | |||
| 6e0680efa0 | |||
| c4db7fd1f9 | |||
| e6e324eb28 | |||
| df2f7e7527 | |||
| c25d4c4887 | |||
| c3b67faf98 | |||
| 319af5cf0a | |||
| 19a90b45bc | |||
| 9f6bcb38c0 | |||
| 471d93063a | |||
| 08e0f52b77 | |||
| 910cf8b218 | |||
| e31f97e3ba | |||
| f3a2296e59 | |||
| 004ea2c25e | |||
| 45f2416db4 | |||
| eae0f8dd06 | |||
| 270a0e737f | |||
| 4ac7d726ec | |||
| 174b038bf3 | |||
| 5f781d366e | |||
| 27139dedac | |||
| abef3e86f4 | |||
| 2da1d1bf57 | |||
| 84b1940fca | |||
| 3ec6e1d245 | |||
| cb9c2594fc | |||
| b0b31558a2 | |||
| 08ac4e9db5 | |||
| 4d3950c6eb | |||
| 95d7369e54 | |||
| e178a09c47 | |||
| 50200de5af | |||
| 90d051952f | |||
| 8b4afcf8f7 | |||
| bddd38c45e | |||
| 9083050be6 | |||
| 77cf5704b6 | |||
| 67062637f4 | |||
| 48bf1a386f | |||
| 2b0372319d | |||
| d11101e4c6 | |||
| 7678d63cf2 | |||
| c5d45d3220 | |||
| 44b1ba89a9 | |||
| c5a280c012 | |||
| 9ad0ea7382 | |||
| 2efda17c2a | |||
| ad926d34c0 | |||
| 0b41887527 | |||
| 061f98a9e3 | |||
| 1066119083 | |||
| 93b14a17d1 | |||
| 7d82f0d1f4 | |||
| 0a6168089d | |||
| 88f17a814d | |||
| 22e92d23d2 | |||
| 2c30956a13 | |||
| 74776dbcd5 | |||
| ca51b45649 | |||
| fb7d3ab32e | |||
| 0a318cdddf | |||
| 939b694bfd | |||
| dc5d9bdfee | |||
| 0889210262 | |||
| 3bea736a2a | |||
| c6edf33f53 | |||
| ea1ddb6aef | |||
| d579db34a3 | |||
| 9db6ca8592 | |||
| 8e82345931 | |||
| 9451419912 | |||
| c228f3196a | |||
| 4766dfc395 | |||
| b82d93ece4 | |||
| a3d425cf55 | |||
| 7d44b43b3c | |||
| 18f2b12cd0 | |||
| a6a9d828ab | |||
| 327060232a | |||
| e4b7403f12 | |||
| c9977aa0a8 | |||
| c1f9a359e8 | |||
| 95a2ac1e07 | |||
| 4b86ef8c4f | |||
| 64f21ecdae | |||
| 282644f141 | |||
| ca3c1c5f3a | |||
| e4a0c6c759 | |||
| af050e5eed | |||
| 8bb5a436b2 | |||
| 4bb11e823f | |||
| 9ee58dc7a7 | |||
| 0ac8aca893 | |||
| 092b27a6d0 | |||
| 7218ec4df9 | |||
| a943b1d28d | |||
| a5a89b27c8 | |||
| f5df517145 | |||
| 9048ac00db | |||
| 1a5c21dc56 | |||
| c4a1390f4e | |||
| 7b278aab9f | |||
| a0259d8ab9 | |||
| 45e5e65a28 | |||
| c2b9134c6e | |||
| 11c6cf720d | |||
| 5a223afe4c | |||
| ef4822aa8d | |||
| 0e89d6e754 | |||
| a8330d5c3b | |||
| 717d6c5ed5 |
@@ -0,0 +1,65 @@
|
|||||||
|
name: Report issue
|
||||||
|
description: Create a report to help us fix issues with the engine
|
||||||
|
body:
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Describe the issue
|
||||||
|
description: A clear and concise description of what you're experiencing.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Expected behavior
|
||||||
|
description: A clear and concise description of what you expected to happen.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Steps to reproduce
|
||||||
|
description: |
|
||||||
|
Steps to reproduce the behavior.
|
||||||
|
You can also use this section to paste the command line output.
|
||||||
|
placeholder: |
|
||||||
|
```
|
||||||
|
position startpos moves g2g4 e7e5 f2f3
|
||||||
|
go mate 1
|
||||||
|
info string NNUE evaluation using nn-6877cd24400e.nnue enabled
|
||||||
|
info depth 1 seldepth 1 multipv 1 score mate 1 nodes 33 nps 11000 tbhits 0 time 3 pv d8h4
|
||||||
|
bestmove d8h4
|
||||||
|
```
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Anything else?
|
||||||
|
description: |
|
||||||
|
Anything that will give us more context about the issue you are encountering.
|
||||||
|
You can also use this section to propose ideas on how to solve the issue.
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
|
||||||
|
- type: dropdown
|
||||||
|
attributes:
|
||||||
|
label: Operating system
|
||||||
|
options:
|
||||||
|
- All
|
||||||
|
- Windows
|
||||||
|
- Linux
|
||||||
|
- MacOS
|
||||||
|
- Android
|
||||||
|
- Other or N/A
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
attributes:
|
||||||
|
label: Stockfish version
|
||||||
|
description: |
|
||||||
|
This can be found by running the engine.
|
||||||
|
You can also use the commit ID.
|
||||||
|
placeholder: Stockfish 15 / e6e324e
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
blank_issues_enabled: false
|
||||||
|
contact_links:
|
||||||
|
- name: Discord server
|
||||||
|
url: https://discord.gg/GWDRS3kU6R
|
||||||
|
about: Feel free to ask for support or have a chat with us in our Discord server!
|
||||||
|
- name: Discussions, Q&A, ideas, show us something...
|
||||||
|
url: https://github.com/official-stockfish/Stockfish/discussions/new
|
||||||
|
about: Do you have an idea for Stockfish? Do you want to show something that you made? Please open a discussion about it!
|
||||||
+31
-257
@@ -1,6 +1,8 @@
|
|||||||
name: Stockfish
|
name: Stockfish
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
|
tags:
|
||||||
|
- '*'
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
- tools
|
- tools
|
||||||
@@ -10,268 +12,40 @@ on:
|
|||||||
- master
|
- master
|
||||||
- tools
|
- tools
|
||||||
jobs:
|
jobs:
|
||||||
Stockfish:
|
Prerelease:
|
||||||
name: ${{ matrix.config.name }}
|
if: github.ref == 'refs/heads/master'
|
||||||
runs-on: ${{ matrix.config.os }}
|
runs-on: ubuntu-latest
|
||||||
env:
|
|
||||||
COMPILER: ${{ matrix.config.compiler }}
|
|
||||||
COMP: ${{ matrix.config.comp }}
|
|
||||||
CXXFLAGS: "-Werror"
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
config:
|
|
||||||
- {
|
|
||||||
name: "Ubuntu 20.04 GCC",
|
|
||||||
os: ubuntu-20.04,
|
|
||||||
compiler: g++,
|
|
||||||
comp: gcc,
|
|
||||||
run_expensive_tests: true,
|
|
||||||
run_32bit_tests: true,
|
|
||||||
run_64bit_tests: true,
|
|
||||||
shell: 'bash {0}'
|
|
||||||
}
|
|
||||||
- {
|
|
||||||
name: "Ubuntu 20.04 Clang",
|
|
||||||
os: ubuntu-20.04,
|
|
||||||
compiler: clang++,
|
|
||||||
comp: clang,
|
|
||||||
run_expensive_tests: false,
|
|
||||||
run_32bit_tests: true,
|
|
||||||
run_64bit_tests: true,
|
|
||||||
shell: 'bash {0}'
|
|
||||||
}
|
|
||||||
- {
|
|
||||||
name: "MacOS 10.15 Apple Clang",
|
|
||||||
os: macos-10.15,
|
|
||||||
compiler: clang++,
|
|
||||||
comp: clang,
|
|
||||||
run_expensive_tests: false,
|
|
||||||
run_32bit_tests: false,
|
|
||||||
run_64bit_tests: true,
|
|
||||||
shell: 'bash {0}'
|
|
||||||
}
|
|
||||||
- {
|
|
||||||
name: "MacOS 10.15 GCC 10",
|
|
||||||
os: macos-10.15,
|
|
||||||
compiler: g++-10,
|
|
||||||
comp: gcc,
|
|
||||||
run_expensive_tests: false,
|
|
||||||
run_32bit_tests: false,
|
|
||||||
run_64bit_tests: true,
|
|
||||||
shell: 'bash {0}'
|
|
||||||
}
|
|
||||||
- {
|
|
||||||
name: "Windows 2019 Mingw-w64 GCC x86_64",
|
|
||||||
os: windows-2019,
|
|
||||||
compiler: g++,
|
|
||||||
comp: gcc,
|
|
||||||
run_expensive_tests: false,
|
|
||||||
run_32bit_tests: false,
|
|
||||||
run_64bit_tests: true,
|
|
||||||
msys_sys: 'mingw64',
|
|
||||||
msys_env: 'x86_64',
|
|
||||||
shell: 'msys2 {0}'
|
|
||||||
}
|
|
||||||
- {
|
|
||||||
name: "Windows 2019 Mingw-w64 GCC i686",
|
|
||||||
os: windows-2019,
|
|
||||||
compiler: g++,
|
|
||||||
comp: gcc,
|
|
||||||
run_expensive_tests: false,
|
|
||||||
run_32bit_tests: true,
|
|
||||||
run_64bit_tests: false,
|
|
||||||
msys_sys: 'mingw32',
|
|
||||||
msys_env: 'i686',
|
|
||||||
shell: 'msys2 {0}'
|
|
||||||
}
|
|
||||||
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
working-directory: src
|
|
||||||
shell: ${{ matrix.config.shell }}
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Download required linux packages
|
# returns null if no pre-release exists
|
||||||
if: runner.os == 'Linux'
|
- name: Get Commit SHA of Latest Pre-release
|
||||||
run: |
|
run: |
|
||||||
sudo apt update
|
# Install required packages
|
||||||
sudo apt install expect valgrind g++-multilib
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y curl jq
|
||||||
|
|
||||||
- name: Setup msys and install required packages
|
echo "COMMIT_SHA=$(jq -r 'map(select(.prerelease)) | first | .tag_name' <<< $(curl -s https://api.github.com/repos/${{ github.repository_owner }}/Stockfish/releases))" >> $GITHUB_ENV
|
||||||
if: runner.os == 'Windows'
|
|
||||||
uses: msys2/setup-msys2@v2
|
# delete old previous pre-release and tag
|
||||||
|
- uses: dev-drprasad/delete-tag-and-release@v0.2.1
|
||||||
|
if: env.COMMIT_SHA != 'null'
|
||||||
with:
|
with:
|
||||||
msystem: ${{matrix.config.msys_sys}}
|
tag_name: ${{ env.COMMIT_SHA }}
|
||||||
install: mingw-w64-${{matrix.config.msys_env}}-gcc make git expect
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Download the used network from the fishtest framework
|
Sanitizers:
|
||||||
run: |
|
uses: ./.github/workflows/stockfish_sanitizers.yml
|
||||||
make net
|
Tests:
|
||||||
|
uses: ./.github/workflows/stockfish_test.yml
|
||||||
- name: Extract the bench number from the commit history
|
Compiles:
|
||||||
run: |
|
uses: ./.github/workflows/stockfish_compile_test.yml
|
||||||
git log HEAD | grep "\b[Bb]ench[ :]\+[0-9]\{7\}" | head -n 1 | sed "s/[^0-9]*\([0-9]*\).*/\1/g" > git_sig
|
Binaries:
|
||||||
[ -s git_sig ] && echo "benchref=$(cat git_sig)" >> $GITHUB_ENV && echo "Reference bench:" $(cat git_sig) || echo "No bench found"
|
if: github.ref == 'refs/heads/master' || (startsWith(github.ref_name, 'sf_') && github.ref_type == 'tag')
|
||||||
|
uses: ./.github/workflows/stockfish_binaries.yml
|
||||||
- name: Check compiler
|
ARM_Binaries:
|
||||||
run: |
|
if: github.ref == 'refs/heads/master' || (startsWith(github.ref_name, 'sf_') && github.ref_type == 'tag')
|
||||||
$COMPILER -v
|
uses: ./.github/workflows/stockfish_arm_binaries.yml
|
||||||
|
|
||||||
- name: Test help target
|
|
||||||
run: |
|
|
||||||
make help
|
|
||||||
|
|
||||||
# x86-32 tests
|
|
||||||
|
|
||||||
- name: Test debug x86-32 build
|
|
||||||
if: ${{ matrix.config.run_32bit_tests }}
|
|
||||||
run: |
|
|
||||||
export CXXFLAGS="-Werror -D_GLIBCXX_DEBUG"
|
|
||||||
make clean
|
|
||||||
make -j2 ARCH=x86-32 optimize=no debug=yes build
|
|
||||||
../tests/signature.sh $benchref
|
|
||||||
|
|
||||||
- name: Test x86-32 build
|
|
||||||
if: ${{ matrix.config.run_32bit_tests }}
|
|
||||||
run: |
|
|
||||||
make clean
|
|
||||||
make -j2 ARCH=x86-32 build
|
|
||||||
../tests/signature.sh $benchref
|
|
||||||
|
|
||||||
- name: Test x86-32-sse41-popcnt build
|
|
||||||
if: ${{ matrix.config.run_32bit_tests }}
|
|
||||||
run: |
|
|
||||||
make clean
|
|
||||||
make -j2 ARCH=x86-32-sse41-popcnt build
|
|
||||||
../tests/signature.sh $benchref
|
|
||||||
|
|
||||||
- name: Test x86-32-sse2 build
|
|
||||||
if: ${{ matrix.config.run_32bit_tests }}
|
|
||||||
run: |
|
|
||||||
make clean
|
|
||||||
make -j2 ARCH=x86-32-sse2 build
|
|
||||||
../tests/signature.sh $benchref
|
|
||||||
|
|
||||||
- name: Test general-32 build
|
|
||||||
if: ${{ matrix.config.run_32bit_tests }}
|
|
||||||
run: |
|
|
||||||
make clean
|
|
||||||
make -j2 ARCH=general-32 build
|
|
||||||
../tests/signature.sh $benchref
|
|
||||||
|
|
||||||
# x86-64 tests
|
|
||||||
|
|
||||||
- name: Test debug x86-64-modern build
|
|
||||||
if: ${{ matrix.config.run_64bit_tests }}
|
|
||||||
run: |
|
|
||||||
export CXXFLAGS="-Werror -D_GLIBCXX_DEBUG"
|
|
||||||
make clean
|
|
||||||
make -j2 ARCH=x86-64-modern optimize=no debug=yes build
|
|
||||||
../tests/signature.sh $benchref
|
|
||||||
|
|
||||||
- name: Test x86-64-modern build
|
|
||||||
if: ${{ matrix.config.run_64bit_tests }}
|
|
||||||
run: |
|
|
||||||
make clean
|
|
||||||
make -j2 ARCH=x86-64-modern build
|
|
||||||
../tests/signature.sh $benchref
|
|
||||||
|
|
||||||
- name: Test x86-64-ssse3 build
|
|
||||||
if: ${{ matrix.config.run_64bit_tests }}
|
|
||||||
run: |
|
|
||||||
make clean
|
|
||||||
make -j2 ARCH=x86-64-ssse3 build
|
|
||||||
../tests/signature.sh $benchref
|
|
||||||
|
|
||||||
- name: Test x86-64-sse3-popcnt build
|
|
||||||
if: ${{ matrix.config.run_64bit_tests }}
|
|
||||||
run: |
|
|
||||||
make clean
|
|
||||||
make -j2 ARCH=x86-64-sse3-popcnt build
|
|
||||||
../tests/signature.sh $benchref
|
|
||||||
|
|
||||||
- name: Test x86-64 build
|
|
||||||
if: ${{ matrix.config.run_64bit_tests }}
|
|
||||||
run: |
|
|
||||||
make clean
|
|
||||||
make -j2 ARCH=x86-64 build
|
|
||||||
../tests/signature.sh $benchref
|
|
||||||
|
|
||||||
- name: Test general-64 build
|
|
||||||
if: matrix.config.run_64bit_tests
|
|
||||||
run: |
|
|
||||||
make clean
|
|
||||||
make -j2 ARCH=general-64 build
|
|
||||||
../tests/signature.sh $benchref
|
|
||||||
|
|
||||||
# x86-64 with newer extensions tests
|
|
||||||
|
|
||||||
- name: Compile x86-64-avx2 build
|
|
||||||
if: ${{ matrix.config.run_64bit_tests }}
|
|
||||||
run: |
|
|
||||||
make clean
|
|
||||||
make -j2 ARCH=x86-64-avx2 build
|
|
||||||
|
|
||||||
- name: Compile x86-64-bmi2 build
|
|
||||||
if: ${{ matrix.config.run_64bit_tests }}
|
|
||||||
run: |
|
|
||||||
make clean
|
|
||||||
make -j2 ARCH=x86-64-bmi2 build
|
|
||||||
|
|
||||||
- name: Compile x86-64-avx512 build
|
|
||||||
if: ${{ matrix.config.run_64bit_tests }}
|
|
||||||
run: |
|
|
||||||
make clean
|
|
||||||
make -j2 ARCH=x86-64-avx512 build
|
|
||||||
|
|
||||||
- name: Compile x86-64-vnni512 build
|
|
||||||
if: ${{ matrix.config.run_64bit_tests }}
|
|
||||||
run: |
|
|
||||||
make clean
|
|
||||||
make -j2 ARCH=x86-64-vnni512 build
|
|
||||||
|
|
||||||
- name: Compile x86-64-vnni256 build
|
|
||||||
if: ${{ matrix.config.run_64bit_tests }}
|
|
||||||
run: |
|
|
||||||
make clean
|
|
||||||
make -j2 ARCH=x86-64-vnni256 build
|
|
||||||
|
|
||||||
# Other tests
|
|
||||||
|
|
||||||
- name: Check perft and search reproducibility
|
|
||||||
if: ${{ matrix.config.run_64bit_tests }}
|
|
||||||
run: |
|
|
||||||
make clean
|
|
||||||
make -j2 ARCH=x86-64-modern build
|
|
||||||
../tests/perft.sh
|
|
||||||
../tests/reprosearch.sh
|
|
||||||
|
|
||||||
# Sanitizers
|
|
||||||
|
|
||||||
- name: Run under valgrind
|
|
||||||
if: ${{ matrix.config.run_expensive_tests }}
|
|
||||||
run: |
|
|
||||||
export CXXFLAGS="-O1 -fno-inline"
|
|
||||||
make clean
|
|
||||||
make -j2 ARCH=x86-64-modern debug=yes optimize=no build > /dev/null
|
|
||||||
../tests/instrumented.sh --valgrind
|
|
||||||
../tests/instrumented.sh --valgrind-thread
|
|
||||||
|
|
||||||
- name: Run with UB sanitizer
|
|
||||||
if: ${{ matrix.config.run_expensive_tests }}
|
|
||||||
run: |
|
|
||||||
export CXXFLAGS="-O1 -fno-inline"
|
|
||||||
make clean
|
|
||||||
make -j2 ARCH=x86-64-modern sanitize=undefined optimize=no debug=yes build > /dev/null
|
|
||||||
../tests/instrumented.sh --sanitizer-undefined
|
|
||||||
|
|
||||||
- name: Run with thread sanitizer
|
|
||||||
if: ${{ matrix.config.run_expensive_tests }}
|
|
||||||
run: |
|
|
||||||
export CXXFLAGS="-O1 -fno-inline"
|
|
||||||
make clean
|
|
||||||
make -j2 ARCH=x86-64-modern sanitize=thread optimize=no debug=yes build > /dev/null
|
|
||||||
../tests/instrumented.sh --sanitizer-thread
|
|
||||||
|
|||||||
@@ -0,0 +1,158 @@
|
|||||||
|
name: Stockfish
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
jobs:
|
||||||
|
Stockfish:
|
||||||
|
name: ${{ matrix.config.name }} ${{ matrix.binaries }}
|
||||||
|
runs-on: ${{ matrix.config.os }}
|
||||||
|
env:
|
||||||
|
COMPILER: ${{ matrix.config.compiler }}
|
||||||
|
COMP: ${{ matrix.config.comp }}
|
||||||
|
EMU: ${{ matrix.config.emu }}
|
||||||
|
EXT: ${{ matrix.config.ext }}
|
||||||
|
OS: ${{ matrix.config.os }}
|
||||||
|
BINARY: ${{ matrix.binaries }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
config:
|
||||||
|
- name: Android NDK aarch64
|
||||||
|
os: ubuntu-22.04
|
||||||
|
compiler: aarch64-linux-android21-clang++
|
||||||
|
emu: qemu-aarch64
|
||||||
|
comp: ndk
|
||||||
|
shell: bash {0}
|
||||||
|
- name: Android NDK arm
|
||||||
|
os: ubuntu-22.04
|
||||||
|
compiler: armv7a-linux-androideabi21-clang++
|
||||||
|
emu: qemu-arm
|
||||||
|
comp: ndk
|
||||||
|
shell: bash {0}
|
||||||
|
binaries:
|
||||||
|
- armv8
|
||||||
|
- armv7
|
||||||
|
- armv7-neon
|
||||||
|
exclude:
|
||||||
|
- binaries: armv8
|
||||||
|
config: {compiler: armv7a-linux-androideabi21-clang++}
|
||||||
|
- binaries: armv7
|
||||||
|
config: {compiler: aarch64-linux-android21-clang++}
|
||||||
|
- binaries: armv7-neon
|
||||||
|
config: {compiler: aarch64-linux-android21-clang++}
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: src
|
||||||
|
shell: ${{ matrix.config.shell }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Download required linux packages
|
||||||
|
if: runner.os == 'Linux'
|
||||||
|
run: |
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install qemu-user
|
||||||
|
|
||||||
|
- name: Install NDK
|
||||||
|
if: runner.os == 'Linux'
|
||||||
|
run: |
|
||||||
|
if [ $COMP == ndk ]; then
|
||||||
|
NDKV="21.4.7075529"
|
||||||
|
ANDROID_ROOT=/usr/local/lib/android
|
||||||
|
ANDROID_SDK_ROOT=$ANDROID_ROOT/sdk
|
||||||
|
SDKMANAGER=$ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager
|
||||||
|
echo "y" | $SDKMANAGER "ndk;$NDKV"
|
||||||
|
ANDROID_NDK_ROOT=$ANDROID_SDK_ROOT/ndk/$NDKV
|
||||||
|
ANDROID_NDK_BIN=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin
|
||||||
|
echo "ANDROID_NDK_BIN=$ANDROID_NDK_BIN" >> $GITHUB_ENV
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Download the used network from the fishtest framework
|
||||||
|
run: make net
|
||||||
|
|
||||||
|
- name: Check compiler
|
||||||
|
run: |
|
||||||
|
if [ $COMP == ndk ]; then
|
||||||
|
export PATH=${{ env.ANDROID_NDK_BIN }}:$PATH
|
||||||
|
fi
|
||||||
|
$COMPILER -v
|
||||||
|
|
||||||
|
- name: Test help target
|
||||||
|
run: make help
|
||||||
|
|
||||||
|
- name: Check git
|
||||||
|
run: git --version
|
||||||
|
|
||||||
|
# Compile profile guided builds
|
||||||
|
|
||||||
|
- name: Compile ${{ matrix.binaries }} build
|
||||||
|
run: |
|
||||||
|
if [ $COMP == ndk ]; then
|
||||||
|
export PATH=${{ env.ANDROID_NDK_BIN }}:$PATH
|
||||||
|
export LDFLAGS="-static -Wno-unused-command-line-argument"
|
||||||
|
fi
|
||||||
|
make clean
|
||||||
|
make -j2 profile-build ARCH=$BINARY COMP=$COMP WINE_PATH=$EMU
|
||||||
|
make strip ARCH=$BINARY COMP=$COMP
|
||||||
|
mv ./stockfish$EXT ../stockfish-android-$BINARY$EXT
|
||||||
|
|
||||||
|
- name: Remove non src files
|
||||||
|
run: rm -f *.o .depend *.nnue
|
||||||
|
|
||||||
|
- name: Download wiki
|
||||||
|
run: |
|
||||||
|
git clone https://github.com/official-stockfish/Stockfish.wiki.git ../wiki
|
||||||
|
cd ../wiki
|
||||||
|
rm -rf .git
|
||||||
|
|
||||||
|
- name: Create tar archive.
|
||||||
|
run: |
|
||||||
|
cd ..
|
||||||
|
mkdir stockfish
|
||||||
|
cp -r wiki stockfish/
|
||||||
|
cp -r src stockfish/
|
||||||
|
cp stockfish-android-$BINARY$EXT stockfish/
|
||||||
|
cp "Top CPU Contributors.txt" stockfish/
|
||||||
|
cp Copying.txt stockfish/
|
||||||
|
cp AUTHORS stockfish/
|
||||||
|
cp CITATION.cff stockfish/
|
||||||
|
cp README.md stockfish/
|
||||||
|
tar -cvf stockfish-android-$BINARY.tar stockfish
|
||||||
|
|
||||||
|
- name: Upload binaries
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: stockfish-android-${{ matrix.binaries }}
|
||||||
|
path: stockfish-android-${{ matrix.binaries }}.tar
|
||||||
|
|
||||||
|
- name: Release
|
||||||
|
if: startsWith(github.ref_name, 'sf_') && github.ref_type == 'tag'
|
||||||
|
uses: softprops/action-gh-release@v1
|
||||||
|
with:
|
||||||
|
files: stockfish-android-${{ matrix.binaries }}.tar
|
||||||
|
|
||||||
|
- name: Get last commit sha
|
||||||
|
id: last_commit
|
||||||
|
run: echo "COMMIT_SHA=$(git rev-parse HEAD | cut -c 1-8)" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Get commit date
|
||||||
|
id: commit_date
|
||||||
|
run: echo "COMMIT_DATE=$(git show -s --date=format:'%Y%m%d' --format=%cd HEAD)" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
# Make sure that an old ci which still runs on master doesn't recreate a prerelease
|
||||||
|
- name: Check Pullable Commits
|
||||||
|
id: check_commits
|
||||||
|
run: |
|
||||||
|
git fetch
|
||||||
|
CHANGES=$(git rev-list HEAD..origin/master --count)
|
||||||
|
echo "CHANGES=$CHANGES" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Prerelease
|
||||||
|
if: github.ref_name == 'master' && env.CHANGES == '0'
|
||||||
|
continue-on-error: true
|
||||||
|
uses: softprops/action-gh-release@v1
|
||||||
|
with:
|
||||||
|
name: Stockfish dev-${{ env.COMMIT_DATE }}-${{ env.COMMIT_SHA }}
|
||||||
|
tag_name: stockfish-dev-${{ env.COMMIT_DATE }}-${{ env.COMMIT_SHA }}
|
||||||
|
prerelease: true
|
||||||
|
files: stockfish-android-${{ matrix.binaries }}.tar
|
||||||
@@ -0,0 +1,168 @@
|
|||||||
|
name: Stockfish
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
jobs:
|
||||||
|
Stockfish:
|
||||||
|
name: ${{ matrix.config.name }} ${{ matrix.binaries }}
|
||||||
|
runs-on: ${{ matrix.config.os }}
|
||||||
|
env:
|
||||||
|
COMPILER: ${{ matrix.config.compiler }}
|
||||||
|
COMP: ${{ matrix.config.comp }}
|
||||||
|
EXT: ${{ matrix.config.ext }}
|
||||||
|
NAME: ${{ matrix.config.simple_name }}
|
||||||
|
BINARY: ${{ matrix.binaries }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
config:
|
||||||
|
- name: Ubuntu 20.04 GCC
|
||||||
|
os: ubuntu-20.04
|
||||||
|
simple_name: ubuntu
|
||||||
|
compiler: g++
|
||||||
|
comp: gcc
|
||||||
|
shell: bash {0}
|
||||||
|
archive_ext: tar
|
||||||
|
- name: MacOS 12 Apple Clang
|
||||||
|
os: macos-12
|
||||||
|
simple_name: macos
|
||||||
|
compiler: clang++
|
||||||
|
comp: clang
|
||||||
|
shell: bash {0}
|
||||||
|
archive_ext: tar
|
||||||
|
- name: Windows 2022 Mingw-w64 GCC x86_64
|
||||||
|
os: windows-2022
|
||||||
|
simple_name: windows
|
||||||
|
compiler: g++
|
||||||
|
comp: mingw
|
||||||
|
msys_sys: mingw64
|
||||||
|
msys_env: x86_64-gcc
|
||||||
|
shell: msys2 {0}
|
||||||
|
ext: .exe
|
||||||
|
archive_ext: zip
|
||||||
|
binaries:
|
||||||
|
- x86-64
|
||||||
|
- x86-64-modern
|
||||||
|
- x86-64-avx2
|
||||||
|
exclude:
|
||||||
|
- binaries: x86-64-avx2
|
||||||
|
config: {os: macos-12}
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: src
|
||||||
|
shell: ${{ matrix.config.shell }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Download required linux packages
|
||||||
|
if: runner.os == 'Linux'
|
||||||
|
run: sudo apt update
|
||||||
|
|
||||||
|
- name: Setup msys and install required packages
|
||||||
|
if: runner.os == 'Windows'
|
||||||
|
uses: msys2/setup-msys2@v2
|
||||||
|
with:
|
||||||
|
msystem: ${{ matrix.config.msys_sys }}
|
||||||
|
install: mingw-w64-${{ matrix.config.msys_env }} make git zip
|
||||||
|
|
||||||
|
- name: Download the used network from the fishtest framework
|
||||||
|
run: make net
|
||||||
|
|
||||||
|
- name: Check compiler
|
||||||
|
run: $COMPILER -v
|
||||||
|
|
||||||
|
- name: Test help target
|
||||||
|
run: make help
|
||||||
|
|
||||||
|
- name: Check git
|
||||||
|
run: git --version
|
||||||
|
|
||||||
|
# Compile profile guided builds
|
||||||
|
|
||||||
|
- name: Compile ${{ matrix.binaries }} build
|
||||||
|
run: |
|
||||||
|
make -j2 profile-build ARCH=$BINARY COMP=$COMP
|
||||||
|
make strip ARCH=$BINARY COMP=$COMP
|
||||||
|
mv ./stockfish$EXT ../stockfish-$NAME-$BINARY$EXT
|
||||||
|
|
||||||
|
- name: Remove non src files
|
||||||
|
run: git clean -fx
|
||||||
|
|
||||||
|
- name: Download wiki
|
||||||
|
run: |
|
||||||
|
git clone https://github.com/official-stockfish/Stockfish.wiki.git ../wiki
|
||||||
|
rm -rf ../wiki/.git
|
||||||
|
|
||||||
|
- name: Create directory.
|
||||||
|
run: |
|
||||||
|
cd ..
|
||||||
|
mkdir stockfish
|
||||||
|
cp -r wiki stockfish/
|
||||||
|
cp -r src stockfish/
|
||||||
|
cp stockfish-$NAME-$BINARY$EXT stockfish/
|
||||||
|
cp "Top CPU Contributors.txt" stockfish/
|
||||||
|
cp Copying.txt stockfish/
|
||||||
|
cp AUTHORS stockfish/
|
||||||
|
cp CITATION.cff stockfish/
|
||||||
|
cp README.md stockfish/
|
||||||
|
|
||||||
|
- name: Create tar
|
||||||
|
if: runner.os != 'Windows'
|
||||||
|
run: |
|
||||||
|
cd ..
|
||||||
|
tar -cvf stockfish-$NAME-$BINARY.tar stockfish
|
||||||
|
|
||||||
|
- name: Create zip
|
||||||
|
if: runner.os == 'Windows'
|
||||||
|
run: |
|
||||||
|
cd ..
|
||||||
|
zip -r stockfish-$NAME-$BINARY.zip stockfish
|
||||||
|
|
||||||
|
- name: Upload binaries
|
||||||
|
if: runner.os != 'Windows'
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: stockfish-${{ matrix.config.os }}-${{ matrix.binaries }}
|
||||||
|
path: stockfish-${{ matrix.config.simple_name }}-${{ matrix.binaries }}.tar
|
||||||
|
|
||||||
|
# Artifacts automatically get zipped
|
||||||
|
# to avoid double zipping, we use the unzipped directory
|
||||||
|
- name: Upload binaries
|
||||||
|
if: runner.os == 'Windows'
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: stockfish-${{ matrix.config.os }}-${{ matrix.binaries }}
|
||||||
|
path: stockfish
|
||||||
|
|
||||||
|
- name: Release
|
||||||
|
if: startsWith(github.ref_name, 'sf_') && github.ref_type == 'tag'
|
||||||
|
uses: softprops/action-gh-release@v1
|
||||||
|
with:
|
||||||
|
files: stockfish-${{ matrix.config.simple_name }}-${{ matrix.binaries }}.${{ matrix.config.archive_ext }}
|
||||||
|
|
||||||
|
- name: Get last commit sha
|
||||||
|
id: last_commit
|
||||||
|
run: echo "COMMIT_SHA=$(git rev-parse HEAD | cut -c 1-8)" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Get commit date
|
||||||
|
id: commit_date
|
||||||
|
run: echo "COMMIT_DATE=$(git show -s --date=format:'%Y%m%d' --format=%cd HEAD)" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
# Make sure that an old ci which still runs on master doesn't recreate a prerelease
|
||||||
|
- name: Check Pullable Commits
|
||||||
|
id: check_commits
|
||||||
|
run: |
|
||||||
|
git fetch
|
||||||
|
CHANGES=$(git rev-list HEAD..origin/master --count)
|
||||||
|
echo "CHANGES=$CHANGES" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Prerelease
|
||||||
|
if: github.ref_name == 'master' && env.CHANGES == '0'
|
||||||
|
continue-on-error: true
|
||||||
|
uses: softprops/action-gh-release@v1
|
||||||
|
with:
|
||||||
|
name: Stockfish dev-${{ env.COMMIT_DATE }}-${{ env.COMMIT_SHA }}
|
||||||
|
tag_name: stockfish-dev-${{ env.COMMIT_DATE }}-${{ env.COMMIT_SHA }}
|
||||||
|
prerelease: true
|
||||||
|
files: stockfish-${{ matrix.config.simple_name }}-${{ matrix.binaries }}.${{ matrix.config.archive_ext }}
|
||||||
|
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
name: Stockfish
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
jobs:
|
||||||
|
Stockfish:
|
||||||
|
name: ${{ matrix.config.name }}
|
||||||
|
runs-on: ${{ matrix.config.os }}
|
||||||
|
env:
|
||||||
|
COMPILER: ${{ matrix.config.compiler }}
|
||||||
|
COMP: ${{ matrix.config.comp }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
config:
|
||||||
|
- name: Ubuntu 20.04 GCC
|
||||||
|
os: ubuntu-20.04
|
||||||
|
compiler: g++
|
||||||
|
comp: gcc
|
||||||
|
shell: bash {0}
|
||||||
|
- name: Ubuntu 20.04 Clang
|
||||||
|
os: ubuntu-20.04
|
||||||
|
compiler: clang++
|
||||||
|
comp: clang
|
||||||
|
shell: bash {0}
|
||||||
|
- name: MacOS 12 Apple Clang
|
||||||
|
os: macos-12
|
||||||
|
compiler: clang++
|
||||||
|
comp: clang
|
||||||
|
shell: bash {0}
|
||||||
|
- name: MacOS 12 GCC 11
|
||||||
|
os: macos-12
|
||||||
|
compiler: g++-11
|
||||||
|
comp: gcc
|
||||||
|
shell: bash {0}
|
||||||
|
- name: Windows 2022 Mingw-w64 GCC x86_64
|
||||||
|
os: windows-2022
|
||||||
|
compiler: g++
|
||||||
|
comp: mingw
|
||||||
|
msys_sys: mingw64
|
||||||
|
msys_env: x86_64-gcc
|
||||||
|
shell: msys2 {0}
|
||||||
|
- name: Windows 2022 Mingw-w64 Clang x86_64
|
||||||
|
os: windows-2022
|
||||||
|
compiler: clang++
|
||||||
|
comp: clang
|
||||||
|
msys_sys: clang64
|
||||||
|
msys_env: clang-x86_64-clang
|
||||||
|
shell: msys2 {0}
|
||||||
|
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: src
|
||||||
|
shell: ${{ matrix.config.shell }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Setup msys and install required packages
|
||||||
|
if: runner.os == 'Windows'
|
||||||
|
uses: msys2/setup-msys2@v2
|
||||||
|
with:
|
||||||
|
msystem: ${{matrix.config.msys_sys}}
|
||||||
|
install: mingw-w64-${{matrix.config.msys_env}} make git
|
||||||
|
|
||||||
|
- name: Download the used network from the fishtest framework
|
||||||
|
run: make net
|
||||||
|
|
||||||
|
- name: Check compiler
|
||||||
|
run: $COMPILER -v
|
||||||
|
|
||||||
|
- name: Test help target
|
||||||
|
run: make help
|
||||||
|
|
||||||
|
- name: Check git
|
||||||
|
run: git --version
|
||||||
|
|
||||||
|
# x86-64 with newer extensions tests
|
||||||
|
|
||||||
|
- name: Compile x86-64-avx2 build
|
||||||
|
run: |
|
||||||
|
make clean
|
||||||
|
make -j2 ARCH=x86-64-avx2 build
|
||||||
|
|
||||||
|
- name: Compile x86-64-bmi2 build
|
||||||
|
run: |
|
||||||
|
make clean
|
||||||
|
make -j2 ARCH=x86-64-bmi2 build
|
||||||
|
|
||||||
|
- name: Compile x86-64-avx512 build
|
||||||
|
run: |
|
||||||
|
make clean
|
||||||
|
make -j2 ARCH=x86-64-avx512 build
|
||||||
|
|
||||||
|
- name: Compile x86-64-vnni512 build
|
||||||
|
run: |
|
||||||
|
make clean
|
||||||
|
make -j2 ARCH=x86-64-vnni512 build
|
||||||
|
|
||||||
|
- name: Compile x86-64-vnni256 build
|
||||||
|
run: |
|
||||||
|
make clean
|
||||||
|
make -j2 ARCH=x86-64-vnni256 build
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
name: Stockfish
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
jobs:
|
||||||
|
Stockfish:
|
||||||
|
name: ${{ matrix.sanitizers.name }}
|
||||||
|
runs-on: ${{ matrix.config.os }}
|
||||||
|
env:
|
||||||
|
COMPILER: ${{ matrix.config.compiler }}
|
||||||
|
COMP: ${{ matrix.config.comp }}
|
||||||
|
CXXFLAGS: "-Werror"
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
config:
|
||||||
|
- name: Ubuntu 20.04 GCC
|
||||||
|
os: ubuntu-20.04
|
||||||
|
compiler: g++
|
||||||
|
comp: gcc
|
||||||
|
shell: bash {0}
|
||||||
|
sanitizers:
|
||||||
|
- name: Run with thread sanitizer
|
||||||
|
make_option: sanitize=thread
|
||||||
|
instrumented_option: sanitizer-thread
|
||||||
|
- name: Run with UB sanitizer
|
||||||
|
make_option: sanitize=undefined
|
||||||
|
instrumented_option: sanitizer-undefined
|
||||||
|
- name: Run under valgrind
|
||||||
|
make_option: ""
|
||||||
|
instrumented_option: valgrind
|
||||||
|
- name: Run under valgrind-thread
|
||||||
|
make_option: ""
|
||||||
|
instrumented_option: valgrind-thread
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: src
|
||||||
|
shell: ${{ matrix.config.shell }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Download required linux packages
|
||||||
|
run: |
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install expect valgrind g++-multilib
|
||||||
|
|
||||||
|
- name: Download the used network from the fishtest framework
|
||||||
|
run: make net
|
||||||
|
|
||||||
|
- name: Check compiler
|
||||||
|
run: $COMPILER -v
|
||||||
|
|
||||||
|
- name: Test help target
|
||||||
|
run: make help
|
||||||
|
|
||||||
|
- name: Check git
|
||||||
|
run: git --version
|
||||||
|
|
||||||
|
# Sanitizers
|
||||||
|
|
||||||
|
- name: ${{ matrix.sanitizers.name }}
|
||||||
|
run: |
|
||||||
|
export CXXFLAGS="-O1 -fno-inline"
|
||||||
|
make clean
|
||||||
|
make -j2 ARCH=x86-64-modern ${{ matrix.sanitizers.make_option }} debug=yes optimize=no build > /dev/null
|
||||||
|
../tests/instrumented.sh --${{ matrix.sanitizers.instrumented_option }}
|
||||||
@@ -0,0 +1,256 @@
|
|||||||
|
name: Stockfish
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
jobs:
|
||||||
|
Stockfish:
|
||||||
|
name: ${{ matrix.config.name }}
|
||||||
|
runs-on: ${{ matrix.config.os }}
|
||||||
|
env:
|
||||||
|
COMPILER: ${{ matrix.config.compiler }}
|
||||||
|
COMP: ${{ matrix.config.comp }}
|
||||||
|
CXXFLAGS: "-Werror"
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
config:
|
||||||
|
- name: Ubuntu 20.04 GCC
|
||||||
|
os: ubuntu-20.04
|
||||||
|
compiler: g++
|
||||||
|
comp: gcc
|
||||||
|
run_32bit_tests: true
|
||||||
|
run_64bit_tests: true
|
||||||
|
shell: bash {0}
|
||||||
|
- name: Ubuntu 20.04 Clang
|
||||||
|
os: ubuntu-20.04
|
||||||
|
compiler: clang++
|
||||||
|
comp: clang
|
||||||
|
run_32bit_tests: true
|
||||||
|
run_64bit_tests: true
|
||||||
|
shell: bash {0}
|
||||||
|
- name: Android NDK aarch64
|
||||||
|
os: ubuntu-22.04
|
||||||
|
compiler: aarch64-linux-android21-clang++
|
||||||
|
comp: ndk
|
||||||
|
run_armv8_tests: true
|
||||||
|
shell: bash {0}
|
||||||
|
- name: Android NDK arm
|
||||||
|
os: ubuntu-22.04
|
||||||
|
compiler: armv7a-linux-androideabi21-clang++
|
||||||
|
comp: ndk
|
||||||
|
run_armv7_tests: true
|
||||||
|
shell: bash {0}
|
||||||
|
- name: MacOS 12 Apple Clang
|
||||||
|
os: macos-12
|
||||||
|
compiler: clang++
|
||||||
|
comp: clang
|
||||||
|
run_64bit_tests: true
|
||||||
|
shell: bash {0}
|
||||||
|
- name: MacOS 12 GCC 11
|
||||||
|
os: macos-12
|
||||||
|
compiler: g++-11
|
||||||
|
comp: gcc
|
||||||
|
run_64bit_tests: true
|
||||||
|
shell: bash {0}
|
||||||
|
- name: Windows 2022 Mingw-w64 GCC x86_64
|
||||||
|
os: windows-2022
|
||||||
|
compiler: g++
|
||||||
|
comp: mingw
|
||||||
|
run_64bit_tests: true
|
||||||
|
msys_sys: mingw64
|
||||||
|
msys_env: x86_64-gcc
|
||||||
|
shell: msys2 {0}
|
||||||
|
- name: Windows 2022 Mingw-w64 GCC i686
|
||||||
|
os: windows-2022
|
||||||
|
compiler: g++
|
||||||
|
comp: mingw
|
||||||
|
run_32bit_tests: true
|
||||||
|
msys_sys: mingw32
|
||||||
|
msys_env: i686-gcc
|
||||||
|
shell: msys2 {0}
|
||||||
|
- name: Windows 2022 Mingw-w64 Clang x86_64
|
||||||
|
os: windows-2022
|
||||||
|
compiler: clang++
|
||||||
|
comp: clang
|
||||||
|
run_64bit_tests: true
|
||||||
|
msys_sys: clang64
|
||||||
|
msys_env: clang-x86_64-clang
|
||||||
|
shell: msys2 {0}
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: src
|
||||||
|
shell: ${{ matrix.config.shell }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Download required linux packages
|
||||||
|
if: runner.os == 'Linux'
|
||||||
|
run: |
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install expect valgrind g++-multilib qemu-user
|
||||||
|
|
||||||
|
- name: Install NDK
|
||||||
|
if: runner.os == 'Linux'
|
||||||
|
run: |
|
||||||
|
if [ $COMP == ndk ]; then
|
||||||
|
NDKV="21.4.7075529"
|
||||||
|
ANDROID_ROOT=/usr/local/lib/android
|
||||||
|
ANDROID_SDK_ROOT=$ANDROID_ROOT/sdk
|
||||||
|
SDKMANAGER=$ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager
|
||||||
|
echo "y" | $SDKMANAGER "ndk;$NDKV"
|
||||||
|
ANDROID_NDK_ROOT=$ANDROID_SDK_ROOT/ndk/$NDKV
|
||||||
|
ANDROID_NDK_BIN=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin
|
||||||
|
echo "ANDROID_NDK_BIN=$ANDROID_NDK_BIN" >> $GITHUB_ENV
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Setup msys and install required packages
|
||||||
|
if: runner.os == 'Windows'
|
||||||
|
uses: msys2/setup-msys2@v2
|
||||||
|
with:
|
||||||
|
msystem: ${{ matrix.config.msys_sys }}
|
||||||
|
install: mingw-w64-${{ matrix.config.msys_env }} make git expect
|
||||||
|
|
||||||
|
- name: Download the used network from the fishtest framework
|
||||||
|
run: make net
|
||||||
|
|
||||||
|
- name: Extract the bench number from the commit history
|
||||||
|
run: |
|
||||||
|
git log HEAD | grep -o "\b[Bb]ench[ :]\+[1-9][0-9]\{5,9\}\b" | head -n 1 | sed "s/[^0-9]//g" > git_sig
|
||||||
|
[ -s git_sig ] && echo "benchref=$(cat git_sig)" >> $GITHUB_ENV && echo "Reference bench:" $(cat git_sig) || echo "No bench found"
|
||||||
|
|
||||||
|
- name: Check compiler
|
||||||
|
run: |
|
||||||
|
if [ $COMP == ndk ]; then
|
||||||
|
export PATH=${{ env.ANDROID_NDK_BIN }}:$PATH
|
||||||
|
fi
|
||||||
|
$COMPILER -v
|
||||||
|
|
||||||
|
- name: Test help target
|
||||||
|
run: make help
|
||||||
|
|
||||||
|
- name: Check git
|
||||||
|
run: git --version
|
||||||
|
|
||||||
|
# x86-32 tests
|
||||||
|
|
||||||
|
- name: Test debug x86-32 build
|
||||||
|
if: ${{ matrix.config.run_32bit_tests }}
|
||||||
|
run: |
|
||||||
|
export CXXFLAGS="-Werror -D_GLIBCXX_DEBUG"
|
||||||
|
make clean
|
||||||
|
make -j2 ARCH=x86-32 optimize=no debug=yes build
|
||||||
|
../tests/signature.sh $benchref
|
||||||
|
|
||||||
|
- name: Test x86-32 build
|
||||||
|
if: ${{ matrix.config.run_32bit_tests }}
|
||||||
|
run: |
|
||||||
|
make clean
|
||||||
|
make -j2 ARCH=x86-32 build
|
||||||
|
../tests/signature.sh $benchref
|
||||||
|
|
||||||
|
- name: Test x86-32-sse41-popcnt build
|
||||||
|
if: ${{ matrix.config.run_32bit_tests }}
|
||||||
|
run: |
|
||||||
|
make clean
|
||||||
|
make -j2 ARCH=x86-32-sse41-popcnt build
|
||||||
|
../tests/signature.sh $benchref
|
||||||
|
|
||||||
|
- name: Test x86-32-sse2 build
|
||||||
|
if: ${{ matrix.config.run_32bit_tests }}
|
||||||
|
run: |
|
||||||
|
make clean
|
||||||
|
make -j2 ARCH=x86-32-sse2 build
|
||||||
|
../tests/signature.sh $benchref
|
||||||
|
|
||||||
|
- name: Test general-32 build
|
||||||
|
if: ${{ matrix.config.run_32bit_tests }}
|
||||||
|
run: |
|
||||||
|
make clean
|
||||||
|
make -j2 ARCH=general-32 build
|
||||||
|
../tests/signature.sh $benchref
|
||||||
|
|
||||||
|
# x86-64 tests
|
||||||
|
|
||||||
|
- name: Test debug x86-64-modern build
|
||||||
|
if: ${{ matrix.config.run_64bit_tests }}
|
||||||
|
run: |
|
||||||
|
export CXXFLAGS="-Werror -D_GLIBCXX_DEBUG"
|
||||||
|
make clean
|
||||||
|
make -j2 ARCH=x86-64-modern optimize=no debug=yes build
|
||||||
|
../tests/signature.sh $benchref
|
||||||
|
|
||||||
|
- name: Test x86-64-modern build
|
||||||
|
if: ${{ matrix.config.run_64bit_tests }}
|
||||||
|
run: |
|
||||||
|
make clean
|
||||||
|
make -j2 ARCH=x86-64-modern build
|
||||||
|
../tests/signature.sh $benchref
|
||||||
|
|
||||||
|
- name: Test x86-64-ssse3 build
|
||||||
|
if: ${{ matrix.config.run_64bit_tests }}
|
||||||
|
run: |
|
||||||
|
make clean
|
||||||
|
make -j2 ARCH=x86-64-ssse3 build
|
||||||
|
../tests/signature.sh $benchref
|
||||||
|
|
||||||
|
- name: Test x86-64-sse3-popcnt build
|
||||||
|
if: ${{ matrix.config.run_64bit_tests }}
|
||||||
|
run: |
|
||||||
|
make clean
|
||||||
|
make -j2 ARCH=x86-64-sse3-popcnt build
|
||||||
|
../tests/signature.sh $benchref
|
||||||
|
|
||||||
|
- name: Test x86-64 build
|
||||||
|
if: ${{ matrix.config.run_64bit_tests }}
|
||||||
|
run: |
|
||||||
|
make clean
|
||||||
|
make -j2 ARCH=x86-64 build
|
||||||
|
../tests/signature.sh $benchref
|
||||||
|
|
||||||
|
- name: Test general-64 build
|
||||||
|
if: matrix.config.run_64bit_tests
|
||||||
|
run: |
|
||||||
|
make clean
|
||||||
|
make -j2 ARCH=general-64 build
|
||||||
|
../tests/signature.sh $benchref
|
||||||
|
|
||||||
|
# armv8 tests
|
||||||
|
|
||||||
|
- name: Test armv8 build
|
||||||
|
if: ${{ matrix.config.run_armv8_tests }}
|
||||||
|
run: |
|
||||||
|
export PATH=${{ env.ANDROID_NDK_BIN }}:$PATH
|
||||||
|
export LDFLAGS="-static -Wno-unused-command-line-argument"
|
||||||
|
make clean
|
||||||
|
make -j2 ARCH=armv8 build
|
||||||
|
../tests/signature.sh $benchref
|
||||||
|
|
||||||
|
# armv7 tests
|
||||||
|
|
||||||
|
- name: Test armv7 build
|
||||||
|
if: ${{ matrix.config.run_armv7_tests }}
|
||||||
|
run: |
|
||||||
|
export PATH=${{ env.ANDROID_NDK_BIN }}:$PATH
|
||||||
|
export LDFLAGS="-static -Wno-unused-command-line-argument"
|
||||||
|
make clean
|
||||||
|
make -j2 ARCH=armv7 build
|
||||||
|
../tests/signature.sh $benchref
|
||||||
|
|
||||||
|
- name: Test armv7-neon build
|
||||||
|
if: ${{ matrix.config.run_armv7_tests }}
|
||||||
|
run: |
|
||||||
|
export PATH=${{ env.ANDROID_NDK_BIN }}:$PATH
|
||||||
|
export LDFLAGS="-static -Wno-unused-command-line-argument"
|
||||||
|
make clean
|
||||||
|
make -j2 ARCH=armv7-neon build
|
||||||
|
../tests/signature.sh $benchref
|
||||||
|
|
||||||
|
# Other tests
|
||||||
|
|
||||||
|
- name: Check perft and search reproducibility
|
||||||
|
if: ${{ matrix.config.run_64bit_tests }}
|
||||||
|
run: |
|
||||||
|
make clean
|
||||||
|
make -j2 ARCH=x86-64-modern build
|
||||||
|
../tests/perft.sh
|
||||||
|
../tests/reprosearch.sh
|
||||||
@@ -1,17 +1,15 @@
|
|||||||
# List of authors for Stockfish
|
# Founders of the Stockfish project and Fishtest infrastructure
|
||||||
|
|
||||||
# Founders of the Stockfish project and fishtest infrastructure
|
|
||||||
Tord Romstad (romstad)
|
Tord Romstad (romstad)
|
||||||
Marco Costalba (mcostalba)
|
Marco Costalba (mcostalba)
|
||||||
Joona Kiiski (zamar)
|
Joona Kiiski (zamar)
|
||||||
Gary Linscott (glinscott)
|
Gary Linscott (glinscott)
|
||||||
|
|
||||||
# Authors and inventors of NNUE, training, NNUE port
|
# Authors and inventors of NNUE, training, and NNUE port
|
||||||
Yu Nasu (ynasu87)
|
Yu Nasu (ynasu87)
|
||||||
Motohiro Isozaki (yaneurao)
|
Motohiro Isozaki (yaneurao)
|
||||||
Hisayori Noda (nodchip)
|
Hisayori Noda (nodchip)
|
||||||
|
|
||||||
# all other authors of the code in alphabetical order
|
# All other authors of Stockfish code (in alphabetical order)
|
||||||
Aditya (absimaldata)
|
Aditya (absimaldata)
|
||||||
Adrian Petrescu (apetresc)
|
Adrian Petrescu (apetresc)
|
||||||
Ajith Chandy Jose (ajithcj)
|
Ajith Chandy Jose (ajithcj)
|
||||||
@@ -21,6 +19,7 @@ Alexander Kure
|
|||||||
Alexander Pagel (Lolligerhans)
|
Alexander Pagel (Lolligerhans)
|
||||||
Alfredo Menezes (lonfom169)
|
Alfredo Menezes (lonfom169)
|
||||||
Ali AlZhrani (Cooffe)
|
Ali AlZhrani (Cooffe)
|
||||||
|
Andreas Matthies (Matthies)
|
||||||
Andrei Vetrov (proukornew)
|
Andrei Vetrov (proukornew)
|
||||||
Andrew Grant (AndyGrant)
|
Andrew Grant (AndyGrant)
|
||||||
Andrey Neporada (nepal)
|
Andrey Neporada (nepal)
|
||||||
@@ -31,21 +30,27 @@ Arjun Temurnikar
|
|||||||
Artem Solopiy (EntityFX)
|
Artem Solopiy (EntityFX)
|
||||||
Auguste Pop
|
Auguste Pop
|
||||||
Balint Pfliegel
|
Balint Pfliegel
|
||||||
|
Ben Chaney (Chaneybenjamini)
|
||||||
Ben Koshy (BKSpurgeon)
|
Ben Koshy (BKSpurgeon)
|
||||||
Bill Henry (VoyagerOne)
|
Bill Henry (VoyagerOne)
|
||||||
Bojun Guo (noobpwnftw, Nooby)
|
Bojun Guo (noobpwnftw, Nooby)
|
||||||
|
borg323
|
||||||
|
Boštjan Mejak (PedanticHacker)
|
||||||
braich
|
braich
|
||||||
Brian Sheppard (SapphireBrand, briansheppard-toast)
|
Brian Sheppard (SapphireBrand, briansheppard-toast)
|
||||||
Bruno de Melo Costa (BM123499)
|
Bruno de Melo Costa (BM123499)
|
||||||
|
Bruno Pellanda (pellanda)
|
||||||
Bryan Cross (crossbr)
|
Bryan Cross (crossbr)
|
||||||
candirufish
|
candirufish
|
||||||
Chess13234
|
Chess13234
|
||||||
Chris Cain (ceebo)
|
Chris Cain (ceebo)
|
||||||
|
clefrks
|
||||||
Dale Weiler (graphitemaster)
|
Dale Weiler (graphitemaster)
|
||||||
Dan Schmidt (dfannius)
|
|
||||||
Daniel Axtens (daxtens)
|
Daniel Axtens (daxtens)
|
||||||
Daniel Dugovic (ddugovic)
|
Daniel Dugovic (ddugovic)
|
||||||
|
Dan Schmidt (dfannius)
|
||||||
Dariusz Orzechowski (dorzechowski)
|
Dariusz Orzechowski (dorzechowski)
|
||||||
|
David (dav1312)
|
||||||
David Zar
|
David Zar
|
||||||
Daylen Yang (daylen)
|
Daylen Yang (daylen)
|
||||||
Deshawn Mohan-Smith (GoldenRare)
|
Deshawn Mohan-Smith (GoldenRare)
|
||||||
@@ -54,12 +59,12 @@ DiscanX
|
|||||||
Dominik Schlösser (domschl)
|
Dominik Schlösser (domschl)
|
||||||
double-beep
|
double-beep
|
||||||
Douglas Matos Gomes (dsmsgms)
|
Douglas Matos Gomes (dsmsgms)
|
||||||
|
Dubslow
|
||||||
Eduardo Cáceres (eduherminio)
|
Eduardo Cáceres (eduherminio)
|
||||||
Eelco de Groot (KingDefender)
|
Eelco de Groot (KingDefender)
|
||||||
Elvin Liu (solarlight2)
|
Elvin Liu (solarlight2)
|
||||||
erbsenzaehler
|
erbsenzaehler
|
||||||
Ernesto Gatti
|
Ernesto Gatti
|
||||||
Linmiao Xu (linrock)
|
|
||||||
Fabian Beuke (madnight)
|
Fabian Beuke (madnight)
|
||||||
Fabian Fichter (ianfab)
|
Fabian Fichter (ianfab)
|
||||||
Fanael Linithien (Fanael)
|
Fanael Linithien (Fanael)
|
||||||
@@ -72,37 +77,41 @@ George Sobala (gsobala)
|
|||||||
gguliash
|
gguliash
|
||||||
Giacomo Lorenzetti (G-Lorenz)
|
Giacomo Lorenzetti (G-Lorenz)
|
||||||
Gian-Carlo Pascutto (gcp)
|
Gian-Carlo Pascutto (gcp)
|
||||||
|
Goh CJ (cj5716)
|
||||||
Gontran Lemaire (gonlem)
|
Gontran Lemaire (gonlem)
|
||||||
Goodkov Vasiliy Aleksandrovich (goodkov)
|
Goodkov Vasiliy Aleksandrovich (goodkov)
|
||||||
Gregor Cramer
|
Gregor Cramer
|
||||||
GuardianRM
|
GuardianRM
|
||||||
Günther Demetz (pb00067, pb00068)
|
|
||||||
Guy Vreuls (gvreuls)
|
Guy Vreuls (gvreuls)
|
||||||
|
Günther Demetz (pb00067, pb00068)
|
||||||
Henri Wiechers
|
Henri Wiechers
|
||||||
Hiraoka Takuya (HiraokaTakuya)
|
Hiraoka Takuya (HiraokaTakuya)
|
||||||
homoSapiensSapiens
|
homoSapiensSapiens
|
||||||
Hongzhi Cheng
|
Hongzhi Cheng
|
||||||
Ivan Ivec (IIvec)
|
Ivan Ivec (IIvec)
|
||||||
Jacques B. (Timshel)
|
Jacques B. (Timshel)
|
||||||
|
Jake Senne (w1wwwwww)
|
||||||
Jan Ondruš (hxim)
|
Jan Ondruš (hxim)
|
||||||
Jared Kish (Kurtbusch)
|
Jared Kish (Kurtbusch, kurt22i)
|
||||||
Jarrod Torriero (DU-jdto)
|
Jarrod Torriero (DU-jdto)
|
||||||
Jean Gauthier (OuaisBla)
|
|
||||||
Jean-Francois Romang (jromang)
|
Jean-Francois Romang (jromang)
|
||||||
|
Jean Gauthier (OuaisBla)
|
||||||
Jekaa
|
Jekaa
|
||||||
Jerry Donald Watson (jerrydonaldwatson)
|
Jerry Donald Watson (jerrydonaldwatson)
|
||||||
jjoshua2
|
jjoshua2
|
||||||
Jonathan Calovski (Mysseno)
|
|
||||||
Jonathan Buladas Dumale (SFisGOD)
|
Jonathan Buladas Dumale (SFisGOD)
|
||||||
|
Jonathan Calovski (Mysseno)
|
||||||
|
Jonathan McDermid (jonathanmcdermid)
|
||||||
Joost VandeVondele (vondele)
|
Joost VandeVondele (vondele)
|
||||||
Jörg Oster (joergoster)
|
|
||||||
Joseph Ellis (jhellis3)
|
Joseph Ellis (jhellis3)
|
||||||
Joseph R. Prostko
|
Joseph R. Prostko
|
||||||
|
Jörg Oster (joergoster)
|
||||||
Julian Willemer (NightlyKing)
|
Julian Willemer (NightlyKing)
|
||||||
jundery
|
jundery
|
||||||
Justin Blanchard (UncombedCoconut)
|
Justin Blanchard (UncombedCoconut)
|
||||||
Kelly Wilson
|
Kelly Wilson
|
||||||
Ken Takusagawa
|
Ken Takusagawa
|
||||||
|
Kian E (KJE-98)
|
||||||
kinderchocolate
|
kinderchocolate
|
||||||
Kiran Panditrao (Krgp)
|
Kiran Panditrao (Krgp)
|
||||||
Kojirion
|
Kojirion
|
||||||
@@ -110,6 +119,7 @@ Krystian Kuzniarek (kuzkry)
|
|||||||
Leonardo Ljubičić (ICCF World Champion)
|
Leonardo Ljubičić (ICCF World Champion)
|
||||||
Leonid Pechenik (lp--)
|
Leonid Pechenik (lp--)
|
||||||
Liam Keegan (lkeegan)
|
Liam Keegan (lkeegan)
|
||||||
|
Linmiao Xu (linrock)
|
||||||
Linus Arver (listx)
|
Linus Arver (listx)
|
||||||
loco-loco
|
loco-loco
|
||||||
Lub van den Berg (ElbertoOne)
|
Lub van den Berg (ElbertoOne)
|
||||||
@@ -123,6 +133,8 @@ marotear
|
|||||||
Matt Ginsberg (mattginsberg)
|
Matt Ginsberg (mattginsberg)
|
||||||
Matthew Lai (matthewlai)
|
Matthew Lai (matthewlai)
|
||||||
Matthew Sullivan (Matt14916)
|
Matthew Sullivan (Matt14916)
|
||||||
|
Max A. (Disservin)
|
||||||
|
Maxim Masiutin (maximmasiutin)
|
||||||
Maxim Molchanov (Maxim)
|
Maxim Molchanov (Maxim)
|
||||||
Michael An (man)
|
Michael An (man)
|
||||||
Michael Byrne (MichaelB7)
|
Michael Byrne (MichaelB7)
|
||||||
@@ -132,39 +144,46 @@ Michael Whiteley (protonspring)
|
|||||||
Michel Van den Bergh (vdbergh)
|
Michel Van den Bergh (vdbergh)
|
||||||
Miguel Lahoz (miguel-l)
|
Miguel Lahoz (miguel-l)
|
||||||
Mikael Bäckman (mbootsector)
|
Mikael Bäckman (mbootsector)
|
||||||
|
Mike Babigian (Farseer)
|
||||||
Mira
|
Mira
|
||||||
Miroslav Fontán (Hexik)
|
Miroslav Fontán (Hexik)
|
||||||
Moez Jellouli (MJZ1977)
|
Moez Jellouli (MJZ1977)
|
||||||
Mohammed Li (tthsqe12)
|
Mohammed Li (tthsqe12)
|
||||||
|
Muzhen J (XInTheDark)
|
||||||
Nathan Rugg (nmrugg)
|
Nathan Rugg (nmrugg)
|
||||||
Nick Pelling (nickpelling)
|
Nguyen Pham (nguyenpham)
|
||||||
Nicklas Persson (NicklasPersson)
|
Nicklas Persson (NicklasPersson)
|
||||||
|
Nick Pelling (nickpelling)
|
||||||
Niklas Fiekas (niklasf)
|
Niklas Fiekas (niklasf)
|
||||||
Nikolay Kostov (NikolayIT)
|
Nikolay Kostov (NikolayIT)
|
||||||
Nguyen Pham (nguyenpham)
|
|
||||||
Norman Schmidt (FireFather)
|
Norman Schmidt (FireFather)
|
||||||
notruck
|
notruck
|
||||||
Ofek Shochat (OfekShochat, ghostway)
|
Ofek Shochat (OfekShochat, ghostway)
|
||||||
Ondrej Mosnáček (WOnder93)
|
Ondrej Mosnáček (WOnder93)
|
||||||
|
Ondřej Mišina (AndrovT)
|
||||||
Oskar Werkelin Ahlin
|
Oskar Werkelin Ahlin
|
||||||
Pablo Vazquez
|
Pablo Vazquez
|
||||||
Panthee
|
Panthee
|
||||||
Pascal Romaret
|
Pascal Romaret
|
||||||
Pasquale Pigazzini (ppigazzini)
|
Pasquale Pigazzini (ppigazzini)
|
||||||
Patrick Jansen (mibere)
|
Patrick Jansen (mibere)
|
||||||
pellanda
|
Peter Schneider (pschneider1968)
|
||||||
Peter Zsifkovits (CoffeeOne)
|
Peter Zsifkovits (CoffeeOne)
|
||||||
|
PikaCat
|
||||||
Praveen Kumar Tummala (praveentml)
|
Praveen Kumar Tummala (praveentml)
|
||||||
|
Prokop Randáček (ProkopRandacek)
|
||||||
Rahul Dsilva (silversolver1)
|
Rahul Dsilva (silversolver1)
|
||||||
Ralph Stößer (Ralph Stoesser)
|
Ralph Stößer (Ralph Stoesser)
|
||||||
Raminder Singh
|
Raminder Singh
|
||||||
renouve
|
renouve
|
||||||
Reuven Peleg
|
Reuven Peleg (R-Peleg)
|
||||||
Richard Lloyd
|
Richard Lloyd (Richard-Lloyd)
|
||||||
Rodrigo Exterckötter Tjäder
|
Rodrigo Exterckötter Tjäder
|
||||||
Ron Britvich (Britvich)
|
Rodrigo Roim (roim)
|
||||||
Ronald de Man (syzygy1, syzygy)
|
Ronald de Man (syzygy1, syzygy)
|
||||||
|
Ron Britvich (Britvich)
|
||||||
rqs
|
rqs
|
||||||
|
Rui Coelho (ruicoelhopedro)
|
||||||
Ryan Schmitt
|
Ryan Schmitt
|
||||||
Ryan Takker
|
Ryan Takker
|
||||||
Sami Kiminki (skiminki)
|
Sami Kiminki (skiminki)
|
||||||
@@ -173,20 +192,22 @@ Sergei Antonov (saproj)
|
|||||||
Sergei Ivanov (svivanov72)
|
Sergei Ivanov (svivanov72)
|
||||||
Sergio Vieri (sergiovieri)
|
Sergio Vieri (sergiovieri)
|
||||||
sf-x
|
sf-x
|
||||||
|
Shahin M. Shahin (peregrine)
|
||||||
Shane Booth (shane31)
|
Shane Booth (shane31)
|
||||||
Shawn Varghese (xXH4CKST3RXx)
|
Shawn Varghese (xXH4CKST3RXx)
|
||||||
Siad Daboul (Topologist)
|
Siad Daboul (Topologist)
|
||||||
Stefan Geschwentner (locutus2)
|
Stefan Geschwentner (locutus2)
|
||||||
Stefano Cardanobile (Stefano80)
|
Stefano Cardanobile (Stefano80)
|
||||||
|
Stefano Di Martino (StefanoD)
|
||||||
Steinar Gunderson (sesse)
|
Steinar Gunderson (sesse)
|
||||||
Stéphane Nicolet (snicolet)
|
Stéphane Nicolet (snicolet)
|
||||||
Prokop Randáček (ProkopRandacek)
|
Syine Mineta (MinetaS)
|
||||||
Thanar2
|
Thanar2
|
||||||
thaspel
|
thaspel
|
||||||
theo77186
|
theo77186
|
||||||
|
Tomasz Sobczyk (Sopel97)
|
||||||
Tom Truscott
|
Tom Truscott
|
||||||
Tom Vijlbrief (tomtor)
|
Tom Vijlbrief (tomtor)
|
||||||
Tomasz Sobczyk (Sopel97)
|
|
||||||
Torsten Franz (torfranz, tfranzer)
|
Torsten Franz (torfranz, tfranzer)
|
||||||
Torsten Hellwig (Torom)
|
Torsten Hellwig (Torom)
|
||||||
Tracey Emery (basepr1me)
|
Tracey Emery (basepr1me)
|
||||||
@@ -194,10 +215,12 @@ tttak
|
|||||||
Unai Corzo (unaiic)
|
Unai Corzo (unaiic)
|
||||||
Uri Blass (uriblass)
|
Uri Blass (uriblass)
|
||||||
Vince Negri (cuddlestmonkey)
|
Vince Negri (cuddlestmonkey)
|
||||||
|
Viren
|
||||||
|
windfishballad
|
||||||
|
xefoci7612
|
||||||
zz4032
|
zz4032
|
||||||
|
|
||||||
|
|
||||||
# Additionally, we acknowledge the authors and maintainers of fishtest,
|
# Additionally, we acknowledge the authors and maintainers of fishtest,
|
||||||
# an amazing and essential framework for the development of Stockfish!
|
# an amazing and essential framework for Stockfish development!
|
||||||
#
|
#
|
||||||
# https://github.com/glinscott/fishtest/blob/master/AUTHORS
|
# https://github.com/glinscott/fishtest/blob/master/AUTHORS
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# This CITATION.cff file was generated with cffinit.
|
||||||
|
# Visit https://bit.ly/cffinit to generate yours today!
|
||||||
|
|
||||||
|
cff-version: 1.2.0
|
||||||
|
title: Stockfish
|
||||||
|
message: >-
|
||||||
|
Please cite this software using the metadata from this
|
||||||
|
file.
|
||||||
|
type: software
|
||||||
|
authors:
|
||||||
|
- name: The Stockfish developers (see AUTHORS file)
|
||||||
|
repository-code: 'https://github.com/official-stockfish/Stockfish'
|
||||||
|
url: 'https://stockfishchess.org/'
|
||||||
|
repository-artifact: 'https://stockfishchess.org/download/'
|
||||||
|
abstract: Stockfish is a free and strong UCI chess engine.
|
||||||
|
keywords:
|
||||||
|
- chess
|
||||||
|
- artificial intelligence (AI)
|
||||||
|
- tree search
|
||||||
|
- alpha-beta search
|
||||||
|
- neural networks (NN)
|
||||||
|
- efficiently updatable neural networks (NNUE)
|
||||||
|
license: GPL-3.0
|
||||||
@@ -1,327 +1,164 @@
|
|||||||
|
<div align="center">
|
||||||
|
|
||||||
|
[![Stockfish][stockfish128-logo]][website-link]
|
||||||
|
|
||||||
|
<h3>Stockfish</h3>
|
||||||
|
|
||||||
|
A free and strong UCI chess engine.
|
||||||
|
<br>
|
||||||
|
<strong>[Explore Stockfish docs »][wiki-link]</strong>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
[Report bug][issue-link]
|
||||||
|
·
|
||||||
|
[Open a discussion][discussions-link]
|
||||||
|
·
|
||||||
|
[Discord][discord-link]
|
||||||
|
·
|
||||||
|
[Blog][website-blog-link]
|
||||||
|
|
||||||
|
[![Build][build-badge]][build-link]
|
||||||
|
[![License][license-badge]][license-link]
|
||||||
|
<br>
|
||||||
|
[![Release][release-badge]][release-link]
|
||||||
|
[![Commits][commits-badge]][commits-link]
|
||||||
|
<br>
|
||||||
|
[![Website][website-badge]][website-link]
|
||||||
|
[![Fishtest][fishtest-badge]][fishtest-link]
|
||||||
|
[![Discord][discord-badge]][discord-link]
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
[](https://github.com/official-stockfish/Stockfish/actions)
|
[Stockfish][website-link] is a **free and strong UCI chess engine** derived from
|
||||||
[](https://ci.appveyor.com/project/mcostalba/stockfish/branch/master)
|
Glaurung 2.1 that analyzes chess positions and computes the optimal moves.
|
||||||
|
|
||||||
[Stockfish](https://stockfishchess.org) is a free, powerful UCI chess engine
|
Stockfish **does not include a graphical user interface** (GUI) that is required
|
||||||
derived from Glaurung 2.1. Stockfish is not a complete chess program and requires a
|
to display a chessboard and to make it easy to input moves. These GUIs are
|
||||||
UCI-compatible graphical user interface (GUI) (e.g. XBoard with PolyGlot, Scid,
|
developed independently from Stockfish and are available online. **Read the
|
||||||
Cute Chess, eboard, Arena, Sigma Chess, Shredder, Chess Partner or Fritz) in order
|
documentation for your GUI** of choice for information about how to use
|
||||||
to be used comfortably. Read the documentation for your GUI of choice for information
|
Stockfish with it.
|
||||||
about how to use Stockfish with it.
|
|
||||||
|
|
||||||
The Stockfish engine features two evaluation functions for chess, the classical
|
|
||||||
evaluation based on handcrafted terms, and the NNUE evaluation based on efficiently
|
|
||||||
updatable neural networks. The classical evaluation runs efficiently on almost all
|
|
||||||
CPU architectures, while the NNUE evaluation benefits from the vector
|
|
||||||
intrinsics available on most CPUs (sse2, avx2, neon, or similar).
|
|
||||||
|
|
||||||
|
See also the Stockfish [documentation][wiki-usage-link] for further usage help.
|
||||||
|
|
||||||
## Files
|
## Files
|
||||||
|
|
||||||
This distribution of Stockfish consists of the following files:
|
This distribution of Stockfish consists of the following files:
|
||||||
|
|
||||||
* [Readme.md](https://github.com/official-stockfish/Stockfish/blob/master/README.md), the file you are currently reading.
|
* [README.md][readme-link], the file you are currently reading.
|
||||||
|
|
||||||
* [Copying.txt](https://github.com/official-stockfish/Stockfish/blob/master/Copying.txt), a text file containing the GNU General Public License version 3.
|
* [Copying.txt][license-link], a text file containing the GNU General Public
|
||||||
|
License version 3.
|
||||||
|
|
||||||
* [AUTHORS](https://github.com/official-stockfish/Stockfish/blob/master/AUTHORS), a text file with the list of authors for the project
|
* [AUTHORS][authors-link], a text file with the list of authors for the project.
|
||||||
|
|
||||||
* [src](https://github.com/official-stockfish/Stockfish/tree/master/src), a subdirectory containing the full source code, including a Makefile
|
* [src][src-link], a subdirectory containing the full source code, including a
|
||||||
that can be used to compile Stockfish on Unix-like systems.
|
Makefile that can be used to compile Stockfish on Unix-like systems.
|
||||||
|
|
||||||
* a file with the .nnue extension, storing the neural network for the NNUE
|
* a file with the .nnue extension, storing the neural network for the NNUE
|
||||||
evaluation. Binary distributions will have this file embedded.
|
evaluation. Binary distributions will have this file embedded.
|
||||||
|
|
||||||
## The UCI protocol and available options
|
## The UCI protocol
|
||||||
|
|
||||||
The Universal Chess Interface (UCI) is a standard protocol used to communicate with
|
The [Universal Chess Interface][uci-link] (UCI) is a standard text-based protocol
|
||||||
a chess engine, and is the recommended way to do so for typical graphical user interfaces
|
used to communicate with a chess engine and is the recommended way to do so for
|
||||||
(GUI) or chess tools. Stockfish implements the majority of it options as described
|
typical graphical user interfaces (GUI) or chess tools. Stockfish implements the
|
||||||
in [the UCI protocol](https://www.shredderchess.com/download/div/uci.zip).
|
majority of its options.
|
||||||
|
|
||||||
Developers can see the default values for UCI options available in Stockfish by typing
|
Developers can see the default values for the UCI options available in Stockfish
|
||||||
`./stockfish uci` in a terminal, but the majority of users will typically see them and
|
by typing `./stockfish uci` in a terminal, but most users should typically use a
|
||||||
change them via a chess GUI. This is a list of available UCI options in Stockfish:
|
chess GUI to interact with Stockfish.
|
||||||
|
|
||||||
* #### Threads
|
For more information on UCI or debug commands, see our [documentation][wiki-commands-link].
|
||||||
The number of CPU threads used for searching a position. For best performance, set
|
|
||||||
this equal to the number of CPU cores available.
|
|
||||||
|
|
||||||
* #### Hash
|
## Compiling Stockfish
|
||||||
The size of the hash table in MB. It is recommended to set Hash after setting Threads.
|
|
||||||
|
|
||||||
* #### Clear Hash
|
Stockfish has support for 32 or 64-bit CPUs, certain hardware instructions,
|
||||||
Clear the hash table.
|
big-endian machines such as Power PC, and other platforms.
|
||||||
|
|
||||||
* #### Ponder
|
On Unix-like systems, it should be easy to compile Stockfish directly from the
|
||||||
Let Stockfish ponder its next move while the opponent is thinking.
|
source code with the included Makefile in the folder `src`. In general, it is
|
||||||
|
recommended to run `make help` to see a list of make targets with corresponding
|
||||||
* #### MultiPV
|
descriptions.
|
||||||
Output the N best lines (principal variations, PVs) when searching.
|
|
||||||
Leave at 1 for best performance.
|
|
||||||
|
|
||||||
* #### Use NNUE
|
|
||||||
Toggle between the NNUE and classical evaluation functions. If set to "true",
|
|
||||||
the network parameters must be available to load from file (see also EvalFile),
|
|
||||||
if they are not embedded in the binary.
|
|
||||||
|
|
||||||
* #### EvalFile
|
|
||||||
The name of the file of the NNUE evaluation parameters. Depending on the GUI the
|
|
||||||
filename might have to include the full path to the folder/directory that contains the file.
|
|
||||||
Other locations, such as the directory that contains the binary and the working directory,
|
|
||||||
are also searched.
|
|
||||||
|
|
||||||
* #### UCI_AnalyseMode
|
|
||||||
An option handled by your GUI.
|
|
||||||
|
|
||||||
* #### UCI_Chess960
|
|
||||||
An option handled by your GUI. If true, Stockfish will play Chess960.
|
|
||||||
|
|
||||||
* #### UCI_ShowWDL
|
|
||||||
If enabled, show approximate WDL statistics as part of the engine output.
|
|
||||||
These WDL numbers model expected game outcomes for a given evaluation and
|
|
||||||
game ply for engine self-play at fishtest LTC conditions (60+0.6s per game).
|
|
||||||
|
|
||||||
* #### UCI_LimitStrength
|
|
||||||
Enable weaker play aiming for an Elo rating as set by UCI_Elo. This option overrides Skill Level.
|
|
||||||
|
|
||||||
* #### UCI_Elo
|
|
||||||
If enabled by UCI_LimitStrength, aim for an engine strength of the given Elo.
|
|
||||||
This Elo rating has been calibrated at a time control of 60s+0.6s and anchored to CCRL 40/4.
|
|
||||||
|
|
||||||
* #### Skill Level
|
|
||||||
Lower the Skill Level in order to make Stockfish play weaker (see also UCI_LimitStrength).
|
|
||||||
Internally, MultiPV is enabled, and with a certain probability depending on the Skill Level a
|
|
||||||
weaker move will be played.
|
|
||||||
|
|
||||||
* #### SyzygyPath
|
|
||||||
Path to the folders/directories storing the Syzygy tablebase files. Multiple
|
|
||||||
directories are to be separated by ";" on Windows and by ":" on Unix-based
|
|
||||||
operating systems. Do not use spaces around the ";" or ":".
|
|
||||||
|
|
||||||
Example: `C:\tablebases\wdl345;C:\tablebases\wdl6;D:\tablebases\dtz345;D:\tablebases\dtz6`
|
|
||||||
|
|
||||||
It is recommended to store .rtbw files on an SSD. There is no loss in storing
|
|
||||||
the .rtbz files on a regular HD. It is recommended to verify all md5 checksums
|
|
||||||
of the downloaded tablebase files (`md5sum -c checksum.md5`) as corruption will
|
|
||||||
lead to engine crashes.
|
|
||||||
|
|
||||||
* #### SyzygyProbeDepth
|
|
||||||
Minimum remaining search depth for which a position is probed. Set this option
|
|
||||||
to a higher value to probe less aggressively if you experience too much slowdown
|
|
||||||
(in terms of nps) due to tablebase probing.
|
|
||||||
|
|
||||||
* #### Syzygy50MoveRule
|
|
||||||
Disable to let fifty-move rule draws detected by Syzygy tablebase probes count
|
|
||||||
as wins or losses. This is useful for ICCF correspondence games.
|
|
||||||
|
|
||||||
* #### SyzygyProbeLimit
|
|
||||||
Limit Syzygy tablebase probing to positions with at most this many pieces left
|
|
||||||
(including kings and pawns).
|
|
||||||
|
|
||||||
* #### Move Overhead
|
|
||||||
Assume a time delay of x ms due to network and GUI overheads. This is useful to
|
|
||||||
avoid losses on time in those cases.
|
|
||||||
|
|
||||||
* #### Slow Mover
|
|
||||||
Lower values will make Stockfish take less time in games, higher values will
|
|
||||||
make it think longer.
|
|
||||||
|
|
||||||
* #### nodestime
|
|
||||||
Tells the engine to use nodes searched instead of wall time to account for
|
|
||||||
elapsed time. Useful for engine testing.
|
|
||||||
|
|
||||||
* #### Debug Log File
|
|
||||||
Write all communication to and from the engine into a text file.
|
|
||||||
|
|
||||||
For developers the following non-standard commands might be of interest, mainly useful for debugging:
|
|
||||||
|
|
||||||
* #### bench *ttSize threads limit fenFile limitType evalType*
|
|
||||||
Performs a standard benchmark using various options. The signature of a version (standard node
|
|
||||||
count) is obtained using all defaults. `bench` is currently `bench 16 1 13 default depth mixed`.
|
|
||||||
|
|
||||||
* #### compiler
|
|
||||||
Give information about the compiler and environment used for building a binary.
|
|
||||||
|
|
||||||
* #### d
|
|
||||||
Display the current position, with ascii art and fen.
|
|
||||||
|
|
||||||
* #### eval
|
|
||||||
Return the evaluation of the current position.
|
|
||||||
|
|
||||||
* #### export_net [filename]
|
|
||||||
Exports the currently loaded network to a file.
|
|
||||||
If the currently loaded network is the embedded network and the filename
|
|
||||||
is not specified then the network is saved to the file matching the name
|
|
||||||
of the embedded network, as defined in evaluate.h.
|
|
||||||
If the currently loaded network is not the embedded network (some net set
|
|
||||||
through the UCI setoption) then the filename parameter is required and the
|
|
||||||
network is saved into that file.
|
|
||||||
|
|
||||||
* #### flip
|
|
||||||
Flips the side to move.
|
|
||||||
|
|
||||||
|
|
||||||
## A note on classical evaluation versus NNUE evaluation
|
|
||||||
|
|
||||||
Both approaches assign a value to a position that is used in alpha-beta (PVS) search
|
|
||||||
to find the best move. The classical evaluation computes this value as a function
|
|
||||||
of various chess concepts, handcrafted by experts, tested and tuned using fishtest.
|
|
||||||
The NNUE evaluation computes this value with a neural network based on basic
|
|
||||||
inputs (e.g. piece positions only). The network is optimized and trained
|
|
||||||
on the evaluations of millions of positions at moderate search depth.
|
|
||||||
|
|
||||||
The NNUE evaluation was first introduced in shogi, and ported to Stockfish afterward.
|
|
||||||
It can be evaluated efficiently on CPUs, and exploits the fact that only parts
|
|
||||||
of the neural network need to be updated after a typical chess move.
|
|
||||||
[The nodchip repository](https://github.com/nodchip/Stockfish) provides additional
|
|
||||||
tools to train and develop the NNUE networks. On CPUs supporting modern vector instructions
|
|
||||||
(avx2 and similar), the NNUE evaluation results in much stronger playing strength, even
|
|
||||||
if the nodes per second computed by the engine is somewhat lower (roughly 80% of nps
|
|
||||||
is typical).
|
|
||||||
|
|
||||||
Notes:
|
|
||||||
|
|
||||||
1) the NNUE evaluation depends on the Stockfish binary and the network parameter
|
|
||||||
file (see the EvalFile UCI option). Not every parameter file is compatible with a given
|
|
||||||
Stockfish binary, but the default value of the EvalFile UCI option is the name of a network
|
|
||||||
that is guaranteed to be compatible with that binary.
|
|
||||||
|
|
||||||
2) to use the NNUE evaluation, the additional data file with neural network parameters
|
|
||||||
needs to be available. Normally, this file is already embedded in the binary or it
|
|
||||||
can be downloaded. The filename for the default (recommended) net can be found as the default
|
|
||||||
value of the `EvalFile` UCI option, with the format `nn-[SHA256 first 12 digits].nnue`
|
|
||||||
(for instance, `nn-c157e0a5755b.nnue`). This file can be downloaded from
|
|
||||||
```
|
|
||||||
https://tests.stockfishchess.org/api/nn/[filename]
|
|
||||||
```
|
|
||||||
replacing `[filename]` as needed.
|
|
||||||
|
|
||||||
## What to expect from the Syzygy tablebases?
|
|
||||||
|
|
||||||
If the engine is searching a position that is not in the tablebases (e.g.
|
|
||||||
a position with 8 pieces), it will access the tablebases during the search.
|
|
||||||
If the engine reports a very large score (typically 153.xx), this means
|
|
||||||
it has found a winning line into a tablebase position.
|
|
||||||
|
|
||||||
If the engine is given a position to search that is in the tablebases, it
|
|
||||||
will use the tablebases at the beginning of the search to preselect all
|
|
||||||
good moves, i.e. all moves that preserve the win or preserve the draw while
|
|
||||||
taking into account the 50-move rule.
|
|
||||||
It will then perform a search only on those moves. **The engine will not move
|
|
||||||
immediately**, unless there is only a single good move. **The engine likely
|
|
||||||
will not report a mate score, even if the position is known to be won.**
|
|
||||||
|
|
||||||
It is therefore clear that this behaviour is not identical to what one might
|
|
||||||
be used to with Nalimov tablebases. There are technical reasons for this
|
|
||||||
difference, the main technical reason being that Nalimov tablebases use the
|
|
||||||
DTM metric (distance-to-mate), while the Syzygy tablebases use a variation of the
|
|
||||||
DTZ metric (distance-to-zero, zero meaning any move that resets the 50-move
|
|
||||||
counter). This special metric is one of the reasons that the Syzygy tablebases are
|
|
||||||
more compact than Nalimov tablebases, while still storing all information
|
|
||||||
needed for optimal play and in addition being able to take into account
|
|
||||||
the 50-move rule.
|
|
||||||
|
|
||||||
## Large Pages
|
|
||||||
|
|
||||||
Stockfish supports large pages on Linux and Windows. Large pages make
|
|
||||||
the hash access more efficient, improving the engine speed, especially
|
|
||||||
on large hash sizes. Typical increases are 5..10% in terms of nodes per
|
|
||||||
second, but speed increases up to 30% have been measured. The support is
|
|
||||||
automatic. Stockfish attempts to use large pages when available and
|
|
||||||
will fall back to regular memory allocation when this is not the case.
|
|
||||||
|
|
||||||
### Support on Linux
|
|
||||||
|
|
||||||
Large page support on Linux is obtained by the Linux kernel
|
|
||||||
transparent huge pages functionality. Typically, transparent huge pages
|
|
||||||
are already enabled, and no configuration is needed.
|
|
||||||
|
|
||||||
### Support on Windows
|
|
||||||
|
|
||||||
The use of large pages requires "Lock Pages in Memory" privilege. See
|
|
||||||
[Enable the Lock Pages in Memory Option (Windows)](https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/enable-the-lock-pages-in-memory-option-windows)
|
|
||||||
on how to enable this privilege, then run [RAMMap](https://docs.microsoft.com/en-us/sysinternals/downloads/rammap)
|
|
||||||
to double-check that large pages are used. We suggest that you reboot
|
|
||||||
your computer after you have enabled large pages, because long Windows
|
|
||||||
sessions suffer from memory fragmentation, which may prevent Stockfish
|
|
||||||
from getting large pages: a fresh session is better in this regard.
|
|
||||||
|
|
||||||
## Compiling Stockfish yourself from the sources
|
|
||||||
|
|
||||||
Stockfish has support for 32 or 64-bit CPUs, certain hardware
|
|
||||||
instructions, big-endian machines such as Power PC, and other platforms.
|
|
||||||
|
|
||||||
On Unix-like systems, it should be easy to compile Stockfish
|
|
||||||
directly from the source code with the included Makefile in the folder
|
|
||||||
`src`. In general it is recommended to run `make help` to see a list of make
|
|
||||||
targets with corresponding descriptions.
|
|
||||||
|
|
||||||
```
|
```
|
||||||
cd src
|
cd src
|
||||||
make help
|
make -j build ARCH=x86-64-modern
|
||||||
make net
|
|
||||||
make build ARCH=x86-64-modern
|
|
||||||
```
|
```
|
||||||
|
|
||||||
When not using the Makefile to compile (for instance, with Microsoft MSVC) you
|
Detailed compilation instructions for all platforms can be found in our
|
||||||
need to manually set/unset some switches in the compiler command line; see
|
[documentation][wiki-compile-link].
|
||||||
file *types.h* for a quick reference.
|
|
||||||
|
|
||||||
When reporting an issue or a bug, please tell us which Stockfish version
|
## Contributing
|
||||||
and which compiler you used to create your executable. This information
|
|
||||||
can be found by typing the following command in a console:
|
|
||||||
|
|
||||||
```
|
|
||||||
./stockfish compiler
|
|
||||||
```
|
|
||||||
|
|
||||||
## Understanding the code base and participating in the project
|
|
||||||
|
|
||||||
Stockfish's improvement over the last decade has been a great community
|
|
||||||
effort. There are a few ways to help contribute to its growth.
|
|
||||||
|
|
||||||
### Donating hardware
|
### Donating hardware
|
||||||
|
|
||||||
Improving Stockfish requires a massive amount of testing. You can donate
|
Improving Stockfish requires a massive amount of testing. You can donate your
|
||||||
your hardware resources by installing the [Fishtest Worker](https://github.com/glinscott/fishtest/wiki/Running-the-worker:-overview)
|
hardware resources by installing the [Fishtest Worker][worker-link] and viewing
|
||||||
and view the current tests on [Fishtest](https://tests.stockfishchess.org/tests).
|
the current tests on [Fishtest][fishtest-link].
|
||||||
|
|
||||||
### Improving the code
|
### Improving the code
|
||||||
|
|
||||||
If you want to help improve the code, there are several valuable resources:
|
In the [chessprogramming wiki][programming-link], many techniques used in
|
||||||
|
|
||||||
* [In this wiki,](https://www.chessprogramming.org) many techniques used in
|
|
||||||
Stockfish are explained with a lot of background information.
|
Stockfish are explained with a lot of background information.
|
||||||
|
The [section on Stockfish][programmingsf-link] describes many features
|
||||||
|
and techniques used by Stockfish. However, it is generic rather than
|
||||||
|
focused on Stockfish's precise implementation.
|
||||||
|
|
||||||
* [The section on Stockfish](https://www.chessprogramming.org/Stockfish)
|
The engine testing is done on [Fishtest][fishtest-link].
|
||||||
describes many features and techniques used by Stockfish. However, it is
|
If you want to help improve Stockfish, please read this [guideline][guideline-link]
|
||||||
generic rather than being focused on Stockfish's precise implementation.
|
|
||||||
Nevertheless, a helpful resource.
|
|
||||||
|
|
||||||
* The latest source can always be found on [GitHub](https://github.com/official-stockfish/Stockfish).
|
|
||||||
Discussions about Stockfish take place these days mainly in the [FishCooking](https://groups.google.com/forum/#!forum/fishcooking)
|
|
||||||
group and on the [Stockfish Discord channel](https://discord.gg/nv8gDtt).
|
|
||||||
The engine testing is done on [Fishtest](https://tests.stockfishchess.org/tests).
|
|
||||||
If you want to help improve Stockfish, please read this [guideline](https://github.com/glinscott/fishtest/wiki/Creating-my-first-test)
|
|
||||||
first, where the basics of Stockfish development are explained.
|
first, where the basics of Stockfish development are explained.
|
||||||
|
|
||||||
|
Discussions about Stockfish take place these days mainly in the Stockfish
|
||||||
|
[Discord server][discord-link]. This is also the best place to ask questions
|
||||||
|
about the codebase and how to improve it.
|
||||||
|
|
||||||
## Terms of use
|
## Terms of use
|
||||||
|
|
||||||
Stockfish is free, and distributed under the **GNU General Public License version 3**
|
Stockfish is free and distributed under the
|
||||||
(GPL v3). Essentially, this means you are free to do almost exactly
|
[**GNU General Public License version 3**][license-link] (GPL v3). Essentially,
|
||||||
what you want with the program, including distributing it among your
|
this means you are free to do almost exactly what you want with the program,
|
||||||
friends, making it available for download from your website, selling
|
including distributing it among your friends, making it available for download
|
||||||
it (either by itself or as part of some bigger software package), or
|
from your website, selling it (either by itself or as part of some bigger
|
||||||
using it as the starting point for a software project of your own.
|
software package), or using it as the starting point for a software project of
|
||||||
|
your own.
|
||||||
|
|
||||||
The only real limitation is that whenever you distribute Stockfish in
|
The only real limitation is that whenever you distribute Stockfish in some way,
|
||||||
some way, you MUST always include the full source code, or a pointer
|
you MUST always include the license and the full source code (or a pointer to
|
||||||
to where the source code can be found, to generate the exact binary
|
where the source code can be found) to generate the exact binary you are
|
||||||
you are distributing. If you make any changes to the source code,
|
distributing. If you make any changes to the source code, these changes must
|
||||||
these changes must also be made available under the GPL.
|
also be made available under GPL v3.
|
||||||
|
|
||||||
For full details, read the copy of the GPL v3 found in the file named
|
|
||||||
[*Copying.txt*](https://github.com/official-stockfish/Stockfish/blob/master/Copying.txt).
|
[authors-link]: https://github.com/official-stockfish/Stockfish/blob/master/AUTHORS
|
||||||
|
[build-link]: https://github.com/official-stockfish/Stockfish/actions/workflows/stockfish.yml
|
||||||
|
[commits-link]: https://github.com/official-stockfish/Stockfish/commits/master
|
||||||
|
[discord-link]: https://discord.gg/GWDRS3kU6R
|
||||||
|
[issue-link]: https://github.com/official-stockfish/Stockfish/issues/new?assignees=&labels=&template=BUG-REPORT.yml
|
||||||
|
[discussions-link]: https://github.com/official-stockfish/Stockfish/discussions/new
|
||||||
|
[fishtest-link]: https://tests.stockfishchess.org/tests
|
||||||
|
[guideline-link]: https://github.com/glinscott/fishtest/wiki/Creating-my-first-test
|
||||||
|
[license-link]: https://github.com/official-stockfish/Stockfish/blob/master/Copying.txt
|
||||||
|
[programming-link]: https://www.chessprogramming.org/Main_Page
|
||||||
|
[programmingsf-link]: https://www.chessprogramming.org/Stockfish
|
||||||
|
[readme-link]: https://github.com/official-stockfish/Stockfish/blob/master/README.md
|
||||||
|
[release-link]: https://github.com/official-stockfish/Stockfish/releases/latest
|
||||||
|
[src-link]: https://github.com/official-stockfish/Stockfish/tree/master/src
|
||||||
|
[stockfish128-logo]: https://stockfishchess.org/images/logo/icon_128x128.png
|
||||||
|
[uci-link]: https://backscattering.de/chess/uci/
|
||||||
|
[website-link]: https://stockfishchess.org
|
||||||
|
[website-blog-link]: https://stockfishchess.org/blog/
|
||||||
|
[wiki-link]: https://github.com/official-stockfish/Stockfish/wiki
|
||||||
|
[wiki-usage-link]: https://github.com/official-stockfish/Stockfish/wiki/Download-and-usage
|
||||||
|
[wiki-compile-link]: https://github.com/official-stockfish/Stockfish/wiki/Compiling-from-source
|
||||||
|
[wiki-commands-link]: https://github.com/official-stockfish/Stockfish/wiki/Commands
|
||||||
|
[worker-link]: https://github.com/glinscott/fishtest/wiki/Running-the-worker
|
||||||
|
|
||||||
|
[build-badge]: https://img.shields.io/github/actions/workflow/status/official-stockfish/Stockfish/stockfish.yml?branch=master&style=for-the-badge&label=stockfish&logo=github
|
||||||
|
[commits-badge]: https://img.shields.io/github/commits-since/official-stockfish/Stockfish/latest?style=for-the-badge
|
||||||
|
[discord-badge]: https://img.shields.io/discord/435943710472011776?style=for-the-badge&label=discord&logo=Discord
|
||||||
|
[fishtest-badge]: https://img.shields.io/website?style=for-the-badge&down_color=red&down_message=Offline&label=Fishtest&up_color=success&up_message=Online&url=https%3A%2F%2Ftests.stockfishchess.org%2Ftests%2Ffinished
|
||||||
|
[license-badge]: https://img.shields.io/github/license/official-stockfish/Stockfish?style=for-the-badge&label=license&color=success
|
||||||
|
[release-badge]: https://img.shields.io/github/v/release/official-stockfish/Stockfish?style=for-the-badge&label=official%20release
|
||||||
|
[website-badge]: https://img.shields.io/website?style=for-the-badge&down_color=red&down_message=Offline&label=website&up_color=success&up_message=Online&url=https%3A%2F%2Fstockfishchess.org
|
||||||
|
|||||||
+150
-88
@@ -1,205 +1,267 @@
|
|||||||
Contributors to Fishtest with >10,000 CPU hours, as of Jun 29, 2021.
|
Contributors to Fishtest with >10,000 CPU hours, as of 2023-06-20.
|
||||||
Thank you!
|
Thank you!
|
||||||
|
|
||||||
Username CPU Hours Games played
|
Username CPU Hours Games played
|
||||||
-----------------------------------------------------
|
------------------------------------------------------------------
|
||||||
noobpwnftw 27649494 1834734733
|
noobpwnftw 37457426 2850540907
|
||||||
mlang 1426107 89454622
|
technologov 14135647 742892808
|
||||||
dew 1380910 82831648
|
linrock 4423514 303254809
|
||||||
|
mlang 3026000 200065824
|
||||||
|
dew 1689162 100033738
|
||||||
|
okrout 1578136 148855886
|
||||||
|
pemo 1508508 48814305
|
||||||
|
grandphish2 1461406 91540343
|
||||||
|
TueRens 1194790 70400852
|
||||||
|
JojoM 947612 61773190
|
||||||
|
tvijlbrief 796125 51897690
|
||||||
|
sebastronomy 742434 38218524
|
||||||
mibere 703840 46867607
|
mibere 703840 46867607
|
||||||
grandphish2 692707 41737913
|
gvreuls 651026 42988582
|
||||||
tvijlbrief 669642 42371594
|
oz 543438 39314736
|
||||||
JojoM 597778 35297180
|
cw 517858 34869755
|
||||||
TueRens 519226 31823562
|
fastgm 503862 30260818
|
||||||
cw 458421 30307421
|
leszek 467278 33514883
|
||||||
fastgm 439667 25950040
|
CSU_Dynasty 464940 31177118
|
||||||
gvreuls 436599 28177460
|
ctoks 434416 28506889
|
||||||
crunchy 427035 27344275
|
crunchy 427035 27344275
|
||||||
CSU_Dynasty 374765 25106278
|
maximmasiutin 424795 26577722
|
||||||
Fisherman 326901 21822979
|
bcross 415722 29060963
|
||||||
ctoks 325477 21767943
|
olafm 395922 32268020
|
||||||
velislav 295343 18844324
|
rpngn 348378 24560289
|
||||||
linrock 292789 10624427
|
velislav 342567 22138992
|
||||||
bcross 278584 19488961
|
Fisherman 327231 21829379
|
||||||
okrout 262818 13803272
|
mgrabiak 300612 20608380
|
||||||
pemo 245982 11376085
|
Dantist 296386 18031762
|
||||||
glinscott 217799 13780820
|
nordlandia 246201 16189678
|
||||||
leszek 212346 12959025
|
robal 241300 15656382
|
||||||
nordlandia 211692 13484886
|
marrco 234581 17714473
|
||||||
|
ncfish1 227517 15233777
|
||||||
|
glinscott 208125 13277240
|
||||||
|
drabel 204167 13930674
|
||||||
|
mhoram 202894 12601997
|
||||||
bking_US 198894 11876016
|
bking_US 198894 11876016
|
||||||
drabel 196463 13450602
|
|
||||||
robal 195473 12375650
|
|
||||||
mgrabiak 187226 12016564
|
|
||||||
Dantist 183202 10990484
|
|
||||||
Thanar 179852 12365359
|
Thanar 179852 12365359
|
||||||
vdv 175274 9889046
|
vdv 175544 9904472
|
||||||
spams 157128 10319326
|
spams 157128 10319326
|
||||||
marrco 150295 9402141
|
|
||||||
sqrt2 147963 9724586
|
sqrt2 147963 9724586
|
||||||
mhoram 141278 8901241
|
DesolatedDodo 146350 9536172
|
||||||
|
Calis007 143165 9478764
|
||||||
|
vdbergh 138650 9064413
|
||||||
CoffeeOne 137100 5024116
|
CoffeeOne 137100 5024116
|
||||||
vdbergh 137041 8926915
|
armo9494 136191 9460264
|
||||||
malala 136182 8002293
|
malala 136182 8002293
|
||||||
xoto 133702 9156676
|
xoto 133759 9159372
|
||||||
davar 122092 7960001
|
davar 129023 8376525
|
||||||
|
DMBK 122960 8980062
|
||||||
dsmith 122059 7570238
|
dsmith 122059 7570238
|
||||||
|
amicic 119661 7938029
|
||||||
Data 113305 8220352
|
Data 113305 8220352
|
||||||
BrunoBanani 112960 7436849
|
BrunoBanani 112960 7436849
|
||||||
|
CypressChess 108331 7759788
|
||||||
|
skiminki 107583 7218170
|
||||||
|
jcAEie 105675 8238962
|
||||||
MaZePallas 102823 6633619
|
MaZePallas 102823 6633619
|
||||||
sterni1971 100532 5880772
|
sterni1971 100532 5880772
|
||||||
|
sunu 100167 7040199
|
||||||
|
zeryl 99331 6221261
|
||||||
|
thirdlife 99124 2242380
|
||||||
ElbertoOne 99028 7023771
|
ElbertoOne 99028 7023771
|
||||||
|
cuistot 98853 6069816
|
||||||
|
bigpen0r 94809 6529203
|
||||||
brabos 92118 6186135
|
brabos 92118 6186135
|
||||||
oz 92100 6486640
|
Wolfgang 91939 6105872
|
||||||
psk 89957 5984901
|
psk 89957 5984901
|
||||||
amicic 89156 5392305
|
sschnee 88235 5268000
|
||||||
sunu 88851 6028873
|
racerschmacer 85805 6122790
|
||||||
|
Fifis 85722 5709729
|
||||||
|
Dubslow 84986 6042456
|
||||||
Vizvezdenec 83761 5344740
|
Vizvezdenec 83761 5344740
|
||||||
0x3C33 82614 5271253
|
0x3C33 82614 5271253
|
||||||
BRAVONE 81239 5054681
|
BRAVONE 81239 5054681
|
||||||
racerschmacer 80899 5759262
|
|
||||||
cuistot 80300 4606144
|
|
||||||
nssy 76497 5259388
|
nssy 76497 5259388
|
||||||
|
jromang 76106 5236025
|
||||||
teddybaer 75125 5407666
|
teddybaer 75125 5407666
|
||||||
|
tolkki963 74762 5149662
|
||||||
|
megaman7de 74351 4940352
|
||||||
|
Wencey 74181 4711488
|
||||||
Pking_cda 73776 5293873
|
Pking_cda 73776 5293873
|
||||||
jromang 72192 5057715
|
yurikvelo 73150 5004382
|
||||||
|
markkulix 72607 5304642
|
||||||
|
Bobo1239 70579 4794999
|
||||||
solarlight 70517 5028306
|
solarlight 70517 5028306
|
||||||
dv8silencer 70287 3883992
|
dv8silencer 70287 3883992
|
||||||
Bobo1239 68515 4652287
|
|
||||||
manap 66273 4121774
|
manap 66273 4121774
|
||||||
skiminki 65088 4023328
|
|
||||||
tinker 64333 4268790
|
tinker 64333 4268790
|
||||||
sschnee 60767 3500800
|
qurashee 61208 3429862
|
||||||
qurashee 57344 3168264
|
Mineta 59357 4418202
|
||||||
|
Spprtr 58723 3911011
|
||||||
|
AGI 58147 4325994
|
||||||
robnjr 57262 4053117
|
robnjr 57262 4053117
|
||||||
Freja 56938 3733019
|
Freja 56938 3733019
|
||||||
|
MaxKlaxxMiner 56879 3423958
|
||||||
|
MarcusTullius 56746 3762951
|
||||||
ttruscott 56010 3680085
|
ttruscott 56010 3680085
|
||||||
rkl 55132 4164467
|
rkl 55132 4164467
|
||||||
renouve 53811 3501516
|
renouve 53811 3501516
|
||||||
|
javran 53785 4627608
|
||||||
finfish 51360 3370515
|
finfish 51360 3370515
|
||||||
eva42 51272 3599691
|
eva42 51272 3599691
|
||||||
|
eastorwest 51117 3454811
|
||||||
rap 49985 3219146
|
rap 49985 3219146
|
||||||
pb00067 49727 3298270
|
pb00067 49733 3298934
|
||||||
|
OuaisBla 48626 3445134
|
||||||
ronaldjerum 47654 3240695
|
ronaldjerum 47654 3240695
|
||||||
bigpen0r 47653 3335327
|
|
||||||
eastorwest 47585 3221629
|
|
||||||
biffhero 46564 3111352
|
biffhero 46564 3111352
|
||||||
VoyagerOne 45476 3452465
|
VoyagerOne 45476 3452465
|
||||||
yurikvelo 44834 3034550
|
jmdana 44893 3065205
|
||||||
|
maposora 44597 4039578
|
||||||
|
oryx 44570 3454238
|
||||||
speedycpu 43842 3003273
|
speedycpu 43842 3003273
|
||||||
jbwiebe 43305 2805433
|
jbwiebe 43305 2805433
|
||||||
Spprtr 42279 2680153
|
GPUex 42378 3133332
|
||||||
DesolatedDodo 42007 2447516
|
|
||||||
Antihistamine 41788 2761312
|
Antihistamine 41788 2761312
|
||||||
mhunt 41735 2691355
|
mhunt 41735 2691355
|
||||||
homyur 39893 2850481
|
homyur 39893 2850481
|
||||||
gri 39871 2515779
|
gri 39871 2515779
|
||||||
Fifis 38776 2529121
|
Garf 37741 2999686
|
||||||
oryx 38724 2966648
|
SC 37299 2731694
|
||||||
SC 37290 2731014
|
|
||||||
csnodgrass 36207 2688994
|
csnodgrass 36207 2688994
|
||||||
jmdana 36157 2210661
|
|
||||||
strelock 34716 2074055
|
strelock 34716 2074055
|
||||||
rpngn 33951 2057395
|
szupaw 34102 2880346
|
||||||
Garf 33922 2751802
|
|
||||||
EthanOConnor 33370 2090311
|
EthanOConnor 33370 2090311
|
||||||
slakovv 32915 2021889
|
slakovv 32915 2021889
|
||||||
|
Gelma 31771 1551204
|
||||||
|
gopeto 31671 2060990
|
||||||
|
kdave 31157 2198362
|
||||||
manapbk 30987 1810399
|
manapbk 30987 1810399
|
||||||
Prcuvu 30377 2170122
|
Prcuvu 30377 2170122
|
||||||
anst 30301 2190091
|
anst 30301 2190091
|
||||||
jkiiski 30136 1904470
|
jkiiski 30136 1904470
|
||||||
|
spcc 29925 1901692
|
||||||
hyperbolic.tom 29840 2017394
|
hyperbolic.tom 29840 2017394
|
||||||
|
chuckstablers 29659 2093438
|
||||||
Pyafue 29650 1902349
|
Pyafue 29650 1902349
|
||||||
Wolfgang 29260 1658936
|
belzedar94 28846 1811530
|
||||||
zeryl 28156 1579911
|
|
||||||
OuaisBla 27636 1578800
|
|
||||||
DMBK 27051 1999456
|
|
||||||
chriswk 26902 1868317
|
chriswk 26902 1868317
|
||||||
|
xwziegtm 26897 2124586
|
||||||
achambord 26582 1767323
|
achambord 26582 1767323
|
||||||
Patrick_G 26276 1801617
|
Patrick_G 26276 1801617
|
||||||
yorkman 26193 1992080
|
yorkman 26193 1992080
|
||||||
|
Ulysses 25288 1689730
|
||||||
SFTUser 25182 1675689
|
SFTUser 25182 1675689
|
||||||
nabildanial 24942 1519409
|
nabildanial 24942 1519409
|
||||||
Sharaf_DG 24765 1786697
|
Sharaf_DG 24765 1786697
|
||||||
ncfish1 24411 1520927
|
Maxim 24705 1502062
|
||||||
rodneyc 24227 1409514
|
rodneyc 24376 1416402
|
||||||
agg177 23890 1395014
|
agg177 23890 1395014
|
||||||
|
Goatminola 23763 1956036
|
||||||
|
Ente 23639 1671638
|
||||||
|
Jopo12321 23467 1483172
|
||||||
JanErik 23408 1703875
|
JanErik 23408 1703875
|
||||||
Isidor 23388 1680691
|
Isidor 23388 1680691
|
||||||
Norabor 23164 1591830
|
Norabor 23371 1603244
|
||||||
cisco2015 22897 1762669
|
cisco2015 22920 1763301
|
||||||
|
jsys14 22824 1591906
|
||||||
Zirie 22542 1472937
|
Zirie 22542 1472937
|
||||||
team-oh 22272 1636708
|
team-oh 22272 1636708
|
||||||
|
Roady 22220 1465606
|
||||||
MazeOfGalious 21978 1629593
|
MazeOfGalious 21978 1629593
|
||||||
sg4032 21947 1643265
|
sg4032 21947 1643353
|
||||||
ianh2105 21725 1632562
|
ianh2105 21725 1632562
|
||||||
xor12 21628 1680365
|
xor12 21628 1680365
|
||||||
dex 21612 1467203
|
dex 21612 1467203
|
||||||
nesoneg 21494 1463031
|
nesoneg 21494 1463031
|
||||||
|
user213718 21454 1404128
|
||||||
sphinx 21211 1384728
|
sphinx 21211 1384728
|
||||||
|
AndreasKrug 21097 1634811
|
||||||
jjoshua2 21001 1423089
|
jjoshua2 21001 1423089
|
||||||
|
Zake9298 20938 1565848
|
||||||
horst.prack 20878 1465656
|
horst.prack 20878 1465656
|
||||||
Ente 20865 1477066
|
|
||||||
0xB00B1ES 20590 1208666
|
0xB00B1ES 20590 1208666
|
||||||
j3corre 20405 941444
|
j3corre 20405 941444
|
||||||
Adrian.Schmidt123 20316 1281436
|
Adrian.Schmidt123 20316 1281436
|
||||||
wei 19973 1745989
|
wei 19973 1745989
|
||||||
MaxKlaxxMiner 19850 1009176
|
notchris 19958 1800128
|
||||||
|
Serpensin 19840 1697528
|
||||||
|
Gaster319 19712 1677310
|
||||||
|
fishtester 19617 1257388
|
||||||
rstoesser 19569 1293588
|
rstoesser 19569 1293588
|
||||||
gopeto 19491 1174952
|
|
||||||
eudhan 19274 1283717
|
eudhan 19274 1283717
|
||||||
|
votoanthuan 19108 1609992
|
||||||
|
vulcan 18871 1729392
|
||||||
|
Karpovbot 18766 1053178
|
||||||
|
qoo_charly_cai 18543 1284937
|
||||||
jundery 18445 1115855
|
jundery 18445 1115855
|
||||||
megaman7de 18377 1067540
|
|
||||||
iisiraider 18247 1101015
|
|
||||||
ville 17883 1384026
|
ville 17883 1384026
|
||||||
chris 17698 1487385
|
chris 17698 1487385
|
||||||
purplefishies 17595 1092533
|
purplefishies 17595 1092533
|
||||||
dju 17353 978595
|
dju 17414 981289
|
||||||
|
iisiraider 17275 1049015
|
||||||
DragonLord 17014 1162790
|
DragonLord 17014 1162790
|
||||||
|
redstone59 16842 1461780
|
||||||
|
Alb11747 16787 1213926
|
||||||
IgorLeMasson 16064 1147232
|
IgorLeMasson 16064 1147232
|
||||||
|
Karby 15982 979610
|
||||||
|
scuzzi 15757 968735
|
||||||
ako027ako 15671 1173203
|
ako027ako 15671 1173203
|
||||||
chuckstablers 15289 891576
|
|
||||||
Nikolay.IT 15154 1068349
|
Nikolay.IT 15154 1068349
|
||||||
Andrew Grant 15114 895539
|
Andrew Grant 15114 895539
|
||||||
|
Naven94 15054 834762
|
||||||
OssumOpossum 14857 1007129
|
OssumOpossum 14857 1007129
|
||||||
Karby 14808 867120
|
ZacHFX 14783 1021842
|
||||||
enedene 14476 905279
|
enedene 14476 905279
|
||||||
bpfliegel 14298 884523
|
bpfliegel 14233 882523
|
||||||
mpx86 14019 759568
|
mpx86 14019 759568
|
||||||
jpulman 13982 870599
|
jpulman 13982 870599
|
||||||
|
Skiff84 13826 721996
|
||||||
crocogoat 13803 1117422
|
crocogoat 13803 1117422
|
||||||
joster 13794 950160
|
|
||||||
Nesa92 13786 1114691
|
Nesa92 13786 1114691
|
||||||
|
joster 13710 946160
|
||||||
|
mbeier 13650 1044928
|
||||||
Hjax 13535 915487
|
Hjax 13535 915487
|
||||||
jsys14 13459 785000
|
Nullvalue 13468 1140498
|
||||||
Dark_wizzie 13422 1007152
|
Dark_wizzie 13422 1007152
|
||||||
|
Rudolphous 13244 883140
|
||||||
|
pirt 13100 1009897
|
||||||
|
Machariel 13010 863104
|
||||||
|
infinigon 12991 943216
|
||||||
mabichito 12903 749391
|
mabichito 12903 749391
|
||||||
thijsk 12886 722107
|
thijsk 12886 722107
|
||||||
AdrianSA 12860 804972
|
AdrianSA 12860 804972
|
||||||
Flopzee 12698 894821
|
Flopzee 12698 894821
|
||||||
|
korposzczur 12606 838168
|
||||||
fatmurphy 12547 853210
|
fatmurphy 12547 853210
|
||||||
Rudolphous 12520 832340
|
|
||||||
scuzzi 12511 845761
|
|
||||||
SapphireBrand 12416 969604
|
SapphireBrand 12416 969604
|
||||||
|
Oakwen 12399 844109
|
||||||
|
deflectooor 12386 579392
|
||||||
modolief 12386 896470
|
modolief 12386 896470
|
||||||
Machariel 12335 810784
|
Farseer 12249 694108
|
||||||
|
Jackfish 12213 805008
|
||||||
pgontarz 12151 848794
|
pgontarz 12151 848794
|
||||||
|
dbernier 12103 860824
|
||||||
|
getraideBFF 12072 1024966
|
||||||
stocky 11954 699440
|
stocky 11954 699440
|
||||||
mschmidt 11941 803401
|
mschmidt 11941 803401
|
||||||
Maxim 11543 836024
|
MooTheCow 11870 773598
|
||||||
|
FormazChar 11766 885707
|
||||||
|
whelanh 11557 245188
|
||||||
|
3cho 11494 1031076
|
||||||
infinity 11470 727027
|
infinity 11470 727027
|
||||||
|
aga 11412 695127
|
||||||
torbjo 11395 729145
|
torbjo 11395 729145
|
||||||
Thomas A. Anderson 11372 732094
|
Thomas A. Anderson 11372 732094
|
||||||
savage84 11358 670860
|
savage84 11358 670860
|
||||||
d64 11263 789184
|
d64 11263 789184
|
||||||
MooTheCow 11237 720174
|
ali-al-zhrani 11245 779246
|
||||||
snicolet 11106 869170
|
snicolet 11106 869170
|
||||||
ali-al-zhrani 11086 767926
|
dapper 11032 771402
|
||||||
AndreasKrug 10875 887457
|
ols 10947 624903
|
||||||
pirt 10806 836519
|
Karmatron 10828 677458
|
||||||
basepi 10637 744851
|
basepi 10637 744851
|
||||||
michaelrpg 10508 739039
|
Cubox 10621 826448
|
||||||
|
michaelrpg 10509 739239
|
||||||
|
OIVAS7572 10420 995586
|
||||||
|
jojo2357 10419 929708
|
||||||
|
WoodMan777 10380 873720
|
||||||
|
Garruk 10365 706465
|
||||||
dzjp 10343 732529
|
dzjp 10343 732529
|
||||||
aga 10302 622975
|
|
||||||
ols 10259 570669
|
|
||||||
lbraesch 10252 647825
|
|
||||||
FormazChar 10059 757283
|
|
||||||
|
|||||||
@@ -1,88 +0,0 @@
|
|||||||
version: 1.0.{build}
|
|
||||||
clone_depth: 50
|
|
||||||
|
|
||||||
branches:
|
|
||||||
only:
|
|
||||||
- master
|
|
||||||
|
|
||||||
# Operating system (build VM template)
|
|
||||||
os: Visual Studio 2019
|
|
||||||
|
|
||||||
# Build platform, i.e. x86, x64, AnyCPU. This setting is optional.
|
|
||||||
platform:
|
|
||||||
- x86
|
|
||||||
- x64
|
|
||||||
|
|
||||||
# build Configuration, i.e. Debug, Release, etc.
|
|
||||||
configuration:
|
|
||||||
- Debug
|
|
||||||
- Release
|
|
||||||
|
|
||||||
matrix:
|
|
||||||
# The build fail immediately once one of the job fails
|
|
||||||
fast_finish: true
|
|
||||||
|
|
||||||
# Scripts that are called at very beginning, before repo cloning
|
|
||||||
init:
|
|
||||||
- cmake --version
|
|
||||||
- msbuild /version
|
|
||||||
|
|
||||||
before_build:
|
|
||||||
- ps: |
|
|
||||||
# Get sources
|
|
||||||
$src = get-childitem -Path *.cpp -Recurse | select -ExpandProperty FullName
|
|
||||||
$src = $src -join ' '
|
|
||||||
$src = $src.Replace("\", "/")
|
|
||||||
|
|
||||||
# Build CMakeLists.txt
|
|
||||||
$t = 'cmake_minimum_required(VERSION 3.17)',
|
|
||||||
'project(Stockfish)',
|
|
||||||
'set(CMAKE_CXX_STANDARD 17)',
|
|
||||||
'set(CMAKE_CXX_STANDARD_REQUIRED ON)',
|
|
||||||
'set (CMAKE_CXX_EXTENSIONS OFF)',
|
|
||||||
'set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/src)',
|
|
||||||
'set(source_files', $src, ')',
|
|
||||||
'add_executable(stockfish ${source_files})'
|
|
||||||
|
|
||||||
# Write CMakeLists.txt withouth BOM
|
|
||||||
$MyPath = (Get-Item -Path "." -Verbose).FullName + '\CMakeLists.txt'
|
|
||||||
$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding $False
|
|
||||||
[System.IO.File]::WriteAllLines($MyPath, $t, $Utf8NoBomEncoding)
|
|
||||||
|
|
||||||
# Obtain bench reference from git log
|
|
||||||
$b = git log HEAD | sls "\b[Bb]ench[ :]+[0-9]{7}" | select -first 1
|
|
||||||
$bench = $b -match '\D+(\d+)' | % { $matches[1] }
|
|
||||||
Write-Host "Reference bench:" $bench
|
|
||||||
$g = "Visual Studio 16 2019"
|
|
||||||
If (${env:PLATFORM} -eq 'x64') { $a = "x64" }
|
|
||||||
If (${env:PLATFORM} -eq 'x86') { $a = "Win32" }
|
|
||||||
cmake -G "${g}" -A ${a} .
|
|
||||||
Write-Host "Generated files for: " $g $a
|
|
||||||
|
|
||||||
build_script:
|
|
||||||
- cmake --build . --config %CONFIGURATION% -- /verbosity:minimal
|
|
||||||
- ps: |
|
|
||||||
# Download default NNUE net from fishtest
|
|
||||||
$nnuenet = Get-Content -Path src\evaluate.h | Select-String -CaseSensitive -Pattern "EvalFileDefaultName" | Select-String -CaseSensitive -Pattern "nn-[a-z0-9]{12}.nnue"
|
|
||||||
$dummy = $nnuenet -match "(?<nnuenet>nn-[a-z0-9]{12}.nnue)"
|
|
||||||
$nnuenet = $Matches.nnuenet
|
|
||||||
Write-Host "Default net:" $nnuenet
|
|
||||||
$nnuedownloadurl = "https://tests.stockfishchess.org/api/nn/$nnuenet"
|
|
||||||
$nnuefilepath = "src\${env:CONFIGURATION}\$nnuenet"
|
|
||||||
if (Test-Path -Path $nnuefilepath) {
|
|
||||||
Write-Host "Already available."
|
|
||||||
} else {
|
|
||||||
Write-Host "Downloading $nnuedownloadurl to $nnuefilepath"
|
|
||||||
Invoke-WebRequest -Uri $nnuedownloadurl -OutFile $nnuefilepath
|
|
||||||
}
|
|
||||||
|
|
||||||
before_test:
|
|
||||||
- cd src/%CONFIGURATION%
|
|
||||||
- stockfish bench 2> out.txt >NUL
|
|
||||||
- ps: |
|
|
||||||
# Verify bench number
|
|
||||||
$s = (gc "./out.txt" | out-string)
|
|
||||||
$r = ($s -match 'Nodes searched \D+(\d+)' | % { $matches[1] })
|
|
||||||
Write-Host "Engine bench:" $r
|
|
||||||
Write-Host "Reference bench:" $bench
|
|
||||||
If ($r -ne $bench) { exit 1 }
|
|
||||||
+243
-118
@@ -1,5 +1,5 @@
|
|||||||
# Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
# Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
# Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
# Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
#
|
#
|
||||||
# Stockfish is free software: you can redistribute it and/or modify
|
# Stockfish is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -19,8 +19,26 @@
|
|||||||
### Section 1. General Configuration
|
### Section 1. General Configuration
|
||||||
### ==========================================================================
|
### ==========================================================================
|
||||||
|
|
||||||
|
### Establish the operating system name
|
||||||
|
KERNEL = $(shell uname -s)
|
||||||
|
ifeq ($(KERNEL),Linux)
|
||||||
|
OS = $(shell uname -o)
|
||||||
|
endif
|
||||||
|
|
||||||
|
### Target Windows OS
|
||||||
|
ifeq ($(OS),Windows_NT)
|
||||||
|
ifneq ($(COMP),ndk)
|
||||||
|
target_windows = yes
|
||||||
|
endif
|
||||||
|
else ifeq ($(COMP),mingw)
|
||||||
|
target_windows = yes
|
||||||
|
ifeq ($(WINE_PATH),)
|
||||||
|
WINE_PATH = $(shell which wine)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
### Executable name
|
### Executable name
|
||||||
ifeq ($(COMP),mingw)
|
ifeq ($(target_windows),yes)
|
||||||
EXE = stockfish.exe
|
EXE = stockfish.exe
|
||||||
else
|
else
|
||||||
EXE = stockfish
|
EXE = stockfish
|
||||||
@@ -32,9 +50,9 @@ BINDIR = $(PREFIX)/bin
|
|||||||
|
|
||||||
### Built-in benchmark for pgo-builds
|
### Built-in benchmark for pgo-builds
|
||||||
ifeq ($(SDE_PATH),)
|
ifeq ($(SDE_PATH),)
|
||||||
PGOBENCH = ./$(EXE) bench
|
PGOBENCH = $(WINE_PATH) ./$(EXE) bench
|
||||||
else
|
else
|
||||||
PGOBENCH = $(SDE_PATH) -- ./$(EXE) bench
|
PGOBENCH = $(SDE_PATH) -- $(WINE_PATH) ./$(EXE) bench
|
||||||
endif
|
endif
|
||||||
|
|
||||||
### Source and object files
|
### Source and object files
|
||||||
@@ -47,12 +65,6 @@ OBJS = $(notdir $(SRCS:.cpp=.o))
|
|||||||
|
|
||||||
VPATH = syzygy:nnue:nnue/features
|
VPATH = syzygy:nnue:nnue/features
|
||||||
|
|
||||||
### Establish the operating system name
|
|
||||||
KERNEL = $(shell uname -s)
|
|
||||||
ifeq ($(KERNEL),Linux)
|
|
||||||
OS = $(shell uname -o)
|
|
||||||
endif
|
|
||||||
|
|
||||||
### ==========================================================================
|
### ==========================================================================
|
||||||
### Section 2. High-level Configuration
|
### Section 2. High-level Configuration
|
||||||
### ==========================================================================
|
### ==========================================================================
|
||||||
@@ -78,10 +90,12 @@ endif
|
|||||||
# ssse3 = yes/no --- -mssse3 --- Use Intel Supplemental Streaming SIMD Extensions 3
|
# ssse3 = yes/no --- -mssse3 --- Use Intel Supplemental Streaming SIMD Extensions 3
|
||||||
# sse41 = yes/no --- -msse4.1 --- Use Intel Streaming SIMD Extensions 4.1
|
# sse41 = yes/no --- -msse4.1 --- Use Intel Streaming SIMD Extensions 4.1
|
||||||
# avx2 = yes/no --- -mavx2 --- Use Intel Advanced Vector Extensions 2
|
# avx2 = yes/no --- -mavx2 --- Use Intel Advanced Vector Extensions 2
|
||||||
|
# avxvnni = yes/no --- -mavxvnni --- Use Intel Vector Neural Network Instructions AVX
|
||||||
# avx512 = yes/no --- -mavx512bw --- Use Intel Advanced Vector Extensions 512
|
# avx512 = yes/no --- -mavx512bw --- Use Intel Advanced Vector Extensions 512
|
||||||
# vnni256 = yes/no --- -mavx512vnni --- Use Intel Vector Neural Network Instructions 256
|
# vnni256 = yes/no --- -mavx256vnni --- Use Intel Vector Neural Network Instructions 512 with 256bit operands
|
||||||
# vnni512 = yes/no --- -mavx512vnni --- Use Intel Vector Neural Network Instructions 512
|
# vnni512 = yes/no --- -mavx512vnni --- Use Intel Vector Neural Network Instructions 512
|
||||||
# neon = yes/no --- -DUSE_NEON --- Use ARM SIMD architecture
|
# neon = yes/no --- -DUSE_NEON --- Use ARM SIMD architecture
|
||||||
|
# dotprod = yes/no --- -DUSE_NEON_DOTPROD --- Use ARM advanced SIMD Int8 dot product instructions
|
||||||
#
|
#
|
||||||
# Note that Makefile is space sensitive, so when adding new architectures
|
# Note that Makefile is space sensitive, so when adding new architectures
|
||||||
# or modifying existing flags, you have to make sure there are no extra spaces
|
# or modifying existing flags, you have to make sure there are no extra spaces
|
||||||
@@ -100,10 +114,10 @@ endif
|
|||||||
# explicitly check for the list of supported architectures (as listed with make help),
|
# explicitly check for the list of supported architectures (as listed with make help),
|
||||||
# the user can override with `make ARCH=x86-32-vnni256 SUPPORTED_ARCH=true`
|
# the user can override with `make ARCH=x86-32-vnni256 SUPPORTED_ARCH=true`
|
||||||
ifeq ($(ARCH), $(filter $(ARCH), \
|
ifeq ($(ARCH), $(filter $(ARCH), \
|
||||||
x86-64-vnni512 x86-64-vnni256 x86-64-avx512 x86-64-bmi2 x86-64-avx2 \
|
x86-64-vnni512 x86-64-vnni256 x86-64-avx512 x86-64-avxvnni x86-64-bmi2 \
|
||||||
x86-64-sse41-popcnt x86-64-modern x86-64-ssse3 x86-64-sse3-popcnt \
|
x86-64-avx2 x86-64-sse41-popcnt x86-64-modern x86-64-ssse3 x86-64-sse3-popcnt \
|
||||||
x86-64 x86-32-sse41-popcnt x86-32-sse2 x86-32 ppc-64 ppc-32 e2k \
|
x86-64 x86-32-sse41-popcnt x86-32-sse2 x86-32 ppc-64 ppc-32 e2k \
|
||||||
armv7 armv7-neon armv8 apple-silicon general-64 general-32))
|
armv7 armv7-neon armv8 armv8-dotprod apple-silicon general-64 general-32 riscv64))
|
||||||
SUPPORTED_ARCH=true
|
SUPPORTED_ARCH=true
|
||||||
else
|
else
|
||||||
SUPPORTED_ARCH=false
|
SUPPORTED_ARCH=false
|
||||||
@@ -122,10 +136,13 @@ sse2 = no
|
|||||||
ssse3 = no
|
ssse3 = no
|
||||||
sse41 = no
|
sse41 = no
|
||||||
avx2 = no
|
avx2 = no
|
||||||
|
avxvnni = no
|
||||||
avx512 = no
|
avx512 = no
|
||||||
vnni256 = no
|
vnni256 = no
|
||||||
vnni512 = no
|
vnni512 = no
|
||||||
neon = no
|
neon = no
|
||||||
|
dotprod = no
|
||||||
|
arm_version = 0
|
||||||
STRIP = strip
|
STRIP = strip
|
||||||
|
|
||||||
### 2.2 Architecture specific
|
### 2.2 Architecture specific
|
||||||
@@ -137,7 +154,7 @@ ifeq ($(findstring x86,$(ARCH)),x86)
|
|||||||
ifeq ($(findstring x86-32,$(ARCH)),x86-32)
|
ifeq ($(findstring x86-32,$(ARCH)),x86-32)
|
||||||
arch = i386
|
arch = i386
|
||||||
bits = 32
|
bits = 32
|
||||||
sse = yes
|
sse = no
|
||||||
mmx = yes
|
mmx = yes
|
||||||
else
|
else
|
||||||
arch = x86_64
|
arch = x86_64
|
||||||
@@ -192,6 +209,17 @@ ifeq ($(findstring -avx2,$(ARCH)),-avx2)
|
|||||||
avx2 = yes
|
avx2 = yes
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(findstring -avxvnni,$(ARCH)),-avxvnni)
|
||||||
|
popcnt = yes
|
||||||
|
sse = yes
|
||||||
|
sse2 = yes
|
||||||
|
ssse3 = yes
|
||||||
|
sse41 = yes
|
||||||
|
avx2 = yes
|
||||||
|
avxvnni = yes
|
||||||
|
pext = yes
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(findstring -bmi2,$(ARCH)),-bmi2)
|
ifeq ($(findstring -bmi2,$(ARCH)),-bmi2)
|
||||||
popcnt = yes
|
popcnt = yes
|
||||||
sse = yes
|
sse = yes
|
||||||
@@ -262,6 +290,7 @@ ifeq ($(ARCH),armv7)
|
|||||||
arch = armv7
|
arch = armv7
|
||||||
prefetch = yes
|
prefetch = yes
|
||||||
bits = 32
|
bits = 32
|
||||||
|
arm_version = 7
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(ARCH),armv7-neon)
|
ifeq ($(ARCH),armv7-neon)
|
||||||
@@ -270,6 +299,7 @@ ifeq ($(ARCH),armv7-neon)
|
|||||||
popcnt = yes
|
popcnt = yes
|
||||||
neon = yes
|
neon = yes
|
||||||
bits = 32
|
bits = 32
|
||||||
|
arm_version = 7
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(ARCH),armv8)
|
ifeq ($(ARCH),armv8)
|
||||||
@@ -277,6 +307,16 @@ ifeq ($(ARCH),armv8)
|
|||||||
prefetch = yes
|
prefetch = yes
|
||||||
popcnt = yes
|
popcnt = yes
|
||||||
neon = yes
|
neon = yes
|
||||||
|
arm_version = 8
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(ARCH),armv8-dotprod)
|
||||||
|
arch = armv8
|
||||||
|
prefetch = yes
|
||||||
|
popcnt = yes
|
||||||
|
neon = yes
|
||||||
|
dotprod = yes
|
||||||
|
arm_version = 8
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(ARCH),apple-silicon)
|
ifeq ($(ARCH),apple-silicon)
|
||||||
@@ -284,6 +324,8 @@ ifeq ($(ARCH),apple-silicon)
|
|||||||
prefetch = yes
|
prefetch = yes
|
||||||
popcnt = yes
|
popcnt = yes
|
||||||
neon = yes
|
neon = yes
|
||||||
|
dotprod = yes
|
||||||
|
arm_version = 8
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(ARCH),ppc-32)
|
ifeq ($(ARCH),ppc-32)
|
||||||
@@ -308,16 +350,26 @@ ifeq ($(findstring e2k,$(ARCH)),e2k)
|
|||||||
popcnt = yes
|
popcnt = yes
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(ARCH),riscv64)
|
||||||
|
arch = riscv64
|
||||||
endif
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
### ==========================================================================
|
### ==========================================================================
|
||||||
### Section 3. Low-level Configuration
|
### Section 3. Low-level Configuration
|
||||||
### ==========================================================================
|
### ==========================================================================
|
||||||
|
|
||||||
### 3.1 Selecting compiler (default = gcc)
|
### 3.1 Selecting compiler (default = gcc)
|
||||||
CXXFLAGS += -Wall -Wcast-qual -fno-exceptions -std=c++17 $(EXTRACXXFLAGS)
|
ifeq ($(MAKELEVEL),0)
|
||||||
DEPENDFLAGS += -std=c++17
|
export ENV_CXXFLAGS := $(CXXFLAGS)
|
||||||
LDFLAGS += $(EXTRALDFLAGS)
|
export ENV_DEPENDFLAGS := $(DEPENDFLAGS)
|
||||||
|
export ENV_LDFLAGS := $(LDFLAGS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
CXXFLAGS = $(ENV_CXXFLAGS) -Wall -Wcast-qual -fno-exceptions -std=c++17 $(EXTRACXXFLAGS)
|
||||||
|
DEPENDFLAGS = $(ENV_DEPENDFLAGS) -std=c++17
|
||||||
|
LDFLAGS = $(ENV_LDFLAGS) $(EXTRALDFLAGS)
|
||||||
|
|
||||||
ifeq ($(COMP),)
|
ifeq ($(COMP),)
|
||||||
COMP=gcc
|
COMP=gcc
|
||||||
@@ -326,13 +378,16 @@ endif
|
|||||||
ifeq ($(COMP),gcc)
|
ifeq ($(COMP),gcc)
|
||||||
comp=gcc
|
comp=gcc
|
||||||
CXX=g++
|
CXX=g++
|
||||||
CXXFLAGS += -pedantic -Wextra -Wshadow
|
CXXFLAGS += -pedantic -Wextra -Wshadow -Wmissing-declarations
|
||||||
|
|
||||||
ifeq ($(arch),$(filter $(arch),armv7 armv8))
|
ifeq ($(arch),$(filter $(arch),armv7 armv8 riscv64))
|
||||||
ifeq ($(OS),Android)
|
ifeq ($(OS),Android)
|
||||||
CXXFLAGS += -m$(bits)
|
CXXFLAGS += -m$(bits)
|
||||||
LDFLAGS += -m$(bits)
|
LDFLAGS += -m$(bits)
|
||||||
endif
|
endif
|
||||||
|
ifeq ($(ARCH),riscv64)
|
||||||
|
CXXFLAGS += -latomic
|
||||||
|
endif
|
||||||
else
|
else
|
||||||
CXXFLAGS += -m$(bits)
|
CXXFLAGS += -m$(bits)
|
||||||
LDFLAGS += -m$(bits)
|
LDFLAGS += -m$(bits)
|
||||||
@@ -347,57 +402,62 @@ ifeq ($(COMP),gcc)
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(target_windows),yes)
|
||||||
|
LDFLAGS += -static
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(COMP),mingw)
|
ifeq ($(COMP),mingw)
|
||||||
comp=mingw
|
comp=mingw
|
||||||
|
|
||||||
ifeq ($(KERNEL),Linux)
|
|
||||||
ifeq ($(bits),64)
|
ifeq ($(bits),64)
|
||||||
ifeq ($(shell which x86_64-w64-mingw32-c++-posix),)
|
ifeq ($(shell which x86_64-w64-mingw32-c++-posix 2> /dev/null),)
|
||||||
CXX=x86_64-w64-mingw32-c++
|
CXX=x86_64-w64-mingw32-c++
|
||||||
else
|
else
|
||||||
CXX=x86_64-w64-mingw32-c++-posix
|
CXX=x86_64-w64-mingw32-c++-posix
|
||||||
endif
|
endif
|
||||||
else
|
else
|
||||||
ifeq ($(shell which i686-w64-mingw32-c++-posix),)
|
ifeq ($(shell which i686-w64-mingw32-c++-posix 2> /dev/null),)
|
||||||
CXX=i686-w64-mingw32-c++
|
CXX=i686-w64-mingw32-c++
|
||||||
else
|
else
|
||||||
CXX=i686-w64-mingw32-c++-posix
|
CXX=i686-w64-mingw32-c++-posix
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
else
|
CXXFLAGS += -pedantic -Wextra -Wshadow -Wmissing-declarations
|
||||||
CXX=g++
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
CXXFLAGS += -pedantic -Wextra -Wshadow
|
ifeq ($(COMP),icx)
|
||||||
LDFLAGS += -static
|
comp=icx
|
||||||
endif
|
CXX=icpx
|
||||||
|
CXXFLAGS += --intel -pedantic -Wextra -Wshadow -Wmissing-prototypes \
|
||||||
ifeq ($(COMP),icc)
|
-Wconditional-uninitialized -Wabi -Wdeprecated
|
||||||
comp=icc
|
|
||||||
CXX=icpc
|
|
||||||
CXXFLAGS += -diag-disable 1476,10120 -Wcheck -Wabi -Wdeprecated -strict-ansi
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(COMP),clang)
|
ifeq ($(COMP),clang)
|
||||||
comp=clang
|
comp=clang
|
||||||
CXX=clang++
|
CXX=clang++
|
||||||
CXXFLAGS += -pedantic -Wextra -Wshadow
|
ifeq ($(target_windows),yes)
|
||||||
|
CXX=x86_64-w64-mingw32-clang++
|
||||||
|
endif
|
||||||
|
|
||||||
ifneq ($(KERNEL),Darwin)
|
CXXFLAGS += -pedantic -Wextra -Wshadow -Wmissing-prototypes \
|
||||||
ifneq ($(KERNEL),OpenBSD)
|
-Wconditional-uninitialized
|
||||||
ifneq ($(KERNEL),FreeBSD)
|
|
||||||
|
ifeq ($(filter $(KERNEL),Darwin OpenBSD FreeBSD),)
|
||||||
|
ifeq ($(target_windows),)
|
||||||
ifneq ($(RTLIB),compiler-rt)
|
ifneq ($(RTLIB),compiler-rt)
|
||||||
LDFLAGS += -latomic
|
LDFLAGS += -latomic
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(arch),$(filter $(arch),armv7 armv8))
|
ifeq ($(arch),$(filter $(arch),armv7 armv8 riscv64))
|
||||||
ifeq ($(OS),Android)
|
ifeq ($(OS),Android)
|
||||||
CXXFLAGS += -m$(bits)
|
CXXFLAGS += -m$(bits)
|
||||||
LDFLAGS += -m$(bits)
|
LDFLAGS += -m$(bits)
|
||||||
endif
|
endif
|
||||||
|
ifeq ($(ARCH),riscv64)
|
||||||
|
CXXFLAGS += -latomic
|
||||||
|
endif
|
||||||
else
|
else
|
||||||
CXXFLAGS += -m$(bits)
|
CXXFLAGS += -m$(bits)
|
||||||
LDFLAGS += -m$(bits)
|
LDFLAGS += -m$(bits)
|
||||||
@@ -423,24 +483,35 @@ ifeq ($(COMP),ndk)
|
|||||||
ifeq ($(arch),armv7)
|
ifeq ($(arch),armv7)
|
||||||
CXX=armv7a-linux-androideabi16-clang++
|
CXX=armv7a-linux-androideabi16-clang++
|
||||||
CXXFLAGS += -mthumb -march=armv7-a -mfloat-abi=softfp -mfpu=neon
|
CXXFLAGS += -mthumb -march=armv7-a -mfloat-abi=softfp -mfpu=neon
|
||||||
|
ifneq ($(shell which arm-linux-androideabi-strip 2>/dev/null),)
|
||||||
STRIP=arm-linux-androideabi-strip
|
STRIP=arm-linux-androideabi-strip
|
||||||
|
else
|
||||||
|
STRIP=llvm-strip
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
ifeq ($(arch),armv8)
|
ifeq ($(arch),armv8)
|
||||||
CXX=aarch64-linux-android21-clang++
|
CXX=aarch64-linux-android21-clang++
|
||||||
|
ifneq ($(shell which aarch64-linux-android-strip 2>/dev/null),)
|
||||||
STRIP=aarch64-linux-android-strip
|
STRIP=aarch64-linux-android-strip
|
||||||
|
else
|
||||||
|
STRIP=llvm-strip
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
LDFLAGS += -static-libstdc++ -pie -lm -latomic
|
LDFLAGS += -static-libstdc++ -pie -lm -latomic
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(comp),icc)
|
ifeq ($(comp),icx)
|
||||||
profile_make = icc-profile-make
|
profile_make = icx-profile-make
|
||||||
profile_use = icc-profile-use
|
profile_use = icx-profile-use
|
||||||
else ifeq ($(comp),clang)
|
else ifeq ($(comp),clang)
|
||||||
profile_make = clang-profile-make
|
profile_make = clang-profile-make
|
||||||
profile_use = clang-profile-use
|
profile_use = clang-profile-use
|
||||||
else
|
else
|
||||||
profile_make = gcc-profile-make
|
profile_make = gcc-profile-make
|
||||||
profile_use = gcc-profile-use
|
profile_use = gcc-profile-use
|
||||||
|
ifeq ($(KERNEL),Darwin)
|
||||||
|
EXTRAPROFILEFLAGS = -fvisibility=hidden
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
### Travis CI script uses COMPILER to overwrite CXX
|
### Travis CI script uses COMPILER to overwrite CXX
|
||||||
@@ -455,7 +526,7 @@ endif
|
|||||||
|
|
||||||
### Sometimes gcc is really clang
|
### Sometimes gcc is really clang
|
||||||
ifeq ($(COMP),gcc)
|
ifeq ($(COMP),gcc)
|
||||||
gccversion = $(shell $(CXX) --version)
|
gccversion = $(shell $(CXX) --version 2>/dev/null)
|
||||||
gccisclang = $(findstring clang,$(gccversion))
|
gccisclang = $(findstring clang,$(gccversion))
|
||||||
ifneq ($(gccisclang),)
|
ifneq ($(gccisclang),)
|
||||||
profile_make = clang-profile-make
|
profile_make = clang-profile-make
|
||||||
@@ -501,16 +572,25 @@ ifeq ($(optimize),yes)
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(comp),$(filter $(comp),gcc clang icc))
|
|
||||||
ifeq ($(KERNEL),Darwin)
|
ifeq ($(KERNEL),Darwin)
|
||||||
|
ifeq ($(comp),$(filter $(comp),clang icx))
|
||||||
CXXFLAGS += -mdynamic-no-pic
|
CXXFLAGS += -mdynamic-no-pic
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(comp),gcc)
|
||||||
|
ifneq ($(arch),arm64)
|
||||||
|
CXXFLAGS += -mdynamic-no-pic
|
||||||
|
endif
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(comp),clang)
|
ifeq ($(comp),clang)
|
||||||
|
clangmajorversion = $(shell $(CXX) -dumpversion 2>/dev/null | cut -f1 -d.)
|
||||||
|
ifeq ($(shell expr $(clangmajorversion) \< 16),1)
|
||||||
CXXFLAGS += -fexperimental-new-pass-manager
|
CXXFLAGS += -fexperimental-new-pass-manager
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
### 3.4 Bits
|
### 3.4 Bits
|
||||||
ifeq ($(bits),64)
|
ifeq ($(bits),64)
|
||||||
@@ -529,8 +609,6 @@ endif
|
|||||||
ifeq ($(popcnt),yes)
|
ifeq ($(popcnt),yes)
|
||||||
ifeq ($(arch),$(filter $(arch),ppc64 armv7 armv8 arm64))
|
ifeq ($(arch),$(filter $(arch),ppc64 armv7 armv8 arm64))
|
||||||
CXXFLAGS += -DUSE_POPCNT
|
CXXFLAGS += -DUSE_POPCNT
|
||||||
else ifeq ($(comp),icc)
|
|
||||||
CXXFLAGS += -msse3 -DUSE_POPCNT
|
|
||||||
else
|
else
|
||||||
CXXFLAGS += -msse3 -mpopcnt -DUSE_POPCNT
|
CXXFLAGS += -msse3 -mpopcnt -DUSE_POPCNT
|
||||||
endif
|
endif
|
||||||
@@ -539,62 +617,69 @@ endif
|
|||||||
### 3.6 SIMD architectures
|
### 3.6 SIMD architectures
|
||||||
ifeq ($(avx2),yes)
|
ifeq ($(avx2),yes)
|
||||||
CXXFLAGS += -DUSE_AVX2
|
CXXFLAGS += -DUSE_AVX2
|
||||||
ifeq ($(comp),$(filter $(comp),gcc clang mingw))
|
ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
|
||||||
CXXFLAGS += -mavx2
|
CXXFLAGS += -mavx2 -mbmi
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(avxvnni),yes)
|
||||||
|
CXXFLAGS += -DUSE_VNNI -DUSE_AVXVNNI
|
||||||
|
ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
|
||||||
|
CXXFLAGS += -mavxvnni
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(avx512),yes)
|
ifeq ($(avx512),yes)
|
||||||
CXXFLAGS += -DUSE_AVX512
|
CXXFLAGS += -DUSE_AVX512
|
||||||
ifeq ($(comp),$(filter $(comp),gcc clang mingw))
|
ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
|
||||||
CXXFLAGS += -mavx512f -mavx512bw
|
CXXFLAGS += -mavx512f -mavx512bw
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(vnni256),yes)
|
ifeq ($(vnni256),yes)
|
||||||
CXXFLAGS += -DUSE_VNNI
|
CXXFLAGS += -DUSE_VNNI
|
||||||
ifeq ($(comp),$(filter $(comp),gcc clang mingw))
|
ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
|
||||||
CXXFLAGS += -mavx512f -mavx512bw -mavx512vnni -mavx512dq -mavx512vl -mprefer-vector-width=256
|
CXXFLAGS += -mavx512f -mavx512bw -mavx512vnni -mavx512dq -mavx512vl -mprefer-vector-width=256
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(vnni512),yes)
|
ifeq ($(vnni512),yes)
|
||||||
CXXFLAGS += -DUSE_VNNI
|
CXXFLAGS += -DUSE_VNNI
|
||||||
ifeq ($(comp),$(filter $(comp),gcc clang mingw))
|
ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
|
||||||
CXXFLAGS += -mavx512vnni -mavx512dq -mavx512vl
|
CXXFLAGS += -mavx512f -mavx512bw -mavx512vnni -mavx512dq -mavx512vl -mprefer-vector-width=512
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(sse41),yes)
|
ifeq ($(sse41),yes)
|
||||||
CXXFLAGS += -DUSE_SSE41
|
CXXFLAGS += -DUSE_SSE41
|
||||||
ifeq ($(comp),$(filter $(comp),gcc clang mingw))
|
ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
|
||||||
CXXFLAGS += -msse4.1
|
CXXFLAGS += -msse4.1
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(ssse3),yes)
|
ifeq ($(ssse3),yes)
|
||||||
CXXFLAGS += -DUSE_SSSE3
|
CXXFLAGS += -DUSE_SSSE3
|
||||||
ifeq ($(comp),$(filter $(comp),gcc clang mingw))
|
ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
|
||||||
CXXFLAGS += -mssse3
|
CXXFLAGS += -mssse3
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(sse2),yes)
|
ifeq ($(sse2),yes)
|
||||||
CXXFLAGS += -DUSE_SSE2
|
CXXFLAGS += -DUSE_SSE2
|
||||||
ifeq ($(comp),$(filter $(comp),gcc clang mingw))
|
ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
|
||||||
CXXFLAGS += -msse2
|
CXXFLAGS += -msse2
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(mmx),yes)
|
ifeq ($(mmx),yes)
|
||||||
CXXFLAGS += -DUSE_MMX
|
CXXFLAGS += -DUSE_MMX
|
||||||
ifeq ($(comp),$(filter $(comp),gcc clang mingw))
|
ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
|
||||||
CXXFLAGS += -mmmx
|
CXXFLAGS += -mmmx
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(neon),yes)
|
ifeq ($(neon),yes)
|
||||||
CXXFLAGS += -DUSE_NEON
|
CXXFLAGS += -DUSE_NEON=$(arm_version)
|
||||||
ifeq ($(KERNEL),Linux)
|
ifeq ($(KERNEL),Linux)
|
||||||
ifneq ($(COMP),ndk)
|
ifneq ($(COMP),ndk)
|
||||||
ifneq ($(arch),armv8)
|
ifneq ($(arch),armv8)
|
||||||
@@ -604,24 +689,41 @@ ifeq ($(neon),yes)
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(dotprod),yes)
|
||||||
|
CXXFLAGS += -march=armv8.2-a+dotprod -DUSE_NEON_DOTPROD
|
||||||
|
endif
|
||||||
|
|
||||||
### 3.7 pext
|
### 3.7 pext
|
||||||
ifeq ($(pext),yes)
|
ifeq ($(pext),yes)
|
||||||
CXXFLAGS += -DUSE_PEXT
|
CXXFLAGS += -DUSE_PEXT
|
||||||
ifeq ($(comp),$(filter $(comp),gcc clang mingw))
|
ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
|
||||||
CXXFLAGS += -mbmi2
|
CXXFLAGS += -mbmi2
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
### 3.7.1 Try to include git commit sha for versioning
|
||||||
|
GIT_SHA = $(shell git rev-parse HEAD 2>/dev/null | cut -c 1-8)
|
||||||
|
ifneq ($(GIT_SHA), )
|
||||||
|
CXXFLAGS += -DGIT_SHA=$(GIT_SHA)
|
||||||
|
endif
|
||||||
|
|
||||||
|
### 3.7.2 Try to include git commit date for versioning
|
||||||
|
GIT_DATE = $(shell git show -s --date=format:'%Y%m%d' --format=%cd HEAD 2>/dev/null)
|
||||||
|
ifneq ($(GIT_DATE), )
|
||||||
|
CXXFLAGS += -DGIT_DATE=$(GIT_DATE)
|
||||||
|
endif
|
||||||
|
|
||||||
### 3.8 Link Time Optimization
|
### 3.8 Link Time Optimization
|
||||||
### This is a mix of compile and link time options because the lto link phase
|
### This is a mix of compile and link time options because the lto link phase
|
||||||
### needs access to the optimization flags.
|
### needs access to the optimization flags.
|
||||||
ifeq ($(optimize),yes)
|
ifeq ($(optimize),yes)
|
||||||
ifeq ($(debug), no)
|
ifeq ($(debug), no)
|
||||||
ifeq ($(comp),clang)
|
ifeq ($(comp),$(filter $(comp),clang icx))
|
||||||
CXXFLAGS += -flto
|
CXXFLAGS += -flto=full
|
||||||
ifneq ($(findstring MINGW,$(KERNEL)),)
|
ifeq ($(comp),icx)
|
||||||
CXXFLAGS += -fuse-ld=lld
|
CXXFLAGS += -fwhole-program-vtables
|
||||||
else ifneq ($(findstring MSYS,$(KERNEL)),)
|
endif
|
||||||
|
ifeq ($(target_windows),yes)
|
||||||
CXXFLAGS += -fuse-ld=lld
|
CXXFLAGS += -fuse-ld=lld
|
||||||
endif
|
endif
|
||||||
LDFLAGS += $(CXXFLAGS)
|
LDFLAGS += $(CXXFLAGS)
|
||||||
@@ -630,28 +732,18 @@ ifeq ($(debug), no)
|
|||||||
# GCC on some systems.
|
# GCC on some systems.
|
||||||
else ifeq ($(comp),gcc)
|
else ifeq ($(comp),gcc)
|
||||||
ifeq ($(gccisclang),)
|
ifeq ($(gccisclang),)
|
||||||
CXXFLAGS += -flto
|
CXXFLAGS += -flto -flto-partition=one
|
||||||
LDFLAGS += $(CXXFLAGS) -flto=jobserver
|
LDFLAGS += $(CXXFLAGS) -flto=jobserver
|
||||||
ifneq ($(findstring MINGW,$(KERNEL)),)
|
|
||||||
LDFLAGS += -save-temps
|
|
||||||
else ifneq ($(findstring MSYS,$(KERNEL)),)
|
|
||||||
LDFLAGS += -save-temps
|
|
||||||
endif
|
|
||||||
else
|
else
|
||||||
CXXFLAGS += -flto
|
CXXFLAGS += -flto=full
|
||||||
LDFLAGS += $(CXXFLAGS)
|
LDFLAGS += $(CXXFLAGS)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# To use LTO and static linking on windows, the tool chain requires a recent gcc:
|
# To use LTO and static linking on Windows,
|
||||||
# gcc version 10.1 in msys2 or TDM-GCC version 9.2 are known to work, older might not.
|
# the tool chain requires gcc version 10.1 or later.
|
||||||
# So, only enable it for a cross from Linux by default.
|
|
||||||
else ifeq ($(comp),mingw)
|
else ifeq ($(comp),mingw)
|
||||||
ifeq ($(KERNEL),Linux)
|
CXXFLAGS += -flto -flto-partition=one
|
||||||
ifneq ($(arch),i386)
|
LDFLAGS += $(CXXFLAGS) -save-temps
|
||||||
CXXFLAGS += -flto
|
|
||||||
LDFLAGS += $(CXXFLAGS) -flto=jobserver
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
@@ -677,18 +769,19 @@ help:
|
|||||||
@echo "Supported targets:"
|
@echo "Supported targets:"
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "help > Display architecture details"
|
@echo "help > Display architecture details"
|
||||||
@echo "build > Standard build"
|
@echo "profile-build > standard build with profile-guided optimization"
|
||||||
|
@echo "build > skip profile-guided optimization"
|
||||||
@echo "net > Download the default nnue net"
|
@echo "net > Download the default nnue net"
|
||||||
@echo "profile-build > Faster build (with profile-guided optimization)"
|
|
||||||
@echo "strip > Strip executable"
|
@echo "strip > Strip executable"
|
||||||
@echo "install > Install executable"
|
@echo "install > Install executable"
|
||||||
@echo "clean > Clean up"
|
@echo "clean > Clean up"
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "Supported archs:"
|
@echo "Supported archs:"
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "x86-64-vnni512 > x86 64-bit with vnni support 512bit wide"
|
@echo "x86-64-vnni512 > x86 64-bit with vnni 512bit support"
|
||||||
@echo "x86-64-vnni256 > x86 64-bit with vnni support 256bit wide"
|
@echo "x86-64-vnni256 > x86 64-bit with vnni 512bit support, limit operands to 256bit wide"
|
||||||
@echo "x86-64-avx512 > x86 64-bit with avx512 support"
|
@echo "x86-64-avx512 > x86 64-bit with avx512 support"
|
||||||
|
@echo "x86-64-avxvnni > x86 64-bit with vnni 256bit support"
|
||||||
@echo "x86-64-bmi2 > x86 64-bit with bmi2 support"
|
@echo "x86-64-bmi2 > x86 64-bit with bmi2 support"
|
||||||
@echo "x86-64-avx2 > x86 64-bit with avx2 support"
|
@echo "x86-64-avx2 > x86 64-bit with avx2 support"
|
||||||
@echo "x86-64-sse41-popcnt > x86 64-bit with sse41 and popcnt support"
|
@echo "x86-64-sse41-popcnt > x86 64-bit with sse41 and popcnt support"
|
||||||
@@ -704,27 +797,30 @@ help:
|
|||||||
@echo "armv7 > ARMv7 32-bit"
|
@echo "armv7 > ARMv7 32-bit"
|
||||||
@echo "armv7-neon > ARMv7 32-bit with popcnt and neon"
|
@echo "armv7-neon > ARMv7 32-bit with popcnt and neon"
|
||||||
@echo "armv8 > ARMv8 64-bit with popcnt and neon"
|
@echo "armv8 > ARMv8 64-bit with popcnt and neon"
|
||||||
|
@echo "armv8-dotprod > ARMv8 64-bit with popcnt, neon and dot product support"
|
||||||
@echo "e2k > Elbrus 2000"
|
@echo "e2k > Elbrus 2000"
|
||||||
@echo "apple-silicon > Apple silicon ARM64"
|
@echo "apple-silicon > Apple silicon ARM64"
|
||||||
@echo "general-64 > unspecified 64-bit"
|
@echo "general-64 > unspecified 64-bit"
|
||||||
@echo "general-32 > unspecified 32-bit"
|
@echo "general-32 > unspecified 32-bit"
|
||||||
|
@echo "riscv64 > RISC-V 64-bit"
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "Supported compilers:"
|
@echo "Supported compilers:"
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "gcc > Gnu compiler (default)"
|
@echo "gcc > Gnu compiler (default)"
|
||||||
@echo "mingw > Gnu compiler with MinGW under Windows"
|
@echo "mingw > Gnu compiler with MinGW under Windows"
|
||||||
@echo "clang > LLVM Clang compiler"
|
@echo "clang > LLVM Clang compiler"
|
||||||
@echo "icc > Intel compiler"
|
@echo "icx > Intel oneAPI DPC++/C++ Compiler"
|
||||||
@echo "ndk > Google NDK to cross-compile for Android"
|
@echo "ndk > Google NDK to cross-compile for Android"
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "Simple examples. If you don't know what to do, you likely want to run: "
|
@echo "Simple examples. If you don't know what to do, you likely want to run one of: "
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "make -j build ARCH=x86-64 (A portable, slow compile for 64-bit systems)"
|
@echo "make -j profile-build ARCH=x86-64-avx2 # typically a fast compile for common systems "
|
||||||
@echo "make -j build ARCH=x86-32 (A portable, slow compile for 32-bit systems)"
|
@echo "make -j profile-build ARCH=x86-64-modern # A more portable compile for 64-bit systems "
|
||||||
|
@echo "make -j profile-build ARCH=x86-64 # A portable compile for 64-bit systems "
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "Advanced examples, for experienced users looking for performance: "
|
@echo "Advanced examples, for experienced users: "
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "make help ARCH=x86-64-bmi2"
|
@echo "make -j profile-build ARCH=x86-64-bmi2"
|
||||||
@echo "make -j profile-build ARCH=x86-64-bmi2 COMP=gcc COMPCXX=g++-9.0"
|
@echo "make -j profile-build ARCH=x86-64-bmi2 COMP=gcc COMPCXX=g++-9.0"
|
||||||
@echo "make -j build ARCH=x86-64-ssse3 COMP=clang"
|
@echo "make -j build ARCH=x86-64-ssse3 COMP=clang"
|
||||||
@echo ""
|
@echo ""
|
||||||
@@ -739,8 +835,10 @@ endif
|
|||||||
|
|
||||||
|
|
||||||
.PHONY: help build profile-build strip install clean net objclean profileclean \
|
.PHONY: help build profile-build strip install clean net objclean profileclean \
|
||||||
config-sanity icc-profile-use icc-profile-make gcc-profile-use gcc-profile-make \
|
config-sanity \
|
||||||
clang-profile-use clang-profile-make
|
icx-profile-use icx-profile-make \
|
||||||
|
gcc-profile-use gcc-profile-make \
|
||||||
|
clang-profile-use clang-profile-make FORCE
|
||||||
|
|
||||||
build: net config-sanity
|
build: net config-sanity
|
||||||
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) all
|
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) all
|
||||||
@@ -751,7 +849,7 @@ profile-build: net config-sanity objclean profileclean
|
|||||||
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_make)
|
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_make)
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "Step 2/4. Running benchmark for pgo-build ..."
|
@echo "Step 2/4. Running benchmark for pgo-build ..."
|
||||||
$(PGOBENCH) > /dev/null
|
$(PGOBENCH) 2>&1 | tail -n 4
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "Step 3/4. Building optimized executable ..."
|
@echo "Step 3/4. Building optimized executable ..."
|
||||||
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) objclean
|
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) objclean
|
||||||
@@ -766,7 +864,7 @@ strip:
|
|||||||
install:
|
install:
|
||||||
-mkdir -p -m 755 $(BINDIR)
|
-mkdir -p -m 755 $(BINDIR)
|
||||||
-cp $(EXE) $(BINDIR)
|
-cp $(EXE) $(BINDIR)
|
||||||
-strip $(BINDIR)/$(EXE)
|
$(STRIP) $(BINDIR)/$(EXE)
|
||||||
|
|
||||||
# clean all
|
# clean all
|
||||||
clean: objclean profileclean
|
clean: objclean profileclean
|
||||||
@@ -776,37 +874,50 @@ clean: objclean profileclean
|
|||||||
net:
|
net:
|
||||||
$(eval nnuenet := $(shell grep EvalFileDefaultName evaluate.h | grep define | sed 's/.*\(nn-[a-z0-9]\{12\}.nnue\).*/\1/'))
|
$(eval nnuenet := $(shell grep EvalFileDefaultName evaluate.h | grep define | sed 's/.*\(nn-[a-z0-9]\{12\}.nnue\).*/\1/'))
|
||||||
@echo "Default net: $(nnuenet)"
|
@echo "Default net: $(nnuenet)"
|
||||||
$(eval nnuedownloadurl := https://tests.stockfishchess.org/api/nn/$(nnuenet))
|
$(eval nnuedownloadurl1 := https://tests.stockfishchess.org/api/nn/$(nnuenet))
|
||||||
|
$(eval nnuedownloadurl2 := https://github.com/official-stockfish/networks/raw/master/$(nnuenet))
|
||||||
$(eval curl_or_wget := $(shell if hash curl 2>/dev/null; then echo "curl -skL"; elif hash wget 2>/dev/null; then echo "wget -qO-"; fi))
|
$(eval curl_or_wget := $(shell if hash curl 2>/dev/null; then echo "curl -skL"; elif hash wget 2>/dev/null; then echo "wget -qO-"; fi))
|
||||||
@if test -f "$(nnuenet)"; then \
|
@if [ "x$(curl_or_wget)" = "x" ]; then \
|
||||||
echo "Already available."; \
|
echo "Neither curl nor wget is installed. Install one of these tools unless the net has been downloaded manually"; \
|
||||||
else \
|
fi
|
||||||
if [ "x$(curl_or_wget)" = "x" ]; then \
|
|
||||||
echo "Automatic download failed: neither curl nor wget is installed. Install one of these tools or download the net manually"; exit 1; \
|
|
||||||
else \
|
|
||||||
echo "Downloading $(nnuedownloadurl)"; $(curl_or_wget) $(nnuedownloadurl) > $(nnuenet);\
|
|
||||||
fi; \
|
|
||||||
fi;
|
|
||||||
$(eval shasum_command := $(shell if hash shasum 2>/dev/null; then echo "shasum -a 256 "; elif hash sha256sum 2>/dev/null; then echo "sha256sum "; fi))
|
$(eval shasum_command := $(shell if hash shasum 2>/dev/null; then echo "shasum -a 256 "; elif hash sha256sum 2>/dev/null; then echo "sha256sum "; fi))
|
||||||
@if [ "x$(shasum_command)" != "x" ]; then \
|
@if [ "x$(shasum_command)" = "x" ]; then \
|
||||||
if [ "$(nnuenet)" != "nn-"`$(shasum_command) $(nnuenet) | cut -c1-12`".nnue" ]; then \
|
|
||||||
echo "Failed download or $(nnuenet) corrupted, please delete!"; exit 1; \
|
|
||||||
fi \
|
|
||||||
else \
|
|
||||||
echo "shasum / sha256sum not found, skipping net validation"; \
|
echo "shasum / sha256sum not found, skipping net validation"; \
|
||||||
fi
|
fi
|
||||||
|
@for nnuedownloadurl in "$(nnuedownloadurl1)" "$(nnuedownloadurl2)"; do \
|
||||||
|
if test -f "$(nnuenet)"; then \
|
||||||
|
echo "$(nnuenet) available."; \
|
||||||
|
else \
|
||||||
|
if [ "x$(curl_or_wget)" != "x" ]; then \
|
||||||
|
echo "Downloading $${nnuedownloadurl}"; $(curl_or_wget) $${nnuedownloadurl} > $(nnuenet);\
|
||||||
|
else \
|
||||||
|
echo "No net found and download not possible"; exit 1;\
|
||||||
|
fi; \
|
||||||
|
fi; \
|
||||||
|
if [ "x$(shasum_command)" != "x" ]; then \
|
||||||
|
if [ "$(nnuenet)" != "nn-"`$(shasum_command) $(nnuenet) | cut -c1-12`".nnue" ]; then \
|
||||||
|
echo "Removing failed download"; rm -f $(nnuenet); \
|
||||||
|
else \
|
||||||
|
echo "Network validated"; break; \
|
||||||
|
fi; \
|
||||||
|
fi; \
|
||||||
|
done
|
||||||
|
@if ! test -f "$(nnuenet)"; then \
|
||||||
|
echo "Failed to download $(nnuenet)."; \
|
||||||
|
fi
|
||||||
|
|
||||||
# clean binaries and objects
|
# clean binaries and objects
|
||||||
objclean:
|
objclean:
|
||||||
@rm -f $(EXE) *.o ./syzygy/*.o ./nnue/*.o ./nnue/features/*.o
|
@rm -f stockfish stockfish.exe *.o ./syzygy/*.o ./nnue/*.o ./nnue/features/*.o
|
||||||
|
|
||||||
# clean auxiliary profiling files
|
# clean auxiliary profiling files
|
||||||
profileclean:
|
profileclean:
|
||||||
@rm -rf profdir
|
@rm -rf profdir
|
||||||
@rm -f bench.txt *.gcda *.gcno ./syzygy/*.gcda ./nnue/*.gcda ./nnue/features/*.gcda *.s
|
@rm -f bench.txt *.gcda *.gcno ./syzygy/*.gcda ./nnue/*.gcda ./nnue/features/*.gcda *.s
|
||||||
@rm -f stockfish.profdata *.profraw
|
@rm -f stockfish.profdata *.profraw
|
||||||
@rm -f stockfish.exe.lto_wrapper_args
|
@rm -f stockfish.*args*
|
||||||
@rm -f stockfish.exe.ltrans.out
|
@rm -f stockfish.*lt*
|
||||||
|
@rm -f stockfish.res
|
||||||
@rm -f ./-lstdc++.res
|
@rm -f ./-lstdc++.res
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -837,10 +948,14 @@ config-sanity: net
|
|||||||
@echo "ssse3: '$(ssse3)'"
|
@echo "ssse3: '$(ssse3)'"
|
||||||
@echo "sse41: '$(sse41)'"
|
@echo "sse41: '$(sse41)'"
|
||||||
@echo "avx2: '$(avx2)'"
|
@echo "avx2: '$(avx2)'"
|
||||||
|
@echo "avxvnni: '$(avxvnni)'"
|
||||||
@echo "avx512: '$(avx512)'"
|
@echo "avx512: '$(avx512)'"
|
||||||
@echo "vnni256: '$(vnni256)'"
|
@echo "vnni256: '$(vnni256)'"
|
||||||
@echo "vnni512: '$(vnni512)'"
|
@echo "vnni512: '$(vnni512)'"
|
||||||
@echo "neon: '$(neon)'"
|
@echo "neon: '$(neon)'"
|
||||||
|
@echo "dotprod: '$(dotprod)'"
|
||||||
|
@echo "arm_version: '$(arm_version)'"
|
||||||
|
@echo "target_windows: '$(target_windows)'"
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "Flags:"
|
@echo "Flags:"
|
||||||
@echo "CXX: $(CXX)"
|
@echo "CXX: $(CXX)"
|
||||||
@@ -854,7 +969,7 @@ config-sanity: net
|
|||||||
@test "$(SUPPORTED_ARCH)" = "true"
|
@test "$(SUPPORTED_ARCH)" = "true"
|
||||||
@test "$(arch)" = "any" || test "$(arch)" = "x86_64" || test "$(arch)" = "i386" || \
|
@test "$(arch)" = "any" || test "$(arch)" = "x86_64" || test "$(arch)" = "i386" || \
|
||||||
test "$(arch)" = "ppc64" || test "$(arch)" = "ppc" || test "$(arch)" = "e2k" || \
|
test "$(arch)" = "ppc64" || test "$(arch)" = "ppc" || test "$(arch)" = "e2k" || \
|
||||||
test "$(arch)" = "armv7" || test "$(arch)" = "armv8" || test "$(arch)" = "arm64"
|
test "$(arch)" = "armv7" || test "$(arch)" = "armv8" || test "$(arch)" = "arm64" || test "$(arch)" = "riscv64"
|
||||||
@test "$(bits)" = "32" || test "$(bits)" = "64"
|
@test "$(bits)" = "32" || test "$(bits)" = "64"
|
||||||
@test "$(prefetch)" = "yes" || test "$(prefetch)" = "no"
|
@test "$(prefetch)" = "yes" || test "$(prefetch)" = "no"
|
||||||
@test "$(popcnt)" = "yes" || test "$(popcnt)" = "no"
|
@test "$(popcnt)" = "yes" || test "$(popcnt)" = "no"
|
||||||
@@ -869,12 +984,16 @@ config-sanity: net
|
|||||||
@test "$(vnni256)" = "yes" || test "$(vnni256)" = "no"
|
@test "$(vnni256)" = "yes" || test "$(vnni256)" = "no"
|
||||||
@test "$(vnni512)" = "yes" || test "$(vnni512)" = "no"
|
@test "$(vnni512)" = "yes" || test "$(vnni512)" = "no"
|
||||||
@test "$(neon)" = "yes" || test "$(neon)" = "no"
|
@test "$(neon)" = "yes" || test "$(neon)" = "no"
|
||||||
@test "$(comp)" = "gcc" || test "$(comp)" = "icc" || test "$(comp)" = "mingw" || test "$(comp)" = "clang" \
|
@test "$(comp)" = "gcc" || test "$(comp)" = "icx" || test "$(comp)" = "mingw" || test "$(comp)" = "clang" \
|
||||||
|| test "$(comp)" = "armv7a-linux-androideabi16-clang" || test "$(comp)" = "aarch64-linux-android21-clang"
|
|| test "$(comp)" = "armv7a-linux-androideabi16-clang" || test "$(comp)" = "aarch64-linux-android21-clang"
|
||||||
|
|
||||||
$(EXE): $(OBJS)
|
$(EXE): $(OBJS)
|
||||||
+$(CXX) -o $@ $(OBJS) $(LDFLAGS)
|
+$(CXX) -o $@ $(OBJS) $(LDFLAGS)
|
||||||
|
|
||||||
|
# Force recompilation to ensure version info is up-to-date
|
||||||
|
misc.o: FORCE
|
||||||
|
FORCE:
|
||||||
|
|
||||||
clang-profile-make:
|
clang-profile-make:
|
||||||
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
|
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
|
||||||
EXTRACXXFLAGS='-fprofile-instr-generate ' \
|
EXTRACXXFLAGS='-fprofile-instr-generate ' \
|
||||||
@@ -892,27 +1011,33 @@ gcc-profile-make:
|
|||||||
@mkdir -p profdir
|
@mkdir -p profdir
|
||||||
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
|
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
|
||||||
EXTRACXXFLAGS='-fprofile-generate=profdir' \
|
EXTRACXXFLAGS='-fprofile-generate=profdir' \
|
||||||
|
EXTRACXXFLAGS+=$(EXTRAPROFILEFLAGS) \
|
||||||
EXTRALDFLAGS='-lgcov' \
|
EXTRALDFLAGS='-lgcov' \
|
||||||
all
|
all
|
||||||
|
|
||||||
gcc-profile-use:
|
gcc-profile-use:
|
||||||
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
|
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
|
||||||
EXTRACXXFLAGS='-fprofile-use=profdir -fno-peel-loops -fno-tracer' \
|
EXTRACXXFLAGS='-fprofile-use=profdir -fno-peel-loops -fno-tracer' \
|
||||||
|
EXTRACXXFLAGS+=$(EXTRAPROFILEFLAGS) \
|
||||||
EXTRALDFLAGS='-lgcov' \
|
EXTRALDFLAGS='-lgcov' \
|
||||||
all
|
all
|
||||||
|
|
||||||
icc-profile-make:
|
icx-profile-make:
|
||||||
@mkdir -p profdir
|
|
||||||
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
|
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
|
||||||
EXTRACXXFLAGS='-prof-gen=srcpos -prof_dir ./profdir' \
|
EXTRACXXFLAGS='-fprofile-instr-generate ' \
|
||||||
|
EXTRALDFLAGS=' -fprofile-instr-generate' \
|
||||||
all
|
all
|
||||||
|
|
||||||
icc-profile-use:
|
icx-profile-use:
|
||||||
|
$(XCRUN) llvm-profdata merge -output=stockfish.profdata *.profraw
|
||||||
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
|
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
|
||||||
EXTRACXXFLAGS='-prof_use -prof_dir ./profdir' \
|
EXTRACXXFLAGS='-fprofile-instr-use=stockfish.profdata' \
|
||||||
|
EXTRALDFLAGS='-fprofile-use ' \
|
||||||
all
|
all
|
||||||
|
|
||||||
.depend: $(SRCS)
|
.depend: $(SRCS)
|
||||||
-@$(CXX) $(DEPENDFLAGS) -MM $(SRCS) > $@ 2> /dev/null
|
-@$(CXX) $(DEPENDFLAGS) -MM $(SRCS) > $@ 2> /dev/null
|
||||||
|
|
||||||
|
ifeq (, $(filter $(MAKECMDGOALS), help strip install clean net objclean profileclean config-sanity))
|
||||||
-include .depend
|
-include .depend
|
||||||
|
endif
|
||||||
|
|||||||
+4
-1
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -16,6 +16,8 @@
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "benchmark.h"
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <istream>
|
#include <istream>
|
||||||
@@ -87,6 +89,7 @@ const vector<string> Defaults = {
|
|||||||
// Chess 960
|
// Chess 960
|
||||||
"setoption name UCI_Chess960 value true",
|
"setoption name UCI_Chess960 value true",
|
||||||
"bbqnnrkr/pppppppp/8/8/8/8/PPPPPPPP/BBQNNRKR w HFhf - 0 1 moves g2g3 d7d5 d2d4 c8h3 c1g5 e8d6 g5e7 f7f6",
|
"bbqnnrkr/pppppppp/8/8/8/8/PPPPPPPP/BBQNNRKR w HFhf - 0 1 moves g2g3 d7d5 d2d4 c8h3 c1g5 e8d6 g5e7 f7f6",
|
||||||
|
"nqbnrkrb/pppppppp/8/8/8/8/PPPPPPPP/NQBNRKRB w KQkq - 0 1",
|
||||||
"setoption name UCI_Chess960 value false"
|
"setoption name UCI_Chess960 value false"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Stockfish is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BENCHMARK_H_INCLUDED
|
||||||
|
#define BENCHMARK_H_INCLUDED
|
||||||
|
|
||||||
|
#include <iosfwd>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Stockfish {
|
||||||
|
|
||||||
|
class Position;
|
||||||
|
|
||||||
|
std::vector<std::string> setup_bench(const Position&, std::istream&);
|
||||||
|
|
||||||
|
} // namespace Stockfish
|
||||||
|
|
||||||
|
#endif // #ifndef BENCHMARK_H_INCLUDED
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
+1
-5
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -27,7 +27,6 @@ namespace Stockfish {
|
|||||||
uint8_t PopCnt16[1 << 16];
|
uint8_t PopCnt16[1 << 16];
|
||||||
uint8_t SquareDistance[SQUARE_NB][SQUARE_NB];
|
uint8_t SquareDistance[SQUARE_NB][SQUARE_NB];
|
||||||
|
|
||||||
Bitboard SquareBB[SQUARE_NB];
|
|
||||||
Bitboard LineBB[SQUARE_NB][SQUARE_NB];
|
Bitboard LineBB[SQUARE_NB][SQUARE_NB];
|
||||||
Bitboard BetweenBB[SQUARE_NB][SQUARE_NB];
|
Bitboard BetweenBB[SQUARE_NB][SQUARE_NB];
|
||||||
Bitboard PseudoAttacks[PIECE_TYPE_NB][SQUARE_NB];
|
Bitboard PseudoAttacks[PIECE_TYPE_NB][SQUARE_NB];
|
||||||
@@ -82,9 +81,6 @@ void Bitboards::init() {
|
|||||||
for (unsigned i = 0; i < (1 << 16); ++i)
|
for (unsigned i = 0; i < (1 << 16); ++i)
|
||||||
PopCnt16[i] = uint8_t(std::bitset<16>(i).count());
|
PopCnt16[i] = uint8_t(std::bitset<16>(i).count());
|
||||||
|
|
||||||
for (Square s = SQ_A1; s <= SQ_H8; ++s)
|
|
||||||
SquareBB[s] = (1ULL << s);
|
|
||||||
|
|
||||||
for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
|
for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
|
||||||
for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2)
|
for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2)
|
||||||
SquareDistance[s1][s2] = std::max(distance<File>(s1, s2), distance<Rank>(s1, s2));
|
SquareDistance[s1][s2] = std::max(distance<File>(s1, s2), distance<Rank>(s1, s2));
|
||||||
|
|||||||
+2
-3
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -74,7 +74,6 @@ constexpr Bitboard KingFlank[FILE_NB] = {
|
|||||||
extern uint8_t PopCnt16[1 << 16];
|
extern uint8_t PopCnt16[1 << 16];
|
||||||
extern uint8_t SquareDistance[SQUARE_NB][SQUARE_NB];
|
extern uint8_t SquareDistance[SQUARE_NB][SQUARE_NB];
|
||||||
|
|
||||||
extern Bitboard SquareBB[SQUARE_NB];
|
|
||||||
extern Bitboard BetweenBB[SQUARE_NB][SQUARE_NB];
|
extern Bitboard BetweenBB[SQUARE_NB][SQUARE_NB];
|
||||||
extern Bitboard LineBB[SQUARE_NB][SQUARE_NB];
|
extern Bitboard LineBB[SQUARE_NB][SQUARE_NB];
|
||||||
extern Bitboard PseudoAttacks[PIECE_TYPE_NB][SQUARE_NB];
|
extern Bitboard PseudoAttacks[PIECE_TYPE_NB][SQUARE_NB];
|
||||||
@@ -108,7 +107,7 @@ extern Magic BishopMagics[SQUARE_NB];
|
|||||||
|
|
||||||
inline Bitboard square_bb(Square s) {
|
inline Bitboard square_bb(Square s) {
|
||||||
assert(is_ok(s));
|
assert(is_ok(s));
|
||||||
return SquareBB[s];
|
return (1ULL << s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
+62
-83
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
#include "timeman.h"
|
#include "timeman.h"
|
||||||
#include "uci.h"
|
#include "uci.h"
|
||||||
#include "incbin/incbin.h"
|
#include "incbin/incbin.h"
|
||||||
|
#include "nnue/evaluate_nnue.h"
|
||||||
|
|
||||||
// Macro to embed the default efficiently updatable neural network (NNUE) file
|
// Macro to embed the default efficiently updatable neural network (NNUE) file
|
||||||
// data in the engine binary (using incbin.h, by Dale Weiler).
|
// data in the engine binary (using incbin.h, by Dale Weiler).
|
||||||
@@ -82,20 +82,18 @@ namespace Eval {
|
|||||||
eval_file = EvalFileDefaultName;
|
eval_file = EvalFileDefaultName;
|
||||||
|
|
||||||
#if defined(DEFAULT_NNUE_DIRECTORY)
|
#if defined(DEFAULT_NNUE_DIRECTORY)
|
||||||
#define stringify2(x) #x
|
|
||||||
#define stringify(x) stringify2(x)
|
|
||||||
vector<string> dirs = { "<internal>" , "" , CommandLine::binaryDirectory , stringify(DEFAULT_NNUE_DIRECTORY) };
|
vector<string> dirs = { "<internal>" , "" , CommandLine::binaryDirectory , stringify(DEFAULT_NNUE_DIRECTORY) };
|
||||||
#else
|
#else
|
||||||
vector<string> dirs = { "<internal>" , "" , CommandLine::binaryDirectory };
|
vector<string> dirs = { "<internal>" , "" , CommandLine::binaryDirectory };
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (string directory : dirs)
|
for (const string& directory : dirs)
|
||||||
if (currentEvalFileName != eval_file)
|
if (currentEvalFileName != eval_file)
|
||||||
{
|
{
|
||||||
if (directory != "<internal>")
|
if (directory != "<internal>")
|
||||||
{
|
{
|
||||||
ifstream stream(directory + eval_file, ios::binary);
|
ifstream stream(directory + eval_file, ios::binary);
|
||||||
if (load_eval(eval_file, stream))
|
if (NNUE::load_eval(eval_file, stream))
|
||||||
currentEvalFileName = eval_file;
|
currentEvalFileName = eval_file;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,9 +106,10 @@ namespace Eval {
|
|||||||
|
|
||||||
MemoryBuffer buffer(const_cast<char*>(reinterpret_cast<const char*>(gEmbeddedNNUEData)),
|
MemoryBuffer buffer(const_cast<char*>(reinterpret_cast<const char*>(gEmbeddedNNUEData)),
|
||||||
size_t(gEmbeddedNNUESize));
|
size_t(gEmbeddedNNUESize));
|
||||||
|
(void) gEmbeddedNNUEEnd; // Silence warning on unused variable
|
||||||
|
|
||||||
istream stream(&buffer);
|
istream stream(&buffer);
|
||||||
if (load_eval(eval_file, stream))
|
if (NNUE::load_eval(eval_file, stream))
|
||||||
currentEvalFileName = eval_file;
|
currentEvalFileName = eval_file;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -158,24 +157,24 @@ namespace Trace {
|
|||||||
|
|
||||||
Score scores[TERM_NB][COLOR_NB];
|
Score scores[TERM_NB][COLOR_NB];
|
||||||
|
|
||||||
double to_cp(Value v) { return double(v) / PawnValueEg; }
|
static double to_cp(Value v) { return double(v) / UCI::NormalizeToPawnValue; }
|
||||||
|
|
||||||
void add(int idx, Color c, Score s) {
|
static void add(int idx, Color c, Score s) {
|
||||||
scores[idx][c] = s;
|
scores[idx][c] = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
void add(int idx, Score w, Score b = SCORE_ZERO) {
|
static void add(int idx, Score w, Score b = SCORE_ZERO) {
|
||||||
scores[idx][WHITE] = w;
|
scores[idx][WHITE] = w;
|
||||||
scores[idx][BLACK] = b;
|
scores[idx][BLACK] = b;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os, Score s) {
|
static std::ostream& operator<<(std::ostream& os, Score s) {
|
||||||
os << std::setw(5) << to_cp(mg_value(s)) << " "
|
os << std::setw(5) << to_cp(mg_value(s)) << " "
|
||||||
<< std::setw(5) << to_cp(eg_value(s));
|
<< std::setw(5) << to_cp(eg_value(s));
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os, Term t) {
|
static std::ostream& operator<<(std::ostream& os, Term t) {
|
||||||
|
|
||||||
if (t == MATERIAL || t == IMBALANCE || t == WINNABLE || t == TOTAL)
|
if (t == MATERIAL || t == IMBALANCE || t == WINNABLE || t == TOTAL)
|
||||||
os << " ---- ----" << " | " << " ---- ----";
|
os << " ---- ----" << " | " << " ---- ----";
|
||||||
@@ -192,17 +191,17 @@ using namespace Trace;
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// Threshold for lazy and space evaluation
|
// Threshold for lazy and space evaluation
|
||||||
constexpr Value LazyThreshold1 = Value(3130);
|
constexpr Value LazyThreshold1 = Value(3622);
|
||||||
constexpr Value LazyThreshold2 = Value(2204);
|
constexpr Value LazyThreshold2 = Value(1962);
|
||||||
constexpr Value SpaceThreshold = Value(11551);
|
constexpr Value SpaceThreshold = Value(11551);
|
||||||
|
|
||||||
// KingAttackWeights[PieceType] contains king attack weights by piece type
|
// KingAttackWeights[PieceType] contains king attack weights by piece type
|
||||||
constexpr int KingAttackWeights[PIECE_TYPE_NB] = { 0, 0, 81, 52, 44, 10 };
|
constexpr int KingAttackWeights[PIECE_TYPE_NB] = { 0, 0, 76, 46, 45, 14 };
|
||||||
|
|
||||||
// SafeCheck[PieceType][single/multiple] contains safe check bonus by piece type,
|
// SafeCheck[PieceType][single/multiple] contains safe check bonus by piece type,
|
||||||
// higher if multiple safe checks are possible for that piece type.
|
// higher if multiple safe checks are possible for that piece type.
|
||||||
constexpr int SafeCheck[][2] = {
|
constexpr int SafeCheck[][2] = {
|
||||||
{}, {}, {803, 1292}, {639, 974}, {1087, 1878}, {759, 1132}
|
{}, {}, {805, 1292}, {650, 984}, {1071, 1886}, {730, 1128}
|
||||||
};
|
};
|
||||||
|
|
||||||
#define S(mg, eg) make_score(mg, eg)
|
#define S(mg, eg) make_score(mg, eg)
|
||||||
@@ -228,58 +227,58 @@ namespace {
|
|||||||
// BishopPawns[distance from edge] contains a file-dependent penalty for pawns on
|
// BishopPawns[distance from edge] contains a file-dependent penalty for pawns on
|
||||||
// squares of the same color as our bishop.
|
// squares of the same color as our bishop.
|
||||||
constexpr Score BishopPawns[int(FILE_NB) / 2] = {
|
constexpr Score BishopPawns[int(FILE_NB) / 2] = {
|
||||||
S(3, 8), S(3, 9), S(2, 8), S(3, 8)
|
S(3, 8), S(3, 9), S(2, 7), S(3, 7)
|
||||||
};
|
};
|
||||||
|
|
||||||
// KingProtector[knight/bishop] contains penalty for each distance unit to own king
|
// KingProtector[knight/bishop] contains penalty for each distance unit to own king
|
||||||
constexpr Score KingProtector[] = { S(8, 9), S(6, 9) };
|
constexpr Score KingProtector[] = { S(9, 9), S(7, 9) };
|
||||||
|
|
||||||
// Outpost[knight/bishop] contains bonuses for each knight or bishop occupying a
|
// Outpost[knight/bishop] contains bonuses for each knight or bishop occupying a
|
||||||
// pawn protected square on rank 4 to 6 which is also safe from a pawn attack.
|
// pawn protected square on rank 4 to 6 which is also safe from a pawn attack.
|
||||||
constexpr Score Outpost[] = { S(57, 38), S(31, 24) };
|
constexpr Score Outpost[] = { S(54, 34), S(31, 25) };
|
||||||
|
|
||||||
// PassedRank[Rank] contains a bonus according to the rank of a passed pawn
|
// PassedRank[Rank] contains a bonus according to the rank of a passed pawn
|
||||||
constexpr Score PassedRank[RANK_NB] = {
|
constexpr Score PassedRank[RANK_NB] = {
|
||||||
S(0, 0), S(7, 27), S(16, 32), S(17, 40), S(64, 71), S(170, 174), S(278, 262)
|
S(0, 0), S(2, 38), S(15, 36), S(22, 50), S(64, 81), S(166, 184), S(284, 269)
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr Score RookOnClosedFile = S(10, 5);
|
constexpr Score RookOnClosedFile = S(10, 5);
|
||||||
constexpr Score RookOnOpenFile[] = { S(19, 6), S(47, 26) };
|
constexpr Score RookOnOpenFile[] = { S(18, 8), S(49, 26) };
|
||||||
|
|
||||||
// ThreatByMinor/ByRook[attacked PieceType] contains bonuses according to
|
// ThreatByMinor/ByRook[attacked PieceType] contains bonuses according to
|
||||||
// which piece type attacks which one. Attacks on lesser pieces which are
|
// which piece type attacks which one. Attacks on lesser pieces which are
|
||||||
// pawn-defended are not considered.
|
// pawn-defended are not considered.
|
||||||
constexpr Score ThreatByMinor[PIECE_TYPE_NB] = {
|
constexpr Score ThreatByMinor[PIECE_TYPE_NB] = {
|
||||||
S(0, 0), S(5, 32), S(55, 41), S(77, 56), S(89, 119), S(79, 162)
|
S(0, 0), S(6, 37), S(64, 50), S(82, 57), S(103, 130), S(81, 163)
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr Score ThreatByRook[PIECE_TYPE_NB] = {
|
constexpr Score ThreatByRook[PIECE_TYPE_NB] = {
|
||||||
S(0, 0), S(3, 44), S(37, 68), S(42, 60), S(0, 39), S(58, 43)
|
S(0, 0), S(3, 44), S(36, 71), S(44, 59), S(0, 39), S(60, 39)
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr Value CorneredBishop = Value(50);
|
constexpr Value CorneredBishop = Value(50);
|
||||||
|
|
||||||
// Assorted bonuses and penalties
|
// Assorted bonuses and penalties
|
||||||
constexpr Score UncontestedOutpost = S( 1, 10);
|
constexpr Score UncontestedOutpost = S( 0, 10);
|
||||||
constexpr Score BishopOnKingRing = S( 24, 0);
|
constexpr Score BishopOnKingRing = S( 24, 0);
|
||||||
constexpr Score BishopXRayPawns = S( 4, 5);
|
constexpr Score BishopXRayPawns = S( 4, 5);
|
||||||
constexpr Score FlankAttacks = S( 8, 0);
|
constexpr Score FlankAttacks = S( 8, 0);
|
||||||
constexpr Score Hanging = S( 69, 36);
|
constexpr Score Hanging = S( 72, 40);
|
||||||
constexpr Score KnightOnQueen = S( 16, 11);
|
constexpr Score KnightOnQueen = S( 16, 11);
|
||||||
constexpr Score LongDiagonalBishop = S( 45, 0);
|
constexpr Score LongDiagonalBishop = S( 45, 0);
|
||||||
constexpr Score MinorBehindPawn = S( 18, 3);
|
constexpr Score MinorBehindPawn = S( 18, 3);
|
||||||
constexpr Score PassedFile = S( 11, 8);
|
constexpr Score PassedFile = S( 13, 8);
|
||||||
constexpr Score PawnlessFlank = S( 17, 95);
|
constexpr Score PawnlessFlank = S( 19, 97);
|
||||||
constexpr Score ReachableOutpost = S( 31, 22);
|
constexpr Score ReachableOutpost = S( 33, 19);
|
||||||
constexpr Score RestrictedPiece = S( 7, 7);
|
constexpr Score RestrictedPiece = S( 6, 7);
|
||||||
constexpr Score RookOnKingRing = S( 16, 0);
|
constexpr Score RookOnKingRing = S( 16, 0);
|
||||||
constexpr Score SliderOnQueen = S( 60, 18);
|
constexpr Score SliderOnQueen = S( 62, 21);
|
||||||
constexpr Score ThreatByKing = S( 24, 89);
|
constexpr Score ThreatByKing = S( 24, 87);
|
||||||
constexpr Score ThreatByPawnPush = S( 48, 39);
|
constexpr Score ThreatByPawnPush = S( 48, 39);
|
||||||
constexpr Score ThreatBySafePawn = S(173, 94);
|
constexpr Score ThreatBySafePawn = S(167, 99);
|
||||||
constexpr Score TrappedRook = S( 55, 13);
|
constexpr Score TrappedRook = S( 55, 13);
|
||||||
constexpr Score WeakQueenProtection = S( 14, 0);
|
constexpr Score WeakQueenProtection = S( 14, 0);
|
||||||
constexpr Score WeakQueen = S( 56, 15);
|
constexpr Score WeakQueen = S( 57, 19);
|
||||||
|
|
||||||
|
|
||||||
#undef S
|
#undef S
|
||||||
@@ -388,8 +387,8 @@ namespace {
|
|||||||
Score Evaluation<T>::pieces() {
|
Score Evaluation<T>::pieces() {
|
||||||
|
|
||||||
constexpr Color Them = ~Us;
|
constexpr Color Them = ~Us;
|
||||||
constexpr Direction Down = -pawn_push(Us);
|
[[maybe_unused]] constexpr Direction Down = -pawn_push(Us);
|
||||||
constexpr Bitboard OutpostRanks = (Us == WHITE ? Rank4BB | Rank5BB | Rank6BB
|
[[maybe_unused]] constexpr Bitboard OutpostRanks = (Us == WHITE ? Rank4BB | Rank5BB | Rank6BB
|
||||||
: Rank5BB | Rank4BB | Rank3BB);
|
: Rank5BB | Rank4BB | Rank3BB);
|
||||||
Bitboard b1 = pos.pieces(Us, Pt);
|
Bitboard b1 = pos.pieces(Us, Pt);
|
||||||
Bitboard b, bb;
|
Bitboard b, bb;
|
||||||
@@ -429,7 +428,7 @@ namespace {
|
|||||||
int mob = popcount(b & mobilityArea[Us]);
|
int mob = popcount(b & mobilityArea[Us]);
|
||||||
mobility[Us] += MobilityBonus[Pt - 2][mob];
|
mobility[Us] += MobilityBonus[Pt - 2][mob];
|
||||||
|
|
||||||
if (Pt == BISHOP || Pt == KNIGHT)
|
if constexpr (Pt == BISHOP || Pt == KNIGHT)
|
||||||
{
|
{
|
||||||
// Bonus if the piece is on an outpost square or can reach one
|
// Bonus if the piece is on an outpost square or can reach one
|
||||||
// Bonus for knights (UncontestedOutpost) if few relevant targets
|
// Bonus for knights (UncontestedOutpost) if few relevant targets
|
||||||
@@ -980,7 +979,7 @@ namespace {
|
|||||||
// Initialize score by reading the incrementally updated scores included in
|
// Initialize score by reading the incrementally updated scores included in
|
||||||
// the position object (material + piece square tables) and the material
|
// the position object (material + piece square tables) and the material
|
||||||
// imbalance. Score is computed internally from the white point of view.
|
// imbalance. Score is computed internally from the white point of view.
|
||||||
Score score = pos.psq_score() + me->imbalance() + pos.this_thread()->trend;
|
Score score = pos.psq_score() + me->imbalance();
|
||||||
|
|
||||||
// Probe the pawn hash table
|
// Probe the pawn hash table
|
||||||
pe = Pawns::probe(pos);
|
pe = Pawns::probe(pos);
|
||||||
@@ -988,7 +987,9 @@ namespace {
|
|||||||
|
|
||||||
// Early exit if score is high
|
// Early exit if score is high
|
||||||
auto lazy_skip = [&](Value lazyThreshold) {
|
auto lazy_skip = [&](Value lazyThreshold) {
|
||||||
return abs(mg_value(score) + eg_value(score)) > lazyThreshold + pos.non_pawn_material() / 32;
|
return abs(mg_value(score) + eg_value(score)) > lazyThreshold
|
||||||
|
+ std::abs(pos.this_thread()->bestValue) * 5 / 4
|
||||||
|
+ pos.non_pawn_material() / 32;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (lazy_skip(LazyThreshold1))
|
if (lazy_skip(LazyThreshold1))
|
||||||
@@ -1039,38 +1040,6 @@ make_v:
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Fisher Random Chess: correction for cornered bishops, to fix chess960 play with NNUE
|
|
||||||
|
|
||||||
Value fix_FRC(const Position& pos) {
|
|
||||||
|
|
||||||
constexpr Bitboard Corners = 1ULL << SQ_A1 | 1ULL << SQ_H1 | 1ULL << SQ_A8 | 1ULL << SQ_H8;
|
|
||||||
|
|
||||||
if (!(pos.pieces(BISHOP) & Corners))
|
|
||||||
return VALUE_ZERO;
|
|
||||||
|
|
||||||
int correction = 0;
|
|
||||||
|
|
||||||
if ( pos.piece_on(SQ_A1) == W_BISHOP
|
|
||||||
&& pos.piece_on(SQ_B2) == W_PAWN)
|
|
||||||
correction -= CorneredBishop;
|
|
||||||
|
|
||||||
if ( pos.piece_on(SQ_H1) == W_BISHOP
|
|
||||||
&& pos.piece_on(SQ_G2) == W_PAWN)
|
|
||||||
correction -= CorneredBishop;
|
|
||||||
|
|
||||||
if ( pos.piece_on(SQ_A8) == B_BISHOP
|
|
||||||
&& pos.piece_on(SQ_B7) == B_PAWN)
|
|
||||||
correction += CorneredBishop;
|
|
||||||
|
|
||||||
if ( pos.piece_on(SQ_H8) == B_BISHOP
|
|
||||||
&& pos.piece_on(SQ_G7) == B_PAWN)
|
|
||||||
correction += CorneredBishop;
|
|
||||||
|
|
||||||
return pos.side_to_move() == WHITE ? Value(5 * correction)
|
|
||||||
: -Value(5 * correction);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Eval
|
} // namespace Eval
|
||||||
|
|
||||||
|
|
||||||
@@ -1079,28 +1048,35 @@ make_v:
|
|||||||
|
|
||||||
Value Eval::evaluate(const Position& pos) {
|
Value Eval::evaluate(const Position& pos) {
|
||||||
|
|
||||||
|
assert(!pos.checkers());
|
||||||
|
|
||||||
Value v;
|
Value v;
|
||||||
|
Value psq = pos.psq_eg_stm();
|
||||||
|
|
||||||
// Deciding between classical and NNUE eval: for high PSQ imbalance we use classical,
|
// We use the much less accurate but faster Classical eval when the NNUE
|
||||||
// but we switch to NNUE during long shuffling or with high material on the board.
|
// option is set to false. Otherwise we use the NNUE eval unless the
|
||||||
|
// PSQ advantage is decisive. (~4 Elo at STC, 1 Elo at LTC)
|
||||||
|
bool useClassical = !useNNUE || abs(psq) > 2048;
|
||||||
|
|
||||||
if ( !useNNUE
|
if (useClassical)
|
||||||
|| abs(eg_value(pos.psq_score())) * 5 > (850 + pos.non_pawn_material() / 64) * (5 + pos.rule50_count()))
|
v = Evaluation<NO_TRACE>(pos).value();
|
||||||
v = Evaluation<NO_TRACE>(pos).value(); // classical
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int scale = 883
|
int nnueComplexity;
|
||||||
+ 32 * pos.count<PAWN>()
|
int npm = pos.non_pawn_material() / 64;
|
||||||
+ 32 * pos.non_pawn_material() / 1024;
|
|
||||||
|
|
||||||
v = NNUE::evaluate(pos, true) * scale / 1024; // NNUE
|
Color stm = pos.side_to_move();
|
||||||
|
Value optimism = pos.this_thread()->optimism[stm];
|
||||||
|
|
||||||
if (pos.is_chess960())
|
Value nnue = NNUE::evaluate(pos, true, &nnueComplexity);
|
||||||
v += fix_FRC(pos);
|
|
||||||
|
// Blend optimism with nnue complexity and (semi)classical complexity
|
||||||
|
optimism += optimism * (nnueComplexity + abs(psq - nnue)) / 512;
|
||||||
|
v = (nnue * (945 + npm) + optimism * (150 + npm)) / 1024;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Damp down the evaluation linearly when shuffling
|
// Damp down the evaluation linearly when shuffling
|
||||||
v = v * (100 - pos.rule50_count()) / 100;
|
v = v * (200 - pos.rule50_count()) / 214;
|
||||||
|
|
||||||
// Guarantee evaluation does not hit the tablebase range
|
// Guarantee evaluation does not hit the tablebase range
|
||||||
v = std::clamp(v, VALUE_TB_LOSS_IN_MAX_PLY + 1, VALUE_TB_WIN_IN_MAX_PLY - 1);
|
v = std::clamp(v, VALUE_TB_LOSS_IN_MAX_PLY + 1, VALUE_TB_WIN_IN_MAX_PLY - 1);
|
||||||
@@ -1125,7 +1101,10 @@ std::string Eval::trace(Position& pos) {
|
|||||||
|
|
||||||
std::memset(scores, 0, sizeof(scores));
|
std::memset(scores, 0, sizeof(scores));
|
||||||
|
|
||||||
pos.this_thread()->trend = SCORE_ZERO; // Reset any dynamic contempt
|
// Reset any global variable used in eval
|
||||||
|
pos.this_thread()->bestValue = VALUE_ZERO;
|
||||||
|
pos.this_thread()->optimism[WHITE] = VALUE_ZERO;
|
||||||
|
pos.this_thread()->optimism[BLACK] = VALUE_ZERO;
|
||||||
|
|
||||||
v = Evaluation<TRACE>(pos).value();
|
v = Evaluation<TRACE>(pos).value();
|
||||||
|
|
||||||
|
|||||||
+2
-9
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -39,20 +39,13 @@ namespace Eval {
|
|||||||
// The default net name MUST follow the format nn-[SHA256 first 12 digits].nnue
|
// The default net name MUST follow the format nn-[SHA256 first 12 digits].nnue
|
||||||
// for the build process (profile-build and fishtest) to work. Do not change the
|
// for the build process (profile-build and fishtest) to work. Do not change the
|
||||||
// name of the macro, as it is used in the Makefile.
|
// name of the macro, as it is used in the Makefile.
|
||||||
#define EvalFileDefaultName "nn-13406b1dcbe0.nnue"
|
#define EvalFileDefaultName "nn-5af11540bbfe.nnue"
|
||||||
|
|
||||||
namespace NNUE {
|
namespace NNUE {
|
||||||
|
|
||||||
std::string trace(Position& pos);
|
|
||||||
Value evaluate(const Position& pos, bool adjusted = false);
|
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
void verify();
|
void verify();
|
||||||
|
|
||||||
bool load_eval(std::string name, std::istream& stream);
|
|
||||||
bool save_eval(std::ostream& stream);
|
|
||||||
bool save_eval(const std::optional<std::string>& filename);
|
|
||||||
|
|
||||||
} // namespace NNUE
|
} // namespace NNUE
|
||||||
|
|
||||||
} // namespace Eval
|
} // namespace Eval
|
||||||
|
|||||||
Executable → Regular
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
+3
-3
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -28,7 +28,7 @@ namespace Stockfish::Material {
|
|||||||
|
|
||||||
/// Material::Entry contains various information about a material configuration.
|
/// Material::Entry contains various information about a material configuration.
|
||||||
/// It contains a material imbalance evaluation, a function pointer to a special
|
/// It contains a material imbalance evaluation, a function pointer to a special
|
||||||
/// endgame evaluation function (which in most cases is NULL, meaning that the
|
/// endgame evaluation function (which in most cases is nullptr, meaning that the
|
||||||
/// standard evaluation function will be used), and scale factors.
|
/// standard evaluation function will be used), and scale factors.
|
||||||
///
|
///
|
||||||
/// The scale factors are used to scale the evaluation score up or down. For
|
/// The scale factors are used to scale the evaluation score up or down. For
|
||||||
@@ -62,7 +62,7 @@ struct Entry {
|
|||||||
uint8_t factor[COLOR_NB];
|
uint8_t factor[COLOR_NB];
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef HashTable<Entry, 8192> Table;
|
using Table = HashTable<Entry, 8192>;
|
||||||
|
|
||||||
Entry* probe(const Position& pos);
|
Entry* probe(const Position& pos);
|
||||||
|
|
||||||
|
|||||||
+190
-56
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -32,19 +32,26 @@
|
|||||||
// the calls at compile time), try to load them at runtime. To do this we need
|
// the calls at compile time), try to load them at runtime. To do this we need
|
||||||
// first to define the corresponding function pointers.
|
// first to define the corresponding function pointers.
|
||||||
extern "C" {
|
extern "C" {
|
||||||
typedef bool(*fun1_t)(LOGICAL_PROCESSOR_RELATIONSHIP,
|
using fun1_t = bool(*)(LOGICAL_PROCESSOR_RELATIONSHIP,
|
||||||
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, PDWORD);
|
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, PDWORD);
|
||||||
typedef bool(*fun2_t)(USHORT, PGROUP_AFFINITY);
|
using fun2_t = bool(*)(USHORT, PGROUP_AFFINITY);
|
||||||
typedef bool(*fun3_t)(HANDLE, CONST GROUP_AFFINITY*, PGROUP_AFFINITY);
|
using fun3_t = bool(*)(HANDLE, CONST GROUP_AFFINITY*, PGROUP_AFFINITY);
|
||||||
|
using fun4_t = bool(*)(USHORT, PGROUP_AFFINITY, USHORT, PUSHORT);
|
||||||
|
using fun5_t = WORD(*)();
|
||||||
|
using fun6_t = bool(*)(HANDLE, DWORD, PHANDLE);
|
||||||
|
using fun7_t = bool(*)(LPCSTR, LPCSTR, PLUID);
|
||||||
|
using fun8_t = bool(*)(HANDLE, BOOL, PTOKEN_PRIVILEGES, DWORD, PTOKEN_PRIVILEGES, PDWORD);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <cstdlib>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <string_view>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
#if defined(__linux__) && !defined(__ANDROID__)
|
#if defined(__linux__) && !defined(__ANDROID__)
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -65,9 +72,8 @@ namespace Stockfish {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
/// Version number. If Version is left empty, then compile date in the format
|
/// Version number or dev.
|
||||||
/// DD-MM-YY and show in engine_info.
|
constexpr string_view version = "16";
|
||||||
const string Version = "14.1";
|
|
||||||
|
|
||||||
/// Our fancy logging facility. The trick here is to replace cin.rdbuf() and
|
/// Our fancy logging facility. The trick here is to replace cin.rdbuf() and
|
||||||
/// cout.rdbuf() with two Tie objects that tie cin and cout to a file stream. We
|
/// cout.rdbuf() with two Tie objects that tie cin and cout to a file stream. We
|
||||||
@@ -136,23 +142,41 @@ public:
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
/// engine_info() returns the full name of the current Stockfish version. This
|
/// engine_info() returns the full name of the current Stockfish version.
|
||||||
/// will be either "Stockfish <Tag> DD-MM-YY" (where DD-MM-YY is the date when
|
/// For local dev compiles we try to append the commit sha and commit date
|
||||||
/// the program was compiled) or "Stockfish <Version>", depending on whether
|
/// from git if that fails only the local compilation date is set and "nogit" is specified:
|
||||||
/// Version is empty.
|
/// Stockfish dev-YYYYMMDD-SHA
|
||||||
|
/// or
|
||||||
|
/// Stockfish dev-YYYYMMDD-nogit
|
||||||
|
///
|
||||||
|
/// For releases (non dev builds) we only include the version number:
|
||||||
|
/// Stockfish version
|
||||||
|
|
||||||
string engine_info(bool to_uci) {
|
string engine_info(bool to_uci) {
|
||||||
|
stringstream ss;
|
||||||
|
ss << "Stockfish " << version << setfill('0');
|
||||||
|
|
||||||
const string months("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec");
|
if constexpr (version == "dev")
|
||||||
string month, day, year;
|
|
||||||
stringstream ss, date(__DATE__); // From compiler, format is "Sep 21 2008"
|
|
||||||
|
|
||||||
ss << "Stockfish " << Version << setfill('0');
|
|
||||||
|
|
||||||
if (Version.empty())
|
|
||||||
{
|
{
|
||||||
|
ss << "-";
|
||||||
|
#ifdef GIT_DATE
|
||||||
|
ss << stringify(GIT_DATE);
|
||||||
|
#else
|
||||||
|
constexpr string_view months("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec");
|
||||||
|
string month, day, year;
|
||||||
|
stringstream date(__DATE__); // From compiler, format is "Sep 21 2008"
|
||||||
|
|
||||||
date >> month >> day >> year;
|
date >> month >> day >> year;
|
||||||
ss << setw(2) << day << setw(2) << (1 + months.find(month) / 4) << year.substr(2);
|
ss << year << setw(2) << setfill('0') << (1 + months.find(month) / 4) << setw(2) << setfill('0') << day;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ss << "-";
|
||||||
|
|
||||||
|
#ifdef GIT_SHA
|
||||||
|
ss << stringify(GIT_SHA);
|
||||||
|
#else
|
||||||
|
ss << "nogit";
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
ss << (to_uci ? "\nid author ": " by ")
|
ss << (to_uci ? "\nid author ": " by ")
|
||||||
@@ -166,8 +190,6 @@ string engine_info(bool to_uci) {
|
|||||||
|
|
||||||
std::string compiler_info() {
|
std::string compiler_info() {
|
||||||
|
|
||||||
#define stringify2(x) #x
|
|
||||||
#define stringify(x) stringify2(x)
|
|
||||||
#define make_version_string(major, minor, patch) stringify(major) "." stringify(minor) "." stringify(patch)
|
#define make_version_string(major, minor, patch) stringify(major) "." stringify(minor) "." stringify(patch)
|
||||||
|
|
||||||
/// Predefined macros hell:
|
/// Predefined macros hell:
|
||||||
@@ -279,21 +301,94 @@ std::string compiler_info() {
|
|||||||
|
|
||||||
|
|
||||||
/// Debug functions used mainly to collect run-time statistics
|
/// Debug functions used mainly to collect run-time statistics
|
||||||
static std::atomic<int64_t> hits[2], means[2];
|
constexpr int MaxDebugSlots = 32;
|
||||||
|
|
||||||
void dbg_hit_on(bool b) { ++hits[0]; if (b) ++hits[1]; }
|
namespace {
|
||||||
void dbg_hit_on(bool c, bool b) { if (c) dbg_hit_on(b); }
|
|
||||||
void dbg_mean_of(int v) { ++means[0]; means[1] += v; }
|
template<size_t N>
|
||||||
|
struct DebugInfo {
|
||||||
|
std::atomic<int64_t> data[N] = { 0 };
|
||||||
|
|
||||||
|
constexpr inline std::atomic<int64_t>& operator[](int index) { return data[index]; }
|
||||||
|
};
|
||||||
|
|
||||||
|
DebugInfo<2> hit[MaxDebugSlots];
|
||||||
|
DebugInfo<2> mean[MaxDebugSlots];
|
||||||
|
DebugInfo<3> stdev[MaxDebugSlots];
|
||||||
|
DebugInfo<6> correl[MaxDebugSlots];
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void dbg_hit_on(bool cond, int slot) {
|
||||||
|
|
||||||
|
++hit[slot][0];
|
||||||
|
if (cond)
|
||||||
|
++hit[slot][1];
|
||||||
|
}
|
||||||
|
|
||||||
|
void dbg_mean_of(int64_t value, int slot) {
|
||||||
|
|
||||||
|
++mean[slot][0];
|
||||||
|
mean[slot][1] += value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dbg_stdev_of(int64_t value, int slot) {
|
||||||
|
|
||||||
|
++stdev[slot][0];
|
||||||
|
stdev[slot][1] += value;
|
||||||
|
stdev[slot][2] += value * value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dbg_correl_of(int64_t value1, int64_t value2, int slot) {
|
||||||
|
|
||||||
|
++correl[slot][0];
|
||||||
|
correl[slot][1] += value1;
|
||||||
|
correl[slot][2] += value1 * value1;
|
||||||
|
correl[slot][3] += value2;
|
||||||
|
correl[slot][4] += value2 * value2;
|
||||||
|
correl[slot][5] += value1 * value2;
|
||||||
|
}
|
||||||
|
|
||||||
void dbg_print() {
|
void dbg_print() {
|
||||||
|
|
||||||
if (hits[0])
|
int64_t n;
|
||||||
cerr << "Total " << hits[0] << " Hits " << hits[1]
|
auto E = [&n](int64_t x) { return double(x) / n; };
|
||||||
<< " hit rate (%) " << 100 * hits[1] / hits[0] << endl;
|
auto sqr = [](double x) { return x * x; };
|
||||||
|
|
||||||
if (means[0])
|
for (int i = 0; i < MaxDebugSlots; ++i)
|
||||||
cerr << "Total " << means[0] << " Mean "
|
if ((n = hit[i][0]))
|
||||||
<< (double)means[1] / means[0] << endl;
|
std::cerr << "Hit #" << i
|
||||||
|
<< ": Total " << n << " Hits " << hit[i][1]
|
||||||
|
<< " Hit Rate (%) " << 100.0 * E(hit[i][1])
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
for (int i = 0; i < MaxDebugSlots; ++i)
|
||||||
|
if ((n = mean[i][0]))
|
||||||
|
{
|
||||||
|
std::cerr << "Mean #" << i
|
||||||
|
<< ": Total " << n << " Mean " << E(mean[i][1])
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < MaxDebugSlots; ++i)
|
||||||
|
if ((n = stdev[i][0]))
|
||||||
|
{
|
||||||
|
double r = sqrtl(E(stdev[i][2]) - sqr(E(stdev[i][1])));
|
||||||
|
std::cerr << "Stdev #" << i
|
||||||
|
<< ": Total " << n << " Stdev " << r
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < MaxDebugSlots; ++i)
|
||||||
|
if ((n = correl[i][0]))
|
||||||
|
{
|
||||||
|
double r = (E(correl[i][5]) - E(correl[i][1]) * E(correl[i][3]))
|
||||||
|
/ ( sqrtl(E(correl[i][2]) - sqr(E(correl[i][1])))
|
||||||
|
* sqrtl(E(correl[i][4]) - sqr(E(correl[i][3]))));
|
||||||
|
std::cerr << "Correl. #" << i
|
||||||
|
<< ": Total " << n << " Coefficient " << r
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -354,8 +449,10 @@ void* std_aligned_alloc(size_t alignment, size_t size) {
|
|||||||
#if defined(POSIXALIGNEDALLOC)
|
#if defined(POSIXALIGNEDALLOC)
|
||||||
void *mem;
|
void *mem;
|
||||||
return posix_memalign(&mem, alignment, size) ? nullptr : mem;
|
return posix_memalign(&mem, alignment, size) ? nullptr : mem;
|
||||||
#elif defined(_WIN32)
|
#elif defined(_WIN32) && !defined(_M_ARM) && !defined(_M_ARM64)
|
||||||
return _mm_malloc(size, alignment);
|
return _mm_malloc(size, alignment);
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
return _aligned_malloc(size, alignment);
|
||||||
#else
|
#else
|
||||||
return std::aligned_alloc(alignment, size);
|
return std::aligned_alloc(alignment, size);
|
||||||
#endif
|
#endif
|
||||||
@@ -365,8 +462,10 @@ void std_aligned_free(void* ptr) {
|
|||||||
|
|
||||||
#if defined(POSIXALIGNEDALLOC)
|
#if defined(POSIXALIGNEDALLOC)
|
||||||
free(ptr);
|
free(ptr);
|
||||||
#elif defined(_WIN32)
|
#elif defined(_WIN32) && !defined(_M_ARM) && !defined(_M_ARM64)
|
||||||
_mm_free(ptr);
|
_mm_free(ptr);
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
_aligned_free(ptr);
|
||||||
#else
|
#else
|
||||||
free(ptr);
|
free(ptr);
|
||||||
#endif
|
#endif
|
||||||
@@ -376,10 +475,9 @@ void std_aligned_free(void* ptr) {
|
|||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
|
|
||||||
static void* aligned_large_pages_alloc_windows(size_t allocSize) {
|
static void* aligned_large_pages_alloc_windows([[maybe_unused]] size_t allocSize) {
|
||||||
|
|
||||||
#if !defined(_WIN64)
|
#if !defined(_WIN64)
|
||||||
(void)allocSize; // suppress unused-parameter compiler warning
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
#else
|
#else
|
||||||
|
|
||||||
@@ -391,11 +489,30 @@ static void* aligned_large_pages_alloc_windows(size_t allocSize) {
|
|||||||
if (!largePageSize)
|
if (!largePageSize)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
// We need SeLockMemoryPrivilege, so try to enable it for the process
|
// Dynamically link OpenProcessToken, LookupPrivilegeValue and AdjustTokenPrivileges
|
||||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hProcessToken))
|
|
||||||
|
HMODULE hAdvapi32 = GetModuleHandle(TEXT("advapi32.dll"));
|
||||||
|
|
||||||
|
if (!hAdvapi32)
|
||||||
|
hAdvapi32 = LoadLibrary(TEXT("advapi32.dll"));
|
||||||
|
|
||||||
|
auto fun6 = (fun6_t)(void(*)())GetProcAddress(hAdvapi32, "OpenProcessToken");
|
||||||
|
if (!fun6)
|
||||||
|
return nullptr;
|
||||||
|
auto fun7 = (fun7_t)(void(*)())GetProcAddress(hAdvapi32, "LookupPrivilegeValueA");
|
||||||
|
if (!fun7)
|
||||||
|
return nullptr;
|
||||||
|
auto fun8 = (fun8_t)(void(*)())GetProcAddress(hAdvapi32, "AdjustTokenPrivileges");
|
||||||
|
if (!fun8)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if (LookupPrivilegeValue(NULL, SE_LOCK_MEMORY_NAME, &luid))
|
// We need SeLockMemoryPrivilege, so try to enable it for the process
|
||||||
|
if (!fun6( // OpenProcessToken()
|
||||||
|
GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hProcessToken))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
if (fun7( // LookupPrivilegeValue(nullptr, SE_LOCK_MEMORY_NAME, &luid)
|
||||||
|
nullptr, "SeLockMemoryPrivilege", &luid))
|
||||||
{
|
{
|
||||||
TOKEN_PRIVILEGES tp { };
|
TOKEN_PRIVILEGES tp { };
|
||||||
TOKEN_PRIVILEGES prevTp { };
|
TOKEN_PRIVILEGES prevTp { };
|
||||||
@@ -407,17 +524,18 @@ static void* aligned_large_pages_alloc_windows(size_t allocSize) {
|
|||||||
|
|
||||||
// Try to enable SeLockMemoryPrivilege. Note that even if AdjustTokenPrivileges() succeeds,
|
// Try to enable SeLockMemoryPrivilege. Note that even if AdjustTokenPrivileges() succeeds,
|
||||||
// we still need to query GetLastError() to ensure that the privileges were actually obtained.
|
// we still need to query GetLastError() to ensure that the privileges were actually obtained.
|
||||||
if (AdjustTokenPrivileges(
|
if (fun8( // AdjustTokenPrivileges()
|
||||||
hProcessToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), &prevTp, &prevTpLen) &&
|
hProcessToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), &prevTp, &prevTpLen) &&
|
||||||
GetLastError() == ERROR_SUCCESS)
|
GetLastError() == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
// Round up size to full pages and allocate
|
// Round up size to full pages and allocate
|
||||||
allocSize = (allocSize + largePageSize - 1) & ~size_t(largePageSize - 1);
|
allocSize = (allocSize + largePageSize - 1) & ~size_t(largePageSize - 1);
|
||||||
mem = VirtualAlloc(
|
mem = VirtualAlloc(
|
||||||
NULL, allocSize, MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE);
|
nullptr, allocSize, MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE);
|
||||||
|
|
||||||
// Privilege no longer needed, restore previous state
|
// Privilege no longer needed, restore previous state
|
||||||
AdjustTokenPrivileges(hProcessToken, FALSE, &prevTp, 0, NULL, NULL);
|
fun8( // AdjustTokenPrivileges ()
|
||||||
|
hProcessToken, FALSE, &prevTp, 0, nullptr, nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -435,7 +553,7 @@ void* aligned_large_pages_alloc(size_t allocSize) {
|
|||||||
|
|
||||||
// Fall back to regular, page aligned, allocation if necessary
|
// Fall back to regular, page aligned, allocation if necessary
|
||||||
if (!mem)
|
if (!mem)
|
||||||
mem = VirtualAlloc(NULL, allocSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
mem = VirtualAlloc(nullptr, allocSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
||||||
|
|
||||||
return mem;
|
return mem;
|
||||||
}
|
}
|
||||||
@@ -495,11 +613,11 @@ void bindThisThread(size_t) {}
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
/// best_group() retrieves logical processor information using Windows specific
|
/// best_node() retrieves logical processor information using Windows specific
|
||||||
/// API and returns the best group id for the thread with index idx. Original
|
/// API and returns the best node id for the thread with index idx. Original
|
||||||
/// code from Texel by Peter Österlund.
|
/// code from Texel by Peter Österlund.
|
||||||
|
|
||||||
int best_group(size_t idx) {
|
static int best_node(size_t idx) {
|
||||||
|
|
||||||
int threads = 0;
|
int threads = 0;
|
||||||
int nodes = 0;
|
int nodes = 0;
|
||||||
@@ -508,12 +626,13 @@ int best_group(size_t idx) {
|
|||||||
DWORD byteOffset = 0;
|
DWORD byteOffset = 0;
|
||||||
|
|
||||||
// Early exit if the needed API is not available at runtime
|
// Early exit if the needed API is not available at runtime
|
||||||
HMODULE k32 = GetModuleHandle("Kernel32.dll");
|
HMODULE k32 = GetModuleHandle(TEXT("Kernel32.dll"));
|
||||||
auto fun1 = (fun1_t)(void(*)())GetProcAddress(k32, "GetLogicalProcessorInformationEx");
|
auto fun1 = (fun1_t)(void(*)())GetProcAddress(k32, "GetLogicalProcessorInformationEx");
|
||||||
if (!fun1)
|
if (!fun1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
// First call to get returnLength. We expect it to fail due to null buffer
|
// First call to GetLogicalProcessorInformationEx() to get returnLength.
|
||||||
|
// We expect the call to fail due to null buffer.
|
||||||
if (fun1(RelationAll, nullptr, &returnLength))
|
if (fun1(RelationAll, nullptr, &returnLength))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@@ -521,7 +640,7 @@ int best_group(size_t idx) {
|
|||||||
SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *buffer, *ptr;
|
SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *buffer, *ptr;
|
||||||
ptr = buffer = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)malloc(returnLength);
|
ptr = buffer = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)malloc(returnLength);
|
||||||
|
|
||||||
// Second call, now we expect to succeed
|
// Second call to GetLogicalProcessorInformationEx(), now we expect to succeed
|
||||||
if (!fun1(RelationAll, buffer, &returnLength))
|
if (!fun1(RelationAll, buffer, &returnLength))
|
||||||
{
|
{
|
||||||
free(buffer);
|
free(buffer);
|
||||||
@@ -571,22 +690,38 @@ int best_group(size_t idx) {
|
|||||||
void bindThisThread(size_t idx) {
|
void bindThisThread(size_t idx) {
|
||||||
|
|
||||||
// Use only local variables to be thread-safe
|
// Use only local variables to be thread-safe
|
||||||
int group = best_group(idx);
|
int node = best_node(idx);
|
||||||
|
|
||||||
if (group == -1)
|
if (node == -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Early exit if the needed API are not available at runtime
|
// Early exit if the needed API are not available at runtime
|
||||||
HMODULE k32 = GetModuleHandle("Kernel32.dll");
|
HMODULE k32 = GetModuleHandle(TEXT("Kernel32.dll"));
|
||||||
auto fun2 = (fun2_t)(void(*)())GetProcAddress(k32, "GetNumaNodeProcessorMaskEx");
|
auto fun2 = (fun2_t)(void(*)())GetProcAddress(k32, "GetNumaNodeProcessorMaskEx");
|
||||||
auto fun3 = (fun3_t)(void(*)())GetProcAddress(k32, "SetThreadGroupAffinity");
|
auto fun3 = (fun3_t)(void(*)())GetProcAddress(k32, "SetThreadGroupAffinity");
|
||||||
|
auto fun4 = (fun4_t)(void(*)())GetProcAddress(k32, "GetNumaNodeProcessorMask2");
|
||||||
|
auto fun5 = (fun5_t)(void(*)())GetProcAddress(k32, "GetMaximumProcessorGroupCount");
|
||||||
|
|
||||||
if (!fun2 || !fun3)
|
if (!fun2 || !fun3)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!fun4 || !fun5)
|
||||||
|
{
|
||||||
GROUP_AFFINITY affinity;
|
GROUP_AFFINITY affinity;
|
||||||
if (fun2(group, &affinity))
|
if (fun2(node, &affinity)) // GetNumaNodeProcessorMaskEx
|
||||||
fun3(GetCurrentThread(), &affinity, nullptr);
|
fun3(GetCurrentThread(), &affinity, nullptr); // SetThreadGroupAffinity
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If a numa node has more than one processor group, we assume they are
|
||||||
|
// sized equal and we spread threads evenly across the groups.
|
||||||
|
USHORT elements, returnedElements;
|
||||||
|
elements = fun5(); // GetMaximumProcessorGroupCount
|
||||||
|
GROUP_AFFINITY *affinity = (GROUP_AFFINITY*)malloc(elements * sizeof(GROUP_AFFINITY));
|
||||||
|
if (fun4(node, affinity, elements, &returnedElements)) // GetNumaNodeProcessorMask2
|
||||||
|
fun3(GetCurrentThread(), &affinity[idx % returnedElements], nullptr); // SetThreadGroupAffinity
|
||||||
|
free(affinity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -607,8 +742,7 @@ string argv0; // path+name of the executable binary, as given by argv
|
|||||||
string binaryDirectory; // path of the executable directory
|
string binaryDirectory; // path of the executable directory
|
||||||
string workingDirectory; // path of the working directory
|
string workingDirectory; // path of the working directory
|
||||||
|
|
||||||
void init(int argc, char* argv[]) {
|
void init([[maybe_unused]] int argc, char* argv[]) {
|
||||||
(void)argc;
|
|
||||||
string pathSeparator;
|
string pathSeparator;
|
||||||
|
|
||||||
// extract the path+name of the executable binary
|
// extract the path+name of the executable binary
|
||||||
|
|||||||
+11
-45
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -28,6 +28,9 @@
|
|||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
|
#define stringify2(x) #x
|
||||||
|
#define stringify(x) stringify2(x)
|
||||||
|
|
||||||
namespace Stockfish {
|
namespace Stockfish {
|
||||||
|
|
||||||
std::string engine_info(bool to_uci = false);
|
std::string engine_info(bool to_uci = false);
|
||||||
@@ -39,12 +42,13 @@ void std_aligned_free(void* ptr);
|
|||||||
void* aligned_large_pages_alloc(size_t size); // memory aligned by page size, min alignment: 4096 bytes
|
void* aligned_large_pages_alloc(size_t size); // memory aligned by page size, min alignment: 4096 bytes
|
||||||
void aligned_large_pages_free(void* mem); // nop if mem == nullptr
|
void aligned_large_pages_free(void* mem); // nop if mem == nullptr
|
||||||
|
|
||||||
void dbg_hit_on(bool b);
|
void dbg_hit_on(bool cond, int slot = 0);
|
||||||
void dbg_hit_on(bool c, bool b);
|
void dbg_mean_of(int64_t value, int slot = 0);
|
||||||
void dbg_mean_of(int v);
|
void dbg_stdev_of(int64_t value, int slot = 0);
|
||||||
|
void dbg_correl_of(int64_t value1, int64_t value2, int slot = 0);
|
||||||
void dbg_print();
|
void dbg_print();
|
||||||
|
|
||||||
typedef std::chrono::milliseconds::rep TimePoint; // A value in milliseconds
|
using TimePoint = std::chrono::milliseconds::rep; // A value in milliseconds
|
||||||
static_assert(sizeof(TimePoint) == sizeof(int64_t), "TimePoint should be 64 bits");
|
static_assert(sizeof(TimePoint) == sizeof(int64_t), "TimePoint should be 64 bits");
|
||||||
inline TimePoint now() {
|
inline TimePoint now() {
|
||||||
return std::chrono::duration_cast<std::chrono::milliseconds>
|
return std::chrono::duration_cast<std::chrono::milliseconds>
|
||||||
@@ -85,59 +89,21 @@ static inline const union { uint32_t i; char c[4]; } Le = { 0x01020304 };
|
|||||||
static inline const bool IsLittleEndian = (Le.c[0] == 4);
|
static inline const bool IsLittleEndian = (Le.c[0] == 4);
|
||||||
|
|
||||||
|
|
||||||
// RunningAverage : a class to calculate a running average of a series of values.
|
|
||||||
// For efficiency, all computations are done with integers.
|
|
||||||
class RunningAverage {
|
|
||||||
public:
|
|
||||||
|
|
||||||
// Constructor
|
|
||||||
RunningAverage() {}
|
|
||||||
|
|
||||||
// Reset the running average to rational value p / q
|
|
||||||
void set(int64_t p, int64_t q)
|
|
||||||
{ average = p * PERIOD * RESOLUTION / q; }
|
|
||||||
|
|
||||||
// Update average with value v
|
|
||||||
void update(int64_t v)
|
|
||||||
{ average = RESOLUTION * v + (PERIOD - 1) * average / PERIOD; }
|
|
||||||
|
|
||||||
// Test if average is strictly greater than rational a / b
|
|
||||||
bool is_greater(int64_t a, int64_t b)
|
|
||||||
{ return b * average > a * PERIOD * RESOLUTION ; }
|
|
||||||
|
|
||||||
private :
|
|
||||||
static constexpr int64_t PERIOD = 4096;
|
|
||||||
static constexpr int64_t RESOLUTION = 1024;
|
|
||||||
int64_t average;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T, std::size_t MaxSize>
|
template <typename T, std::size_t MaxSize>
|
||||||
class ValueList {
|
class ValueList {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::size_t size() const { return size_; }
|
std::size_t size() const { return size_; }
|
||||||
void resize(std::size_t newSize) { size_ = newSize; }
|
|
||||||
void push_back(const T& value) { values_[size_++] = value; }
|
void push_back(const T& value) { values_[size_++] = value; }
|
||||||
T& operator[](std::size_t index) { return values_[index]; }
|
|
||||||
T* begin() { return values_; }
|
|
||||||
T* end() { return values_ + size_; }
|
|
||||||
const T& operator[](std::size_t index) const { return values_[index]; }
|
|
||||||
const T* begin() const { return values_; }
|
const T* begin() const { return values_; }
|
||||||
const T* end() const { return values_ + size_; }
|
const T* end() const { return values_ + size_; }
|
||||||
|
|
||||||
void swap(ValueList& other) {
|
|
||||||
const std::size_t maxSize = std::max(size_, other.size_);
|
|
||||||
for (std::size_t i = 0; i < maxSize; ++i) {
|
|
||||||
std::swap(values_[i], other.values_[i]);
|
|
||||||
}
|
|
||||||
std::swap(size_, other.size_);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T values_[MaxSize];
|
T values_[MaxSize];
|
||||||
std::size_t size_ = 0;
|
std::size_t size_ = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/// xorshift64star Pseudo-Random Number Generator
|
/// xorshift64star Pseudo-Random Number Generator
|
||||||
/// This class is based on original code written and dedicated
|
/// This class is based on original code written and dedicated
|
||||||
/// to the public domain by Sebastiano Vigna (2014).
|
/// to the public domain by Sebastiano Vigna (2014).
|
||||||
@@ -176,7 +142,7 @@ public:
|
|||||||
|
|
||||||
inline uint64_t mul_hi64(uint64_t a, uint64_t b) {
|
inline uint64_t mul_hi64(uint64_t a, uint64_t b) {
|
||||||
#if defined(__GNUC__) && defined(IS_64BIT)
|
#if defined(__GNUC__) && defined(IS_64BIT)
|
||||||
__extension__ typedef unsigned __int128 uint128;
|
__extension__ using uint128 = unsigned __int128;
|
||||||
return ((uint128)a * (uint128)b) >> 64;
|
return ((uint128)a * (uint128)b) >> 64;
|
||||||
#else
|
#else
|
||||||
uint64_t aL = (uint32_t)a, aH = a >> 32;
|
uint64_t aL = (uint32_t)a, aH = a >> 32;
|
||||||
|
|||||||
+22
-14
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -25,13 +25,21 @@ namespace Stockfish {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
template<GenType Type, Direction D>
|
template<GenType Type, Direction D, bool Enemy>
|
||||||
ExtMove* make_promotions(ExtMove* moveList, Square to) {
|
ExtMove* make_promotions(ExtMove* moveList, [[maybe_unused]] Square to) {
|
||||||
|
|
||||||
if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
|
if constexpr (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
|
||||||
|
{
|
||||||
*moveList++ = make<PROMOTION>(to - D, to, QUEEN);
|
*moveList++ = make<PROMOTION>(to - D, to, QUEEN);
|
||||||
|
if constexpr (Enemy && Type == CAPTURES)
|
||||||
|
{
|
||||||
|
*moveList++ = make<PROMOTION>(to - D, to, ROOK);
|
||||||
|
*moveList++ = make<PROMOTION>(to - D, to, BISHOP);
|
||||||
|
*moveList++ = make<PROMOTION>(to - D, to, KNIGHT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (Type == QUIETS || Type == EVASIONS || Type == NON_EVASIONS)
|
if constexpr ((Type == QUIETS && !Enemy) || Type == EVASIONS || Type == NON_EVASIONS)
|
||||||
{
|
{
|
||||||
*moveList++ = make<PROMOTION>(to - D, to, ROOK);
|
*moveList++ = make<PROMOTION>(to - D, to, ROOK);
|
||||||
*moveList++ = make<PROMOTION>(to - D, to, BISHOP);
|
*moveList++ = make<PROMOTION>(to - D, to, BISHOP);
|
||||||
@@ -60,18 +68,18 @@ namespace {
|
|||||||
Bitboard pawnsNotOn7 = pos.pieces(Us, PAWN) & ~TRank7BB;
|
Bitboard pawnsNotOn7 = pos.pieces(Us, PAWN) & ~TRank7BB;
|
||||||
|
|
||||||
// Single and double pawn pushes, no promotions
|
// Single and double pawn pushes, no promotions
|
||||||
if (Type != CAPTURES)
|
if constexpr (Type != CAPTURES)
|
||||||
{
|
{
|
||||||
Bitboard b1 = shift<Up>(pawnsNotOn7) & emptySquares;
|
Bitboard b1 = shift<Up>(pawnsNotOn7) & emptySquares;
|
||||||
Bitboard b2 = shift<Up>(b1 & TRank3BB) & emptySquares;
|
Bitboard b2 = shift<Up>(b1 & TRank3BB) & emptySquares;
|
||||||
|
|
||||||
if (Type == EVASIONS) // Consider only blocking squares
|
if constexpr (Type == EVASIONS) // Consider only blocking squares
|
||||||
{
|
{
|
||||||
b1 &= target;
|
b1 &= target;
|
||||||
b2 &= target;
|
b2 &= target;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Type == QUIET_CHECKS)
|
if constexpr (Type == QUIET_CHECKS)
|
||||||
{
|
{
|
||||||
// To make a quiet check, you either make a direct check by pushing a pawn
|
// To make a quiet check, you either make a direct check by pushing a pawn
|
||||||
// or push a blocker pawn that is not on the same file as the enemy king.
|
// or push a blocker pawn that is not on the same file as the enemy king.
|
||||||
@@ -102,21 +110,21 @@ namespace {
|
|||||||
Bitboard b2 = shift<UpLeft >(pawnsOn7) & enemies;
|
Bitboard b2 = shift<UpLeft >(pawnsOn7) & enemies;
|
||||||
Bitboard b3 = shift<Up >(pawnsOn7) & emptySquares;
|
Bitboard b3 = shift<Up >(pawnsOn7) & emptySquares;
|
||||||
|
|
||||||
if (Type == EVASIONS)
|
if constexpr (Type == EVASIONS)
|
||||||
b3 &= target;
|
b3 &= target;
|
||||||
|
|
||||||
while (b1)
|
while (b1)
|
||||||
moveList = make_promotions<Type, UpRight>(moveList, pop_lsb(b1));
|
moveList = make_promotions<Type, UpRight, true>(moveList, pop_lsb(b1));
|
||||||
|
|
||||||
while (b2)
|
while (b2)
|
||||||
moveList = make_promotions<Type, UpLeft >(moveList, pop_lsb(b2));
|
moveList = make_promotions<Type, UpLeft, true>(moveList, pop_lsb(b2));
|
||||||
|
|
||||||
while (b3)
|
while (b3)
|
||||||
moveList = make_promotions<Type, Up >(moveList, pop_lsb(b3));
|
moveList = make_promotions<Type, Up, false>(moveList, pop_lsb(b3));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Standard and en passant captures
|
// Standard and en passant captures
|
||||||
if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
|
if constexpr (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
|
||||||
{
|
{
|
||||||
Bitboard b1 = shift<UpRight>(pawnsNotOn7) & enemies;
|
Bitboard b1 = shift<UpRight>(pawnsNotOn7) & enemies;
|
||||||
Bitboard b2 = shift<UpLeft >(pawnsNotOn7) & enemies;
|
Bitboard b2 = shift<UpLeft >(pawnsNotOn7) & enemies;
|
||||||
@@ -264,7 +272,7 @@ ExtMove* generate<LEGAL>(const Position& pos, ExtMove* moveList) {
|
|||||||
moveList = pos.checkers() ? generate<EVASIONS >(pos, moveList)
|
moveList = pos.checkers() ? generate<EVASIONS >(pos, moveList)
|
||||||
: generate<NON_EVASIONS>(pos, moveList);
|
: generate<NON_EVASIONS>(pos, moveList);
|
||||||
while (cur != moveList)
|
while (cur != moveList)
|
||||||
if ( ((pinned && pinned & from_sq(*cur)) || from_sq(*cur) == ksq || type_of(*cur) == EN_PASSANT)
|
if ( ((pinned & from_sq(*cur)) || from_sq(*cur) == ksq || type_of(*cur) == EN_PASSANT)
|
||||||
&& !pos.legal(*cur))
|
&& !pos.legal(*cur))
|
||||||
*cur = (--moveList)->move;
|
*cur = (--moveList)->move;
|
||||||
else
|
else
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
+55
-29
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "bitboard.h"
|
||||||
#include "movepick.h"
|
#include "movepick.h"
|
||||||
|
|
||||||
namespace Stockfish {
|
namespace Stockfish {
|
||||||
@@ -56,11 +57,14 @@ namespace {
|
|||||||
/// ordering is at the current node.
|
/// ordering is at the current node.
|
||||||
|
|
||||||
/// MovePicker constructor for the main search
|
/// MovePicker constructor for the main search
|
||||||
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, const LowPlyHistory* lp,
|
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh,
|
||||||
const CapturePieceToHistory* cph, const PieceToHistory** ch, Move cm, const Move* killers, int pl)
|
const CapturePieceToHistory* cph,
|
||||||
: pos(p), mainHistory(mh), lowPlyHistory(lp), captureHistory(cph), continuationHistory(ch),
|
const PieceToHistory** ch,
|
||||||
ttMove(ttm), refutations{{killers[0], 0}, {killers[1], 0}, {cm, 0}}, depth(d), ply(pl) {
|
Move cm,
|
||||||
|
const Move* killers)
|
||||||
|
: pos(p), mainHistory(mh), captureHistory(cph), continuationHistory(ch),
|
||||||
|
ttMove(ttm), refutations{{killers[0], 0}, {killers[1], 0}, {cm, 0}}, depth(d)
|
||||||
|
{
|
||||||
assert(d > 0);
|
assert(d > 0);
|
||||||
|
|
||||||
stage = (pos.checkers() ? EVASION_TT : MAIN_TT) +
|
stage = (pos.checkers() ? EVASION_TT : MAIN_TT) +
|
||||||
@@ -69,59 +73,80 @@ MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHist
|
|||||||
|
|
||||||
/// MovePicker constructor for quiescence search
|
/// MovePicker constructor for quiescence search
|
||||||
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh,
|
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh,
|
||||||
const CapturePieceToHistory* cph, const PieceToHistory** ch, Square rs)
|
const CapturePieceToHistory* cph,
|
||||||
: pos(p), mainHistory(mh), captureHistory(cph), continuationHistory(ch), ttMove(ttm), recaptureSquare(rs), depth(d) {
|
const PieceToHistory** ch,
|
||||||
|
Square rs)
|
||||||
|
: pos(p), mainHistory(mh), captureHistory(cph), continuationHistory(ch), ttMove(ttm), recaptureSquare(rs), depth(d)
|
||||||
|
{
|
||||||
assert(d <= 0);
|
assert(d <= 0);
|
||||||
|
|
||||||
stage = (pos.checkers() ? EVASION_TT : QSEARCH_TT) +
|
stage = (pos.checkers() ? EVASION_TT : QSEARCH_TT) +
|
||||||
!( ttm
|
!( ttm
|
||||||
&& (pos.checkers() || depth > DEPTH_QS_RECAPTURES || to_sq(ttm) == recaptureSquare)
|
|
||||||
&& pos.pseudo_legal(ttm));
|
&& pos.pseudo_legal(ttm));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// MovePicker constructor for ProbCut: we generate captures with SEE greater
|
/// MovePicker constructor for ProbCut: we generate captures with SEE greater
|
||||||
/// than or equal to the given threshold.
|
/// than or equal to the given threshold.
|
||||||
MovePicker::MovePicker(const Position& p, Move ttm, Value th, const CapturePieceToHistory* cph)
|
MovePicker::MovePicker(const Position& p, Move ttm, Value th, const CapturePieceToHistory* cph)
|
||||||
: pos(p), captureHistory(cph), ttMove(ttm), threshold(th) {
|
: pos(p), captureHistory(cph), ttMove(ttm), threshold(th)
|
||||||
|
{
|
||||||
assert(!pos.checkers());
|
assert(!pos.checkers());
|
||||||
|
|
||||||
stage = PROBCUT_TT + !(ttm && pos.capture(ttm)
|
stage = PROBCUT_TT + !(ttm && pos.capture_stage(ttm)
|
||||||
&& pos.pseudo_legal(ttm)
|
&& pos.pseudo_legal(ttm)
|
||||||
&& pos.see_ge(ttm, threshold));
|
&& pos.see_ge(ttm, threshold));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// MovePicker::score() assigns a numerical value to each move in a list, used
|
/// MovePicker::score() assigns a numerical value to each move in a list, used
|
||||||
/// for sorting. Captures are ordered by Most Valuable Victim (MVV), preferring
|
/// for sorting. Captures are ordered by Most Valuable Victim (MVV), preferring
|
||||||
/// captures with a good history. Quiets moves are ordered using the histories.
|
/// captures with a good history. Quiets moves are ordered using the history tables.
|
||||||
template<GenType Type>
|
template<GenType Type>
|
||||||
void MovePicker::score() {
|
void MovePicker::score() {
|
||||||
|
|
||||||
static_assert(Type == CAPTURES || Type == QUIETS || Type == EVASIONS, "Wrong type");
|
static_assert(Type == CAPTURES || Type == QUIETS || Type == EVASIONS, "Wrong type");
|
||||||
|
|
||||||
|
[[maybe_unused]] Bitboard threatenedByPawn, threatenedByMinor, threatenedByRook, threatenedPieces;
|
||||||
|
if constexpr (Type == QUIETS)
|
||||||
|
{
|
||||||
|
Color us = pos.side_to_move();
|
||||||
|
|
||||||
|
threatenedByPawn = pos.attacks_by<PAWN>(~us);
|
||||||
|
threatenedByMinor = pos.attacks_by<KNIGHT>(~us) | pos.attacks_by<BISHOP>(~us) | threatenedByPawn;
|
||||||
|
threatenedByRook = pos.attacks_by<ROOK>(~us) | threatenedByMinor;
|
||||||
|
|
||||||
|
// Pieces threatened by pieces of lesser material value
|
||||||
|
threatenedPieces = (pos.pieces(us, QUEEN) & threatenedByRook)
|
||||||
|
| (pos.pieces(us, ROOK) & threatenedByMinor)
|
||||||
|
| (pos.pieces(us, KNIGHT, BISHOP) & threatenedByPawn);
|
||||||
|
}
|
||||||
|
|
||||||
for (auto& m : *this)
|
for (auto& m : *this)
|
||||||
if constexpr (Type == CAPTURES)
|
if constexpr (Type == CAPTURES)
|
||||||
m.value = int(PieceValue[MG][pos.piece_on(to_sq(m))]) * 6
|
m.value = (7 * int(PieceValue[MG][pos.piece_on(to_sq(m))])
|
||||||
+ (*captureHistory)[pos.moved_piece(m)][to_sq(m)][type_of(pos.piece_on(to_sq(m)))];
|
+ (*captureHistory)[pos.moved_piece(m)][to_sq(m)][type_of(pos.piece_on(to_sq(m)))]) / 16;
|
||||||
|
|
||||||
else if constexpr (Type == QUIETS)
|
else if constexpr (Type == QUIETS)
|
||||||
m.value = (*mainHistory)[pos.side_to_move()][from_to(m)]
|
m.value = 2 * (*mainHistory)[pos.side_to_move()][from_to(m)]
|
||||||
+ 2 * (*continuationHistory[0])[pos.moved_piece(m)][to_sq(m)]
|
+ 2 * (*continuationHistory[0])[pos.moved_piece(m)][to_sq(m)]
|
||||||
+ (*continuationHistory[1])[pos.moved_piece(m)][to_sq(m)]
|
+ (*continuationHistory[1])[pos.moved_piece(m)][to_sq(m)]
|
||||||
+ (*continuationHistory[3])[pos.moved_piece(m)][to_sq(m)]
|
+ (*continuationHistory[3])[pos.moved_piece(m)][to_sq(m)]
|
||||||
+ (*continuationHistory[5])[pos.moved_piece(m)][to_sq(m)]
|
+ (*continuationHistory[5])[pos.moved_piece(m)][to_sq(m)]
|
||||||
+ (ply < MAX_LPH ? 6 * (*lowPlyHistory)[ply][from_to(m)] : 0);
|
+ (threatenedPieces & from_sq(m) ?
|
||||||
|
(type_of(pos.moved_piece(m)) == QUEEN && !(to_sq(m) & threatenedByRook) ? 50000
|
||||||
|
: type_of(pos.moved_piece(m)) == ROOK && !(to_sq(m) & threatenedByMinor) ? 25000
|
||||||
|
: !(to_sq(m) & threatenedByPawn) ? 15000
|
||||||
|
: 0)
|
||||||
|
: 0)
|
||||||
|
+ bool(pos.check_squares(type_of(pos.moved_piece(m))) & to_sq(m)) * 16384;
|
||||||
else // Type == EVASIONS
|
else // Type == EVASIONS
|
||||||
{
|
{
|
||||||
if (pos.capture(m))
|
if (pos.capture_stage(m))
|
||||||
m.value = PieceValue[MG][pos.piece_on(to_sq(m))]
|
m.value = PieceValue[MG][pos.piece_on(to_sq(m))]
|
||||||
- Value(type_of(pos.moved_piece(m)));
|
- Value(type_of(pos.moved_piece(m)))
|
||||||
|
+ (1 << 28);
|
||||||
else
|
else
|
||||||
m.value = (*mainHistory)[pos.side_to_move()][from_to(m)]
|
m.value = (*mainHistory)[pos.side_to_move()][from_to(m)]
|
||||||
+ 2 * (*continuationHistory[0])[pos.moved_piece(m)][to_sq(m)]
|
+ (*continuationHistory[0])[pos.moved_piece(m)][to_sq(m)];
|
||||||
- (1 << 28);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,7 +157,7 @@ Move MovePicker::select(Pred filter) {
|
|||||||
|
|
||||||
while (cur < endMoves)
|
while (cur < endMoves)
|
||||||
{
|
{
|
||||||
if (T == Best)
|
if constexpr (T == Best)
|
||||||
std::swap(*cur, *std::max_element(cur, endMoves));
|
std::swap(*cur, *std::max_element(cur, endMoves));
|
||||||
|
|
||||||
if (*cur != ttMove && filter())
|
if (*cur != ttMove && filter())
|
||||||
@@ -165,12 +190,13 @@ top:
|
|||||||
endMoves = generate<CAPTURES>(pos, cur);
|
endMoves = generate<CAPTURES>(pos, cur);
|
||||||
|
|
||||||
score<CAPTURES>();
|
score<CAPTURES>();
|
||||||
|
partial_insertion_sort(cur, endMoves, std::numeric_limits<int>::min());
|
||||||
++stage;
|
++stage;
|
||||||
goto top;
|
goto top;
|
||||||
|
|
||||||
case GOOD_CAPTURE:
|
case GOOD_CAPTURE:
|
||||||
if (select<Best>([&](){
|
if (select<Next>([&](){
|
||||||
return pos.see_ge(*cur, Value(-69 * cur->value / 1024)) ?
|
return pos.see_ge(*cur, Value(-cur->value)) ?
|
||||||
// Move losing capture to endBadCaptures to be tried later
|
// Move losing capture to endBadCaptures to be tried later
|
||||||
true : (*endBadCaptures++ = *cur, false); }))
|
true : (*endBadCaptures++ = *cur, false); }))
|
||||||
return *(cur - 1);
|
return *(cur - 1);
|
||||||
@@ -189,7 +215,7 @@ top:
|
|||||||
|
|
||||||
case REFUTATION:
|
case REFUTATION:
|
||||||
if (select<Next>([&](){ return *cur != MOVE_NONE
|
if (select<Next>([&](){ return *cur != MOVE_NONE
|
||||||
&& !pos.capture(*cur)
|
&& !pos.capture_stage(*cur)
|
||||||
&& pos.pseudo_legal(*cur); }))
|
&& pos.pseudo_legal(*cur); }))
|
||||||
return *(cur - 1);
|
return *(cur - 1);
|
||||||
++stage;
|
++stage;
|
||||||
@@ -237,10 +263,10 @@ top:
|
|||||||
return select<Best>([](){ return true; });
|
return select<Best>([](){ return true; });
|
||||||
|
|
||||||
case PROBCUT:
|
case PROBCUT:
|
||||||
return select<Best>([&](){ return pos.see_ge(*cur, threshold); });
|
return select<Next>([&](){ return pos.see_ge(*cur, threshold); });
|
||||||
|
|
||||||
case QCAPTURE:
|
case QCAPTURE:
|
||||||
if (select<Best>([&](){ return depth > DEPTH_QS_RECAPTURES
|
if (select<Next>([&](){ return depth > DEPTH_QS_RECAPTURES
|
||||||
|| to_sq(*cur) == recaptureSquare; }))
|
|| to_sq(*cur) == recaptureSquare; }))
|
||||||
return *(cur - 1);
|
return *(cur - 1);
|
||||||
|
|
||||||
|
|||||||
+16
-24
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -62,14 +62,14 @@ public:
|
|||||||
template <typename T, int D, int Size, int... Sizes>
|
template <typename T, int D, int Size, int... Sizes>
|
||||||
struct Stats : public std::array<Stats<T, D, Sizes...>, Size>
|
struct Stats : public std::array<Stats<T, D, Sizes...>, Size>
|
||||||
{
|
{
|
||||||
typedef Stats<T, D, Size, Sizes...> stats;
|
using stats = Stats<T, D, Size, Sizes...>;
|
||||||
|
|
||||||
void fill(const T& v) {
|
void fill(const T& v) {
|
||||||
|
|
||||||
// For standard-layout 'this' points to first struct member
|
// For standard-layout 'this' points to first struct member
|
||||||
assert(std::is_standard_layout<stats>::value);
|
assert(std::is_standard_layout<stats>::value);
|
||||||
|
|
||||||
typedef StatsEntry<T, D> entry;
|
using entry = StatsEntry<T, D>;
|
||||||
entry* p = reinterpret_cast<entry*>(this);
|
entry* p = reinterpret_cast<entry*>(this);
|
||||||
std::fill(p, p + sizeof(*this) / sizeof(entry), v);
|
std::fill(p, p + sizeof(*this) / sizeof(entry), v);
|
||||||
}
|
}
|
||||||
@@ -86,28 +86,24 @@ enum StatsType { NoCaptures, Captures };
|
|||||||
/// unsuccessful during the current search, and is used for reduction and move
|
/// unsuccessful during the current search, and is used for reduction and move
|
||||||
/// ordering decisions. It uses 2 tables (one for each color) indexed by
|
/// ordering decisions. It uses 2 tables (one for each color) indexed by
|
||||||
/// the move's from and to squares, see www.chessprogramming.org/Butterfly_Boards
|
/// the move's from and to squares, see www.chessprogramming.org/Butterfly_Boards
|
||||||
typedef Stats<int16_t, 14365, COLOR_NB, int(SQUARE_NB) * int(SQUARE_NB)> ButterflyHistory;
|
/// (~11 elo)
|
||||||
|
using ButterflyHistory = Stats<int16_t, 7183, COLOR_NB, int(SQUARE_NB) * int(SQUARE_NB)>;
|
||||||
/// At higher depths LowPlyHistory records successful quiet moves near the root
|
|
||||||
/// and quiet moves which are/were in the PV (ttPv). LowPlyHistory is populated during
|
|
||||||
/// iterative deepening and at each new search the data is shifted down by 2 plies
|
|
||||||
constexpr int MAX_LPH = 4;
|
|
||||||
typedef Stats<int16_t, 10692, MAX_LPH, int(SQUARE_NB) * int(SQUARE_NB)> LowPlyHistory;
|
|
||||||
|
|
||||||
/// CounterMoveHistory stores counter moves indexed by [piece][to] of the previous
|
/// CounterMoveHistory stores counter moves indexed by [piece][to] of the previous
|
||||||
/// move, see www.chessprogramming.org/Countermove_Heuristic
|
/// move, see www.chessprogramming.org/Countermove_Heuristic
|
||||||
typedef Stats<Move, NOT_USED, PIECE_NB, SQUARE_NB> CounterMoveHistory;
|
using CounterMoveHistory = Stats<Move, NOT_USED, PIECE_NB, SQUARE_NB>;
|
||||||
|
|
||||||
/// CapturePieceToHistory is addressed by a move's [piece][to][captured piece type]
|
/// CapturePieceToHistory is addressed by a move's [piece][to][captured piece type]
|
||||||
typedef Stats<int16_t, 10692, PIECE_NB, SQUARE_NB, PIECE_TYPE_NB> CapturePieceToHistory;
|
using CapturePieceToHistory = Stats<int16_t, 10692, PIECE_NB, SQUARE_NB, PIECE_TYPE_NB>;
|
||||||
|
|
||||||
/// PieceToHistory is like ButterflyHistory but is addressed by a move's [piece][to]
|
/// PieceToHistory is like ButterflyHistory but is addressed by a move's [piece][to]
|
||||||
typedef Stats<int16_t, 29952, PIECE_NB, SQUARE_NB> PieceToHistory;
|
using PieceToHistory = Stats<int16_t, 29952, PIECE_NB, SQUARE_NB>;
|
||||||
|
|
||||||
/// ContinuationHistory is the combined history of a given pair of moves, usually
|
/// ContinuationHistory is the combined history of a given pair of moves, usually
|
||||||
/// the current one given a previous one. The nested history table is based on
|
/// the current one given a previous one. The nested history table is based on
|
||||||
/// PieceToHistory instead of ButterflyBoards.
|
/// PieceToHistory instead of ButterflyBoards.
|
||||||
typedef Stats<PieceToHistory, NOT_USED, PIECE_NB, SQUARE_NB> ContinuationHistory;
|
/// (~63 elo)
|
||||||
|
using ContinuationHistory = Stats<PieceToHistory, NOT_USED, PIECE_NB, SQUARE_NB>;
|
||||||
|
|
||||||
|
|
||||||
/// MovePicker class is used to pick one pseudo-legal move at a time from the
|
/// MovePicker class is used to pick one pseudo-legal move at a time from the
|
||||||
@@ -123,18 +119,16 @@ class MovePicker {
|
|||||||
public:
|
public:
|
||||||
MovePicker(const MovePicker&) = delete;
|
MovePicker(const MovePicker&) = delete;
|
||||||
MovePicker& operator=(const MovePicker&) = delete;
|
MovePicker& operator=(const MovePicker&) = delete;
|
||||||
MovePicker(const Position&, Move, Value, const CapturePieceToHistory*);
|
MovePicker(const Position&, Move, Depth, const ButterflyHistory*,
|
||||||
|
const CapturePieceToHistory*,
|
||||||
|
const PieceToHistory**,
|
||||||
|
Move,
|
||||||
|
const Move*);
|
||||||
MovePicker(const Position&, Move, Depth, const ButterflyHistory*,
|
MovePicker(const Position&, Move, Depth, const ButterflyHistory*,
|
||||||
const CapturePieceToHistory*,
|
const CapturePieceToHistory*,
|
||||||
const PieceToHistory**,
|
const PieceToHistory**,
|
||||||
Square);
|
Square);
|
||||||
MovePicker(const Position&, Move, Depth, const ButterflyHistory*,
|
MovePicker(const Position&, Move, Value, const CapturePieceToHistory*);
|
||||||
const LowPlyHistory*,
|
|
||||||
const CapturePieceToHistory*,
|
|
||||||
const PieceToHistory**,
|
|
||||||
Move,
|
|
||||||
const Move*,
|
|
||||||
int);
|
|
||||||
Move next_move(bool skipQuiets = false);
|
Move next_move(bool skipQuiets = false);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -145,7 +139,6 @@ private:
|
|||||||
|
|
||||||
const Position& pos;
|
const Position& pos;
|
||||||
const ButterflyHistory* mainHistory;
|
const ButterflyHistory* mainHistory;
|
||||||
const LowPlyHistory* lowPlyHistory;
|
|
||||||
const CapturePieceToHistory* captureHistory;
|
const CapturePieceToHistory* captureHistory;
|
||||||
const PieceToHistory** continuationHistory;
|
const PieceToHistory** continuationHistory;
|
||||||
Move ttMove;
|
Move ttMove;
|
||||||
@@ -154,7 +147,6 @@ private:
|
|||||||
Square recaptureSquare;
|
Square recaptureSquare;
|
||||||
Value threshold;
|
Value threshold;
|
||||||
Depth depth;
|
Depth depth;
|
||||||
int ply;
|
|
||||||
ExtMove moves[MAX_MOVES];
|
ExtMove moves[MAX_MOVES];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+43
-53
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -18,15 +18,15 @@
|
|||||||
|
|
||||||
// Code for calculating NNUE evaluation function
|
// Code for calculating NNUE evaluation function
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <iomanip>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <iomanip>
|
#include <string_view>
|
||||||
#include <fstream>
|
|
||||||
|
|
||||||
#include "../evaluate.h"
|
#include "../evaluate.h"
|
||||||
#include "../position.h"
|
#include "../position.h"
|
||||||
#include "../misc.h"
|
|
||||||
#include "../uci.h"
|
#include "../uci.h"
|
||||||
#include "../types.h"
|
#include "../types.h"
|
||||||
|
|
||||||
@@ -83,7 +83,7 @@ namespace Stockfish::Eval::NNUE {
|
|||||||
} // namespace Detail
|
} // namespace Detail
|
||||||
|
|
||||||
// Initialize the evaluation function parameters
|
// Initialize the evaluation function parameters
|
||||||
void initialize() {
|
static void initialize() {
|
||||||
|
|
||||||
Detail::initialize(featureTransformer);
|
Detail::initialize(featureTransformer);
|
||||||
for (std::size_t i = 0; i < LayerStacks; ++i)
|
for (std::size_t i = 0; i < LayerStacks; ++i)
|
||||||
@@ -91,7 +91,7 @@ namespace Stockfish::Eval::NNUE {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Read network header
|
// Read network header
|
||||||
bool read_header(std::istream& stream, std::uint32_t* hashValue, std::string* desc)
|
static bool read_header(std::istream& stream, std::uint32_t* hashValue, std::string* desc)
|
||||||
{
|
{
|
||||||
std::uint32_t version, size;
|
std::uint32_t version, size;
|
||||||
|
|
||||||
@@ -105,17 +105,17 @@ namespace Stockfish::Eval::NNUE {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write network header
|
// Write network header
|
||||||
bool write_header(std::ostream& stream, std::uint32_t hashValue, const std::string& desc)
|
static bool write_header(std::ostream& stream, std::uint32_t hashValue, const std::string& desc)
|
||||||
{
|
{
|
||||||
write_little_endian<std::uint32_t>(stream, Version);
|
write_little_endian<std::uint32_t>(stream, Version);
|
||||||
write_little_endian<std::uint32_t>(stream, hashValue);
|
write_little_endian<std::uint32_t>(stream, hashValue);
|
||||||
write_little_endian<std::uint32_t>(stream, desc.size());
|
write_little_endian<std::uint32_t>(stream, (std::uint32_t)desc.size());
|
||||||
stream.write(&desc[0], desc.size());
|
stream.write(&desc[0], desc.size());
|
||||||
return !stream.fail();
|
return !stream.fail();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read network parameters
|
// Read network parameters
|
||||||
bool read_parameters(std::istream& stream) {
|
static bool read_parameters(std::istream& stream) {
|
||||||
|
|
||||||
std::uint32_t hashValue;
|
std::uint32_t hashValue;
|
||||||
if (!read_header(stream, &hashValue, &netDescription)) return false;
|
if (!read_header(stream, &hashValue, &netDescription)) return false;
|
||||||
@@ -127,7 +127,7 @@ namespace Stockfish::Eval::NNUE {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write network parameters
|
// Write network parameters
|
||||||
bool write_parameters(std::ostream& stream) {
|
static bool write_parameters(std::ostream& stream) {
|
||||||
|
|
||||||
if (!write_header(stream, HashValue, netDescription)) return false;
|
if (!write_header(stream, HashValue, netDescription)) return false;
|
||||||
if (!Detail::write_parameters(stream, *featureTransformer)) return false;
|
if (!Detail::write_parameters(stream, *featureTransformer)) return false;
|
||||||
@@ -136,39 +136,42 @@ namespace Stockfish::Eval::NNUE {
|
|||||||
return (bool)stream;
|
return (bool)stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void hint_common_parent_position(const Position& pos) {
|
||||||
|
if (Eval::useNNUE)
|
||||||
|
featureTransformer->hint_common_access(pos);
|
||||||
|
}
|
||||||
|
|
||||||
// Evaluation function. Perform differential calculation.
|
// Evaluation function. Perform differential calculation.
|
||||||
Value evaluate(const Position& pos, bool adjusted) {
|
Value evaluate(const Position& pos, bool adjusted, int* complexity) {
|
||||||
|
|
||||||
// We manually align the arrays on the stack because with gcc < 9.3
|
// We manually align the arrays on the stack because with gcc < 9.3
|
||||||
// overaligning stack variables with alignas() doesn't work correctly.
|
// overaligning stack variables with alignas() doesn't work correctly.
|
||||||
|
|
||||||
constexpr uint64_t alignment = CacheLineSize;
|
constexpr uint64_t alignment = CacheLineSize;
|
||||||
int delta = 7;
|
constexpr int delta = 24;
|
||||||
|
|
||||||
#if defined(ALIGNAS_ON_STACK_VARIABLES_BROKEN)
|
#if defined(ALIGNAS_ON_STACK_VARIABLES_BROKEN)
|
||||||
TransformedFeatureType transformedFeaturesUnaligned[
|
TransformedFeatureType transformedFeaturesUnaligned[
|
||||||
FeatureTransformer::BufferSize + alignment / sizeof(TransformedFeatureType)];
|
FeatureTransformer::BufferSize + alignment / sizeof(TransformedFeatureType)];
|
||||||
char bufferUnaligned[Network::BufferSize + alignment];
|
|
||||||
|
|
||||||
auto* transformedFeatures = align_ptr_up<alignment>(&transformedFeaturesUnaligned[0]);
|
auto* transformedFeatures = align_ptr_up<alignment>(&transformedFeaturesUnaligned[0]);
|
||||||
auto* buffer = align_ptr_up<alignment>(&bufferUnaligned[0]);
|
|
||||||
#else
|
#else
|
||||||
alignas(alignment)
|
alignas(alignment)
|
||||||
TransformedFeatureType transformedFeatures[FeatureTransformer::BufferSize];
|
TransformedFeatureType transformedFeatures[FeatureTransformer::BufferSize];
|
||||||
alignas(alignment) char buffer[Network::BufferSize];
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ASSERT_ALIGNED(transformedFeatures, alignment);
|
ASSERT_ALIGNED(transformedFeatures, alignment);
|
||||||
ASSERT_ALIGNED(buffer, alignment);
|
|
||||||
|
|
||||||
const std::size_t bucket = (pos.count<ALL_PIECES>() - 1) / 4;
|
const int bucket = (pos.count<ALL_PIECES>() - 1) / 4;
|
||||||
const auto psqt = featureTransformer->transform(pos, transformedFeatures, bucket);
|
const auto psqt = featureTransformer->transform(pos, transformedFeatures, bucket);
|
||||||
const auto positional = network[bucket]->propagate(transformedFeatures, buffer)[0];
|
const auto positional = network[bucket]->propagate(transformedFeatures);
|
||||||
|
|
||||||
// Give more value to positional evaluation when material is balanced
|
if (complexity)
|
||||||
if ( adjusted
|
*complexity = abs(psqt - positional) / OutputScale;
|
||||||
&& abs(pos.non_pawn_material(WHITE) - pos.non_pawn_material(BLACK)) <= RookValueMg - BishopValueMg)
|
|
||||||
return static_cast<Value>(((128 - delta) * psqt + (128 + delta) * positional) / 128 / OutputScale);
|
// Give more value to positional evaluation when adjusted flag is set
|
||||||
|
if (adjusted)
|
||||||
|
return static_cast<Value>(((1024 - delta) * psqt + (1024 + delta) * positional) / (1024 * OutputScale));
|
||||||
else
|
else
|
||||||
return static_cast<Value>((psqt + positional) / OutputScale);
|
return static_cast<Value>((psqt + positional) / OutputScale);
|
||||||
}
|
}
|
||||||
@@ -191,27 +194,20 @@ namespace Stockfish::Eval::NNUE {
|
|||||||
#if defined(ALIGNAS_ON_STACK_VARIABLES_BROKEN)
|
#if defined(ALIGNAS_ON_STACK_VARIABLES_BROKEN)
|
||||||
TransformedFeatureType transformedFeaturesUnaligned[
|
TransformedFeatureType transformedFeaturesUnaligned[
|
||||||
FeatureTransformer::BufferSize + alignment / sizeof(TransformedFeatureType)];
|
FeatureTransformer::BufferSize + alignment / sizeof(TransformedFeatureType)];
|
||||||
char bufferUnaligned[Network::BufferSize + alignment];
|
|
||||||
|
|
||||||
auto* transformedFeatures = align_ptr_up<alignment>(&transformedFeaturesUnaligned[0]);
|
auto* transformedFeatures = align_ptr_up<alignment>(&transformedFeaturesUnaligned[0]);
|
||||||
auto* buffer = align_ptr_up<alignment>(&bufferUnaligned[0]);
|
|
||||||
#else
|
#else
|
||||||
alignas(alignment)
|
alignas(alignment)
|
||||||
TransformedFeatureType transformedFeatures[FeatureTransformer::BufferSize];
|
TransformedFeatureType transformedFeatures[FeatureTransformer::BufferSize];
|
||||||
alignas(alignment) char buffer[Network::BufferSize];
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ASSERT_ALIGNED(transformedFeatures, alignment);
|
ASSERT_ALIGNED(transformedFeatures, alignment);
|
||||||
ASSERT_ALIGNED(buffer, alignment);
|
|
||||||
|
|
||||||
NnueEvalTrace t{};
|
NnueEvalTrace t{};
|
||||||
t.correctBucket = (pos.count<ALL_PIECES>() - 1) / 4;
|
t.correctBucket = (pos.count<ALL_PIECES>() - 1) / 4;
|
||||||
for (std::size_t bucket = 0; bucket < LayerStacks; ++bucket) {
|
for (IndexType bucket = 0; bucket < LayerStacks; ++bucket) {
|
||||||
const auto psqt = featureTransformer->transform(pos, transformedFeatures, bucket);
|
const auto materialist = featureTransformer->transform(pos, transformedFeatures, bucket);
|
||||||
const auto output = network[bucket]->propagate(transformedFeatures, buffer);
|
const auto positional = network[bucket]->propagate(transformedFeatures);
|
||||||
|
|
||||||
int materialist = psqt;
|
|
||||||
int positional = output[0];
|
|
||||||
|
|
||||||
t.psqt[bucket] = static_cast<Value>( materialist / OutputScale );
|
t.psqt[bucket] = static_cast<Value>( materialist / OutputScale );
|
||||||
t.positional[bucket] = static_cast<Value>( positional / OutputScale );
|
t.positional[bucket] = static_cast<Value>( positional / OutputScale );
|
||||||
@@ -220,7 +216,7 @@ namespace Stockfish::Eval::NNUE {
|
|||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const std::string PieceToChar(" PNBRQK pnbrqk");
|
constexpr std::string_view PieceToChar(" PNBRQK pnbrqk");
|
||||||
|
|
||||||
|
|
||||||
// format_cp_compact() converts a Value into (centi)pawns and writes it in a buffer.
|
// format_cp_compact() converts a Value into (centi)pawns and writes it in a buffer.
|
||||||
@@ -229,12 +225,12 @@ namespace Stockfish::Eval::NNUE {
|
|||||||
|
|
||||||
buffer[0] = (v < 0 ? '-' : v > 0 ? '+' : ' ');
|
buffer[0] = (v < 0 ? '-' : v > 0 ? '+' : ' ');
|
||||||
|
|
||||||
int cp = std::abs(100 * v / PawnValueEg);
|
int cp = std::abs(100 * v / UCI::NormalizeToPawnValue);
|
||||||
if (cp >= 10000)
|
if (cp >= 10000)
|
||||||
{
|
{
|
||||||
buffer[1] = '0' + cp / 10000; cp %= 10000;
|
buffer[1] = '0' + cp / 10000; cp %= 10000;
|
||||||
buffer[2] = '0' + cp / 1000; cp %= 1000;
|
buffer[2] = '0' + cp / 1000; cp %= 1000;
|
||||||
buffer[3] = '0' + cp / 100; cp %= 100;
|
buffer[3] = '0' + cp / 100;
|
||||||
buffer[4] = ' ';
|
buffer[4] = ' ';
|
||||||
}
|
}
|
||||||
else if (cp >= 1000)
|
else if (cp >= 1000)
|
||||||
@@ -254,14 +250,15 @@ namespace Stockfish::Eval::NNUE {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// format_cp_aligned_dot() converts a Value into (centi)pawns and writes it in a buffer,
|
// format_cp_aligned_dot() converts a Value into (centi)pawns, always keeping two decimals.
|
||||||
// always keeping two decimals. The buffer must have capacity for at least 7 chars.
|
static void format_cp_aligned_dot(Value v, std::stringstream &stream) {
|
||||||
static void format_cp_aligned_dot(Value v, char* buffer) {
|
const double cp = 1.0 * std::abs(int(v)) / UCI::NormalizeToPawnValue;
|
||||||
|
|
||||||
buffer[0] = (v < 0 ? '-' : v > 0 ? '+' : ' ');
|
stream << (v < 0 ? '-' : v > 0 ? '+' : ' ')
|
||||||
|
<< std::setiosflags(std::ios::fixed)
|
||||||
double cp = 1.0 * std::abs(int(v)) / PawnValueEg;
|
<< std::setw(6)
|
||||||
sprintf(&buffer[1], "%6.2f", cp);
|
<< std::setprecision(2)
|
||||||
|
<< cp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -341,17 +338,10 @@ namespace Stockfish::Eval::NNUE {
|
|||||||
|
|
||||||
for (std::size_t bucket = 0; bucket < LayerStacks; ++bucket)
|
for (std::size_t bucket = 0; bucket < LayerStacks; ++bucket)
|
||||||
{
|
{
|
||||||
char buffer[3][8];
|
ss << "| " << bucket << " ";
|
||||||
std::memset(buffer, '\0', sizeof(buffer));
|
ss << " | "; format_cp_aligned_dot(t.psqt[bucket], ss); ss << " "
|
||||||
|
<< " | "; format_cp_aligned_dot(t.positional[bucket], ss); ss << " "
|
||||||
format_cp_aligned_dot(t.psqt[bucket], buffer[0]);
|
<< " | "; format_cp_aligned_dot(t.psqt[bucket] + t.positional[bucket], ss); ss << " "
|
||||||
format_cp_aligned_dot(t.positional[bucket], buffer[1]);
|
|
||||||
format_cp_aligned_dot(t.psqt[bucket] + t.positional[bucket], buffer[2]);
|
|
||||||
|
|
||||||
ss << "| " << bucket << " "
|
|
||||||
<< " | " << buffer[0] << " "
|
|
||||||
<< " | " << buffer[1] << " "
|
|
||||||
<< " | " << buffer[2] << " "
|
|
||||||
<< " |";
|
<< " |";
|
||||||
if (bucket == t.correctBucket)
|
if (bucket == t.correctBucket)
|
||||||
ss << " <-- this bucket is used";
|
ss << " <-- this bucket is used";
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -31,6 +31,7 @@ namespace Stockfish::Eval::NNUE {
|
|||||||
constexpr std::uint32_t HashValue =
|
constexpr std::uint32_t HashValue =
|
||||||
FeatureTransformer::get_hash_value() ^ Network::get_hash_value();
|
FeatureTransformer::get_hash_value() ^ Network::get_hash_value();
|
||||||
|
|
||||||
|
|
||||||
// Deleter for automating release of memory area
|
// Deleter for automating release of memory area
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct AlignedDeleter {
|
struct AlignedDeleter {
|
||||||
@@ -54,6 +55,14 @@ namespace Stockfish::Eval::NNUE {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
using LargePagePtr = std::unique_ptr<T, LargePageDeleter<T>>;
|
using LargePagePtr = std::unique_ptr<T, LargePageDeleter<T>>;
|
||||||
|
|
||||||
|
std::string trace(Position& pos);
|
||||||
|
Value evaluate(const Position& pos, bool adjusted = false, int* complexity = nullptr);
|
||||||
|
void hint_common_parent_position(const Position& pos);
|
||||||
|
|
||||||
|
bool load_eval(std::string name, std::istream& stream);
|
||||||
|
bool save_eval(std::ostream& stream);
|
||||||
|
bool save_eval(const std::optional<std::string>& filename);
|
||||||
|
|
||||||
} // namespace Stockfish::Eval::NNUE
|
} // namespace Stockfish::Eval::NNUE
|
||||||
|
|
||||||
#endif // #ifndef NNUE_EVALUATE_NNUE_H_INCLUDED
|
#endif // #ifndef NNUE_EVALUATE_NNUE_H_INCLUDED
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -24,50 +24,51 @@
|
|||||||
|
|
||||||
namespace Stockfish::Eval::NNUE::Features {
|
namespace Stockfish::Eval::NNUE::Features {
|
||||||
|
|
||||||
// Orient a square according to perspective (rotates by 180 for black)
|
|
||||||
inline Square HalfKAv2_hm::orient(Color perspective, Square s, Square ksq) {
|
|
||||||
return Square(int(s) ^ (bool(perspective) * SQ_A8) ^ ((file_of(ksq) < FILE_E) * SQ_H1));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Index of a feature for a given king position and another piece on some square
|
// Index of a feature for a given king position and another piece on some square
|
||||||
inline IndexType HalfKAv2_hm::make_index(Color perspective, Square s, Piece pc, Square ksq) {
|
template<Color Perspective>
|
||||||
Square o_ksq = orient(perspective, ksq, ksq);
|
inline IndexType HalfKAv2_hm::make_index(Square s, Piece pc, Square ksq) {
|
||||||
return IndexType(orient(perspective, s, ksq) + PieceSquareIndex[perspective][pc] + PS_NB * KingBuckets[o_ksq]);
|
return IndexType((int(s) ^ OrientTBL[Perspective][ksq]) + PieceSquareIndex[Perspective][pc] + KingBuckets[Perspective][ksq]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a list of indices for active features
|
// Get a list of indices for active features
|
||||||
|
template<Color Perspective>
|
||||||
void HalfKAv2_hm::append_active_indices(
|
void HalfKAv2_hm::append_active_indices(
|
||||||
const Position& pos,
|
const Position& pos,
|
||||||
Color perspective,
|
|
||||||
IndexList& active
|
IndexList& active
|
||||||
) {
|
) {
|
||||||
Square ksq = pos.square<KING>(perspective);
|
Square ksq = pos.square<KING>(Perspective);
|
||||||
Bitboard bb = pos.pieces();
|
Bitboard bb = pos.pieces();
|
||||||
while (bb)
|
while (bb)
|
||||||
{
|
{
|
||||||
Square s = pop_lsb(bb);
|
Square s = pop_lsb(bb);
|
||||||
active.push_back(make_index(perspective, s, pos.piece_on(s), ksq));
|
active.push_back(make_index<Perspective>(s, pos.piece_on(s), ksq));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Explicit template instantiations
|
||||||
|
template void HalfKAv2_hm::append_active_indices<WHITE>(const Position& pos, IndexList& active);
|
||||||
|
template void HalfKAv2_hm::append_active_indices<BLACK>(const Position& pos, IndexList& active);
|
||||||
|
|
||||||
// append_changed_indices() : get a list of indices for recently changed features
|
// append_changed_indices() : get a list of indices for recently changed features
|
||||||
|
template<Color Perspective>
|
||||||
void HalfKAv2_hm::append_changed_indices(
|
void HalfKAv2_hm::append_changed_indices(
|
||||||
Square ksq,
|
Square ksq,
|
||||||
const DirtyPiece& dp,
|
const DirtyPiece& dp,
|
||||||
Color perspective,
|
|
||||||
IndexList& removed,
|
IndexList& removed,
|
||||||
IndexList& added
|
IndexList& added
|
||||||
) {
|
) {
|
||||||
for (int i = 0; i < dp.dirty_num; ++i) {
|
for (int i = 0; i < dp.dirty_num; ++i) {
|
||||||
if (dp.from[i] != SQ_NONE)
|
if (dp.from[i] != SQ_NONE)
|
||||||
removed.push_back(make_index(perspective, dp.from[i], dp.piece[i], ksq));
|
removed.push_back(make_index<Perspective>(dp.from[i], dp.piece[i], ksq));
|
||||||
if (dp.to[i] != SQ_NONE)
|
if (dp.to[i] != SQ_NONE)
|
||||||
added.push_back(make_index(perspective, dp.to[i], dp.piece[i], ksq));
|
added.push_back(make_index<Perspective>(dp.to[i], dp.piece[i], ksq));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Explicit template instantiations
|
||||||
|
template void HalfKAv2_hm::append_changed_indices<WHITE>(Square ksq, const DirtyPiece& dp, IndexList& removed, IndexList& added);
|
||||||
|
template void HalfKAv2_hm::append_changed_indices<BLACK>(Square ksq, const DirtyPiece& dp, IndexList& removed, IndexList& added);
|
||||||
|
|
||||||
int HalfKAv2_hm::update_cost(const StateInfo* st) {
|
int HalfKAv2_hm::update_cost(const StateInfo* st) {
|
||||||
return st->dirtyPiece.dirty_num;
|
return st->dirtyPiece.dirty_num;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -62,11 +62,9 @@ namespace Stockfish::Eval::NNUE::Features {
|
|||||||
PS_NONE, PS_W_PAWN, PS_W_KNIGHT, PS_W_BISHOP, PS_W_ROOK, PS_W_QUEEN, PS_KING, PS_NONE }
|
PS_NONE, PS_W_PAWN, PS_W_KNIGHT, PS_W_BISHOP, PS_W_ROOK, PS_W_QUEEN, PS_KING, PS_NONE }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Orient a square according to perspective (rotates by 180 for black)
|
|
||||||
static Square orient(Color perspective, Square s, Square ksq);
|
|
||||||
|
|
||||||
// Index of a feature for a given king position and another piece on some square
|
// Index of a feature for a given king position and another piece on some square
|
||||||
static IndexType make_index(Color perspective, Square s, Piece pc, Square ksq);
|
template<Color Perspective>
|
||||||
|
static IndexType make_index(Square s, Piece pc, Square ksq);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Feature name
|
// Feature name
|
||||||
@@ -79,15 +77,45 @@ namespace Stockfish::Eval::NNUE::Features {
|
|||||||
static constexpr IndexType Dimensions =
|
static constexpr IndexType Dimensions =
|
||||||
static_cast<IndexType>(SQUARE_NB) * static_cast<IndexType>(PS_NB) / 2;
|
static_cast<IndexType>(SQUARE_NB) * static_cast<IndexType>(PS_NB) / 2;
|
||||||
|
|
||||||
static constexpr int KingBuckets[64] = {
|
#define B(v) (v * PS_NB)
|
||||||
-1, -1, -1, -1, 31, 30, 29, 28,
|
static constexpr int KingBuckets[COLOR_NB][SQUARE_NB] = {
|
||||||
-1, -1, -1, -1, 27, 26, 25, 24,
|
{ B(28), B(29), B(30), B(31), B(31), B(30), B(29), B(28),
|
||||||
-1, -1, -1, -1, 23, 22, 21, 20,
|
B(24), B(25), B(26), B(27), B(27), B(26), B(25), B(24),
|
||||||
-1, -1, -1, -1, 19, 18, 17, 16,
|
B(20), B(21), B(22), B(23), B(23), B(22), B(21), B(20),
|
||||||
-1, -1, -1, -1, 15, 14, 13, 12,
|
B(16), B(17), B(18), B(19), B(19), B(18), B(17), B(16),
|
||||||
-1, -1, -1, -1, 11, 10, 9, 8,
|
B(12), B(13), B(14), B(15), B(15), B(14), B(13), B(12),
|
||||||
-1, -1, -1, -1, 7, 6, 5, 4,
|
B( 8), B( 9), B(10), B(11), B(11), B(10), B( 9), B( 8),
|
||||||
-1, -1, -1, -1, 3, 2, 1, 0
|
B( 4), B( 5), B( 6), B( 7), B( 7), B( 6), B( 5), B( 4),
|
||||||
|
B( 0), B( 1), B( 2), B( 3), B( 3), B( 2), B( 1), B( 0) },
|
||||||
|
{ B( 0), B( 1), B( 2), B( 3), B( 3), B( 2), B( 1), B( 0),
|
||||||
|
B( 4), B( 5), B( 6), B( 7), B( 7), B( 6), B( 5), B( 4),
|
||||||
|
B( 8), B( 9), B(10), B(11), B(11), B(10), B( 9), B( 8),
|
||||||
|
B(12), B(13), B(14), B(15), B(15), B(14), B(13), B(12),
|
||||||
|
B(16), B(17), B(18), B(19), B(19), B(18), B(17), B(16),
|
||||||
|
B(20), B(21), B(22), B(23), B(23), B(22), B(21), B(20),
|
||||||
|
B(24), B(25), B(26), B(27), B(27), B(26), B(25), B(24),
|
||||||
|
B(28), B(29), B(30), B(31), B(31), B(30), B(29), B(28) }
|
||||||
|
};
|
||||||
|
#undef B
|
||||||
|
|
||||||
|
// Orient a square according to perspective (rotates by 180 for black)
|
||||||
|
static constexpr int OrientTBL[COLOR_NB][SQUARE_NB] = {
|
||||||
|
{ SQ_H1, SQ_H1, SQ_H1, SQ_H1, SQ_A1, SQ_A1, SQ_A1, SQ_A1,
|
||||||
|
SQ_H1, SQ_H1, SQ_H1, SQ_H1, SQ_A1, SQ_A1, SQ_A1, SQ_A1,
|
||||||
|
SQ_H1, SQ_H1, SQ_H1, SQ_H1, SQ_A1, SQ_A1, SQ_A1, SQ_A1,
|
||||||
|
SQ_H1, SQ_H1, SQ_H1, SQ_H1, SQ_A1, SQ_A1, SQ_A1, SQ_A1,
|
||||||
|
SQ_H1, SQ_H1, SQ_H1, SQ_H1, SQ_A1, SQ_A1, SQ_A1, SQ_A1,
|
||||||
|
SQ_H1, SQ_H1, SQ_H1, SQ_H1, SQ_A1, SQ_A1, SQ_A1, SQ_A1,
|
||||||
|
SQ_H1, SQ_H1, SQ_H1, SQ_H1, SQ_A1, SQ_A1, SQ_A1, SQ_A1,
|
||||||
|
SQ_H1, SQ_H1, SQ_H1, SQ_H1, SQ_A1, SQ_A1, SQ_A1, SQ_A1 },
|
||||||
|
{ SQ_H8, SQ_H8, SQ_H8, SQ_H8, SQ_A8, SQ_A8, SQ_A8, SQ_A8,
|
||||||
|
SQ_H8, SQ_H8, SQ_H8, SQ_H8, SQ_A8, SQ_A8, SQ_A8, SQ_A8,
|
||||||
|
SQ_H8, SQ_H8, SQ_H8, SQ_H8, SQ_A8, SQ_A8, SQ_A8, SQ_A8,
|
||||||
|
SQ_H8, SQ_H8, SQ_H8, SQ_H8, SQ_A8, SQ_A8, SQ_A8, SQ_A8,
|
||||||
|
SQ_H8, SQ_H8, SQ_H8, SQ_H8, SQ_A8, SQ_A8, SQ_A8, SQ_A8,
|
||||||
|
SQ_H8, SQ_H8, SQ_H8, SQ_H8, SQ_A8, SQ_A8, SQ_A8, SQ_A8,
|
||||||
|
SQ_H8, SQ_H8, SQ_H8, SQ_H8, SQ_A8, SQ_A8, SQ_A8, SQ_A8,
|
||||||
|
SQ_H8, SQ_H8, SQ_H8, SQ_H8, SQ_A8, SQ_A8, SQ_A8, SQ_A8 }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Maximum number of simultaneously active features.
|
// Maximum number of simultaneously active features.
|
||||||
@@ -95,16 +123,16 @@ namespace Stockfish::Eval::NNUE::Features {
|
|||||||
using IndexList = ValueList<IndexType, MaxActiveDimensions>;
|
using IndexList = ValueList<IndexType, MaxActiveDimensions>;
|
||||||
|
|
||||||
// Get a list of indices for active features
|
// Get a list of indices for active features
|
||||||
|
template<Color Perspective>
|
||||||
static void append_active_indices(
|
static void append_active_indices(
|
||||||
const Position& pos,
|
const Position& pos,
|
||||||
Color perspective,
|
|
||||||
IndexList& active);
|
IndexList& active);
|
||||||
|
|
||||||
// Get a list of indices for recently changed features
|
// Get a list of indices for recently changed features
|
||||||
|
template<Color Perspective>
|
||||||
static void append_changed_indices(
|
static void append_changed_indices(
|
||||||
Square ksq,
|
Square ksq,
|
||||||
const DirtyPiece& dp,
|
const DirtyPiece& dp,
|
||||||
Color perspective,
|
|
||||||
IndexList& removed,
|
IndexList& removed,
|
||||||
IndexList& added
|
IndexList& added
|
||||||
);
|
);
|
||||||
|
|||||||
+137
-128
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -25,13 +25,13 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include "../nnue_common.h"
|
#include "../nnue_common.h"
|
||||||
#include "../../simd.h"
|
#include "simd.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This file contains the definition for a fully connected layer (aka affine transform).
|
This file contains the definition for a fully connected layer (aka affine transform).
|
||||||
Two approaches are employed, depending on the sizes of the transform.
|
Two approaches are employed, depending on the sizes of the transform.
|
||||||
|
|
||||||
Approach 1:
|
Approach 1 (a specialization for large inputs):
|
||||||
- used when the PaddedInputDimensions >= 128
|
- used when the PaddedInputDimensions >= 128
|
||||||
- uses AVX512 if possible
|
- uses AVX512 if possible
|
||||||
- processes inputs in batches of 2*InputSimdWidth
|
- processes inputs in batches of 2*InputSimdWidth
|
||||||
@@ -42,9 +42,8 @@
|
|||||||
depends on the architecture (the amount of registers)
|
depends on the architecture (the amount of registers)
|
||||||
- accumulate + hadd is used
|
- accumulate + hadd is used
|
||||||
|
|
||||||
Approach 2:
|
Approach 2 (a specialization for small inputs):
|
||||||
- used when the PaddedInputDimensions < 128
|
- used when the PaddedInputDimensions < 128
|
||||||
- does not use AVX512
|
|
||||||
- expected use-case is for when PaddedInputDimensions == 32 and InputDimensions <= 32.
|
- expected use-case is for when PaddedInputDimensions == 32 and InputDimensions <= 32.
|
||||||
- that's why AVX512 is hard to implement
|
- that's why AVX512 is hard to implement
|
||||||
- expected use-case is small layers
|
- expected use-case is small layers
|
||||||
@@ -63,20 +62,21 @@ namespace Stockfish::Eval::NNUE::Layers {
|
|||||||
{
|
{
|
||||||
# if defined(USE_SSE2)
|
# if defined(USE_SSE2)
|
||||||
// At least a multiple of 16, with SSE2.
|
// At least a multiple of 16, with SSE2.
|
||||||
static_assert(PaddedInputDimensions % 16 == 0);
|
constexpr IndexType NumChunks = ceil_to_multiple<IndexType>(InputDimensions, 16) / 16;
|
||||||
constexpr IndexType NumChunks = PaddedInputDimensions / 16;
|
|
||||||
const __m128i Zeros = _mm_setzero_si128();
|
const __m128i Zeros = _mm_setzero_si128();
|
||||||
const auto inputVector = reinterpret_cast<const __m128i*>(input);
|
const auto inputVector = reinterpret_cast<const __m128i*>(input);
|
||||||
|
|
||||||
# elif defined(USE_MMX)
|
# elif defined(USE_MMX)
|
||||||
static_assert(InputDimensions % 8 == 0);
|
constexpr IndexType NumChunks = ceil_to_multiple<IndexType>(InputDimensions, 8) / 8;
|
||||||
constexpr IndexType NumChunks = InputDimensions / 8;
|
|
||||||
const __m64 Zeros = _mm_setzero_si64();
|
const __m64 Zeros = _mm_setzero_si64();
|
||||||
const auto inputVector = reinterpret_cast<const __m64*>(input);
|
const auto inputVector = reinterpret_cast<const __m64*>(input);
|
||||||
|
|
||||||
|
# elif defined(USE_NEON_DOTPROD)
|
||||||
|
constexpr IndexType NumChunks = ceil_to_multiple<IndexType>(InputDimensions, 16) / 16;
|
||||||
|
const auto inputVector = reinterpret_cast<const int8x16_t*>(input);
|
||||||
|
|
||||||
# elif defined(USE_NEON)
|
# elif defined(USE_NEON)
|
||||||
static_assert(PaddedInputDimensions % 16 == 0);
|
constexpr IndexType NumChunks = ceil_to_multiple<IndexType>(InputDimensions, 16) / 16;
|
||||||
constexpr IndexType NumChunks = PaddedInputDimensions / 16;
|
|
||||||
const auto inputVector = reinterpret_cast<const int8x8_t*>(input);
|
const auto inputVector = reinterpret_cast<const int8x8_t*>(input);
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
@@ -126,6 +126,14 @@ namespace Stockfish::Eval::NNUE::Layers {
|
|||||||
sum = _mm_add_pi32(sum, _mm_unpackhi_pi32(sum, sum));
|
sum = _mm_add_pi32(sum, _mm_unpackhi_pi32(sum, sum));
|
||||||
output[i] = _mm_cvtsi64_si32(sum);
|
output[i] = _mm_cvtsi64_si32(sum);
|
||||||
|
|
||||||
|
# elif defined(USE_NEON_DOTPROD)
|
||||||
|
int32x4_t sum = {biases[i]};
|
||||||
|
const auto row = reinterpret_cast<const int8x16_t*>(&weights[offset]);
|
||||||
|
for (IndexType j = 0; j < NumChunks; ++j) {
|
||||||
|
sum = vdotq_s32(sum, inputVector[j], row[j]);
|
||||||
|
}
|
||||||
|
output[i] = vaddvq_s32(sum);
|
||||||
|
|
||||||
# elif defined(USE_NEON)
|
# elif defined(USE_NEON)
|
||||||
int32x4_t sum = {biases[i]};
|
int32x4_t sum = {biases[i]};
|
||||||
const auto row = reinterpret_cast<const int8x8_t*>(&weights[offset]);
|
const auto row = reinterpret_cast<const int8x8_t*>(&weights[offset]);
|
||||||
@@ -151,69 +159,76 @@ namespace Stockfish::Eval::NNUE::Layers {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <typename PreviousLayer, IndexType OutDims, typename Enabled = void>
|
template <IndexType InDims, IndexType OutDims, typename Enabled = void>
|
||||||
class AffineTransform;
|
class AffineTransform;
|
||||||
|
|
||||||
// A specialization for large inputs.
|
#if defined (USE_AVX512)
|
||||||
template <typename PreviousLayer, IndexType OutDims>
|
constexpr IndexType LargeInputSize = 2 * 64;
|
||||||
class AffineTransform<PreviousLayer, OutDims, std::enable_if_t<(PreviousLayer::OutputDimensions >= 2*64-1)>> {
|
#else
|
||||||
|
constexpr IndexType LargeInputSize = std::numeric_limits<IndexType>::max();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// A specialization for large inputs
|
||||||
|
template <IndexType InDims, IndexType OutDims>
|
||||||
|
class AffineTransform<InDims, OutDims, std::enable_if_t<(ceil_to_multiple<IndexType>(InDims, MaxSimdWidth) >= LargeInputSize)>> {
|
||||||
public:
|
public:
|
||||||
// Input/output type
|
// Input/output type
|
||||||
using InputType = typename PreviousLayer::OutputType;
|
using InputType = std::uint8_t;
|
||||||
using OutputType = std::int32_t;
|
using OutputType = std::int32_t;
|
||||||
static_assert(std::is_same<InputType, std::uint8_t>::value, "");
|
|
||||||
|
|
||||||
// Number of input/output dimensions
|
// Number of input/output dimensions
|
||||||
static constexpr IndexType InputDimensions = PreviousLayer::OutputDimensions;
|
static constexpr IndexType InputDimensions = InDims;
|
||||||
static constexpr IndexType OutputDimensions = OutDims;
|
static constexpr IndexType OutputDimensions = OutDims;
|
||||||
|
|
||||||
static constexpr IndexType PaddedInputDimensions =
|
static constexpr IndexType PaddedInputDimensions =
|
||||||
ceil_to_multiple<IndexType>(InputDimensions, MaxSimdWidth);
|
ceil_to_multiple<IndexType>(InputDimensions, MaxSimdWidth);
|
||||||
|
static constexpr IndexType PaddedOutputDimensions =
|
||||||
|
ceil_to_multiple<IndexType>(OutputDimensions, MaxSimdWidth);
|
||||||
|
|
||||||
static_assert(PaddedInputDimensions >= 128, "Something went wrong. This specialization should not have been chosen.");
|
using OutputBuffer = OutputType[PaddedOutputDimensions];
|
||||||
|
|
||||||
|
static_assert(PaddedInputDimensions >= LargeInputSize, "Something went wrong. This specialization (for large inputs) should not have been chosen.");
|
||||||
|
|
||||||
#if defined (USE_AVX512)
|
#if defined (USE_AVX512)
|
||||||
static constexpr const IndexType InputSimdWidth = 64;
|
static constexpr IndexType InputSimdWidth = 64;
|
||||||
static constexpr const IndexType MaxNumOutputRegs = 16;
|
static constexpr IndexType MaxNumOutputRegs = 16;
|
||||||
#elif defined (USE_AVX2)
|
#elif defined (USE_AVX2)
|
||||||
static constexpr const IndexType InputSimdWidth = 32;
|
static constexpr IndexType InputSimdWidth = 32;
|
||||||
static constexpr const IndexType MaxNumOutputRegs = 8;
|
static constexpr IndexType MaxNumOutputRegs = 8;
|
||||||
#elif defined (USE_SSSE3)
|
#elif defined (USE_SSSE3)
|
||||||
static constexpr const IndexType InputSimdWidth = 16;
|
static constexpr IndexType InputSimdWidth = 16;
|
||||||
static constexpr const IndexType MaxNumOutputRegs = 8;
|
static constexpr IndexType MaxNumOutputRegs = 8;
|
||||||
|
#elif defined (USE_NEON_DOTPROD)
|
||||||
|
static constexpr IndexType InputSimdWidth = 16;
|
||||||
|
static constexpr IndexType MaxNumOutputRegs = 8;
|
||||||
|
#elif defined (USE_NEON)
|
||||||
|
static constexpr IndexType InputSimdWidth = 8;
|
||||||
|
static constexpr IndexType MaxNumOutputRegs = 8;
|
||||||
#else
|
#else
|
||||||
// The fallback implementation will not have permuted weights.
|
// The fallback implementation will not have permuted weights.
|
||||||
// We define these to avoid a lot of ifdefs later.
|
// We define these to avoid a lot of ifdefs later.
|
||||||
static constexpr const IndexType InputSimdWidth = 1;
|
static constexpr IndexType InputSimdWidth = 1;
|
||||||
static constexpr const IndexType MaxNumOutputRegs = 1;
|
static constexpr IndexType MaxNumOutputRegs = 1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// A big block is a region in the weight matrix of the size [PaddedInputDimensions, NumOutputRegs].
|
// A big block is a region in the weight matrix of the size [PaddedInputDimensions, NumOutputRegs].
|
||||||
// A small block is a region of size [InputSimdWidth, 1]
|
// A small block is a region of size [InputSimdWidth, 1]
|
||||||
|
|
||||||
static constexpr const IndexType NumOutputRegs = std::min(MaxNumOutputRegs, OutputDimensions);
|
static constexpr IndexType NumOutputRegs = std::min(MaxNumOutputRegs, OutputDimensions);
|
||||||
static constexpr const IndexType SmallBlockSize = InputSimdWidth;
|
static constexpr IndexType SmallBlockSize = InputSimdWidth;
|
||||||
static constexpr const IndexType BigBlockSize = NumOutputRegs * PaddedInputDimensions;
|
static constexpr IndexType BigBlockSize = NumOutputRegs * PaddedInputDimensions;
|
||||||
static constexpr const IndexType NumSmallBlocksInBigBlock = BigBlockSize / SmallBlockSize;
|
static constexpr IndexType NumSmallBlocksInBigBlock = BigBlockSize / SmallBlockSize;
|
||||||
static constexpr const IndexType NumSmallBlocksPerOutput = PaddedInputDimensions / SmallBlockSize;
|
static constexpr IndexType NumSmallBlocksPerOutput = PaddedInputDimensions / SmallBlockSize;
|
||||||
static constexpr const IndexType NumBigBlocks = OutputDimensions / NumOutputRegs;
|
static constexpr IndexType NumBigBlocks = OutputDimensions / NumOutputRegs;
|
||||||
|
|
||||||
static_assert(OutputDimensions % NumOutputRegs == 0);
|
static_assert(OutputDimensions % NumOutputRegs == 0);
|
||||||
|
|
||||||
// Size of forward propagation buffer used in this layer
|
|
||||||
static constexpr std::size_t SelfBufferSize =
|
|
||||||
ceil_to_multiple(OutputDimensions * sizeof(OutputType), CacheLineSize);
|
|
||||||
|
|
||||||
// Size of the forward propagation buffer used from the input layer to this layer
|
|
||||||
static constexpr std::size_t BufferSize =
|
|
||||||
PreviousLayer::BufferSize + SelfBufferSize;
|
|
||||||
|
|
||||||
// Hash value embedded in the evaluation file
|
// Hash value embedded in the evaluation file
|
||||||
static constexpr std::uint32_t get_hash_value() {
|
static constexpr std::uint32_t get_hash_value(std::uint32_t prevHash) {
|
||||||
std::uint32_t hashValue = 0xCC03DAE4u;
|
std::uint32_t hashValue = 0xCC03DAE4u;
|
||||||
hashValue += OutputDimensions;
|
hashValue += OutputDimensions;
|
||||||
hashValue ^= PreviousLayer::get_hash_value() >> 1;
|
hashValue ^= prevHash >> 1;
|
||||||
hashValue ^= PreviousLayer::get_hash_value() << 31;
|
hashValue ^= prevHash << 31;
|
||||||
return hashValue;
|
return hashValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,11 +255,9 @@ namespace Stockfish::Eval::NNUE::Layers {
|
|||||||
|
|
||||||
// Read network parameters
|
// Read network parameters
|
||||||
bool read_parameters(std::istream& stream) {
|
bool read_parameters(std::istream& stream) {
|
||||||
if (!previousLayer.read_parameters(stream)) return false;
|
read_little_endian<BiasType>(stream, biases, OutputDimensions);
|
||||||
for (std::size_t i = 0; i < OutputDimensions; ++i)
|
|
||||||
biases[i] = read_little_endian<BiasType>(stream);
|
|
||||||
|
|
||||||
for (std::size_t i = 0; i < OutputDimensions * PaddedInputDimensions; ++i)
|
for (IndexType i = 0; i < OutputDimensions * PaddedInputDimensions; ++i)
|
||||||
weights[get_weight_index(i)] = read_little_endian<WeightType>(stream);
|
weights[get_weight_index(i)] = read_little_endian<WeightType>(stream);
|
||||||
|
|
||||||
return !stream.fail();
|
return !stream.fail();
|
||||||
@@ -252,11 +265,9 @@ namespace Stockfish::Eval::NNUE::Layers {
|
|||||||
|
|
||||||
// Write network parameters
|
// Write network parameters
|
||||||
bool write_parameters(std::ostream& stream) const {
|
bool write_parameters(std::ostream& stream) const {
|
||||||
if (!previousLayer.write_parameters(stream)) return false;
|
write_little_endian<BiasType>(stream, biases, OutputDimensions);
|
||||||
for (std::size_t i = 0; i < OutputDimensions; ++i)
|
|
||||||
write_little_endian<BiasType>(stream, biases[i]);
|
|
||||||
|
|
||||||
for (std::size_t i = 0; i < OutputDimensions * PaddedInputDimensions; ++i)
|
for (IndexType i = 0; i < OutputDimensions * PaddedInputDimensions; ++i)
|
||||||
write_little_endian<WeightType>(stream, weights[get_weight_index(i)]);
|
write_little_endian<WeightType>(stream, weights[get_weight_index(i)]);
|
||||||
|
|
||||||
return !stream.fail();
|
return !stream.fail();
|
||||||
@@ -264,58 +275,75 @@ namespace Stockfish::Eval::NNUE::Layers {
|
|||||||
|
|
||||||
// Forward propagation
|
// Forward propagation
|
||||||
const OutputType* propagate(
|
const OutputType* propagate(
|
||||||
const TransformedFeatureType* transformedFeatures, char* buffer) const {
|
const InputType* input, OutputType* output) const {
|
||||||
const auto input = previousLayer.propagate(
|
|
||||||
transformedFeatures, buffer + SelfBufferSize);
|
|
||||||
OutputType* output = reinterpret_cast<OutputType*>(buffer);
|
|
||||||
|
|
||||||
#if defined (USE_AVX512)
|
#if defined (USE_AVX512)
|
||||||
using vec_t = __m512i;
|
using acc_vec_t = __m512i;
|
||||||
#define vec_setzero _mm512_setzero_si512
|
using bias_vec_t = __m128i;
|
||||||
#define vec_set_32 _mm512_set1_epi32
|
using weight_vec_t = __m512i;
|
||||||
#define vec_add_dpbusd_32 Simd::m512_add_dpbusd_epi32
|
using in_vec_t = __m512i;
|
||||||
|
#define vec_zero _mm512_setzero_si512()
|
||||||
#define vec_add_dpbusd_32x2 Simd::m512_add_dpbusd_epi32x2
|
#define vec_add_dpbusd_32x2 Simd::m512_add_dpbusd_epi32x2
|
||||||
#define vec_hadd Simd::m512_hadd
|
#define vec_hadd Simd::m512_hadd
|
||||||
#define vec_haddx4 Simd::m512_haddx4
|
#define vec_haddx4 Simd::m512_haddx4
|
||||||
#elif defined (USE_AVX2)
|
#elif defined (USE_AVX2)
|
||||||
using vec_t = __m256i;
|
using acc_vec_t = __m256i;
|
||||||
#define vec_setzero _mm256_setzero_si256
|
using bias_vec_t = __m128i;
|
||||||
#define vec_set_32 _mm256_set1_epi32
|
using weight_vec_t = __m256i;
|
||||||
#define vec_add_dpbusd_32 Simd::m256_add_dpbusd_epi32
|
using in_vec_t = __m256i;
|
||||||
|
#define vec_zero _mm256_setzero_si256()
|
||||||
#define vec_add_dpbusd_32x2 Simd::m256_add_dpbusd_epi32x2
|
#define vec_add_dpbusd_32x2 Simd::m256_add_dpbusd_epi32x2
|
||||||
#define vec_hadd Simd::m256_hadd
|
#define vec_hadd Simd::m256_hadd
|
||||||
#define vec_haddx4 Simd::m256_haddx4
|
#define vec_haddx4 Simd::m256_haddx4
|
||||||
#elif defined (USE_SSSE3)
|
#elif defined (USE_SSSE3)
|
||||||
using vec_t = __m128i;
|
using acc_vec_t = __m128i;
|
||||||
#define vec_setzero _mm_setzero_si128
|
using bias_vec_t = __m128i;
|
||||||
#define vec_set_32 _mm_set1_epi32
|
using weight_vec_t = __m128i;
|
||||||
#define vec_add_dpbusd_32 Simd::m128_add_dpbusd_epi32
|
using in_vec_t = __m128i;
|
||||||
|
#define vec_zero _mm_setzero_si128()
|
||||||
#define vec_add_dpbusd_32x2 Simd::m128_add_dpbusd_epi32x2
|
#define vec_add_dpbusd_32x2 Simd::m128_add_dpbusd_epi32x2
|
||||||
#define vec_hadd Simd::m128_hadd
|
#define vec_hadd Simd::m128_hadd
|
||||||
#define vec_haddx4 Simd::m128_haddx4
|
#define vec_haddx4 Simd::m128_haddx4
|
||||||
|
#elif defined (USE_NEON_DOTPROD)
|
||||||
|
using acc_vec_t = int32x4_t;
|
||||||
|
using bias_vec_t = int32x4_t;
|
||||||
|
using weight_vec_t = int8x16_t;
|
||||||
|
using in_vec_t = int8x16_t;
|
||||||
|
#define vec_zero {0}
|
||||||
|
#define vec_add_dpbusd_32x2 Simd::dotprod_m128_add_dpbusd_epi32x2
|
||||||
|
#define vec_hadd Simd::neon_m128_hadd
|
||||||
|
#define vec_haddx4 Simd::neon_m128_haddx4
|
||||||
|
#elif defined (USE_NEON)
|
||||||
|
using acc_vec_t = int32x4_t;
|
||||||
|
using bias_vec_t = int32x4_t;
|
||||||
|
using weight_vec_t = int8x8_t;
|
||||||
|
using in_vec_t = int8x8_t;
|
||||||
|
#define vec_zero {0}
|
||||||
|
#define vec_add_dpbusd_32x2 Simd::neon_m128_add_dpbusd_epi32x2
|
||||||
|
#define vec_hadd Simd::neon_m128_hadd
|
||||||
|
#define vec_haddx4 Simd::neon_m128_haddx4
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined (USE_SSSE3)
|
#if defined (USE_SSSE3) || defined (USE_NEON)
|
||||||
const vec_t* invec = reinterpret_cast<const vec_t*>(input);
|
const in_vec_t* invec = reinterpret_cast<const in_vec_t*>(input);
|
||||||
|
|
||||||
|
|
||||||
// Perform accumulation to registers for each big block
|
// Perform accumulation to registers for each big block
|
||||||
for (IndexType bigBlock = 0; bigBlock < NumBigBlocks; ++bigBlock)
|
for (IndexType bigBlock = 0; bigBlock < NumBigBlocks; ++bigBlock)
|
||||||
{
|
{
|
||||||
vec_t acc[NumOutputRegs] = { vec_setzero() };
|
acc_vec_t acc[NumOutputRegs] = { vec_zero };
|
||||||
|
|
||||||
// Each big block has NumOutputRegs small blocks in each "row", one per register.
|
// Each big block has NumOutputRegs small blocks in each "row", one per register.
|
||||||
// We process two small blocks at a time to save on one addition without VNNI.
|
// We process two small blocks at a time to save on one addition without VNNI.
|
||||||
for (IndexType smallBlock = 0; smallBlock < NumSmallBlocksPerOutput; smallBlock += 2)
|
for (IndexType smallBlock = 0; smallBlock < NumSmallBlocksPerOutput; smallBlock += 2)
|
||||||
{
|
{
|
||||||
const vec_t* weightvec =
|
const weight_vec_t* weightvec =
|
||||||
reinterpret_cast<const vec_t*>(
|
reinterpret_cast<const weight_vec_t*>(
|
||||||
weights
|
weights
|
||||||
+ bigBlock * BigBlockSize
|
+ bigBlock * BigBlockSize
|
||||||
+ smallBlock * SmallBlockSize * NumOutputRegs);
|
+ smallBlock * SmallBlockSize * NumOutputRegs);
|
||||||
|
|
||||||
const vec_t in0 = invec[smallBlock + 0];
|
const in_vec_t in0 = invec[smallBlock + 0];
|
||||||
const vec_t in1 = invec[smallBlock + 1];
|
const in_vec_t in1 = invec[smallBlock + 1];
|
||||||
|
|
||||||
for (IndexType k = 0; k < NumOutputRegs; ++k)
|
for (IndexType k = 0; k < NumOutputRegs; ++k)
|
||||||
vec_add_dpbusd_32x2(acc[k], in0, weightvec[k], in1, weightvec[k + NumOutputRegs]);
|
vec_add_dpbusd_32x2(acc[k], in0, weightvec[k], in1, weightvec[k + NumOutputRegs]);
|
||||||
@@ -324,8 +352,8 @@ namespace Stockfish::Eval::NNUE::Layers {
|
|||||||
// Horizontally add all accumulators.
|
// Horizontally add all accumulators.
|
||||||
if constexpr (NumOutputRegs % 4 == 0)
|
if constexpr (NumOutputRegs % 4 == 0)
|
||||||
{
|
{
|
||||||
__m128i* outputvec = reinterpret_cast<__m128i*>(output);
|
bias_vec_t* outputvec = reinterpret_cast<bias_vec_t*>(output);
|
||||||
const __m128i* biasvec = reinterpret_cast<const __m128i*>(biases);
|
const bias_vec_t* biasvec = reinterpret_cast<const bias_vec_t*>(biases);
|
||||||
|
|
||||||
for (IndexType k = 0; k < NumOutputRegs; k += 4)
|
for (IndexType k = 0; k < NumOutputRegs; k += 4)
|
||||||
{
|
{
|
||||||
@@ -343,9 +371,7 @@ namespace Stockfish::Eval::NNUE::Layers {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# undef vec_setzero
|
# undef vec_zero
|
||||||
# undef vec_set_32
|
|
||||||
# undef vec_add_dpbusd_32
|
|
||||||
# undef vec_add_dpbusd_32x2
|
# undef vec_add_dpbusd_32x2
|
||||||
# undef vec_hadd
|
# undef vec_hadd
|
||||||
# undef vec_haddx4
|
# undef vec_haddx4
|
||||||
@@ -365,48 +391,38 @@ namespace Stockfish::Eval::NNUE::Layers {
|
|||||||
using BiasType = OutputType;
|
using BiasType = OutputType;
|
||||||
using WeightType = std::int8_t;
|
using WeightType = std::int8_t;
|
||||||
|
|
||||||
PreviousLayer previousLayer;
|
|
||||||
|
|
||||||
alignas(CacheLineSize) BiasType biases[OutputDimensions];
|
alignas(CacheLineSize) BiasType biases[OutputDimensions];
|
||||||
alignas(CacheLineSize) WeightType weights[OutputDimensions * PaddedInputDimensions];
|
alignas(CacheLineSize) WeightType weights[OutputDimensions * PaddedInputDimensions];
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename PreviousLayer, IndexType OutDims>
|
// A specialization for small inputs
|
||||||
class AffineTransform<PreviousLayer, OutDims, std::enable_if_t<(PreviousLayer::OutputDimensions < 2*64-1)>> {
|
template <IndexType InDims, IndexType OutDims>
|
||||||
|
class AffineTransform<InDims, OutDims, std::enable_if_t<(ceil_to_multiple<IndexType>(InDims, MaxSimdWidth) < LargeInputSize)>> {
|
||||||
public:
|
public:
|
||||||
// Input/output type
|
// Input/output type
|
||||||
using InputType = typename PreviousLayer::OutputType;
|
// Input/output type
|
||||||
|
using InputType = std::uint8_t;
|
||||||
using OutputType = std::int32_t;
|
using OutputType = std::int32_t;
|
||||||
static_assert(std::is_same<InputType, std::uint8_t>::value, "");
|
|
||||||
|
|
||||||
// Number of input/output dimensions
|
// Number of input/output dimensions
|
||||||
static constexpr IndexType InputDimensions =
|
static constexpr IndexType InputDimensions = InDims;
|
||||||
PreviousLayer::OutputDimensions;
|
|
||||||
static constexpr IndexType OutputDimensions = OutDims;
|
static constexpr IndexType OutputDimensions = OutDims;
|
||||||
|
|
||||||
static constexpr IndexType PaddedInputDimensions =
|
static constexpr IndexType PaddedInputDimensions =
|
||||||
ceil_to_multiple<IndexType>(InputDimensions, MaxSimdWidth);
|
ceil_to_multiple<IndexType>(InputDimensions, MaxSimdWidth);
|
||||||
|
static constexpr IndexType PaddedOutputDimensions =
|
||||||
|
ceil_to_multiple<IndexType>(OutputDimensions, MaxSimdWidth);
|
||||||
|
|
||||||
static_assert(PaddedInputDimensions < 128, "Something went wrong. This specialization should not have been chosen.");
|
using OutputBuffer = OutputType[PaddedOutputDimensions];
|
||||||
|
|
||||||
#if defined (USE_SSSE3)
|
static_assert(PaddedInputDimensions < LargeInputSize, "Something went wrong. This specialization (for small inputs) should not have been chosen.");
|
||||||
static constexpr const IndexType OutputSimdWidth = SimdWidth / 4;
|
|
||||||
static constexpr const IndexType InputSimdWidth = SimdWidth;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Size of forward propagation buffer used in this layer
|
|
||||||
static constexpr std::size_t SelfBufferSize =
|
|
||||||
ceil_to_multiple(OutputDimensions * sizeof(OutputType), CacheLineSize);
|
|
||||||
|
|
||||||
// Size of the forward propagation buffer used from the input layer to this layer
|
|
||||||
static constexpr std::size_t BufferSize =
|
|
||||||
PreviousLayer::BufferSize + SelfBufferSize;
|
|
||||||
|
|
||||||
// Hash value embedded in the evaluation file
|
// Hash value embedded in the evaluation file
|
||||||
static constexpr std::uint32_t get_hash_value() {
|
static constexpr std::uint32_t get_hash_value(std::uint32_t prevHash) {
|
||||||
std::uint32_t hashValue = 0xCC03DAE4u;
|
std::uint32_t hashValue = 0xCC03DAE4u;
|
||||||
hashValue += OutputDimensions;
|
hashValue += OutputDimensions;
|
||||||
hashValue ^= PreviousLayer::get_hash_value() >> 1;
|
hashValue ^= prevHash >> 1;
|
||||||
hashValue ^= PreviousLayer::get_hash_value() << 31;
|
hashValue ^= prevHash << 31;
|
||||||
return hashValue;
|
return hashValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -429,10 +445,8 @@ namespace Stockfish::Eval::NNUE::Layers {
|
|||||||
|
|
||||||
// Read network parameters
|
// Read network parameters
|
||||||
bool read_parameters(std::istream& stream) {
|
bool read_parameters(std::istream& stream) {
|
||||||
if (!previousLayer.read_parameters(stream)) return false;
|
read_little_endian<BiasType>(stream, biases, OutputDimensions);
|
||||||
for (std::size_t i = 0; i < OutputDimensions; ++i)
|
for (IndexType i = 0; i < OutputDimensions * PaddedInputDimensions; ++i)
|
||||||
biases[i] = read_little_endian<BiasType>(stream);
|
|
||||||
for (std::size_t i = 0; i < OutputDimensions * PaddedInputDimensions; ++i)
|
|
||||||
weights[get_weight_index(i)] = read_little_endian<WeightType>(stream);
|
weights[get_weight_index(i)] = read_little_endian<WeightType>(stream);
|
||||||
|
|
||||||
return !stream.fail();
|
return !stream.fail();
|
||||||
@@ -440,51 +454,50 @@ namespace Stockfish::Eval::NNUE::Layers {
|
|||||||
|
|
||||||
// Write network parameters
|
// Write network parameters
|
||||||
bool write_parameters(std::ostream& stream) const {
|
bool write_parameters(std::ostream& stream) const {
|
||||||
if (!previousLayer.write_parameters(stream)) return false;
|
write_little_endian<BiasType>(stream, biases, OutputDimensions);
|
||||||
for (std::size_t i = 0; i < OutputDimensions; ++i)
|
|
||||||
write_little_endian<BiasType>(stream, biases[i]);
|
|
||||||
|
|
||||||
for (std::size_t i = 0; i < OutputDimensions * PaddedInputDimensions; ++i)
|
for (IndexType i = 0; i < OutputDimensions * PaddedInputDimensions; ++i)
|
||||||
write_little_endian<WeightType>(stream, weights[get_weight_index(i)]);
|
write_little_endian<WeightType>(stream, weights[get_weight_index(i)]);
|
||||||
|
|
||||||
return !stream.fail();
|
return !stream.fail();
|
||||||
}
|
}
|
||||||
// Forward propagation
|
// Forward propagation
|
||||||
const OutputType* propagate(
|
const OutputType* propagate(
|
||||||
const TransformedFeatureType* transformedFeatures, char* buffer) const {
|
const InputType* input, OutputType* output) const {
|
||||||
const auto input = previousLayer.propagate(
|
|
||||||
transformedFeatures, buffer + SelfBufferSize);
|
|
||||||
const auto output = reinterpret_cast<OutputType*>(buffer);
|
|
||||||
|
|
||||||
#if defined (USE_AVX2)
|
#if defined (USE_AVX512)
|
||||||
|
using vec_t = __m512i;
|
||||||
|
#define vec_setzero _mm512_setzero_si512
|
||||||
|
#define vec_set_32 _mm512_set1_epi32
|
||||||
|
#define vec_add_dpbusd_32 Simd::m512_add_dpbusd_epi32
|
||||||
|
#define vec_add_dpbusd_32x2 Simd::m512_add_dpbusd_epi32x2
|
||||||
|
#define vec_hadd Simd::m512_hadd
|
||||||
|
#elif defined (USE_AVX2)
|
||||||
using vec_t = __m256i;
|
using vec_t = __m256i;
|
||||||
#define vec_setzero _mm256_setzero_si256
|
#define vec_setzero _mm256_setzero_si256
|
||||||
#define vec_set_32 _mm256_set1_epi32
|
#define vec_set_32 _mm256_set1_epi32
|
||||||
#define vec_add_dpbusd_32 Simd::m256_add_dpbusd_epi32
|
#define vec_add_dpbusd_32 Simd::m256_add_dpbusd_epi32
|
||||||
#define vec_add_dpbusd_32x2 Simd::m256_add_dpbusd_epi32x2
|
#define vec_add_dpbusd_32x2 Simd::m256_add_dpbusd_epi32x2
|
||||||
#define vec_add_dpbusd_32x4 Simd::m256_add_dpbusd_epi32x4
|
|
||||||
#define vec_hadd Simd::m256_hadd
|
#define vec_hadd Simd::m256_hadd
|
||||||
#define vec_haddx4 Simd::m256_haddx4
|
|
||||||
#elif defined (USE_SSSE3)
|
#elif defined (USE_SSSE3)
|
||||||
using vec_t = __m128i;
|
using vec_t = __m128i;
|
||||||
#define vec_setzero _mm_setzero_si128
|
#define vec_setzero _mm_setzero_si128
|
||||||
#define vec_set_32 _mm_set1_epi32
|
#define vec_set_32 _mm_set1_epi32
|
||||||
#define vec_add_dpbusd_32 Simd::m128_add_dpbusd_epi32
|
#define vec_add_dpbusd_32 Simd::m128_add_dpbusd_epi32
|
||||||
#define vec_add_dpbusd_32x2 Simd::m128_add_dpbusd_epi32x2
|
#define vec_add_dpbusd_32x2 Simd::m128_add_dpbusd_epi32x2
|
||||||
#define vec_add_dpbusd_32x4 Simd::m128_add_dpbusd_epi32x4
|
|
||||||
#define vec_hadd Simd::m128_hadd
|
#define vec_hadd Simd::m128_hadd
|
||||||
#define vec_haddx4 Simd::m128_haddx4
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined (USE_SSSE3)
|
#if defined (USE_SSSE3)
|
||||||
const auto inputVector = reinterpret_cast<const vec_t*>(input);
|
const auto inputVector = reinterpret_cast<const vec_t*>(input);
|
||||||
|
|
||||||
static_assert(InputDimensions % 8 == 0);
|
static constexpr IndexType OutputSimdWidth = sizeof(vec_t) / sizeof(OutputType);
|
||||||
|
|
||||||
static_assert(OutputDimensions % OutputSimdWidth == 0 || OutputDimensions == 1);
|
static_assert(OutputDimensions % OutputSimdWidth == 0 || OutputDimensions == 1);
|
||||||
|
|
||||||
if constexpr (OutputDimensions % OutputSimdWidth == 0)
|
if constexpr (OutputDimensions % OutputSimdWidth == 0)
|
||||||
{
|
{
|
||||||
constexpr IndexType NumChunks = InputDimensions / 4;
|
constexpr IndexType NumChunks = ceil_to_multiple<IndexType>(InputDimensions, 8) / 4;
|
||||||
constexpr IndexType NumRegs = OutputDimensions / OutputSimdWidth;
|
constexpr IndexType NumRegs = OutputDimensions / OutputSimdWidth;
|
||||||
|
|
||||||
const auto input32 = reinterpret_cast<const std::int32_t*>(input);
|
const auto input32 = reinterpret_cast<const std::int32_t*>(input);
|
||||||
@@ -525,9 +538,7 @@ namespace Stockfish::Eval::NNUE::Layers {
|
|||||||
# undef vec_set_32
|
# undef vec_set_32
|
||||||
# undef vec_add_dpbusd_32
|
# undef vec_add_dpbusd_32
|
||||||
# undef vec_add_dpbusd_32x2
|
# undef vec_add_dpbusd_32x2
|
||||||
# undef vec_add_dpbusd_32x4
|
|
||||||
# undef vec_hadd
|
# undef vec_hadd
|
||||||
# undef vec_haddx4
|
|
||||||
#else
|
#else
|
||||||
// Use old implementation for the other architectures.
|
// Use old implementation for the other architectures.
|
||||||
affine_transform_non_ssse3<
|
affine_transform_non_ssse3<
|
||||||
@@ -543,8 +554,6 @@ namespace Stockfish::Eval::NNUE::Layers {
|
|||||||
using BiasType = OutputType;
|
using BiasType = OutputType;
|
||||||
using WeightType = std::int8_t;
|
using WeightType = std::int8_t;
|
||||||
|
|
||||||
PreviousLayer previousLayer;
|
|
||||||
|
|
||||||
alignas(CacheLineSize) BiasType biases[OutputDimensions];
|
alignas(CacheLineSize) BiasType biases[OutputDimensions];
|
||||||
alignas(CacheLineSize) WeightType weights[OutputDimensions * PaddedInputDimensions];
|
alignas(CacheLineSize) WeightType weights[OutputDimensions * PaddedInputDimensions];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,286 @@
|
|||||||
|
/*
|
||||||
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Stockfish is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Definition of layer AffineTransformSparseInput of NNUE evaluation function
|
||||||
|
|
||||||
|
#ifndef NNUE_LAYERS_AFFINE_TRANSFORM_SPARSE_INPUT_H_INCLUDED
|
||||||
|
#define NNUE_LAYERS_AFFINE_TRANSFORM_SPARSE_INPUT_H_INCLUDED
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
|
#include <type_traits>
|
||||||
|
#include "../nnue_common.h"
|
||||||
|
#include "affine_transform.h"
|
||||||
|
#include "simd.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file contains the definition for a fully connected layer (aka affine transform) with block sparse input.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Stockfish::Eval::NNUE::Layers {
|
||||||
|
#if defined(__GNUC__) // GCC, Clang, ICC
|
||||||
|
|
||||||
|
static inline IndexType lsb_(std::uint32_t b) {
|
||||||
|
assert(b);
|
||||||
|
return IndexType(__builtin_ctzl(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(_MSC_VER) // MSVC
|
||||||
|
|
||||||
|
static inline IndexType lsb_(std::uint32_t b) {
|
||||||
|
assert(b);
|
||||||
|
unsigned long idx;
|
||||||
|
_BitScanForward(&idx, b);
|
||||||
|
return (IndexType) idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // Compiler is neither GCC nor MSVC compatible
|
||||||
|
|
||||||
|
#error "Compiler not supported."
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(USE_SSSE3)
|
||||||
|
alignas(CacheLineSize) static inline const std::array<std::array<std::uint16_t, 8>, 256> lookup_indices = [](){
|
||||||
|
std::array<std::array<std::uint16_t, 8>, 256> v{};
|
||||||
|
for (int i = 0; i < 256; ++i)
|
||||||
|
{
|
||||||
|
int j = i;
|
||||||
|
int k = 0;
|
||||||
|
while(j)
|
||||||
|
{
|
||||||
|
const IndexType lsbIndex = lsb_(std::uint32_t(j));
|
||||||
|
j &= j - 1;
|
||||||
|
v[i][k] = lsbIndex;
|
||||||
|
++k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}();
|
||||||
|
alignas(CacheLineSize) static inline const std::array<unsigned, 256> lookup_count = [](){
|
||||||
|
std::array<unsigned, 256> v;
|
||||||
|
for (int i = 0; i < 256; ++i)
|
||||||
|
{
|
||||||
|
int j = i;
|
||||||
|
int k = 0;
|
||||||
|
while(j)
|
||||||
|
{
|
||||||
|
j &= j - 1;
|
||||||
|
++k;
|
||||||
|
}
|
||||||
|
v[i] = k;
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}();
|
||||||
|
|
||||||
|
// Find indices of nonzero numbers in an int32_t array
|
||||||
|
template<const IndexType InputDimensions>
|
||||||
|
void find_nnz(const std::int32_t* input, std::uint16_t* out, IndexType& count_out) {
|
||||||
|
#if defined (USE_AVX512)
|
||||||
|
using vec_t = __m512i;
|
||||||
|
#define vec_nnz(a) _mm512_cmpgt_epi32_mask(a, _mm512_setzero_si512())
|
||||||
|
#elif defined (USE_AVX2)
|
||||||
|
using vec_t = __m256i;
|
||||||
|
#define vec_nnz(a) _mm256_movemask_ps(_mm256_castsi256_ps(_mm256_cmpgt_epi32(a, _mm256_setzero_si256())))
|
||||||
|
#elif defined (USE_SSSE3)
|
||||||
|
using vec_t = __m128i;
|
||||||
|
#define vec_nnz(a) _mm_movemask_ps(_mm_castsi128_ps(_mm_cmpgt_epi32(a, _mm_setzero_si128())))
|
||||||
|
#endif
|
||||||
|
constexpr IndexType InputSimdWidth = sizeof(vec_t) / sizeof(std::int32_t);
|
||||||
|
// Inputs are processed InputSimdWidth at a time and outputs are processed 8 at a time so we process in chunks of max(InputSimdWidth, 8)
|
||||||
|
constexpr IndexType ChunkSize = std::max<IndexType>(InputSimdWidth, 8);
|
||||||
|
constexpr IndexType NumChunks = InputDimensions / ChunkSize;
|
||||||
|
constexpr IndexType InputsPerChunk = ChunkSize / InputSimdWidth;
|
||||||
|
constexpr IndexType OutputsPerChunk = ChunkSize / 8;
|
||||||
|
|
||||||
|
const auto inputVector = reinterpret_cast<const vec_t*>(input);
|
||||||
|
IndexType count = 0;
|
||||||
|
__m128i base = _mm_set1_epi16(0);
|
||||||
|
__m128i increment = _mm_set1_epi16(8);
|
||||||
|
for (IndexType i = 0; i < NumChunks; ++i)
|
||||||
|
{
|
||||||
|
// bitmask of nonzero values in this chunk
|
||||||
|
unsigned nnz = 0;
|
||||||
|
for (IndexType j = 0; j < InputsPerChunk; ++j)
|
||||||
|
{
|
||||||
|
const vec_t inputChunk = inputVector[i * InputsPerChunk + j];
|
||||||
|
nnz |= (unsigned)vec_nnz(inputChunk) << (j * InputSimdWidth);
|
||||||
|
}
|
||||||
|
for (IndexType j = 0; j < OutputsPerChunk; ++j)
|
||||||
|
{
|
||||||
|
const auto lookup = (nnz >> (j * 8)) & 0xFF;
|
||||||
|
const auto offsets = _mm_loadu_si128(reinterpret_cast<const __m128i*>(&lookup_indices[lookup]));
|
||||||
|
_mm_storeu_si128(reinterpret_cast<__m128i*>(out + count), _mm_add_epi16(base, offsets));
|
||||||
|
count += lookup_count[lookup];
|
||||||
|
base = _mm_add_epi16(base, increment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
count_out = count;
|
||||||
|
}
|
||||||
|
# undef vec_nnz
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Sparse input implementation
|
||||||
|
template <IndexType InDims, IndexType OutDims>
|
||||||
|
class AffineTransformSparseInput {
|
||||||
|
public:
|
||||||
|
// Input/output type
|
||||||
|
// Input/output type
|
||||||
|
using InputType = std::uint8_t;
|
||||||
|
using OutputType = std::int32_t;
|
||||||
|
|
||||||
|
// Number of input/output dimensions
|
||||||
|
static constexpr IndexType InputDimensions = InDims;
|
||||||
|
static constexpr IndexType OutputDimensions = OutDims;
|
||||||
|
|
||||||
|
static_assert(OutputDimensions % 16 == 0, "Only implemented for OutputDimensions divisible by 16.");
|
||||||
|
|
||||||
|
static constexpr IndexType PaddedInputDimensions =
|
||||||
|
ceil_to_multiple<IndexType>(InputDimensions, MaxSimdWidth);
|
||||||
|
static constexpr IndexType PaddedOutputDimensions =
|
||||||
|
ceil_to_multiple<IndexType>(OutputDimensions, MaxSimdWidth);
|
||||||
|
|
||||||
|
#if defined (USE_SSSE3)
|
||||||
|
static constexpr IndexType ChunkSize = 4;
|
||||||
|
#else
|
||||||
|
static constexpr IndexType ChunkSize = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using OutputBuffer = OutputType[PaddedOutputDimensions];
|
||||||
|
|
||||||
|
// Hash value embedded in the evaluation file
|
||||||
|
static constexpr std::uint32_t get_hash_value(std::uint32_t prevHash) {
|
||||||
|
std::uint32_t hashValue = 0xCC03DAE4u;
|
||||||
|
hashValue += OutputDimensions;
|
||||||
|
hashValue ^= prevHash >> 1;
|
||||||
|
hashValue ^= prevHash << 31;
|
||||||
|
return hashValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static IndexType get_weight_index_scrambled(IndexType i)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
(i / ChunkSize) % (PaddedInputDimensions / ChunkSize) * OutputDimensions * ChunkSize +
|
||||||
|
i / PaddedInputDimensions * ChunkSize +
|
||||||
|
i % ChunkSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
static IndexType get_weight_index(IndexType i)
|
||||||
|
{
|
||||||
|
#if defined (USE_SSSE3)
|
||||||
|
return get_weight_index_scrambled(i);
|
||||||
|
#else
|
||||||
|
return i;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read network parameters
|
||||||
|
bool read_parameters(std::istream& stream) {
|
||||||
|
read_little_endian<BiasType>(stream, biases, OutputDimensions);
|
||||||
|
for (IndexType i = 0; i < OutputDimensions * PaddedInputDimensions; ++i)
|
||||||
|
weights[get_weight_index(i)] = read_little_endian<WeightType>(stream);
|
||||||
|
|
||||||
|
return !stream.fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write network parameters
|
||||||
|
bool write_parameters(std::ostream& stream) const {
|
||||||
|
write_little_endian<BiasType>(stream, biases, OutputDimensions);
|
||||||
|
|
||||||
|
for (IndexType i = 0; i < OutputDimensions * PaddedInputDimensions; ++i)
|
||||||
|
write_little_endian<WeightType>(stream, weights[get_weight_index(i)]);
|
||||||
|
|
||||||
|
return !stream.fail();
|
||||||
|
}
|
||||||
|
// Forward propagation
|
||||||
|
const OutputType* propagate(
|
||||||
|
const InputType* input, OutputType* output) const {
|
||||||
|
|
||||||
|
#if defined (USE_SSSE3)
|
||||||
|
#if defined (USE_AVX512)
|
||||||
|
using vec_t = __m512i;
|
||||||
|
#define vec_setzero _mm512_setzero_si512
|
||||||
|
#define vec_set_32 _mm512_set1_epi32
|
||||||
|
#define vec_add_dpbusd_32 Simd::m512_add_dpbusd_epi32
|
||||||
|
#elif defined (USE_AVX2)
|
||||||
|
using vec_t = __m256i;
|
||||||
|
#define vec_setzero _mm256_setzero_si256
|
||||||
|
#define vec_set_32 _mm256_set1_epi32
|
||||||
|
#define vec_add_dpbusd_32 Simd::m256_add_dpbusd_epi32
|
||||||
|
#elif defined (USE_SSSE3)
|
||||||
|
using vec_t = __m128i;
|
||||||
|
#define vec_setzero _mm_setzero_si128
|
||||||
|
#define vec_set_32 _mm_set1_epi32
|
||||||
|
#define vec_add_dpbusd_32 Simd::m128_add_dpbusd_epi32
|
||||||
|
#endif
|
||||||
|
static constexpr IndexType OutputSimdWidth = sizeof(vec_t) / sizeof(OutputType);
|
||||||
|
|
||||||
|
constexpr IndexType NumChunks = ceil_to_multiple<IndexType>(InputDimensions, 8) / ChunkSize;
|
||||||
|
constexpr IndexType NumRegs = OutputDimensions / OutputSimdWidth;
|
||||||
|
std::uint16_t nnz[NumChunks];
|
||||||
|
IndexType count;
|
||||||
|
|
||||||
|
const auto input32 = reinterpret_cast<const std::int32_t*>(input);
|
||||||
|
|
||||||
|
// Find indices of nonzero 32bit blocks
|
||||||
|
find_nnz<NumChunks>(input32, nnz, count);
|
||||||
|
|
||||||
|
const vec_t* biasvec = reinterpret_cast<const vec_t*>(biases);
|
||||||
|
vec_t acc[NumRegs];
|
||||||
|
for (IndexType k = 0; k < NumRegs; ++k)
|
||||||
|
acc[k] = biasvec[k];
|
||||||
|
|
||||||
|
for (IndexType j = 0; j < count; ++j)
|
||||||
|
{
|
||||||
|
const auto i = nnz[j];
|
||||||
|
const vec_t in = vec_set_32(input32[i]);
|
||||||
|
const auto col = reinterpret_cast<const vec_t*>(&weights[i * OutputDimensions * ChunkSize]);
|
||||||
|
for (IndexType k = 0; k < NumRegs; ++k)
|
||||||
|
vec_add_dpbusd_32(acc[k], in, col[k]);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec_t* outptr = reinterpret_cast<vec_t*>(output);
|
||||||
|
for (IndexType k = 0; k < NumRegs; ++k)
|
||||||
|
outptr[k] = acc[k];
|
||||||
|
# undef vec_setzero
|
||||||
|
# undef vec_set_32
|
||||||
|
# undef vec_add_dpbusd_32
|
||||||
|
#else
|
||||||
|
// Use dense implementation for the other architectures.
|
||||||
|
affine_transform_non_ssse3<
|
||||||
|
InputDimensions,
|
||||||
|
PaddedInputDimensions,
|
||||||
|
OutputDimensions>(output, weights, biases, input);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
using BiasType = OutputType;
|
||||||
|
using WeightType = std::int8_t;
|
||||||
|
|
||||||
|
alignas(CacheLineSize) BiasType biases[OutputDimensions];
|
||||||
|
alignas(CacheLineSize) WeightType weights[OutputDimensions * PaddedInputDimensions];
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Stockfish::Eval::NNUE::Layers
|
||||||
|
|
||||||
|
#endif // #ifndef NNUE_LAYERS_AFFINE_TRANSFORM_SPARSE_INPUT_H_INCLUDED
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -26,51 +26,41 @@
|
|||||||
namespace Stockfish::Eval::NNUE::Layers {
|
namespace Stockfish::Eval::NNUE::Layers {
|
||||||
|
|
||||||
// Clipped ReLU
|
// Clipped ReLU
|
||||||
template <typename PreviousLayer>
|
template <IndexType InDims>
|
||||||
class ClippedReLU {
|
class ClippedReLU {
|
||||||
public:
|
public:
|
||||||
// Input/output type
|
// Input/output type
|
||||||
using InputType = typename PreviousLayer::OutputType;
|
using InputType = std::int32_t;
|
||||||
using OutputType = std::uint8_t;
|
using OutputType = std::uint8_t;
|
||||||
static_assert(std::is_same<InputType, std::int32_t>::value, "");
|
|
||||||
|
|
||||||
// Number of input/output dimensions
|
// Number of input/output dimensions
|
||||||
static constexpr IndexType InputDimensions = PreviousLayer::OutputDimensions;
|
static constexpr IndexType InputDimensions = InDims;
|
||||||
static constexpr IndexType OutputDimensions = InputDimensions;
|
static constexpr IndexType OutputDimensions = InputDimensions;
|
||||||
static constexpr IndexType PaddedOutputDimensions =
|
static constexpr IndexType PaddedOutputDimensions =
|
||||||
ceil_to_multiple<IndexType>(OutputDimensions, 32);
|
ceil_to_multiple<IndexType>(OutputDimensions, 32);
|
||||||
|
|
||||||
// Size of forward propagation buffer used in this layer
|
using OutputBuffer = OutputType[PaddedOutputDimensions];
|
||||||
static constexpr std::size_t SelfBufferSize =
|
|
||||||
ceil_to_multiple(OutputDimensions * sizeof(OutputType), CacheLineSize);
|
|
||||||
|
|
||||||
// Size of the forward propagation buffer used from the input layer to this layer
|
|
||||||
static constexpr std::size_t BufferSize =
|
|
||||||
PreviousLayer::BufferSize + SelfBufferSize;
|
|
||||||
|
|
||||||
// Hash value embedded in the evaluation file
|
// Hash value embedded in the evaluation file
|
||||||
static constexpr std::uint32_t get_hash_value() {
|
static constexpr std::uint32_t get_hash_value(std::uint32_t prevHash) {
|
||||||
std::uint32_t hashValue = 0x538D24C7u;
|
std::uint32_t hashValue = 0x538D24C7u;
|
||||||
hashValue += PreviousLayer::get_hash_value();
|
hashValue += prevHash;
|
||||||
return hashValue;
|
return hashValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read network parameters
|
// Read network parameters
|
||||||
bool read_parameters(std::istream& stream) {
|
bool read_parameters(std::istream&) {
|
||||||
return previousLayer.read_parameters(stream);
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write network parameters
|
// Write network parameters
|
||||||
bool write_parameters(std::ostream& stream) const {
|
bool write_parameters(std::ostream&) const {
|
||||||
return previousLayer.write_parameters(stream);
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Forward propagation
|
// Forward propagation
|
||||||
const OutputType* propagate(
|
const OutputType* propagate(
|
||||||
const TransformedFeatureType* transformedFeatures, char* buffer) const {
|
const InputType* input, OutputType* output) const {
|
||||||
const auto input = previousLayer.propagate(
|
|
||||||
transformedFeatures, buffer + SelfBufferSize);
|
|
||||||
const auto output = reinterpret_cast<OutputType*>(buffer);
|
|
||||||
|
|
||||||
#if defined(USE_AVX2)
|
#if defined(USE_AVX2)
|
||||||
if constexpr (InputDimensions % SimdWidth == 0) {
|
if constexpr (InputDimensions % SimdWidth == 0) {
|
||||||
@@ -181,19 +171,8 @@ namespace Stockfish::Eval::NNUE::Layers {
|
|||||||
std::max(0, std::min(127, input[i] >> WeightScaleBits)));
|
std::max(0, std::min(127, input[i] >> WeightScaleBits)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Affine transform layers expect that there is at least
|
|
||||||
// ceil_to_multiple(OutputDimensions, 32) initialized values.
|
|
||||||
// We cannot do this in the affine transform because it requires
|
|
||||||
// preallocating space here.
|
|
||||||
for (IndexType i = OutputDimensions; i < PaddedOutputDimensions; ++i) {
|
|
||||||
output[i] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
PreviousLayer previousLayer;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Stockfish::Eval::NNUE::Layers
|
} // namespace Stockfish::Eval::NNUE::Layers
|
||||||
|
|||||||
@@ -1,73 +0,0 @@
|
|||||||
/*
|
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
Stockfish is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// NNUE evaluation function layer InputSlice definition
|
|
||||||
|
|
||||||
#ifndef NNUE_LAYERS_INPUT_SLICE_H_INCLUDED
|
|
||||||
#define NNUE_LAYERS_INPUT_SLICE_H_INCLUDED
|
|
||||||
|
|
||||||
#include "../nnue_common.h"
|
|
||||||
|
|
||||||
namespace Stockfish::Eval::NNUE::Layers {
|
|
||||||
|
|
||||||
// Input layer
|
|
||||||
template <IndexType OutDims, IndexType Offset = 0>
|
|
||||||
class InputSlice {
|
|
||||||
public:
|
|
||||||
// Need to maintain alignment
|
|
||||||
static_assert(Offset % MaxSimdWidth == 0, "");
|
|
||||||
|
|
||||||
// Output type
|
|
||||||
using OutputType = TransformedFeatureType;
|
|
||||||
|
|
||||||
// Output dimensionality
|
|
||||||
static constexpr IndexType OutputDimensions = OutDims;
|
|
||||||
|
|
||||||
// Size of forward propagation buffer used from the input layer to this layer
|
|
||||||
static constexpr std::size_t BufferSize = 0;
|
|
||||||
|
|
||||||
// Hash value embedded in the evaluation file
|
|
||||||
static constexpr std::uint32_t get_hash_value() {
|
|
||||||
std::uint32_t hashValue = 0xEC42E90Du;
|
|
||||||
hashValue ^= OutputDimensions ^ (Offset << 10);
|
|
||||||
return hashValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read network parameters
|
|
||||||
bool read_parameters(std::istream& /*stream*/) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write network parameters
|
|
||||||
bool write_parameters(std::ostream& /*stream*/) const {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Forward propagation
|
|
||||||
const OutputType* propagate(
|
|
||||||
const TransformedFeatureType* transformedFeatures,
|
|
||||||
char* /*buffer*/) const {
|
|
||||||
return transformedFeatures + Offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Stockfish::Eval::NNUE::Layers
|
|
||||||
|
|
||||||
#endif // #ifndef NNUE_LAYERS_INPUT_SLICE_H_INCLUDED
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -46,6 +46,13 @@
|
|||||||
#define USE_INLINE_ASM
|
#define USE_INLINE_ASM
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Use either the AVX512 or AVX-VNNI version of the VNNI instructions.
|
||||||
|
#if defined(USE_AVXVNNI)
|
||||||
|
#define VNNI_PREFIX "%{vex%} "
|
||||||
|
#else
|
||||||
|
#define VNNI_PREFIX ""
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Stockfish::Simd {
|
namespace Stockfish::Simd {
|
||||||
|
|
||||||
#if defined (USE_AVX512)
|
#if defined (USE_AVX512)
|
||||||
@@ -146,7 +153,7 @@ namespace Stockfish::Simd {
|
|||||||
asm(
|
asm(
|
||||||
"vpdpbusd %[b0], %[a0], %[acc]\n\t"
|
"vpdpbusd %[b0], %[a0], %[acc]\n\t"
|
||||||
"vpdpbusd %[b1], %[a1], %[acc]\n\t"
|
"vpdpbusd %[b1], %[a1], %[acc]\n\t"
|
||||||
: [acc]"+v"(acc)
|
: [acc]"+&v"(acc)
|
||||||
: [a0]"v"(a0), [b0]"vm"(b0), [a1]"v"(a1), [b1]"vm"(b1)
|
: [a0]"v"(a0), [b0]"vm"(b0), [a1]"v"(a1), [b1]"vm"(b1)
|
||||||
);
|
);
|
||||||
# else
|
# else
|
||||||
@@ -158,18 +165,19 @@ namespace Stockfish::Simd {
|
|||||||
__m512i tmp0 = _mm512_maddubs_epi16(a0, b0);
|
__m512i tmp0 = _mm512_maddubs_epi16(a0, b0);
|
||||||
__m512i tmp1 = _mm512_maddubs_epi16(a1, b1);
|
__m512i tmp1 = _mm512_maddubs_epi16(a1, b1);
|
||||||
asm(
|
asm(
|
||||||
"vpaddsw %[tmp0], %[tmp1], %[tmp0]\n\t"
|
|
||||||
"vpmaddwd %[tmp0], %[ones], %[tmp0]\n\t"
|
"vpmaddwd %[tmp0], %[ones], %[tmp0]\n\t"
|
||||||
|
"vpmaddwd %[tmp1], %[ones], %[tmp1]\n\t"
|
||||||
|
"vpaddd %[tmp0], %[tmp1], %[tmp0]\n\t"
|
||||||
"vpaddd %[acc], %[tmp0], %[acc]\n\t"
|
"vpaddd %[acc], %[tmp0], %[acc]\n\t"
|
||||||
: [acc]"+v"(acc), [tmp0]"+&v"(tmp0)
|
: [acc]"+v"(acc), [tmp0]"+&v"(tmp0), [tmp1]"+&v"(tmp1)
|
||||||
: [tmp1]"v"(tmp1), [ones]"v"(_mm512_set1_epi16(1))
|
: [ones]"v"(_mm512_set1_epi16(1))
|
||||||
);
|
);
|
||||||
# else
|
# else
|
||||||
__m512i product0 = _mm512_maddubs_epi16(a0, b0);
|
__m512i product0 = _mm512_maddubs_epi16(a0, b0);
|
||||||
__m512i product1 = _mm512_maddubs_epi16(a1, b1);
|
__m512i product1 = _mm512_maddubs_epi16(a1, b1);
|
||||||
product0 = _mm512_adds_epi16(product0, product1);
|
|
||||||
product0 = _mm512_madd_epi16(product0, _mm512_set1_epi16(1));
|
product0 = _mm512_madd_epi16(product0, _mm512_set1_epi16(1));
|
||||||
acc = _mm512_add_epi32(acc, product0);
|
product1 = _mm512_madd_epi16(product1, _mm512_set1_epi16(1));
|
||||||
|
acc = _mm512_add_epi32(acc, _mm512_add_epi32(product0, product1));
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
}
|
}
|
||||||
@@ -208,7 +216,7 @@ namespace Stockfish::Simd {
|
|||||||
# if defined (USE_VNNI)
|
# if defined (USE_VNNI)
|
||||||
# if defined (USE_INLINE_ASM)
|
# if defined (USE_INLINE_ASM)
|
||||||
asm(
|
asm(
|
||||||
"vpdpbusd %[b], %[a], %[acc]\n\t"
|
VNNI_PREFIX "vpdpbusd %[b], %[a], %[acc]\n\t"
|
||||||
: [acc]"+v"(acc)
|
: [acc]"+v"(acc)
|
||||||
: [a]"v"(a), [b]"vm"(b)
|
: [a]"v"(a), [b]"vm"(b)
|
||||||
);
|
);
|
||||||
@@ -240,9 +248,9 @@ namespace Stockfish::Simd {
|
|||||||
# if defined (USE_VNNI)
|
# if defined (USE_VNNI)
|
||||||
# if defined (USE_INLINE_ASM)
|
# if defined (USE_INLINE_ASM)
|
||||||
asm(
|
asm(
|
||||||
"vpdpbusd %[b0], %[a0], %[acc]\n\t"
|
VNNI_PREFIX "vpdpbusd %[b0], %[a0], %[acc]\n\t"
|
||||||
"vpdpbusd %[b1], %[a1], %[acc]\n\t"
|
VNNI_PREFIX "vpdpbusd %[b1], %[a1], %[acc]\n\t"
|
||||||
: [acc]"+v"(acc)
|
: [acc]"+&v"(acc)
|
||||||
: [a0]"v"(a0), [b0]"vm"(b0), [a1]"v"(a1), [b1]"vm"(b1)
|
: [a0]"v"(a0), [b0]"vm"(b0), [a1]"v"(a1), [b1]"vm"(b1)
|
||||||
);
|
);
|
||||||
# else
|
# else
|
||||||
@@ -254,18 +262,19 @@ namespace Stockfish::Simd {
|
|||||||
__m256i tmp0 = _mm256_maddubs_epi16(a0, b0);
|
__m256i tmp0 = _mm256_maddubs_epi16(a0, b0);
|
||||||
__m256i tmp1 = _mm256_maddubs_epi16(a1, b1);
|
__m256i tmp1 = _mm256_maddubs_epi16(a1, b1);
|
||||||
asm(
|
asm(
|
||||||
"vpaddsw %[tmp0], %[tmp1], %[tmp0]\n\t"
|
|
||||||
"vpmaddwd %[tmp0], %[ones], %[tmp0]\n\t"
|
"vpmaddwd %[tmp0], %[ones], %[tmp0]\n\t"
|
||||||
|
"vpmaddwd %[tmp1], %[ones], %[tmp1]\n\t"
|
||||||
|
"vpaddd %[tmp0], %[tmp1], %[tmp0]\n\t"
|
||||||
"vpaddd %[acc], %[tmp0], %[acc]\n\t"
|
"vpaddd %[acc], %[tmp0], %[acc]\n\t"
|
||||||
: [acc]"+v"(acc), [tmp0]"+&v"(tmp0)
|
: [acc]"+v"(acc), [tmp0]"+&v"(tmp0), [tmp1]"+&v"(tmp1)
|
||||||
: [tmp1]"v"(tmp1), [ones]"v"(_mm256_set1_epi16(1))
|
: [ones]"v"(_mm256_set1_epi16(1))
|
||||||
);
|
);
|
||||||
# else
|
# else
|
||||||
__m256i product0 = _mm256_maddubs_epi16(a0, b0);
|
__m256i product0 = _mm256_maddubs_epi16(a0, b0);
|
||||||
__m256i product1 = _mm256_maddubs_epi16(a1, b1);
|
__m256i product1 = _mm256_maddubs_epi16(a1, b1);
|
||||||
product0 = _mm256_adds_epi16(product0, product1);
|
|
||||||
product0 = _mm256_madd_epi16(product0, _mm256_set1_epi16(1));
|
product0 = _mm256_madd_epi16(product0, _mm256_set1_epi16(1));
|
||||||
acc = _mm256_add_epi32(acc, product0);
|
product1 = _mm256_madd_epi16(product1, _mm256_set1_epi16(1));
|
||||||
|
acc = _mm256_add_epi32(acc, _mm256_add_epi32(product0, product1));
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
}
|
}
|
||||||
@@ -319,23 +328,76 @@ namespace Stockfish::Simd {
|
|||||||
__m128i tmp0 = _mm_maddubs_epi16(a0, b0);
|
__m128i tmp0 = _mm_maddubs_epi16(a0, b0);
|
||||||
__m128i tmp1 = _mm_maddubs_epi16(a1, b1);
|
__m128i tmp1 = _mm_maddubs_epi16(a1, b1);
|
||||||
asm(
|
asm(
|
||||||
"paddsw %[tmp1], %[tmp0]\n\t"
|
|
||||||
"pmaddwd %[ones], %[tmp0]\n\t"
|
"pmaddwd %[ones], %[tmp0]\n\t"
|
||||||
|
"pmaddwd %[ones], %[tmp1]\n\t"
|
||||||
|
"paddd %[tmp1], %[tmp0]\n\t"
|
||||||
"paddd %[tmp0], %[acc]\n\t"
|
"paddd %[tmp0], %[acc]\n\t"
|
||||||
: [acc]"+v"(acc), [tmp0]"+&v"(tmp0)
|
: [acc]"+v"(acc), [tmp0]"+&v"(tmp0), [tmp1]"+&v"(tmp1)
|
||||||
: [tmp1]"v"(tmp1), [ones]"v"(_mm_set1_epi16(1))
|
: [ones]"v"(_mm_set1_epi16(1))
|
||||||
);
|
);
|
||||||
# else
|
# else
|
||||||
__m128i product0 = _mm_maddubs_epi16(a0, b0);
|
__m128i product0 = _mm_maddubs_epi16(a0, b0);
|
||||||
__m128i product1 = _mm_maddubs_epi16(a1, b1);
|
__m128i product1 = _mm_maddubs_epi16(a1, b1);
|
||||||
product0 = _mm_adds_epi16(product0, product1);
|
|
||||||
product0 = _mm_madd_epi16(product0, _mm_set1_epi16(1));
|
product0 = _mm_madd_epi16(product0, _mm_set1_epi16(1));
|
||||||
acc = _mm_add_epi32(acc, product0);
|
product1 = _mm_madd_epi16(product1, _mm_set1_epi16(1));
|
||||||
|
acc = _mm_add_epi32(acc, _mm_add_epi32(product0, product1));
|
||||||
# endif
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined (USE_NEON_DOTPROD)
|
||||||
|
|
||||||
|
[[maybe_unused]] static void dotprod_m128_add_dpbusd_epi32x2(
|
||||||
|
int32x4_t& acc,
|
||||||
|
int8x16_t a0, int8x16_t b0,
|
||||||
|
int8x16_t a1, int8x16_t b1) {
|
||||||
|
|
||||||
|
acc = vdotq_s32(acc, a0, b0);
|
||||||
|
acc = vdotq_s32(acc, a1, b1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined (USE_NEON)
|
||||||
|
|
||||||
|
[[maybe_unused]] static int neon_m128_reduce_add_epi32(int32x4_t s) {
|
||||||
|
# if USE_NEON >= 8
|
||||||
|
return vaddvq_s32(s);
|
||||||
|
# else
|
||||||
|
return s[0] + s[1] + s[2] + s[3];
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
|
||||||
|
[[maybe_unused]] static int neon_m128_hadd(int32x4_t sum, int bias) {
|
||||||
|
return neon_m128_reduce_add_epi32(sum) + bias;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[maybe_unused]] static int32x4_t neon_m128_haddx4(
|
||||||
|
int32x4_t sum0, int32x4_t sum1, int32x4_t sum2, int32x4_t sum3,
|
||||||
|
int32x4_t bias) {
|
||||||
|
|
||||||
|
int32x4_t hsums {
|
||||||
|
neon_m128_reduce_add_epi32(sum0),
|
||||||
|
neon_m128_reduce_add_epi32(sum1),
|
||||||
|
neon_m128_reduce_add_epi32(sum2),
|
||||||
|
neon_m128_reduce_add_epi32(sum3)
|
||||||
|
};
|
||||||
|
return vaddq_s32(hsums, bias);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[maybe_unused]] static void neon_m128_add_dpbusd_epi32x2(
|
||||||
|
int32x4_t& acc,
|
||||||
|
int8x8_t a0, int8x8_t b0,
|
||||||
|
int8x8_t a1, int8x8_t b1) {
|
||||||
|
|
||||||
|
int16x8_t product = vmull_s8(a0, b0);
|
||||||
|
product = vmlal_s8(product, a1, b1);
|
||||||
|
acc = vpadalq_s16(acc, product);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // STOCKFISH_SIMD_H_INCLUDED
|
#endif // STOCKFISH_SIMD_H_INCLUDED
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Stockfish is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Definition of layer ClippedReLU of NNUE evaluation function
|
||||||
|
|
||||||
|
#ifndef NNUE_LAYERS_SQR_CLIPPED_RELU_H_INCLUDED
|
||||||
|
#define NNUE_LAYERS_SQR_CLIPPED_RELU_H_INCLUDED
|
||||||
|
|
||||||
|
#include "../nnue_common.h"
|
||||||
|
|
||||||
|
namespace Stockfish::Eval::NNUE::Layers {
|
||||||
|
|
||||||
|
// Clipped ReLU
|
||||||
|
template <IndexType InDims>
|
||||||
|
class SqrClippedReLU {
|
||||||
|
public:
|
||||||
|
// Input/output type
|
||||||
|
using InputType = std::int32_t;
|
||||||
|
using OutputType = std::uint8_t;
|
||||||
|
|
||||||
|
// Number of input/output dimensions
|
||||||
|
static constexpr IndexType InputDimensions = InDims;
|
||||||
|
static constexpr IndexType OutputDimensions = InputDimensions;
|
||||||
|
static constexpr IndexType PaddedOutputDimensions =
|
||||||
|
ceil_to_multiple<IndexType>(OutputDimensions, 32);
|
||||||
|
|
||||||
|
using OutputBuffer = OutputType[PaddedOutputDimensions];
|
||||||
|
|
||||||
|
// Hash value embedded in the evaluation file
|
||||||
|
static constexpr std::uint32_t get_hash_value(std::uint32_t prevHash) {
|
||||||
|
std::uint32_t hashValue = 0x538D24C7u;
|
||||||
|
hashValue += prevHash;
|
||||||
|
return hashValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read network parameters
|
||||||
|
bool read_parameters(std::istream&) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write network parameters
|
||||||
|
bool write_parameters(std::ostream&) const {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forward propagation
|
||||||
|
const OutputType* propagate(
|
||||||
|
const InputType* input, OutputType* output) const {
|
||||||
|
|
||||||
|
#if defined(USE_SSE2)
|
||||||
|
constexpr IndexType NumChunks = InputDimensions / 16;
|
||||||
|
|
||||||
|
#ifdef USE_SSE41
|
||||||
|
const __m128i Zero = _mm_setzero_si128();
|
||||||
|
#else
|
||||||
|
const __m128i k0x80s = _mm_set1_epi8(-128);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static_assert(WeightScaleBits == 6);
|
||||||
|
const auto in = reinterpret_cast<const __m128i*>(input);
|
||||||
|
const auto out = reinterpret_cast<__m128i*>(output);
|
||||||
|
for (IndexType i = 0; i < NumChunks; ++i) {
|
||||||
|
__m128i words0 = _mm_packs_epi32(
|
||||||
|
_mm_load_si128(&in[i * 4 + 0]),
|
||||||
|
_mm_load_si128(&in[i * 4 + 1]));
|
||||||
|
__m128i words1 = _mm_packs_epi32(
|
||||||
|
_mm_load_si128(&in[i * 4 + 2]),
|
||||||
|
_mm_load_si128(&in[i * 4 + 3]));
|
||||||
|
|
||||||
|
// Not sure if
|
||||||
|
words0 = _mm_srli_epi16(_mm_mulhi_epi16(words0, words0), 3);
|
||||||
|
words1 = _mm_srli_epi16(_mm_mulhi_epi16(words1, words1), 3);
|
||||||
|
|
||||||
|
const __m128i packedbytes = _mm_packs_epi16(words0, words1);
|
||||||
|
|
||||||
|
_mm_store_si128(&out[i],
|
||||||
|
|
||||||
|
#ifdef USE_SSE41
|
||||||
|
_mm_max_epi8(packedbytes, Zero)
|
||||||
|
#else
|
||||||
|
_mm_subs_epi8(_mm_adds_epi8(packedbytes, k0x80s), k0x80s)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
||||||
|
constexpr IndexType Start = NumChunks * 16;
|
||||||
|
|
||||||
|
#else
|
||||||
|
constexpr IndexType Start = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (IndexType i = Start; i < InputDimensions; ++i) {
|
||||||
|
output[i] = static_cast<OutputType>(
|
||||||
|
// really should be /127 but we need to make it fast
|
||||||
|
// needs to be accounted for in the trainer
|
||||||
|
std::max(0ll, std::min(127ll, (((long long)input[i] * input[i]) >> (2 * WeightScaleBits)) / 128)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Stockfish::Eval::NNUE::Layers
|
||||||
|
|
||||||
|
#endif // NNUE_LAYERS_SQR_CLIPPED_RELU_H_INCLUDED
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -21,13 +21,18 @@
|
|||||||
#ifndef NNUE_ARCHITECTURE_H_INCLUDED
|
#ifndef NNUE_ARCHITECTURE_H_INCLUDED
|
||||||
#define NNUE_ARCHITECTURE_H_INCLUDED
|
#define NNUE_ARCHITECTURE_H_INCLUDED
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "nnue_common.h"
|
#include "nnue_common.h"
|
||||||
|
|
||||||
#include "features/half_ka_v2_hm.h"
|
#include "features/half_ka_v2_hm.h"
|
||||||
|
|
||||||
#include "layers/input_slice.h"
|
#include "layers/affine_transform_sparse_input.h"
|
||||||
#include "layers/affine_transform.h"
|
#include "layers/affine_transform.h"
|
||||||
#include "layers/clipped_relu.h"
|
#include "layers/clipped_relu.h"
|
||||||
|
#include "layers/sqr_clipped_relu.h"
|
||||||
|
|
||||||
|
#include "../misc.h"
|
||||||
|
|
||||||
namespace Stockfish::Eval::NNUE {
|
namespace Stockfish::Eval::NNUE {
|
||||||
|
|
||||||
@@ -35,25 +40,97 @@ namespace Stockfish::Eval::NNUE {
|
|||||||
using FeatureSet = Features::HalfKAv2_hm;
|
using FeatureSet = Features::HalfKAv2_hm;
|
||||||
|
|
||||||
// Number of input feature dimensions after conversion
|
// Number of input feature dimensions after conversion
|
||||||
constexpr IndexType TransformedFeatureDimensions = 1024;
|
constexpr IndexType TransformedFeatureDimensions = 1536;
|
||||||
constexpr IndexType PSQTBuckets = 8;
|
constexpr IndexType PSQTBuckets = 8;
|
||||||
constexpr IndexType LayerStacks = 8;
|
constexpr IndexType LayerStacks = 8;
|
||||||
|
|
||||||
namespace Layers {
|
struct Network
|
||||||
|
{
|
||||||
|
static constexpr int FC_0_OUTPUTS = 15;
|
||||||
|
static constexpr int FC_1_OUTPUTS = 32;
|
||||||
|
|
||||||
// Define network structure
|
Layers::AffineTransformSparseInput<TransformedFeatureDimensions, FC_0_OUTPUTS + 1> fc_0;
|
||||||
using InputLayer = InputSlice<TransformedFeatureDimensions * 2>;
|
Layers::SqrClippedReLU<FC_0_OUTPUTS + 1> ac_sqr_0;
|
||||||
using HiddenLayer1 = ClippedReLU<AffineTransform<InputLayer, 8>>;
|
Layers::ClippedReLU<FC_0_OUTPUTS + 1> ac_0;
|
||||||
using HiddenLayer2 = ClippedReLU<AffineTransform<HiddenLayer1, 32>>;
|
Layers::AffineTransform<FC_0_OUTPUTS * 2, FC_1_OUTPUTS> fc_1;
|
||||||
using OutputLayer = AffineTransform<HiddenLayer2, 1>;
|
Layers::ClippedReLU<FC_1_OUTPUTS> ac_1;
|
||||||
|
Layers::AffineTransform<FC_1_OUTPUTS, 1> fc_2;
|
||||||
|
|
||||||
} // namespace Layers
|
// Hash value embedded in the evaluation file
|
||||||
|
static constexpr std::uint32_t get_hash_value() {
|
||||||
|
// input slice hash
|
||||||
|
std::uint32_t hashValue = 0xEC42E90Du;
|
||||||
|
hashValue ^= TransformedFeatureDimensions * 2;
|
||||||
|
|
||||||
using Network = Layers::OutputLayer;
|
hashValue = decltype(fc_0)::get_hash_value(hashValue);
|
||||||
|
hashValue = decltype(ac_0)::get_hash_value(hashValue);
|
||||||
|
hashValue = decltype(fc_1)::get_hash_value(hashValue);
|
||||||
|
hashValue = decltype(ac_1)::get_hash_value(hashValue);
|
||||||
|
hashValue = decltype(fc_2)::get_hash_value(hashValue);
|
||||||
|
|
||||||
static_assert(TransformedFeatureDimensions % MaxSimdWidth == 0, "");
|
return hashValue;
|
||||||
static_assert(Network::OutputDimensions == 1, "");
|
}
|
||||||
static_assert(std::is_same<Network::OutputType, std::int32_t>::value, "");
|
|
||||||
|
// Read network parameters
|
||||||
|
bool read_parameters(std::istream& stream) {
|
||||||
|
return fc_0.read_parameters(stream)
|
||||||
|
&& ac_0.read_parameters(stream)
|
||||||
|
&& fc_1.read_parameters(stream)
|
||||||
|
&& ac_1.read_parameters(stream)
|
||||||
|
&& fc_2.read_parameters(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write network parameters
|
||||||
|
bool write_parameters(std::ostream& stream) const {
|
||||||
|
return fc_0.write_parameters(stream)
|
||||||
|
&& ac_0.write_parameters(stream)
|
||||||
|
&& fc_1.write_parameters(stream)
|
||||||
|
&& ac_1.write_parameters(stream)
|
||||||
|
&& fc_2.write_parameters(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::int32_t propagate(const TransformedFeatureType* transformedFeatures)
|
||||||
|
{
|
||||||
|
struct alignas(CacheLineSize) Buffer
|
||||||
|
{
|
||||||
|
alignas(CacheLineSize) decltype(fc_0)::OutputBuffer fc_0_out;
|
||||||
|
alignas(CacheLineSize) decltype(ac_sqr_0)::OutputType ac_sqr_0_out[ceil_to_multiple<IndexType>(FC_0_OUTPUTS * 2, 32)];
|
||||||
|
alignas(CacheLineSize) decltype(ac_0)::OutputBuffer ac_0_out;
|
||||||
|
alignas(CacheLineSize) decltype(fc_1)::OutputBuffer fc_1_out;
|
||||||
|
alignas(CacheLineSize) decltype(ac_1)::OutputBuffer ac_1_out;
|
||||||
|
alignas(CacheLineSize) decltype(fc_2)::OutputBuffer fc_2_out;
|
||||||
|
|
||||||
|
Buffer()
|
||||||
|
{
|
||||||
|
std::memset(this, 0, sizeof(*this));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(__clang__) && (__APPLE__)
|
||||||
|
// workaround for a bug reported with xcode 12
|
||||||
|
static thread_local auto tlsBuffer = std::make_unique<Buffer>();
|
||||||
|
// Access TLS only once, cache result.
|
||||||
|
Buffer& buffer = *tlsBuffer;
|
||||||
|
#else
|
||||||
|
alignas(CacheLineSize) static thread_local Buffer buffer;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
fc_0.propagate(transformedFeatures, buffer.fc_0_out);
|
||||||
|
ac_sqr_0.propagate(buffer.fc_0_out, buffer.ac_sqr_0_out);
|
||||||
|
ac_0.propagate(buffer.fc_0_out, buffer.ac_0_out);
|
||||||
|
std::memcpy(buffer.ac_sqr_0_out + FC_0_OUTPUTS, buffer.ac_0_out, FC_0_OUTPUTS * sizeof(decltype(ac_0)::OutputType));
|
||||||
|
fc_1.propagate(buffer.ac_sqr_0_out, buffer.fc_1_out);
|
||||||
|
ac_1.propagate(buffer.fc_1_out, buffer.ac_1_out);
|
||||||
|
fc_2.propagate(buffer.ac_1_out, buffer.fc_2_out);
|
||||||
|
|
||||||
|
// buffer.fc_0_out[FC_0_OUTPUTS] is such that 1.0 is equal to 127*(1<<WeightScaleBits) in quantized form
|
||||||
|
// but we want 1.0 to be equal to 600*OutputScale
|
||||||
|
std::int32_t fwdOut = int(buffer.fc_0_out[FC_0_OUTPUTS]) * (600*OutputScale) / (127*(1<<WeightScaleBits));
|
||||||
|
std::int32_t outputValue = buffer.fc_2_out[0] + fwdOut;
|
||||||
|
|
||||||
|
return outputValue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Stockfish::Eval::NNUE
|
} // namespace Stockfish::Eval::NNUE
|
||||||
|
|
||||||
|
|||||||
+81
-4
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -57,6 +57,9 @@ namespace Stockfish::Eval::NNUE {
|
|||||||
// Size of cache line (in bytes)
|
// Size of cache line (in bytes)
|
||||||
constexpr std::size_t CacheLineSize = 64;
|
constexpr std::size_t CacheLineSize = 64;
|
||||||
|
|
||||||
|
constexpr const char Leb128MagicString[] = "COMPRESSED_LEB128";
|
||||||
|
constexpr const std::size_t Leb128MagicStringSize = sizeof(Leb128MagicString) - 1;
|
||||||
|
|
||||||
// SIMD width (in bytes)
|
// SIMD width (in bytes)
|
||||||
#if defined(USE_AVX2)
|
#if defined(USE_AVX2)
|
||||||
constexpr std::size_t SimdWidth = 32;
|
constexpr std::size_t SimdWidth = 32;
|
||||||
@@ -109,7 +112,7 @@ namespace Stockfish::Eval::NNUE {
|
|||||||
|
|
||||||
// write_little_endian() is our utility to write an integer (signed or unsigned, any size)
|
// write_little_endian() is our utility to write an integer (signed or unsigned, any size)
|
||||||
// to a stream in little-endian order. We swap the byte order before the write if
|
// to a stream in little-endian order. We swap the byte order before the write if
|
||||||
// necessary to always write in little endian order, independantly of the byte
|
// necessary to always write in little endian order, independently of the byte
|
||||||
// ordering of the compiling machine.
|
// ordering of the compiling machine.
|
||||||
template <typename IntType>
|
template <typename IntType>
|
||||||
inline void write_little_endian(std::ostream& stream, IntType value) {
|
inline void write_little_endian(std::ostream& stream, IntType value) {
|
||||||
@@ -127,11 +130,11 @@ namespace Stockfish::Eval::NNUE {
|
|||||||
{
|
{
|
||||||
for (; i + 1 < sizeof(IntType); ++i)
|
for (; i + 1 < sizeof(IntType); ++i)
|
||||||
{
|
{
|
||||||
u[i] = v;
|
u[i] = (std::uint8_t)v;
|
||||||
v >>= 8;
|
v >>= 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
u[i] = v;
|
u[i] = (std::uint8_t)v;
|
||||||
|
|
||||||
stream.write(reinterpret_cast<char*>(u), sizeof(IntType));
|
stream.write(reinterpret_cast<char*>(u), sizeof(IntType));
|
||||||
}
|
}
|
||||||
@@ -159,6 +162,80 @@ namespace Stockfish::Eval::NNUE {
|
|||||||
write_little_endian<IntType>(stream, values[i]);
|
write_little_endian<IntType>(stream, values[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename IntType>
|
||||||
|
inline void read_leb_128(std::istream& stream, IntType* out, std::size_t count) {
|
||||||
|
static_assert(std::is_signed_v<IntType>, "Not implemented for unsigned types");
|
||||||
|
char leb128MagicString[Leb128MagicStringSize];
|
||||||
|
stream.read(leb128MagicString, Leb128MagicStringSize);
|
||||||
|
assert(strncmp(Leb128MagicString, leb128MagicString, Leb128MagicStringSize) == 0);
|
||||||
|
const std::uint32_t BUF_SIZE = 4096;
|
||||||
|
std::uint8_t buf[BUF_SIZE];
|
||||||
|
auto bytes_left = read_little_endian<std::uint32_t>(stream);
|
||||||
|
std::uint32_t buf_pos = BUF_SIZE;
|
||||||
|
for (std::size_t i = 0; i < count; ++i) {
|
||||||
|
IntType result = 0;
|
||||||
|
size_t shift = 0;
|
||||||
|
do {
|
||||||
|
if (buf_pos == BUF_SIZE) {
|
||||||
|
stream.read(reinterpret_cast<char*>(buf), std::min(bytes_left, BUF_SIZE));
|
||||||
|
buf_pos = 0;
|
||||||
|
}
|
||||||
|
std::uint8_t byte = buf[buf_pos++];
|
||||||
|
--bytes_left;
|
||||||
|
result |= (byte & 0x7f) << shift;
|
||||||
|
shift += 7;
|
||||||
|
if ((byte & 0x80) == 0) {
|
||||||
|
out[i] = sizeof(IntType) * 8 <= shift || (byte & 0x40) == 0 ? result : result | ~((1 << shift) - 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (shift < sizeof(IntType) * 8);
|
||||||
|
}
|
||||||
|
assert(bytes_left == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename IntType>
|
||||||
|
inline void write_leb_128(std::ostream& stream, const IntType* values, std::size_t count) {
|
||||||
|
static_assert(std::is_signed_v<IntType>, "Not implemented for unsigned types");
|
||||||
|
stream.write(Leb128MagicString, Leb128MagicStringSize);
|
||||||
|
std::uint32_t byte_count = 0;
|
||||||
|
for (std::size_t i = 0; i < count; ++i) {
|
||||||
|
IntType value = values[i];
|
||||||
|
std::uint8_t byte;
|
||||||
|
do {
|
||||||
|
byte = value & 0x7f;
|
||||||
|
value >>= 7;
|
||||||
|
++byte_count;
|
||||||
|
} while ((byte & 0x40) == 0 ? value != 0 : value != -1);
|
||||||
|
}
|
||||||
|
write_little_endian(stream, byte_count);
|
||||||
|
const std::uint32_t BUF_SIZE = 4096;
|
||||||
|
std::uint8_t buf[BUF_SIZE];
|
||||||
|
std::uint32_t buf_pos = 0;
|
||||||
|
auto flush = [&]() {
|
||||||
|
if (buf_pos > 0) {
|
||||||
|
stream.write(reinterpret_cast<char*>(buf), buf_pos);
|
||||||
|
buf_pos = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
auto write = [&](std::uint8_t byte) {
|
||||||
|
buf[buf_pos++] = byte;
|
||||||
|
if (buf_pos == BUF_SIZE) flush();
|
||||||
|
};
|
||||||
|
for (std::size_t i = 0; i < count; ++i) {
|
||||||
|
IntType value = values[i];
|
||||||
|
while (true) {
|
||||||
|
std::uint8_t byte = value & 0x7f;
|
||||||
|
value >>= 7;
|
||||||
|
if ((byte & 0x40) == 0 ? value == 0 : value == -1) {
|
||||||
|
write(byte);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
write(byte | 0x80);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
flush();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Stockfish::Eval::NNUE
|
} // namespace Stockfish::Eval::NNUE
|
||||||
|
|
||||||
#endif // #ifndef NNUE_COMMON_H_INCLUDED
|
#endif // #ifndef NNUE_COMMON_H_INCLUDED
|
||||||
|
|||||||
+261
-201
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -25,6 +25,7 @@
|
|||||||
#include "nnue_architecture.h"
|
#include "nnue_architecture.h"
|
||||||
|
|
||||||
#include <cstring> // std::memset()
|
#include <cstring> // std::memset()
|
||||||
|
#include <utility> // std::pair
|
||||||
|
|
||||||
namespace Stockfish::Eval::NNUE {
|
namespace Stockfish::Eval::NNUE {
|
||||||
|
|
||||||
@@ -41,74 +42,127 @@ namespace Stockfish::Eval::NNUE {
|
|||||||
"Per feature PSQT values cannot be processed at granularity lower than 8 at a time.");
|
"Per feature PSQT values cannot be processed at granularity lower than 8 at a time.");
|
||||||
|
|
||||||
#ifdef USE_AVX512
|
#ifdef USE_AVX512
|
||||||
typedef __m512i vec_t;
|
using vec_t = __m512i;
|
||||||
typedef __m256i psqt_vec_t;
|
using psqt_vec_t = __m256i;
|
||||||
#define vec_load(a) _mm512_load_si512(a)
|
#define vec_load(a) _mm512_load_si512(a)
|
||||||
#define vec_store(a,b) _mm512_store_si512(a,b)
|
#define vec_store(a,b) _mm512_store_si512(a,b)
|
||||||
#define vec_add_16(a,b) _mm512_add_epi16(a,b)
|
#define vec_add_16(a,b) _mm512_add_epi16(a,b)
|
||||||
#define vec_sub_16(a,b) _mm512_sub_epi16(a,b)
|
#define vec_sub_16(a,b) _mm512_sub_epi16(a,b)
|
||||||
|
#define vec_mul_16(a,b) _mm512_mullo_epi16(a,b)
|
||||||
|
#define vec_zero() _mm512_setzero_epi32()
|
||||||
|
#define vec_set_16(a) _mm512_set1_epi16(a)
|
||||||
|
#define vec_max_16(a,b) _mm512_max_epi16(a,b)
|
||||||
|
#define vec_min_16(a,b) _mm512_min_epi16(a,b)
|
||||||
|
inline vec_t vec_msb_pack_16(vec_t a, vec_t b){
|
||||||
|
vec_t compacted = _mm512_packs_epi16(_mm512_srli_epi16(a,7),_mm512_srli_epi16(b,7));
|
||||||
|
return _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 2, 4, 6, 1, 3, 5, 7), compacted);
|
||||||
|
}
|
||||||
#define vec_load_psqt(a) _mm256_load_si256(a)
|
#define vec_load_psqt(a) _mm256_load_si256(a)
|
||||||
#define vec_store_psqt(a,b) _mm256_store_si256(a,b)
|
#define vec_store_psqt(a,b) _mm256_store_si256(a,b)
|
||||||
#define vec_add_psqt_32(a,b) _mm256_add_epi32(a,b)
|
#define vec_add_psqt_32(a,b) _mm256_add_epi32(a,b)
|
||||||
#define vec_sub_psqt_32(a,b) _mm256_sub_epi32(a,b)
|
#define vec_sub_psqt_32(a,b) _mm256_sub_epi32(a,b)
|
||||||
#define vec_zero_psqt() _mm256_setzero_si256()
|
#define vec_zero_psqt() _mm256_setzero_si256()
|
||||||
#define NumRegistersSIMD 32
|
#define NumRegistersSIMD 32
|
||||||
|
#define MaxChunkSize 64
|
||||||
|
|
||||||
#elif USE_AVX2
|
#elif USE_AVX2
|
||||||
typedef __m256i vec_t;
|
using vec_t = __m256i;
|
||||||
typedef __m256i psqt_vec_t;
|
using psqt_vec_t = __m256i;
|
||||||
#define vec_load(a) _mm256_load_si256(a)
|
#define vec_load(a) _mm256_load_si256(a)
|
||||||
#define vec_store(a,b) _mm256_store_si256(a,b)
|
#define vec_store(a,b) _mm256_store_si256(a,b)
|
||||||
#define vec_add_16(a,b) _mm256_add_epi16(a,b)
|
#define vec_add_16(a,b) _mm256_add_epi16(a,b)
|
||||||
#define vec_sub_16(a,b) _mm256_sub_epi16(a,b)
|
#define vec_sub_16(a,b) _mm256_sub_epi16(a,b)
|
||||||
|
#define vec_mul_16(a,b) _mm256_mullo_epi16(a,b)
|
||||||
|
#define vec_zero() _mm256_setzero_si256()
|
||||||
|
#define vec_set_16(a) _mm256_set1_epi16(a)
|
||||||
|
#define vec_max_16(a,b) _mm256_max_epi16(a,b)
|
||||||
|
#define vec_min_16(a,b) _mm256_min_epi16(a,b)
|
||||||
|
inline vec_t vec_msb_pack_16(vec_t a, vec_t b){
|
||||||
|
vec_t compacted = _mm256_packs_epi16(_mm256_srli_epi16(a,7), _mm256_srli_epi16(b,7));
|
||||||
|
return _mm256_permute4x64_epi64(compacted, 0b11011000);
|
||||||
|
}
|
||||||
#define vec_load_psqt(a) _mm256_load_si256(a)
|
#define vec_load_psqt(a) _mm256_load_si256(a)
|
||||||
#define vec_store_psqt(a,b) _mm256_store_si256(a,b)
|
#define vec_store_psqt(a,b) _mm256_store_si256(a,b)
|
||||||
#define vec_add_psqt_32(a,b) _mm256_add_epi32(a,b)
|
#define vec_add_psqt_32(a,b) _mm256_add_epi32(a,b)
|
||||||
#define vec_sub_psqt_32(a,b) _mm256_sub_epi32(a,b)
|
#define vec_sub_psqt_32(a,b) _mm256_sub_epi32(a,b)
|
||||||
#define vec_zero_psqt() _mm256_setzero_si256()
|
#define vec_zero_psqt() _mm256_setzero_si256()
|
||||||
#define NumRegistersSIMD 16
|
#define NumRegistersSIMD 16
|
||||||
|
#define MaxChunkSize 32
|
||||||
|
|
||||||
#elif USE_SSE2
|
#elif USE_SSE2
|
||||||
typedef __m128i vec_t;
|
using vec_t = __m128i;
|
||||||
typedef __m128i psqt_vec_t;
|
using psqt_vec_t = __m128i;
|
||||||
#define vec_load(a) (*(a))
|
#define vec_load(a) (*(a))
|
||||||
#define vec_store(a,b) *(a)=(b)
|
#define vec_store(a,b) *(a)=(b)
|
||||||
#define vec_add_16(a,b) _mm_add_epi16(a,b)
|
#define vec_add_16(a,b) _mm_add_epi16(a,b)
|
||||||
#define vec_sub_16(a,b) _mm_sub_epi16(a,b)
|
#define vec_sub_16(a,b) _mm_sub_epi16(a,b)
|
||||||
|
#define vec_mul_16(a,b) _mm_mullo_epi16(a,b)
|
||||||
|
#define vec_zero() _mm_setzero_si128()
|
||||||
|
#define vec_set_16(a) _mm_set1_epi16(a)
|
||||||
|
#define vec_max_16(a,b) _mm_max_epi16(a,b)
|
||||||
|
#define vec_min_16(a,b) _mm_min_epi16(a,b)
|
||||||
|
#define vec_msb_pack_16(a,b) _mm_packs_epi16(_mm_srli_epi16(a,7),_mm_srli_epi16(b,7))
|
||||||
#define vec_load_psqt(a) (*(a))
|
#define vec_load_psqt(a) (*(a))
|
||||||
#define vec_store_psqt(a,b) *(a)=(b)
|
#define vec_store_psqt(a,b) *(a)=(b)
|
||||||
#define vec_add_psqt_32(a,b) _mm_add_epi32(a,b)
|
#define vec_add_psqt_32(a,b) _mm_add_epi32(a,b)
|
||||||
#define vec_sub_psqt_32(a,b) _mm_sub_epi32(a,b)
|
#define vec_sub_psqt_32(a,b) _mm_sub_epi32(a,b)
|
||||||
#define vec_zero_psqt() _mm_setzero_si128()
|
#define vec_zero_psqt() _mm_setzero_si128()
|
||||||
#define NumRegistersSIMD (Is64Bit ? 16 : 8)
|
#define NumRegistersSIMD (Is64Bit ? 16 : 8)
|
||||||
|
#define MaxChunkSize 16
|
||||||
|
|
||||||
#elif USE_MMX
|
#elif USE_MMX
|
||||||
typedef __m64 vec_t;
|
using vec_t = __m64;
|
||||||
typedef __m64 psqt_vec_t;
|
using psqt_vec_t = __m64;
|
||||||
#define vec_load(a) (*(a))
|
#define vec_load(a) (*(a))
|
||||||
#define vec_store(a,b) *(a)=(b)
|
#define vec_store(a,b) *(a)=(b)
|
||||||
#define vec_add_16(a,b) _mm_add_pi16(a,b)
|
#define vec_add_16(a,b) _mm_add_pi16(a,b)
|
||||||
#define vec_sub_16(a,b) _mm_sub_pi16(a,b)
|
#define vec_sub_16(a,b) _mm_sub_pi16(a,b)
|
||||||
|
#define vec_mul_16(a,b) _mm_mullo_pi16(a,b)
|
||||||
|
#define vec_zero() _mm_setzero_si64()
|
||||||
|
#define vec_set_16(a) _mm_set1_pi16(a)
|
||||||
|
inline vec_t vec_max_16(vec_t a,vec_t b){
|
||||||
|
vec_t comparison = _mm_cmpgt_pi16(a,b);
|
||||||
|
return _mm_or_si64(_mm_and_si64(comparison, a), _mm_andnot_si64(comparison, b));
|
||||||
|
}
|
||||||
|
inline vec_t vec_min_16(vec_t a,vec_t b){
|
||||||
|
vec_t comparison = _mm_cmpgt_pi16(a,b);
|
||||||
|
return _mm_or_si64(_mm_and_si64(comparison, b), _mm_andnot_si64(comparison, a));
|
||||||
|
}
|
||||||
|
#define vec_msb_pack_16(a,b) _mm_packs_pi16(_mm_srli_pi16(a,7),_mm_srli_pi16(b,7))
|
||||||
#define vec_load_psqt(a) (*(a))
|
#define vec_load_psqt(a) (*(a))
|
||||||
#define vec_store_psqt(a,b) *(a)=(b)
|
#define vec_store_psqt(a,b) *(a)=(b)
|
||||||
#define vec_add_psqt_32(a,b) _mm_add_pi32(a,b)
|
#define vec_add_psqt_32(a,b) _mm_add_pi32(a,b)
|
||||||
#define vec_sub_psqt_32(a,b) _mm_sub_pi32(a,b)
|
#define vec_sub_psqt_32(a,b) _mm_sub_pi32(a,b)
|
||||||
#define vec_zero_psqt() _mm_setzero_si64()
|
#define vec_zero_psqt() _mm_setzero_si64()
|
||||||
|
#define vec_cleanup() _mm_empty()
|
||||||
#define NumRegistersSIMD 8
|
#define NumRegistersSIMD 8
|
||||||
|
#define MaxChunkSize 8
|
||||||
|
|
||||||
#elif USE_NEON
|
#elif USE_NEON
|
||||||
typedef int16x8_t vec_t;
|
using vec_t = int16x8_t;
|
||||||
typedef int32x4_t psqt_vec_t;
|
using psqt_vec_t = int32x4_t;
|
||||||
#define vec_load(a) (*(a))
|
#define vec_load(a) (*(a))
|
||||||
#define vec_store(a,b) *(a)=(b)
|
#define vec_store(a,b) *(a)=(b)
|
||||||
#define vec_add_16(a,b) vaddq_s16(a,b)
|
#define vec_add_16(a,b) vaddq_s16(a,b)
|
||||||
#define vec_sub_16(a,b) vsubq_s16(a,b)
|
#define vec_sub_16(a,b) vsubq_s16(a,b)
|
||||||
|
#define vec_mul_16(a,b) vmulq_s16(a,b)
|
||||||
|
#define vec_zero() vec_t{0}
|
||||||
|
#define vec_set_16(a) vdupq_n_s16(a)
|
||||||
|
#define vec_max_16(a,b) vmaxq_s16(a,b)
|
||||||
|
#define vec_min_16(a,b) vminq_s16(a,b)
|
||||||
|
inline vec_t vec_msb_pack_16(vec_t a, vec_t b){
|
||||||
|
const int8x8_t shifta = vshrn_n_s16(a, 7);
|
||||||
|
const int8x8_t shiftb = vshrn_n_s16(b, 7);
|
||||||
|
const int8x16_t compacted = vcombine_s8(shifta,shiftb);
|
||||||
|
return *reinterpret_cast<const vec_t*> (&compacted);
|
||||||
|
}
|
||||||
#define vec_load_psqt(a) (*(a))
|
#define vec_load_psqt(a) (*(a))
|
||||||
#define vec_store_psqt(a,b) *(a)=(b)
|
#define vec_store_psqt(a,b) *(a)=(b)
|
||||||
#define vec_add_psqt_32(a,b) vaddq_s32(a,b)
|
#define vec_add_psqt_32(a,b) vaddq_s32(a,b)
|
||||||
#define vec_sub_psqt_32(a,b) vsubq_s32(a,b)
|
#define vec_sub_psqt_32(a,b) vsubq_s32(a,b)
|
||||||
#define vec_zero_psqt() psqt_vec_t{0}
|
#define vec_zero_psqt() psqt_vec_t{0}
|
||||||
#define NumRegistersSIMD 16
|
#define NumRegistersSIMD 16
|
||||||
|
#define MaxChunkSize 16
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#undef VECTOR
|
#undef VECTOR
|
||||||
@@ -123,8 +177,10 @@ namespace Stockfish::Eval::NNUE {
|
|||||||
// We use __m* types as template arguments, which causes GCC to emit warnings
|
// We use __m* types as template arguments, which causes GCC to emit warnings
|
||||||
// about losing some attribute information. This is irrelevant to us as we
|
// about losing some attribute information. This is irrelevant to us as we
|
||||||
// only take their size, so the following pragma are harmless.
|
// only take their size, so the following pragma are harmless.
|
||||||
|
#if defined(__GNUC__)
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wignored-attributes"
|
#pragma GCC diagnostic ignored "-Wignored-attributes"
|
||||||
|
#endif
|
||||||
|
|
||||||
template <typename SIMDRegisterType,
|
template <typename SIMDRegisterType,
|
||||||
typename LaneType,
|
typename LaneType,
|
||||||
@@ -156,9 +212,9 @@ namespace Stockfish::Eval::NNUE {
|
|||||||
|
|
||||||
static constexpr int NumRegs = BestRegisterCount<vec_t, WeightType, TransformedFeatureDimensions, NumRegistersSIMD>();
|
static constexpr int NumRegs = BestRegisterCount<vec_t, WeightType, TransformedFeatureDimensions, NumRegistersSIMD>();
|
||||||
static constexpr int NumPsqtRegs = BestRegisterCount<psqt_vec_t, PSQTWeightType, PSQTBuckets, NumRegistersSIMD>();
|
static constexpr int NumPsqtRegs = BestRegisterCount<psqt_vec_t, PSQTWeightType, PSQTBuckets, NumRegistersSIMD>();
|
||||||
|
#if defined(__GNUC__)
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -183,7 +239,7 @@ namespace Stockfish::Eval::NNUE {
|
|||||||
|
|
||||||
// Number of input/output dimensions
|
// Number of input/output dimensions
|
||||||
static constexpr IndexType InputDimensions = FeatureSet::Dimensions;
|
static constexpr IndexType InputDimensions = FeatureSet::Dimensions;
|
||||||
static constexpr IndexType OutputDimensions = HalfDimensions * 2;
|
static constexpr IndexType OutputDimensions = HalfDimensions;
|
||||||
|
|
||||||
// Size of forward propagation buffer
|
// Size of forward propagation buffer
|
||||||
static constexpr std::size_t BufferSize =
|
static constexpr std::size_t BufferSize =
|
||||||
@@ -191,15 +247,15 @@ namespace Stockfish::Eval::NNUE {
|
|||||||
|
|
||||||
// Hash value embedded in the evaluation file
|
// Hash value embedded in the evaluation file
|
||||||
static constexpr std::uint32_t get_hash_value() {
|
static constexpr std::uint32_t get_hash_value() {
|
||||||
return FeatureSet::HashValue ^ OutputDimensions;
|
return FeatureSet::HashValue ^ (OutputDimensions * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read network parameters
|
// Read network parameters
|
||||||
bool read_parameters(std::istream& stream) {
|
bool read_parameters(std::istream& stream) {
|
||||||
|
|
||||||
read_little_endian<BiasType >(stream, biases , HalfDimensions );
|
read_leb_128<BiasType >(stream, biases , HalfDimensions );
|
||||||
read_little_endian<WeightType >(stream, weights , HalfDimensions * InputDimensions);
|
read_leb_128<WeightType >(stream, weights , HalfDimensions * InputDimensions);
|
||||||
read_little_endian<PSQTWeightType>(stream, psqtWeights, PSQTBuckets * InputDimensions);
|
read_leb_128<PSQTWeightType>(stream, psqtWeights, PSQTBuckets * InputDimensions);
|
||||||
|
|
||||||
return !stream.fail();
|
return !stream.fail();
|
||||||
}
|
}
|
||||||
@@ -207,17 +263,17 @@ namespace Stockfish::Eval::NNUE {
|
|||||||
// Write network parameters
|
// Write network parameters
|
||||||
bool write_parameters(std::ostream& stream) const {
|
bool write_parameters(std::ostream& stream) const {
|
||||||
|
|
||||||
write_little_endian<BiasType >(stream, biases , HalfDimensions );
|
write_leb_128<BiasType >(stream, biases , HalfDimensions );
|
||||||
write_little_endian<WeightType >(stream, weights , HalfDimensions * InputDimensions);
|
write_leb_128<WeightType >(stream, weights , HalfDimensions * InputDimensions);
|
||||||
write_little_endian<PSQTWeightType>(stream, psqtWeights, PSQTBuckets * InputDimensions);
|
write_leb_128<PSQTWeightType>(stream, psqtWeights, PSQTBuckets * InputDimensions);
|
||||||
|
|
||||||
return !stream.fail();
|
return !stream.fail();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert input features
|
// Convert input features
|
||||||
std::int32_t transform(const Position& pos, OutputType* output, int bucket) const {
|
std::int32_t transform(const Position& pos, OutputType* output, int bucket) const {
|
||||||
update_accumulator(pos, WHITE);
|
update_accumulator<WHITE>(pos);
|
||||||
update_accumulator(pos, BLACK);
|
update_accumulator<BLACK>(pos);
|
||||||
|
|
||||||
const Color perspectives[2] = {pos.side_to_move(), ~pos.side_to_move()};
|
const Color perspectives[2] = {pos.side_to_move(), ~pos.side_to_move()};
|
||||||
const auto& accumulation = pos.state()->accumulator.accumulation;
|
const auto& accumulation = pos.state()->accumulator.accumulation;
|
||||||
@@ -229,147 +285,89 @@ namespace Stockfish::Eval::NNUE {
|
|||||||
) / 2;
|
) / 2;
|
||||||
|
|
||||||
|
|
||||||
#if defined(USE_AVX512)
|
|
||||||
|
|
||||||
constexpr IndexType NumChunks = HalfDimensions / (SimdWidth * 2);
|
|
||||||
static_assert(HalfDimensions % (SimdWidth * 2) == 0);
|
|
||||||
const __m512i Control = _mm512_setr_epi64(0, 2, 4, 6, 1, 3, 5, 7);
|
|
||||||
const __m512i Zero = _mm512_setzero_si512();
|
|
||||||
|
|
||||||
for (IndexType p = 0; p < 2; ++p)
|
for (IndexType p = 0; p < 2; ++p)
|
||||||
{
|
{
|
||||||
const IndexType offset = HalfDimensions * p;
|
const IndexType offset = (HalfDimensions / 2) * p;
|
||||||
auto out = reinterpret_cast<__m512i*>(&output[offset]);
|
|
||||||
for (IndexType j = 0; j < NumChunks; ++j)
|
#if defined(VECTOR)
|
||||||
|
|
||||||
|
constexpr IndexType OutputChunkSize = MaxChunkSize;
|
||||||
|
static_assert((HalfDimensions / 2) % OutputChunkSize == 0);
|
||||||
|
constexpr IndexType NumOutputChunks = HalfDimensions / 2 / OutputChunkSize;
|
||||||
|
|
||||||
|
vec_t Zero = vec_zero();
|
||||||
|
vec_t One = vec_set_16(127);
|
||||||
|
|
||||||
|
const vec_t* in0 = reinterpret_cast<const vec_t*>(&(accumulation[perspectives[p]][0]));
|
||||||
|
const vec_t* in1 = reinterpret_cast<const vec_t*>(&(accumulation[perspectives[p]][HalfDimensions / 2]));
|
||||||
|
vec_t* out = reinterpret_cast< vec_t*>(output + offset);
|
||||||
|
|
||||||
|
for (IndexType j = 0; j < NumOutputChunks; j += 1)
|
||||||
{
|
{
|
||||||
__m512i sum0 = _mm512_load_si512(&reinterpret_cast<const __m512i*>
|
const vec_t sum0a = vec_max_16(vec_min_16(in0[j * 2 + 0], One), Zero);
|
||||||
(accumulation[perspectives[p]])[j * 2 + 0]);
|
const vec_t sum0b = vec_max_16(vec_min_16(in0[j * 2 + 1], One), Zero);
|
||||||
__m512i sum1 = _mm512_load_si512(&reinterpret_cast<const __m512i*>
|
const vec_t sum1a = vec_max_16(vec_min_16(in1[j * 2 + 0], One), Zero);
|
||||||
(accumulation[perspectives[p]])[j * 2 + 1]);
|
const vec_t sum1b = vec_max_16(vec_min_16(in1[j * 2 + 1], One), Zero);
|
||||||
|
|
||||||
_mm512_store_si512(&out[j], _mm512_permutexvar_epi64(Control,
|
const vec_t pa = vec_mul_16(sum0a, sum1a);
|
||||||
_mm512_max_epi8(_mm512_packs_epi16(sum0, sum1), Zero)));
|
const vec_t pb = vec_mul_16(sum0b, sum1b);
|
||||||
|
|
||||||
|
out[j] = vec_msb_pack_16(pa, pb);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return psqt;
|
|
||||||
|
|
||||||
#elif defined(USE_AVX2)
|
|
||||||
|
|
||||||
constexpr IndexType NumChunks = HalfDimensions / SimdWidth;
|
|
||||||
constexpr int Control = 0b11011000;
|
|
||||||
const __m256i Zero = _mm256_setzero_si256();
|
|
||||||
|
|
||||||
for (IndexType p = 0; p < 2; ++p)
|
|
||||||
{
|
|
||||||
const IndexType offset = HalfDimensions * p;
|
|
||||||
auto out = reinterpret_cast<__m256i*>(&output[offset]);
|
|
||||||
for (IndexType j = 0; j < NumChunks; ++j)
|
|
||||||
{
|
|
||||||
__m256i sum0 = _mm256_load_si256(&reinterpret_cast<const __m256i*>
|
|
||||||
(accumulation[perspectives[p]])[j * 2 + 0]);
|
|
||||||
__m256i sum1 = _mm256_load_si256(&reinterpret_cast<const __m256i*>
|
|
||||||
(accumulation[perspectives[p]])[j * 2 + 1]);
|
|
||||||
|
|
||||||
_mm256_store_si256(&out[j], _mm256_permute4x64_epi64(
|
|
||||||
_mm256_max_epi8(_mm256_packs_epi16(sum0, sum1), Zero), Control));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return psqt;
|
|
||||||
|
|
||||||
#elif defined(USE_SSE2)
|
|
||||||
|
|
||||||
#ifdef USE_SSE41
|
|
||||||
constexpr IndexType NumChunks = HalfDimensions / SimdWidth;
|
|
||||||
const __m128i Zero = _mm_setzero_si128();
|
|
||||||
#else
|
|
||||||
constexpr IndexType NumChunks = HalfDimensions / SimdWidth;
|
|
||||||
const __m128i k0x80s = _mm_set1_epi8(-128);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (IndexType p = 0; p < 2; ++p)
|
|
||||||
{
|
|
||||||
const IndexType offset = HalfDimensions * p;
|
|
||||||
auto out = reinterpret_cast<__m128i*>(&output[offset]);
|
|
||||||
for (IndexType j = 0; j < NumChunks; ++j)
|
|
||||||
{
|
|
||||||
__m128i sum0 = _mm_load_si128(&reinterpret_cast<const __m128i*>
|
|
||||||
(accumulation[perspectives[p]])[j * 2 + 0]);
|
|
||||||
__m128i sum1 = _mm_load_si128(&reinterpret_cast<const __m128i*>
|
|
||||||
(accumulation[perspectives[p]])[j * 2 + 1]);
|
|
||||||
const __m128i packedbytes = _mm_packs_epi16(sum0, sum1);
|
|
||||||
|
|
||||||
#ifdef USE_SSE41
|
|
||||||
_mm_store_si128(&out[j], _mm_max_epi8(packedbytes, Zero));
|
|
||||||
#else
|
|
||||||
_mm_store_si128(&out[j], _mm_subs_epi8(_mm_adds_epi8(packedbytes, k0x80s), k0x80s));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return psqt;
|
|
||||||
|
|
||||||
#elif defined(USE_MMX)
|
|
||||||
|
|
||||||
constexpr IndexType NumChunks = HalfDimensions / SimdWidth;
|
|
||||||
const __m64 k0x80s = _mm_set1_pi8(-128);
|
|
||||||
|
|
||||||
for (IndexType p = 0; p < 2; ++p)
|
|
||||||
{
|
|
||||||
const IndexType offset = HalfDimensions * p;
|
|
||||||
auto out = reinterpret_cast<__m64*>(&output[offset]);
|
|
||||||
for (IndexType j = 0; j < NumChunks; ++j)
|
|
||||||
{
|
|
||||||
__m64 sum0 = *(&reinterpret_cast<const __m64*>(accumulation[perspectives[p]])[j * 2 + 0]);
|
|
||||||
__m64 sum1 = *(&reinterpret_cast<const __m64*>(accumulation[perspectives[p]])[j * 2 + 1]);
|
|
||||||
const __m64 packedbytes = _mm_packs_pi16(sum0, sum1);
|
|
||||||
out[j] = _mm_subs_pi8(_mm_adds_pi8(packedbytes, k0x80s), k0x80s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_mm_empty();
|
|
||||||
return psqt;
|
|
||||||
|
|
||||||
#elif defined(USE_NEON)
|
|
||||||
|
|
||||||
constexpr IndexType NumChunks = HalfDimensions / (SimdWidth / 2);
|
|
||||||
const int8x8_t Zero = {0};
|
|
||||||
|
|
||||||
for (IndexType p = 0; p < 2; ++p)
|
|
||||||
{
|
|
||||||
const IndexType offset = HalfDimensions * p;
|
|
||||||
const auto out = reinterpret_cast<int8x8_t*>(&output[offset]);
|
|
||||||
for (IndexType j = 0; j < NumChunks; ++j)
|
|
||||||
{
|
|
||||||
int16x8_t sum = reinterpret_cast<const int16x8_t*>(accumulation[perspectives[p]])[j];
|
|
||||||
out[j] = vmax_s8(vqmovn_s16(sum), Zero);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return psqt;
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
for (IndexType p = 0; p < 2; ++p)
|
for (IndexType j = 0; j < HalfDimensions / 2; ++j) {
|
||||||
{
|
BiasType sum0 = accumulation[static_cast<int>(perspectives[p])][j + 0];
|
||||||
const IndexType offset = HalfDimensions * p;
|
BiasType sum1 = accumulation[static_cast<int>(perspectives[p])][j + HalfDimensions / 2];
|
||||||
for (IndexType j = 0; j < HalfDimensions; ++j)
|
sum0 = std::max<int>(0, std::min<int>(127, sum0));
|
||||||
{
|
sum1 = std::max<int>(0, std::min<int>(127, sum1));
|
||||||
BiasType sum = accumulation[perspectives[p]][j];
|
output[offset + j] = static_cast<OutputType>(sum0 * sum1 / 128);
|
||||||
output[offset + j] = static_cast<OutputType>(std::max<int>(0, std::min<int>(127, sum)));
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return psqt;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(vec_cleanup)
|
||||||
|
vec_cleanup();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return psqt;
|
||||||
} // end of function transform()
|
} // end of function transform()
|
||||||
|
|
||||||
|
void hint_common_access(const Position& pos) const {
|
||||||
|
hint_common_access_for_perspective<WHITE>(pos);
|
||||||
|
hint_common_access_for_perspective<BLACK>(pos);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void update_accumulator(const Position& pos, const Color perspective) const {
|
template<Color Perspective>
|
||||||
|
[[nodiscard]] std::pair<StateInfo*, StateInfo*> try_find_computed_accumulator(const Position& pos) const {
|
||||||
|
// Look for a usable accumulator of an earlier position. We keep track
|
||||||
|
// of the estimated gain in terms of features to be added/subtracted.
|
||||||
|
StateInfo *st = pos.state(), *next = nullptr;
|
||||||
|
int gain = FeatureSet::refresh_cost(pos);
|
||||||
|
while (st->previous && !st->accumulator.computed[Perspective])
|
||||||
|
{
|
||||||
|
// This governs when a full feature refresh is needed and how many
|
||||||
|
// updates are better than just one full refresh.
|
||||||
|
if ( FeatureSet::requires_refresh(st, Perspective)
|
||||||
|
|| (gain -= FeatureSet::update_cost(st) + 1) < 0)
|
||||||
|
break;
|
||||||
|
next = st;
|
||||||
|
st = st->previous;
|
||||||
|
}
|
||||||
|
return { st, next };
|
||||||
|
}
|
||||||
|
|
||||||
// The size must be enough to contain the largest possible update.
|
// NOTE: The parameter states_to_update is an array of position states, ending with nullptr.
|
||||||
// That might depend on the feature set and generally relies on the
|
// All states must be sequential, that is states_to_update[i] must either be reachable
|
||||||
// feature set's update cost calculation to be correct and never
|
// by repeatedly applying ->previous from states_to_update[i+1] or states_to_update[i] == nullptr.
|
||||||
// allow updates with more added/removed features than MaxActiveDimensions.
|
// computed_st must be reachable by repeatedly applying ->previous on states_to_update[0], if not nullptr.
|
||||||
|
template<Color Perspective, size_t N>
|
||||||
|
void update_accumulator_incremental(const Position& pos, StateInfo* computed_st, StateInfo* states_to_update[N]) const {
|
||||||
|
static_assert(N > 0);
|
||||||
|
assert(states_to_update[N-1] == nullptr);
|
||||||
|
|
||||||
#ifdef VECTOR
|
#ifdef VECTOR
|
||||||
// Gcc-10.2 unnecessarily spills AVX2 registers if this array
|
// Gcc-10.2 unnecessarily spills AVX2 registers if this array
|
||||||
@@ -378,51 +376,48 @@ namespace Stockfish::Eval::NNUE {
|
|||||||
psqt_vec_t psqt[NumPsqtRegs];
|
psqt_vec_t psqt[NumPsqtRegs];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Look for a usable accumulator of an earlier position. We keep track
|
if (states_to_update[0] == nullptr)
|
||||||
// of the estimated gain in terms of features to be added/subtracted.
|
|
||||||
StateInfo *st = pos.state(), *next = nullptr;
|
|
||||||
int gain = FeatureSet::refresh_cost(pos);
|
|
||||||
while (st->previous && !st->accumulator.computed[perspective])
|
|
||||||
{
|
|
||||||
// This governs when a full feature refresh is needed and how many
|
|
||||||
// updates are better than just one full refresh.
|
|
||||||
if ( FeatureSet::requires_refresh(st, perspective)
|
|
||||||
|| (gain -= FeatureSet::update_cost(st) + 1) < 0)
|
|
||||||
break;
|
|
||||||
next = st;
|
|
||||||
st = st->previous;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (st->accumulator.computed[perspective])
|
|
||||||
{
|
|
||||||
if (next == nullptr)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Update incrementally in two steps. First, we update the "next"
|
// Update incrementally going back through states_to_update.
|
||||||
// accumulator. Then, we update the current accumulator (pos.state()).
|
|
||||||
|
|
||||||
// Gather all features to be updated.
|
// Gather all features to be updated.
|
||||||
const Square ksq = pos.square<KING>(perspective);
|
const Square ksq = pos.square<KING>(Perspective);
|
||||||
FeatureSet::IndexList removed[2], added[2];
|
|
||||||
FeatureSet::append_changed_indices(
|
|
||||||
ksq, next->dirtyPiece, perspective, removed[0], added[0]);
|
|
||||||
for (StateInfo *st2 = pos.state(); st2 != next; st2 = st2->previous)
|
|
||||||
FeatureSet::append_changed_indices(
|
|
||||||
ksq, st2->dirtyPiece, perspective, removed[1], added[1]);
|
|
||||||
|
|
||||||
// Mark the accumulators as computed.
|
// The size must be enough to contain the largest possible update.
|
||||||
next->accumulator.computed[perspective] = true;
|
// That might depend on the feature set and generally relies on the
|
||||||
pos.state()->accumulator.computed[perspective] = true;
|
// feature set's update cost calculation to be correct and never
|
||||||
|
// allow updates with more added/removed features than MaxActiveDimensions.
|
||||||
|
FeatureSet::IndexList removed[N-1], added[N-1];
|
||||||
|
|
||||||
|
{
|
||||||
|
int i = N-2; // last potential state to update. Skip last element because it must be nullptr.
|
||||||
|
while (states_to_update[i] == nullptr)
|
||||||
|
--i;
|
||||||
|
|
||||||
|
StateInfo *st2 = states_to_update[i];
|
||||||
|
|
||||||
|
for (; i >= 0; --i)
|
||||||
|
{
|
||||||
|
states_to_update[i]->accumulator.computed[Perspective] = true;
|
||||||
|
|
||||||
|
StateInfo* end_state = i == 0 ? computed_st : states_to_update[i - 1];
|
||||||
|
|
||||||
|
for (; st2 != end_state; st2 = st2->previous)
|
||||||
|
FeatureSet::append_changed_indices<Perspective>(
|
||||||
|
ksq, st2->dirtyPiece, removed[i], added[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StateInfo* st = computed_st;
|
||||||
|
|
||||||
// Now update the accumulators listed in states_to_update[], where the last element is a sentinel.
|
// Now update the accumulators listed in states_to_update[], where the last element is a sentinel.
|
||||||
StateInfo *states_to_update[3] =
|
|
||||||
{ next, next == pos.state() ? nullptr : pos.state(), nullptr };
|
|
||||||
#ifdef VECTOR
|
#ifdef VECTOR
|
||||||
for (IndexType j = 0; j < HalfDimensions / TileHeight; ++j)
|
for (IndexType j = 0; j < HalfDimensions / TileHeight; ++j)
|
||||||
{
|
{
|
||||||
// Load accumulator
|
// Load accumulator
|
||||||
auto accTile = reinterpret_cast<vec_t*>(
|
auto accTile = reinterpret_cast<vec_t*>(
|
||||||
&st->accumulator.accumulation[perspective][j * TileHeight]);
|
&st->accumulator.accumulation[Perspective][j * TileHeight]);
|
||||||
for (IndexType k = 0; k < NumRegs; ++k)
|
for (IndexType k = 0; k < NumRegs; ++k)
|
||||||
acc[k] = vec_load(&accTile[k]);
|
acc[k] = vec_load(&accTile[k]);
|
||||||
|
|
||||||
@@ -448,7 +443,7 @@ namespace Stockfish::Eval::NNUE {
|
|||||||
|
|
||||||
// Store accumulator
|
// Store accumulator
|
||||||
accTile = reinterpret_cast<vec_t*>(
|
accTile = reinterpret_cast<vec_t*>(
|
||||||
&states_to_update[i]->accumulator.accumulation[perspective][j * TileHeight]);
|
&states_to_update[i]->accumulator.accumulation[Perspective][j * TileHeight]);
|
||||||
for (IndexType k = 0; k < NumRegs; ++k)
|
for (IndexType k = 0; k < NumRegs; ++k)
|
||||||
vec_store(&accTile[k], acc[k]);
|
vec_store(&accTile[k], acc[k]);
|
||||||
}
|
}
|
||||||
@@ -458,7 +453,7 @@ namespace Stockfish::Eval::NNUE {
|
|||||||
{
|
{
|
||||||
// Load accumulator
|
// Load accumulator
|
||||||
auto accTilePsqt = reinterpret_cast<psqt_vec_t*>(
|
auto accTilePsqt = reinterpret_cast<psqt_vec_t*>(
|
||||||
&st->accumulator.psqtAccumulation[perspective][j * PsqtTileHeight]);
|
&st->accumulator.psqtAccumulation[Perspective][j * PsqtTileHeight]);
|
||||||
for (std::size_t k = 0; k < NumPsqtRegs; ++k)
|
for (std::size_t k = 0; k < NumPsqtRegs; ++k)
|
||||||
psqt[k] = vec_load_psqt(&accTilePsqt[k]);
|
psqt[k] = vec_load_psqt(&accTilePsqt[k]);
|
||||||
|
|
||||||
@@ -484,7 +479,7 @@ namespace Stockfish::Eval::NNUE {
|
|||||||
|
|
||||||
// Store accumulator
|
// Store accumulator
|
||||||
accTilePsqt = reinterpret_cast<psqt_vec_t*>(
|
accTilePsqt = reinterpret_cast<psqt_vec_t*>(
|
||||||
&states_to_update[i]->accumulator.psqtAccumulation[perspective][j * PsqtTileHeight]);
|
&states_to_update[i]->accumulator.psqtAccumulation[Perspective][j * PsqtTileHeight]);
|
||||||
for (std::size_t k = 0; k < NumPsqtRegs; ++k)
|
for (std::size_t k = 0; k < NumPsqtRegs; ++k)
|
||||||
vec_store_psqt(&accTilePsqt[k], psqt[k]);
|
vec_store_psqt(&accTilePsqt[k], psqt[k]);
|
||||||
}
|
}
|
||||||
@@ -493,12 +488,12 @@ namespace Stockfish::Eval::NNUE {
|
|||||||
#else
|
#else
|
||||||
for (IndexType i = 0; states_to_update[i]; ++i)
|
for (IndexType i = 0; states_to_update[i]; ++i)
|
||||||
{
|
{
|
||||||
std::memcpy(states_to_update[i]->accumulator.accumulation[perspective],
|
std::memcpy(states_to_update[i]->accumulator.accumulation[Perspective],
|
||||||
st->accumulator.accumulation[perspective],
|
st->accumulator.accumulation[Perspective],
|
||||||
HalfDimensions * sizeof(BiasType));
|
HalfDimensions * sizeof(BiasType));
|
||||||
|
|
||||||
for (std::size_t k = 0; k < PSQTBuckets; ++k)
|
for (std::size_t k = 0; k < PSQTBuckets; ++k)
|
||||||
states_to_update[i]->accumulator.psqtAccumulation[perspective][k] = st->accumulator.psqtAccumulation[perspective][k];
|
states_to_update[i]->accumulator.psqtAccumulation[Perspective][k] = st->accumulator.psqtAccumulation[Perspective][k];
|
||||||
|
|
||||||
st = states_to_update[i];
|
st = states_to_update[i];
|
||||||
|
|
||||||
@@ -508,10 +503,10 @@ namespace Stockfish::Eval::NNUE {
|
|||||||
const IndexType offset = HalfDimensions * index;
|
const IndexType offset = HalfDimensions * index;
|
||||||
|
|
||||||
for (IndexType j = 0; j < HalfDimensions; ++j)
|
for (IndexType j = 0; j < HalfDimensions; ++j)
|
||||||
st->accumulator.accumulation[perspective][j] -= weights[offset + j];
|
st->accumulator.accumulation[Perspective][j] -= weights[offset + j];
|
||||||
|
|
||||||
for (std::size_t k = 0; k < PSQTBuckets; ++k)
|
for (std::size_t k = 0; k < PSQTBuckets; ++k)
|
||||||
st->accumulator.psqtAccumulation[perspective][k] -= psqtWeights[index * PSQTBuckets + k];
|
st->accumulator.psqtAccumulation[Perspective][k] -= psqtWeights[index * PSQTBuckets + k];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Difference calculation for the activated features
|
// Difference calculation for the activated features
|
||||||
@@ -520,21 +515,35 @@ namespace Stockfish::Eval::NNUE {
|
|||||||
const IndexType offset = HalfDimensions * index;
|
const IndexType offset = HalfDimensions * index;
|
||||||
|
|
||||||
for (IndexType j = 0; j < HalfDimensions; ++j)
|
for (IndexType j = 0; j < HalfDimensions; ++j)
|
||||||
st->accumulator.accumulation[perspective][j] += weights[offset + j];
|
st->accumulator.accumulation[Perspective][j] += weights[offset + j];
|
||||||
|
|
||||||
for (std::size_t k = 0; k < PSQTBuckets; ++k)
|
for (std::size_t k = 0; k < PSQTBuckets; ++k)
|
||||||
st->accumulator.psqtAccumulation[perspective][k] += psqtWeights[index * PSQTBuckets + k];
|
st->accumulator.psqtAccumulation[Perspective][k] += psqtWeights[index * PSQTBuckets + k];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(USE_MMX)
|
||||||
|
_mm_empty();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
template<Color Perspective>
|
||||||
|
void update_accumulator_refresh(const Position& pos) const {
|
||||||
|
#ifdef VECTOR
|
||||||
|
// Gcc-10.2 unnecessarily spills AVX2 registers if this array
|
||||||
|
// is defined in the VECTOR code below, once in each branch
|
||||||
|
vec_t acc[NumRegs];
|
||||||
|
psqt_vec_t psqt[NumPsqtRegs];
|
||||||
|
#endif
|
||||||
|
|
||||||
// Refresh the accumulator
|
// Refresh the accumulator
|
||||||
|
// Could be extracted to a separate function because it's done in 2 places,
|
||||||
|
// but it's unclear if compilers would correctly handle register allocation.
|
||||||
auto& accumulator = pos.state()->accumulator;
|
auto& accumulator = pos.state()->accumulator;
|
||||||
accumulator.computed[perspective] = true;
|
accumulator.computed[Perspective] = true;
|
||||||
FeatureSet::IndexList active;
|
FeatureSet::IndexList active;
|
||||||
FeatureSet::append_active_indices(pos, perspective, active);
|
FeatureSet::append_active_indices<Perspective>(pos, active);
|
||||||
|
|
||||||
#ifdef VECTOR
|
#ifdef VECTOR
|
||||||
for (IndexType j = 0; j < HalfDimensions / TileHeight; ++j)
|
for (IndexType j = 0; j < HalfDimensions / TileHeight; ++j)
|
||||||
@@ -554,7 +563,7 @@ namespace Stockfish::Eval::NNUE {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto accTile = reinterpret_cast<vec_t*>(
|
auto accTile = reinterpret_cast<vec_t*>(
|
||||||
&accumulator.accumulation[perspective][j * TileHeight]);
|
&accumulator.accumulation[Perspective][j * TileHeight]);
|
||||||
for (unsigned k = 0; k < NumRegs; k++)
|
for (unsigned k = 0; k < NumRegs; k++)
|
||||||
vec_store(&accTile[k], acc[k]);
|
vec_store(&accTile[k], acc[k]);
|
||||||
}
|
}
|
||||||
@@ -574,36 +583,87 @@ namespace Stockfish::Eval::NNUE {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto accTilePsqt = reinterpret_cast<psqt_vec_t*>(
|
auto accTilePsqt = reinterpret_cast<psqt_vec_t*>(
|
||||||
&accumulator.psqtAccumulation[perspective][j * PsqtTileHeight]);
|
&accumulator.psqtAccumulation[Perspective][j * PsqtTileHeight]);
|
||||||
for (std::size_t k = 0; k < NumPsqtRegs; ++k)
|
for (std::size_t k = 0; k < NumPsqtRegs; ++k)
|
||||||
vec_store_psqt(&accTilePsqt[k], psqt[k]);
|
vec_store_psqt(&accTilePsqt[k], psqt[k]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
std::memcpy(accumulator.accumulation[perspective], biases,
|
std::memcpy(accumulator.accumulation[Perspective], biases,
|
||||||
HalfDimensions * sizeof(BiasType));
|
HalfDimensions * sizeof(BiasType));
|
||||||
|
|
||||||
for (std::size_t k = 0; k < PSQTBuckets; ++k)
|
for (std::size_t k = 0; k < PSQTBuckets; ++k)
|
||||||
accumulator.psqtAccumulation[perspective][k] = 0;
|
accumulator.psqtAccumulation[Perspective][k] = 0;
|
||||||
|
|
||||||
for (const auto index : active)
|
for (const auto index : active)
|
||||||
{
|
{
|
||||||
const IndexType offset = HalfDimensions * index;
|
const IndexType offset = HalfDimensions * index;
|
||||||
|
|
||||||
for (IndexType j = 0; j < HalfDimensions; ++j)
|
for (IndexType j = 0; j < HalfDimensions; ++j)
|
||||||
accumulator.accumulation[perspective][j] += weights[offset + j];
|
accumulator.accumulation[Perspective][j] += weights[offset + j];
|
||||||
|
|
||||||
for (std::size_t k = 0; k < PSQTBuckets; ++k)
|
for (std::size_t k = 0; k < PSQTBuckets; ++k)
|
||||||
accumulator.psqtAccumulation[perspective][k] += psqtWeights[index * PSQTBuckets + k];
|
accumulator.psqtAccumulation[Perspective][k] += psqtWeights[index * PSQTBuckets + k];
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(USE_MMX)
|
#if defined(USE_MMX)
|
||||||
_mm_empty();
|
_mm_empty();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<Color Perspective>
|
||||||
|
void hint_common_access_for_perspective(const Position& pos) const {
|
||||||
|
|
||||||
|
// Works like update_accumulator, but performs less work.
|
||||||
|
// Updates ONLY the accumulator for pos.
|
||||||
|
|
||||||
|
// Look for a usable accumulator of an earlier position. We keep track
|
||||||
|
// of the estimated gain in terms of features to be added/subtracted.
|
||||||
|
// Fast early exit.
|
||||||
|
if (pos.state()->accumulator.computed[Perspective])
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto [oldest_st, _] = try_find_computed_accumulator<Perspective>(pos);
|
||||||
|
|
||||||
|
if (oldest_st->accumulator.computed[Perspective])
|
||||||
|
{
|
||||||
|
// Only update current position accumulator to minimize work.
|
||||||
|
StateInfo* states_to_update[2] = { pos.state(), nullptr };
|
||||||
|
update_accumulator_incremental<Perspective, 2>(pos, oldest_st, states_to_update);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
update_accumulator_refresh<Perspective>(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<Color Perspective>
|
||||||
|
void update_accumulator(const Position& pos) const {
|
||||||
|
|
||||||
|
auto [oldest_st, next] = try_find_computed_accumulator<Perspective>(pos);
|
||||||
|
|
||||||
|
if (oldest_st->accumulator.computed[Perspective])
|
||||||
|
{
|
||||||
|
if (next == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Now update the accumulators listed in states_to_update[], where the last element is a sentinel.
|
||||||
|
// Currently we update 2 accumulators.
|
||||||
|
// 1. for the current position
|
||||||
|
// 2. the next accumulator after the computed one
|
||||||
|
// The heuristic may change in the future.
|
||||||
|
StateInfo *states_to_update[3] =
|
||||||
|
{ next, next == pos.state() ? nullptr : pos.state(), nullptr };
|
||||||
|
|
||||||
|
update_accumulator_incremental<Perspective, 3>(pos, oldest_st, states_to_update);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
update_accumulator_refresh<Perspective>(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
alignas(CacheLineSize) BiasType biases[HalfDimensions];
|
alignas(CacheLineSize) BiasType biases[HalfDimensions];
|
||||||
alignas(CacheLineSize) WeightType weights[HalfDimensions * InputDimensions];
|
alignas(CacheLineSize) WeightType weights[HalfDimensions * InputDimensions];
|
||||||
alignas(CacheLineSize) PSQTWeightType psqtWeights[InputDimensions * PSQTBuckets];
|
alignas(CacheLineSize) PSQTWeightType psqtWeights[InputDimensions * PSQTBuckets];
|
||||||
|
|||||||
+20
-20
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -32,30 +32,30 @@ namespace {
|
|||||||
#define S(mg, eg) make_score(mg, eg)
|
#define S(mg, eg) make_score(mg, eg)
|
||||||
|
|
||||||
// Pawn penalties
|
// Pawn penalties
|
||||||
constexpr Score Backward = S( 9, 22);
|
constexpr Score Backward = S( 6, 19);
|
||||||
constexpr Score Doubled = S(13, 51);
|
constexpr Score Doubled = S(11, 51);
|
||||||
constexpr Score DoubledEarly = S(20, 7);
|
constexpr Score DoubledEarly = S(17, 7);
|
||||||
constexpr Score Isolated = S( 3, 15);
|
constexpr Score Isolated = S( 1, 20);
|
||||||
constexpr Score WeakLever = S( 4, 58);
|
constexpr Score WeakLever = S( 2, 57);
|
||||||
constexpr Score WeakUnopposed = S(13, 24);
|
constexpr Score WeakUnopposed = S(15, 18);
|
||||||
|
|
||||||
// Bonus for blocked pawns at 5th or 6th rank
|
// Bonus for blocked pawns at 5th or 6th rank
|
||||||
constexpr Score BlockedPawn[2] = { S(-17, -6), S(-9, 2) };
|
constexpr Score BlockedPawn[2] = { S(-19, -8), S(-7, 3) };
|
||||||
|
|
||||||
constexpr Score BlockedStorm[RANK_NB] = {
|
constexpr Score BlockedStorm[RANK_NB] = {
|
||||||
S(0, 0), S(0, 0), S(75, 78), S(-8, 16), S(-6, 10), S(-6, 6), S(0, 2)
|
S(0, 0), S(0, 0), S(64, 75), S(-3, 14), S(-12, 19), S(-7, 4), S(-10, 5)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Connected pawn bonus
|
// Connected pawn bonus
|
||||||
constexpr int Connected[RANK_NB] = { 0, 5, 7, 11, 23, 48, 87 };
|
constexpr int Connected[RANK_NB] = { 0, 3, 7, 7, 15, 54, 86 };
|
||||||
|
|
||||||
// Strength of pawn shelter for our king by [distance from edge][rank].
|
// Strength of pawn shelter for our king by [distance from edge][rank].
|
||||||
// RANK_1 = 0 is used for files where we have no pawn, or pawn is behind our king.
|
// RANK_1 = 0 is used for files where we have no pawn, or pawn is behind our king.
|
||||||
constexpr Value ShelterStrength[int(FILE_NB) / 2][RANK_NB] = {
|
constexpr Value ShelterStrength[int(FILE_NB) / 2][RANK_NB] = {
|
||||||
{ V( -5), V( 82), V( 92), V( 54), V( 36), V( 22), V( 28) },
|
{ V(-2), V(85), V(95), V(53), V(39), V(23), V(25) },
|
||||||
{ V(-44), V( 63), V( 33), V(-50), V(-30), V(-12), V( -62) },
|
{ V(-55), V(64), V(32), V(-55), V(-30), V(-11), V(-61) },
|
||||||
{ V(-11), V( 77), V( 22), V( -6), V( 31), V( 8), V( -45) },
|
{ V(-11), V(75), V(19), V(-6), V(26), V(9), V(-47) },
|
||||||
{ V(-39), V(-12), V(-29), V(-50), V(-43), V(-68), V(-164) }
|
{ V(-41), V(-11), V(-27), V(-58), V(-42), V(-66), V(-163) }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Danger of enemy pawns moving toward our king by [distance from edge][rank].
|
// Danger of enemy pawns moving toward our king by [distance from edge][rank].
|
||||||
@@ -63,17 +63,17 @@ namespace {
|
|||||||
// is behind our king. Note that UnblockedStorm[0][1-2] accommodate opponent pawn
|
// is behind our king. Note that UnblockedStorm[0][1-2] accommodate opponent pawn
|
||||||
// on edge, likely blocked by our king.
|
// on edge, likely blocked by our king.
|
||||||
constexpr Value UnblockedStorm[int(FILE_NB) / 2][RANK_NB] = {
|
constexpr Value UnblockedStorm[int(FILE_NB) / 2][RANK_NB] = {
|
||||||
{ V( 87), V(-288), V(-168), V( 96), V( 47), V( 44), V( 46) },
|
{ V(94), V(-280), V(-170), V(90), V(59), V(47), V(53) },
|
||||||
{ V( 42), V( -25), V( 120), V( 45), V( 34), V( -9), V( 24) },
|
{ V(43), V(-17), V(128), V(39), V(26), V(-17), V(15) },
|
||||||
{ V( -8), V( 51), V( 167), V( 35), V( -4), V(-16), V(-12) },
|
{ V(-9), V(62), V(170), V(34), V(-5), V(-20), V(-11) },
|
||||||
{ V(-17), V( -13), V( 100), V( 4), V( 9), V(-16), V(-31) }
|
{ V(-27), V(-19), V(106), V(10), V(2), V(-13), V(-24) }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// KingOnFile[semi-open Us][semi-open Them] contains bonuses/penalties
|
// KingOnFile[semi-open Us][semi-open Them] contains bonuses/penalties
|
||||||
// for king when the king is on a semi-open or open file.
|
// for king when the king is on a semi-open or open file.
|
||||||
constexpr Score KingOnFile[2][2] = {{ S(-21,10), S(-7, 1) },
|
constexpr Score KingOnFile[2][2] = {{ S(-18,11), S(-6,-3) },
|
||||||
{ S( 0,-3), S( 9,-4) }};
|
{ S( 0, 0), S( 5,-4) }};
|
||||||
|
|
||||||
#undef S
|
#undef S
|
||||||
#undef V
|
#undef V
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -61,7 +61,7 @@ struct Entry {
|
|||||||
int blockedCount;
|
int blockedCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef HashTable<Entry, 131072> Table;
|
using Table = HashTable<Entry, 131072>;
|
||||||
|
|
||||||
Entry* probe(const Position& pos);
|
Entry* probe(const Position& pos);
|
||||||
|
|
||||||
|
|||||||
+51
-52
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
#include <cstring> // For std::memset, std::memcmp
|
#include <cstring> // For std::memset, std::memcmp
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
#include "bitboard.h"
|
#include "bitboard.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
@@ -46,7 +47,7 @@ namespace Zobrist {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
const string PieceToChar(" PNBRQK pnbrqk");
|
constexpr std::string_view PieceToChar(" PNBRQK pnbrqk");
|
||||||
|
|
||||||
constexpr Piece Pieces[] = { W_PAWN, W_KNIGHT, W_BISHOP, W_ROOK, W_QUEEN, W_KING,
|
constexpr Piece Pieces[] = { W_PAWN, W_KNIGHT, W_BISHOP, W_ROOK, W_QUEEN, W_KING,
|
||||||
B_PAWN, B_KNIGHT, B_BISHOP, B_ROOK, B_QUEEN, B_KING };
|
B_PAWN, B_KNIGHT, B_BISHOP, B_ROOK, B_QUEEN, B_KING };
|
||||||
@@ -96,7 +97,7 @@ std::ostream& operator<<(std::ostream& os, const Position& pos) {
|
|||||||
|
|
||||||
// Marcel van Kervinck's cuckoo algorithm for fast detection of "upcoming repetition"
|
// Marcel van Kervinck's cuckoo algorithm for fast detection of "upcoming repetition"
|
||||||
// situations. Description of the algorithm in the following paper:
|
// situations. Description of the algorithm in the following paper:
|
||||||
// https://marcelk.net/2013-04-06/paper/upcoming-rep-v2.pdf
|
// http://web.archive.org/web/20201107002606/https://marcelk.net/2013-04-06/paper/upcoming-rep-v2.pdf
|
||||||
|
|
||||||
// First and second hash functions for indexing the cuckoo tables
|
// First and second hash functions for indexing the cuckoo tables
|
||||||
inline int H1(Key h) { return h & 0x1fff; }
|
inline int H1(Key h) { return h & 0x1fff; }
|
||||||
@@ -129,7 +130,7 @@ void Position::init() {
|
|||||||
// Prepare the cuckoo tables
|
// Prepare the cuckoo tables
|
||||||
std::memset(cuckoo, 0, sizeof(cuckoo));
|
std::memset(cuckoo, 0, sizeof(cuckoo));
|
||||||
std::memset(cuckooMove, 0, sizeof(cuckooMove));
|
std::memset(cuckooMove, 0, sizeof(cuckooMove));
|
||||||
int count = 0;
|
[[maybe_unused]] int count = 0;
|
||||||
for (Piece pc : Pieces)
|
for (Piece pc : Pieces)
|
||||||
for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
|
for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
|
||||||
for (Square s2 = Square(s1 + 1); s2 <= SQ_H8; ++s2)
|
for (Square s2 = Square(s1 + 1); s2 <= SQ_H8; ++s2)
|
||||||
@@ -281,7 +282,7 @@ Position& Position::set(const string& fenStr, bool isChess960, StateInfo* si, Th
|
|||||||
|
|
||||||
chess960 = isChess960;
|
chess960 = isChess960;
|
||||||
thisThread = th;
|
thisThread = th;
|
||||||
set_state(st);
|
set_state();
|
||||||
|
|
||||||
assert(pos_is_ok());
|
assert(pos_is_ok());
|
||||||
|
|
||||||
@@ -312,60 +313,59 @@ void Position::set_castling_right(Color c, Square rfrom) {
|
|||||||
|
|
||||||
/// Position::set_check_info() sets king attacks to detect if a move gives check
|
/// Position::set_check_info() sets king attacks to detect if a move gives check
|
||||||
|
|
||||||
void Position::set_check_info(StateInfo* si) const {
|
void Position::set_check_info() const {
|
||||||
|
|
||||||
si->blockersForKing[WHITE] = slider_blockers(pieces(BLACK), square<KING>(WHITE), si->pinners[BLACK]);
|
st->blockersForKing[WHITE] = slider_blockers(pieces(BLACK), square<KING>(WHITE), st->pinners[BLACK]);
|
||||||
si->blockersForKing[BLACK] = slider_blockers(pieces(WHITE), square<KING>(BLACK), si->pinners[WHITE]);
|
st->blockersForKing[BLACK] = slider_blockers(pieces(WHITE), square<KING>(BLACK), st->pinners[WHITE]);
|
||||||
|
|
||||||
Square ksq = square<KING>(~sideToMove);
|
Square ksq = square<KING>(~sideToMove);
|
||||||
|
|
||||||
si->checkSquares[PAWN] = pawn_attacks_bb(~sideToMove, ksq);
|
st->checkSquares[PAWN] = pawn_attacks_bb(~sideToMove, ksq);
|
||||||
si->checkSquares[KNIGHT] = attacks_bb<KNIGHT>(ksq);
|
st->checkSquares[KNIGHT] = attacks_bb<KNIGHT>(ksq);
|
||||||
si->checkSquares[BISHOP] = attacks_bb<BISHOP>(ksq, pieces());
|
st->checkSquares[BISHOP] = attacks_bb<BISHOP>(ksq, pieces());
|
||||||
si->checkSquares[ROOK] = attacks_bb<ROOK>(ksq, pieces());
|
st->checkSquares[ROOK] = attacks_bb<ROOK>(ksq, pieces());
|
||||||
si->checkSquares[QUEEN] = si->checkSquares[BISHOP] | si->checkSquares[ROOK];
|
st->checkSquares[QUEEN] = st->checkSquares[BISHOP] | st->checkSquares[ROOK];
|
||||||
si->checkSquares[KING] = 0;
|
st->checkSquares[KING] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Position::set_state() computes the hash keys of the position, and other
|
/// Position::set_state() computes the hash keys of the position, and other
|
||||||
/// data that once computed is updated incrementally as moves are made.
|
/// data that once computed is updated incrementally as moves are made.
|
||||||
/// The function is only used when a new position is set up, and to verify
|
/// The function is only used when a new position is set up
|
||||||
/// the correctness of the StateInfo data when running in debug mode.
|
|
||||||
|
|
||||||
void Position::set_state(StateInfo* si) const {
|
void Position::set_state() const {
|
||||||
|
|
||||||
si->key = si->materialKey = 0;
|
st->key = st->materialKey = 0;
|
||||||
si->pawnKey = Zobrist::noPawns;
|
st->pawnKey = Zobrist::noPawns;
|
||||||
si->nonPawnMaterial[WHITE] = si->nonPawnMaterial[BLACK] = VALUE_ZERO;
|
st->nonPawnMaterial[WHITE] = st->nonPawnMaterial[BLACK] = VALUE_ZERO;
|
||||||
si->checkersBB = attackers_to(square<KING>(sideToMove)) & pieces(~sideToMove);
|
st->checkersBB = attackers_to(square<KING>(sideToMove)) & pieces(~sideToMove);
|
||||||
|
|
||||||
set_check_info(si);
|
set_check_info();
|
||||||
|
|
||||||
for (Bitboard b = pieces(); b; )
|
for (Bitboard b = pieces(); b; )
|
||||||
{
|
{
|
||||||
Square s = pop_lsb(b);
|
Square s = pop_lsb(b);
|
||||||
Piece pc = piece_on(s);
|
Piece pc = piece_on(s);
|
||||||
si->key ^= Zobrist::psq[pc][s];
|
st->key ^= Zobrist::psq[pc][s];
|
||||||
|
|
||||||
if (type_of(pc) == PAWN)
|
if (type_of(pc) == PAWN)
|
||||||
si->pawnKey ^= Zobrist::psq[pc][s];
|
st->pawnKey ^= Zobrist::psq[pc][s];
|
||||||
|
|
||||||
else if (type_of(pc) != KING)
|
else if (type_of(pc) != KING)
|
||||||
si->nonPawnMaterial[color_of(pc)] += PieceValue[MG][pc];
|
st->nonPawnMaterial[color_of(pc)] += PieceValue[MG][pc];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (si->epSquare != SQ_NONE)
|
if (st->epSquare != SQ_NONE)
|
||||||
si->key ^= Zobrist::enpassant[file_of(si->epSquare)];
|
st->key ^= Zobrist::enpassant[file_of(st->epSquare)];
|
||||||
|
|
||||||
if (sideToMove == BLACK)
|
if (sideToMove == BLACK)
|
||||||
si->key ^= Zobrist::side;
|
st->key ^= Zobrist::side;
|
||||||
|
|
||||||
si->key ^= Zobrist::castling[si->castlingRights];
|
st->key ^= Zobrist::castling[st->castlingRights];
|
||||||
|
|
||||||
for (Piece pc : Pieces)
|
for (Piece pc : Pieces)
|
||||||
for (int cnt = 0; cnt < pieceCount[pc]; ++cnt)
|
for (int cnt = 0; cnt < pieceCount[pc]; ++cnt)
|
||||||
si->materialKey ^= Zobrist::psq[pc][cnt];
|
st->materialKey ^= Zobrist::psq[pc][cnt];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -568,8 +568,7 @@ bool Position::pseudo_legal(const Move m) const {
|
|||||||
: MoveList<NON_EVASIONS>(*this).contains(m);
|
: MoveList<NON_EVASIONS>(*this).contains(m);
|
||||||
|
|
||||||
// Is not a promotion, so promotion piece must be empty
|
// Is not a promotion, so promotion piece must be empty
|
||||||
if (promotion_type(m) - KNIGHT != NO_PIECE_TYPE)
|
assert(promotion_type(m) - KNIGHT == NO_PIECE_TYPE);
|
||||||
return false;
|
|
||||||
|
|
||||||
// If the 'from' square is not occupied by a piece belonging to the side to
|
// If the 'from' square is not occupied by a piece belonging to the side to
|
||||||
// move, the move is obviously not legal.
|
// move, the move is obviously not legal.
|
||||||
@@ -765,9 +764,6 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
|
|||||||
// Update board and piece lists
|
// Update board and piece lists
|
||||||
remove_piece(capsq);
|
remove_piece(capsq);
|
||||||
|
|
||||||
if (type_of(m) == EN_PASSANT)
|
|
||||||
board[capsq] = NO_PIECE;
|
|
||||||
|
|
||||||
// Update material hash key and prefetch access to materialTable
|
// Update material hash key and prefetch access to materialTable
|
||||||
k ^= Zobrist::psq[captured][capsq];
|
k ^= Zobrist::psq[captured][capsq];
|
||||||
st->materialKey ^= Zobrist::psq[captured][pieceCount[captured]];
|
st->materialKey ^= Zobrist::psq[captured][pieceCount[captured]];
|
||||||
@@ -868,7 +864,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
|
|||||||
sideToMove = ~sideToMove;
|
sideToMove = ~sideToMove;
|
||||||
|
|
||||||
// Update king attacks used for fast check detection
|
// Update king attacks used for fast check detection
|
||||||
set_check_info(st);
|
set_check_info();
|
||||||
|
|
||||||
// Calculate the repetition info. It is the ply distance from the previous
|
// Calculate the repetition info. It is the ply distance from the previous
|
||||||
// occurrence of the same position, negative in the 3-fold case, or zero
|
// occurrence of the same position, negative in the 3-fold case, or zero
|
||||||
@@ -1020,7 +1016,7 @@ void Position::do_null_move(StateInfo& newSt) {
|
|||||||
|
|
||||||
sideToMove = ~sideToMove;
|
sideToMove = ~sideToMove;
|
||||||
|
|
||||||
set_check_info(st);
|
set_check_info();
|
||||||
|
|
||||||
st->repetition = 0;
|
st->repetition = 0;
|
||||||
|
|
||||||
@@ -1054,7 +1050,10 @@ Key Position::key_after(Move m) const {
|
|||||||
if (captured)
|
if (captured)
|
||||||
k ^= Zobrist::psq[captured][to];
|
k ^= Zobrist::psq[captured][to];
|
||||||
|
|
||||||
return k ^ Zobrist::psq[pc][to] ^ Zobrist::psq[pc][from];
|
k ^= Zobrist::psq[pc][to] ^ Zobrist::psq[pc][from];
|
||||||
|
|
||||||
|
return (captured || type_of(pc) == PAWN)
|
||||||
|
? k : adjust_key50<true>(k);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1062,7 +1061,7 @@ Key Position::key_after(Move m) const {
|
|||||||
/// SEE value of move is greater or equal to the given threshold. We'll use an
|
/// SEE value of move is greater or equal to the given threshold. We'll use an
|
||||||
/// algorithm similar to alpha-beta pruning with a null window.
|
/// algorithm similar to alpha-beta pruning with a null window.
|
||||||
|
|
||||||
bool Position::see_ge(Move m, Value threshold) const {
|
bool Position::see_ge(Move m, Bitboard& occupied, Value threshold) const {
|
||||||
|
|
||||||
assert(is_ok(m));
|
assert(is_ok(m));
|
||||||
|
|
||||||
@@ -1081,7 +1080,7 @@ bool Position::see_ge(Move m, Value threshold) const {
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
assert(color_of(piece_on(from)) == sideToMove);
|
assert(color_of(piece_on(from)) == sideToMove);
|
||||||
Bitboard occupied = pieces() ^ from ^ to;
|
occupied = pieces() ^ from ^ to; // xoring to is important for pinned piece logic
|
||||||
Color stm = sideToMove;
|
Color stm = sideToMove;
|
||||||
Bitboard attackers = attackers_to(to, occupied);
|
Bitboard attackers = attackers_to(to, occupied);
|
||||||
Bitboard stmAttackers, bb;
|
Bitboard stmAttackers, bb;
|
||||||
@@ -1099,10 +1098,12 @@ bool Position::see_ge(Move m, Value threshold) const {
|
|||||||
// Don't allow pinned pieces to attack as long as there are
|
// Don't allow pinned pieces to attack as long as there are
|
||||||
// pinners on their original square.
|
// pinners on their original square.
|
||||||
if (pinners(~stm) & occupied)
|
if (pinners(~stm) & occupied)
|
||||||
|
{
|
||||||
stmAttackers &= ~blockers_for_king(stm);
|
stmAttackers &= ~blockers_for_king(stm);
|
||||||
|
|
||||||
if (!stmAttackers)
|
if (!stmAttackers)
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
res ^= 1;
|
res ^= 1;
|
||||||
|
|
||||||
@@ -1110,45 +1111,44 @@ bool Position::see_ge(Move m, Value threshold) const {
|
|||||||
// the bitboard 'attackers' any X-ray attackers behind it.
|
// the bitboard 'attackers' any X-ray attackers behind it.
|
||||||
if ((bb = stmAttackers & pieces(PAWN)))
|
if ((bb = stmAttackers & pieces(PAWN)))
|
||||||
{
|
{
|
||||||
|
occupied ^= least_significant_square_bb(bb);
|
||||||
if ((swap = PawnValueMg - swap) < res)
|
if ((swap = PawnValueMg - swap) < res)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
occupied ^= least_significant_square_bb(bb);
|
|
||||||
attackers |= attacks_bb<BISHOP>(to, occupied) & pieces(BISHOP, QUEEN);
|
attackers |= attacks_bb<BISHOP>(to, occupied) & pieces(BISHOP, QUEEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if ((bb = stmAttackers & pieces(KNIGHT)))
|
else if ((bb = stmAttackers & pieces(KNIGHT)))
|
||||||
{
|
{
|
||||||
|
occupied ^= least_significant_square_bb(bb);
|
||||||
if ((swap = KnightValueMg - swap) < res)
|
if ((swap = KnightValueMg - swap) < res)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
occupied ^= least_significant_square_bb(bb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else if ((bb = stmAttackers & pieces(BISHOP)))
|
else if ((bb = stmAttackers & pieces(BISHOP)))
|
||||||
{
|
{
|
||||||
|
occupied ^= least_significant_square_bb(bb);
|
||||||
if ((swap = BishopValueMg - swap) < res)
|
if ((swap = BishopValueMg - swap) < res)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
occupied ^= least_significant_square_bb(bb);
|
|
||||||
attackers |= attacks_bb<BISHOP>(to, occupied) & pieces(BISHOP, QUEEN);
|
attackers |= attacks_bb<BISHOP>(to, occupied) & pieces(BISHOP, QUEEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if ((bb = stmAttackers & pieces(ROOK)))
|
else if ((bb = stmAttackers & pieces(ROOK)))
|
||||||
{
|
{
|
||||||
|
occupied ^= least_significant_square_bb(bb);
|
||||||
if ((swap = RookValueMg - swap) < res)
|
if ((swap = RookValueMg - swap) < res)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
occupied ^= least_significant_square_bb(bb);
|
|
||||||
attackers |= attacks_bb<ROOK>(to, occupied) & pieces(ROOK, QUEEN);
|
attackers |= attacks_bb<ROOK>(to, occupied) & pieces(ROOK, QUEEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if ((bb = stmAttackers & pieces(QUEEN)))
|
else if ((bb = stmAttackers & pieces(QUEEN)))
|
||||||
{
|
{
|
||||||
|
occupied ^= least_significant_square_bb(bb);
|
||||||
if ((swap = QueenValueMg - swap) < res)
|
if ((swap = QueenValueMg - swap) < res)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
occupied ^= least_significant_square_bb(bb);
|
|
||||||
attackers |= (attacks_bb<BISHOP>(to, occupied) & pieces(BISHOP, QUEEN))
|
attackers |= (attacks_bb<BISHOP>(to, occupied) & pieces(BISHOP, QUEEN))
|
||||||
| (attacks_bb<ROOK >(to, occupied) & pieces(ROOK , QUEEN));
|
| (attacks_bb<ROOK >(to, occupied) & pieces(ROOK , QUEEN));
|
||||||
}
|
}
|
||||||
@@ -1162,6 +1162,11 @@ bool Position::see_ge(Move m, Value threshold) const {
|
|||||||
return bool(res);
|
return bool(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Position::see_ge(Move m, Value threshold) const {
|
||||||
|
Bitboard occupied;
|
||||||
|
return see_ge(m, occupied, threshold);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Position::is_draw() tests whether the position is drawn by 50-move rule
|
/// Position::is_draw() tests whether the position is drawn by 50-move rule
|
||||||
/// or by repetition. It does not detect stalemates.
|
/// or by repetition. It does not detect stalemates.
|
||||||
@@ -1318,12 +1323,6 @@ bool Position::pos_is_ok() const {
|
|||||||
if (p1 != p2 && (pieces(p1) & pieces(p2)))
|
if (p1 != p2 && (pieces(p1) & pieces(p2)))
|
||||||
assert(0 && "pos_is_ok: Bitboards");
|
assert(0 && "pos_is_ok: Bitboards");
|
||||||
|
|
||||||
StateInfo si = *st;
|
|
||||||
ASSERT_ALIGNED(&si, Eval::NNUE::CacheLineSize);
|
|
||||||
|
|
||||||
set_state(&si);
|
|
||||||
if (std::memcmp(&si, st, sizeof(StateInfo)))
|
|
||||||
assert(0 && "pos_is_ok: State");
|
|
||||||
|
|
||||||
for (Piece pc : Pieces)
|
for (Piece pc : Pieces)
|
||||||
if ( pieceCount[pc] != popcount(pieces(color_of(pc), type_of(pc)))
|
if ( pieceCount[pc] != popcount(pieces(color_of(pc), type_of(pc)))
|
||||||
|
|||||||
+57
-26
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -68,7 +68,7 @@ struct StateInfo {
|
|||||||
/// start position to the position just before the search starts). Needed by
|
/// start position to the position just before the search starts). Needed by
|
||||||
/// 'draw by repetition' detection. Use a std::deque because pointers to
|
/// 'draw by repetition' detection. Use a std::deque because pointers to
|
||||||
/// elements are not invalidated upon list resizing.
|
/// elements are not invalidated upon list resizing.
|
||||||
typedef std::unique_ptr<std::deque<StateInfo>> StateListPtr;
|
using StateListPtr = std::unique_ptr<std::deque<StateInfo>>;
|
||||||
|
|
||||||
|
|
||||||
/// Position class stores information regarding the board representation as
|
/// Position class stores information regarding the board representation as
|
||||||
@@ -92,10 +92,9 @@ public:
|
|||||||
|
|
||||||
// Position representation
|
// Position representation
|
||||||
Bitboard pieces(PieceType pt) const;
|
Bitboard pieces(PieceType pt) const;
|
||||||
Bitboard pieces(PieceType pt1, PieceType pt2) const;
|
template<typename ...PieceTypes> Bitboard pieces(PieceType pt, PieceTypes... pts) const;
|
||||||
Bitboard pieces(Color c) const;
|
Bitboard pieces(Color c) const;
|
||||||
Bitboard pieces(Color c, PieceType pt) const;
|
template<typename ...PieceTypes> Bitboard pieces(Color c, PieceTypes... pts) const;
|
||||||
Bitboard pieces(Color c, PieceType pt1, PieceType pt2) const;
|
|
||||||
Piece piece_on(Square s) const;
|
Piece piece_on(Square s) const;
|
||||||
Square ep_square() const;
|
Square ep_square() const;
|
||||||
bool empty(Square s) const;
|
bool empty(Square s) const;
|
||||||
@@ -120,12 +119,13 @@ public:
|
|||||||
Bitboard attackers_to(Square s) const;
|
Bitboard attackers_to(Square s) const;
|
||||||
Bitboard attackers_to(Square s, Bitboard occupied) const;
|
Bitboard attackers_to(Square s, Bitboard occupied) const;
|
||||||
Bitboard slider_blockers(Bitboard sliders, Square s, Bitboard& pinners) const;
|
Bitboard slider_blockers(Bitboard sliders, Square s, Bitboard& pinners) const;
|
||||||
|
template<PieceType Pt> Bitboard attacks_by(Color c) const;
|
||||||
|
|
||||||
// Properties of moves
|
// Properties of moves
|
||||||
bool legal(Move m) const;
|
bool legal(Move m) const;
|
||||||
bool pseudo_legal(const Move m) const;
|
bool pseudo_legal(const Move m) const;
|
||||||
bool capture(Move m) const;
|
bool capture(Move m) const;
|
||||||
bool capture_or_promotion(Move m) const;
|
bool capture_stage(Move m) const;
|
||||||
bool gives_check(Move m) const;
|
bool gives_check(Move m) const;
|
||||||
Piece moved_piece(Move m) const;
|
Piece moved_piece(Move m) const;
|
||||||
Piece captured_piece() const;
|
Piece captured_piece() const;
|
||||||
@@ -144,6 +144,7 @@ public:
|
|||||||
|
|
||||||
// Static Exchange Evaluation
|
// Static Exchange Evaluation
|
||||||
bool see_ge(Move m, Value threshold = VALUE_ZERO) const;
|
bool see_ge(Move m, Value threshold = VALUE_ZERO) const;
|
||||||
|
bool see_ge(Move m, Bitboard& occupied, Value threshold = VALUE_ZERO) const;
|
||||||
|
|
||||||
// Accessing hash keys
|
// Accessing hash keys
|
||||||
Key key() const;
|
Key key() const;
|
||||||
@@ -161,6 +162,7 @@ public:
|
|||||||
bool has_repeated() const;
|
bool has_repeated() const;
|
||||||
int rule50_count() const;
|
int rule50_count() const;
|
||||||
Score psq_score() const;
|
Score psq_score() const;
|
||||||
|
Value psq_eg_stm() const;
|
||||||
Value non_pawn_material(Color c) const;
|
Value non_pawn_material(Color c) const;
|
||||||
Value non_pawn_material() const;
|
Value non_pawn_material() const;
|
||||||
|
|
||||||
@@ -177,13 +179,15 @@ public:
|
|||||||
private:
|
private:
|
||||||
// Initialization helpers (used while setting up a position)
|
// Initialization helpers (used while setting up a position)
|
||||||
void set_castling_right(Color c, Square rfrom);
|
void set_castling_right(Color c, Square rfrom);
|
||||||
void set_state(StateInfo* si) const;
|
void set_state() const;
|
||||||
void set_check_info(StateInfo* si) const;
|
void set_check_info() const;
|
||||||
|
|
||||||
// Other helpers
|
// Other helpers
|
||||||
void move_piece(Square from, Square to);
|
void move_piece(Square from, Square to);
|
||||||
template<bool Do>
|
template<bool Do>
|
||||||
void do_castling(Color us, Square from, Square& to, Square& rfrom, Square& rto);
|
void do_castling(Color us, Square from, Square& to, Square& rfrom, Square& rto);
|
||||||
|
template<bool AfterMove>
|
||||||
|
Key adjust_key50(Key k) const;
|
||||||
|
|
||||||
// Data members
|
// Data members
|
||||||
Piece board[SQUARE_NB];
|
Piece board[SQUARE_NB];
|
||||||
@@ -201,7 +205,7 @@ private:
|
|||||||
bool chess960;
|
bool chess960;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern std::ostream& operator<<(std::ostream& os, const Position& pos);
|
std::ostream& operator<<(std::ostream& os, const Position& pos);
|
||||||
|
|
||||||
inline Color Position::side_to_move() const {
|
inline Color Position::side_to_move() const {
|
||||||
return sideToMove;
|
return sideToMove;
|
||||||
@@ -224,20 +228,18 @@ inline Bitboard Position::pieces(PieceType pt = ALL_PIECES) const {
|
|||||||
return byTypeBB[pt];
|
return byTypeBB[pt];
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Bitboard Position::pieces(PieceType pt1, PieceType pt2) const {
|
template<typename ...PieceTypes>
|
||||||
return pieces(pt1) | pieces(pt2);
|
inline Bitboard Position::pieces(PieceType pt, PieceTypes... pts) const {
|
||||||
|
return pieces(pt) | pieces(pts...);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Bitboard Position::pieces(Color c) const {
|
inline Bitboard Position::pieces(Color c) const {
|
||||||
return byColorBB[c];
|
return byColorBB[c];
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Bitboard Position::pieces(Color c, PieceType pt) const {
|
template<typename ...PieceTypes>
|
||||||
return pieces(c) & pieces(pt);
|
inline Bitboard Position::pieces(Color c, PieceTypes... pts) const {
|
||||||
}
|
return pieces(c) & pieces(pts...);
|
||||||
|
|
||||||
inline Bitboard Position::pieces(Color c, PieceType pt1, PieceType pt2) const {
|
|
||||||
return pieces(c) & (pieces(pt1) | pieces(pt2));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<PieceType Pt> inline int Position::count(Color c) const {
|
template<PieceType Pt> inline int Position::count(Color c) const {
|
||||||
@@ -285,6 +287,22 @@ inline Bitboard Position::attackers_to(Square s) const {
|
|||||||
return attackers_to(s, pieces());
|
return attackers_to(s, pieces());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<PieceType Pt>
|
||||||
|
inline Bitboard Position::attacks_by(Color c) const {
|
||||||
|
|
||||||
|
if constexpr (Pt == PAWN)
|
||||||
|
return c == WHITE ? pawn_attacks_bb<WHITE>(pieces(WHITE, PAWN))
|
||||||
|
: pawn_attacks_bb<BLACK>(pieces(BLACK, PAWN));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Bitboard threats = 0;
|
||||||
|
Bitboard attackers = pieces(c, Pt);
|
||||||
|
while (attackers)
|
||||||
|
threats |= attacks_bb<Pt>(pop_lsb(attackers), pieces());
|
||||||
|
return threats;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline Bitboard Position::checkers() const {
|
inline Bitboard Position::checkers() const {
|
||||||
return st->checkersBB;
|
return st->checkersBB;
|
||||||
}
|
}
|
||||||
@@ -310,8 +328,14 @@ inline int Position::pawns_on_same_color_squares(Color c, Square s) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline Key Position::key() const {
|
inline Key Position::key() const {
|
||||||
return st->rule50 < 14 ? st->key
|
return adjust_key50<false>(st->key);
|
||||||
: st->key ^ make_key((st->rule50 - 14) / 8);
|
}
|
||||||
|
|
||||||
|
template<bool AfterMove>
|
||||||
|
inline Key Position::adjust_key50(Key k) const
|
||||||
|
{
|
||||||
|
return st->rule50 < 14 - AfterMove
|
||||||
|
? k : k ^ make_key((st->rule50 - (14 - AfterMove)) / 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Key Position::pawn_key() const {
|
inline Key Position::pawn_key() const {
|
||||||
@@ -326,6 +350,10 @@ inline Score Position::psq_score() const {
|
|||||||
return psq;
|
return psq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline Value Position::psq_eg_stm() const {
|
||||||
|
return (sideToMove == WHITE ? 1 : -1) * eg_value(psq);
|
||||||
|
}
|
||||||
|
|
||||||
inline Value Position::non_pawn_material(Color c) const {
|
inline Value Position::non_pawn_material(Color c) const {
|
||||||
return st->nonPawnMaterial[c];
|
return st->nonPawnMaterial[c];
|
||||||
}
|
}
|
||||||
@@ -352,15 +380,18 @@ inline bool Position::is_chess960() const {
|
|||||||
return chess960;
|
return chess960;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool Position::capture_or_promotion(Move m) const {
|
|
||||||
assert(is_ok(m));
|
|
||||||
return type_of(m) != NORMAL ? type_of(m) != CASTLING : !empty(to_sq(m));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool Position::capture(Move m) const {
|
inline bool Position::capture(Move m) const {
|
||||||
assert(is_ok(m));
|
assert(is_ok(m));
|
||||||
// Castling is encoded as "king captures rook"
|
return (!empty(to_sq(m)) && type_of(m) != CASTLING)
|
||||||
return (!empty(to_sq(m)) && type_of(m) != CASTLING) || type_of(m) == EN_PASSANT;
|
|| type_of(m) == EN_PASSANT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns true if a move is generated from the capture stage
|
||||||
|
// having also queen promotions covered, i.e. consistency with the capture stage move generation
|
||||||
|
// is needed to avoid the generation of duplicate moves.
|
||||||
|
inline bool Position::capture_stage(Move m) const {
|
||||||
|
assert(is_ok(m));
|
||||||
|
return capture(m) || promotion_type(m) == QUEEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Piece Position::captured_piece() const {
|
inline Piece Position::captured_piece() const {
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -30,7 +30,7 @@ namespace Stockfish::PSQT
|
|||||||
extern Score psq[PIECE_NB][SQUARE_NB];
|
extern Score psq[PIECE_NB][SQUARE_NB];
|
||||||
|
|
||||||
// Fill psqt array from a set of internally linked parameters
|
// Fill psqt array from a set of internally linked parameters
|
||||||
extern void init();
|
void init();
|
||||||
|
|
||||||
} // namespace Stockfish::PSQT
|
} // namespace Stockfish::PSQT
|
||||||
|
|
||||||
|
|||||||
+432
-424
File diff suppressed because it is too large
Load Diff
+7
-6
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -31,9 +31,6 @@ class Position;
|
|||||||
|
|
||||||
namespace Search {
|
namespace Search {
|
||||||
|
|
||||||
/// Threshold used for countermoves based pruning
|
|
||||||
constexpr int CounterMovePruneThreshold = 0;
|
|
||||||
|
|
||||||
|
|
||||||
/// Stack struct keeps track of the information we need to remember from nodes
|
/// Stack struct keeps track of the information we need to remember from nodes
|
||||||
/// shallower and deeper in the tree during the search. Each search thread has
|
/// shallower and deeper in the tree during the search. Each search thread has
|
||||||
@@ -47,13 +44,13 @@ struct Stack {
|
|||||||
Move excludedMove;
|
Move excludedMove;
|
||||||
Move killers[2];
|
Move killers[2];
|
||||||
Value staticEval;
|
Value staticEval;
|
||||||
Depth depth;
|
|
||||||
int statScore;
|
int statScore;
|
||||||
int moveCount;
|
int moveCount;
|
||||||
bool inCheck;
|
bool inCheck;
|
||||||
bool ttPv;
|
bool ttPv;
|
||||||
bool ttHit;
|
bool ttHit;
|
||||||
int doubleExtensions;
|
int doubleExtensions;
|
||||||
|
int cutoffCnt;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -73,13 +70,17 @@ struct RootMove {
|
|||||||
|
|
||||||
Value score = -VALUE_INFINITE;
|
Value score = -VALUE_INFINITE;
|
||||||
Value previousScore = -VALUE_INFINITE;
|
Value previousScore = -VALUE_INFINITE;
|
||||||
|
Value averageScore = -VALUE_INFINITE;
|
||||||
|
Value uciScore = -VALUE_INFINITE;
|
||||||
|
bool scoreLowerbound = false;
|
||||||
|
bool scoreUpperbound = false;
|
||||||
int selDepth = 0;
|
int selDepth = 0;
|
||||||
int tbRank = 0;
|
int tbRank = 0;
|
||||||
Value tbScore;
|
Value tbScore;
|
||||||
std::vector<Move> pv;
|
std::vector<Move> pv;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<RootMove> RootMoves;
|
using RootMoves = std::vector<RootMove>;
|
||||||
|
|
||||||
|
|
||||||
/// LimitsType struct stores information sent by GUI about available time to
|
/// LimitsType struct stores information sent by GUI about available time to
|
||||||
|
|||||||
+30
-31
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -24,9 +24,10 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <sstream>
|
|
||||||
#include <type_traits>
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string_view>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
#include "../bitboard.h"
|
#include "../bitboard.h"
|
||||||
#include "../movegen.h"
|
#include "../movegen.h"
|
||||||
@@ -59,6 +60,7 @@ namespace Stockfish {
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr int TBPIECES = 7; // Max number of supported pieces
|
constexpr int TBPIECES = 7; // Max number of supported pieces
|
||||||
|
constexpr int MAX_DTZ = 1 << 18; // Max DTZ supported, large enough to deal with the syzygy TB limit.
|
||||||
|
|
||||||
enum { BigEndian, LittleEndian };
|
enum { BigEndian, LittleEndian };
|
||||||
enum TBType { WDL, DTZ }; // Used as template parameter
|
enum TBType { WDL, DTZ }; // Used as template parameter
|
||||||
@@ -69,7 +71,7 @@ enum TBFlag { STM = 1, Mapped = 2, WinPlies = 4, LossPlies = 8, Wide = 16, Singl
|
|||||||
inline WDLScore operator-(WDLScore d) { return WDLScore(-int(d)); }
|
inline WDLScore operator-(WDLScore d) { return WDLScore(-int(d)); }
|
||||||
inline Square operator^(Square s, int i) { return Square(int(s) ^ i); }
|
inline Square operator^(Square s, int i) { return Square(int(s) ^ i); }
|
||||||
|
|
||||||
const std::string PieceToChar = " PNBRQK pnbrqk";
|
constexpr std::string_view PieceToChar = " PNBRQK pnbrqk";
|
||||||
|
|
||||||
int MapPawns[SQUARE_NB];
|
int MapPawns[SQUARE_NB];
|
||||||
int MapB1H1H7[SQUARE_NB];
|
int MapB1H1H7[SQUARE_NB];
|
||||||
@@ -140,7 +142,7 @@ struct SparseEntry {
|
|||||||
|
|
||||||
static_assert(sizeof(SparseEntry) == 6, "SparseEntry must be 6 bytes");
|
static_assert(sizeof(SparseEntry) == 6, "SparseEntry must be 6 bytes");
|
||||||
|
|
||||||
typedef uint16_t Sym; // Huffman symbol
|
using Sym = uint16_t; // Huffman symbol
|
||||||
|
|
||||||
struct LR {
|
struct LR {
|
||||||
enum Side { Left, Right };
|
enum Side { Left, Right };
|
||||||
@@ -198,12 +200,9 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Memory map the file and check it. File should be already open and will be
|
// Memory map the file and check it.
|
||||||
// closed after mapping.
|
|
||||||
uint8_t* map(void** baseAddress, uint64_t* mapping, TBType type) {
|
uint8_t* map(void** baseAddress, uint64_t* mapping, TBType type) {
|
||||||
|
if (is_open())
|
||||||
assert(is_open());
|
|
||||||
|
|
||||||
close(); // Need to re-open to get native file descriptor
|
close(); // Need to re-open to get native file descriptor
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
@@ -235,7 +234,7 @@ public:
|
|||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
// Note FILE_FLAG_RANDOM_ACCESS is only a hint to Windows and as such may get ignored.
|
// Note FILE_FLAG_RANDOM_ACCESS is only a hint to Windows and as such may get ignored.
|
||||||
HANDLE fd = CreateFile(fname.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr,
|
HANDLE fd = CreateFileA(fname.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr,
|
||||||
OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, nullptr);
|
OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, nullptr);
|
||||||
|
|
||||||
if (fd == INVALID_HANDLE_VALUE)
|
if (fd == INVALID_HANDLE_VALUE)
|
||||||
@@ -328,7 +327,7 @@ struct PairsData {
|
|||||||
// first access, when the corresponding file is memory mapped.
|
// first access, when the corresponding file is memory mapped.
|
||||||
template<TBType Type>
|
template<TBType Type>
|
||||||
struct TBTable {
|
struct TBTable {
|
||||||
typedef typename std::conditional<Type == WDL, WDLScore, int>::type Ret;
|
using Ret = typename std::conditional<Type == WDL, WDLScore, int>::type;
|
||||||
|
|
||||||
static constexpr int Sides = Type == WDL ? 2 : 1;
|
static constexpr int Sides = Type == WDL ? 2 : 1;
|
||||||
|
|
||||||
@@ -769,7 +768,7 @@ Ret do_probe_table(const Position& pos, T* entry, WDLScore wdl, ProbeState* resu
|
|||||||
goto encode_remaining; // With pawns we have finished special treatments
|
goto encode_remaining; // With pawns we have finished special treatments
|
||||||
}
|
}
|
||||||
|
|
||||||
// In positions withouth pawns, we further flip the squares to ensure leading
|
// In positions without pawns, we further flip the squares to ensure leading
|
||||||
// piece is below RANK_5.
|
// piece is below RANK_5.
|
||||||
if (rank_of(squares[0]) > RANK_4)
|
if (rank_of(squares[0]) > RANK_4)
|
||||||
for (int i = 0; i < size; ++i)
|
for (int i = 0; i < size; ++i)
|
||||||
@@ -812,7 +811,7 @@ Ret do_probe_table(const Position& pos, T* entry, WDLScore wdl, ProbeState* resu
|
|||||||
// Rs "together" in 62 * 61 / 2 ways (we divide by 2 because rooks can be
|
// Rs "together" in 62 * 61 / 2 ways (we divide by 2 because rooks can be
|
||||||
// swapped and still get the same position.)
|
// swapped and still get the same position.)
|
||||||
//
|
//
|
||||||
// In case we have at least 3 unique pieces (inlcuded kings) we encode them
|
// In case we have at least 3 unique pieces (included kings) we encode them
|
||||||
// together.
|
// together.
|
||||||
if (entry->hasUniquePieces) {
|
if (entry->hasUniquePieces) {
|
||||||
|
|
||||||
@@ -827,7 +826,7 @@ Ret do_probe_table(const Position& pos, T* entry, WDLScore wdl, ProbeState* resu
|
|||||||
+ (squares[1] - adjust1)) * 62
|
+ (squares[1] - adjust1)) * 62
|
||||||
+ squares[2] - adjust2;
|
+ squares[2] - adjust2;
|
||||||
|
|
||||||
// First piece is on a1-h8 diagonal, second below: map this occurence to
|
// First piece is on a1-h8 diagonal, second below: map this occurrence to
|
||||||
// 6 to differentiate from the above case, rank_of() maps a1-d4 diagonal
|
// 6 to differentiate from the above case, rank_of() maps a1-d4 diagonal
|
||||||
// to 0...3 and finally MapB1H1H7[] maps the b1-h1-h7 triangle to 0..27.
|
// to 0...3 and finally MapB1H1H7[] maps the b1-h1-h7 triangle to 0..27.
|
||||||
else if (off_A1H8(squares[1]))
|
else if (off_A1H8(squares[1]))
|
||||||
@@ -857,7 +856,7 @@ encode_remaining:
|
|||||||
idx *= d->groupIdx[0];
|
idx *= d->groupIdx[0];
|
||||||
Square* groupSq = squares + d->groupLen[0];
|
Square* groupSq = squares + d->groupLen[0];
|
||||||
|
|
||||||
// Encode remainig pawns then pieces according to square, in ascending order
|
// Encode remaining pawns then pieces according to square, in ascending order
|
||||||
bool remainingPawns = entry->hasPawns && entry->pawnCount[1];
|
bool remainingPawns = entry->hasPawns && entry->pawnCount[1];
|
||||||
|
|
||||||
while (d->groupLen[++next])
|
while (d->groupLen[++next])
|
||||||
@@ -885,7 +884,7 @@ encode_remaining:
|
|||||||
|
|
||||||
// Group together pieces that will be encoded together. The general rule is that
|
// Group together pieces that will be encoded together. The general rule is that
|
||||||
// a group contains pieces of same type and color. The exception is the leading
|
// a group contains pieces of same type and color. The exception is the leading
|
||||||
// group that, in case of positions withouth pawns, can be formed by 3 different
|
// group that, in case of positions without pawns, can be formed by 3 different
|
||||||
// pieces (default) or by the king pair when there is not a unique piece apart
|
// pieces (default) or by the king pair when there is not a unique piece apart
|
||||||
// from the kings. When there are pawns, pawns are always first in pieces[].
|
// from the kings. When there are pawns, pawns are always first in pieces[].
|
||||||
//
|
//
|
||||||
@@ -917,7 +916,7 @@ void set_groups(T& e, PairsData* d, int order[], File f) {
|
|||||||
//
|
//
|
||||||
// This ensures unique encoding for the whole position. The order of the
|
// This ensures unique encoding for the whole position. The order of the
|
||||||
// groups is a per-table parameter and could not follow the canonical leading
|
// groups is a per-table parameter and could not follow the canonical leading
|
||||||
// pawns/pieces -> remainig pawns -> remaining pieces. In particular the
|
// pawns/pieces -> remaining pawns -> remaining pieces. In particular the
|
||||||
// first group is at order[0] position and the remaining pawns, when present,
|
// first group is at order[0] position and the remaining pawns, when present,
|
||||||
// are at order[1] position.
|
// are at order[1] position.
|
||||||
bool pp = e.hasPawns && e.pawnCount[1]; // Pawns on both sides
|
bool pp = e.hasPawns && e.pawnCount[1]; // Pawns on both sides
|
||||||
@@ -937,7 +936,7 @@ void set_groups(T& e, PairsData* d, int order[], File f) {
|
|||||||
d->groupIdx[1] = idx;
|
d->groupIdx[1] = idx;
|
||||||
idx *= Binomial[d->groupLen[1]][48 - d->groupLen[0]];
|
idx *= Binomial[d->groupLen[1]][48 - d->groupLen[0]];
|
||||||
}
|
}
|
||||||
else // Remainig pieces
|
else // Remaining pieces
|
||||||
{
|
{
|
||||||
d->groupIdx[next] = idx;
|
d->groupIdx[next] = idx;
|
||||||
idx *= Binomial[d->groupLen[next]][freeSquares];
|
idx *= Binomial[d->groupLen[next]][freeSquares];
|
||||||
@@ -947,7 +946,7 @@ void set_groups(T& e, PairsData* d, int order[], File f) {
|
|||||||
d->groupIdx[n] = idx;
|
d->groupIdx[n] = idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
// In Recursive Pairing each symbol represents a pair of childern symbols. So
|
// In Recursive Pairing each symbol represents a pair of children symbols. So
|
||||||
// read d->btree[] symbols data and expand each one in his left and right child
|
// read d->btree[] symbols data and expand each one in his left and right child
|
||||||
// symbol until reaching the leafs that represent the symbol value.
|
// symbol until reaching the leafs that represent the symbol value.
|
||||||
uint8_t set_symlen(PairsData* d, Sym s, std::vector<bool>& visited) {
|
uint8_t set_symlen(PairsData* d, Sym s, std::vector<bool>& visited) {
|
||||||
@@ -1290,7 +1289,7 @@ void Tablebases::init(const std::string& paths) {
|
|||||||
for (auto s : diagonal)
|
for (auto s : diagonal)
|
||||||
MapA1D1D4[s] = code++;
|
MapA1D1D4[s] = code++;
|
||||||
|
|
||||||
// MapKK[] encodes all the 461 possible legal positions of two kings where
|
// MapKK[] encodes all the 462 possible legal positions of two kings where
|
||||||
// the first is in the a1-d1-d4 triangle. If the first king is on the a1-d4
|
// the first is in the a1-d1-d4 triangle. If the first king is on the a1-d4
|
||||||
// diagonal, the other one shall not to be above the a1-h8 diagonal.
|
// diagonal, the other one shall not to be above the a1-h8 diagonal.
|
||||||
std::vector<std::pair<int, Square>> bothOnDiagonal;
|
std::vector<std::pair<int, Square>> bothOnDiagonal;
|
||||||
@@ -1317,7 +1316,7 @@ void Tablebases::init(const std::string& paths) {
|
|||||||
for (auto p : bothOnDiagonal)
|
for (auto p : bothOnDiagonal)
|
||||||
MapKK[p.first][p.second] = code++;
|
MapKK[p.first][p.second] = code++;
|
||||||
|
|
||||||
// Binomial[] stores the Binomial Coefficents using Pascal rule. There
|
// Binomial[] stores the Binomial Coefficients using Pascal rule. There
|
||||||
// are Binomial[k][n] ways to choose k elements from a set of n elements.
|
// are Binomial[k][n] ways to choose k elements from a set of n elements.
|
||||||
Binomial[0][0] = 1;
|
Binomial[0][0] = 1;
|
||||||
|
|
||||||
@@ -1337,7 +1336,7 @@ void Tablebases::init(const std::string& paths) {
|
|||||||
for (int leadPawnsCnt = 1; leadPawnsCnt <= 5; ++leadPawnsCnt)
|
for (int leadPawnsCnt = 1; leadPawnsCnt <= 5; ++leadPawnsCnt)
|
||||||
for (File f = FILE_A; f <= FILE_D; ++f)
|
for (File f = FILE_A; f <= FILE_D; ++f)
|
||||||
{
|
{
|
||||||
// Restart the index at every file because TB table is splitted
|
// Restart the index at every file because TB table is split
|
||||||
// by file, so we can reuse the same index for different files.
|
// by file, so we can reuse the same index for different files.
|
||||||
int idx = 0;
|
int idx = 0;
|
||||||
|
|
||||||
@@ -1513,7 +1512,7 @@ int Tablebases::probe_dtz(Position& pos, ProbeState* result) {
|
|||||||
// A return value false indicates that not all probes were successful.
|
// A return value false indicates that not all probes were successful.
|
||||||
bool Tablebases::root_probe(Position& pos, Search::RootMoves& rootMoves) {
|
bool Tablebases::root_probe(Position& pos, Search::RootMoves& rootMoves) {
|
||||||
|
|
||||||
ProbeState result;
|
ProbeState result = OK;
|
||||||
StateInfo st;
|
StateInfo st;
|
||||||
|
|
||||||
// Obtain 50-move counter for the root position
|
// Obtain 50-move counter for the root position
|
||||||
@@ -1522,7 +1521,7 @@ bool Tablebases::root_probe(Position& pos, Search::RootMoves& rootMoves) {
|
|||||||
// Check whether a position was repeated since the last zeroing move.
|
// Check whether a position was repeated since the last zeroing move.
|
||||||
bool rep = pos.has_repeated();
|
bool rep = pos.has_repeated();
|
||||||
|
|
||||||
int dtz, bound = Options["Syzygy50MoveRule"] ? 900 : 1;
|
int dtz, bound = Options["Syzygy50MoveRule"] ? (MAX_DTZ - 100) : 1;
|
||||||
|
|
||||||
// Probe and rank each move
|
// Probe and rank each move
|
||||||
for (auto& m : rootMoves)
|
for (auto& m : rootMoves)
|
||||||
@@ -1565,8 +1564,8 @@ bool Tablebases::root_probe(Position& pos, Search::RootMoves& rootMoves) {
|
|||||||
|
|
||||||
// Better moves are ranked higher. Certain wins are ranked equally.
|
// Better moves are ranked higher. Certain wins are ranked equally.
|
||||||
// Losing moves are ranked equally unless a 50-move draw is in sight.
|
// Losing moves are ranked equally unless a 50-move draw is in sight.
|
||||||
int r = dtz > 0 ? (dtz + cnt50 <= 99 && !rep ? 1000 : 1000 - (dtz + cnt50))
|
int r = dtz > 0 ? (dtz + cnt50 <= 99 && !rep ? MAX_DTZ : MAX_DTZ - (dtz + cnt50))
|
||||||
: dtz < 0 ? (-dtz * 2 + cnt50 < 100 ? -1000 : -1000 + (-dtz + cnt50))
|
: dtz < 0 ? (-dtz * 2 + cnt50 < 100 ? -MAX_DTZ : -MAX_DTZ + (-dtz + cnt50))
|
||||||
: 0;
|
: 0;
|
||||||
m.tbRank = r;
|
m.tbRank = r;
|
||||||
|
|
||||||
@@ -1574,9 +1573,9 @@ bool Tablebases::root_probe(Position& pos, Search::RootMoves& rootMoves) {
|
|||||||
// 1 cp to cursed wins and let it grow to 49 cp as the positions gets
|
// 1 cp to cursed wins and let it grow to 49 cp as the positions gets
|
||||||
// closer to a real win.
|
// closer to a real win.
|
||||||
m.tbScore = r >= bound ? VALUE_MATE - MAX_PLY - 1
|
m.tbScore = r >= bound ? VALUE_MATE - MAX_PLY - 1
|
||||||
: r > 0 ? Value((std::max( 3, r - 800) * int(PawnValueEg)) / 200)
|
: r > 0 ? Value((std::max( 3, r - (MAX_DTZ - 200)) * int(PawnValueEg)) / 200)
|
||||||
: r == 0 ? VALUE_DRAW
|
: r == 0 ? VALUE_DRAW
|
||||||
: r > -bound ? Value((std::min(-3, r + 800) * int(PawnValueEg)) / 200)
|
: r > -bound ? Value((std::min(-3, r + (MAX_DTZ - 200)) * int(PawnValueEg)) / 200)
|
||||||
: -VALUE_MATE + MAX_PLY + 1;
|
: -VALUE_MATE + MAX_PLY + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1590,9 +1589,9 @@ bool Tablebases::root_probe(Position& pos, Search::RootMoves& rootMoves) {
|
|||||||
// A return value false indicates that not all probes were successful.
|
// A return value false indicates that not all probes were successful.
|
||||||
bool Tablebases::root_probe_wdl(Position& pos, Search::RootMoves& rootMoves) {
|
bool Tablebases::root_probe_wdl(Position& pos, Search::RootMoves& rootMoves) {
|
||||||
|
|
||||||
static const int WDL_to_rank[] = { -1000, -899, 0, 899, 1000 };
|
static const int WDL_to_rank[] = { -MAX_DTZ, -MAX_DTZ + 101, 0, MAX_DTZ - 101, MAX_DTZ };
|
||||||
|
|
||||||
ProbeState result;
|
ProbeState result = OK;
|
||||||
StateInfo st;
|
StateInfo st;
|
||||||
WDLScore wdl;
|
WDLScore wdl;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -31,14 +31,12 @@ enum WDLScore {
|
|||||||
WDLDraw = 0, // Draw
|
WDLDraw = 0, // Draw
|
||||||
WDLCursedWin = 1, // Win, but draw under 50-move rule
|
WDLCursedWin = 1, // Win, but draw under 50-move rule
|
||||||
WDLWin = 2, // Win
|
WDLWin = 2, // Win
|
||||||
|
|
||||||
WDLScoreNone = -1000
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Possible states after a probing operation
|
// Possible states after a probing operation
|
||||||
enum ProbeState {
|
enum ProbeState {
|
||||||
FAIL = 0, // Probe failed (missing file table)
|
FAIL = 0, // Probe failed (missing file table)
|
||||||
OK = 1, // Probe succesful
|
OK = 1, // Probe successful
|
||||||
CHANGE_STM = -1, // DTZ should check the other side
|
CHANGE_STM = -1, // DTZ should check the other side
|
||||||
ZEROING_BEST_MOVE = 2 // Best move zeroes DTZ (capture or pawn move)
|
ZEROING_BEST_MOVE = 2 // Best move zeroes DTZ (capture or pawn move)
|
||||||
};
|
};
|
||||||
|
|||||||
+31
-29
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -59,26 +59,22 @@ void Thread::clear() {
|
|||||||
|
|
||||||
counterMoves.fill(MOVE_NONE);
|
counterMoves.fill(MOVE_NONE);
|
||||||
mainHistory.fill(0);
|
mainHistory.fill(0);
|
||||||
lowPlyHistory.fill(0);
|
|
||||||
captureHistory.fill(0);
|
captureHistory.fill(0);
|
||||||
|
|
||||||
for (bool inCheck : { false, true })
|
for (bool inCheck : { false, true })
|
||||||
for (StatsType c : { NoCaptures, Captures })
|
for (StatsType c : { NoCaptures, Captures })
|
||||||
{
|
|
||||||
for (auto& to : continuationHistory[inCheck][c])
|
for (auto& to : continuationHistory[inCheck][c])
|
||||||
for (auto& h : to)
|
for (auto& h : to)
|
||||||
h->fill(0);
|
h->fill(-71);
|
||||||
continuationHistory[inCheck][c][NO_PIECE][0]->fill(Search::CounterMovePruneThreshold - 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Thread::start_searching() wakes up the thread that will start the search
|
/// Thread::start_searching() wakes up the thread that will start the search
|
||||||
|
|
||||||
void Thread::start_searching() {
|
void Thread::start_searching() {
|
||||||
|
mutex.lock();
|
||||||
std::lock_guard<std::mutex> lk(mutex);
|
|
||||||
searching = true;
|
searching = true;
|
||||||
|
mutex.unlock(); // Unlock before notifying saves a few CPU-cycles
|
||||||
cv.notify_one(); // Wake up the thread in idle_loop()
|
cv.notify_one(); // Wake up the thread in idle_loop()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,20 +124,20 @@ void Thread::idle_loop() {
|
|||||||
|
|
||||||
void ThreadPool::set(size_t requested) {
|
void ThreadPool::set(size_t requested) {
|
||||||
|
|
||||||
if (size() > 0) // destroy any existing thread(s)
|
if (threads.size() > 0) // destroy any existing thread(s)
|
||||||
{
|
{
|
||||||
main()->wait_for_search_finished();
|
main()->wait_for_search_finished();
|
||||||
|
|
||||||
while (size() > 0)
|
while (threads.size() > 0)
|
||||||
delete back(), pop_back();
|
delete threads.back(), threads.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (requested > 0) // create new thread(s)
|
if (requested > 0) // create new thread(s)
|
||||||
{
|
{
|
||||||
push_back(new MainThread(0));
|
threads.push_back(new MainThread(0));
|
||||||
|
|
||||||
while (size() < requested)
|
while (threads.size() < requested)
|
||||||
push_back(new Thread(size()));
|
threads.push_back(new Thread(threads.size()));
|
||||||
clear();
|
clear();
|
||||||
|
|
||||||
// Reallocate the hash with the new threadpool size
|
// Reallocate the hash with the new threadpool size
|
||||||
@@ -157,11 +153,12 @@ void ThreadPool::set(size_t requested) {
|
|||||||
|
|
||||||
void ThreadPool::clear() {
|
void ThreadPool::clear() {
|
||||||
|
|
||||||
for (Thread* th : *this)
|
for (Thread* th : threads)
|
||||||
th->clear();
|
th->clear();
|
||||||
|
|
||||||
main()->callsCnt = 0;
|
main()->callsCnt = 0;
|
||||||
main()->bestPreviousScore = VALUE_INFINITE;
|
main()->bestPreviousScore = VALUE_INFINITE;
|
||||||
|
main()->bestPreviousAverageScore = VALUE_INFINITE;
|
||||||
main()->previousTimeReduction = 1.0;
|
main()->previousTimeReduction = 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,7 +186,7 @@ void ThreadPool::start_thinking(Position& pos, StateListPtr& states,
|
|||||||
Tablebases::rank_root_moves(pos, rootMoves);
|
Tablebases::rank_root_moves(pos, rootMoves);
|
||||||
|
|
||||||
// After ownership transfer 'states' becomes empty, so if we stop the search
|
// After ownership transfer 'states' becomes empty, so if we stop the search
|
||||||
// and call 'go' again without setting a new position states.get() == NULL.
|
// and call 'go' again without setting a new position states.get() == nullptr.
|
||||||
assert(states.get() || setupStates.get());
|
assert(states.get() || setupStates.get());
|
||||||
|
|
||||||
if (states.get())
|
if (states.get())
|
||||||
@@ -200,7 +197,7 @@ void ThreadPool::start_thinking(Position& pos, StateListPtr& states,
|
|||||||
// be deduced from a fen string, so set() clears them and they are set from
|
// be deduced from a fen string, so set() clears them and they are set from
|
||||||
// setupStates->back() later. The rootState is per thread, earlier states are shared
|
// setupStates->back() later. The rootState is per thread, earlier states are shared
|
||||||
// since they are read-only.
|
// since they are read-only.
|
||||||
for (Thread* th : *this)
|
for (Thread* th : threads)
|
||||||
{
|
{
|
||||||
th->nodes = th->tbHits = th->nmpMinPly = th->bestMoveChanges = 0;
|
th->nodes = th->tbHits = th->nmpMinPly = th->bestMoveChanges = 0;
|
||||||
th->rootDepth = th->completedDepth = 0;
|
th->rootDepth = th->completedDepth = 0;
|
||||||
@@ -214,20 +211,23 @@ void ThreadPool::start_thinking(Position& pos, StateListPtr& states,
|
|||||||
|
|
||||||
Thread* ThreadPool::get_best_thread() const {
|
Thread* ThreadPool::get_best_thread() const {
|
||||||
|
|
||||||
Thread* bestThread = front();
|
Thread* bestThread = threads.front();
|
||||||
std::map<Move, int64_t> votes;
|
std::map<Move, int64_t> votes;
|
||||||
Value minScore = VALUE_NONE;
|
Value minScore = VALUE_NONE;
|
||||||
|
|
||||||
// Find minimum score of all threads
|
// Find minimum score of all threads
|
||||||
for (Thread* th: *this)
|
for (Thread* th: threads)
|
||||||
minScore = std::min(minScore, th->rootMoves[0].score);
|
minScore = std::min(minScore, th->rootMoves[0].score);
|
||||||
|
|
||||||
// Vote according to score and depth, and select the best thread
|
// Vote according to score and depth, and select the best thread
|
||||||
for (Thread* th : *this)
|
auto thread_value = [minScore](Thread* th) {
|
||||||
{
|
return (th->rootMoves[0].score - minScore + 14) * int(th->completedDepth);
|
||||||
votes[th->rootMoves[0].pv[0]] +=
|
};
|
||||||
(th->rootMoves[0].score - minScore + 14) * int(th->completedDepth);
|
|
||||||
|
|
||||||
|
for (Thread* th : threads)
|
||||||
|
votes[th->rootMoves[0].pv[0]] += thread_value(th);
|
||||||
|
|
||||||
|
for (Thread* th : threads)
|
||||||
if (abs(bestThread->rootMoves[0].score) >= VALUE_TB_WIN_IN_MAX_PLY)
|
if (abs(bestThread->rootMoves[0].score) >= VALUE_TB_WIN_IN_MAX_PLY)
|
||||||
{
|
{
|
||||||
// Make sure we pick the shortest mate / TB conversion or stave off mate the longest
|
// Make sure we pick the shortest mate / TB conversion or stave off mate the longest
|
||||||
@@ -236,9 +236,11 @@ Thread* ThreadPool::get_best_thread() const {
|
|||||||
}
|
}
|
||||||
else if ( th->rootMoves[0].score >= VALUE_TB_WIN_IN_MAX_PLY
|
else if ( th->rootMoves[0].score >= VALUE_TB_WIN_IN_MAX_PLY
|
||||||
|| ( th->rootMoves[0].score > VALUE_TB_LOSS_IN_MAX_PLY
|
|| ( th->rootMoves[0].score > VALUE_TB_LOSS_IN_MAX_PLY
|
||||||
&& votes[th->rootMoves[0].pv[0]] > votes[bestThread->rootMoves[0].pv[0]]))
|
&& ( votes[th->rootMoves[0].pv[0]] > votes[bestThread->rootMoves[0].pv[0]]
|
||||||
|
|| ( votes[th->rootMoves[0].pv[0]] == votes[bestThread->rootMoves[0].pv[0]]
|
||||||
|
&& thread_value(th) * int(th->rootMoves[0].pv.size() > 2)
|
||||||
|
> thread_value(bestThread) * int(bestThread->rootMoves[0].pv.size() > 2)))))
|
||||||
bestThread = th;
|
bestThread = th;
|
||||||
}
|
|
||||||
|
|
||||||
return bestThread;
|
return bestThread;
|
||||||
}
|
}
|
||||||
@@ -248,8 +250,8 @@ Thread* ThreadPool::get_best_thread() const {
|
|||||||
|
|
||||||
void ThreadPool::start_searching() {
|
void ThreadPool::start_searching() {
|
||||||
|
|
||||||
for (Thread* th : *this)
|
for (Thread* th : threads)
|
||||||
if (th != front())
|
if (th != threads.front())
|
||||||
th->start_searching();
|
th->start_searching();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,8 +260,8 @@ void ThreadPool::start_searching() {
|
|||||||
|
|
||||||
void ThreadPool::wait_for_search_finished() const {
|
void ThreadPool::wait_for_search_finished() const {
|
||||||
|
|
||||||
for (Thread* th : *this)
|
for (Thread* th : threads)
|
||||||
if (th != front())
|
if (th != threads.front())
|
||||||
th->wait_for_search_finished();
|
th->wait_for_search_finished();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+15
-11
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -60,24 +60,19 @@ public:
|
|||||||
Pawns::Table pawnsTable;
|
Pawns::Table pawnsTable;
|
||||||
Material::Table materialTable;
|
Material::Table materialTable;
|
||||||
size_t pvIdx, pvLast;
|
size_t pvIdx, pvLast;
|
||||||
RunningAverage doubleExtensionAverage[COLOR_NB];
|
|
||||||
uint64_t nodesLastExplosive;
|
|
||||||
uint64_t nodesLastNormal;
|
|
||||||
std::atomic<uint64_t> nodes, tbHits, bestMoveChanges;
|
std::atomic<uint64_t> nodes, tbHits, bestMoveChanges;
|
||||||
int selDepth, nmpMinPly;
|
int selDepth, nmpMinPly;
|
||||||
Color nmpColor;
|
Value bestValue, optimism[COLOR_NB];
|
||||||
ExplosionState state;
|
|
||||||
|
|
||||||
Position rootPos;
|
Position rootPos;
|
||||||
StateInfo rootState;
|
StateInfo rootState;
|
||||||
Search::RootMoves rootMoves;
|
Search::RootMoves rootMoves;
|
||||||
Depth rootDepth, completedDepth;
|
Depth rootDepth, completedDepth;
|
||||||
|
Value rootDelta;
|
||||||
CounterMoveHistory counterMoves;
|
CounterMoveHistory counterMoves;
|
||||||
ButterflyHistory mainHistory;
|
ButterflyHistory mainHistory;
|
||||||
LowPlyHistory lowPlyHistory;
|
|
||||||
CapturePieceToHistory captureHistory;
|
CapturePieceToHistory captureHistory;
|
||||||
ContinuationHistory continuationHistory[2][2];
|
ContinuationHistory continuationHistory[2][2];
|
||||||
Score trend;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -92,6 +87,7 @@ struct MainThread : public Thread {
|
|||||||
|
|
||||||
double previousTimeReduction;
|
double previousTimeReduction;
|
||||||
Value bestPreviousScore;
|
Value bestPreviousScore;
|
||||||
|
Value bestPreviousAverageScore;
|
||||||
Value iterValue[4];
|
Value iterValue[4];
|
||||||
int callsCnt;
|
int callsCnt;
|
||||||
bool stopOnPonderhit;
|
bool stopOnPonderhit;
|
||||||
@@ -103,13 +99,13 @@ struct MainThread : public Thread {
|
|||||||
/// parking and, most importantly, launching a thread. All the access to threads
|
/// parking and, most importantly, launching a thread. All the access to threads
|
||||||
/// is done through this class.
|
/// is done through this class.
|
||||||
|
|
||||||
struct ThreadPool : public std::vector<Thread*> {
|
struct ThreadPool {
|
||||||
|
|
||||||
void start_thinking(Position&, StateListPtr&, const Search::LimitsType&, bool = false);
|
void start_thinking(Position&, StateListPtr&, const Search::LimitsType&, bool = false);
|
||||||
void clear();
|
void clear();
|
||||||
void set(size_t);
|
void set(size_t);
|
||||||
|
|
||||||
MainThread* main() const { return static_cast<MainThread*>(front()); }
|
MainThread* main() const { return static_cast<MainThread*>(threads.front()); }
|
||||||
uint64_t nodes_searched() const { return accumulate(&Thread::nodes); }
|
uint64_t nodes_searched() const { return accumulate(&Thread::nodes); }
|
||||||
uint64_t tb_hits() const { return accumulate(&Thread::tbHits); }
|
uint64_t tb_hits() const { return accumulate(&Thread::tbHits); }
|
||||||
Thread* get_best_thread() const;
|
Thread* get_best_thread() const;
|
||||||
@@ -118,13 +114,21 @@ struct ThreadPool : public std::vector<Thread*> {
|
|||||||
|
|
||||||
std::atomic_bool stop, increaseDepth;
|
std::atomic_bool stop, increaseDepth;
|
||||||
|
|
||||||
|
auto cbegin() const noexcept { return threads.cbegin(); }
|
||||||
|
auto begin() noexcept { return threads.begin(); }
|
||||||
|
auto end() noexcept { return threads.end(); }
|
||||||
|
auto cend() const noexcept { return threads.cend(); }
|
||||||
|
auto size() const noexcept { return threads.size(); }
|
||||||
|
auto empty() const noexcept { return threads.empty(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
StateListPtr setupStates;
|
StateListPtr setupStates;
|
||||||
|
std::vector<Thread*> threads;
|
||||||
|
|
||||||
uint64_t accumulate(std::atomic<uint64_t> Thread::* member) const {
|
uint64_t accumulate(std::atomic<uint64_t> Thread::* member) const {
|
||||||
|
|
||||||
uint64_t sum = 0;
|
uint64_t sum = 0;
|
||||||
for (Thread* th : *this)
|
for (Thread* th : threads)
|
||||||
sum += (th->*member).load(std::memory_order_relaxed);
|
sum += (th->*member).load(std::memory_order_relaxed);
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -41,7 +41,7 @@ void* start_routine(void* ptr)
|
|||||||
P* p = reinterpret_cast<P*>(ptr);
|
P* p = reinterpret_cast<P*>(ptr);
|
||||||
(p->first->*(p->second))(); // Call member function pointer
|
(p->first->*(p->second))(); // Call member function pointer
|
||||||
delete p;
|
delete p;
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
class NativeThread {
|
class NativeThread {
|
||||||
@@ -56,7 +56,7 @@ public:
|
|||||||
pthread_attr_setstacksize(attr, TH_STACK_SIZE);
|
pthread_attr_setstacksize(attr, TH_STACK_SIZE);
|
||||||
pthread_create(&thread, attr, start_routine<T>, new P(obj, fun));
|
pthread_create(&thread, attr, start_routine<T>, new P(obj, fun));
|
||||||
}
|
}
|
||||||
void join() { pthread_join(thread, NULL); }
|
void join() { pthread_join(thread, nullptr); }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Stockfish
|
} // namespace Stockfish
|
||||||
@@ -65,7 +65,7 @@ public:
|
|||||||
|
|
||||||
namespace Stockfish {
|
namespace Stockfish {
|
||||||
|
|
||||||
typedef std::thread NativeThread;
|
using NativeThread = std::thread;
|
||||||
|
|
||||||
} // namespace Stockfish
|
} // namespace Stockfish
|
||||||
|
|
||||||
|
|||||||
+8
-4
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -36,6 +36,12 @@ TimeManagement Time; // Our global time management object
|
|||||||
|
|
||||||
void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) {
|
void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) {
|
||||||
|
|
||||||
|
// if we have no time, no need to initialize TM, except for the start time,
|
||||||
|
// which is used by movetime.
|
||||||
|
startTime = limits.startTime;
|
||||||
|
if (limits.time[us] == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
TimePoint moveOverhead = TimePoint(Options["Move Overhead"]);
|
TimePoint moveOverhead = TimePoint(Options["Move Overhead"]);
|
||||||
TimePoint slowMover = TimePoint(Options["Slow Mover"]);
|
TimePoint slowMover = TimePoint(Options["Slow Mover"]);
|
||||||
TimePoint npmsec = TimePoint(Options["nodestime"]);
|
TimePoint npmsec = TimePoint(Options["nodestime"]);
|
||||||
@@ -59,8 +65,6 @@ void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) {
|
|||||||
limits.npmsec = npmsec;
|
limits.npmsec = npmsec;
|
||||||
}
|
}
|
||||||
|
|
||||||
startTime = limits.startTime;
|
|
||||||
|
|
||||||
// Maximum move horizon of 50 moves
|
// Maximum move horizon of 50 moves
|
||||||
int mtg = limits.movestogo ? std::min(limits.movestogo, 50) : 50;
|
int mtg = limits.movestogo ? std::min(limits.movestogo, 50) : 50;
|
||||||
|
|
||||||
@@ -80,7 +84,7 @@ void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) {
|
|||||||
// game time for the current move, so also cap to 20% of available game time.
|
// game time for the current move, so also cap to 20% of available game time.
|
||||||
if (limits.movestogo == 0)
|
if (limits.movestogo == 0)
|
||||||
{
|
{
|
||||||
optScale = std::min(0.0084 + std::pow(ply + 3.0, 0.5) * 0.0042,
|
optScale = std::min(0.0120 + std::pow(ply + 3.0, 0.45) * 0.0039,
|
||||||
0.2 * limits.time[us] / double(timeLeft))
|
0.2 * limits.time[us] / double(timeLeft))
|
||||||
* optExtra;
|
* optExtra;
|
||||||
maxScale = std::min(7.0, 4.0 + ply / 12.0);
|
maxScale = std::min(7.0, 4.0 + ply / 12.0);
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
+4
-4
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -42,7 +42,7 @@ void TTEntry::save(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev)
|
|||||||
// Overwrite less valuable entries (cheapest checks first)
|
// Overwrite less valuable entries (cheapest checks first)
|
||||||
if ( b == BOUND_EXACT
|
if ( b == BOUND_EXACT
|
||||||
|| (uint16_t)k != key16
|
|| (uint16_t)k != key16
|
||||||
|| d - DEPTH_OFFSET > depth8 - 4)
|
|| d - DEPTH_OFFSET + 2 * pv > depth8 - 4)
|
||||||
{
|
{
|
||||||
assert(d > DEPTH_OFFSET);
|
assert(d > DEPTH_OFFSET);
|
||||||
assert(d < 256 + DEPTH_OFFSET);
|
assert(d < 256 + DEPTH_OFFSET);
|
||||||
@@ -87,7 +87,7 @@ void TranspositionTable::clear() {
|
|||||||
|
|
||||||
std::vector<std::thread> threads;
|
std::vector<std::thread> threads;
|
||||||
|
|
||||||
for (size_t idx = 0; idx < Options["Threads"]; ++idx)
|
for (size_t idx = 0; idx < size_t(Options["Threads"]); ++idx)
|
||||||
{
|
{
|
||||||
threads.emplace_back([this, idx]() {
|
threads.emplace_back([this, idx]() {
|
||||||
|
|
||||||
@@ -98,7 +98,7 @@ void TranspositionTable::clear() {
|
|||||||
// Each thread will zero its part of the hash table
|
// Each thread will zero its part of the hash table
|
||||||
const size_t stride = size_t(clusterCount / Options["Threads"]),
|
const size_t stride = size_t(clusterCount / Options["Threads"]),
|
||||||
start = size_t(stride * idx),
|
start = size_t(stride * idx),
|
||||||
len = idx != Options["Threads"] - 1 ?
|
len = idx != size_t(Options["Threads"]) - 1 ?
|
||||||
stride : clusterCount - start;
|
stride : clusterCount - start;
|
||||||
|
|
||||||
std::memset(&table[start], 0, len * sizeof(Cluster));
|
std::memset(&table[start], 0, len * sizeof(Cluster));
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
+5
-5
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -26,8 +26,8 @@
|
|||||||
|
|
||||||
namespace Stockfish {
|
namespace Stockfish {
|
||||||
|
|
||||||
typedef std::pair<int, int> Range; // Option's min-max values
|
using Range = std::pair<int, int>; // Option's min-max values
|
||||||
typedef Range (RangeFun) (int);
|
using RangeFun = Range (int);
|
||||||
|
|
||||||
// Default Range function, to calculate Option's min-max values
|
// Default Range function, to calculate Option's min-max values
|
||||||
inline Range default_range(int v) {
|
inline Range default_range(int v) {
|
||||||
@@ -75,7 +75,7 @@ struct SetRange {
|
|||||||
|
|
||||||
class Tune {
|
class Tune {
|
||||||
|
|
||||||
typedef void (PostUpdate) (); // Post-update function
|
using PostUpdate = void (); // Post-update function
|
||||||
|
|
||||||
Tune() { read_results(); }
|
Tune() { read_results(); }
|
||||||
Tune(const Tune&) = delete;
|
Tune(const Tune&) = delete;
|
||||||
@@ -84,7 +84,7 @@ class Tune {
|
|||||||
|
|
||||||
static Tune& instance() { static Tune t; return t; } // Singleton
|
static Tune& instance() { static Tune t; return t; } // Singleton
|
||||||
|
|
||||||
// Use polymorphism to accomodate Entry of different types in the same vector
|
// Use polymorphism to accommodate Entry of different types in the same vector
|
||||||
struct EntryBase {
|
struct EntryBase {
|
||||||
virtual ~EntryBase() = default;
|
virtual ~EntryBase() = default;
|
||||||
virtual void init_option() = 0;
|
virtual void init_option() = 0;
|
||||||
|
|||||||
+13
-17
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -103,8 +103,8 @@ constexpr bool Is64Bit = true;
|
|||||||
constexpr bool Is64Bit = false;
|
constexpr bool Is64Bit = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef uint64_t Key;
|
using Key = uint64_t;
|
||||||
typedef uint64_t Bitboard;
|
using Bitboard = uint64_t;
|
||||||
|
|
||||||
constexpr int MAX_MOVES = 256;
|
constexpr int MAX_MOVES = 256;
|
||||||
constexpr int MAX_PLY = 246;
|
constexpr int MAX_PLY = 246;
|
||||||
@@ -173,11 +173,6 @@ enum Bound {
|
|||||||
BOUND_EXACT = BOUND_UPPER | BOUND_LOWER
|
BOUND_EXACT = BOUND_UPPER | BOUND_LOWER
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ExplosionState {
|
|
||||||
EXPLOSION_NONE,
|
|
||||||
MUST_CALM_DOWN
|
|
||||||
};
|
|
||||||
|
|
||||||
enum Value : int {
|
enum Value : int {
|
||||||
VALUE_ZERO = 0,
|
VALUE_ZERO = 0,
|
||||||
VALUE_DRAW = 0,
|
VALUE_DRAW = 0,
|
||||||
@@ -191,6 +186,9 @@ enum Value : int {
|
|||||||
VALUE_MATE_IN_MAX_PLY = VALUE_MATE - MAX_PLY,
|
VALUE_MATE_IN_MAX_PLY = VALUE_MATE - MAX_PLY,
|
||||||
VALUE_MATED_IN_MAX_PLY = -VALUE_MATE_IN_MAX_PLY,
|
VALUE_MATED_IN_MAX_PLY = -VALUE_MATE_IN_MAX_PLY,
|
||||||
|
|
||||||
|
// In the code, we make the assumption that these values
|
||||||
|
// are such that non_pawn_material() can be used to uniquely
|
||||||
|
// identify the material on the board.
|
||||||
PawnValueMg = 126, PawnValueEg = 208,
|
PawnValueMg = 126, PawnValueEg = 208,
|
||||||
KnightValueMg = 781, KnightValueEg = 854,
|
KnightValueMg = 781, KnightValueEg = 854,
|
||||||
BishopValueMg = 825, BishopValueEg = 915,
|
BishopValueMg = 825, BishopValueEg = 915,
|
||||||
@@ -220,7 +218,7 @@ constexpr Value PieceValue[PHASE_NB][PIECE_NB] = {
|
|||||||
VALUE_ZERO, PawnValueEg, KnightValueEg, BishopValueEg, RookValueEg, QueenValueEg, VALUE_ZERO, VALUE_ZERO }
|
VALUE_ZERO, PawnValueEg, KnightValueEg, BishopValueEg, RookValueEg, QueenValueEg, VALUE_ZERO, VALUE_ZERO }
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef int Depth;
|
using Depth = int;
|
||||||
|
|
||||||
enum : int {
|
enum : int {
|
||||||
DEPTH_QS_CHECKS = 0,
|
DEPTH_QS_CHECKS = 0,
|
||||||
@@ -418,6 +416,10 @@ inline Color color_of(Piece pc) {
|
|||||||
return Color(pc >> 3);
|
return Color(pc >> 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr bool is_ok(Move m) {
|
||||||
|
return m != MOVE_NONE && m != MOVE_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
constexpr bool is_ok(Square s) {
|
constexpr bool is_ok(Square s) {
|
||||||
return s >= SQ_A1 && s <= SQ_H8;
|
return s >= SQ_A1 && s <= SQ_H8;
|
||||||
}
|
}
|
||||||
@@ -447,10 +449,12 @@ constexpr Direction pawn_push(Color c) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constexpr Square from_sq(Move m) {
|
constexpr Square from_sq(Move m) {
|
||||||
|
assert(is_ok(m));
|
||||||
return Square((m >> 6) & 0x3F);
|
return Square((m >> 6) & 0x3F);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr Square to_sq(Move m) {
|
constexpr Square to_sq(Move m) {
|
||||||
|
assert(is_ok(m));
|
||||||
return Square(m & 0x3F);
|
return Square(m & 0x3F);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -470,19 +474,11 @@ constexpr Move make_move(Square from, Square to) {
|
|||||||
return Move((from << 6) + to);
|
return Move((from << 6) + to);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr Move reverse_move(Move m) {
|
|
||||||
return make_move(to_sq(m), from_sq(m));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<MoveType T>
|
template<MoveType T>
|
||||||
constexpr Move make(Square from, Square to, PieceType pt = KNIGHT) {
|
constexpr Move make(Square from, Square to, PieceType pt = KNIGHT) {
|
||||||
return Move(T + ((pt - KNIGHT) << 12) + (from << 6) + to);
|
return Move(T + ((pt - KNIGHT) << 12) + (from << 6) + to);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool is_ok(Move m) {
|
|
||||||
return from_sq(m) != to_sq(m); // Catch MOVE_NULL and MOVE_NONE
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Based on a congruential pseudo random number generator
|
/// Based on a congruential pseudo random number generator
|
||||||
constexpr Key make_key(uint64_t seed) {
|
constexpr Key make_key(uint64_t seed) {
|
||||||
return seed * 6364136223846793005ULL + 1442695040888963407ULL;
|
return seed * 6364136223846793005ULL + 1442695040888963407ULL;
|
||||||
|
|||||||
+86
-71
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "benchmark.h"
|
||||||
#include "evaluate.h"
|
#include "evaluate.h"
|
||||||
#include "movegen.h"
|
#include "movegen.h"
|
||||||
#include "position.h"
|
#include "position.h"
|
||||||
@@ -31,23 +32,22 @@
|
|||||||
#include "tt.h"
|
#include "tt.h"
|
||||||
#include "uci.h"
|
#include "uci.h"
|
||||||
#include "syzygy/tbprobe.h"
|
#include "syzygy/tbprobe.h"
|
||||||
|
#include "nnue/evaluate_nnue.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
namespace Stockfish {
|
namespace Stockfish {
|
||||||
|
|
||||||
extern vector<string> setup_bench(const Position&, istream&);
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// FEN string of the initial position, normal chess
|
// FEN string for the initial position in standard chess
|
||||||
const char* StartFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
const char* StartFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
||||||
|
|
||||||
|
|
||||||
// position() is called when engine receives the "position" UCI command.
|
// position() is called when the engine receives the "position" UCI command.
|
||||||
// The function sets up the position described in the given FEN string ("fen")
|
// It sets up the position that is described in the given FEN string ("fen") or
|
||||||
// or the starting position ("startpos") and then makes the moves given in the
|
// the initial position ("startpos") and then makes the moves given in the following
|
||||||
// following move list ("moves").
|
// move list ("moves").
|
||||||
|
|
||||||
void position(Position& pos, istringstream& is, StateListPtr& states) {
|
void position(Position& pos, istringstream& is, StateListPtr& states) {
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ namespace {
|
|||||||
if (token == "startpos")
|
if (token == "startpos")
|
||||||
{
|
{
|
||||||
fen = StartFEN;
|
fen = StartFEN;
|
||||||
is >> token; // Consume "moves" token if any
|
is >> token; // Consume the "moves" token, if any
|
||||||
}
|
}
|
||||||
else if (token == "fen")
|
else if (token == "fen")
|
||||||
while (is >> token && token != "moves")
|
while (is >> token && token != "moves")
|
||||||
@@ -67,10 +67,10 @@ namespace {
|
|||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
|
|
||||||
states = StateListPtr(new std::deque<StateInfo>(1)); // Drop old and create a new one
|
states = StateListPtr(new std::deque<StateInfo>(1)); // Drop the old state and create a new one
|
||||||
pos.set(fen, Options["UCI_Chess960"], &states->back(), Threads.main());
|
pos.set(fen, Options["UCI_Chess960"], &states->back(), Threads.main());
|
||||||
|
|
||||||
// Parse move list (if any)
|
// Parse the move list, if any
|
||||||
while (is >> token && (m = UCI::to_move(pos, token)) != MOVE_NONE)
|
while (is >> token && (m = UCI::to_move(pos, token)) != MOVE_NONE)
|
||||||
{
|
{
|
||||||
states->emplace_back();
|
states->emplace_back();
|
||||||
@@ -78,8 +78,8 @@ namespace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// trace_eval() prints the evaluation for the current position, consistent with the UCI
|
// trace_eval() prints the evaluation of the current position, consistent with
|
||||||
// options set so far.
|
// the UCI options set so far.
|
||||||
|
|
||||||
void trace_eval(Position& pos) {
|
void trace_eval(Position& pos) {
|
||||||
|
|
||||||
@@ -93,20 +93,20 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// setoption() is called when engine receives the "setoption" UCI command. The
|
// setoption() is called when the engine receives the "setoption" UCI command.
|
||||||
// function updates the UCI option ("name") to the given value ("value").
|
// The function updates the UCI option ("name") to the given value ("value").
|
||||||
|
|
||||||
void setoption(istringstream& is) {
|
void setoption(istringstream& is) {
|
||||||
|
|
||||||
string token, name, value;
|
string token, name, value;
|
||||||
|
|
||||||
is >> token; // Consume "name" token
|
is >> token; // Consume the "name" token
|
||||||
|
|
||||||
// Read option name (can contain spaces)
|
// Read the option name (can contain spaces)
|
||||||
while (is >> token && token != "value")
|
while (is >> token && token != "value")
|
||||||
name += (name.empty() ? "" : " ") + token;
|
name += (name.empty() ? "" : " ") + token;
|
||||||
|
|
||||||
// Read option value (can contain spaces)
|
// Read the option value (can contain spaces)
|
||||||
while (is >> token)
|
while (is >> token)
|
||||||
value += (value.empty() ? "" : " ") + token;
|
value += (value.empty() ? "" : " ") + token;
|
||||||
|
|
||||||
@@ -117,9 +117,9 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// go() is called when engine receives the "go" UCI command. The function sets
|
// go() is called when the engine receives the "go" UCI command. The function
|
||||||
// the thinking time and other parameters from the input string, then starts
|
// sets the thinking time and other parameters from the input string, then starts
|
||||||
// the search.
|
// with a search.
|
||||||
|
|
||||||
void go(Position& pos, istringstream& is, StateListPtr& states) {
|
void go(Position& pos, istringstream& is, StateListPtr& states) {
|
||||||
|
|
||||||
@@ -127,7 +127,7 @@ namespace {
|
|||||||
string token;
|
string token;
|
||||||
bool ponderMode = false;
|
bool ponderMode = false;
|
||||||
|
|
||||||
limits.startTime = now(); // As early as possible!
|
limits.startTime = now(); // The search starts as early as possible
|
||||||
|
|
||||||
while (is >> token)
|
while (is >> token)
|
||||||
if (token == "searchmoves") // Needs to be the last command on the line
|
if (token == "searchmoves") // Needs to be the last command on the line
|
||||||
@@ -151,9 +151,9 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// bench() is called when engine receives the "bench" command. Firstly
|
// bench() is called when the engine receives the "bench" command.
|
||||||
// a list of UCI commands is setup according to bench parameters, then
|
// Firstly, a list of UCI commands is set up according to the bench
|
||||||
// it is run one by one printing a summary at the end.
|
// parameters, then it is run one by one, printing a summary at the end.
|
||||||
|
|
||||||
void bench(Position& pos, istream& args, StateListPtr& states) {
|
void bench(Position& pos, istream& args, StateListPtr& states) {
|
||||||
|
|
||||||
@@ -161,7 +161,7 @@ namespace {
|
|||||||
uint64_t num, nodes = 0, cnt = 1;
|
uint64_t num, nodes = 0, cnt = 1;
|
||||||
|
|
||||||
vector<string> list = setup_bench(pos, args);
|
vector<string> list = setup_bench(pos, args);
|
||||||
num = count_if(list.begin(), list.end(), [](string s) { return s.find("go ") == 0 || s.find("eval") == 0; });
|
num = count_if(list.begin(), list.end(), [](const string& s) { return s.find("go ") == 0 || s.find("eval") == 0; });
|
||||||
|
|
||||||
TimePoint elapsed = now();
|
TimePoint elapsed = now();
|
||||||
|
|
||||||
@@ -184,12 +184,12 @@ namespace {
|
|||||||
}
|
}
|
||||||
else if (token == "setoption") setoption(is);
|
else if (token == "setoption") setoption(is);
|
||||||
else if (token == "position") position(pos, is, states);
|
else if (token == "position") position(pos, is, states);
|
||||||
else if (token == "ucinewgame") { Search::clear(); elapsed = now(); } // Search::clear() may take some while
|
else if (token == "ucinewgame") { Search::clear(); elapsed = now(); } // Search::clear() may take a while
|
||||||
}
|
}
|
||||||
|
|
||||||
elapsed = now() - elapsed + 1; // Ensure positivity to avoid a 'divide by zero'
|
elapsed = now() - elapsed + 1; // Ensure positivity to avoid a 'divide by zero'
|
||||||
|
|
||||||
dbg_print(); // Just before exiting
|
dbg_print();
|
||||||
|
|
||||||
cerr << "\n==========================="
|
cerr << "\n==========================="
|
||||||
<< "\nTotal time (ms) : " << elapsed
|
<< "\nTotal time (ms) : " << elapsed
|
||||||
@@ -197,36 +197,40 @@ namespace {
|
|||||||
<< "\nNodes/second : " << 1000 * nodes / elapsed << endl;
|
<< "\nNodes/second : " << 1000 * nodes / elapsed << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The win rate model returns the probability (per mille) of winning given an eval
|
// The win rate model returns the probability of winning (in per mille units) given an
|
||||||
// and a game-ply. The model fits rather accurately the LTC fishtest statistics.
|
// eval and a game ply. It fits the LTC fishtest statistics rather accurately.
|
||||||
int win_rate_model(Value v, int ply) {
|
int win_rate_model(Value v, int ply) {
|
||||||
|
|
||||||
// The model captures only up to 240 plies, so limit input (and rescale)
|
// The model only captures up to 240 plies, so limit the input and then rescale
|
||||||
double m = std::min(240, ply) / 64.0;
|
double m = std::min(240, ply) / 64.0;
|
||||||
|
|
||||||
// Coefficients of a 3rd order polynomial fit based on fishtest data
|
// The coefficients of a third-order polynomial fit is based on the fishtest data
|
||||||
// for two parameters needed to transform eval to the argument of a
|
// for two parameters that need to transform eval to the argument of a logistic
|
||||||
// logistic function.
|
// function.
|
||||||
double as[] = {-3.68389304, 30.07065921, -60.52878723, 149.53378557};
|
constexpr double as[] = { 0.38036525, -2.82015070, 23.17882135, 307.36768407};
|
||||||
double bs[] = {-2.0181857, 15.85685038, -29.83452023, 47.59078827};
|
constexpr double bs[] = { -2.29434733, 13.27689788, -14.26828904, 63.45318330 };
|
||||||
|
|
||||||
|
// Enforce that NormalizeToPawnValue corresponds to a 50% win rate at ply 64
|
||||||
|
static_assert(UCI::NormalizeToPawnValue == int(as[0] + as[1] + as[2] + as[3]));
|
||||||
|
|
||||||
double a = (((as[0] * m + as[1]) * m + as[2]) * m) + as[3];
|
double a = (((as[0] * m + as[1]) * m + as[2]) * m) + as[3];
|
||||||
double b = (((bs[0] * m + bs[1]) * m + bs[2]) * m) + bs[3];
|
double b = (((bs[0] * m + bs[1]) * m + bs[2]) * m) + bs[3];
|
||||||
|
|
||||||
// Transform eval to centipawns with limited range
|
// Transform the eval to centipawns with limited range
|
||||||
double x = std::clamp(double(100 * v) / PawnValueEg, -2000.0, 2000.0);
|
double x = std::clamp(double(v), -4000.0, 4000.0);
|
||||||
|
|
||||||
// Return win rate in per mille (rounded to nearest)
|
// Return the win rate in per mille units rounded to the nearest value
|
||||||
return int(0.5 + 1000 / (1 + std::exp((a - x) / b)));
|
return int(0.5 + 1000 / (1 + std::exp((a - x) / b)));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
/// UCI::loop() waits for a command from stdin, parses it and calls the appropriate
|
/// UCI::loop() waits for a command from the stdin, parses it and then calls the appropriate
|
||||||
/// function. Also intercepts EOF from stdin to ensure gracefully exiting if the
|
/// function. It also intercepts an end-of-file (EOF) indication from the stdin to ensure a
|
||||||
/// GUI dies unexpectedly. When called with some command line arguments, e.g. to
|
/// graceful exit if the GUI dies unexpectedly. When called with some command-line arguments,
|
||||||
/// run 'bench', once the command is executed the function returns immediately.
|
/// like running 'bench', the function returns immediately after the command is executed.
|
||||||
/// In addition to the UCI ones, also some additional debug commands are supported.
|
/// In addition to the UCI ones, some additional debug commands are also supported.
|
||||||
|
|
||||||
void UCI::loop(int argc, char* argv[]) {
|
void UCI::loop(int argc, char* argv[]) {
|
||||||
|
|
||||||
@@ -240,24 +244,24 @@ void UCI::loop(int argc, char* argv[]) {
|
|||||||
cmd += std::string(argv[i]) + " ";
|
cmd += std::string(argv[i]) + " ";
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (argc == 1 && !getline(cin, cmd)) // Block here waiting for input or EOF
|
if (argc == 1 && !getline(cin, cmd)) // Wait for an input or an end-of-file (EOF) indication
|
||||||
cmd = "quit";
|
cmd = "quit";
|
||||||
|
|
||||||
istringstream is(cmd);
|
istringstream is(cmd);
|
||||||
|
|
||||||
token.clear(); // Avoid a stale if getline() returns empty or blank line
|
token.clear(); // Avoid a stale if getline() returns nothing or a blank line
|
||||||
is >> skipws >> token;
|
is >> skipws >> token;
|
||||||
|
|
||||||
if ( token == "quit"
|
if ( token == "quit"
|
||||||
|| token == "stop")
|
|| token == "stop")
|
||||||
Threads.stop = true;
|
Threads.stop = true;
|
||||||
|
|
||||||
// The GUI sends 'ponderhit' to tell us the user has played the expected move.
|
// The GUI sends 'ponderhit' to tell that the user has played the expected move.
|
||||||
// So 'ponderhit' will be sent if we were told to ponder on the same move the
|
// So, 'ponderhit' is sent if pondering was done on the same move that the user
|
||||||
// user has played. We should continue searching but switch from pondering to
|
// has played. The search should continue, but should also switch from pondering
|
||||||
// normal search.
|
// to the normal search.
|
||||||
else if (token == "ponderhit")
|
else if (token == "ponderhit")
|
||||||
Threads.main()->ponder = false; // Switch to normal search
|
Threads.main()->ponder = false; // Switch to the normal search
|
||||||
|
|
||||||
else if (token == "uci")
|
else if (token == "uci")
|
||||||
sync_cout << "id name " << engine_info(true)
|
sync_cout << "id name " << engine_info(true)
|
||||||
@@ -270,8 +274,8 @@ void UCI::loop(int argc, char* argv[]) {
|
|||||||
else if (token == "ucinewgame") Search::clear();
|
else if (token == "ucinewgame") Search::clear();
|
||||||
else if (token == "isready") sync_cout << "readyok" << sync_endl;
|
else if (token == "isready") sync_cout << "readyok" << sync_endl;
|
||||||
|
|
||||||
// Additional custom non-UCI commands, mainly for debugging.
|
// Add custom non-UCI commands, mainly for debugging purposes.
|
||||||
// Do not use these commands during a search!
|
// These commands must not be used during a search!
|
||||||
else if (token == "flip") pos.flip();
|
else if (token == "flip") pos.flip();
|
||||||
else if (token == "bench") bench(pos, is, states);
|
else if (token == "bench") bench(pos, is, states);
|
||||||
else if (token == "d") sync_cout << pos << sync_endl;
|
else if (token == "d") sync_cout << pos << sync_endl;
|
||||||
@@ -285,19 +289,25 @@ void UCI::loop(int argc, char* argv[]) {
|
|||||||
filename = f;
|
filename = f;
|
||||||
Eval::NNUE::save_eval(filename);
|
Eval::NNUE::save_eval(filename);
|
||||||
}
|
}
|
||||||
|
else if (token == "--help" || token == "help" || token == "--license" || token == "license")
|
||||||
|
sync_cout << "\nStockfish is a powerful chess engine for playing and analyzing."
|
||||||
|
"\nIt is released as free software licensed under the GNU GPLv3 License."
|
||||||
|
"\nStockfish is normally used with a graphical user interface (GUI) and implements"
|
||||||
|
"\nthe Universal Chess Interface (UCI) protocol to communicate with a GUI, an API, etc."
|
||||||
|
"\nFor any further information, visit https://github.com/official-stockfish/Stockfish#readme"
|
||||||
|
"\nor read the corresponding README.md and Copying.txt files distributed along with this program.\n" << sync_endl;
|
||||||
else if (!token.empty() && token[0] != '#')
|
else if (!token.empty() && token[0] != '#')
|
||||||
sync_cout << "Unknown command: " << cmd << sync_endl;
|
sync_cout << "Unknown command: '" << cmd << "'. Type help for more information." << sync_endl;
|
||||||
|
|
||||||
} while (token != "quit" && argc == 1); // Command line args are one-shot
|
} while (token != "quit" && argc == 1); // The command-line arguments are one-shot
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// UCI::value() converts a Value to a string suitable for use with the UCI
|
/// UCI::value() converts a Value to a string by adhering to the UCI protocol specification:
|
||||||
/// protocol specification:
|
|
||||||
///
|
///
|
||||||
/// cp <x> The score from the engine's point of view in centipawns.
|
/// cp <x> The score from the engine's point of view in centipawns.
|
||||||
/// mate <y> Mate in y moves, not plies. If the engine is getting mated
|
/// mate <y> Mate in 'y' moves (not plies). If the engine is getting mated,
|
||||||
/// use negative values for y.
|
/// uses negative values for 'y'.
|
||||||
|
|
||||||
string UCI::value(Value v) {
|
string UCI::value(Value v) {
|
||||||
|
|
||||||
@@ -305,8 +315,13 @@ string UCI::value(Value v) {
|
|||||||
|
|
||||||
stringstream ss;
|
stringstream ss;
|
||||||
|
|
||||||
if (abs(v) < VALUE_MATE_IN_MAX_PLY)
|
if (abs(v) < VALUE_TB_WIN_IN_MAX_PLY)
|
||||||
ss << "cp " << v * 100 / PawnValueEg;
|
ss << "cp " << v * 100 / NormalizeToPawnValue;
|
||||||
|
else if (abs(v) < VALUE_MATE_IN_MAX_PLY)
|
||||||
|
{
|
||||||
|
const int ply = VALUE_MATE_IN_MAX_PLY - 1 - std::abs(v); // recompute ss->ply
|
||||||
|
ss << "cp " << (v > 0 ? 20000 - ply : -20000 + ply);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
ss << "mate " << (v > 0 ? VALUE_MATE - v + 1 : -VALUE_MATE - v) / 2;
|
ss << "mate " << (v > 0 ? VALUE_MATE - v + 1 : -VALUE_MATE - v) / 2;
|
||||||
|
|
||||||
@@ -314,8 +329,8 @@ string UCI::value(Value v) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// UCI::wdl() report WDL statistics given an evaluation and a game ply, based on
|
/// UCI::wdl() reports the win-draw-loss (WDL) statistics given an evaluation
|
||||||
/// data gathered for fishtest LTC games.
|
/// and a game ply based on the data gathered for fishtest LTC games.
|
||||||
|
|
||||||
string UCI::wdl(Value v, int ply) {
|
string UCI::wdl(Value v, int ply) {
|
||||||
|
|
||||||
@@ -338,21 +353,21 @@ std::string UCI::square(Square s) {
|
|||||||
|
|
||||||
|
|
||||||
/// UCI::move() converts a Move to a string in coordinate notation (g1f3, a7a8q).
|
/// UCI::move() converts a Move to a string in coordinate notation (g1f3, a7a8q).
|
||||||
/// The only special case is castling, where we print in the e1g1 notation in
|
/// The only special case is castling where the e1g1 notation is printed in
|
||||||
/// normal chess mode, and in e1h1 notation in chess960 mode. Internally all
|
/// standard chess mode and in e1h1 notation it is printed in Chess960 mode.
|
||||||
/// castling moves are always encoded as 'king captures rook'.
|
/// Internally, all castling moves are always encoded as 'king captures rook'.
|
||||||
|
|
||||||
string UCI::move(Move m, bool chess960) {
|
string UCI::move(Move m, bool chess960) {
|
||||||
|
|
||||||
Square from = from_sq(m);
|
|
||||||
Square to = to_sq(m);
|
|
||||||
|
|
||||||
if (m == MOVE_NONE)
|
if (m == MOVE_NONE)
|
||||||
return "(none)";
|
return "(none)";
|
||||||
|
|
||||||
if (m == MOVE_NULL)
|
if (m == MOVE_NULL)
|
||||||
return "0000";
|
return "0000";
|
||||||
|
|
||||||
|
Square from = from_sq(m);
|
||||||
|
Square to = to_sq(m);
|
||||||
|
|
||||||
if (type_of(m) == CASTLING && !chess960)
|
if (type_of(m) == CASTLING && !chess960)
|
||||||
to = make_square(to > from ? FILE_G : FILE_C, rank_of(from));
|
to = make_square(to > from ? FILE_G : FILE_C, rank_of(from));
|
||||||
|
|
||||||
@@ -370,8 +385,8 @@ string UCI::move(Move m, bool chess960) {
|
|||||||
|
|
||||||
Move UCI::to_move(const Position& pos, string& str) {
|
Move UCI::to_move(const Position& pos, string& str) {
|
||||||
|
|
||||||
if (str.length() == 5) // Junior could send promotion piece in uppercase
|
if (str.length() == 5)
|
||||||
str[4] = char(tolower(str[4]));
|
str[4] = char(tolower(str[4])); // The promotion piece character must be lowercased
|
||||||
|
|
||||||
for (const auto& m : MoveList<LEGAL>(pos))
|
for (const auto& m : MoveList<LEGAL>(pos))
|
||||||
if (str == UCI::move(m, pos.is_chess960()))
|
if (str == UCI::move(m, pos.is_chess960()))
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -30,20 +30,27 @@ class Position;
|
|||||||
|
|
||||||
namespace UCI {
|
namespace UCI {
|
||||||
|
|
||||||
|
// Normalizes the internal value as reported by evaluate or search
|
||||||
|
// to the UCI centipawn result used in output. This value is derived from
|
||||||
|
// the win_rate_model() such that Stockfish outputs an advantage of
|
||||||
|
// "100 centipawns" for a position if the engine has a 50% probability to win
|
||||||
|
// from this position in selfplay at fishtest LTC time control.
|
||||||
|
const int NormalizeToPawnValue = 328;
|
||||||
|
|
||||||
class Option;
|
class Option;
|
||||||
|
|
||||||
/// Custom comparator because UCI options should be case insensitive
|
/// Define a custom comparator, because the UCI options should be case-insensitive
|
||||||
struct CaseInsensitiveLess {
|
struct CaseInsensitiveLess {
|
||||||
bool operator() (const std::string&, const std::string&) const;
|
bool operator() (const std::string&, const std::string&) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Our options container is actually a std::map
|
/// The options container is defined as a std::map
|
||||||
typedef std::map<std::string, Option, CaseInsensitiveLess> OptionsMap;
|
using OptionsMap = std::map<std::string, Option, CaseInsensitiveLess>;
|
||||||
|
|
||||||
/// Option class implements an option as defined by UCI protocol
|
/// The Option class implements each option as specified by the UCI protocol
|
||||||
class Option {
|
class Option {
|
||||||
|
|
||||||
typedef void (*OnChange)(const Option&);
|
using OnChange = void (*)(const Option&);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Option(OnChange = nullptr);
|
Option(OnChange = nullptr);
|
||||||
@@ -54,7 +61,7 @@ public:
|
|||||||
|
|
||||||
Option& operator=(const std::string&);
|
Option& operator=(const std::string&);
|
||||||
void operator<<(const Option&);
|
void operator<<(const Option&);
|
||||||
operator double() const;
|
operator int() const;
|
||||||
operator std::string() const;
|
operator std::string() const;
|
||||||
bool operator==(const char*) const;
|
bool operator==(const char*) const;
|
||||||
|
|
||||||
@@ -72,7 +79,7 @@ void loop(int argc, char* argv[]);
|
|||||||
std::string value(Value v);
|
std::string value(Value v);
|
||||||
std::string square(Square s);
|
std::string square(Square s);
|
||||||
std::string move(Move m, bool chess960);
|
std::string move(Move m, bool chess960);
|
||||||
std::string pv(const Position& pos, Depth depth, Value alpha, Value beta);
|
std::string pv(const Position& pos, Depth depth);
|
||||||
std::string wdl(Value v, int ply);
|
std::string wdl(Value v, int ply);
|
||||||
Move to_move(const Position& pos, std::string& str);
|
Move to_move(const Position& pos, std::string& str);
|
||||||
|
|
||||||
|
|||||||
+12
-12
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
|
||||||
|
|
||||||
Stockfish is free software: you can redistribute it and/or modify
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -38,13 +38,13 @@ UCI::OptionsMap Options; // Global object
|
|||||||
namespace UCI {
|
namespace UCI {
|
||||||
|
|
||||||
/// 'On change' actions, triggered by an option's value change
|
/// 'On change' actions, triggered by an option's value change
|
||||||
void on_clear_hash(const Option&) { Search::clear(); }
|
static void on_clear_hash(const Option&) { Search::clear(); }
|
||||||
void on_hash_size(const Option& o) { TT.resize(size_t(o)); }
|
static void on_hash_size(const Option& o) { TT.resize(size_t(o)); }
|
||||||
void on_logger(const Option& o) { start_logger(o); }
|
static void on_logger(const Option& o) { start_logger(o); }
|
||||||
void on_threads(const Option& o) { Threads.set(size_t(o)); }
|
static void on_threads(const Option& o) { Threads.set(size_t(o)); }
|
||||||
void on_tb_path(const Option& o) { Tablebases::init(o); }
|
static void on_tb_path(const Option& o) { Tablebases::init(o); }
|
||||||
void on_use_NNUE(const Option& ) { Eval::NNUE::init(); }
|
static void on_use_NNUE(const Option&) { Eval::NNUE::init(); }
|
||||||
void on_eval_file(const Option& ) { Eval::NNUE::init(); }
|
static void on_eval_file(const Option&) { Eval::NNUE::init(); }
|
||||||
|
|
||||||
/// Our case insensitive less() function as required by UCI protocol
|
/// Our case insensitive less() function as required by UCI protocol
|
||||||
bool CaseInsensitiveLess::operator() (const string& s1, const string& s2) const {
|
bool CaseInsensitiveLess::operator() (const string& s1, const string& s2) const {
|
||||||
@@ -61,7 +61,7 @@ void init(OptionsMap& o) {
|
|||||||
constexpr int MaxHashMB = Is64Bit ? 33554432 : 2048;
|
constexpr int MaxHashMB = Is64Bit ? 33554432 : 2048;
|
||||||
|
|
||||||
o["Debug Log File"] << Option("", on_logger);
|
o["Debug Log File"] << Option("", on_logger);
|
||||||
o["Threads"] << Option(1, 1, 512, on_threads);
|
o["Threads"] << Option(1, 1, 1024, on_threads);
|
||||||
o["Hash"] << Option(16, 1, MaxHashMB, on_hash_size);
|
o["Hash"] << Option(16, 1, MaxHashMB, on_hash_size);
|
||||||
o["Clear Hash"] << Option(on_clear_hash);
|
o["Clear Hash"] << Option(on_clear_hash);
|
||||||
o["Ponder"] << Option(false);
|
o["Ponder"] << Option(false);
|
||||||
@@ -73,7 +73,7 @@ void init(OptionsMap& o) {
|
|||||||
o["UCI_Chess960"] << Option(false);
|
o["UCI_Chess960"] << Option(false);
|
||||||
o["UCI_AnalyseMode"] << Option(false);
|
o["UCI_AnalyseMode"] << Option(false);
|
||||||
o["UCI_LimitStrength"] << Option(false);
|
o["UCI_LimitStrength"] << Option(false);
|
||||||
o["UCI_Elo"] << Option(1350, 1350, 2850);
|
o["UCI_Elo"] << Option(1320, 1320, 3190);
|
||||||
o["UCI_ShowWDL"] << Option(false);
|
o["UCI_ShowWDL"] << Option(false);
|
||||||
o["SyzygyPath"] << Option("<empty>", on_tb_path);
|
o["SyzygyPath"] << Option("<empty>", on_tb_path);
|
||||||
o["SyzygyProbeDepth"] << Option(1, 1, 100);
|
o["SyzygyProbeDepth"] << Option(1, 1, 100);
|
||||||
@@ -128,9 +128,9 @@ Option::Option(double v, int minv, int maxv, OnChange f) : type("spin"), min(min
|
|||||||
Option::Option(const char* v, const char* cur, OnChange f) : type("combo"), min(0), max(0), on_change(f)
|
Option::Option(const char* v, const char* cur, OnChange f) : type("combo"), min(0), max(0), on_change(f)
|
||||||
{ defaultValue = v; currentValue = cur; }
|
{ defaultValue = v; currentValue = cur; }
|
||||||
|
|
||||||
Option::operator double() const {
|
Option::operator int() const {
|
||||||
assert(type == "check" || type == "spin");
|
assert(type == "check" || type == "spin");
|
||||||
return (type == "spin" ? stof(currentValue) : currentValue == "true");
|
return (type == "spin" ? std::stoi(currentValue) : currentValue == "true");
|
||||||
}
|
}
|
||||||
|
|
||||||
Option::operator std::string() const {
|
Option::operator std::string() const {
|
||||||
|
|||||||
@@ -70,7 +70,8 @@ for args in "eval" \
|
|||||||
"go depth 10" \
|
"go depth 10" \
|
||||||
"go movetime 1000" \
|
"go movetime 1000" \
|
||||||
"go wtime 8000 btime 8000 winc 500 binc 500" \
|
"go wtime 8000 btime 8000 winc 500 binc 500" \
|
||||||
"bench 128 $threads 8 default depth"
|
"bench 128 $threads 8 default depth" \
|
||||||
|
"export_net verify.nnue"
|
||||||
do
|
do
|
||||||
|
|
||||||
echo "$prefix $exeprefix ./stockfish $args $postfix"
|
echo "$prefix $exeprefix ./stockfish $args $postfix"
|
||||||
@@ -78,6 +79,11 @@ do
|
|||||||
|
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# verify the generated net equals the base net
|
||||||
|
network=`./stockfish uci | grep 'option name EvalFile type string default' | awk '{print $NF}'`
|
||||||
|
echo "Comparing $network to the written verify.nnue"
|
||||||
|
diff $network verify.nnue
|
||||||
|
|
||||||
# more general testing, following an uci protocol exchange
|
# more general testing, following an uci protocol exchange
|
||||||
cat << EOF > game.exp
|
cat << EOF > game.exp
|
||||||
set timeout 240
|
set timeout 240
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ cat << EOF > repeat.exp
|
|||||||
expect eof
|
expect eof
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# to increase the likelyhood of finding a non-reproducible case,
|
# to increase the likelihood of finding a non-reproducible case,
|
||||||
# the allowed number of nodes are varied systematically
|
# the allowed number of nodes are varied systematically
|
||||||
for i in `seq 1 20`
|
for i in `seq 1 20`
|
||||||
do
|
do
|
||||||
|
|||||||
Reference in New Issue
Block a user