private HalfKpParameters ReadHalfKpParameters(BinaryReader reader, NnueArchitecture architecture)
        {
            var featureTransformerHash = reader.ReadUInt32();

            if (featureTransformerHash != ExpectedFeatureTransformerHash)
            {
                throw new NnueException($"Invalid feature transformer hash, expected {ExpectedFeatureTransformerHash}, read {featureTransformerHash}");
            }

            var parameters = new HalfKpParameters();

            parameters.FeatureTransformer = ReadFeatureTransformerParameters(reader, 41024, 256);

            var networkHash = reader.ReadUInt32();

            if (networkHash != ExpectedNetworkHash)
            {
                throw new NnueException($"Invalid network hash, expected {ExpectedNetworkHash}, read {networkHash}");
            }

            parameters.Hidden1 = ReadHiddenParameters(reader, 512, 32, architecture);
            parameters.Hidden2 = ReadHiddenParameters(reader, 32, 32, architecture);
            parameters.Output  = ReadOutputParameters(reader, 32, 1);

            return(parameters);
        }
        private uint GetWeightIndex(uint r, uint c, uint dims, NnueArchitecture architecture)
        {
            if (architecture == NnueArchitecture.Avx2)
            {
                if (dims > 32)
                {
                    uint b = c & 0x18;
                    b = (b << 1) | (b >> 1);
                    c = (c & ~0x18U) | (b & 0x18);
                }
            }

            return(c * 32 + r);
        }
        public NnueManagedClient(HalfKpParameters parameters)
        {
            NnueArchitecture architecture;

            if (Avx2.IsSupported)
            {
                architecture    = NnueArchitecture.Avx2;
                _implementation = new NnueImplAvx2(parameters);
            }
            else
            {
                architecture    = NnueArchitecture.Fallback;
                _implementation = new NnueImplFallback(parameters);
            }
            Architecture = architecture;
        }
        private NnueParameters ReadHiddenParameters(BinaryReader reader, uint inputDimensions, uint outputDimensions, NnueArchitecture architecture)
        {
            var parameters = new NnueParameters();

            parameters.Biases  = new int[outputDimensions];
            parameters.Weights = new sbyte[outputDimensions * inputDimensions];

            for (var i = 0; i < parameters.Biases.Length; i++)
            {
                parameters.Biases[i] = reader.ReadInt32();
            }

            if (architecture == NnueArchitecture.Avx2)
            {
                permute_biases(parameters.Biases);
            }

            for (uint i = 0; i < outputDimensions; i++)
            {
                for (uint j = 0; j < inputDimensions; j++)
                {
                    var index = GetWeightIndex(i, j, inputDimensions, architecture);
                    parameters.Weights[index] = reader.ReadSByte();
                }
            }

            return(parameters);
        }