BuildDivisorTransitions application added.
This commit is contained in:
1 parent
97fd041ec0
commit
046cfe7d26
12 files changed
+979
-4
No files matched your search
@@ -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/*
|
||||
Vendored
+30
-2
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
Vendored
+46
-1
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
Reference in new issue
Block a user