-
Notifications
You must be signed in to change notification settings - Fork 16
/
EPEA_Star.cs
218 lines (183 loc) · 9.15 KB
/
EPEA_Star.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System;
using System.Diagnostics;
namespace mapf;
class EPEA_Star : A_Star
{
protected int expandedFullStates;
protected int accExpandedFullStates;
public EPEA_Star(IHeuristicCalculator<WorldState> heuristic = null, bool mstar = false,
bool mstarShuffle = false)
: base(heuristic, mstar, mstarShuffle)
{
if (Constants.costFunction == Constants.CostFunction.MAKESPAN ||
Constants.costFunction == Constants.CostFunction.MAKESPAN_THEN_SUM_OF_COSTS
)
{
throw new NotImplementedException("Makespan support isn't implemented at the moment. Use A*+OD for now.");
}
}
override protected WorldState CreateSearchRoot(int minDepth = -1, int minCost = -1, MDDNode mddNode = null)
{
var root = new WorldStateForPartialExpansion(this.instance.agents, minDepth, minCost, mddNode);
root.sic = (int)SumIndividualCosts.h(root, this.instance);
return root;
}
protected override WorldState CreateSearchNode(WorldState from)
{
return new WorldStateForPartialExpansion((WorldStateForPartialExpansion)from);
}
override public string GetName() { return "EPE" + base.GetName(); }
public override void Setup(ProblemInstance problemInstance, int minDepth, Run runner,
ConflictAvoidanceTable CAT = null,
ISet<CbsConstraint> constraints = null, ISet<CbsConstraint> positiveConstraints = null,
int minCost = -1, int maxCost = int.MaxValue, MDD mdd = null)
{
base.Setup(problemInstance, minDepth, runner, CAT, constraints, positiveConstraints,
minCost, maxCost, mdd);
this.expandedFullStates = 0;
}
public override void Expand(WorldState nodeP)
{
var node = (WorldStateForPartialExpansion)nodeP;
bool wasAlreadyExpanded = true;
if (node.IsAlreadyExpanded() == false)
{
node.calcSingleAgentDeltaFs(instance, this.IsValid);
expandedFullStates++;
node.alreadyExpanded = true;
wasAlreadyExpanded = false;
//node.hBonus = 0; // Locking any hbonus that doesn't come from partial expansion
node.targetDeltaF = 0; // Assuming a consistent heuristic (as done in the paper), the min delta F is zero.
node.remainingDeltaF = node.targetDeltaF; // Just for the following hasChildrenForCurrentDeltaF call.
while (node.hasMoreChildren() && node.hasChildrenForCurrentDeltaF() == false) // DeltaF=0 may not be possible if all agents have obstacles between their location and the goal
{
node.targetDeltaF++;
node.remainingDeltaF = node.targetDeltaF;
}
if (node.hasMoreChildren() == false) // Node has no possible children at all
{
node.Clear();
return;
}
}
// If this node was already expanded, notice its h was updated, so the deltaF refers to its original H
do
{
if (debug)
Debug.WriteLine($"Generating children with target deltaF={node.targetDeltaF}. Actual delta F may be lower because the parent node may have various H boosts.");
base.Expand(node);
// base.Expand computes every child's h value from scratch, even though we could compute it incrementally from intermediate nodes
if (node.IsAlreadyExpanded() == false)
{
// Node was cleared during expansion.
// It's unnecessary and unsafe to continue to prepare it for the next partial expansion.
return;
// TODO: Is there a prettier way to do this?
}
//if (wasAlreadyExpanded)
//{
// // Only doing it after expansion so that the children get the higher h
// node.h -= node.targetDeltaF; // This way we retain any BPMX or other h boosts, allowing the new targetDeltaF to fully add to the base h
// node.hBonus -= node.targetDeltaF;
//}
// FIXME: Why is this commented out? It was the only use of wasAlreadyExpanded, so if
// removing the above is correct, also remove wasAlreadyExpanded.
// This node's target delta F was exhausted - increment it until a target delta F with actual children is found
do
{
node.targetDeltaF++;
node.remainingDeltaF = node.targetDeltaF; // Just for the following hasChildrenForCurrentDeltaF call.
} while (node.hasMoreChildren() && node.hasChildrenForCurrentDeltaF() == false);
} while (node.hasMoreChildren() && node.g + node.sic + node.targetDeltaF <= node.minGoalCost); // Generate more children immediately if we have a lower bound on the solution depth
if (node.hasMoreChildren() && node.hasChildrenForCurrentDeltaF() && node.g + node.sic + node.targetDeltaF <= this.maxSolutionCost)
{
// Assuming the heuristic used doesn't give a lower estimate than SIC for each and every one of the node's children,
// (an ok assumption since SIC is quite basic, no heuristic we use is ever worse than it)
// then the current target deltaF is really exhausted, since the deltaG is always correct,
// and the deltaH predicted by SIC is less than or equal to the finalDeltaH.
// So if the heuristic gives the same estimate as SIC for this node
// (and that mainly happens when SIC happens to give a perfect estimate),
// we can increment the node's f to g+SIC+targetDeltaH
// Re-insert node into open list
openList.Add(node);
if (this.debug)
{
Debug.WriteLine($"Re-inserting node {node.generated} into the open list (with targetDeltaF: {node.targetDeltaF})");
Debug.WriteLine("");
}
}
else
{
node.Clear();
//TODO: Think about this.surplusNodesAvoided. Can it be correctly incremented?
}
}
protected override List<WorldState> ExpandOneAgent(List<WorldState> intermediateNodes, int agentIndex)
{
// Expand the agent
List<WorldState> generated = base.ExpandOneAgent(intermediateNodes, agentIndex);
// Update target F
foreach (WorldState simpleLookingNode in generated) {
var node = (WorldStateForPartialExpansion)simpleLookingNode;
node.UpdateRemainingDeltaF(agentIndex);
}
// Prune nodes that can't get to the target F - even before their real H is calculated!
generated = generated.Where(
node => ((WorldStateForPartialExpansion)node).remainingDeltaF != ushort.MaxValue && // last move was good
((WorldStateForPartialExpansion)node).hasChildrenForCurrentDeltaF(agentIndex+1)
).ToList();
return generated;
}
protected override bool ProcessGeneratedNode(WorldState currentNode)
{
bool ret = base.ProcessGeneratedNode(currentNode);
var node = (WorldStateForPartialExpansion)currentNode;
node.ClearExpansionData();
node.sic = (int)SumIndividualCosts.h(node, this.instance);
// We defer calling the expensive calcSingleAgentDeltaFs to when the node is expanded, which means we might only then find out the node's current
// target deltaF=0 is not possibe.
return ret;
}
public override void OutputStatisticsHeader(TextWriter output)
{
base.OutputStatisticsHeader(output);
output.Write(this.ToString() + " Expanded Full States");
output.Write(Run.RESULTS_DELIMITER);
}
public override void OutputStatistics(TextWriter output)
{
base.OutputStatistics(output);
Console.WriteLine("Expanded Full States: {0}", this.expandedFullStates);
output.Write(this.expandedFullStates + Run.RESULTS_DELIMITER);
}
public override int NumStatsColumns
{
get
{
return 1 + base.NumStatsColumns;
}
}
public override void ClearAccumulatedStatistics()
{
base.ClearAccumulatedStatistics();
this.accExpandedFullStates = 0;
}
public override void AccumulateStatistics()
{
base.AccumulateStatistics();
this.accExpandedFullStates += this.expandedFullStates;
}
public override void OutputAccumulatedStatistics(TextWriter output)
{
base.OutputAccumulatedStatistics(output);
Console.WriteLine(this.ToString() + " Accumulated Total Expanded Full States (Low-Level): {0}", this.accExpandedFullStates);
output.Write(this.accExpandedFullStates + Run.RESULTS_DELIMITER);
}
public override float GetEffectiveBranchingFactor()
{
return ((float)this.GetGenerated() - 1) / this.expandedFullStates;
}
}