diff --git a/.github/workflows/release-pipeline.yaml b/.github/workflows/release-pipeline.yaml
index 1f19c11..06280df 100644
--- a/.github/workflows/release-pipeline.yaml
+++ b/.github/workflows/release-pipeline.yaml
@@ -25,7 +25,7 @@ jobs:
working-directory: Sapling
id: get_version
run: |
- VERSION=1.1.1
+ VERSION=1.1.2
echo "Application version: $VERSION"
echo "::set-output name=version::$VERSION"
diff --git a/Sapling.Engine/BoardState.cs b/Sapling.Engine/BoardState.cs
index 977e6d1..fe1418b 100644
--- a/Sapling.Engine/BoardState.cs
+++ b/Sapling.Engine/BoardState.cs
@@ -4,7 +4,7 @@ namespace Sapling.Engine;
using System.Runtime.InteropServices;
-[StructLayout(LayoutKind.Explicit, Size = 142)] // Explicit layout with size control
+[StructLayout(LayoutKind.Explicit, Size = 144)] // Explicit layout with size control
public unsafe struct BoardStateData
{
// 8-byte fields (grouped together for optimal alignment)
@@ -18,22 +18,23 @@ public unsafe struct BoardStateData
// Grouped bools (using 1 byte each)
[FieldOffset(131)] public bool WhiteToMove; // 1 byte
[FieldOffset(132)] public bool InCheck; // 1 byte
- [FieldOffset(133)] public bool ShouldWhiteMirrored; // 1 byte
- [FieldOffset(134)] public bool ShouldBlackMirrored; // 1 byte
- [FieldOffset(135)] public bool WhiteMirrored; // 1 byte
- [FieldOffset(136)] public bool BlackMirrored; // 1 byte
+ [FieldOffset(133)] public bool WhiteMirrored; // 1 byte
+ [FieldOffset(134)] public bool BlackMirrored; // 1 byte
// 4-byte field (for proper alignment)
// CastleRights (assuming this is a byte-sized enum)
- [FieldOffset(137)] public CastleRights CastleRights; // 1 byte
+ [FieldOffset(135)] public CastleRights CastleRights; // 1 byte
// Smaller fields (grouped together for minimal padding)
- [FieldOffset(138)] public byte WhiteKingSquare; // 1 byte
- [FieldOffset(139)] public byte BlackKingSquare; // 1 byte
- [FieldOffset(140)] public byte EnPassantFile; // 1 byte
- [FieldOffset(141)] public byte PieceCount; // 1 byte
-
+ [FieldOffset(136)] public byte WhiteKingSquare; // 1 byte
+ [FieldOffset(137)] public byte BlackKingSquare; // 1 byte
+ [FieldOffset(138)] public byte EnPassantFile; // 1 byte
+ [FieldOffset(139)] public byte PieceCount; // 1 byte
+ [FieldOffset(140)] public byte WhiteInputBucket; // 1 byte
+ [FieldOffset(141)] public byte BlackInputBucket; // 1 byte
+ [FieldOffset(142)] public bool WhiteNeedsRefresh; // 1 byte
+ [FieldOffset(143)] public bool BlackNeedsRefresh; // 1 byte
public void CloneTo(ref BoardStateData copy)
{
fixed (BoardStateData* sourcePtr = &this)
diff --git a/Sapling.Engine/BoardStateExtensions.cs b/Sapling.Engine/BoardStateExtensions.cs
index 62c5f1c..b87e295 100644
--- a/Sapling.Engine/BoardStateExtensions.cs
+++ b/Sapling.Engine/BoardStateExtensions.cs
@@ -376,24 +376,6 @@ public static void UpdateCastleStatus(this ref BoardStateData board, CastleRight
board.Hash ^= Zobrist.BlackQueenSideCastlingRights;
}
}
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void UpdateMirrorStatus(this ref BoardStateData board,byte piece, bool fromMirroredSide, bool toMirroredSide)
- {
- if (fromMirroredSide == toMirroredSide)
- {
- return;
- }
-
- if (piece == Constants.WhiteKing)
- {
- board.ShouldWhiteMirrored = toMirroredSide;
- }
-
- if (piece == Constants.BlackKing)
- {
- board.ShouldBlackMirrored = toMirroredSide;
- }
- }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe void FinishApply(this ref BoardStateData board, VectorShort* whiteAcc, VectorShort* blackAcc, ulong* hashHistory, uint m,
@@ -404,6 +386,15 @@ public static unsafe void FinishApply(this ref BoardStateData board, VectorShort
var (movedPiece, fromSquare, toSquare, capturedPiece, moveType) = m.Deconstruct();
+ if (movedPiece == Constants.WhiteKing)
+ {
+ board.WhiteNeedsRefresh |= board.WhiteMirrored != toSquare.IsMirroredSide() || board.WhiteInputBucket != NnueEvaluator.GetKingBucket(toSquare);
+ }
+ else if (movedPiece == Constants.BlackKing)
+ {
+ board.BlackNeedsRefresh |= board.BlackMirrored != toSquare.IsMirroredSide() || board.BlackInputBucket != NnueEvaluator.GetKingBucket((byte)(toSquare ^ 0x38));
+ }
+
if (moveType == 0)
{
board.Replace(whiteAcc, blackAcc, movedPiece, fromSquare, toSquare);
@@ -427,8 +418,8 @@ public static unsafe void FinishApply(this ref BoardStateData board, VectorShort
// Castle move
if (toSquare == 62)
{
- board.Replace(whiteAcc, blackAcc, Constants.BlackRook, 63, 61);
- board.Replace(whiteAcc, blackAcc, Constants.BlackKing, fromSquare, toSquare);
+ board.Replace( whiteAcc, blackAcc, Constants.BlackRook, 63, 61);
+ board.Replace( whiteAcc, blackAcc, Constants.BlackKing, fromSquare, toSquare);
board.Hash ^= Zobrist.PiecesArray[Constants.BlackKing * 64 + fromSquare] ^
Zobrist.PiecesArray[Constants.BlackKing * 64 + toSquare] ^
Zobrist.PiecesArray[Constants.BlackRook * 64 + 63] ^
@@ -514,7 +505,6 @@ public static unsafe void FinishApply(this ref BoardStateData board, VectorShort
}
board.UpdateCastleStatus(prevCastle);
- board.UpdateMirrorStatus(movedPiece, fromSquare.IsMirroredSide(), toSquare.IsMirroredSide());
hashHistory[board.TurnCount - 1] = board.Hash;
}
diff --git a/Sapling.Engine/Evaluation/NnueEvaluator.cs b/Sapling.Engine/Evaluation/NnueEvaluator.cs
index fe254b6..b1781bb 100644
--- a/Sapling.Engine/Evaluation/NnueEvaluator.cs
+++ b/Sapling.Engine/Evaluation/NnueEvaluator.cs
@@ -22,6 +22,7 @@ public static unsafe class NnueEvaluator
public const int AccumulatorSize = NnueWeights.Layer1Size / VectorSize;
public const int L1ByteSize = sizeof(short) * NnueWeights.Layer1Size;
+ public const int InputBucketWeightCount = NnueWeights.InputSize * AccumulatorSize;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void SimdCopy(VectorShort* destination, VectorShort* source)
@@ -36,14 +37,14 @@ public static void SimdCopy(VectorShort* destination, VectorShort* source)
public static int Evaluate(this ref BoardStateData board, VectorShort* whiteAcc, VectorShort* blackAcc)
{
- if (board.WhiteMirrored != board.ShouldWhiteMirrored)
+ if (board.WhiteNeedsRefresh)
{
- board.MirrorWhite(whiteAcc);
+ board.RefreshWhite(whiteAcc);
}
- if (board.BlackMirrored != board.ShouldBlackMirrored)
+ if (board.BlackNeedsRefresh)
{
- board.MirrorBlack(blackAcc);
+ board.RefreshBlack(blackAcc);
}
var bucket = (board.PieceCount - 2) / BucketDivisor;
@@ -96,15 +97,29 @@ public static int BlackFeatureIndices(bool mirrored, int piece, byte square)
public static void Deactivate(this ref BoardStateData board, VectorShort* whiteAcc, VectorShort* blackAcc, int piece, int square)
{
var (bIdx, wIdx) = FeatureIndices(board.WhiteMirrored, board.BlackMirrored, piece, square);
- SubtractWeights(whiteAcc, wIdx);
- SubtractWeights(blackAcc, bIdx);
+ if (!board.WhiteNeedsRefresh)
+ {
+ SubtractWeights(whiteAcc, board.WhiteInputBucket, wIdx);
+ }
+
+ if (!board.BlackNeedsRefresh)
+ {
+ SubtractWeights(blackAcc, board.BlackInputBucket, bIdx);
+ }
}
public static void Apply(this ref BoardStateData board, VectorShort* whiteAcc, VectorShort* blackAcc, int piece, int square)
{
var (bIdx, wIdx) = FeatureIndices(board.WhiteMirrored, board.BlackMirrored, piece, square);
- AddWeights(whiteAcc, wIdx);
- AddWeights(blackAcc, bIdx);
+ if (!board.WhiteNeedsRefresh)
+ {
+ AddWeights(whiteAcc, board.WhiteInputBucket, wIdx);
+ }
+
+ if (!board.BlackNeedsRefresh)
+ {
+ AddWeights(blackAcc, board.BlackInputBucket, bIdx);
+ }
}
public static void Replace(this ref BoardStateData board, VectorShort* whiteAcc, VectorShort* blackAcc, int piece, int from, int to)
@@ -112,15 +127,22 @@ public static void Replace(this ref BoardStateData board, VectorShort* whiteAcc,
var (from_bIdx, from_wIdx) = FeatureIndices(board.WhiteMirrored, board.BlackMirrored, piece, from);
var (to_bIdx, to_wIdx) = FeatureIndices(board.WhiteMirrored, board.BlackMirrored, piece, to);
- ReplaceWeights(whiteAcc, to_wIdx, from_wIdx);
- ReplaceWeights(blackAcc, to_bIdx, from_bIdx);
+ if (!board.WhiteNeedsRefresh)
+ {
+ ReplaceWeights(whiteAcc, board.WhiteInputBucket, to_wIdx, from_wIdx);
+ }
+
+ if (!board.BlackNeedsRefresh)
+ {
+ ReplaceWeights(blackAcc, board.BlackInputBucket, to_bIdx, from_bIdx);
+ }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static void ReplaceWeights(VectorShort* accuPtr, int addFeatureIndex, int removeFeatureIndex)
+ private static void ReplaceWeights(VectorShort* accuPtr, int inputBucket, int addFeatureIndex, int removeFeatureIndex)
{
- var addFeatureOffsetPtr = NnueWeights.FeatureWeights + addFeatureIndex * AccumulatorSize;
- var removeFeatureOffsetPtr = NnueWeights.FeatureWeights + removeFeatureIndex * AccumulatorSize;
+ var addFeatureOffsetPtr = NnueWeights.FeatureWeights + inputBucket * InputBucketWeightCount + addFeatureIndex * AccumulatorSize;
+ var removeFeatureOffsetPtr = NnueWeights.FeatureWeights + inputBucket * InputBucketWeightCount + removeFeatureIndex * AccumulatorSize;
for (var i = AccumulatorSize - 1; i >= 0; i--)
{
accuPtr[i] += addFeatureOffsetPtr[i] - removeFeatureOffsetPtr[i];
@@ -128,9 +150,9 @@ private static void ReplaceWeights(VectorShort* accuPtr, int addFeatureIndex, in
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static void SubtractWeights(VectorShort* accuPtr, int inputFeatureIndex)
+ private static void SubtractWeights(VectorShort* accuPtr, int inputBucket, int inputFeatureIndex)
{
- var featurePtr = NnueWeights.FeatureWeights + inputFeatureIndex * AccumulatorSize;
+ var featurePtr = NnueWeights.FeatureWeights + inputBucket * InputBucketWeightCount + inputFeatureIndex * AccumulatorSize;
for (var i = AccumulatorSize - 1; i >= 0; i--)
{
accuPtr[i] -= featurePtr[i];
@@ -138,19 +160,40 @@ private static void SubtractWeights(VectorShort* accuPtr, int inputFeatureIndex)
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static void AddWeights(VectorShort* accuPtr, int inputFeatureIndex)
+ private static void AddWeights(VectorShort* accuPtr, int inputBucket, int inputFeatureIndex)
{
- var featurePtr = NnueWeights.FeatureWeights + inputFeatureIndex * AccumulatorSize;
+ var featurePtr = NnueWeights.FeatureWeights + inputBucket * InputBucketWeightCount + inputFeatureIndex * AccumulatorSize;
for (var i = AccumulatorSize - 1; i >= 0; i--)
{
accuPtr[i] += featurePtr[i];
}
}
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static byte GetKingBucket(byte index)
+ {
+ if (index < 2) // Indices 0-1 -> 0
+ return 0;
+ if (index < 6) // Indices 2-5 -> 1
+ return 1;
+ if (index < 8) // Indices 6-7 -> 0
+ return 0;
+ if (index < 16) // Indices 8-15 -> 2
+ return 2;
+
+ // Indices 16-63 -> 3
+ return 3;
+ }
+
public static void FillAccumulators(this ref BoardStateData board, VectorShort* whiteAcc, VectorShort* blackAcc)
{
- board.WhiteMirrored = board.ShouldWhiteMirrored = board.WhiteKingSquare.IsMirroredSide();
- board.BlackMirrored = board.ShouldBlackMirrored = board.BlackKingSquare.IsMirroredSide();
+ board.WhiteNeedsRefresh = false;
+ board.BlackNeedsRefresh = false;
+ board.WhiteMirrored = board.WhiteKingSquare.IsMirroredSide();
+ board.WhiteInputBucket = GetKingBucket(board.WhiteKingSquare);
+ board.BlackMirrored = board.BlackKingSquare.IsMirroredSide();
+ board.BlackInputBucket = GetKingBucket((byte)(board.BlackKingSquare ^ 0x38));
+
for (var i = AccumulatorSize - 1; i >= 0; i--)
{
whiteAcc[i] = blackAcc[i] = NnueWeights.FeatureBiases[i];
@@ -243,171 +286,178 @@ private static int ForwardCReLU(VectorShort* usAcc, VectorShort* themAcc, int bu
return VectorType.Sum(sum);
}
- public static void MirrorWhite(this ref BoardStateData board, VectorShort* whiteAcc)
+ public static void RefreshWhite(this ref BoardStateData board, VectorShort* whiteAcc)
{
- board.WhiteMirrored = board.ShouldWhiteMirrored;
+ board.WhiteNeedsRefresh = false;
+ board.WhiteMirrored = board.WhiteKingSquare.IsMirroredSide();
+ board.WhiteInputBucket = NnueEvaluator.GetKingBucket(board.WhiteKingSquare);
+
for (var i = 0; i < AccumulatorSize; i++)
{
whiteAcc[i] = NnueWeights.FeatureBiases[i];
}
// Accumulate layer weights
- AddWeights(whiteAcc, WhiteFeatureIndices(board.WhiteMirrored, Constants.WhiteKing, board.WhiteKingSquare));
+ AddWeights(whiteAcc, board.WhiteInputBucket, WhiteFeatureIndices(board.WhiteMirrored, Constants.WhiteKing, board.WhiteKingSquare));
var bitboards = board.Occupancy[Constants.WhitePawn];
while (bitboards != 0)
{
- AddWeights(whiteAcc,
+ AddWeights(whiteAcc, board.WhiteInputBucket,
WhiteFeatureIndices(board.WhiteMirrored, Constants.WhitePawn, bitboards.PopLSB()));
}
bitboards = board.Occupancy[Constants.WhiteKnight];
while (bitboards != 0)
{
- AddWeights(whiteAcc,
+ AddWeights(whiteAcc, board.WhiteInputBucket,
WhiteFeatureIndices(board.WhiteMirrored, Constants.WhiteKnight, bitboards.PopLSB()));
}
bitboards = board.Occupancy[Constants.WhiteBishop];
while (bitboards != 0)
{
- AddWeights(whiteAcc,
+ AddWeights(whiteAcc, board.WhiteInputBucket,
WhiteFeatureIndices(board.WhiteMirrored, Constants.WhiteBishop, bitboards.PopLSB()));
}
bitboards = board.Occupancy[Constants.WhiteRook];
while (bitboards != 0)
{
- AddWeights(whiteAcc,
+ AddWeights(whiteAcc, board.WhiteInputBucket,
WhiteFeatureIndices(board.WhiteMirrored, Constants.WhiteRook, bitboards.PopLSB()));
}
bitboards = board.Occupancy[Constants.WhiteQueen];
while (bitboards != 0)
{
- AddWeights(whiteAcc,
+ AddWeights(whiteAcc, board.WhiteInputBucket,
WhiteFeatureIndices(board.WhiteMirrored, Constants.WhiteQueen, bitboards.PopLSB()));
}
- AddWeights(whiteAcc, WhiteFeatureIndices(board.WhiteMirrored, Constants.BlackKing, board.BlackKingSquare));
+ AddWeights(whiteAcc, board.WhiteInputBucket, WhiteFeatureIndices(board.WhiteMirrored, Constants.BlackKing, board.BlackKingSquare));
bitboards = board.Occupancy[Constants.BlackPawn];
while (bitboards != 0)
{
- AddWeights(whiteAcc,
+ AddWeights(whiteAcc, board.WhiteInputBucket,
WhiteFeatureIndices(board.WhiteMirrored, Constants.BlackPawn, bitboards.PopLSB()));
}
bitboards = board.Occupancy[Constants.BlackKnight];
while (bitboards != 0)
{
- AddWeights(whiteAcc,
+ AddWeights(whiteAcc, board.WhiteInputBucket,
WhiteFeatureIndices(board.WhiteMirrored, Constants.BlackKnight, bitboards.PopLSB()));
}
bitboards = board.Occupancy[Constants.BlackBishop];
while (bitboards != 0)
{
- AddWeights(whiteAcc,
+ AddWeights(whiteAcc, board.WhiteInputBucket,
WhiteFeatureIndices(board.WhiteMirrored, Constants.BlackBishop, bitboards.PopLSB()));
}
bitboards = board.Occupancy[Constants.BlackRook];
while (bitboards != 0)
{
- AddWeights(whiteAcc,
+ AddWeights(whiteAcc, board.WhiteInputBucket,
WhiteFeatureIndices(board.WhiteMirrored, Constants.BlackRook, bitboards.PopLSB()));
}
bitboards = board.Occupancy[Constants.BlackQueen];
while (bitboards != 0)
{
- AddWeights(whiteAcc,
+ AddWeights(whiteAcc, board.WhiteInputBucket,
WhiteFeatureIndices(board.WhiteMirrored, Constants.BlackQueen, bitboards.PopLSB()));
}
}
- public static void MirrorBlack(this ref BoardStateData board, VectorShort* blackAcc)
+ public static void RefreshBlack(this ref BoardStateData board, VectorShort* blackAcc)
{
- board.BlackMirrored = board.ShouldBlackMirrored;
+ board.BlackNeedsRefresh = false;
+ board.BlackMirrored = board.BlackKingSquare.IsMirroredSide();
+ board.BlackInputBucket = NnueEvaluator.GetKingBucket((byte)(board.BlackKingSquare ^ 0x38));
+
+
for (var i = 0; i < AccumulatorSize; i++)
{
blackAcc[i] = NnueWeights.FeatureBiases[i];
}
// Accumulate layer weights
- AddWeights(blackAcc, BlackFeatureIndices(board.BlackMirrored, Constants.WhiteKing, board.WhiteKingSquare));
+ AddWeights(blackAcc, board.BlackInputBucket, BlackFeatureIndices(board.BlackMirrored, Constants.WhiteKing, board.WhiteKingSquare));
var bitboards = board.Occupancy[Constants.WhitePawn];
while (bitboards != 0)
{
- AddWeights(blackAcc,
+ AddWeights(blackAcc, board.BlackInputBucket,
BlackFeatureIndices(board.BlackMirrored, Constants.WhitePawn, bitboards.PopLSB()));
}
bitboards = board.Occupancy[Constants.WhiteKnight];
while (bitboards != 0)
{
- AddWeights(blackAcc,
+ AddWeights(blackAcc, board.BlackInputBucket,
BlackFeatureIndices(board.BlackMirrored, Constants.WhiteKnight, bitboards.PopLSB()));
}
bitboards = board.Occupancy[Constants.WhiteBishop];
while (bitboards != 0)
{
- AddWeights(blackAcc,
+ AddWeights(blackAcc, board.BlackInputBucket,
BlackFeatureIndices(board.BlackMirrored, Constants.WhiteBishop, bitboards.PopLSB()));
}
bitboards = board.Occupancy[Constants.WhiteRook];
while (bitboards != 0)
{
- AddWeights(blackAcc,
+ AddWeights(blackAcc, board.BlackInputBucket,
BlackFeatureIndices(board.BlackMirrored, Constants.WhiteRook, bitboards.PopLSB()));
}
bitboards = board.Occupancy[Constants.WhiteQueen];
while (bitboards != 0)
{
- AddWeights(blackAcc,
+ AddWeights(blackAcc, board.BlackInputBucket,
BlackFeatureIndices(board.BlackMirrored, Constants.WhiteQueen, bitboards.PopLSB()));
}
- AddWeights(blackAcc, BlackFeatureIndices(board.BlackMirrored, Constants.BlackKing, board.BlackKingSquare));
+ AddWeights(blackAcc, board.BlackInputBucket, BlackFeatureIndices(board.BlackMirrored, Constants.BlackKing, board.BlackKingSquare));
bitboards = board.Occupancy[Constants.BlackPawn];
while (bitboards != 0)
{
- AddWeights(blackAcc,
+ AddWeights(blackAcc, board.BlackInputBucket,
BlackFeatureIndices(board.BlackMirrored, Constants.BlackPawn, bitboards.PopLSB()));
}
bitboards = board.Occupancy[Constants.BlackKnight];
while (bitboards != 0)
{
- AddWeights(blackAcc,
+ AddWeights(blackAcc, board.BlackInputBucket,
BlackFeatureIndices(board.BlackMirrored, Constants.BlackKnight, bitboards.PopLSB()));
}
bitboards = board.Occupancy[Constants.BlackBishop];
while (bitboards != 0)
{
- AddWeights(blackAcc,
+ AddWeights(blackAcc, board.BlackInputBucket,
BlackFeatureIndices(board.BlackMirrored, Constants.BlackBishop, bitboards.PopLSB()));
}
bitboards = board.Occupancy[Constants.BlackRook];
while (bitboards != 0)
{
- AddWeights(blackAcc,
+ AddWeights(blackAcc, board.BlackInputBucket,
BlackFeatureIndices(board.BlackMirrored, Constants.BlackRook, bitboards.PopLSB()));
}
bitboards = board.Occupancy[Constants.BlackQueen];
while (bitboards != 0)
{
- AddWeights(blackAcc,
+ AddWeights(blackAcc, board.BlackInputBucket,
BlackFeatureIndices(board.BlackMirrored, Constants.BlackQueen, bitboards.PopLSB()));
}
}
diff --git a/Sapling.Engine/Evaluation/NnueWeights.cs b/Sapling.Engine/Evaluation/NnueWeights.cs
index aa1cefe..8b5feb0 100644
--- a/Sapling.Engine/Evaluation/NnueWeights.cs
+++ b/Sapling.Engine/Evaluation/NnueWeights.cs
@@ -8,8 +8,8 @@ public static class NnueWeights
public const int InputSize = 768;
public const int Layer1Size = 1024;
+ public const short InputBuckets = 4;
public const short OutputBuckets = 8;
-
public static readonly unsafe VectorShort* FeatureWeights;
public static readonly unsafe VectorShort* FeatureBiases;
public static readonly unsafe VectorShort* OutputWeights;
@@ -23,7 +23,7 @@ static unsafe NnueWeights()
using var stream = assembly
.GetManifestResourceStream($"{name}.Resources.sapling.nnue")!;
- var featureWeights = new short[InputSize * Layer1Size];
+ var featureWeights = new short[InputSize * Layer1Size * InputBuckets];
var featureBiases = new short[Layer1Size];
var outputWeights = new short[Layer1Size * 2 * OutputBuckets];
@@ -68,6 +68,9 @@ static unsafe NnueWeights()
OutputBiases[i] = reader.ReadInt16();
}
+ //var result = Encoding.UTF8.GetString(reader.ReadBytes((int)(reader.BaseStream.Length - reader.BaseStream.Position)));
+ // Console.WriteLine(result);
+
// Allocate unmanaged memory
FeatureWeights = AlignedAllocZeroedShort((nuint)featureWeights.Length);
FeatureBiases = AlignedAllocZeroedShort((nuint)featureBiases.Length);
diff --git a/Sapling.Engine/Resources/WeightsHistory/17_(768x4-1024)x2-8.bin b/Sapling.Engine/Resources/WeightsHistory/17_(768x4-1024)x2-8.bin
new file mode 100644
index 0000000..9cb4e7a
Binary files /dev/null and b/Sapling.Engine/Resources/WeightsHistory/17_(768x4-1024)x2-8.bin differ
diff --git a/Sapling.Engine/Resources/WeightsHistory/log.txt b/Sapling.Engine/Resources/WeightsHistory/log.txt
index 2fd2935..cccf5df 100644
--- a/Sapling.Engine/Resources/WeightsHistory/log.txt
+++ b/Sapling.Engine/Resources/WeightsHistory/log.txt
@@ -141,4 +141,12 @@ SuperBatches: 180
Data: 1.5bn positions
WDL: 0.4
LR: CosineDecayLR 0.001 * 0.3 * 0.3 * 0.3
+SuperBatches: 200
+
+----------------------------------
+17_(768x4-1024)x2-8.bin
+----------------------------------
+Data: 1.5bn positions
+WDL: 0.3
+LR: CosineDecayLR 0.001 * 0.3 * 0.3 * 0.3
SuperBatches: 200
\ No newline at end of file
diff --git a/Sapling.Engine/Resources/sapling.nnue b/Sapling.Engine/Resources/sapling.nnue
index 106f96c..9cb4e7a 100644
Binary files a/Sapling.Engine/Resources/sapling.nnue and b/Sapling.Engine/Resources/sapling.nnue differ
diff --git a/Sapling/Sapling.csproj b/Sapling/Sapling.csproj
index 666a01f..f884459 100644
--- a/Sapling/Sapling.csproj
+++ b/Sapling/Sapling.csproj
@@ -7,9 +7,9 @@