More minor optimizations

This commit is contained in:
Asriel Camora
2023-06-21 06:16:57 -07:00
parent fc0ffc11f3
commit 0b2b80d6b5
10 changed files with 76 additions and 64 deletions
+5 -5
View File
@@ -2,12 +2,12 @@ using Craftimizer.Simulator.Actions;
namespace Craftimizer.Simulator; namespace Craftimizer.Simulator;
public record struct ActionStates public struct ActionStates
{ {
public byte TouchComboIdx { get; set; } public byte TouchComboIdx;
public byte CarefulObservationCount { get; set; } public byte CarefulObservationCount;
public bool UsedHeartAndSoul { get; set; } public bool UsedHeartAndSoul;
public bool Observed { get; set; } public bool Observed;
public void MutateState(ActionType action) public void MutateState(ActionType action)
{ {
+14 -14
View File
@@ -1,17 +1,17 @@
namespace Craftimizer.Simulator; namespace Craftimizer.Simulator;
public record struct Effects public struct Effects
{ {
public byte InnerQuiet { get; set; } public byte InnerQuiet;
public byte WasteNot { get; set; } public byte WasteNot;
public byte Veneration { get; set; } public byte Veneration;
public byte GreatStrides { get; set; } public byte GreatStrides;
public byte Innovation { get; set; } public byte Innovation;
public byte FinalAppraisal { get; set; } public byte FinalAppraisal;
public byte WasteNot2 { get; set; } public byte WasteNot2;
public byte MuscleMemory { get; set; } public byte MuscleMemory;
public byte Manipulation { get; set; } public byte Manipulation;
public bool HeartAndSoul { get; set; } public bool HeartAndSoul;
public void SetDuration(EffectType effect, byte duration) public void SetDuration(EffectType effect, byte duration)
{ {
@@ -57,7 +57,7 @@ public record struct Effects
InnerQuiet++; InnerQuiet++;
} }
public byte GetDuration(EffectType effect) => public readonly byte GetDuration(EffectType effect) =>
effect switch effect switch
{ {
EffectType.InnerQuiet => (byte)(InnerQuiet != 0 ? 1 : 0), EffectType.InnerQuiet => (byte)(InnerQuiet != 0 ? 1 : 0),
@@ -73,11 +73,11 @@ public record struct Effects
_ => 0 _ => 0
}; };
public byte GetStrength(EffectType effect) => public readonly byte GetStrength(EffectType effect) =>
effect == EffectType.InnerQuiet ? InnerQuiet : effect == EffectType.InnerQuiet ? InnerQuiet :
(byte)(GetDuration(effect) != 0 ? 1 : 0); (byte)(GetDuration(effect) != 0 ? 1 : 0);
public bool HasEffect(EffectType effect) => public readonly bool HasEffect(EffectType effect) =>
GetDuration(effect) != 0; GetDuration(effect) != 0;
public void DecrementDuration() public void DecrementDuration()
+1 -1
View File
@@ -1,6 +1,6 @@
namespace Craftimizer.Simulator; namespace Craftimizer.Simulator;
public record SimulationInput public sealed class SimulationInput
{ {
public CharacterStats Stats { get; } public CharacterStats Stats { get; }
public RecipeInfo Recipe { get; } public RecipeInfo Recipe { get; }
+1 -3
View File
@@ -1,8 +1,6 @@
using Craftimizer.Simulator.Actions;
namespace Craftimizer.Simulator; namespace Craftimizer.Simulator;
public readonly record struct SimulationState public readonly struct SimulationState
{ {
public SimulationInput Input { get; init; } public SimulationInput Input { get; init; }
+7 -7
View File
@@ -5,9 +5,9 @@ using System.Runtime.Intrinsics.X86;
namespace Craftimizer.Solver.Crafty; namespace Craftimizer.Solver.Crafty;
public sealed class ActionSet public struct ActionSet
{ {
private uint Bits { get; set; } private uint bits;
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int NthBitSet(uint value, int n) private static int NthBitSet(uint value, int n)
@@ -47,13 +47,13 @@ public sealed class ActionSet
private static ActionType ToAction(int index) => Simulator.AcceptedActions[index]; private static ActionType ToAction(int index) => Simulator.AcceptedActions[index];
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool HasAction(ActionType action) => (Bits & (1u << (FromAction(action) + 1))) != 0; public readonly bool HasAction(ActionType action) => (bits & (1u << (FromAction(action) + 1))) != 0;
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AddAction(ActionType action) => Bits |= 1u << (FromAction(action) + 1); public void AddAction(ActionType action) => bits |= 1u << (FromAction(action) + 1);
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void RemoveAction(ActionType action) => Bits &= ~(1u << (FromAction(action) + 1)); public void RemoveAction(ActionType action) => bits &= ~(1u << (FromAction(action) + 1));
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public ActionType ElementAt(int index) => ToAction(NthBitSet(Bits, index) - 1); public readonly ActionType ElementAt(int index) => ToAction(NthBitSet(bits, index) - 1);
public int Count => BitOperations.PopCount(Bits); public readonly int Count => BitOperations.PopCount(bits);
} }
+13 -6
View File
@@ -4,25 +4,32 @@ namespace Craftimizer.Solver.Crafty;
public class Arena<T> where T : struct public class Arena<T> where T : struct
{ {
public readonly record struct Node public readonly struct Node
{ {
public T State { get; init; } public readonly T State;
public List<int> Children { get; init; } public readonly List<int> Children;
public int Parent { get; init; } public readonly int Parent;
public Node(T state, int parent)
{
State = state;
Children = new();
Parent = parent;
}
} }
private readonly List<Node> nodes = new(); private readonly List<Node> nodes = new();
public Arena(T initialState = default) public Arena(T initialState = default)
{ {
nodes.Add(new() { Parent = -1, Children = new(), State = initialState }); nodes.Add(new(initialState, -1));
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public int Insert(int parentIndex, T state) public int Insert(int parentIndex, T state)
{ {
var index = nodes.Count; var index = nodes.Count;
nodes.Add(new() { Parent = parentIndex, Children = new(), State = state }); nodes.Add(new(state, parentIndex));
nodes[parentIndex].Children.Add(index); nodes[parentIndex].Children.Add(index);
return index; return index;
} }
+7
View File
@@ -0,0 +1,7 @@
namespace Craftimizer.Solver.Crafty;
public class NodeData
{
public ActionSet AvailableActions;
public NodeScores Scores;
}
+11 -4
View File
@@ -1,8 +1,15 @@
namespace Craftimizer.Solver.Crafty; namespace Craftimizer.Solver.Crafty;
public sealed class NodeScores public struct NodeScores
{ {
public float ScoreSum { get; set; } public float ScoreSum;
public float MaxScore { get; set; } public float MaxScore;
public float Visits { get; set; } public float Visits;
public void Visit(float score)
{
ScoreSum += score;
MaxScore = Math.Max(MaxScore, score);
Visits++;
}
} }
+3 -4
View File
@@ -3,18 +3,17 @@ using Craftimizer.Simulator.Actions;
namespace Craftimizer.Solver.Crafty; namespace Craftimizer.Solver.Crafty;
public readonly record struct SimulationNode public readonly struct SimulationNode
{ {
public SimulationState State { get; init; } public SimulationState State { get; init; }
public ActionType? Action { get; init; } public ActionType? Action { get; init; }
public ActionSet AvailableActions { get; init; }
public CompletionState SimulationCompletionState { get; init; } public CompletionState SimulationCompletionState { get; init; }
public CompletionState CompletionState => public CompletionState CompletionState =>
AvailableActions.Count == 0 && SimulationCompletionState == CompletionState.Incomplete ? Data.AvailableActions.Count == 0 && SimulationCompletionState == CompletionState.Incomplete ?
CompletionState.NoMoreActions : CompletionState.NoMoreActions :
SimulationCompletionState; SimulationCompletionState;
public NodeScores Scores { get; init; } public NodeData Data { get; init; }
public bool IsComplete => CompletionState != CompletionState.Incomplete; public bool IsComplete => CompletionState != CompletionState.Incomplete;
+14 -20
View File
@@ -28,8 +28,7 @@ public class Solver
State = state, State = state,
Action = null, Action = null,
SimulationCompletionState = Simulator.CompletionState, SimulationCompletionState = Simulator.CompletionState,
AvailableActions = Simulator.AvailableActionsHeuristic(strict), Data = new() { AvailableActions = Simulator.AvailableActionsHeuristic(strict) }
Scores = new()
}); });
} }
@@ -45,8 +44,7 @@ public class Solver
State = newState, State = newState,
Action = action, Action = action,
SimulationCompletionState = Simulator.CompletionState, SimulationCompletionState = Simulator.CompletionState,
AvailableActions = Simulator.AvailableActionsHeuristic(strict), Data = new() { AvailableActions = Simulator.AvailableActionsHeuristic(strict) }
Scores = new()
}; };
} }
@@ -59,9 +57,9 @@ public class Solver
if (node.IsComplete) if (node.IsComplete)
return (currentIndex, node.CompletionState); return (currentIndex, node.CompletionState);
if (!node.AvailableActions.HasAction(action)) if (!node.Data.AvailableActions.HasAction(action))
return (currentIndex, CompletionState.InvalidAction); return (currentIndex, CompletionState.InvalidAction);
node.AvailableActions.RemoveAction(action); node.Data.AvailableActions.RemoveAction(action);
currentIndex = Tree.Insert(currentIndex, Execute(node.State, action, strict)); currentIndex = Tree.Insert(currentIndex, Execute(node.State, action, strict));
} }
@@ -122,7 +120,7 @@ public class Solver
for (var j = 0; j < iterCount; ++j) for (var j = 0; j < iterCount; ++j)
{ {
var node = Tree.Get(children[i + j]).State.Scores; var node = Tree.Get(children[i + j]).State.Data.Scores;
scoreSums[j] = node.ScoreSum; scoreSums[j] = node.ScoreSum;
visits[j] = node.Visits; visits[j] = node.Visits;
maxScores[j] = node.MaxScore; maxScores[j] = node.MaxScore;
@@ -148,7 +146,7 @@ public class Solver
{ {
var selectedNode = Tree.Get(selectedIndex); var selectedNode = Tree.Get(selectedIndex);
var expandable = selectedNode.State.AvailableActions.Count != 0; var expandable = selectedNode.State.Data.AvailableActions.Count != 0;
var likelyTerminal = selectedNode.Children.Count == 0; var likelyTerminal = selectedNode.Children.Count == 0;
if (expandable || likelyTerminal) if (expandable || likelyTerminal)
{ {
@@ -156,7 +154,7 @@ public class Solver
} }
// select the node with the highest score // select the node with the highest score
selectedIndex = EvalBestChild(selectedNode.State.Scores.Visits, selectedNode.Children); selectedIndex = EvalBestChild(selectedNode.State.Data.Scores.Visits, selectedNode.Children);
} }
} }
@@ -167,8 +165,8 @@ public class Solver
if (initialNode.IsComplete) if (initialNode.IsComplete)
return (initialIndex, initialNode.CompletionState, initialNode.CalculateScore() ?? 0); return (initialIndex, initialNode.CompletionState, initialNode.CalculateScore() ?? 0);
var randomAction = initialNode.AvailableActions.ElementAt(0); var randomAction = initialNode.Data.AvailableActions.ElementAt(0);
initialNode.AvailableActions.RemoveAction(randomAction); initialNode.Data.AvailableActions.RemoveAction(randomAction);
var expandedState = Execute(initialNode.State, randomAction, true); var expandedState = Execute(initialNode.State, randomAction, true);
var expandedIndex = Tree.Insert(initialIndex, expandedState); var expandedIndex = Tree.Insert(initialIndex, expandedState);
@@ -179,7 +177,7 @@ public class Solver
{ {
if (currentState.IsComplete) if (currentState.IsComplete)
break; break;
randomAction = currentState.AvailableActions.ElementAt(0); randomAction = currentState.Data.AvailableActions.ElementAt(0);
actions.Add(randomAction); actions.Add(randomAction);
currentState = Execute(currentState.State, randomAction, true); currentState = Execute(currentState.State, randomAction, true);
} }
@@ -188,7 +186,7 @@ public class Solver
var score = currentState.CalculateScore() ?? 0; var score = currentState.CalculateScore() ?? 0;
if (currentState.CompletionState == CompletionState.ProgressComplete) if (currentState.CompletionState == CompletionState.ProgressComplete)
{ {
if (score >= ScoreStorageThreshold && score >= Tree.Get(0).State.Scores.MaxScore) if (score >= ScoreStorageThreshold && score >= Tree.Get(0).State.Data.Scores.MaxScore)
{ {
(var terminalIndex, _) = ExecuteActions(expandedIndex, actions, true); (var terminalIndex, _) = ExecuteActions(expandedIndex, actions, true);
return (terminalIndex, currentState.CompletionState, score); return (terminalIndex, currentState.CompletionState, score);
@@ -203,11 +201,7 @@ public class Solver
while (true) while (true)
{ {
var currentNode = Tree.Get(currentIndex); var currentNode = Tree.Get(currentIndex);
var currentScores = currentNode.State.Scores; currentNode.State.Data.Scores.Visit(score);
currentScores.Visits++;
currentScores.ScoreSum += score;
if (currentScores.MaxScore < score)
currentScores.MaxScore = score;
if (currentIndex == targetIndex) if (currentIndex == targetIndex)
break; break;
@@ -233,7 +227,7 @@ public class Solver
var node = Tree.Get(0); var node = Tree.Get(0);
while (node.Children.Count != 0) while (node.Children.Count != 0)
{ {
var next_index = RustMaxBy(node.Children, n => Tree.Get(n).State.Scores.MaxScore); var next_index = RustMaxBy(node.Children, n => Tree.Get(n).State.Data.Scores.MaxScore);
node = Tree.Get(next_index); node = Tree.Get(next_index);
if (node.State.Action != null) if (node.State.Action != null)
actions.Add(node.State.Action.Value); actions.Add(node.State.Action.Value);
@@ -264,7 +258,7 @@ public class Solver
solver.Search(0); solver.Search(0);
var (solution_actions, solution_node) = solver.Solution(); var (solution_actions, solution_node) = solver.Solution();
if (solution_node.Scores.MaxScore >= 1.0) if (solution_node.Data.Scores.MaxScore >= 1.0)
{ {
actions.AddRange(solution_actions); actions.AddRange(solution_actions);
return (actions, solution_node.State); return (actions, solution_node.State);