<commit_before>﻿namespace AppliedAlgebra.GfAlgorithms.Extensions
{
    using System;
    using System.Linq;
    using GfPolynoms;
    using GfPolynoms.Extensions;

    public static class FieldElementsVectorExtensions
    {
        /// <summary>
        /// Computes the Hamming distance between codewords <paramref name="first"/> and <paramref name="second"/>
        /// </summary>
        public static int ComputeHammingDistance(this FieldElement[] first, FieldElement[] second)
        {
            if(first == null)
                throw new ArgumentNullException(nameof(first));
            if (second == null)
                throw new ArgumentNullException(nameof(second));
            if (first.Length != second.Length)
                throw new InvalidOperationException("Codewords must have the same length");

            var distance = 0;
            for (var i = 0; i < first.Length; i++)
            {
                if(first[i].Field.Equals(second[i].Field) == false)
                    throw new InvalidOperationException("Fields of the codewords must be the same");

                if (first[i].Equals(second[i]) == false)
                    distance++;
            }

            return distance;
        }

        /// <summary>
        /// Adds noise <paramref name="additiveNoise"/> to signal <paramref name="vector"/>
        /// </summary>
        public static FieldElement[] AddNoise(this FieldElement[] vector, FieldElement[] additiveNoise)
        {
            if (vector == null)
                throw new ArgumentNullException(nameof(vector));
            if (additiveNoise == null)
                throw new ArgumentNullException(nameof(additiveNoise));
            if (vector.Length != additiveNoise.Length)
                throw new InvalidOperationException("Codewords must have the same length");

            return vector.Select((x, i) => x + additiveNoise[i]).ToArray();
        }

        private static FieldElement[] PerformFourierTransform(this FieldElement[] vector, bool isDirect)
        {
            if (vector == null)
                throw new ArgumentNullException(nameof(vector));
            if (vector.Length == 0)
                throw new ArgumentNullException($"{nameof(vector)} must not be empty");
            if (vector.Any(x => x == null))
                throw new ArgumentNullException($"{nameof(vector)} components must not be null");

            var field = vector[0].Field;
            if (vector.Any(x => field.Equals(x.Field) == false))
                throw new ArgumentException($"{nameof(vector)} components must belong to the one field");

            FieldElement multiplier;
            FieldElement primitiveRoot;
            FieldElement[] preparedVector;

            if (isDirect)
            {
                var fieldExtension = field.FindExtensionContainingPrimitiveRoot(vector.Length);

                multiplier = fieldExtension.One();
                primitiveRoot = fieldExtension.GetPrimitiveRoot(vector.Length);
                preparedVector = vector.Select(x => x.TransferToSubfield(fieldExtension)).Reverse().ToArray();
            }
            else
            {
                multiplier = field.CreateElement(vector.Length % field.Characteristic).InverseForMultiplication();
                primitiveRoot = field.GetPrimitiveRoot(vector.Length);
                preparedVector = vector.Reverse().ToArray();
            }

            return Enumerable.Range(0, vector.Length)
                .Select(x =>
                        {
                            var argument = FieldElement.Pow(primitiveRoot, isDirect ? x : -x);
                            return multiplier * preparedVector.Aggregate(
                                primitiveRoot.Field.Zero(),
                                (spectrumComponent, component) => component + spectrumComponent * argument
                            );
                        })
                .ToArray();
        }

        /// <summary>
        /// Computes direct Fourier transform for the given signal <paramref name="signal"/>
        /// </summary>
        public static FieldElement[] GetSpectrum(this FieldElement[] signal) =>
            signal.PerformFourierTransform(true);

        /// <summary>
        /// Computes reverse Fourier transform for the given spectrum <paramref name="spectrum"/>
        /// </summary>
        public static FieldElement[] GetSignal(this FieldElement[] spectrum) =>
            spectrum.PerformFourierTransform(false);
    }
}<commit_msg>Fourier transform calculation was reorganized<commit_after>﻿namespace AppliedAlgebra.GfAlgorithms.Extensions
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using GfPolynoms;
    using GfPolynoms.Extensions;
    using GfPolynoms.GaloisFields;

    public static class FieldElementsVectorExtensions
    {
        /// <summary>
        /// Computes the Hamming distance between codewords <paramref name="first"/> and <paramref name="second"/>
        /// </summary>
        public static int ComputeHammingDistance(this FieldElement[] first, FieldElement[] second)
        {
            if(first == null)
                throw new ArgumentNullException(nameof(first));
            if (second == null)
                throw new ArgumentNullException(nameof(second));
            if (first.Length != second.Length)
                throw new InvalidOperationException("Codewords must have the same length");

            var distance = 0;
            for (var i = 0; i < first.Length; i++)
            {
                if(first[i].Field.Equals(second[i].Field) == false)
                    throw new InvalidOperationException("Fields of the codewords must be the same");

                if (first[i].Equals(second[i]) == false)
                    distance++;
            }

            return distance;
        }

        /// <summary>
        /// Adds noise <paramref name="additiveNoise"/> to signal <paramref name="vector"/>
        /// </summary>
        public static FieldElement[] AddNoise(this FieldElement[] vector, FieldElement[] additiveNoise)
        {
            if (vector == null)
                throw new ArgumentNullException(nameof(vector));
            if (additiveNoise == null)
                throw new ArgumentNullException(nameof(additiveNoise));
            if (vector.Length != additiveNoise.Length)
                throw new InvalidOperationException("Codewords must have the same length");

            return vector.Select((x, i) => x + additiveNoise[i]).ToArray();
        }

        /// <summary>
        /// Determines field of the vector <paramref name="vector"/>
        /// </summary>
        /// <param name="vector">Field elements vector</param>
        public static GaloisField GetField(this FieldElement[] vector)
        {
            if (vector == null)
                throw new ArgumentNullException(nameof(vector));
            if (vector.Length == 0)
                throw new ArgumentNullException($"{nameof(vector)} must not be empty");
            if (vector.Any(x => x == null))
                throw new ArgumentNullException($"{nameof(vector)} components must not be null");

            var field = vector[0].Field;
            if (vector.Any(x => field.Equals(x.Field) == false))
                throw new ArgumentException($"{nameof(vector)} components must belong to the one field");

            return field;
        }

        private static FieldElement[] ComputeValues(FieldElement primitiveRoot, IReadOnlyCollection<FieldElement> vector)
        {
            var reversedVector = vector.Reverse().ToArray();
            return Enumerable.Range(0, vector.Count)
                .Select(x =>
                        {
                            var argument = FieldElement.Pow(primitiveRoot, x);
                            return reversedVector.Aggregate(
                                primitiveRoot.Field.Zero(),
                                (spectrumComponent, component) => component + spectrumComponent * argument
                            );
                        })
                .ToArray();
        }

        /// <summary>
        /// Computes direct Fourier transform for the given signal <paramref name="signal"/>
        /// </summary>
        public static FieldElement[] GetSpectrum(this FieldElement[] signal)
        {
            var field = signal.GetField();
            var fieldExtension = field.FindExtensionContainingPrimitiveRoot(signal.Length);

            var primitiveRoot = fieldExtension.GetPrimitiveRoot(signal.Length);
            var preparedSignal = signal.Select(x => x.TransferToSubfield(fieldExtension)).ToArray();
            return ComputeValues(primitiveRoot, preparedSignal);
        }

        /// <summary>
        /// Computes reverse Fourier transform for the given spectrum <paramref name="spectrum"/>
        /// </summary>
        public static FieldElement[] GetSignal(this FieldElement[] spectrum)
        {
            var field = spectrum.GetField();

            var primitiveRoot = field.GetPrimitiveRoot(spectrum.Length).InverseForMultiplication();
            var multiplier = field.CreateElement(spectrum.Length % field.Characteristic).InverseForMultiplication();
            return ComputeValues(primitiveRoot, spectrum)
                .Select(value => multiplier * value)
                .ToArray();
        }
    }
}
{'fraction_non_alphanumeric': 0.10254777070063695, 'fraction_numerical': 0.0010615711252653928, 'mean_word_length': 1.9185254027261462, 'pattern_counts': {'":': 0, '<': 39, '<?xml version=': 0, '>': 52, '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': '5561799', 'n_tokens_mistral': 2276, 'n_tokens_neox': 2160, 'n_words': 569}