NativeMultiHashMap <int, int> GetBinnedStateKeys(PlanGraph <int, StateInfo, int, ActionInfo, StateTransitionInfo> planGraph) { var binned = new NativeMultiHashMap <int, int>(planGraph.StateInfoLookup.Count(), Allocator.Persistent); using (var stateKeys = planGraph.StateInfoLookup.GetKeyArray(Allocator.Temp)) { foreach (var stateKey in stateKeys) { binned.Add(stateKey.GetHashCode(), stateKey); } } return(binned); }
/// <summary> /// Will build a tree with N subnodes per node = actionsPerState * resultsPerAction; /// A depth of 1 will result in a single root node /// </summary> internal static PlanGraph <int, StateInfo, int, ActionInfo, StateTransitionInfo> BuildTree(int actionsPerState = 2, int resultsPerAction = 2, int depth = 10) { Debug.Assert(depth > 0); // tree float probabilityPerResult = 1f / resultsPerAction; int nextStateIndex = 0; var subNodesPerNode = actionsPerState * resultsPerAction; int totalStates = GetTotalNodeCountForTreeDepth(subNodesPerNode, depth); var planGraph = new PlanGraph <int, StateInfo, int, ActionInfo, StateTransitionInfo>(totalStates, totalStates, totalStates); var builder = new PlanGraphBuilder <int, int> { planGraph = planGraph }; var queue = new NativeQueue <int>(Allocator.TempJob); // Add root int rootStateIndex = nextStateIndex; nextStateIndex++; builder.AddState(rootStateIndex); queue.Enqueue(rootStateIndex); for (int horizon = 0; horizon < depth - 1; horizon++) { var statesInHorizon = Math.Pow(actionsPerState * resultsPerAction, horizon); for (int i = 0; i < statesInHorizon; i++) { var state = queue.Dequeue(); var stateContext = builder.WithState(state); for (int actionIndex = 0; actionIndex < actionsPerState; actionIndex++) { var actionContext = stateContext.AddAction(actionIndex); for (int j = 0; j < resultsPerAction; j++) { var newStateIndex = nextStateIndex; nextStateIndex++; actionContext.AddResultingState(newStateIndex, probability: probabilityPerResult); queue.Enqueue(newStateIndex); } } } } queue.Dispose(); return(planGraph); }
public void SetupPartialPlanGraph() { m_PlanGraph = new PlanGraph <int, StateInfo, int, ActionInfo, StateTransitionInfo>(10, 10, 10); var builder = new PlanGraphBuilder <int, int>() { planGraph = m_PlanGraph }; var stateContext = builder.AddState(k_RootState); stateContext.AddAction(k_ActionOne).AddResultingState(k_StateOne); stateContext.AddAction(k_ActionTwo).AddResultingState(k_StateTwo); // Add first half of actions to simulate action system builder.WithState(k_StateOne).AddAction(k_ActionOne); builder.WithState(k_StateTwo).AddAction(k_ActionTwo); }
internal static void AddRootCycles(PlanGraph <int, StateInfo, int, ActionInfo, StateTransitionInfo> planGraph, int rootKey, int actionKey = -2) { var builder = new PlanGraphBuilder <int, int> { planGraph = planGraph }; var stateInfoLookup = planGraph.StateInfoLookup; using (var stateKeyArray = stateInfoLookup.GetKeyArray(Allocator.TempJob)) { foreach (var stateKey in stateKeyArray) { if (planGraph.ActionLookup.TryGetFirstValue(stateKey, out _, out _)) { builder.WithState(stateKey).AddAction(actionKey).AddResultingState(rootKey); } } } }
internal static PlanGraph <int, StateInfo, int, ActionInfo, StateTransitionInfo> BuildLattice(int midLatticeDepth = 10) { int nextStateIndex = 0; int totalStates = (int)Math.Pow(2, midLatticeDepth) * 2; var planGraph = new PlanGraph <int, StateInfo, int, ActionInfo, StateTransitionInfo>(totalStates, totalStates, totalStates); var builder = new PlanGraphBuilder <int, int> { planGraph = planGraph }; var queue = new NativeQueue <int>(Allocator.TempJob); // Add root int rootStateIndex = nextStateIndex; nextStateIndex++; builder.AddState(rootStateIndex); queue.Enqueue(rootStateIndex); for (int horizon = 0; horizon < midLatticeDepth; horizon++) { var statesInHorizon = Math.Pow(2, horizon); for (int i = 0; i < statesInHorizon; i++) { var state = queue.Dequeue(); var stateContext = builder.WithState(state); var leftIndex = i == 0 ? nextStateIndex : nextStateIndex - 1; nextStateIndex++; stateContext.AddAction(0).AddResultingState(leftIndex); if (i == 0) { queue.Enqueue(leftIndex); } var rightIndex = nextStateIndex; nextStateIndex++; stateContext.AddAction(1).AddResultingState(rightIndex); queue.Enqueue(rightIndex); } } for (int horizon = midLatticeDepth - 1; horizon >= 0; horizon--) { var statesInHorizon = Math.Pow(2, horizon); for (int i = 0; i < statesInHorizon; i++) { var state = queue.Dequeue(); var stateContext = builder.WithState(state); if (i > 0) { var leftIndex = nextStateIndex - 1; stateContext.AddAction(0).AddResultingState(leftIndex); //queue.Enqueue(leftIndex); } if (i < statesInHorizon - 1) { var rightIndex = nextStateIndex; nextStateIndex++; stateContext.AddAction(1).AddResultingState(rightIndex); queue.Enqueue(rightIndex); } } } queue.Dispose(); return(planGraph); }
public void MatchManyExistingStates() { const int kRootState = 0; const int kActionCount = 1000; PlanGraph <int, StateInfo, int, ActionInfo, StateTransitionInfo> planGraph = default; NativeMultiHashMap <int, int> binnedStateKeys = default; NativeQueue <int> newStatesQueue = default; NativeList <StateTransitionInfoPair <int, int, StateTransitionInfo> > statesToProcess = default; NativeQueue <int> newStatesToDestroy = default; Measure.Method(() => { var stateTransitionInfoLookup = planGraph.StateTransitionInfoLookup; var resultingStateLookup = planGraph.ResultingStateLookup; var expansionJob = new GraphExpansionJob <int, int, TestStateDataContext, int> { BinnedStateKeys = binnedStateKeys, NewStateTransitionInfoPairs = statesToProcess.AsDeferredJobArray(), ActionLookup = planGraph.ActionLookup.AsParallelWriter(), ActionInfoLookup = planGraph.ActionInfoLookup.AsParallelWriter(), StateTransitionInfoLookup = stateTransitionInfoLookup.AsParallelWriter(), ResultingStateLookup = resultingStateLookup.AsParallelWriter(), NewStates = newStatesQueue.AsParallelWriter(), PredecessorGraph = planGraph.PredecessorGraph.AsParallelWriter(), StateDataContext = new TestStateDataContext(), StatesToDestroy = newStatesToDestroy.AsParallelWriter(), }; expansionJob.Schedule(statesToProcess, default).Complete(); }).SetUp(() => { // One root node and all children nodes of a single depth planGraph = PlanGraphUtility.BuildTree(kActionCount, 1, 1); planGraph.ExpandBy(kActionCount, kActionCount); newStatesQueue = new NativeQueue <int>(Allocator.TempJob); newStatesToDestroy = new NativeQueue <int>(Allocator.TempJob); // Extend graph by one depth with the same number of actions / resulting states that loop back on themselves statesToProcess = new NativeList <StateTransitionInfoPair <int, int, StateTransitionInfo> >(kActionCount, Allocator.TempJob); for (var i = 0; i < kActionCount; i++) { statesToProcess.Add(new StateTransitionInfoPair <int, int, StateTransitionInfo>(kRootState, i, i, new StateTransitionInfo() { Probability = 1, TransitionUtilityValue = 1 })); } binnedStateKeys = GetBinnedStateKeys(planGraph); }).CleanUp(() => { planGraph.Dispose(); newStatesQueue.Dispose(); statesToProcess.Dispose(); binnedStateKeys.Dispose(); newStatesToDestroy.Dispose(); }).WarmupCount(1).MeasurementCount(30).IterationsPerMeasurement(1).Run(); PerformanceUtility.AssertRange(4.3, 6.25); }