diff --git a/EvenPerfectBitScanner.ResultsParser/Program.cs b/EvenPerfectBitScanner.ResultsParser/Program.cs index fcdff98..3a388d5 100644 --- a/EvenPerfectBitScanner.ResultsParser/Program.cs +++ b/EvenPerfectBitScanner.ResultsParser/Program.cs @@ -19,149 +19,153 @@ internal static class Program "/help" }; - private const string DefaultHeader = "p,searchedMersenne,detailedCheck,isPerfect"; + private const string DefaultHeader = "p,searchedMersenne,detailedCheck,passedAllTests"; - private static int Main(string[] args) - { - if (args.Length == 0) - { - PrintHelp(); - return 1; - } + private static int Main(string[] args) + { + if (args.Length == 0) + { + PrintHelp(); + return 1; + } - if (args.Length == 1 && IsHelpOption(args[0])) - { - PrintHelp(); - return 0; - } + if (args.Length == 1 && IsHelpOption(args[0])) + { + PrintHelp(); + return 0; + } - string inputPath = args[0]; - if (IsHelpOption(inputPath)) - { - PrintHelp(); - return 0; - } + string inputPath = args[0]; + if (IsHelpOption(inputPath)) + { + PrintHelp(); + return 0; + } - if (!File.Exists(inputPath)) - { - Console.Error.WriteLine($"Input file '{inputPath}' was not found."); - return 1; - } + if (!File.Exists(inputPath)) + { + Console.Error.WriteLine($"Input file '{inputPath}' was not found."); + return 1; + } - if (!TryParseRangeArguments(args.AsSpan(1), out ulong pMin, out ulong pMax)) - { - return 1; - } + if (!TryParseRangeArguments(args.AsSpan(1), out ulong pMin, out ulong pMax)) + { + return 1; + } - if (pMin > pMax) - { - Console.Error.WriteLine("The --p-min value cannot be greater than --p-max."); - return 1; - } + if (pMin > pMax) + { + Console.Error.WriteLine("The --p-min value cannot be greater than --p-max."); + return 1; + } - try - { - ProcessFile(inputPath, pMin, pMax); - return 0; - } - catch (Exception exception) - { - Console.Error.WriteLine($"Processing failed: {exception.Message}"); + try + { + ProcessFile(inputPath, pMin, pMax); + return 0; + } + catch (Exception exception) + { + Console.Error.WriteLine($"Processing failed: {exception.Message}"); return 1; } } private static bool IsHelpOption(string value) => HelpOptions.Contains(value); - private static bool TryParseRangeArguments(ReadOnlySpan arguments, out ulong pMin, out ulong pMax) - { - pMin = 0UL; - pMax = ulong.MaxValue; - if (arguments.Length == 0) - { - return true; - } + private static bool TryParseRangeArguments(ReadOnlySpan arguments, out ulong pMin, out ulong pMax) + { + pMin = 0UL; + pMax = ulong.MaxValue; + if (arguments.Length == 0) + { + return true; + } - if ((arguments.Length & 1) == 1) - { - Console.Error.WriteLine("Each range option must be followed by a numeric value."); - PrintHelp(); - return false; - } + if ((arguments.Length & 1) == 1) + { + Console.Error.WriteLine("Each range option must be followed by a numeric value."); + PrintHelp(); + return false; + } - for (int i = 0; i < arguments.Length; i += 2) - { - string option = arguments[i]; - string value = arguments[i + 1]; + int index; + string option, optionAndValue, value; + for (int i = 0; i < arguments.Length; i += 2) + { + optionAndValue = arguments[i]; + index = optionAndValue.IndexOf('='); + option = optionAndValue[..index]; + value = optionAndValue[(index + 1)..]; - try - { - switch (option) - { - case "--p-min": - pMin = ParseRangeValue(option, value); - break; - case "--p-max": - pMax = ParseRangeValue(option, value); - break; - default: - Console.Error.WriteLine($"Unsupported option '{option}'."); - PrintHelp(); - return false; - } - } - catch (FormatException exception) - { - Console.Error.WriteLine(exception.Message); - PrintHelp(); - return false; - } - } + try + { + switch (option) + { + case "--p-min": + pMin = ParseRangeValue(option, value); + break; + case "--p-max": + pMax = ParseRangeValue(option, value); + break; + default: + Console.Error.WriteLine($"Unsupported option '{option}'."); + PrintHelp(); + return false; + } + } + catch (FormatException exception) + { + Console.Error.WriteLine(exception.Message); + PrintHelp(); + return false; + } + } - return true; - } + return true; + } - private static ulong ParseRangeValue(string option, string value) - { - if (!ulong.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out ulong parsed)) - { - throw new FormatException($"Value '{value}' for option '{option}' is not a valid non-negative integer."); - } + private static ulong ParseRangeValue(string option, string value) + { + if (!ulong.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out ulong parsed)) + { + throw new FormatException($"Value '{value}' for option '{option}' is not a valid non-negative integer."); + } - return parsed; - } + return parsed; + } - private static void PrintHelp() - { - Console.WriteLine("EvenPerfectBitScanner.ResultsParser"); - Console.WriteLine("Parses CSV results produced by the candidate scanner."); - Console.WriteLine(); - Console.WriteLine("Usage:"); - Console.WriteLine(" EvenPerfectBitScanner.ResultsParser [--p-min ] [--p-max ]"); - Console.WriteLine(); - Console.WriteLine("The program accepts the following help switches:"); - Console.WriteLine(" --?, -?, /?, -help, --help, --h, -h, /h, /help"); - Console.WriteLine(); - Console.WriteLine("Optional range arguments allow filtering primes by exponent:"); - Console.WriteLine(" --p-min - include entries with p >= value"); - Console.WriteLine(" --p-max - include entries with p <= value"); - Console.WriteLine(); - Console.WriteLine("Outputs prime results into four files placed next to the source file:"); - Console.WriteLine(" raw-primes- - prime entries in the original order"); - Console.WriteLine(" sorted-primes- - prime entries sorted by p"); - Console.WriteLine(" sorted-primes-passed- - sorted prime entries with isPerfect = true"); - Console.WriteLine(" sorted-primes-rejected- - sorted prime entries with isPerfect = false"); + private static void PrintHelp() + { + Console.WriteLine("EvenPerfectBitScanner.ResultsParser"); + Console.WriteLine("Parses CSV results produced by the candidate scanner."); + Console.WriteLine(); + Console.WriteLine("Usage:"); + Console.WriteLine(" EvenPerfectBitScanner.ResultsParser [--p-min ] [--p-max ]"); + Console.WriteLine(); + Console.WriteLine("The program accepts the following help switches:"); + Console.WriteLine(" --?, -?, /?, -help, --help, --h, -h, /h, /help"); + Console.WriteLine(); + Console.WriteLine("Optional range arguments allow filtering primes by exponent:"); + Console.WriteLine(" --p-min - include entries with p >= value"); + Console.WriteLine(" --p-max - include entries with p <= value"); + Console.WriteLine(); + Console.WriteLine("Outputs prime results into four files placed next to the source file:"); + Console.WriteLine(" raw-primes- - prime entries in the original order"); + Console.WriteLine(" sorted-primes- - prime entries sorted by p"); + Console.WriteLine(" sorted-primes-passed- - sorted prime entries with passedAllTests = true"); + Console.WriteLine(" sorted-primes-rejected- - sorted prime entries with passedAllTests = false"); Console.WriteLine(); Console.WriteLine("Example:"); - Console.WriteLine(" EvenPerfectBitScanner.ResultsParser results.csv --p-min 89 --p-max 107"); - } + Console.WriteLine(" EvenPerfectBitScanner.ResultsParser results.csv --p-min 89 --p-max 107"); + } - private static void ProcessFile(string inputPath, ulong pMin, ulong pMax) - { - using IEnumerator enumerator = File.ReadLines(inputPath).GetEnumerator(); - if (!enumerator.MoveNext()) - { - Console.WriteLine("Input file did not contain any data. Created empty outputs using the default header."); + private static void ProcessFile(string inputPath, ulong pMin, ulong pMax) + { + using IEnumerator enumerator = File.ReadLines(inputPath).GetEnumerator(); + if (!enumerator.MoveNext()) + { + Console.WriteLine("Input file did not contain any data. Created empty outputs using the default header."); string fallbackHeader = DefaultHeader; string rawFallbackPath = BuildOutputPath(inputPath, "raw-primes-"); WriteCsv(rawFallbackPath, fallbackHeader, Array.Empty()); @@ -182,25 +186,25 @@ internal static class Program List pendingResults = new(); List primeResults = new(); int consoleProgress = 0; - while (enumerator.MoveNext()) - { - string currentLine = enumerator.Current; - if (string.IsNullOrWhiteSpace(currentLine)) - { - continue; - } + while (enumerator.MoveNext()) + { + string currentLine = enumerator.Current; + if (string.IsNullOrWhiteSpace(currentLine)) + { + continue; + } - CandidateResult result = ParseLine(currentLine); - if (result.P < pMin || result.P > pMax) - { - continue; - } + CandidateResult result = ParseLine(currentLine); + if (result.P < pMin || result.P > pMax) + { + continue; + } - InsertPendingResult(pendingResults, result); - DrainPrimeMatches(pendingResults, primeResults, ref currentPrime, primeEnumerator, false); - if (++consoleProgress == 10_000) - { - Console.WriteLine($"Processed {result.P}"); + InsertPendingResult(pendingResults, result); + DrainPrimeMatches(pendingResults, primeResults, ref currentPrime, primeEnumerator, false); + if (++consoleProgress == 10_000) + { + Console.WriteLine($"Processed {result.P}"); consoleProgress = 0; } } @@ -219,15 +223,17 @@ internal static class Program } List sortedResults = [.. primeResults]; + Console.WriteLine("Sorting candidates..."); BubbleSort(sortedResults); - List passedResults = []; - List rejectedResults = []; + Console.WriteLine("Splitting results..."); + List passedResults = new(sortedResults.Count); + List rejectedResults = new(sortedResults.Count); for (int i = 0; i < sortedResults.Count; i++) { CandidateResult candidate = sortedResults[i]; - if (candidate.IsPerfect) + if (candidate.PassedAllTests) { passedResults.Add(candidate); } @@ -237,6 +243,7 @@ internal static class Program } } + Console.WriteLine("Saving files..."); string sortedOutputPath = BuildOutputPath(inputPath, "sorted-primes-"); string passedOutputPath = BuildOutputPath(inputPath, "sorted-primes-passed-"); string rejectedOutputPath = BuildOutputPath(inputPath, "sorted-primes-rejected-"); @@ -276,10 +283,10 @@ internal static class Program } ReadOnlySpan pSpan = span[..firstCommaIndex]; - ReadOnlySpan isPerfectSpan = span[(lastCommaIndex + 1)..]; + ReadOnlySpan passedAllTestsSpan = span[(lastCommaIndex + 1)..]; ulong p = ulong.Parse(pSpan, NumberStyles.Integer, CultureInfo.InvariantCulture); - bool isPerfect = bool.Parse(isPerfectSpan); - return new CandidateResult(p, isPerfect, trimmedLine); + bool passedAllTests = bool.Parse(passedAllTestsSpan); + return new CandidateResult(p, passedAllTests, trimmedLine); } private static string BuildOutputPath(string inputPath, string prefix) @@ -475,13 +482,13 @@ internal static class Program return low; } - private readonly record struct CandidateResult(ulong P, bool IsPerfect, string Csv) + private readonly record struct CandidateResult(ulong P, bool PassedAllTests, string Csv) { public string ToCsv() => Csv; public readonly string Csv = Csv; public readonly ulong P = P; - public readonly bool IsPerfect = IsPerfect; + public readonly bool PassedAllTests = PassedAllTests; } } diff --git a/EvenPerfectBitScanner/Program.cs b/EvenPerfectBitScanner/Program.cs index 64bb07e..36192e9 100644 --- a/EvenPerfectBitScanner/Program.cs +++ b/EvenPerfectBitScanner/Program.cs @@ -476,7 +476,7 @@ internal static class Program ulong remainder = currentP % 6UL; if (currentP == InitialP && string.IsNullOrEmpty(filterFile)) { - // bool isPerfect = IsEvenPerfectCandidate(InitialP, out bool searchedMersenne, out bool detailedCheck); + // bool passedAllTests = IsEvenPerfectCandidate(InitialP, out bool searchedMersenne, out bool detailedCheck); // Skip the already processed range below 138 million while (currentP < 138_000_000UL && !Volatile.Read(ref _limitReached)) { @@ -527,9 +527,9 @@ internal static class Program if (File.Exists(ResultsFileName)) { Console.WriteLine("Processing previous results..."); - LoadResultsFile(ResultsFileName, (p, detailedCheck, isPerfect) => + LoadResultsFile(ResultsFileName, (p, detailedCheck, passedAllTests) => { - if (detailedCheck && isPerfect) + if (detailedCheck && passedAllTests) { _primeCount++; } @@ -546,9 +546,9 @@ internal static class Program if (useFilter) { Console.WriteLine("Loading filter..."); - LoadResultsFile(filterFile, (p, detailedCheck, isPerfect) => + LoadResultsFile(filterFile, (p, detailedCheck, passedAllTests) => { - if (isPerfect) + if (passedAllTests) { Console.WriteLine($"Adding {p}"); filter.Add(p); @@ -597,7 +597,7 @@ internal static class Program { int count, j; ulong p; - bool isPerfect, searchedMersenne, detailedCheck; + bool passedAllTests, searchedMersenne, detailedCheck; ulong[] buffer = new ulong[blockSize]; while (!Volatile.Read(ref _limitReached)) { @@ -612,8 +612,8 @@ internal static class Program for (j = 0; j < count && !Volatile.Read(ref _limitReached); j++) { p = buffer[j]; - isPerfect = IsEvenPerfectCandidate(p, divisorCyclesSearchLimit, out searchedMersenne, out detailedCheck); - PrintResult(p, searchedMersenne, detailedCheck, isPerfect); + passedAllTests = IsEvenPerfectCandidate(p, divisorCyclesSearchLimit, out searchedMersenne, out detailedCheck); + PrintResult(p, searchedMersenne, detailedCheck, passedAllTests); } } else @@ -630,8 +630,8 @@ internal static class Program Console.WriteLine($"Testing {p}"); } - isPerfect = IsEvenPerfectCandidate(p, divisorCyclesSearchLimit, out searchedMersenne, out detailedCheck); - PrintResult(p, searchedMersenne, detailedCheck, isPerfect); + passedAllTests = IsEvenPerfectCandidate(p, divisorCyclesSearchLimit, out searchedMersenne, out detailedCheck); + PrintResult(p, searchedMersenne, detailedCheck, passedAllTests); if (p == maxP) { Volatile.Write(ref _limitReached, true); @@ -690,11 +690,11 @@ internal static class Program } ReadOnlySpan detailedSpan = span[..third]; - ReadOnlySpan perfectSpan = span[(third + 1)..]; + ReadOnlySpan passedAllTestsSpan = span[(third + 1)..]; - if (bool.TryParse(detailedSpan, out bool detailed) && bool.TryParse(perfectSpan, out bool isPerfect)) + if (bool.TryParse(detailedSpan, out bool detailed) && bool.TryParse(passedAllTestsSpan, out bool passedAllTests)) { - lineProcessorAction(p, detailed, isPerfect); + lineProcessorAction(p, detailed, passedAllTests); } } } @@ -790,9 +790,9 @@ internal static class Program } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void PrintResult(ulong currentP, bool searchedMersenne, bool detailedCheck, bool isPerfect) + private static void PrintResult(ulong currentP, bool searchedMersenne, bool detailedCheck, bool passedAllTests) { - if (isPerfect) + if (passedAllTests) { int newCount = Interlocked.Increment(ref _primeCount); if (newCount >= 2) @@ -813,7 +813,7 @@ internal static class Program .Append(currentP).Append(',') .Append(searchedMersenne).Append(',') .Append(detailedCheck).Append(',') - .Append(isPerfect).Append('\n'); + .Append(passedAllTests).Append('\n'); lock (Sync) {