Update solver scoring; remove byregot adjustment

This commit is contained in:
Asriel Camora
2023-11-04 19:40:31 -07:00
parent 5bee39678c
commit bfc8708fbd
6 changed files with 157 additions and 141 deletions
+85 -128
View File
@@ -1,18 +1,30 @@
using Craftimizer.Simulator;
using Craftimizer.Simulator.Actions;
using Craftimizer.Solver;
using System.Diagnostics;
namespace Craftimizer.Benchmark;
internal static class Program
{
private static async Task Main(string[] args)
private static Task Main(string[] args)
{
#if !IS_TRACE
RunBench(args);
return Task.CompletedTask;
#else
return RunTrace();
#endif
// return RunOther();
}
private static void RunBench(string[] args)
{
Environment.SetEnvironmentVariable("IS_BENCH", "1");
BenchmarkDotNet.Running.BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);
#else
}
private static async Task RunTrace()
{
var input = new SimulationInput(
new()
{
@@ -43,143 +55,88 @@ internal static class Program
var config = new SolverConfig()
{
Algorithm = SolverAlgorithm.Stepwise,
Iterations = 30000
Iterations = 30000,
MaxStepCount = 25
};
var solver = new Solver.Solver(config, new(input));
solver.OnNewAction += s => Console.WriteLine($">{s}");
solver.Start();
var (_, s) = await solver.GetTask().ConfigureAwait(false);
Console.WriteLine($"Qual: {s.Quality}/{s.Input.Recipe.MaxQuality}");
#endif
return;
////TypeLayout.PrintLayout<ArenaNode<SimulationNode>>(true);
////return;
//var input = new SimulationInput(
// new CharacterStats
// {
// Craftsmanship = 4078,
// Control = 3897,
// CP = 704,
// Level = 90,
// CanUseManipulation = true,
// HasSplendorousBuff = false,
// IsSpecialist = false,
// CLvl = 560,
// },
// new RecipeInfo()
// {
// IsExpert = false,
// ClassJobLevel = 90,
// RLvl = 640,
// ConditionsFlag = 15,
// MaxDurability = 70,
// MaxQuality = 14040,
// MaxProgress = 6600,
// QualityModifier = 70,
// QualityDivider = 115,
// ProgressModifier = 80,
// ProgressDivider = 130,
// }
//);
//var config = new SolverConfig()
//{
// Iterations = 100_000,
// ForkCount = 32,
// FurcatedActionCount = 16,
// MaxStepCount = 30,
//};
//var sim = new SimulatorNoRandom(new(input));
//(_, var state) = sim.Execute(new(input), ActionType.MuscleMemory);
//(_, state) = sim.Execute(state, ActionType.PrudentTouch);
////(_, state) = sim.Execute(state, ActionType.Manipulation);
////(_, state) = sim.Execute(state, ActionType.Veneration);
////(_, state) = sim.Execute(state, ActionType.WasteNot);
////(_, state) = sim.Execute(state, ActionType.Groundwork);
////(_, state) = sim.Execute(state, ActionType.Groundwork);
////(_, state) = sim.Execute(state, ActionType.Groundwork);
////(_, state) = sim.Execute(state, ActionType.Innovation);
////(_, state) = sim.Execute(state, ActionType.PrudentTouch);
////(_, state) = sim.Execute(state, ActionType.AdvancedTouchCombo);
////(_, state) = sim.Execute(state, ActionType.Manipulation);
////(_, state) = sim.Execute(state, ActionType.Innovation);
////(_, state) = sim.Execute(state, ActionType.PrudentTouch);
////(_, state) = sim.Execute(state, ActionType.AdvancedTouchCombo);
////(_, state) = sim.Execute(state, ActionType.GreatStrides);
////(_, state) = sim.Execute(state, ActionType.Innovation);
////(_, state) = sim.Execute(state, ActionType.FocusedTouchCombo);
////(_, state) = sim.Execute(state, ActionType.GreatStrides);
////(_, state) = sim.Execute(state, ActionType.ByregotsBlessing);
////(_, state) = sim.Execute(state, ActionType.CarefulSynthesis);
////(_, state) = sim.Execute(state, ActionType.CarefulSynthesis);
//Console.WriteLine($"{state.Quality} {state.CP} {state.Progress} {state.Durability}");
////return;
//var solver = new Solver.Solver(config, state);
//solver.OnLog += Console.WriteLine;
//solver.OnNewAction += s => Console.WriteLine(s);
//solver.Start();
//var (_, s) = await solver.GetTask().ConfigureAwait(false);
//Console.WriteLine($"Qual: {s.Quality}/{s.Input.Recipe.MaxQuality}");
}
private static void Benchmark(Func<SolverSolution> search)
private static async Task RunOther()
{
var s = Stopwatch.StartNew();
List<int> q = new();
for (var i = 0; i < 15; ++i)
//TypeLayout.PrintLayout<ArenaNode<SimulationNode>>(true);
//return;
var input = new SimulationInput(
new CharacterStats
{
Craftsmanship = 4078,
Control = 3897,
CP = 704,
Level = 90,
CanUseManipulation = true,
HasSplendorousBuff = false,
IsSpecialist = false,
CLvl = 560,
},
new RecipeInfo()
{
IsExpert = false,
ClassJobLevel = 90,
RLvl = 640,
ConditionsFlag = 15,
MaxDurability = 70,
MaxQuality = 14040,
MaxProgress = 6600,
QualityModifier = 70,
QualityDivider = 115,
ProgressModifier = 80,
ProgressDivider = 130,
}
);
var config = new SolverConfig()
{
var state = search().State;
//Console.WriteLine($"Qual: {state.Quality}/{state.Input.Recipe.MaxQuality}");
q.Add(state.Quality);
}
s.Stop();
Console.WriteLine($"{s.Elapsed.TotalMilliseconds / 60:0.00}ms/cycle");
Console.WriteLine(string.Join(',', q));
q.Sort();
Console.WriteLine($"Min: {Quartile(q, 0)}, Max: {Quartile(q, 4)}, Avg: {Quartile(q, 2)}, Q1: {Quartile(q, 1)}, Q3: {Quartile(q, 3)}");
}
// https://stackoverflow.com/a/31536435
private static float Quartile(List<int> input, int quartile)
{
float dblPercentage = quartile switch
{
0 => 0, // Smallest value in the data set
1 => 25, // First quartile (25th percentile)
2 => 50, // Second quartile (50th percentile)
3 => 75, // Third quartile (75th percentile)
4 => 100, // Largest value in the data set
_ => 0,
Iterations = 100_000,
ForkCount = 32,
FurcatedActionCount = 16,
MaxStepCount = 30,
};
if (dblPercentage >= 100) return input[^1];
var position = (input.Count + 1) * dblPercentage / 100f;
var n = (dblPercentage / 100f * (input.Count - 1)) + 1;
var sim = new SimulatorNoRandom(new(input));
(_, var state) = sim.Execute(new(input), ActionType.MuscleMemory);
(_, state) = sim.Execute(state, ActionType.PrudentTouch);
//(_, state) = sim.Execute(state, ActionType.Manipulation);
//(_, state) = sim.Execute(state, ActionType.Veneration);
//(_, state) = sim.Execute(state, ActionType.WasteNot);
//(_, state) = sim.Execute(state, ActionType.Groundwork);
//(_, state) = sim.Execute(state, ActionType.Groundwork);
//(_, state) = sim.Execute(state, ActionType.Groundwork);
//(_, state) = sim.Execute(state, ActionType.Innovation);
//(_, state) = sim.Execute(state, ActionType.PrudentTouch);
//(_, state) = sim.Execute(state, ActionType.AdvancedTouchCombo);
//(_, state) = sim.Execute(state, ActionType.Manipulation);
//(_, state) = sim.Execute(state, ActionType.Innovation);
//(_, state) = sim.Execute(state, ActionType.PrudentTouch);
//(_, state) = sim.Execute(state, ActionType.AdvancedTouchCombo);
//(_, state) = sim.Execute(state, ActionType.GreatStrides);
//(_, state) = sim.Execute(state, ActionType.Innovation);
//(_, state) = sim.Execute(state, ActionType.FocusedTouchCombo);
//(_, state) = sim.Execute(state, ActionType.GreatStrides);
//(_, state) = sim.Execute(state, ActionType.ByregotsBlessing);
//(_, state) = sim.Execute(state, ActionType.CarefulSynthesis);
//(_, state) = sim.Execute(state, ActionType.CarefulSynthesis);
float leftNumber, rightNumber;
if (position >= 1)
{
leftNumber = input[(int)MathF.Floor(n) - 1];
rightNumber = input[(int)MathF.Floor(n)];
}
else
{
leftNumber = input[0]; // first data
rightNumber = input[1]; // first data
}
if (leftNumber == rightNumber)
return leftNumber;
else
{
var part = n - MathF.Floor(n);
return leftNumber + (part * (rightNumber - leftNumber));
}
Console.WriteLine($"{state.Quality} {state.CP} {state.Progress} {state.Durability}");
//return;
var solver = new Solver.Solver(config, state);
solver.OnLog += Console.WriteLine;
solver.OnNewAction += s => Console.WriteLine(s);
solver.Start();
var (_, s) = await solver.GetTask().ConfigureAwait(false);
Console.WriteLine($"Qual: {s.Quality}/{s.Input.Recipe.MaxQuality}");
}
}
+7 -2
View File
@@ -8,7 +8,7 @@
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<Platforms>x64</Platforms>
<Configurations>Debug;Release</Configurations>
<Configurations>Debug;Release;Trace</Configurations>
</PropertyGroup>
<ItemGroup>
@@ -22,9 +22,14 @@
<ProjectReference Include="..\Simulator\Craftimizer.Simulator.csproj" />
<ProjectReference Include="..\Solver\Craftimizer.Solver.csproj" />
</ItemGroup>
<PropertyGroup Condition="'$(IS_BENCH)'=='1'">
<DefineConstants>$(DefineConstants);IS_DETERMINISTIC</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Trace'">
<Optimize>True</Optimize>
<DefineConstants>$(DefineConstants);IS_DETERMINISTIC;IS_TRACE</DefineConstants>
</PropertyGroup>
</Project>
+21 -7
View File
@@ -89,33 +89,47 @@ public class ActionSetTests
Assert.AreEqual(4, set.Count);
#if !IS_TRACE
Assert.AreEqual(ActionType.DelicateSynthesis, set.ElementAt(0));
Assert.AreEqual(ActionType.FocusedTouch, set.ElementAt(1));
Assert.AreEqual(ActionType.ByregotsBlessing, set.ElementAt(2));
Assert.AreEqual(ActionType.BasicSynthesis, set.ElementAt(3));
#else
Assert.AreEqual(ActionType.BasicSynthesis, set.ElementAt(0));
Assert.AreEqual(ActionType.ByregotsBlessing, set.ElementAt(1));
Assert.AreEqual(ActionType.FocusedTouch, set.ElementAt(2));
Assert.AreEqual(ActionType.DelicateSynthesis, set.ElementAt(3));
#endif
set.RemoveAction(ActionType.FocusedTouch);
Assert.AreEqual(3, set.Count);
#if !IS_TRACE
Assert.AreEqual(ActionType.DelicateSynthesis, set.ElementAt(0));
Assert.AreEqual(ActionType.ByregotsBlessing, set.ElementAt(1));
Assert.AreEqual(ActionType.BasicSynthesis, set.ElementAt(2));
#else
Assert.AreEqual(ActionType.BasicSynthesis, set.ElementAt(0));
Assert.AreEqual(ActionType.ByregotsBlessing, set.ElementAt(1));
Assert.AreEqual(ActionType.DelicateSynthesis, set.ElementAt(2));
#endif
}
[TestMethod]
public void TestRandomIndex()
{
#if IS_DETERMINISTIC
Assert.Inconclusive("Craftimizer is built for benchmarking; all random actions are deterministic and not actually random.");
Assert.Inconclusive("Craftimizer is currently built for determinism; all random actions are not actually random.");
#endif
var actions = new[]
{
ActionType.BasicTouch,
ActionType.BasicSynthesis,
ActionType.GreatStrides,
ActionType.TrainedFinesse,
};
{
ActionType.BasicTouch,
ActionType.BasicSynthesis,
ActionType.GreatStrides,
ActionType.TrainedFinesse,
};
var set = new ActionSet();
foreach(var action in actions)
+2 -1
View File
@@ -53,7 +53,8 @@ Global
{C3AEA981-9DA8-405C-995B-86528493891B}.Debug|x64.Build.0 = Debug|x64
{C3AEA981-9DA8-405C-995B-86528493891B}.Release|x64.ActiveCfg = Release|x64
{C3AEA981-9DA8-405C-995B-86528493891B}.Release|x64.Build.0 = Release|x64
{C3AEA981-9DA8-405C-995B-86528493891B}.Trace|x64.ActiveCfg = Release|x64
{C3AEA981-9DA8-405C-995B-86528493891B}.Trace|x64.ActiveCfg = Trace|x64
{C3AEA981-9DA8-405C-995B-86528493891B}.Trace|x64.Build.0 = Trace|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
+37 -1
View File
@@ -11,6 +11,7 @@ public struct ActionSet
public static readonly ActionType[] AcceptedActions = new[]
{
#if !IS_TRACE
ActionType.StandardTouchCombo,
ActionType.AdvancedTouchCombo,
ActionType.FocusedTouchCombo,
@@ -40,6 +41,36 @@ public struct ActionSet
ActionType.Observe,
ActionType.MastersMend,
ActionType.BasicTouch,
#else
//ActionType.BasicSynthesis,
ActionType.BasicTouch,
ActionType.MastersMend,
ActionType.Observe,
ActionType.WasteNot,
ActionType.Veneration,
ActionType.StandardTouch,
ActionType.GreatStrides,
ActionType.Innovation,
ActionType.BasicSynthesis,
ActionType.WasteNot2,
ActionType.ByregotsBlessing,
ActionType.MuscleMemory,
//ActionType.CarefulSynthesis,
ActionType.Manipulation,
ActionType.PrudentTouch,
ActionType.FocusedSynthesis,
ActionType.FocusedTouch,
ActionType.Reflect,
ActionType.PreparatoryTouch,
//ActionType.Groundwork,
ActionType.DelicateSynthesis,
ActionType.TrainedEye,
ActionType.CarefulSynthesis,
ActionType.AdvancedTouch,
ActionType.Groundwork,
ActionType.PrudentSynthesis,
ActionType.TrainedFinesse,
#endif
};
public static readonly int[] AcceptedActionsLUT;
@@ -64,7 +95,12 @@ public struct ActionSet
}
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ActionType ToAction(int index) => AcceptedActions[index];
private static ActionType ToAction(int index)
{
if (index < 0 || index >= AcceptedActions.Length)
throw new ArgumentOutOfRangeException(nameof(index), index, $"Index {index} is out of range for {nameof(ActionSet)}.");
return AcceptedActions[index];
}
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint ToMask(ActionType action) => 1u << (FromAction(action) + 1);
+5 -2
View File
@@ -46,6 +46,9 @@ public struct SimulationNode
if (completionState != CompletionState.ProgressComplete)
return null;
if (state.Input.Recipe.MaxQuality == 0)
return 1f - ((float)(state.ActionCount + 1) / config.MaxStepCount);
static float Apply(float bonus, float value, float target) =>
bonus * (target > 0 ? Math.Min(1f, value / target) : 1);
@@ -55,7 +58,7 @@ public struct SimulationNode
state.Input.Recipe.MaxProgress
);
var byregotBonus = CanByregot(state) ? (state.ActiveEffects.InnerQuiet * .2f + 1) * state.Input.BaseQualityGain : 0;
var byregotBonus = 0;// CanByregot(state) ? (state.ActiveEffects.InnerQuiet * .2f + 1) * state.Input.BaseQualityGain : 0;
var qualityScore = Apply(
config.ScoreQuality,
state.Quality + byregotBonus,
@@ -75,7 +78,7 @@ public struct SimulationNode
);
var fewerStepsScore =
config.ScoreSteps * (1f - (float)(state.ActionCount + 1) / config.MaxStepCount);
config.ScoreSteps * (1f - ((float)(state.ActionCount + 1) / config.MaxStepCount));
return progressScore + qualityScore + durabilityScore + cpScore + fewerStepsScore;
}