More minor optimizations
This commit is contained in:
@@ -5,9 +5,9 @@ using System.Runtime.Intrinsics.X86;
|
||||
|
||||
namespace Craftimizer.Solver.Crafty;
|
||||
|
||||
public sealed class ActionSet
|
||||
public struct ActionSet
|
||||
{
|
||||
private uint Bits { get; set; }
|
||||
private uint bits;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
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];
|
||||
|
||||
[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)]
|
||||
public void AddAction(ActionType action) => Bits |= 1u << (FromAction(action) + 1);
|
||||
public void AddAction(ActionType action) => bits |= 1u << (FromAction(action) + 1);
|
||||
[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)]
|
||||
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
@@ -4,25 +4,32 @@ namespace Craftimizer.Solver.Crafty;
|
||||
|
||||
public class Arena<T> where T : struct
|
||||
{
|
||||
public readonly record struct Node
|
||||
public readonly struct Node
|
||||
{
|
||||
public T State { get; init; }
|
||||
public List<int> Children { get; init; }
|
||||
public int Parent { get; init; }
|
||||
public readonly T State;
|
||||
public readonly List<int> Children;
|
||||
public readonly int Parent;
|
||||
|
||||
public Node(T state, int parent)
|
||||
{
|
||||
State = state;
|
||||
Children = new();
|
||||
Parent = parent;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly List<Node> nodes = new();
|
||||
|
||||
public Arena(T initialState = default)
|
||||
{
|
||||
nodes.Add(new() { Parent = -1, Children = new(), State = initialState });
|
||||
nodes.Add(new(initialState, -1));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public int Insert(int parentIndex, T state)
|
||||
{
|
||||
var index = nodes.Count;
|
||||
nodes.Add(new() { Parent = parentIndex, Children = new(), State = state });
|
||||
nodes.Add(new(state, parentIndex));
|
||||
nodes[parentIndex].Children.Add(index);
|
||||
return index;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Craftimizer.Solver.Crafty;
|
||||
|
||||
public class NodeData
|
||||
{
|
||||
public ActionSet AvailableActions;
|
||||
public NodeScores Scores;
|
||||
}
|
||||
@@ -1,8 +1,15 @@
|
||||
namespace Craftimizer.Solver.Crafty;
|
||||
|
||||
public sealed class NodeScores
|
||||
public struct NodeScores
|
||||
{
|
||||
public float ScoreSum { get; set; }
|
||||
public float MaxScore { get; set; }
|
||||
public float Visits { get; set; }
|
||||
public float ScoreSum;
|
||||
public float MaxScore;
|
||||
public float Visits;
|
||||
|
||||
public void Visit(float score)
|
||||
{
|
||||
ScoreSum += score;
|
||||
MaxScore = Math.Max(MaxScore, score);
|
||||
Visits++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,18 +3,17 @@ using Craftimizer.Simulator.Actions;
|
||||
|
||||
namespace Craftimizer.Solver.Crafty;
|
||||
|
||||
public readonly record struct SimulationNode
|
||||
public readonly struct SimulationNode
|
||||
{
|
||||
public SimulationState State { get; init; }
|
||||
public ActionType? Action { get; init; }
|
||||
public ActionSet AvailableActions { get; init; }
|
||||
public CompletionState SimulationCompletionState { get; init; }
|
||||
public CompletionState CompletionState =>
|
||||
AvailableActions.Count == 0 && SimulationCompletionState == CompletionState.Incomplete ?
|
||||
Data.AvailableActions.Count == 0 && SimulationCompletionState == CompletionState.Incomplete ?
|
||||
CompletionState.NoMoreActions :
|
||||
SimulationCompletionState;
|
||||
|
||||
public NodeScores Scores { get; init; }
|
||||
public NodeData Data { get; init; }
|
||||
|
||||
public bool IsComplete => CompletionState != CompletionState.Incomplete;
|
||||
|
||||
|
||||
+14
-20
@@ -28,8 +28,7 @@ public class Solver
|
||||
State = state,
|
||||
Action = null,
|
||||
SimulationCompletionState = Simulator.CompletionState,
|
||||
AvailableActions = Simulator.AvailableActionsHeuristic(strict),
|
||||
Scores = new()
|
||||
Data = new() { AvailableActions = Simulator.AvailableActionsHeuristic(strict) }
|
||||
});
|
||||
}
|
||||
|
||||
@@ -45,8 +44,7 @@ public class Solver
|
||||
State = newState,
|
||||
Action = action,
|
||||
SimulationCompletionState = Simulator.CompletionState,
|
||||
AvailableActions = Simulator.AvailableActionsHeuristic(strict),
|
||||
Scores = new()
|
||||
Data = new() { AvailableActions = Simulator.AvailableActionsHeuristic(strict) }
|
||||
};
|
||||
}
|
||||
|
||||
@@ -59,9 +57,9 @@ public class Solver
|
||||
if (node.IsComplete)
|
||||
return (currentIndex, node.CompletionState);
|
||||
|
||||
if (!node.AvailableActions.HasAction(action))
|
||||
if (!node.Data.AvailableActions.HasAction(action))
|
||||
return (currentIndex, CompletionState.InvalidAction);
|
||||
node.AvailableActions.RemoveAction(action);
|
||||
node.Data.AvailableActions.RemoveAction(action);
|
||||
|
||||
currentIndex = Tree.Insert(currentIndex, Execute(node.State, action, strict));
|
||||
}
|
||||
@@ -122,7 +120,7 @@ public class Solver
|
||||
|
||||
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;
|
||||
visits[j] = node.Visits;
|
||||
maxScores[j] = node.MaxScore;
|
||||
@@ -148,7 +146,7 @@ public class Solver
|
||||
{
|
||||
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;
|
||||
if (expandable || likelyTerminal)
|
||||
{
|
||||
@@ -156,7 +154,7 @@ public class Solver
|
||||
}
|
||||
|
||||
// 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)
|
||||
return (initialIndex, initialNode.CompletionState, initialNode.CalculateScore() ?? 0);
|
||||
|
||||
var randomAction = initialNode.AvailableActions.ElementAt(0);
|
||||
initialNode.AvailableActions.RemoveAction(randomAction);
|
||||
var randomAction = initialNode.Data.AvailableActions.ElementAt(0);
|
||||
initialNode.Data.AvailableActions.RemoveAction(randomAction);
|
||||
var expandedState = Execute(initialNode.State, randomAction, true);
|
||||
var expandedIndex = Tree.Insert(initialIndex, expandedState);
|
||||
|
||||
@@ -179,7 +177,7 @@ public class Solver
|
||||
{
|
||||
if (currentState.IsComplete)
|
||||
break;
|
||||
randomAction = currentState.AvailableActions.ElementAt(0);
|
||||
randomAction = currentState.Data.AvailableActions.ElementAt(0);
|
||||
actions.Add(randomAction);
|
||||
currentState = Execute(currentState.State, randomAction, true);
|
||||
}
|
||||
@@ -188,7 +186,7 @@ public class Solver
|
||||
var score = currentState.CalculateScore() ?? 0;
|
||||
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);
|
||||
return (terminalIndex, currentState.CompletionState, score);
|
||||
@@ -203,11 +201,7 @@ public class Solver
|
||||
while (true)
|
||||
{
|
||||
var currentNode = Tree.Get(currentIndex);
|
||||
var currentScores = currentNode.State.Scores;
|
||||
currentScores.Visits++;
|
||||
currentScores.ScoreSum += score;
|
||||
if (currentScores.MaxScore < score)
|
||||
currentScores.MaxScore = score;
|
||||
currentNode.State.Data.Scores.Visit(score);
|
||||
|
||||
if (currentIndex == targetIndex)
|
||||
break;
|
||||
@@ -233,7 +227,7 @@ public class Solver
|
||||
var node = Tree.Get(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);
|
||||
if (node.State.Action != null)
|
||||
actions.Add(node.State.Action.Value);
|
||||
@@ -264,7 +258,7 @@ public class Solver
|
||||
solver.Search(0);
|
||||
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);
|
||||
return (actions, solution_node.State);
|
||||
|
||||
Reference in New Issue
Block a user