<commit_before>﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Numerics;
using System.Threading;
using System.Threading.Tasks;
using Buddhabrot.Core;
using Buddhabrot.IterationKernels;
using log4net;

namespace Buddhabrot.Points
{
    sealed class VectorPointFinder : PointFinder
    {
        private static readonly ILog Log = LogManager.GetLogger(nameof(VectorPointFinder));

        private const int TrialSize = 5;
        private int _trialNumber = 1;
        private readonly double[] _trialSpeeds = new double[TrialSize];

        enum Mutation
        {
            Smaller,
            Larger
        }

        private int _batchSize = 512;
        private double _lastSpeed = 0;
        private Mutation _lastMutation = Mutation.Larger;
        private readonly IntRange _batchRange = new IntRange(8, 2048, stepSize: 8, maxIsExclusive: false);

        private int VectorCapacity => Vector<float>.Count;

        public VectorPointFinder(
            RandomPointGenerator numberGenerator,
            IntRange iterationRange,
            PointWriter writer,
            PointFinderStatistics statistics) :
            base(numberGenerator, iterationRange, writer, statistics)
        {
        }

        protected override void IteratePointBatch(CancellationToken token)
        {
            var timer = Stopwatch.StartNew();
            var points = NumberGenerator.GetPoints(_batchSize);

            Parallel.ForEach(
                VectorBatch(points),
                (batch, loopState) =>
                {
                    if (token.IsCancellationRequested || loopState.ShouldExitCurrentIteration)
                    {
                        loopState.Stop();
                        return;
                    }

                    var realBatch = new float[VectorCapacity];
                    var imagBatch = new float[VectorCapacity];

                    for (int i = 0; i < VectorCapacity; i++)
                    {
                        realBatch[i] = batch[i].Real;
                        imagBatch[i] = batch[i].Imag;
                    }

                    var cReal = new Vector<float>(realBatch);
                    var cImag = new Vector<float>(imagBatch);

                    var vIterations = VectorKernel.IteratePoints(cReal, cImag, IterationRange.Max);

                    for (int i = 0; i < VectorCapacity; i++)
                    {
                        if (IterationRange.IsInside(vIterations[i]))
                        {
                            PointWriter.Save(batch[i]);
                        }
                    }
                });

            timer.Stop();

            Statistics.AddPointCount(_batchSize);

            var pointsPerSecond = _batchSize / timer.Elapsed.TotalSeconds;
            //Log.Info($"Processed {pointsPerSecond:N1} pts/s.");

            _trialSpeeds[_trialNumber - 1] = pointsPerSecond;

            if (_trialNumber < TrialSize)
            {
                _trialNumber++;
            }
            else
            {
                var trialAverage = _trialSpeeds.Average();
                var faster = trialAverage > _lastSpeed;

                Log.Info($"Trial average: {trialAverage:N1} pts/s, previously {_lastSpeed:N1} pts/s.");

                var newMutation = _lastMutation;

                if (!faster)
                {
                    newMutation = _lastMutation == Mutation.Larger ? Mutation.Smaller : Mutation.Larger;
                }

                _batchSize =
                    newMutation == Mutation.Larger
                        ? Math.Min(_batchRange.Max, _batchSize + _batchRange.StepSize)
                        : Math.Max(_batchRange.Min, _batchSize - _batchRange.StepSize);

                _lastMutation = newMutation;
                _lastSpeed = trialAverage;
                _trialNumber = 1;

                Log.Info($"Making batch {newMutation} to {_batchSize}");
            }
        }

        private IEnumerable<FComplex[]> VectorBatch(IEnumerable<FComplex> pointSequence)
        {
            int count = 0;
            var batch = new FComplex[VectorCapacity];
            foreach (var complex in pointSequence)<commit_msg>Removed dynamic batch size from VectorPointFinder<commit_after>﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Numerics;
using System.Threading;
using System.Threading.Tasks;
using Buddhabrot.Core;
using Buddhabrot.IterationKernels;
using log4net;

namespace Buddhabrot.Points
{
    sealed class VectorPointFinder : PointFinder
    {
        private static readonly ILog Log = LogManager.GetLogger(nameof(VectorPointFinder));

        private const int BatchSize = 512;

        private int VectorCapacity => Vector<float>.Count;

        public VectorPointFinder(
            RandomPointGenerator numberGenerator,
            IntRange iterationRange,
            PointWriter writer,
            PointFinderStatistics statistics) :
            base(numberGenerator, iterationRange, writer, statistics)
        {
        }

        protected override void IteratePointBatch(CancellationToken token)
        {
            var points = NumberGenerator.GetPoints(BatchSize);

            Parallel.ForEach(
                VectorBatch(points),
                (batch, loopState) =>
                {
                    if (token.IsCancellationRequested || loopState.ShouldExitCurrentIteration)
                    {
                        loopState.Stop();
                        return;
                    }

                    var realBatch = new float[VectorCapacity];
                    var imagBatch = new float[VectorCapacity];

                    for (int i = 0; i < VectorCapacity; i++)
                    {
                        realBatch[i] = batch[i].Real;
                        imagBatch[i] = batch[i].Imag;
                    }

                    var cReal = new Vector<float>(realBatch);
                    var cImag = new Vector<float>(imagBatch);

                    var vIterations = VectorKernel.IteratePoints(cReal, cImag, IterationRange.Max);

                    for (int i = 0; i < VectorCapacity; i++)
                    {
                        if (IterationRange.IsInside(vIterations[i]))
                        {
                            PointWriter.Save(batch[i]);
                        }
                    }
                });

            Statistics.AddPointCount(BatchSize);
        }

        private IEnumerable<FComplex[]> VectorBatch(IEnumerable<FComplex> pointSequence)
        {
            int count = 0;
            var batch = new FComplex[VectorCapacity];
            foreach (var complex in pointSequence)
{'fraction_non_alphanumeric': 0.07821723730814639, 'fraction_numerical': 0.004132231404958678, 'mean_word_length': 1.5515813253012047, 'pattern_counts': {'":': 0, '<': 18, '<?xml version=': 0, '>': 18, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2000375', 'n_tokens_mistral': 1728, 'n_tokens_neox': 1598, 'n_words': 366}