Merge pull request #4661 from vondele/clusterMergeMaster17

Merge SF 16 in the cluster branch
This commit is contained in:
Joost VandeVondele
2023-07-05 12:11:22 +02:00
committed by GitHub
67 changed files with 2423 additions and 1732 deletions
+31 -1
View File
@@ -1,6 +1,8 @@
name: Stockfish name: Stockfish
on: on:
push: push:
tags:
- '*'
branches: branches:
- master - master
- tools - tools
@@ -10,6 +12,31 @@ on:
- master - master
- tools - tools
jobs: jobs:
Prerelease:
if: github.ref == 'refs/heads/master'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
# returns null if no pre-release exists
- name: Get Commit SHA of Latest Pre-release
run: |
# Install required packages
sudo apt-get update
sudo apt-get install -y curl jq
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
# delete old previous pre-release and tag
- uses: dev-drprasad/delete-tag-and-release@v0.2.1
if: env.COMMIT_SHA != 'null'
with:
tag_name: ${{ env.COMMIT_SHA }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Sanitizers: Sanitizers:
uses: ./.github/workflows/stockfish_sanitizers.yml uses: ./.github/workflows/stockfish_sanitizers.yml
Tests: Tests:
@@ -17,5 +44,8 @@ jobs:
Compiles: Compiles:
uses: ./.github/workflows/stockfish_compile_test.yml uses: ./.github/workflows/stockfish_compile_test.yml
Binaries: Binaries:
if: github.ref == 'refs/heads/master' if: github.ref == 'refs/heads/master' || (startsWith(github.ref_name, 'sf_') && github.ref_type == 'tag')
uses: ./.github/workflows/stockfish_binaries.yml uses: ./.github/workflows/stockfish_binaries.yml
ARM_Binaries:
if: github.ref == 'refs/heads/master' || (startsWith(github.ref_name, 'sf_') && github.ref_type == 'tag')
uses: ./.github/workflows/stockfish_arm_binaries.yml
@@ -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
+103 -45
View File
@@ -9,35 +9,35 @@ jobs:
COMPILER: ${{ matrix.config.compiler }} COMPILER: ${{ matrix.config.compiler }}
COMP: ${{ matrix.config.comp }} COMP: ${{ matrix.config.comp }}
EXT: ${{ matrix.config.ext }} EXT: ${{ matrix.config.ext }}
OS: ${{ matrix.config.os }} NAME: ${{ matrix.config.simple_name }}
BINARY: ${{ matrix.binaries }} BINARY: ${{ matrix.binaries }}
strategy: strategy:
matrix: matrix:
config: config:
- { - name: Ubuntu 20.04 GCC
name: "Ubuntu 20.04 GCC", os: ubuntu-20.04
os: ubuntu-20.04, simple_name: ubuntu
compiler: g++, compiler: g++
comp: gcc, comp: gcc
shell: 'bash {0}' shell: bash {0}
} archive_ext: tar
- { - name: MacOS 12 Apple Clang
name: "MacOS 12 Apple Clang", os: macos-12
os: macos-12, simple_name: macos
compiler: clang++, compiler: clang++
comp: clang, comp: clang
shell: 'bash {0}' shell: bash {0}
} archive_ext: tar
- { - name: Windows 2022 Mingw-w64 GCC x86_64
name: "Windows 2022 Mingw-w64 GCC x86_64", os: windows-2022
os: windows-2022, simple_name: windows
compiler: g++, compiler: g++
comp: mingw, comp: mingw
msys_sys: 'mingw64', msys_sys: mingw64
msys_env: 'x86_64-gcc', msys_env: x86_64-gcc
shell: 'msys2 {0}', shell: msys2 {0}
ext: .exe ext: .exe
} archive_ext: zip
binaries: binaries:
- x86-64 - x86-64
- x86-64-modern - x86-64-modern
@@ -56,55 +56,113 @@ jobs:
- name: Download required linux packages - name: Download required linux packages
if: runner.os == 'Linux' if: runner.os == 'Linux'
run: | run: sudo apt update
sudo apt update
- name: Setup msys and install required packages - name: Setup msys and install required packages
if: runner.os == 'Windows' if: runner.os == 'Windows'
uses: msys2/setup-msys2@v2 uses: msys2/setup-msys2@v2
with: with:
msystem: ${{matrix.config.msys_sys}} msystem: ${{ matrix.config.msys_sys }}
install: mingw-w64-${{matrix.config.msys_env}} make git expect install: mingw-w64-${{ matrix.config.msys_env }} make git zip
- name: Download the used network from the fishtest framework - name: Download the used network from the fishtest framework
run: | run: make net
make net
- name: Check compiler - name: Check compiler
run: | run: $COMPILER -v
export PATH=$PATH:$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin
$COMPILER -v
- name: Test help target - name: Test help target
run: | run: make help
make help
- name: Check git
run: git --version
# Compile profile guided builds # Compile profile guided builds
- name: Compile ${{ matrix.binaries }} build - name: Compile ${{ matrix.binaries }} build
run: | run: |
make clean
make -j2 profile-build ARCH=$BINARY COMP=$COMP make -j2 profile-build ARCH=$BINARY COMP=$COMP
strip ./stockfish$EXT make strip ARCH=$BINARY COMP=$COMP
mv ./stockfish$EXT ../stockfish-$OS-$BINARY$EXT mv ./stockfish$EXT ../stockfish-$NAME-$BINARY$EXT
- name: Remove non src files - name: Remove non src files
run: rm -f *.o .depend *.nnue run: git clean -fx
- name: Create tar archive. - name: Download wiki
run: |
git clone https://github.com/official-stockfish/Stockfish.wiki.git ../wiki
rm -rf ../wiki/.git
- name: Create directory.
run: | run: |
cd .. cd ..
mkdir stockfish mkdir stockfish
cp -r wiki stockfish/
cp -r src stockfish/ cp -r src stockfish/
cp stockfish-$OS-$BINARY$EXT stockfish/ cp stockfish-$NAME-$BINARY$EXT stockfish/
cp "Top CPU Contributors.txt" stockfish/ cp "Top CPU Contributors.txt" stockfish/
cp Copying.txt stockfish/ cp Copying.txt stockfish/
cp AUTHORS stockfish/ cp AUTHORS stockfish/
tar -cvf stockfish-$OS-$BINARY.tar 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 - name: Upload binaries
if: runner.os != 'Windows'
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name: stockfish-${{ matrix.config.os }}-${{ matrix.binaries }} name: stockfish-${{ matrix.config.os }}-${{ matrix.binaries }}
path: | path: stockfish-${{ matrix.config.simple_name }}-${{ matrix.binaries }}.tar
stockfish-${{ matrix.config.os }}-${{ 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 }}
+42 -55
View File
@@ -11,52 +11,40 @@ jobs:
strategy: strategy:
matrix: matrix:
config: config:
- { - name: Ubuntu 20.04 GCC
name: "Ubuntu 20.04 GCC", os: ubuntu-20.04
os: ubuntu-20.04, compiler: g++
compiler: g++, comp: gcc
comp: gcc, shell: bash {0}
shell: 'bash {0}' - name: Ubuntu 20.04 Clang
} os: ubuntu-20.04
- { compiler: clang++
name: "Ubuntu 20.04 Clang", comp: clang
os: ubuntu-20.04, shell: bash {0}
compiler: clang++, - name: MacOS 12 Apple Clang
comp: clang, os: macos-12
shell: 'bash {0}' compiler: clang++
} comp: clang
- { shell: bash {0}
name: "MacOS 12 Apple Clang", - name: MacOS 12 GCC 11
os: macos-12, os: macos-12
compiler: clang++, compiler: g++-11
comp: clang, comp: gcc
shell: 'bash {0}' shell: bash {0}
} - name: Windows 2022 Mingw-w64 GCC x86_64
- { os: windows-2022
name: "MacOS 12 GCC 11", compiler: g++
os: macos-12, comp: mingw
compiler: g++-11, msys_sys: mingw64
comp: gcc, msys_env: x86_64-gcc
shell: 'bash {0}' shell: msys2 {0}
} - name: Windows 2022 Mingw-w64 Clang x86_64
- { os: windows-2022
name: "Windows 2022 Mingw-w64 GCC x86_64", compiler: clang++
os: windows-2022, comp: clang
compiler: g++, msys_sys: clang64
comp: mingw, msys_env: clang-x86_64-clang
msys_sys: 'mingw64', shell: msys2 {0}
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: defaults:
run: run:
@@ -72,20 +60,19 @@ jobs:
uses: msys2/setup-msys2@v2 uses: msys2/setup-msys2@v2
with: with:
msystem: ${{matrix.config.msys_sys}} msystem: ${{matrix.config.msys_sys}}
install: mingw-w64-${{matrix.config.msys_env}} make git expect install: mingw-w64-${{matrix.config.msys_env}} make git
- name: Download the used network from the fishtest framework - name: Download the used network from the fishtest framework
run: | run: make net
make net
- name: Check compiler - name: Check compiler
run: | run: $COMPILER -v
export PATH=$PATH:$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin
$COMPILER -v
- name: Test help target - name: Test help target
run: | run: make help
make help
- name: Check git
run: git --version
# x86-64 with newer extensions tests # x86-64 with newer extensions tests
@@ -112,4 +99,4 @@ jobs:
- name: Compile x86-64-vnni256 build - name: Compile x86-64-vnni256 build
run: | run: |
make clean make clean
make -j2 ARCH=x86-64-vnni256 build make -j2 ARCH=x86-64-vnni256 build
+25 -36
View File
@@ -12,34 +12,24 @@ jobs:
strategy: strategy:
matrix: matrix:
config: config:
- { - name: Ubuntu 20.04 GCC
name: "Ubuntu 20.04 GCC", os: ubuntu-20.04
os: ubuntu-20.04, compiler: g++
compiler: g++, comp: gcc
comp: gcc, shell: bash {0}
shell: 'bash {0}'
}
sanitizers: sanitizers:
- { - name: Run with thread sanitizer
name: Run with thread sanitizer, make_option: sanitize=thread
make_option: sanitize=thread, instrumented_option: sanitizer-thread
instrumented_option: sanitizer-thread - name: Run with UB sanitizer
} make_option: sanitize=undefined
- { instrumented_option: sanitizer-undefined
name: Run with UB sanitizer, - name: Run under valgrind
make_option: sanitize=undefined, make_option: ""
instrumented_option: sanitizer-undefined instrumented_option: valgrind
} - name: Run under valgrind-thread
- { make_option: ""
name: Run under valgrind, instrumented_option: valgrind-thread
make_option: "",
instrumented_option: valgrind
}
- {
name: Run under valgrind-thread,
make_option: "",
instrumented_option: valgrind-thread
}
defaults: defaults:
run: run:
working-directory: src working-directory: src
@@ -52,20 +42,19 @@ jobs:
- name: Download required linux packages - name: Download required linux packages
run: | run: |
sudo apt update sudo apt update
sudo apt install expect valgrind g++-multilib qemu-user sudo apt install expect valgrind g++-multilib
- name: Download the used network from the fishtest framework - name: Download the used network from the fishtest framework
run: | run: make net
make net
- name: Check compiler - name: Check compiler
run: | run: $COMPILER -v
export PATH=$PATH:$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin
$COMPILER -v
- name: Test help target - name: Test help target
run: | run: make help
make help
- name: Check git
run: git --version
# Sanitizers # Sanitizers
@@ -74,4 +63,4 @@ jobs:
export CXXFLAGS="-O1 -fno-inline" export CXXFLAGS="-O1 -fno-inline"
make clean make clean
make -j2 ARCH=x86-64-modern ${{ matrix.sanitizers.make_option }} debug=yes optimize=no build > /dev/null make -j2 ARCH=x86-64-modern ${{ matrix.sanitizers.make_option }} debug=yes optimize=no build > /dev/null
../tests/instrumented.sh --${{ matrix.sanitizers.instrumented_option }} ../tests/instrumented.sh --${{ matrix.sanitizers.instrumented_option }}
+91 -119
View File
@@ -12,95 +12,68 @@ jobs:
strategy: strategy:
matrix: matrix:
config: config:
- { - name: Ubuntu 20.04 GCC
name: "Ubuntu 20.04 GCC", os: ubuntu-20.04
os: ubuntu-20.04, compiler: g++
compiler: g++, comp: gcc
comp: gcc, run_32bit_tests: true
run_32bit_tests: true, run_64bit_tests: true
run_64bit_tests: true, shell: bash {0}
shell: 'bash {0}' - name: Ubuntu 20.04 Clang
} os: ubuntu-20.04
- { compiler: clang++
name: "Ubuntu 20.04 Clang", comp: clang
os: ubuntu-20.04, run_32bit_tests: true
compiler: clang++, run_64bit_tests: true
comp: clang, shell: bash {0}
run_32bit_tests: true, - name: Android NDK aarch64
run_64bit_tests: true, os: ubuntu-22.04
shell: 'bash {0}' compiler: aarch64-linux-android21-clang++
} comp: ndk
- { run_armv8_tests: true
name: "Ubuntu 20.04 NDK armv8", shell: bash {0}
os: ubuntu-20.04, - name: Android NDK arm
compiler: aarch64-linux-android21-clang++, os: ubuntu-22.04
comp: ndk, compiler: armv7a-linux-androideabi21-clang++
run_armv8_tests: false, comp: ndk
shell: 'bash {0}' run_armv7_tests: true
} shell: bash {0}
- { - name: MacOS 12 Apple Clang
name: "Ubuntu 20.04 NDK armv7", os: macos-12
os: ubuntu-20.04, compiler: clang++
compiler: armv7a-linux-androideabi21-clang++, comp: clang
comp: ndk, run_64bit_tests: true
run_armv7_tests: false, shell: bash {0}
shell: 'bash {0}' - name: MacOS 12 GCC 11
} os: macos-12
- { compiler: g++-11
name: "MacOS 12 Apple Clang", comp: gcc
os: macos-12, run_64bit_tests: true
compiler: clang++, shell: bash {0}
comp: clang, - name: Windows 2022 Mingw-w64 GCC x86_64
run_64bit_tests: true, os: windows-2022
shell: 'bash {0}' compiler: g++
} comp: mingw
- { run_64bit_tests: true
name: "MacOS 12 GCC 11", msys_sys: mingw64
os: macos-12, msys_env: x86_64-gcc
compiler: g++-11, shell: msys2 {0}
comp: gcc, - name: Windows 2022 Mingw-w64 GCC i686
run_64bit_tests: true, os: windows-2022
shell: 'bash {0}' compiler: g++
} comp: mingw
- { run_32bit_tests: true
name: "Windows 2022 Mingw-w64 GCC x86_64", msys_sys: mingw32
os: windows-2022, msys_env: i686-gcc
compiler: g++, shell: msys2 {0}
comp: mingw, - name: Windows 2022 Mingw-w64 Clang x86_64
run_64bit_tests: true, os: windows-2022
msys_sys: 'mingw64', compiler: clang++
msys_env: 'x86_64-gcc', comp: clang
shell: 'msys2 {0}' run_64bit_tests: true
} msys_sys: clang64
- { msys_env: clang-x86_64-clang
name: "Windows 2022 Mingw-w64 GCC i686", shell: msys2 {0}
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}'
}
exclude:
- config:
{
name: "Ubuntu 20.04 NDK armv7"
}
- config:
{
name: "Ubuntu 20.04 NDK armv8"
}
defaults: defaults:
run: run:
working-directory: src working-directory: src
@@ -116,30 +89,47 @@ jobs:
sudo apt update sudo apt update
sudo apt install expect valgrind g++-multilib qemu-user 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 - name: Setup msys and install required packages
if: runner.os == 'Windows' if: runner.os == 'Windows'
uses: msys2/setup-msys2@v2 uses: msys2/setup-msys2@v2
with: with:
msystem: ${{matrix.config.msys_sys}} msystem: ${{ matrix.config.msys_sys }}
install: mingw-w64-${{matrix.config.msys_env}} make git expect install: mingw-w64-${{ matrix.config.msys_env }} make git expect
- name: Download the used network from the fishtest framework - name: Download the used network from the fishtest framework
run: | run: make net
make net
- name: Extract the bench number from the commit history - name: Extract the bench number from the commit history
run: | run: |
git log HEAD | grep "\b[Bb]ench[ :]\+[0-9]\{7\}" | head -n 1 | sed "s/[^0-9]*\([0-9]*\).*/\1/g" > git_sig 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" [ -s git_sig ] && echo "benchref=$(cat git_sig)" >> $GITHUB_ENV && echo "Reference bench:" $(cat git_sig) || echo "No bench found"
- name: Check compiler - name: Check compiler
run: | run: |
export PATH=$PATH:$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin if [ $COMP == ndk ]; then
export PATH=${{ env.ANDROID_NDK_BIN }}:$PATH
fi
$COMPILER -v $COMPILER -v
- name: Test help target - name: Test help target
run: | run: make help
make help
- name: Check git
run: git --version
# x86-32 tests # x86-32 tests
@@ -229,13 +219,7 @@ jobs:
- name: Test armv8 build - name: Test armv8 build
if: ${{ matrix.config.run_armv8_tests }} if: ${{ matrix.config.run_armv8_tests }}
run: | run: |
ANDROID_ROOT=/usr/local/lib/android export PATH=${{ env.ANDROID_NDK_BIN }}:$PATH
ANDROID_SDK_ROOT=${ANDROID_ROOT}/sdk
SDKMANAGER=${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager
echo "y" | $SDKMANAGER "ndk;21.4.7075529"
ANDROID_NDK_ROOT=${ANDROID_SDK_ROOT}/ndk-bundle
ln -sfn $ANDROID_SDK_ROOT/ndk/21.4.7075529 $ANDROID_NDK_ROOT
export PATH=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH
export LDFLAGS="-static -Wno-unused-command-line-argument" export LDFLAGS="-static -Wno-unused-command-line-argument"
make clean make clean
make -j2 ARCH=armv8 build make -j2 ARCH=armv8 build
@@ -246,13 +230,7 @@ jobs:
- name: Test armv7 build - name: Test armv7 build
if: ${{ matrix.config.run_armv7_tests }} if: ${{ matrix.config.run_armv7_tests }}
run: | run: |
ANDROID_ROOT=/usr/local/lib/android export PATH=${{ env.ANDROID_NDK_BIN }}:$PATH
ANDROID_SDK_ROOT=${ANDROID_ROOT}/sdk
SDKMANAGER=${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager
echo "y" | $SDKMANAGER "ndk;21.4.7075529"
ANDROID_NDK_ROOT=${ANDROID_SDK_ROOT}/ndk-bundle
ln -sfn $ANDROID_SDK_ROOT/ndk/21.4.7075529 $ANDROID_NDK_ROOT
export PATH=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH
export LDFLAGS="-static -Wno-unused-command-line-argument" export LDFLAGS="-static -Wno-unused-command-line-argument"
make clean make clean
make -j2 ARCH=armv7 build make -j2 ARCH=armv7 build
@@ -261,13 +239,7 @@ jobs:
- name: Test armv7-neon build - name: Test armv7-neon build
if: ${{ matrix.config.run_armv7_tests }} if: ${{ matrix.config.run_armv7_tests }}
run: | run: |
ANDROID_ROOT=/usr/local/lib/android export PATH=${{ env.ANDROID_NDK_BIN }}:$PATH
ANDROID_SDK_ROOT=${ANDROID_ROOT}/sdk
SDKMANAGER=${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager
echo "y" | $SDKMANAGER "ndk;21.4.7075529"
ANDROID_NDK_ROOT=${ANDROID_SDK_ROOT}/ndk-bundle
ln -sfn $ANDROID_SDK_ROOT/ndk/21.4.7075529 $ANDROID_NDK_ROOT
export PATH=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH
export LDFLAGS="-static -Wno-unused-command-line-argument" export LDFLAGS="-static -Wno-unused-command-line-argument"
make clean make clean
make -j2 ARCH=armv7-neon build make -j2 ARCH=armv7-neon build
@@ -281,4 +253,4 @@ jobs:
make clean make clean
make -j2 ARCH=x86-64-modern build make -j2 ARCH=x86-64-modern build
../tests/perft.sh ../tests/perft.sh
../tests/reprosearch.sh ../tests/reprosearch.sh
+29 -19
View File
@@ -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)
@@ -35,6 +34,7 @@ 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) Boštjan Mejak (PedanticHacker)
braich braich
Brian Sheppard (SapphireBrand, briansheppard-toast) Brian Sheppard (SapphireBrand, briansheppard-toast)
@@ -46,12 +46,12 @@ Chess13234
Chris Cain (ceebo) Chris Cain (ceebo)
clefrks 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 Zar
David (dav1312) David (dav1312)
David Zar
Daylen Yang (daylen) Daylen Yang (daylen)
Deshawn Mohan-Smith (GoldenRare) Deshawn Mohan-Smith (GoldenRare)
Dieter Dobbelaere (ddobbelaere) Dieter Dobbelaere (ddobbelaere)
@@ -65,7 +65,6 @@ 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)
@@ -78,32 +77,35 @@ 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, kurt22i) 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)
@@ -117,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)
@@ -131,6 +134,7 @@ Matt Ginsberg (mattginsberg)
Matthew Lai (matthewlai) Matthew Lai (matthewlai)
Matthew Sullivan (Matt14916) Matthew Sullivan (Matt14916)
Max A. (Disservin) Max A. (Disservin)
Maxim Masiutin (maximmasiutin)
Maxim Molchanov (Maxim) Maxim Molchanov (Maxim)
Michael An (man) Michael An (man)
Michael Byrne (MichaelB7) Michael Byrne (MichaelB7)
@@ -145,16 +149,18 @@ 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
@@ -163,7 +169,9 @@ Pasquale Pigazzini (ppigazzini)
Patrick Jansen (mibere) Patrick Jansen (mibere)
Peter Schneider (pschneider1968) 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
@@ -172,8 +180,8 @@ Reuven Peleg (R-Peleg)
Richard Lloyd (Richard-Lloyd) Richard Lloyd (Richard-Lloyd)
Rodrigo Exterckötter Tjäder Rodrigo Exterckötter Tjäder
Rodrigo Roim (roim) Rodrigo Roim (roim)
Ron Britvich (Britvich)
Ronald de Man (syzygy1, syzygy) Ronald de Man (syzygy1, syzygy)
Ron Britvich (Britvich)
rqs rqs
Rui Coelho (ruicoelhopedro) Rui Coelho (ruicoelhopedro)
Ryan Schmitt Ryan Schmitt
@@ -184,21 +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)
Syine Mineta (MinetaS) Syine Mineta (MinetaS)
Prokop Randáček (ProkopRandacek)
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)
@@ -206,11 +215,12 @@ tttak
Unai Corzo (unaiic) Unai Corzo (unaiic)
Uri Blass (uriblass) Uri Blass (uriblass)
Vince Negri (cuddlestmonkey) Vince Negri (cuddlestmonkey)
Viren
windfishballad
xefoci7612 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
+23
View File
@@ -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
+83 -297
View File
@@ -2,6 +2,21 @@
[![Stockfish][stockfish128-logo]][website-link] [![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] [![Build][build-badge]][build-link]
[![License][license-badge]][license-link] [![License][license-badge]][license-link]
<br> <br>
@@ -16,19 +31,16 @@
## Overview ## Overview
[Stockfish][website-link] is a free, powerful UCI chess engine derived from [Stockfish][website-link] is a **free and strong UCI chess engine** derived from
Glaurung 2.1. Stockfish is not a complete chess program and requires a UCI-compatible Glaurung 2.1 that analyzes chess positions and computes the optimal moves.
graphical user interface (GUI) (e.g. XBoard with PolyGlot, Scid, Cute Chess, eboard,
Arena, Sigma Chess, Shredder, Chess Partner or Fritz) in order to be used comfortably. Stockfish **does not include a graphical user interface** (GUI) that is required
Read the documentation for your GUI of choice for information about how to use to display a chessboard and to make it easy to input moves. These GUIs are
developed independently from Stockfish and are available online. **Read the
documentation for your GUI** of choice for information about how to use
Stockfish with it. Stockfish with it.
The Stockfish engine features two evaluation functions for chess. The efficiently See also the Stockfish [documentation][wiki-usage-link] for further usage help.
updatable neural network (NNUE) based evaluation is the default and by far the strongest.
The classical evaluation based on handcrafted terms remains available. The strongest
network is integrated in the binary and downloaded automatically during the build process.
The NNUE evaluation benefits from the vector intrinsics available on most CPUs (sse2,
avx2, neon, or similar).
## Files ## Files
@@ -36,210 +48,47 @@ This distribution of Stockfish consists of the following files:
* [README.md][readme-link], the file you are currently reading. * [README.md][readme-link], the file you are currently reading.
* [Copying.txt][license-link], a text file containing the GNU General Public License * [Copying.txt][license-link], a text file containing the GNU General Public
version 3. License version 3.
* [AUTHORS][authors-link], 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][src-link], 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 evaluation. * a file with the .nnue extension, storing the neural network for the NNUE
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 its options as described typical graphical user interfaces (GUI) or chess tools. Stockfish implements the
in [the UCI protocol][uci-link]. 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
descriptions.
* #### MultiPV
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 HDD. 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][nodchip-link] provided the first version of the needed tools
to train and develop the NNUE networks. Today, more advanced training tools are
available in [the nnue-pytorch repository][pytorch-link], while data generation tools
are available in [a dedicated branch][tools-link].
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] cd src
make -j build ARCH=x86-64-modern
``` ```
replacing `[filename]` as needed.
## What to expect from the Syzygy tablebases? Detailed compilation instructions for all platforms can be found in our
[documentation][wiki-compile-link].
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.
## Stockfish on distributed memory systems ## Stockfish on distributed memory systems
@@ -266,137 +115,74 @@ implementation that efficiently supports this. Some MPI implentations might bene
from leaving 1 core/thread free for these asynchronous communications, and might require from leaving 1 core/thread free for these asynchronous communications, and might require
setting additional environment variables. ```mpirun``` should forward stdin/stdout setting additional environment variables. ```mpirun``` should forward stdin/stdout
to ```rank 0``` only (e.g. ```srun --input=0 --output=0```). to ```rank 0``` only (e.g. ```srun --input=0 --output=0```).
Refer to your MPI documentation for more info. Refer to your MPI documentation for more info.
## Large Pages ## Contributing
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)][lockpages-link]
on how to enable this privilege, then run [RAMMap][rammap-link]
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
make help
make net
make build ARCH=x86-64-modern
```
When not using the Makefile to compile (for instance, with Microsoft MSVC) you
need to manually set/unset some switches in the compiler command line; see
file *types.h* for a quick reference.
When reporting an issue or a bug, please tell us which Stockfish version
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][worker-link] hardware resources by installing the [Fishtest Worker][worker-link] and viewing
and view the current tests on [Fishtest][fishtest-link]. 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,][programming-link] 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][programmingsf-link]
describes many features and techniques used by Stockfish. However, it is
generic rather than being focused on Stockfish's precise implementation.
Nevertheless, a helpful resource.
* The latest source can always be found on [GitHub][github-link].
Discussions about Stockfish take place these days mainly in the [FishCooking][fishcooking-link]
group and on the [Stockfish Discord channel][discord-link].
The engine testing is done on [Fishtest][fishtest-link]. The engine testing is done on [Fishtest][fishtest-link].
If you want to help improve Stockfish, please read this [guideline][guideline-link] If you want to help improve Stockfish, please read this [guideline][guideline-link]
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 license and the full source code you MUST always include the license and the full source code (or a pointer to
(or a pointer to where the source code can be found) to generate the where the source code can be found) to generate the exact binary you are
exact binary you are distributing. If you make any changes to the distributing. If you make any changes to the source code, these changes must
source code, these changes must also be made available under the GPL v3. also be made available under GPL v3.
For full details, read the copy of the GPL v3 found in the file named
[*Copying.txt*][license-link].
[authors-link]: https://github.com/official-stockfish/Stockfish/blob/master/AUTHORS [authors-link]: https://github.com/official-stockfish/Stockfish/blob/master/AUTHORS
[build-link]: https://github.com/official-stockfish/Stockfish/actions/workflows/stockfish.yml [build-link]: https://github.com/official-stockfish/Stockfish/actions/workflows/stockfish.yml
[commits-link]: https://github.com/official-stockfish/Stockfish/commits/master [commits-link]: https://github.com/official-stockfish/Stockfish/commits/master
[discord-link]: https://discord.gg/GWDRS3kU6R [discord-link]: https://discord.gg/GWDRS3kU6R
[fishcooking-link]: https://groups.google.com/g/fishcooking [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 [fishtest-link]: https://tests.stockfishchess.org/tests
[github-link]: https://github.com/official-stockfish/Stockfish
[guideline-link]: https://github.com/glinscott/fishtest/wiki/Creating-my-first-test [guideline-link]: https://github.com/glinscott/fishtest/wiki/Creating-my-first-test
[license-link]: https://github.com/official-stockfish/Stockfish/blob/master/Copying.txt [license-link]: https://github.com/official-stockfish/Stockfish/blob/master/Copying.txt
[lockpages-link]: https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/enable-the-lock-pages-in-memory-option-windows
[nodchip-link]: https://github.com/nodchip/Stockfish
[programming-link]: https://www.chessprogramming.org/Main_Page [programming-link]: https://www.chessprogramming.org/Main_Page
[programmingsf-link]: https://www.chessprogramming.org/Stockfish [programmingsf-link]: https://www.chessprogramming.org/Stockfish
[pytorch-link]: https://github.com/glinscott/nnue-pytorch
[rammap-link]: https://docs.microsoft.com/en-us/sysinternals/downloads/rammap
[readme-link]: https://github.com/official-stockfish/Stockfish/blob/master/README.md [readme-link]: https://github.com/official-stockfish/Stockfish/blob/master/README.md
[release-link]: https://github.com/official-stockfish/Stockfish/releases/latest [release-link]: https://github.com/official-stockfish/Stockfish/releases/latest
[src-link]: https://github.com/official-stockfish/Stockfish/tree/master/src [src-link]: https://github.com/official-stockfish/Stockfish/tree/master/src
[stockfish128-logo]: https://stockfishchess.org/images/logo/icon_128x128.png [stockfish128-logo]: https://stockfishchess.org/images/logo/icon_128x128.png
[tools-link]: https://github.com/official-stockfish/Stockfish/tree/tools [uci-link]: https://backscattering.de/chess/uci/
[uci-link]: https://www.shredderchess.com/download/div/uci.zip
[website-link]: https://stockfishchess.org [website-link]: https://stockfishchess.org
[worker-link]: https://github.com/glinscott/fishtest/wiki/Running-the-worker:-overview [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/workflow/status/official-stockfish/Stockfish/Stockfish?style=for-the-badge&label=stockfish&logo=github [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 [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 [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 [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
+103 -96
View File
@@ -1,160 +1,167 @@
Contributors to Fishtest with >10,000 CPU hours, as of 2022-11-19. 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 36475307 2748033975 noobpwnftw 37457426 2850540907
technologov 14570711 760073590 technologov 14135647 742892808
linrock 4423514 303254809
mlang 3026000 200065824 mlang 3026000 200065824
dew 1689222 100034318 dew 1689162 100033738
grandphish2 1442171 86798057 okrout 1578136 148855886
okrout 1439985 133471766 pemo 1508508 48814305
pemo 1405374 44189811 grandphish2 1461406 91540343
linrock 1299003 28382783 TueRens 1194790 70400852
TueRens 1163420 71159522 JojoM 947612 61773190
JojoM 897158 55177114
tvijlbrief 796125 51897690 tvijlbrief 796125 51897690
sebastronomy 742434 38218524
mibere 703840 46867607 mibere 703840 46867607
gvreuls 635982 40652394 gvreuls 651026 42988582
oz 590763 41201352 oz 543438 39314736
sebastronomy 581517 23307132 cw 517858 34869755
cw 517915 34865769 fastgm 503862 30260818
fastgm 504266 30264740 leszek 467278 33514883
CSU_Dynasty 479901 31846710 CSU_Dynasty 464940 31177118
ctoks 433503 28180725 ctoks 434416 28506889
crunchy 427035 27344275 crunchy 427035 27344275
leszek 416883 27493447 maximmasiutin 424795 26577722
bcross 409982 28062127 bcross 415722 29060963
velislav 345954 22232274 olafm 395922 32268020
rpngn 348378 24560289
velislav 342567 22138992
Fisherman 327231 21829379 Fisherman 327231 21829379
mgrabiak 300612 20608380
Dantist 296386 18031762 Dantist 296386 18031762
mgrabiak 288928 18869896 nordlandia 246201 16189678
rpngn 259965 16281463 robal 241300 15656382
robal 237653 15148350 marrco 234581 17714473
ncfish1 231764 15275003 ncfish1 227517 15233777
nordlandia 226923 14624832
glinscott 208125 13277240 glinscott 208125 13277240
drabel 204167 13930674 drabel 204167 13930674
mhoram 202894 12601997 mhoram 202894 12601997
bking_US 198894 11876016 bking_US 198894 11876016
thirdlife 198844 5453268
Thanar 179852 12365359 Thanar 179852 12365359
vdv 175544 9904472 vdv 175544 9904472
armo9494 168201 11136452
spams 157128 10319326 spams 157128 10319326
marrco 151599 9551115
sqrt2 147963 9724586 sqrt2 147963 9724586
vdbergh 137690 8971569 DesolatedDodo 146350 9536172
Calis007 143165 9478764
vdbergh 138650 9064413
CoffeeOne 137100 5024116 CoffeeOne 137100 5024116
armo9494 136191 9460264
malala 136182 8002293 malala 136182 8002293
DesolatedDodo 135276 8657464
xoto 133759 9159372 xoto 133759 9159372
davar 129023 8376525 davar 129023 8376525
DMBK 122960 8980062
dsmith 122059 7570238 dsmith 122059 7570238
amicic 119661 7938029 amicic 119661 7938029
Data 113305 8220352 Data 113305 8220352
BrunoBanani 112960 7436849 BrunoBanani 112960 7436849
CypressChess 108331 7759788 CypressChess 108331 7759788
skiminki 106518 7062598 skiminki 107583 7218170
jcAEie 105675 8238962
MaZePallas 102823 6633619 MaZePallas 102823 6633619
sterni1971 100532 5880772 sterni1971 100532 5880772
sunu 100167 7040199 sunu 100167 7040199
zeryl 99331 6221261 zeryl 99331 6221261
thirdlife 99124 2242380
ElbertoOne 99028 7023771 ElbertoOne 99028 7023771
DMBK 97572 6950312 cuistot 98853 6069816
Calis007 96779 5611552 bigpen0r 94809 6529203
cuistot 93111 5536500
brabos 92118 6186135 brabos 92118 6186135
Wolfgang 91769 5720158 Wolfgang 91939 6105872
psk 89957 5984901 psk 89957 5984901
sschnee 88235 5268000
racerschmacer 85805 6122790 racerschmacer 85805 6122790
jcAEie 85527 5630616 Fifis 85722 5709729
Dubslow 84986 6042456
Vizvezdenec 83761 5344740 Vizvezdenec 83761 5344740
sschnee 83557 4853690
0x3C33 82614 5271253 0x3C33 82614 5271253
BRAVONE 81239 5054681 BRAVONE 81239 5054681
Dubslow 78461 5042980
nssy 76497 5259388 nssy 76497 5259388
jromang 76106 5236025 jromang 76106 5236025
teddybaer 75125 5407666 teddybaer 75125 5407666
yurikvelo 73933 5031096 tolkki963 74762 5149662
tolkki963 73885 4721430 megaman7de 74351 4940352
Wencey 74181 4711488
Pking_cda 73776 5293873 Pking_cda 73776 5293873
Bobo1239 71675 4860987 yurikvelo 73150 5004382
markkulix 72607 5304642
Bobo1239 70579 4794999
solarlight 70517 5028306 solarlight 70517 5028306
dv8silencer 70287 3883992 dv8silencer 70287 3883992
Gelma 69304 3980932
manap 66273 4121774 manap 66273 4121774
megaman7de 65419 4120200
markkulix 65331 4114860
bigpen0r 64932 4683883
tinker 64333 4268790 tinker 64333 4268790
qurashee 61208 3429862 qurashee 61208 3429862
AGI 58325 4258646 Mineta 59357 4418202
Spprtr 58723 3911011
AGI 58147 4325994
robnjr 57262 4053117 robnjr 57262 4053117
Freja 56938 3733019 Freja 56938 3733019
MaxKlaxxMiner 56879 3423958 MaxKlaxxMiner 56879 3423958
MarcusTullius 56746 3762951
ttruscott 56010 3680085 ttruscott 56010 3680085
rkl 55132 4164467 rkl 55132 4164467
renouve 53811 3501516 renouve 53811 3501516
Spprtr 52736 3410019 javran 53785 4627608
finfish 51360 3370515 finfish 51360 3370515
eva42 51272 3599691 eva42 51272 3599691
eastorwest 51117 3454811 eastorwest 51117 3454811
rap 49985 3219146 rap 49985 3219146
unixwizard 49734 2536230 pb00067 49733 3298934
pb00067 49727 3298270 OuaisBla 48626 3445134
ronaldjerum 47654 3240695 ronaldjerum 47654 3240695
biffhero 46564 3111352 biffhero 46564 3111352
GPUex 45861 2926502
Fifis 45843 3088497
oryx 45578 3493978
VoyagerOne 45476 3452465 VoyagerOne 45476 3452465
Wencey 44943 2654490 jmdana 44893 3065205
maposora 44597 4039578
oryx 44570 3454238
speedycpu 43842 3003273 speedycpu 43842 3003273
jbwiebe 43305 2805433 jbwiebe 43305 2805433
GPUex 42378 3133332
Antihistamine 41788 2761312 Antihistamine 41788 2761312
mhunt 41735 2691355 mhunt 41735 2691355
olafm 41277 3284344
homyur 39893 2850481 homyur 39893 2850481
gri 39871 2515779 gri 39871 2515779
MarcusTullius 38303 2251097
Garf 37741 2999686 Garf 37741 2999686
kdave 37424 2557406
SC 37299 2731694 SC 37299 2731694
csnodgrass 36207 2688994 csnodgrass 36207 2688994
jmdana 36157 2210661
strelock 34716 2074055 strelock 34716 2074055
szupaw 34102 2880346
EthanOConnor 33370 2090311 EthanOConnor 33370 2090311
slakovv 32915 2021889 slakovv 32915 2021889
gopeto 31669 2060958 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 30135 1903728 spcc 29925 1901692
hyperbolic.tom 29840 2017394 hyperbolic.tom 29840 2017394
xwziegtm 29763 2347412
chuckstablers 29659 2093438 chuckstablers 29659 2093438
Pyafue 29650 1902349 Pyafue 29650 1902349
belzedar94 28846 1811530 belzedar94 28846 1811530
OuaisBla 27636 1578800
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 25289 1674274 Ulysses 25288 1689730
SFTUser 25182 1675689 SFTUser 25182 1675689
nabildanial 24942 1519409 nabildanial 24942 1519409
Sharaf_DG 24765 1786697 Sharaf_DG 24765 1786697
Maxim 24705 1502062
rodneyc 24376 1416402 rodneyc 24376 1416402
agg177 23890 1395014 agg177 23890 1395014
Ente 23747 1674582 Goatminola 23763 1956036
Karpovbot 23629 1313186 Ente 23639 1671638
Jopo12321 23467 1483172
JanErik 23408 1703875 JanErik 23408 1703875
Isidor 23388 1680691 Isidor 23388 1680691
Norabor 23371 1603244 Norabor 23371 1603244
cisco2015 22934 1763773 cisco2015 22920 1763301
jsys14 22824 1591906
Zirie 22542 1472937 Zirie 22542 1472937
team-oh 22272 1636708 team-oh 22272 1636708
Roady 22220 1465606 Roady 22220 1465606
@@ -165,96 +172,96 @@ xor12 21628 1680365
dex 21612 1467203 dex 21612 1467203
nesoneg 21494 1463031 nesoneg 21494 1463031
user213718 21454 1404128 user213718 21454 1404128
AndreasKrug 21227 1577833
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
jsys14 20729 1221010
0xB00B1ES 20590 1208666 0xB00B1ES 20590 1208666
j3corre 20405 941444 j3corre 20405 941444
Adrian.Schmidt123 20316 1281436 Adrian.Schmidt123 20316 1281436
bonsi 20022 1300682
wei 19973 1745989 wei 19973 1745989
dapper 19754 1167758 notchris 19958 1800128
Zake9298 19745 1458416 Serpensin 19840 1697528
Gaster319 19712 1677310
fishtester 19617 1257388 fishtester 19617 1257388
rstoesser 19569 1293588 rstoesser 19569 1293588
eudhan 19274 1283717 eudhan 19274 1283717
votoanthuan 19108 1609992
vulcan 18871 1729392 vulcan 18871 1729392
Jopo12321 18803 1036284 Karpovbot 18766 1053178
qoo_charly_cai 18543 1284937
jundery 18445 1115855 jundery 18445 1115855
ville 17883 1384026 ville 17883 1384026
5t0ckf15hTr4in3r 17809 1105858
chris 17698 1487385 chris 17698 1487385
dju 17697 994333
purplefishies 17595 1092533 purplefishies 17595 1092533
dju 17414 981289
iisiraider 17275 1049015 iisiraider 17275 1049015
DragonLord 17014 1162790 DragonLord 17014 1162790
Karby 16457 1010138 redstone59 16842 1461780
Goatminola 16278 1145026 Alb11747 16787 1213926
IgorLeMasson 16064 1147232 IgorLeMasson 16064 1147232
Gaster319 16056 1109070 Karby 15982 979610
redstone59 15953 1161664
scuzzi 15757 968735 scuzzi 15757 968735
ako027ako 15671 1173203 ako027ako 15671 1173203
Nikolay.IT 15154 1068349 Nikolay.IT 15154 1068349
Andrew Grant 15114 895539 Andrew Grant 15114 895539
Naven94 15054 834762 Naven94 15054 834762
OssumOpossum 14857 1007129 OssumOpossum 14857 1007129
qoo_charly_cai 14490 847865 ZacHFX 14783 1021842
enedene 14476 905279 enedene 14476 905279
szupaw 14252 929130
bpfliegel 14233 882523 bpfliegel 14233 882523
mpx86 14019 759568 mpx86 14019 759568
jpulman 13982 870599 jpulman 13982 870599
Skiff84 13826 721996
crocogoat 13803 1117422 crocogoat 13803 1117422
Nesa92 13786 1114691 Nesa92 13786 1114691
joster 13710 946160 joster 13710 946160
mbeier 13650 1044928 mbeier 13650 1044928
Hjax 13535 915487 Hjax 13535 915487
Nullvalue 13468 1140498
Dark_wizzie 13422 1007152 Dark_wizzie 13422 1007152
Rudolphous 13244 883140 Rudolphous 13244 883140
pirt 13100 1009897
Machariel 13010 863104 Machariel 13010 863104
infinigon 12991 943216 infinigon 12991 943216
pirt 12925 985437
Skiff84 12923 649994
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
woutboat 12419 836696
SapphireBrand 12416 969604 SapphireBrand 12416 969604
Oakwen 12406 840961 Oakwen 12399 844109
deflectooor 12386 579392 deflectooor 12386 579392
modolief 12386 896470 modolief 12386 896470
Farseer 12249 694108 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
MooTheCow 11871 773654 MooTheCow 11870 773598
Jackfish 11867 773550 FormazChar 11766 885707
dbernier 11705 821780
whelanh 11557 245188 whelanh 11557 245188
Maxim 11543 836024 3cho 11494 1031076
Nullvalue 11534 731410
icewulf 11528 650470
FormazChar 11523 861599
infinity 11470 727027 infinity 11470 727027
aga 11412 695127 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
ali-al-zhrani 11272 781310
d64 11263 789184 d64 11263 789184
Bourbaki 11108 709144 ali-al-zhrani 11245 779246
snicolet 11106 869170 snicolet 11106 869170
Alb11747 10855 696920 dapper 11032 771402
ols 10947 624903
Karmatron 10828 677458
basepi 10637 744851 basepi 10637 744851
Cubox 10621 826448 Cubox 10621 826448
Karmatron 10616 674818
michaelrpg 10509 739239 michaelrpg 10509 739239
OIVAS7572 10420 995586 OIVAS7572 10420 995586
Garruk 10348 704905 jojo2357 10419 929708
WoodMan777 10380 873720
Garruk 10365 706465
dzjp 10343 732529 dzjp 10343 732529
ols 10259 570669
+110 -76
View File
@@ -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-2022 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
@@ -69,33 +69,34 @@ VPATH = syzygy:nnue:nnue/features
### Section 2. High-level Configuration ### Section 2. High-level Configuration
### ========================================================================== ### ==========================================================================
# #
# flag --- Comp switch --- Description # flag --- Comp switch --- Description
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
# #
# debug = yes/no --- -DNDEBUG --- Enable/Disable debug mode # debug = yes/no --- -DNDEBUG --- Enable/Disable debug mode
# sanitize = none/<sanitizer> ... (-fsanitize ) # sanitize = none/<sanitizer> ... (-fsanitize )
# --- ( undefined ) --- enable undefined behavior checks # --- ( undefined ) --- enable undefined behavior checks
# --- ( thread ) --- enable threading error checks # --- ( thread ) --- enable threading error checks
# --- ( address ) --- enable memory access checks # --- ( address ) --- enable memory access checks
# --- ...etc... --- see compiler documentation for supported sanitizers # --- ...etc... --- see compiler documentation for supported sanitizers
# optimize = yes/no --- (-O3/-fast etc.) --- Enable/Disable optimizations # optimize = yes/no --- (-O3/-fast etc.) --- Enable/Disable optimizations
# arch = (name) --- (-arch) --- Target architecture # arch = (name) --- (-arch) --- Target architecture
# bits = 64/32 --- -DIS_64BIT --- 64-/32-bit operating system # bits = 64/32 --- -DIS_64BIT --- 64-/32-bit operating system
# prefetch = yes/no --- -DUSE_PREFETCH --- Use prefetch asm-instruction # prefetch = yes/no --- -DUSE_PREFETCH --- Use prefetch asm-instruction
# popcnt = yes/no --- -DUSE_POPCNT --- Use popcnt asm-instruction # popcnt = yes/no --- -DUSE_POPCNT --- Use popcnt asm-instruction
# pext = yes/no --- -DUSE_PEXT --- Use pext x86_64 asm-instruction # pext = yes/no --- -DUSE_PEXT --- Use pext x86_64 asm-instruction
# sse = yes/no --- -msse --- Use Intel Streaming SIMD Extensions # sse = yes/no --- -msse --- Use Intel Streaming SIMD Extensions
# mmx = yes/no --- -mmmx --- Use Intel MMX instructions # mmx = yes/no --- -mmmx --- Use Intel MMX instructions
# sse2 = yes/no --- -msse2 --- Use Intel Streaming SIMD Extensions 2 # sse2 = yes/no --- -msse2 --- Use Intel Streaming SIMD Extensions 2
# 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 # 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
# mpi = yes/no --- -DUSE_MPI --- Use Message Passing Interface # mpi = yes/no --- -DUSE_MPI --- Use Message Passing Interface
# 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
@@ -117,7 +118,7 @@ ifeq ($(ARCH), $(filter $(ARCH), \
x86-64-vnni512 x86-64-vnni256 x86-64-avx512 x86-64-avxvnni x86-64-bmi2 \ x86-64-vnni512 x86-64-vnni256 x86-64-avx512 x86-64-avxvnni x86-64-bmi2 \
x86-64-avx2 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 riscv64)) 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
@@ -142,6 +143,7 @@ vnni256 = no
vnni512 = no vnni512 = no
neon = no neon = no
mpi = no mpi = no
dotprod = no
arm_version = 0 arm_version = 0
STRIP = strip STRIP = strip
@@ -310,11 +312,21 @@ ifeq ($(ARCH),armv8)
arm_version = 8 arm_version = 8
endif endif
ifeq ($(ARCH),armv8-dotprod)
arch = armv8
prefetch = yes
popcnt = yes
neon = yes
dotprod = yes
arm_version = 8
endif
ifeq ($(ARCH),apple-silicon) ifeq ($(ARCH),apple-silicon)
arch = arm64 arch = arm64
prefetch = yes prefetch = yes
popcnt = yes popcnt = yes
neon = yes neon = yes
dotprod = yes
arm_version = 8 arm_version = 8
endif endif
@@ -368,7 +380,7 @@ 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 riscv64)) ifeq ($(arch),$(filter $(arch),armv7 armv8 riscv64))
ifeq ($(OS),Android) ifeq ($(OS),Android)
@@ -412,13 +424,14 @@ ifeq ($(COMP),mingw)
CXX=i686-w64-mingw32-c++-posix CXX=i686-w64-mingw32-c++-posix
endif endif
endif endif
CXXFLAGS += -pedantic -Wextra -Wshadow CXXFLAGS += -pedantic -Wextra -Wshadow -Wmissing-declarations
endif endif
ifeq ($(COMP),icc) ifeq ($(COMP),icx)
comp=icc comp=icx
CXX=icpc CXX=icpx
CXXFLAGS += -diag-disable 1476,10120 -Wcheck -Wabi -Wdeprecated -strict-ansi CXXFLAGS += --intel -pedantic -Wextra -Wshadow -Wmissing-prototypes \
-Wconditional-uninitialized -Wabi -Wdeprecated
endif endif
ifeq ($(COMP),clang) ifeq ($(COMP),clang)
@@ -428,7 +441,8 @@ ifeq ($(COMP),clang)
CXX=x86_64-w64-mingw32-clang++ CXX=x86_64-w64-mingw32-clang++
endif endif
CXXFLAGS += -pedantic -Wextra -Wshadow CXXFLAGS += -pedantic -Wextra -Wshadow -Wmissing-prototypes \
-Wconditional-uninitialized
ifeq ($(filter $(KERNEL),Darwin OpenBSD FreeBSD),) ifeq ($(filter $(KERNEL),Darwin OpenBSD FreeBSD),)
ifeq ($(target_windows),) ifeq ($(target_windows),)
@@ -488,9 +502,9 @@ ifeq ($(COMP),ndk)
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
@@ -514,7 +528,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
@@ -561,7 +575,7 @@ ifeq ($(optimize),yes)
endif endif
ifeq ($(KERNEL),Darwin) ifeq ($(KERNEL),Darwin)
ifeq ($(comp),$(filter $(comp),clang icc)) ifeq ($(comp),$(filter $(comp),clang icx))
CXXFLAGS += -mdynamic-no-pic CXXFLAGS += -mdynamic-no-pic
endif endif
@@ -573,7 +587,10 @@ ifeq ($(optimize),yes)
endif endif
ifeq ($(comp),clang) ifeq ($(comp),clang)
CXXFLAGS += -fexperimental-new-pass-manager clangmajorversion = $(shell $(CXX) -dumpversion 2>/dev/null | cut -f1 -d.)
ifeq ($(shell expr $(clangmajorversion) \< 16),1)
CXXFLAGS += -fexperimental-new-pass-manager
endif
endif endif
endif endif
@@ -594,8 +611,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
@@ -604,63 +619,63 @@ 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 -mbmi CXXFLAGS += -mavx2 -mbmi
endif endif
endif endif
ifeq ($(avxvnni),yes) ifeq ($(avxvnni),yes)
CXXFLAGS += -DUSE_VNNI -DUSE_AVXVNNI CXXFLAGS += -DUSE_VNNI -DUSE_AVXVNNI
ifeq ($(comp),$(filter $(comp),gcc clang mingw)) ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
CXXFLAGS += -mavxvnni 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
@@ -676,24 +691,28 @@ 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 ### 3.7.1 Try to include git commit sha for versioning
GIT_SHA = $(shell git rev-parse --short HEAD 2>/dev/null) GIT_SHA = $(shell git rev-parse HEAD 2>/dev/null | cut -c 1-8)
ifneq ($(GIT_SHA), ) ifneq ($(GIT_SHA), )
CXXFLAGS += -DGIT_SHA=\"$(GIT_SHA)\" CXXFLAGS += -DGIT_SHA=$(GIT_SHA)
endif endif
### 3.7.2 Try to include git commit date for versioning ### 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) GIT_DATE = $(shell git show -s --date=format:'%Y%m%d' --format=%cd HEAD 2>/dev/null)
ifneq ($(GIT_DATE), ) ifneq ($(GIT_DATE), )
CXXFLAGS += -DGIT_DATE=\"$(GIT_DATE)\" CXXFLAGS += -DGIT_DATE=$(GIT_DATE)
endif endif
### 3.8 Link Time Optimization ### 3.8 Link Time Optimization
@@ -701,8 +720,11 @@ endif
### 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=full CXXFLAGS += -flto=full
ifeq ($(comp),icx)
CXXFLAGS += -fwhole-program-vtables
endif
ifeq ($(target_windows),yes) ifeq ($(target_windows),yes)
CXXFLAGS += -fuse-ld=lld CXXFLAGS += -fuse-ld=lld
endif endif
@@ -758,19 +780,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 avxvnni 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"
@@ -786,6 +808,7 @@ 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"
@@ -797,17 +820,18 @@ help:
@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 ""
@@ -822,8 +846,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 FORCE 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
@@ -863,7 +889,7 @@ net:
$(eval nnuedownloadurl2 := https://github.com/official-stockfish/networks/raw/master/$(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 [ "x$(curl_or_wget)" = "x" ]; then \ @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; \ echo "Neither curl nor wget is installed. Install one of these tools unless the net has been downloaded manually"; \
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 \
@@ -874,7 +900,9 @@ net:
echo "$(nnuenet) available."; \ echo "$(nnuenet) available."; \
else \ else \
if [ "x$(curl_or_wget)" != "x" ]; then \ if [ "x$(curl_or_wget)" != "x" ]; then \
echo "Downloading $${nnuedownloadurl}"; $(curl_or_wget) $${nnuedownloadurl} > $(nnuenet);\ echo "Downloading $${nnuedownloadurl}"; $(curl_or_wget) $${nnuedownloadurl} > $(nnuenet);\
else \
echo "No net found and download not possible"; exit 1;\
fi; \ fi; \
fi; \ fi; \
if [ "x$(shasum_command)" != "x" ]; then \ if [ "x$(shasum_command)" != "x" ]; then \
@@ -937,7 +965,9 @@ config-sanity: net
@echo "vnni512: '$(vnni512)'" @echo "vnni512: '$(vnni512)'"
@echo "neon: '$(neon)'" @echo "neon: '$(neon)'"
@echo "mpi: '$(mpi)'" @echo "mpi: '$(mpi)'"
@echo "dotprod: '$(dotprod)'"
@echo "arm_version: '$(arm_version)'" @echo "arm_version: '$(arm_version)'"
@echo "target_windows: '$(target_windows)'"
@echo "" @echo ""
@echo "Flags:" @echo "Flags:"
@echo "CXX: $(CXX)" @echo "CXX: $(CXX)"
@@ -966,7 +996,7 @@ 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)
@@ -1004,18 +1034,22 @@ gcc-profile-use:
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
+3 -1
View File
@@ -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-2022 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>
+34
View File
@@ -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
View File
@@ -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-2022 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
View File
@@ -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-2022 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
View File
@@ -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-2022 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
View File
@@ -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-2022 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
View File
@@ -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-2022 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 -40
View File
@@ -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-2022 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
@@ -37,7 +37,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).
@@ -83,20 +83,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;
} }
@@ -112,7 +110,7 @@ namespace Eval {
(void) gEmbeddedNNUEEnd; // Silence warning on unused variable (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;
} }
} }
@@ -163,24 +161,24 @@ namespace Trace {
Score scores[TERM_NB][COLOR_NB]; Score scores[TERM_NB][COLOR_NB];
double to_cp(Value v) { return double(v) / UCI::NormalizeToPawnValue; } 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 << " ---- ----" << " | " << " ---- ----";
@@ -197,8 +195,8 @@ using namespace Trace;
namespace { namespace {
// Threshold for lazy and space evaluation // Threshold for lazy and space evaluation
constexpr Value LazyThreshold1 = Value(3631); constexpr Value LazyThreshold1 = Value(3622);
constexpr Value LazyThreshold2 = Value(2084); 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
@@ -392,10 +390,10 @@ namespace {
template<Tracing T> template<Color Us, PieceType Pt> template<Tracing T> template<Color Us, PieceType Pt>
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;
Score score = SCORE_ZERO; Score score = SCORE_ZERO;
@@ -434,7 +432,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
@@ -1052,52 +1050,41 @@ make_v:
/// evaluate() is the evaluator for the outer world. It returns a static /// evaluate() is the evaluator for the outer world. It returns a static
/// evaluation of the position from the point of view of the side to move. /// evaluation of the position from the point of view of the side to move.
Value Eval::evaluate(const Position& pos, int* complexity) { Value Eval::evaluate(const Position& pos) {
assert(!pos.checkers());
Value v; Value v;
Value psq = pos.psq_eg_stm(); Value psq = pos.psq_eg_stm();
// We use the much less accurate but faster Classical eval when the NNUE // We use the much less accurate but faster Classical eval when the NNUE
// option is set to false. Otherwise we use the NNUE eval unless the // option is set to false. Otherwise we use the NNUE eval unless the
// PSQ advantage is decisive and several pieces remain. (~3 Elo) // PSQ advantage is decisive. (~4 Elo at STC, 1 Elo at LTC)
bool useClassical = !useNNUE || (pos.count<ALL_PIECES>() > 7 && abs(psq) > 1760); bool useClassical = !useNNUE || abs(psq) > 2048;
if (useClassical) if (useClassical)
v = Evaluation<NO_TRACE>(pos).value(); v = Evaluation<NO_TRACE>(pos).value();
else else
{ {
int nnueComplexity; int nnueComplexity;
int scale = 1064 + 106 * pos.non_pawn_material() / 5120; int npm = pos.non_pawn_material() / 64;
Color stm = pos.side_to_move(); Color stm = pos.side_to_move();
Value optimism = pos.this_thread()->optimism[stm]; Value optimism = pos.this_thread()->optimism[stm];
Value nnue = NNUE::evaluate(pos, true, &nnueComplexity); Value nnue = NNUE::evaluate(pos, true, &nnueComplexity);
// Blend nnue complexity with (semi)classical complexity // Blend optimism with nnue complexity and (semi)classical complexity
nnueComplexity = ( 416 * nnueComplexity optimism += optimism * (nnueComplexity + abs(psq - nnue)) / 512;
+ 424 * abs(psq - nnue) v = (nnue * (945 + npm) + optimism * (150 + npm)) / 1024;
+ (optimism > 0 ? int(optimism) * int(psq - nnue) : 0)
) / 1024;
// Return hybrid NNUE complexity to caller
if (complexity)
*complexity = nnueComplexity;
optimism = optimism * (269 + nnueComplexity) / 256;
v = (nnue * scale + optimism * (scale - 754)) / 1024;
} }
// Damp down the evaluation linearly when shuffling // Damp down the evaluation linearly when shuffling
v = v * (195 - pos.rule50_count()) / 211; 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);
// When not using NNUE, return classical complexity to caller
if (complexity && (!useNNUE || useClassical))
*complexity = abs(v - psq);
return v; return v;
} }
+3 -10
View File
@@ -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-2022 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,7 +31,7 @@ class Position;
namespace Eval { namespace Eval {
std::string trace(Position& pos); std::string trace(Position& pos);
Value evaluate(const Position& pos, int* complexity = nullptr); Value evaluate(const Position& pos);
extern bool useNNUE; extern bool useNNUE;
extern std::string currentEvalFileName; extern std::string currentEvalFileName;
@@ -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-ad9b42354671.nnue" #define EvalFileDefaultName "nn-5af11540bbfe.nnue"
namespace NNUE { namespace NNUE {
std::string trace(Position& pos);
Value evaluate(const Position& pos, bool adjusted = false, int* complexity = nullptr);
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
View File
+1 -1
View File
@@ -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-2022 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
View File
@@ -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-2022 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
View File
@@ -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-2022 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);
+137 -37
View File
@@ -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-2022 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,21 +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);
typedef bool(*fun4_t)(USHORT, PGROUP_AFFINITY, USHORT, PUSHORT); using fun4_t = bool(*)(USHORT, PGROUP_AFFINITY, USHORT, PUSHORT);
typedef WORD(*fun5_t)(); 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>
@@ -68,7 +73,7 @@ namespace Stockfish {
namespace { namespace {
/// Version number or dev. /// Version number or dev.
const string version = "15.1"; constexpr string_view version = "16";
/// 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
@@ -151,13 +156,13 @@ string engine_info(bool to_uci) {
stringstream ss; stringstream ss;
ss << "Stockfish " << version << setfill('0'); ss << "Stockfish " << version << setfill('0');
if (version == "dev") if constexpr (version == "dev")
{ {
ss << "-"; ss << "-";
#ifdef GIT_DATE #ifdef GIT_DATE
ss << GIT_DATE; ss << stringify(GIT_DATE);
#else #else
const string months("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec"); constexpr string_view months("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec");
string month, day, year; string month, day, year;
stringstream date(__DATE__); // From compiler, format is "Sep 21 2008" stringstream date(__DATE__); // From compiler, format is "Sep 21 2008"
@@ -168,7 +173,7 @@ string engine_info(bool to_uci) {
ss << "-"; ss << "-";
#ifdef GIT_SHA #ifdef GIT_SHA
ss << GIT_SHA; ss << stringify(GIT_SHA);
#else #else
ss << "nogit"; ss << "nogit";
#endif #endif
@@ -185,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:
@@ -298,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;
}
} }
@@ -373,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
@@ -384,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
@@ -409,11 +489,30 @@ static void* aligned_large_pages_alloc_windows([[maybe_unused]] 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 { };
@@ -425,17 +524,18 @@ static void* aligned_large_pages_alloc_windows([[maybe_unused]] 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);
} }
} }
@@ -453,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;
} }
@@ -517,7 +617,7 @@ void bindThisThread(size_t) {}
/// API and returns the best node 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_node(size_t idx) { static int best_node(size_t idx) {
int threads = 0; int threads = 0;
int nodes = 0; int nodes = 0;
@@ -526,7 +626,7 @@ int best_node(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;
@@ -596,7 +696,7 @@ void bindThisThread(size_t idx) {
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 fun4 = (fun4_t)(void(*)())GetProcAddress(k32, "GetNumaNodeProcessorMask2");
+10 -32
View File
@@ -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-2022 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,32 +89,6 @@ 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:
// 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) const
{ return b * average > a * (PERIOD * RESOLUTION); }
int64_t value() const
{ return average / (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 {
@@ -164,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
View File
@@ -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-2022 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
View File
@@ -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-2022 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
+10 -11
View File
@@ -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-2022 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
@@ -69,7 +69,6 @@ MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHist
stage = (pos.checkers() ? EVASION_TT : MAIN_TT) + stage = (pos.checkers() ? EVASION_TT : MAIN_TT) +
!(ttm && pos.pseudo_legal(ttm)); !(ttm && pos.pseudo_legal(ttm));
threatenedPieces = 0;
} }
/// MovePicker constructor for quiescence search /// MovePicker constructor for quiescence search
@@ -93,20 +92,20 @@ MovePicker::MovePicker(const Position& p, Move ttm, Value th, const CapturePiece
{ {
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; [[maybe_unused]] Bitboard threatenedByPawn, threatenedByMinor, threatenedByRook, threatenedPieces;
if constexpr (Type == QUIETS) if constexpr (Type == QUIETS)
{ {
Color us = pos.side_to_move(); Color us = pos.side_to_move();
@@ -123,8 +122,8 @@ void MovePicker::score() {
for (auto& m : *this) for (auto& m : *this)
if constexpr (Type == CAPTURES) if constexpr (Type == CAPTURES)
m.value = 6 * int(PieceValue[MG][pos.piece_on(to_sq(m))]) 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 = 2 * (*mainHistory)[pos.side_to_move()][from_to(m)] m.value = 2 * (*mainHistory)[pos.side_to_move()][from_to(m)]
@@ -141,7 +140,7 @@ void MovePicker::score() {
+ bool(pos.check_squares(type_of(pos.moved_piece(m))) & to_sq(m)) * 16384; + 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); + (1 << 28);
@@ -158,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())
@@ -197,7 +196,7 @@ top:
case GOOD_CAPTURE: case GOOD_CAPTURE:
if (select<Next>([&](){ 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);
@@ -216,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;
+8 -10
View File
@@ -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-2022 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);
} }
@@ -87,23 +87,23 @@ enum StatsType { NoCaptures, Captures };
/// 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
/// (~11 elo) /// (~11 elo)
typedef Stats<int16_t, 7183, COLOR_NB, int(SQUARE_NB) * int(SQUARE_NB)> ButterflyHistory; using ButterflyHistory = Stats<int16_t, 7183, COLOR_NB, int(SQUARE_NB) * int(SQUARE_NB)>;
/// 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.
/// (~63 elo) /// (~63 elo)
typedef Stats<PieceToHistory, NOT_USED, PIECE_NB, SQUARE_NB> ContinuationHistory; 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
@@ -131,8 +131,6 @@ public:
MovePicker(const Position&, Move, Value, const CapturePieceToHistory*); MovePicker(const Position&, Move, Value, const CapturePieceToHistory*);
Move next_move(bool skipQuiets = false); Move next_move(bool skipQuiets = false);
Bitboard threatenedPieces;
private: private:
template<PickType T, typename Pred> Move select(Pred); template<PickType T, typename Pred> Move select(Pred);
template<GenType> void score(); template<GenType> void score();
+28 -29
View File
@@ -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-2022 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,7 +105,7 @@ 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);
@@ -115,7 +115,7 @@ namespace Stockfish::Eval::NNUE {
} }
// 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,6 +136,11 @@ 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, int* complexity) { Value evaluate(const Position& pos, bool adjusted, int* complexity) {
@@ -143,7 +148,7 @@ namespace Stockfish::Eval::NNUE {
// 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 = 24 - pos.non_pawn_material() / 9560; constexpr int delta = 24;
#if defined(ALIGNAS_ON_STACK_VARIABLES_BROKEN) #if defined(ALIGNAS_ON_STACK_VARIABLES_BROKEN)
TransformedFeatureType transformedFeaturesUnaligned[ TransformedFeatureType transformedFeaturesUnaligned[
@@ -211,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.
@@ -245,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)) / UCI::NormalizeToPawnValue; << std::setw(6)
sprintf(&buffer[1], "%6.2f", cp); << std::setprecision(2)
<< cp;
} }
@@ -332,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";
+10 -1
View File
@@ -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-2022 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 -1
View File
@@ -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-2022 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
View File
@@ -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-2022 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 -43
View File
@@ -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-2022 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,7 +31,7 @@
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
@@ -72,6 +71,10 @@ namespace Stockfish::Eval::NNUE::Layers {
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)
constexpr IndexType NumChunks = ceil_to_multiple<IndexType>(InputDimensions, 16) / 16; constexpr IndexType NumChunks = ceil_to_multiple<IndexType>(InputDimensions, 16) / 16;
const auto inputVector = reinterpret_cast<const int8x8_t*>(input); const auto inputVector = reinterpret_cast<const int8x8_t*>(input);
@@ -123,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]);
@@ -157,7 +168,7 @@ namespace Stockfish::Eval::NNUE::Layers {
constexpr IndexType LargeInputSize = std::numeric_limits<IndexType>::max(); constexpr IndexType LargeInputSize = std::numeric_limits<IndexType>::max();
#endif #endif
// A specialization for large inputs. // A specialization for large inputs
template <IndexType InDims, IndexType OutDims> template <IndexType InDims, IndexType OutDims>
class AffineTransform<InDims, OutDims, std::enable_if_t<(ceil_to_multiple<IndexType>(InDims, MaxSimdWidth) >= LargeInputSize)>> { class AffineTransform<InDims, OutDims, std::enable_if_t<(ceil_to_multiple<IndexType>(InDims, MaxSimdWidth) >= LargeInputSize)>> {
public: public:
@@ -176,36 +187,39 @@ namespace Stockfish::Eval::NNUE::Layers {
using OutputBuffer = OutputType[PaddedOutputDimensions]; using OutputBuffer = OutputType[PaddedOutputDimensions];
static_assert(PaddedInputDimensions >= LargeInputSize, "Something went wrong. This specialization should not have been chosen."); 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) #elif defined (USE_NEON)
static constexpr const IndexType InputSimdWidth = 8; static constexpr IndexType InputSimdWidth = 8;
static constexpr const IndexType MaxNumOutputRegs = 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);
@@ -241,8 +255,7 @@ namespace Stockfish::Eval::NNUE::Layers {
// Read network parameters // Read network parameters
bool read_parameters(std::istream& stream) { bool read_parameters(std::istream& stream) {
for (IndexType i = 0; i < OutputDimensions; ++i) read_little_endian<BiasType>(stream, biases, OutputDimensions);
biases[i] = read_little_endian<BiasType>(stream);
for (IndexType 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);
@@ -252,8 +265,7 @@ 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 {
for (IndexType i = 0; i < OutputDimensions; ++i) write_little_endian<BiasType>(stream, biases, OutputDimensions);
write_little_endian<BiasType>(stream, biases[i]);
for (IndexType 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)]);
@@ -292,6 +304,15 @@ namespace Stockfish::Eval::NNUE::Layers {
#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) #elif defined (USE_NEON)
using acc_vec_t = int32x4_t; using acc_vec_t = int32x4_t;
using bias_vec_t = int32x4_t; using bias_vec_t = int32x4_t;
@@ -374,6 +395,7 @@ namespace Stockfish::Eval::NNUE::Layers {
alignas(CacheLineSize) WeightType weights[OutputDimensions * PaddedInputDimensions]; alignas(CacheLineSize) WeightType weights[OutputDimensions * PaddedInputDimensions];
}; };
// A specialization for small inputs
template <IndexType InDims, IndexType OutDims> template <IndexType InDims, IndexType OutDims>
class AffineTransform<InDims, OutDims, std::enable_if_t<(ceil_to_multiple<IndexType>(InDims, MaxSimdWidth) < LargeInputSize)>> { class AffineTransform<InDims, OutDims, std::enable_if_t<(ceil_to_multiple<IndexType>(InDims, MaxSimdWidth) < LargeInputSize)>> {
public: public:
@@ -393,12 +415,7 @@ namespace Stockfish::Eval::NNUE::Layers {
using OutputBuffer = OutputType[PaddedOutputDimensions]; using OutputBuffer = OutputType[PaddedOutputDimensions];
static_assert(PaddedInputDimensions < LargeInputSize, "Something went wrong. This specialization should not have been chosen."); static_assert(PaddedInputDimensions < LargeInputSize, "Something went wrong. This specialization (for small inputs) should not have been chosen.");
#if defined (USE_SSSE3)
static constexpr const IndexType OutputSimdWidth = SimdWidth / 4;
static constexpr const IndexType InputSimdWidth = SimdWidth;
#endif
// Hash value embedded in the evaluation file // Hash value embedded in the evaluation file
static constexpr std::uint32_t get_hash_value(std::uint32_t prevHash) { static constexpr std::uint32_t get_hash_value(std::uint32_t prevHash) {
@@ -428,8 +445,7 @@ namespace Stockfish::Eval::NNUE::Layers {
// Read network parameters // Read network parameters
bool read_parameters(std::istream& stream) { bool read_parameters(std::istream& stream) {
for (IndexType i = 0; i < OutputDimensions; ++i) read_little_endian<BiasType>(stream, biases, OutputDimensions);
biases[i] = read_little_endian<BiasType>(stream);
for (IndexType 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);
@@ -438,8 +454,7 @@ 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 {
for (IndexType i = 0; i < OutputDimensions; ++i) write_little_endian<BiasType>(stream, biases, OutputDimensions);
write_little_endian<BiasType>(stream, biases[i]);
for (IndexType 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)]);
@@ -450,29 +465,34 @@ namespace Stockfish::Eval::NNUE::Layers {
const OutputType* propagate( const OutputType* propagate(
const InputType* input, OutputType* output) const { const InputType* input, OutputType* output) const {
#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 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)
@@ -518,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<
@@ -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 -1
View File
@@ -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-2022 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
+34 -18
View File
@@ -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-2022 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
@@ -153,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
@@ -165,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
} }
@@ -249,7 +250,7 @@ namespace Stockfish::Simd {
asm( asm(
VNNI_PREFIX "vpdpbusd %[b0], %[a0], %[acc]\n\t" VNNI_PREFIX "vpdpbusd %[b0], %[a0], %[acc]\n\t"
VNNI_PREFIX "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
@@ -261,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
} }
@@ -326,23 +328,37 @@ 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) #if defined (USE_NEON)
[[maybe_unused]] static int neon_m128_reduce_add_epi32(int32x4_t s) { [[maybe_unused]] static int neon_m128_reduce_add_epi32(int32x4_t s) {
+2 -2
View File
@@ -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-2022 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
@@ -106,7 +106,7 @@ namespace Stockfish::Eval::NNUE::Layers {
for (IndexType i = Start; i < InputDimensions; ++i) { for (IndexType i = Start; i < InputDimensions; ++i) {
output[i] = static_cast<OutputType>( output[i] = static_cast<OutputType>(
// realy should be /127 but we need to make it fast // really should be /127 but we need to make it fast
// needs to be accounted for in the trainer // needs to be accounted for in the trainer
std::max(0ll, std::min(127ll, (((long long)input[i] * input[i]) >> (2 * WeightScaleBits)) / 128))); std::max(0ll, std::min(127ll, (((long long)input[i] * input[i]) >> (2 * WeightScaleBits)) / 128)));
} }
+1 -1
View File
@@ -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-2022 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
+15 -16
View File
@@ -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-2022 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,6 +27,7 @@
#include "features/half_ka_v2_hm.h" #include "features/half_ka_v2_hm.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 "layers/sqr_clipped_relu.h"
@@ -39,7 +40,7 @@ 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;
@@ -48,7 +49,7 @@ struct Network
static constexpr int FC_0_OUTPUTS = 15; static constexpr int FC_0_OUTPUTS = 15;
static constexpr int FC_1_OUTPUTS = 32; static constexpr int FC_1_OUTPUTS = 32;
Layers::AffineTransform<TransformedFeatureDimensions, FC_0_OUTPUTS + 1> fc_0; Layers::AffineTransformSparseInput<TransformedFeatureDimensions, FC_0_OUTPUTS + 1> fc_0;
Layers::SqrClippedReLU<FC_0_OUTPUTS + 1> ac_sqr_0; Layers::SqrClippedReLU<FC_0_OUTPUTS + 1> ac_sqr_0;
Layers::ClippedReLU<FC_0_OUTPUTS + 1> ac_0; Layers::ClippedReLU<FC_0_OUTPUTS + 1> ac_0;
Layers::AffineTransform<FC_0_OUTPUTS * 2, FC_1_OUTPUTS> fc_1; Layers::AffineTransform<FC_0_OUTPUTS * 2, FC_1_OUTPUTS> fc_1;
@@ -72,22 +73,20 @@ struct Network
// Read network parameters // Read network parameters
bool read_parameters(std::istream& stream) { bool read_parameters(std::istream& stream) {
if (!fc_0.read_parameters(stream)) return false; return fc_0.read_parameters(stream)
if (!ac_0.read_parameters(stream)) return false; && ac_0.read_parameters(stream)
if (!fc_1.read_parameters(stream)) return false; && fc_1.read_parameters(stream)
if (!ac_1.read_parameters(stream)) return false; && ac_1.read_parameters(stream)
if (!fc_2.read_parameters(stream)) return false; && fc_2.read_parameters(stream);
return true;
} }
// Read network parameters // Write network parameters
bool write_parameters(std::ostream& stream) const { bool write_parameters(std::ostream& stream) const {
if (!fc_0.write_parameters(stream)) return false; return fc_0.write_parameters(stream)
if (!ac_0.write_parameters(stream)) return false; && ac_0.write_parameters(stream)
if (!fc_1.write_parameters(stream)) return false; && fc_1.write_parameters(stream)
if (!ac_1.write_parameters(stream)) return false; && ac_1.write_parameters(stream)
if (!fc_2.write_parameters(stream)) return false; && fc_2.write_parameters(stream);
return true;
} }
std::int32_t propagate(const TransformedFeatureType* transformedFeatures) std::int32_t propagate(const TransformedFeatureType* transformedFeatures)
+78 -1
View File
@@ -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-2022 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;
@@ -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
+272 -187
View File
@@ -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-2022 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,8 +42,8 @@ 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)
@@ -65,8 +66,8 @@ namespace Stockfish::Eval::NNUE {
#define MaxChunkSize 64 #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)
@@ -89,8 +90,8 @@ namespace Stockfish::Eval::NNUE {
#define MaxChunkSize 32 #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)
@@ -110,8 +111,8 @@ namespace Stockfish::Eval::NNUE {
#define MaxChunkSize 16 #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)
@@ -138,8 +139,8 @@ namespace Stockfish::Eval::NNUE {
#define MaxChunkSize 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)
@@ -252,9 +253,9 @@ namespace Stockfish::Eval::NNUE {
// 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();
} }
@@ -262,9 +263,9 @@ 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();
} }
@@ -332,27 +333,16 @@ namespace Stockfish::Eval::NNUE {
#endif #endif
return psqt; 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:
template<Color Perspective> template<Color Perspective>
void update_accumulator(const Position& pos) const { [[nodiscard]] std::pair<StateInfo*, StateInfo*> try_find_computed_accumulator(const Position& pos) const {
// The size must be enough to contain the largest possible update.
// That might depend on the feature set and generally relies on the
// feature set's update cost calculation to be correct and never
// allow updates with more added/removed features than MaxActiveDimensions.
#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
// Look for a usable accumulator of an earlier position. We keep track // Look for a usable accumulator of an earlier position. We keep track
// of the estimated gain in terms of features to be added/subtracted. // of the estimated gain in terms of features to be added/subtracted.
StateInfo *st = pos.state(), *next = nullptr; StateInfo *st = pos.state(), *next = nullptr;
@@ -367,218 +357,313 @@ namespace Stockfish::Eval::NNUE {
next = st; next = st;
st = st->previous; st = st->previous;
} }
return { st, next };
}
if (st->accumulator.computed[Perspective]) // NOTE: The parameter states_to_update is an array of position states, ending with nullptr.
{ // All states must be sequential, that is states_to_update[i] must either be reachable
if (next == nullptr) // by repeatedly applying ->previous from states_to_update[i+1] or states_to_update[i] == nullptr.
return; // 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);
// Update incrementally in two steps. First, we update the "next"
// accumulator. Then, we update the current accumulator (pos.state()).
// Gather all features to be updated.
const Square ksq = pos.square<KING>(Perspective);
FeatureSet::IndexList removed[2], added[2];
FeatureSet::append_changed_indices<Perspective>(
ksq, next->dirtyPiece, removed[0], added[0]);
for (StateInfo *st2 = pos.state(); st2 != next; st2 = st2->previous)
FeatureSet::append_changed_indices<Perspective>(
ksq, st2->dirtyPiece, removed[1], added[1]);
// Mark the accumulators as computed.
next->accumulator.computed[Perspective] = true;
pos.state()->accumulator.computed[Perspective] = true;
// 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) // 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
if (states_to_update[0] == nullptr)
return;
// Update incrementally going back through states_to_update.
// Gather all features to be updated.
const Square ksq = pos.square<KING>(Perspective);
// The size must be enough to contain the largest possible update.
// That might depend on the feature set and generally relies on the
// 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)
{ {
// Load accumulator states_to_update[i]->accumulator.computed[Perspective] = true;
auto accTile = reinterpret_cast<vec_t*>(
&st->accumulator.accumulation[Perspective][j * TileHeight]);
for (IndexType k = 0; k < NumRegs; ++k)
acc[k] = vec_load(&accTile[k]);
for (IndexType i = 0; states_to_update[i]; ++i) StateInfo* end_state = i == 0 ? computed_st : states_to_update[i - 1];
{
// Difference calculation for the deactivated features
for (const auto index : removed[i])
{
const IndexType offset = HalfDimensions * index + j * TileHeight;
auto column = reinterpret_cast<const vec_t*>(&weights[offset]);
for (IndexType k = 0; k < NumRegs; ++k)
acc[k] = vec_sub_16(acc[k], column[k]);
}
// Difference calculation for the activated features for (; st2 != end_state; st2 = st2->previous)
for (const auto index : added[i]) FeatureSet::append_changed_indices<Perspective>(
{ ksq, st2->dirtyPiece, removed[i], added[i]);
const IndexType offset = HalfDimensions * index + j * TileHeight;
auto column = reinterpret_cast<const vec_t*>(&weights[offset]);
for (IndexType k = 0; k < NumRegs; ++k)
acc[k] = vec_add_16(acc[k], column[k]);
}
// Store accumulator
accTile = reinterpret_cast<vec_t*>(
&states_to_update[i]->accumulator.accumulation[Perspective][j * TileHeight]);
for (IndexType k = 0; k < NumRegs; ++k)
vec_store(&accTile[k], acc[k]);
}
} }
}
for (IndexType j = 0; j < PSQTBuckets / PsqtTileHeight; ++j) StateInfo* st = computed_st;
{
// Load accumulator
auto accTilePsqt = reinterpret_cast<psqt_vec_t*>(
&st->accumulator.psqtAccumulation[Perspective][j * PsqtTileHeight]);
for (std::size_t k = 0; k < NumPsqtRegs; ++k)
psqt[k] = vec_load_psqt(&accTilePsqt[k]);
for (IndexType i = 0; states_to_update[i]; ++i) // Now update the accumulators listed in states_to_update[], where the last element is a sentinel.
{ #ifdef VECTOR
// Difference calculation for the deactivated features for (IndexType j = 0; j < HalfDimensions / TileHeight; ++j)
for (const auto index : removed[i]) {
{ // Load accumulator
const IndexType offset = PSQTBuckets * index + j * PsqtTileHeight; auto accTile = reinterpret_cast<vec_t*>(
auto columnPsqt = reinterpret_cast<const psqt_vec_t*>(&psqtWeights[offset]); &st->accumulator.accumulation[Perspective][j * TileHeight]);
for (std::size_t k = 0; k < NumPsqtRegs; ++k) for (IndexType k = 0; k < NumRegs; ++k)
psqt[k] = vec_sub_psqt_32(psqt[k], columnPsqt[k]); acc[k] = vec_load(&accTile[k]);
}
// Difference calculation for the activated features
for (const auto index : added[i])
{
const IndexType offset = PSQTBuckets * index + j * PsqtTileHeight;
auto columnPsqt = reinterpret_cast<const psqt_vec_t*>(&psqtWeights[offset]);
for (std::size_t k = 0; k < NumPsqtRegs; ++k)
psqt[k] = vec_add_psqt_32(psqt[k], columnPsqt[k]);
}
// Store accumulator
accTilePsqt = reinterpret_cast<psqt_vec_t*>(
&states_to_update[i]->accumulator.psqtAccumulation[Perspective][j * PsqtTileHeight]);
for (std::size_t k = 0; k < NumPsqtRegs; ++k)
vec_store_psqt(&accTilePsqt[k], psqt[k]);
}
}
#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],
st->accumulator.accumulation[Perspective],
HalfDimensions * sizeof(BiasType));
for (std::size_t k = 0; k < PSQTBuckets; ++k)
states_to_update[i]->accumulator.psqtAccumulation[Perspective][k] = st->accumulator.psqtAccumulation[Perspective][k];
st = states_to_update[i];
// Difference calculation for the deactivated features // Difference calculation for the deactivated features
for (const auto index : removed[i]) for (const auto index : removed[i])
{ {
const IndexType offset = HalfDimensions * index; const IndexType offset = HalfDimensions * index + j * TileHeight;
auto column = reinterpret_cast<const vec_t*>(&weights[offset]);
for (IndexType j = 0; j < HalfDimensions; ++j) for (IndexType k = 0; k < NumRegs; ++k)
st->accumulator.accumulation[Perspective][j] -= weights[offset + j]; acc[k] = vec_sub_16(acc[k], column[k]);
for (std::size_t k = 0; k < PSQTBuckets; ++k)
st->accumulator.psqtAccumulation[Perspective][k] -= psqtWeights[index * PSQTBuckets + k];
} }
// Difference calculation for the activated features // Difference calculation for the activated features
for (const auto index : added[i]) for (const auto index : added[i])
{
const IndexType offset = HalfDimensions * index;
for (IndexType j = 0; j < HalfDimensions; ++j)
st->accumulator.accumulation[Perspective][j] += weights[offset + j];
for (std::size_t k = 0; k < PSQTBuckets; ++k)
st->accumulator.psqtAccumulation[Perspective][k] += psqtWeights[index * PSQTBuckets + k];
}
}
#endif
}
else
{
// Refresh the accumulator
auto& accumulator = pos.state()->accumulator;
accumulator.computed[Perspective] = true;
FeatureSet::IndexList active;
FeatureSet::append_active_indices<Perspective>(pos, active);
#ifdef VECTOR
for (IndexType j = 0; j < HalfDimensions / TileHeight; ++j)
{
auto biasesTile = reinterpret_cast<const vec_t*>(
&biases[j * TileHeight]);
for (IndexType k = 0; k < NumRegs; ++k)
acc[k] = biasesTile[k];
for (const auto index : active)
{ {
const IndexType offset = HalfDimensions * index + j * TileHeight; const IndexType offset = HalfDimensions * index + j * TileHeight;
auto column = reinterpret_cast<const vec_t*>(&weights[offset]); auto column = reinterpret_cast<const vec_t*>(&weights[offset]);
for (IndexType k = 0; k < NumRegs; ++k)
for (unsigned k = 0; k < NumRegs; ++k)
acc[k] = vec_add_16(acc[k], column[k]); acc[k] = vec_add_16(acc[k], column[k]);
} }
auto accTile = reinterpret_cast<vec_t*>( // Store accumulator
&accumulator.accumulation[Perspective][j * TileHeight]); accTile = reinterpret_cast<vec_t*>(
for (unsigned k = 0; k < NumRegs; k++) &states_to_update[i]->accumulator.accumulation[Perspective][j * TileHeight]);
for (IndexType k = 0; k < NumRegs; ++k)
vec_store(&accTile[k], acc[k]); vec_store(&accTile[k], acc[k]);
} }
}
for (IndexType j = 0; j < PSQTBuckets / PsqtTileHeight; ++j) for (IndexType j = 0; j < PSQTBuckets / PsqtTileHeight; ++j)
{
// Load accumulator
auto accTilePsqt = reinterpret_cast<psqt_vec_t*>(
&st->accumulator.psqtAccumulation[Perspective][j * PsqtTileHeight]);
for (std::size_t k = 0; k < NumPsqtRegs; ++k)
psqt[k] = vec_load_psqt(&accTilePsqt[k]);
for (IndexType i = 0; states_to_update[i]; ++i)
{ {
for (std::size_t k = 0; k < NumPsqtRegs; ++k) // Difference calculation for the deactivated features
psqt[k] = vec_zero_psqt(); for (const auto index : removed[i])
for (const auto index : active)
{ {
const IndexType offset = PSQTBuckets * index + j * PsqtTileHeight; const IndexType offset = PSQTBuckets * index + j * PsqtTileHeight;
auto columnPsqt = reinterpret_cast<const psqt_vec_t*>(&psqtWeights[offset]); auto columnPsqt = reinterpret_cast<const psqt_vec_t*>(&psqtWeights[offset]);
for (std::size_t k = 0; k < NumPsqtRegs; ++k)
psqt[k] = vec_sub_psqt_32(psqt[k], columnPsqt[k]);
}
// Difference calculation for the activated features
for (const auto index : added[i])
{
const IndexType offset = PSQTBuckets * index + j * PsqtTileHeight;
auto columnPsqt = reinterpret_cast<const psqt_vec_t*>(&psqtWeights[offset]);
for (std::size_t k = 0; k < NumPsqtRegs; ++k) for (std::size_t k = 0; k < NumPsqtRegs; ++k)
psqt[k] = vec_add_psqt_32(psqt[k], columnPsqt[k]); psqt[k] = vec_add_psqt_32(psqt[k], columnPsqt[k]);
} }
auto accTilePsqt = reinterpret_cast<psqt_vec_t*>( // Store accumulator
&accumulator.psqtAccumulation[Perspective][j * PsqtTileHeight]); accTilePsqt = reinterpret_cast<psqt_vec_t*>(
&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]);
} }
}
#else #else
std::memcpy(accumulator.accumulation[Perspective], biases, for (IndexType i = 0; states_to_update[i]; ++i)
{
std::memcpy(states_to_update[i]->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)
accumulator.psqtAccumulation[Perspective][k] = 0; states_to_update[i]->accumulator.psqtAccumulation[Perspective][k] = st->accumulator.psqtAccumulation[Perspective][k];
for (const auto index : active) st = states_to_update[i];
// Difference calculation for the deactivated features
for (const auto index : removed[i])
{ {
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]; 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)
accumulator.psqtAccumulation[Perspective][k] += psqtWeights[index * PSQTBuckets + k]; st->accumulator.psqtAccumulation[Perspective][k] -= psqtWeights[index * PSQTBuckets + k];
}
// Difference calculation for the activated features
for (const auto index : added[i])
{
const IndexType offset = HalfDimensions * index;
for (IndexType j = 0; j < HalfDimensions; ++j)
st->accumulator.accumulation[Perspective][j] += weights[offset + j];
for (std::size_t k = 0; k < PSQTBuckets; ++k)
st->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 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
// 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;
accumulator.computed[Perspective] = true;
FeatureSet::IndexList active;
FeatureSet::append_active_indices<Perspective>(pos, active);
#ifdef VECTOR
for (IndexType j = 0; j < HalfDimensions / TileHeight; ++j)
{
auto biasesTile = reinterpret_cast<const vec_t*>(
&biases[j * TileHeight]);
for (IndexType k = 0; k < NumRegs; ++k)
acc[k] = biasesTile[k];
for (const auto index : active)
{
const IndexType offset = HalfDimensions * index + j * TileHeight;
auto column = reinterpret_cast<const vec_t*>(&weights[offset]);
for (unsigned k = 0; k < NumRegs; ++k)
acc[k] = vec_add_16(acc[k], column[k]);
}
auto accTile = reinterpret_cast<vec_t*>(
&accumulator.accumulation[Perspective][j * TileHeight]);
for (unsigned k = 0; k < NumRegs; k++)
vec_store(&accTile[k], acc[k]);
}
for (IndexType j = 0; j < PSQTBuckets / PsqtTileHeight; ++j)
{
for (std::size_t k = 0; k < NumPsqtRegs; ++k)
psqt[k] = vec_zero_psqt();
for (const auto index : active)
{
const IndexType offset = PSQTBuckets * index + j * PsqtTileHeight;
auto columnPsqt = reinterpret_cast<const psqt_vec_t*>(&psqtWeights[offset]);
for (std::size_t k = 0; k < NumPsqtRegs; ++k)
psqt[k] = vec_add_psqt_32(psqt[k], columnPsqt[k]);
}
auto accTilePsqt = reinterpret_cast<psqt_vec_t*>(
&accumulator.psqtAccumulation[Perspective][j * PsqtTileHeight]);
for (std::size_t k = 0; k < NumPsqtRegs; ++k)
vec_store_psqt(&accTilePsqt[k], psqt[k]);
}
#else
std::memcpy(accumulator.accumulation[Perspective], biases,
HalfDimensions * sizeof(BiasType));
for (std::size_t k = 0; k < PSQTBuckets; ++k)
accumulator.psqtAccumulation[Perspective][k] = 0;
for (const auto index : active)
{
const IndexType offset = HalfDimensions * index;
for (IndexType j = 0; j < HalfDimensions; ++j)
accumulator.accumulation[Perspective][j] += weights[offset + j];
for (std::size_t k = 0; k < PSQTBuckets; ++k)
accumulator.psqtAccumulation[Perspective][k] += psqtWeights[index * PSQTBuckets + k];
}
#endif
#if defined(USE_MMX)
_mm_empty();
#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];
+1 -1
View File
@@ -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-2022 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
View File
@@ -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-2022 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);
+44 -50
View File
@@ -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-2022 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; }
@@ -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;
@@ -1065,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));
@@ -1084,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;
@@ -1115,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));
} }
@@ -1167,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.
@@ -1323,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)))
+25 -18
View File
@@ -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-2022 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;
@@ -126,6 +125,7 @@ public:
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_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;
@@ -178,8 +179,8 @@ 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);
@@ -204,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;
@@ -227,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 {
@@ -383,8 +382,16 @@ inline bool Position::is_chess960() const {
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
View File
@@ -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-2022 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
View File
@@ -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-2022 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
+370 -342
View File
File diff suppressed because it is too large Load Diff
+3 -2
View File
@@ -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-2022 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
@@ -72,6 +72,7 @@ struct RootMove {
Value score = -VALUE_INFINITE; Value score = -VALUE_INFINITE;
Value previousScore = -VALUE_INFINITE; Value previousScore = -VALUE_INFINITE;
Value averageScore = -VALUE_INFINITE; Value averageScore = -VALUE_INFINITE;
Value uciScore = -VALUE_INFINITE;
bool scoreLowerbound = false; bool scoreLowerbound = false;
bool scoreUpperbound = false; bool scoreUpperbound = false;
int selDepth = 0; int selDepth = 0;
@@ -80,7 +81,7 @@ struct RootMove {
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
+13 -15
View File
@@ -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-2022 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 "../cluster.h" #include "../cluster.h"
@@ -71,7 +72,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];
@@ -142,7 +143,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 };
@@ -200,13 +201,10 @@ 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
struct stat statbuf; struct stat statbuf;
@@ -237,7 +235,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)
@@ -330,7 +328,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;
@@ -1516,7 +1514,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
@@ -1595,7 +1593,7 @@ bool Tablebases::root_probe_wdl(Position& pos, Search::RootMoves& rootMoves) {
static const int WDL_to_rank[] = { -MAX_DTZ, -MAX_DTZ + 101, 0, MAX_DTZ - 101, MAX_DTZ }; 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 -1
View File
@@ -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-2022 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 -22
View File
@@ -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-2022 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,7 +60,6 @@ void Thread::clear() {
counterMoves.fill(MOVE_NONE); counterMoves.fill(MOVE_NONE);
mainHistory.fill(0); mainHistory.fill(0);
captureHistory.fill(0); captureHistory.fill(0);
previousDepth = 0;
for (bool inCheck : { false, true }) for (bool inCheck : { false, true })
for (StatsType c : { NoCaptures, Captures }) for (StatsType c : { NoCaptures, Captures })
@@ -73,9 +72,9 @@ void Thread::clear() {
/// 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()
} }
@@ -125,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,7 +156,7 @@ 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;
@@ -190,7 +189,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())
@@ -201,7 +200,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->TTsaves = th->nmpMinPly = th->bestMoveChanges = 0; th->nodes = th->tbHits = th->TTsaves = th->nmpMinPly = th->bestMoveChanges = 0;
th->rootDepth = th->completedDepth = 0; th->rootDepth = th->completedDepth = 0;
@@ -217,12 +216,12 @@ 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
@@ -230,10 +229,10 @@ Thread* ThreadPool::get_best_thread() const {
return (th->rootMoves[0].score - minScore + 14) * int(th->completedDepth); return (th->rootMoves[0].score - minScore + 14) * int(th->completedDepth);
}; };
for (Thread* th : *this) for (Thread* th : threads)
votes[th->rootMoves[0].pv[0]] += thread_value(th); votes[th->rootMoves[0].pv[0]] += thread_value(th);
for (Thread* th : *this) 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
@@ -244,7 +243,8 @@ Thread* ThreadPool::get_best_thread() const {
|| ( 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]] || ( votes[th->rootMoves[0].pv[0]] == votes[bestThread->rootMoves[0].pv[0]]
&& thread_value(th) > thread_value(bestThread))))) && 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;
@@ -255,8 +255,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();
} }
@@ -265,8 +265,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();
} }
+13 -7
View File
@@ -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-2022 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,16 +61,14 @@ public:
Pawns::Table pawnsTable; Pawns::Table pawnsTable;
Material::Table materialTable; Material::Table materialTable;
size_t pvIdx, pvLast; size_t pvIdx, pvLast;
RunningAverage complexityAverage;
std::atomic<uint64_t> nodes, tbHits, TTsaves, bestMoveChanges; std::atomic<uint64_t> nodes, tbHits, TTsaves, bestMoveChanges;
int selDepth, nmpMinPly; int selDepth, nmpMinPly;
Color nmpColor;
Value bestValue, optimism[COLOR_NB]; Value bestValue, optimism[COLOR_NB];
Position rootPos; Position rootPos;
StateInfo rootState; StateInfo rootState;
Search::RootMoves rootMoves; Search::RootMoves rootMoves;
Depth rootDepth, completedDepth, previousDepth; Depth rootDepth, completedDepth;
Value rootDelta; Value rootDelta;
CounterMoveHistory counterMoves; CounterMoveHistory counterMoves;
ButterflyHistory mainHistory; ButterflyHistory mainHistory;
@@ -108,13 +106,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); }
uint64_t TT_saves() const { return accumulate(&Thread::TTsaves); } uint64_t TT_saves() const { return accumulate(&Thread::TTsaves); }
@@ -124,13 +122,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;
} }
+4 -4
View File
@@ -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-2022 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
+7 -3
View File
@@ -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-2022 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;
+1 -1
View File
@@ -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-2022 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
View File
@@ -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-2022 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
@@ -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 -1
View File
@@ -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-2022 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
View File
@@ -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-2022 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
View File
@@ -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-2022 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;
+13 -8
View File
@@ -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-2022 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;
@@ -186,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,
@@ -215,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,
@@ -413,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;
} }
@@ -442,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,10 +479,6 @@ 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;
+15 -10
View File
@@ -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-2022 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 "cluster.h" #include "cluster.h"
#include "movegen.h" #include "movegen.h"
@@ -32,13 +33,12 @@
#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 for the initial position in standard chess // FEN string for the initial position in standard chess
@@ -162,7 +162,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();
@@ -211,8 +211,8 @@ namespace {
// The coefficients of a third-order polynomial fit is based on the fishtest data // The coefficients of a third-order polynomial fit is based on the fishtest data
// for two parameters that need to transform eval to the argument of a logistic // for two parameters that need to transform eval to the argument of a logistic
// function. // function.
constexpr double as[] = { -0.58270499, 2.68512549, 15.24638015, 344.49745382}; constexpr double as[] = { 0.38036525, -2.82015070, 23.17882135, 307.36768407};
constexpr double bs[] = { -2.65734562, 15.96509799, -20.69040836, 73.61029937 }; constexpr double bs[] = { -2.29434733, 13.27689788, -14.26828904, 63.45318330 };
// Enforce that NormalizeToPawnValue corresponds to a 50% win rate at ply 64 // 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])); static_assert(UCI::NormalizeToPawnValue == int(as[0] + as[1] + as[2] + as[3]));
@@ -323,8 +323,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 / NormalizeToPawnValue; 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;
@@ -362,15 +367,15 @@ std::string UCI::square(Square s) {
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));
+5 -5
View File
@@ -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-2022 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
@@ -35,7 +35,7 @@ namespace UCI {
// the win_rate_model() such that Stockfish outputs an advantage of // 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 // "100 centipawns" for a position if the engine has a 50% probability to win
// from this position in selfplay at fishtest LTC time control. // from this position in selfplay at fishtest LTC time control.
const int NormalizeToPawnValue = 361; const int NormalizeToPawnValue = 328;
class Option; class Option;
@@ -45,12 +45,12 @@ struct CaseInsensitiveLess {
}; };
/// The options container is defined as 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>;
/// The Option class implements each option as specified by the 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);
@@ -61,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;
+11 -11
View File
@@ -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-2022 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 {
@@ -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 {
+7 -1
View File
@@ -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