BuildDivisorTransitions application added.

This commit is contained in:
mlemanczyk committed 2025-12-15 07:30:29 +01:00
1 parent 97fd041ec0
commit 046cfe7d26
12 files changed
+979 -4

No files matched your search

+3
View File
@@ -8,6 +8,9 @@ EvenPerfectBitScanner.ResultsParser/bin/*
EvenPerfectBitScanner.ResultsParser/obj/*
EvenPerfectBitScanner.Tests/bin/*
EvenPerfectBitScanner.Tests/obj/*
BuildDivisorTransitions/bin/*
BuildDivisorTransitions/obj/*
PerfectNumbers.Core.Tests/bin/*
PerfectNumbers.Core.Tests/obj/*
.DS_Store
.vs/*
+30 -2
View File
@@ -8,7 +8,8 @@
"options": [
"EvenPerfectBitScanner",
"EvenPerfectBitScanner.ResultsParser",
"EvenPerfectBitScanner.Benchmarks"
"EvenPerfectBitScanner.Benchmarks",
"BuildDivisorTransitions"
],
"default": "EvenPerfectBitScanner"
}
@@ -68,6 +69,33 @@
"internalConsoleOptions": "neverOpen",
"justMyCode": false
},
{
"name": "Run BuildDivisorTransitions",
"type": "coreclr",
"request": "launch",
"noDebug": true,
"preLaunchTask": "Build BuildDivisorTransitions Release",
"program": "${workspaceFolder}/BuildDivisorTransitions/bin/Release/net8.0/BuildDivisorTransitions.dll",
"args": [],
"cwd": "${workspaceFolder}",
"stopAtEntry": false,
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"justMyCode": false
},
{
"name": "Debug BuildDivisorTransitions",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "Build BuildDivisorTransitions Debug",
"program": "${workspaceFolder}/BuildDivisorTransitions/bin/Debug/net8.0/BuildDivisorTransitions.dll",
"args": [],
"cwd": "${workspaceFolder}",
"stopAtEntry": false,
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"justMyCode": false
},
{
"name": "Run EvenPerfectBitScanner.ResultsParser",
"type": "coreclr",
@@ -136,4 +164,4 @@
"justMyCode": false
}
]
}
}
+46 -1
View File
@@ -94,6 +94,36 @@
"group": "build",
"problemMatcher": "$msCompile"
},
{
"label": "Build BuildDivisorTransitions Debug",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/BuildDivisorTransitions/BuildDivisorTransitions.csproj",
"--configuration",
"Debug",
"--framework",
"net8.0"
],
"group": "build",
"problemMatcher": "$msCompile"
},
{
"label": "Build BuildDivisorTransitions Release",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/BuildDivisorTransitions/BuildDivisorTransitions.csproj",
"--configuration",
"Release",
"--framework",
"net8.0"
],
"group": "build",
"problemMatcher": "$msCompile"
},
{
"label": "Run EvenPerfectBitScanner",
"type": "process",
@@ -124,6 +154,21 @@
],
"problemMatcher": []
},
{
"label": "Run BuildDivisorTransitions",
"type": "process",
"command": "dotnet",
"args": [
"run",
"--project",
"${workspaceFolder}/BuildDivisorTransitions/BuildDivisorTransitions.csproj",
"--configuration",
"Release",
"--framework",
"net8.0"
],
"problemMatcher": []
},
{
"label": "Run Release (no debug)",
"type": "process",
@@ -183,4 +228,4 @@
"problemMatcher": []
}
]
}
}
@@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
+211
View File
@@ -0,0 +1,211 @@
using System.Globalization;
using System.Numerics;
using System.Text;
namespace BuildDivisorTransitions;
internal static class Program
{
private const string OutputFileName = "NextKForecastTraning.csv";
private static int Main(string[] args)
{
if (args.Length != 2)
{
PrintUsage();
return 1;
}
string candidatesPath = args[0];
string divisorsPath = args[1];
if (!File.Exists(candidatesPath))
{
Console.Error.WriteLine($"Candidates file not found: {candidatesPath}");
return 1;
}
if (!File.Exists(divisorsPath))
{
Console.Error.WriteLine($"Divisors file not found: {divisorsPath}");
return 1;
}
List<long> candidatePs = LoadCandidates(candidatesPath);
Dictionary<long, BigInteger> divisors = LoadDivisors(divisorsPath);
List<Transition> transitions = BuildTransitions(candidatePs, divisors);
WriteOutput(transitions);
Console.WriteLine($"Saved {transitions.Count} transitions to {OutputFileName}.");
return 0;
}
private static void PrintUsage()
{
Console.WriteLine("Usage: BuildDivisorTransitions <candidatesCsv> <divisorsCsv>");
Console.WriteLine(" candidatesCsv: CSV with columns p,searchedMersenne,detailedCheck,passedAllTests");
Console.WriteLine(" divisorsCsv: CSV with columns p,divisor");
}
private static List<long> LoadCandidates(string path)
{
var result = new List<long>();
var seen = new HashSet<long>();
using var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
using var reader = new StreamReader(stream, Encoding.UTF8, detectEncodingFromByteOrderMarks: true);
while (!reader.EndOfStream)
{
string? line = reader.ReadLine();
if (string.IsNullOrWhiteSpace(line))
{
continue;
}
string trimmedLine = line.Trim();
if (trimmedLine.StartsWith("p", StringComparison.OrdinalIgnoreCase))
{
continue;
}
string[] parts = trimmedLine.Split(',', StringSplitOptions.TrimEntries);
if (parts.Length == 0)
{
continue;
}
if (!long.TryParse(parts[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out long p))
{
throw new FormatException($"Invalid p value '{parts[0]}' in {path}.");
}
if (seen.Add(p))
{
result.Add(p);
}
}
return result;
}
private static Dictionary<long, BigInteger> LoadDivisors(string path)
{
var result = new Dictionary<long, BigInteger>();
using var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
using var reader = new StreamReader(stream, Encoding.UTF8, detectEncodingFromByteOrderMarks: true);
while (!reader.EndOfStream)
{
string? line = reader.ReadLine();
if (string.IsNullOrWhiteSpace(line))
{
continue;
}
string trimmedLine = line.Trim();
if (trimmedLine.StartsWith("p", StringComparison.OrdinalIgnoreCase))
{
continue;
}
string[] parts = trimmedLine.Split(',', StringSplitOptions.TrimEntries);
if (parts.Length < 2)
{
throw new FormatException($"Line '{line}' in {path} does not contain both p and divisor columns.");
}
if (!long.TryParse(parts[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out long p))
{
throw new FormatException($"Invalid p value '{parts[0]}' in {path}.");
}
if (!BigInteger.TryParse(parts[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out BigInteger divisor))
{
throw new FormatException($"Invalid divisor value '{parts[1]}' for p={p} in {path}.");
}
result[p] = divisor;
}
return result;
}
private static List<Transition> BuildTransitions(IReadOnlyList<long> candidatePs, IReadOnlyDictionary<long, BigInteger> divisors)
{
var transitions = new List<Transition>();
for (int i = 0; i < candidatePs.Count - 1; i++)
{
long currentP = candidatePs[i];
long nextP = candidatePs[i + 1];
if (!divisors.TryGetValue(currentP, out BigInteger currentDivisor))
{
continue;
}
if (!divisors.TryGetValue(nextP, out BigInteger nextDivisor))
{
continue;
}
BigInteger currentK = CalculateK(currentP, currentDivisor);
BigInteger nextK = CalculateK(nextP, nextDivisor);
bool isNextKHigher = nextK > currentK;
transitions.Add(new Transition(currentP, currentDivisor, LastDigit(currentP), currentK, LastMersenneDigit(currentP), isNextKHigher));
}
return transitions;
}
private static BigInteger CalculateK(long p, BigInteger divisor)
{
BigInteger numerator = divisor - BigInteger.One;
BigInteger denominator = new BigInteger(p) << 1;
if (denominator <= BigInteger.Zero)
{
throw new InvalidOperationException($"Computed 2p is not positive for p={p}.");
}
BigInteger remainder = numerator % denominator;
if (remainder != BigInteger.Zero)
{
throw new InvalidOperationException($"Divisor {divisor} is not congruent to 1 mod 2p for p={p}.");
}
BigInteger k = numerator / denominator;
if (k < BigInteger.One)
{
throw new InvalidOperationException($"Calculated k={k} is less than 1 for p={p}, divisor={divisor}.");
}
return k;
}
private static void WriteOutput(IReadOnlyCollection<Transition> transitions)
{
using var writer = new StreamWriter(OutputFileName, false, Encoding.UTF8);
writer.WriteLine("p,divisor,lastDigit,k,lastMersenneDigit,isNextKHigher");
foreach (Transition transition in transitions)
{
writer.WriteLine($"{transition.P.ToString(CultureInfo.InvariantCulture)},{FormatBigInteger(transition.Divisor)},{transition.LastDigit},{FormatBigInteger(transition.CurrentK)},{transition.LastMersenneDigit},{(transition.IsNextKHigher ? "1" : "0")}");
}
}
private static int LastDigit(long p) => (int)(Math.Abs(p) % 10);
private static int LastMersenneDigit(long p)
{
long mod = p & 3;
return mod == 1 ? 1 : 7; // odd primes give p%4 == 1 or 3; 2^p mod 10 cycles -> 1 or 7 after subtracting 1
}
private static string FormatBigInteger(in BigInteger value) => value.ToString(CultureInfo.InvariantCulture);
private sealed record Transition(long P, BigInteger Divisor, int LastDigit, BigInteger CurrentK, int LastMersenneDigit, bool IsNextKHigher);
}
@@ -13,7 +13,16 @@
</AssemblyAttribute>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.ML" Version="3.0.1" />
<PackageReference Include="Microsoft.ML.FastTree" Version="3.0.1" />
<PackageReference Include="Microsoft.ML.LightGbm" Version="3.0.1" />
<PackageReference Include="Open.Numeric" Version="3.0.1" />
<PackageReference Include="Open.Numeric.Primes" Version="4.0.4" />
<PackageReference Include="Plotly.NET" Version="3.0.1" />
</ItemGroup>
</Project>
<ItemGroup Label="MLModel1">
<None Include="MLModel1.mlnet">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
@@ -0,0 +1,103 @@
// This file was auto-generated by ML.NET Model Builder.
using Microsoft.ML;
using Microsoft.ML.Data;
using System;
using System.Linq;
using System.IO;
using System.Collections.Generic;
namespace EvenPerfectBitScanner
{
public partial class MLModel1
{
/// <summary>
/// model input class for MLModel1.
/// </summary>
#region model input class
public class ModelInput
{
[LoadColumn(0)]
[ColumnName(@"p")]
public float P { get; set; }
[LoadColumn(1)]
[ColumnName(@"divisor")]
public float Divisor { get; set; }
[LoadColumn(2)]
[ColumnName(@"lastDigit")]
public float LastDigit { get; set; }
[LoadColumn(3)]
[ColumnName(@"k")]
public float K { get; set; }
[LoadColumn(4)]
[ColumnName(@"lastMersenneDigit")]
public float LastMersenneDigit { get; set; }
[LoadColumn(5)]
[ColumnName(@"isNextKHigher")]
public float IsNextKHigher { get; set; }
}
#endregion
/// <summary>
/// model output class for MLModel1.
/// </summary>
#region model output class
public class ModelOutput
{
[ColumnName(@"p")]
public float P { get; set; }
[ColumnName(@"divisor")]
public float Divisor { get; set; }
[ColumnName(@"lastDigit")]
public float LastDigit { get; set; }
[ColumnName(@"k")]
public float K { get; set; }
[ColumnName(@"lastMersenneDigit")]
public float LastMersenneDigit { get; set; }
[ColumnName(@"isNextKHigher")]
public float IsNextKHigher { get; set; }
[ColumnName(@"Features")]
public float[] Features { get; set; }
[ColumnName(@"Score")]
public float Score { get; set; }
}
#endregion
private static string MLNetModelPath = Path.GetFullPath("MLModel1.mlnet");
public static readonly Lazy<PredictionEngine<ModelInput, ModelOutput>> PredictEngine = new Lazy<PredictionEngine<ModelInput, ModelOutput>>(() => CreatePredictEngine(), true);
private static PredictionEngine<ModelInput, ModelOutput> CreatePredictEngine()
{
var mlContext = new MLContext();
ITransformer mlModel = mlContext.Model.Load(MLNetModelPath, out var _);
return mlContext.Model.CreatePredictionEngine<ModelInput, ModelOutput>(mlModel);
}
/// <summary>
/// Use this method to predict on <see cref="ModelInput"/>.
/// </summary>
/// <param name="input">model input.</param>
/// <returns><seealso cref=" ModelOutput"/></returns>
public static ModelOutput Predict(ModelInput input)
{
var predEngine = PredictEngine.Value;
return predEngine.Predict(input);
}
}
}
+125
View File
@@ -0,0 +1,125 @@
// This file was auto-generated by ML.NET Model Builder.
using Microsoft.ML.Data;
using Microsoft.ML;
using System;
using System.Collections.Generic;
using System.Linq;
using Plotly.NET;
using Plotly.NET.LayoutObjects;
namespace EvenPerfectBitScanner
{
public partial class MLModel1
{
/// <summary>
/// Permutation feature importance (PFI) is a technique to determine the importance
/// of features in a trained machine learning model. PFI works by taking a labeled dataset,
/// choosing a feature, and permuting the values for that feature across all the examples,
/// so that each example now has a random value for the feature and the original values for all other features.
/// The evaluation metric (e.g. R-squared) is then calculated for this modified dataset,
/// and the change in the evaluation metric from the original dataset is computed.
/// The larger the change in the evaluation metric, the more important the feature is to the model.
///
/// PFI typically takes a long time to compute, as the evaluation metric is calculated
/// many times to determine the importance of each feature.
///
/// </summary>
/// <param name="mlContext">The common context for all ML.NET operations.</param>
/// <param name="trainData">IDataView used to evaluate the model.</param>
/// <param name="model">Model to evaluate.</param>
/// <param name="labelColumnName">Label column being predicted.</param>
/// <returns>A list of each feature and its importance.</returns>
public static List<Tuple<string, double>> CalculatePFI(MLContext mlContext, IDataView trainData, ITransformer model, string labelColumnName)
{
var preprocessedTrainData = model.Transform(trainData);
var permutationFeatureImportance =
mlContext.Regression
.PermutationFeatureImportance(
model,
preprocessedTrainData,
labelColumnName: labelColumnName);
var featureImportanceMetrics =
permutationFeatureImportance
.Select((kvp) => new { kvp.Key, kvp.Value.RSquared })
.OrderByDescending(myFeatures => Math.Abs(myFeatures.RSquared.Mean));
var featurePFI = new List<Tuple<string, double>>();
foreach (var feature in featureImportanceMetrics)
{
var pfiValue = Math.Abs(feature.RSquared.Mean);
featurePFI.Add(new Tuple<string, double>(feature.Key, pfiValue));
}
return featurePFI;
}
/// <summary>
/// R Squared is a measure of variation between the values predicted by the model and the true values.
/// In a "perfect" model, there would be no variation between predictions and true values.
///
/// Here we will plot the predicted values vs the true values for the trained model. This RegressionChart.html
/// is then saved to the location specified by <param name="folderPath"></param>.
///
/// See more information on R Squared at https://en.wikipedia.org/wiki/Coefficient_of_determination.
/// </summary>
/// <param name="trainData">IDataView used to train the model.</param>
/// <param name="model">Model used for predictions.</param>
/// <param name="labelColumnName">Name of the predicted label column.</param>
/// <param name="folderPath">Folder path to save the RegressionChart.html file into.</param>
public static void PlotRSquaredValues(IDataView trainData, ITransformer model, string labelColumnName, string folderPath)
{
// Number of rows to display in charts.
int numberOfRows = 1000;
// Use the model to make batch predictions on training data
var testResults = model.Transform(trainData);
// Get the actual values from the dataset
var trueValues = testResults.GetColumn<float>(labelColumnName).Take(numberOfRows); ;
// Get the predicted values from the test results
var predictedValues = testResults.GetColumn<float>("Score").Take(numberOfRows);
// Setup what the graph looks like
var title = Title.init(Text: "R-Squared Plot");
var layout = Layout.init<IConvertible>(Title: title, PlotBGColor: Plotly.NET.Color.fromString("#e5ecf6"));
var xAxis = LinearAxis.init<IConvertible, IConvertible, IConvertible, IConvertible, IConvertible, IConvertible>(
Title: Title.init("True Values"),
ZeroLineColor: Plotly.NET.Color.fromString("#ffff"),
GridColor: Plotly.NET.Color.fromString("#ffff"),
ZeroLineWidth: 2);
var yAxis = LinearAxis.init<IConvertible, IConvertible, IConvertible, IConvertible, IConvertible, IConvertible>(
Title: Title.init("Predicted Values"),
ZeroLineColor: Plotly.NET.Color.fromString("#ffff"),
GridColor: Plotly.NET.Color.fromString("#ffff"),
ZeroLineWidth: 2);
// We will plot the line that shows the perfect result. Setup that line here.
var maximumValue = Math.Max(trueValues.Max(), predictedValues.Max());
var perfectX = new[] { 0, maximumValue };
var perfectY = new[] { 0, maximumValue };
// Create the scatterplot that shows the true values vs the predicted values
var trueAndPredictedValues = Chart2D.Chart.Scatter<float, float, string>(x: trueValues, y: predictedValues, mode: StyleParam.Mode.Markers)
.WithLayout(layout)
.WithXAxis(xAxis)
.WithYAxis(yAxis);
// Setup the line that shows what a perfect prediction would look like
var perfectLineGraph = Chart2D.Chart.Line<float, float, string>(x: perfectX, y: perfectY)
.WithLayout(layout)
.WithLine(Line.init(Width: 1.5));
var chartWithValuesAndIdealLine = Chart.Combine(new[] { trueAndPredictedValues, perfectLineGraph });
var chartFilePath = folderPath + "\\RegressionChart.html";
chartWithValuesAndIdealLine.SaveHtml(chartFilePath);
}
}
}
+337
View File
@@ -0,0 +1,337 @@
{
"Scenario": "Regression",
"DataSource": {
"Version": 3,
"EscapeCharacter": "\"",
"ReadMultiLines": false,
"KeepDiacritics": false,
"KeepPunctuations": false,
"AllowQuoting": false,
"Type": "TabularFile",
"FilePath": "C:\\Users\\marek\\source\\repos\\even-perfect-numbers-scanner\\BuildDivisorTransitions\\bin\\Release\\net8.0\\NextKForecastTraning.csv",
"Delimiter": ",",
"DecimalMarker": ".",
"HasHeader": true,
"ColumnProperties": [
{
"ColumnName": "p",
"ColumnPurpose": "Feature",
"ColumnDataFormat": "Single",
"IsCategorical": false,
"Type": "Column",
"Version": 5
},
{
"ColumnName": "divisor",
"ColumnPurpose": "Feature",
"ColumnDataFormat": "Single",
"IsCategorical": false,
"Type": "Column",
"Version": 5
},
{
"ColumnName": "lastDigit",
"ColumnPurpose": "Feature",
"ColumnDataFormat": "Single",
"IsCategorical": true,
"Type": "Column",
"Version": 5
},
{
"ColumnName": "k",
"ColumnPurpose": "Feature",
"ColumnDataFormat": "Single",
"IsCategorical": false,
"Type": "Column",
"Version": 5
},
{
"ColumnName": "lastMersenneDigit",
"ColumnPurpose": "Feature",
"ColumnDataFormat": "Single",
"IsCategorical": true,
"Type": "Column",
"Version": 5
},
{
"ColumnName": "isNextKHigher",
"ColumnPurpose": "Label",
"ColumnDataFormat": "Single",
"IsCategorical": true,
"Type": "Column",
"Version": 5
}
]
},
"Environment": {
"Type": "LocalCPU",
"Version": 1
},
"RunHistory": {
"Version": 3,
"Type": "Result",
"Trials": [
{
"Version": 1,
"Type": "Trial",
"TrainerName": "FastTreeRegression",
"Score": 0.30006118613190746,
"RuntimeInSeconds": 1.489,
"Parameter": {
"_SCHEMA_": "e0 * e1 * e2",
"e0": {
"OutputColumnNames": [
"p",
"divisor",
"lastDigit",
"k",
"lastMersenneDigit"
],
"InputColumnNames": [
"p",
"divisor",
"lastDigit",
"k",
"lastMersenneDigit"
]
},
"e1": {
"InputColumnNames": [
"p",
"divisor",
"lastDigit",
"k",
"lastMersenneDigit"
],
"OutputColumnName": "Features"
},
"e2": {
"NumberOfLeaves": 4,
"MinimumExampleCountPerLeaf": 9,
"NumberOfTrees": 8,
"MaximumBinCountPerFeature": 317,
"FeatureFraction": 0.98434331463123226,
"LearningRate": 0.3857390791447961,
"LabelColumnName": "isNextKHigher",
"FeatureColumnName": "Features",
"DiskTranspose": false
}
}
},
{
"Version": 1,
"Type": "Trial",
"TrainerName": "FastTreeRegression",
"Score": 0.299969238277351,
"RuntimeInSeconds": 1.496,
"Parameter": {
"_SCHEMA_": "e0 * e1 * e2",
"e0": {
"OutputColumnNames": [
"p",
"divisor",
"lastDigit",
"k",
"lastMersenneDigit"
],
"InputColumnNames": [
"p",
"divisor",
"lastDigit",
"k",
"lastMersenneDigit"
]
},
"e1": {
"InputColumnNames": [
"p",
"divisor",
"lastDigit",
"k",
"lastMersenneDigit"
],
"OutputColumnName": "Features"
},
"e2": {
"NumberOfLeaves": 4,
"MinimumExampleCountPerLeaf": 9,
"NumberOfTrees": 8,
"MaximumBinCountPerFeature": 317,
"FeatureFraction": 0.98444606904931908,
"LearningRate": 0.38567641892007121,
"LabelColumnName": "isNextKHigher",
"FeatureColumnName": "Features",
"DiskTranspose": false
}
}
},
{
"Version": 1,
"Type": "Trial",
"TrainerName": "FastTreeRegression",
"Score": 0.29992424440705012,
"RuntimeInSeconds": 0.993,
"Parameter": {
"_SCHEMA_": "e0 * e1 * e2",
"e0": {
"OutputColumnNames": [
"p",
"divisor",
"lastDigit",
"k",
"lastMersenneDigit"
],
"InputColumnNames": [
"p",
"divisor",
"lastDigit",
"k",
"lastMersenneDigit"
]
},
"e1": {
"InputColumnNames": [
"p",
"divisor",
"lastDigit",
"k",
"lastMersenneDigit"
],
"OutputColumnName": "Features"
},
"e2": {
"NumberOfLeaves": 4,
"MinimumExampleCountPerLeaf": 9,
"NumberOfTrees": 8,
"MaximumBinCountPerFeature": 317,
"FeatureFraction": 0.98445819026817927,
"LearningRate": 0.38613186537816252,
"LabelColumnName": "isNextKHigher",
"FeatureColumnName": "Features",
"DiskTranspose": false
}
}
},
{
"Version": 1,
"Type": "Trial",
"TrainerName": "FastTreeRegression",
"Score": 0.29992046748552242,
"RuntimeInSeconds": 1.389,
"Parameter": {
"_SCHEMA_": "e0 * e1 * e2",
"e0": {
"OutputColumnNames": [
"p",
"divisor",
"lastDigit",
"k",
"lastMersenneDigit"
],
"InputColumnNames": [
"p",
"divisor",
"lastDigit",
"k",
"lastMersenneDigit"
]
},
"e1": {
"InputColumnNames": [
"p",
"divisor",
"lastDigit",
"k",
"lastMersenneDigit"
],
"OutputColumnName": "Features"
},
"e2": {
"NumberOfLeaves": 4,
"MinimumExampleCountPerLeaf": 9,
"NumberOfTrees": 8,
"MaximumBinCountPerFeature": 317,
"FeatureFraction": 0.984395476164661,
"LearningRate": 0.3858463322510558,
"LabelColumnName": "isNextKHigher",
"FeatureColumnName": "Features",
"DiskTranspose": false
}
}
},
{
"Version": 1,
"Type": "Trial",
"TrainerName": "FastTreeRegression",
"Score": 0.29984566377505206,
"RuntimeInSeconds": 1.512,
"Parameter": {
"_SCHEMA_": "e0 * e1 * e2",
"e0": {
"OutputColumnNames": [
"p",
"divisor",
"lastDigit",
"k",
"lastMersenneDigit"
],
"InputColumnNames": [
"p",
"divisor",
"lastDigit",
"k",
"lastMersenneDigit"
]
},
"e1": {
"InputColumnNames": [
"p",
"divisor",
"lastDigit",
"k",
"lastMersenneDigit"
],
"OutputColumnName": "Features"
},
"e2": {
"NumberOfLeaves": 4,
"MinimumExampleCountPerLeaf": 8,
"NumberOfTrees": 8,
"MaximumBinCountPerFeature": 317,
"FeatureFraction": 0.98439134546037266,
"LearningRate": 0.38521733136295422,
"LabelColumnName": "isNextKHigher",
"FeatureColumnName": "Features",
"DiskTranspose": false
}
}
}
],
"Estimators": {
"e0": "ReplaceMissingValues",
"e1": "Concatenate",
"e2": "FastTreeRegression",
"e3": "FastForestRegression",
"e4": "LightGbmRegression",
"e5": "LbfgsPoissonRegressionRegression",
"e6": "SdcaRegression"
},
"Schema": "e0 * e1 * (e2 + e3 + e4 + e5 + e6)",
"MetricName": "RSquared",
"ModelFilePath": "C:\\Users\\marek\\source\\repos\\even-perfect-numbers-scanner\\EvenPerfectBitScanner\\MLModel1.mlnet"
},
"Type": "TrainingConfig",
"Version": 5,
"TrainingOption": {
"Version": 2,
"Subsampling": false,
"Type": "RegressionTrainingOption",
"TrainingTime": 3600,
"LabelColumn": "isNextKHigher",
"ValidationOption": {
"Version": 0,
"Type": "CrossValidationValidationOption",
"NumberOfFolds": 10
}
}
}
Binary file not shown.
+100
View File
@@ -0,0 +1,100 @@
// This file was auto-generated by ML.NET Model Builder.
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.ML;
using Microsoft.ML.Data;
using Microsoft.ML.Trainers;
using Microsoft.ML.Trainers.FastTree;
namespace EvenPerfectBitScanner
{
public partial class MLModel1
{
public const string RetrainFilePath = @"C:\Users\marek\source\repos\even-perfect-numbers-scanner\BuildDivisorTransitions\bin\Release\net8.0\NextKForecastTraning.csv";
public const char RetrainSeparatorChar = ',';
public const bool RetrainHasHeader = true;
public const bool RetrainAllowQuoting = false;
/// <summary>
/// Train a new model with the provided dataset.
/// </summary>
/// <param name="outputModelPath">File path for saving the model. Should be similar to "C:\YourPath\ModelName.mlnet"</param>
/// <param name="inputDataFilePath">Path to the data file for training.</param>
/// <param name="separatorChar">Separator character for delimited training file.</param>
/// <param name="hasHeader">Boolean if training file has a header.</param>
public static void Train(string outputModelPath, string inputDataFilePath = RetrainFilePath, char separatorChar = RetrainSeparatorChar, bool hasHeader = RetrainHasHeader, bool allowQuoting = RetrainAllowQuoting)
{
var mlContext = new MLContext();
var data = LoadIDataViewFromFile(mlContext, inputDataFilePath, separatorChar, hasHeader, allowQuoting);
var model = RetrainModel(mlContext, data);
SaveModel(mlContext, model, data, outputModelPath);
}
/// <summary>
/// Load an IDataView from a file path.
/// </summary>
/// <param name="mlContext">The common context for all ML.NET operations.</param>
/// <param name="inputDataFilePath">Path to the data file for training.</param>
/// <param name="separatorChar">Separator character for delimited training file.</param>
/// <param name="hasHeader">Boolean if training file has a header.</param>
/// <returns>IDataView with loaded training data.</returns>
public static IDataView LoadIDataViewFromFile(MLContext mlContext, string inputDataFilePath, char separatorChar, bool hasHeader, bool allowQuoting)
{
return mlContext.Data.LoadFromTextFile<ModelInput>(inputDataFilePath, separatorChar, hasHeader, allowQuoting: allowQuoting);
}
/// <summary>
/// Save a model at the specified path.
/// </summary>
/// <param name="mlContext">The common context for all ML.NET operations.</param>
/// <param name="model">Model to save.</param>
/// <param name="data">IDataView used to train the model.</param>
/// <param name="modelSavePath">File path for saving the model. Should be similar to "C:\YourPath\ModelName.mlnet.</param>
public static void SaveModel(MLContext mlContext, ITransformer model, IDataView data, string modelSavePath)
{
// Pull the data schema from the IDataView used for training the model
DataViewSchema dataViewSchema = data.Schema;
using (var fs = File.Create(modelSavePath))
{
mlContext.Model.Save(model, dataViewSchema, fs);
}
}
/// <summary>
/// Retrain model using the pipeline generated as part of the training process.
/// </summary>
/// <param name="mlContext"></param>
/// <param name="trainData"></param>
/// <returns></returns>
public static ITransformer RetrainModel(MLContext mlContext, IDataView trainData)
{
var pipeline = BuildPipeline(mlContext);
var model = pipeline.Fit(trainData);
return model;
}
/// <summary>
/// build the pipeline that is used from model builder. Use this function to retrain model.
/// </summary>
/// <param name="mlContext"></param>
/// <returns></returns>
public static IEstimator<ITransformer> BuildPipeline(MLContext mlContext)
{
// Data process configuration with pipeline data transformations
var pipeline = mlContext.Transforms.ReplaceMissingValues(new []{new InputOutputColumnPair(@"p", @"p"),new InputOutputColumnPair(@"divisor", @"divisor"),new InputOutputColumnPair(@"lastDigit", @"lastDigit"),new InputOutputColumnPair(@"k", @"k"),new InputOutputColumnPair(@"lastMersenneDigit", @"lastMersenneDigit")})
.Append(mlContext.Transforms.Concatenate(@"Features", new []{@"p",@"divisor",@"lastDigit",@"k",@"lastMersenneDigit"}))
.Append(mlContext.Regression.Trainers.FastTree(new FastTreeRegressionTrainer.Options(){NumberOfLeaves=4,MinimumExampleCountPerLeaf=9,NumberOfTrees=8,MaximumBinCountPerFeature=317,FeatureFraction=0.9843433146312323,LearningRate=0.3857390791447961,LabelColumnName=@"isNextKHigher",FeatureColumnName=@"Features",DiskTranspose=false}));
return pipeline;
}
}
}
+6
View File
@@ -14,6 +14,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EvenPerfectBitScanner.Resul
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EvenPerfectBitScanner.Benchmarks", "EvenPerfectBitScanner.Benchmarks\EvenPerfectBitScanner.Benchmarks.csproj", "{83551FCC-41FA-4162-B541-AFCB5666A29F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildDivisorTransitions", "BuildDivisorTransitions\BuildDivisorTransitions.csproj", "{0A936837-5082-4C0B-AC3B-840AD2E11057}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -47,5 +49,9 @@ Global
{83551FCC-41FA-4162-B541-AFCB5666A29F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{83551FCC-41FA-4162-B541-AFCB5666A29F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{83551FCC-41FA-4162-B541-AFCB5666A29F}.Release|Any CPU.Build.0 = Release|Any CPU
{0A936837-5082-4C0B-AC3B-840AD2E11057}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0A936837-5082-4C0B-AC3B-840AD2E11057}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0A936837-5082-4C0B-AC3B-840AD2E11057}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0A936837-5082-4C0B-AC3B-840AD2E11057}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal