17 #define DEBUG 0 // set debug mode
21 #define debug_print(fmt, ...) printf(fmt,__VA_ARGS__)
23 #define debug_print(fmt, ...) do {} while (0)
27 template <
class state>
37 template <
class state,
class action,
class environment,
bool DFS = true>
40 IBEX(uint64_t minGrow, uint64_t maxGrow,
double growthRate,
bool exponential)
41 :c1(minGrow), c2(maxGrow), gamma(growthRate), oracle(false), exponentialGrowth(exponential) {}
42 void GetPath(environment *env, state from, state to,
43 std::vector<action> &thePath);
44 void GetPath(environment *env,
Heuristic<state> *heuristic, state from, state to,
45 std::vector<action> &thePath);
46 void Dovetail(environment *env,
Heuristic<state> *heuristic, state from, state to,
47 std::vector<action> &thePath);
72 double GCost(
const state &s1,
const state &s2)
73 {
return env->GCost(s1, s2); }
74 double GCost(
const state &s,
const action &a)
75 {
return env->GCost(s, a); }
77 {
return h->HCost(s, goal); }
80 searchBounds &sd, uint64_t nodeLimit, action forbidden);
84 void ExtractPathToStartFromID(uint64_t
node, std::vector<state> &thePath);
109 template <
class state,
class action,
class environment,
bool DFS>
111 std::vector<action> &thePath)
113 GetPath(env, env, from, to, thePath);
116 template <
class state,
class action,
class environment,
bool DFS>
118 std::vector<action> &thePath)
124 solutionPath.clear();
125 solutionCost = DBL_MAX;
130 uint64_t currentNodesUsed;
136 debug_print(
"IBEX: Base search: f: %1.5f, cost limit ∞, target [%" PRId64
", %" PRId64
"]\n", solutionInterval.
lowerBound, c1*nodeLB, c2*nodeLB);
141 if (currentNodesUsed >= c1*nodeLB)
143 nodeLB = currentNodesUsed;
149 (currentNodesUsed >= c1*nodeLB && currentNodesUsed < c2*nodeLB)))
166 if (exponentialGrowth)
170 nextCost = solutionInterval.
lowerBound * gamma;
176 solutionInterval &= LowLevelSearch(nextCost, c2*nodeLB, currentNodesUsed);
179 nodeLB =
std::max(currentNodesUsed, c1*nodeLB);
185 thePath = solutionPath;
186 debug_print(
"Found solution cost %1.5f\n", solutionCost);
190 template <
class state,
class action,
class environment,
bool DFS>
193 state currState = start;
196 debug_print(
" --+DFBnB f: %1.5f; nodes: ∞; ", costLimit);
201 debug_print(
" --+DFBnB f: %1.5f; nodes: %" PRId64
"; ", costLimit, nodeLimit);
210 sd = DFBNBHelper(currState, 0, costLimit, sd, nodeLimit, a);
211 totalNodesExpanded += sd.
nodes;
214 if (sd.
nodes >= nodeLimit)
229 nodesUsed = sd.
nodes;
232 debug_print(
"%" PRId64
" (new) %" PRId64
" (total), solution range: [%1.5f, ∞] ", nodesUsed, totalNodesExpanded, v.
lowerBound);
239 if (solutionCost != DBL_MAX)
252 template <
class state,
class action,
class environment,
bool DFS>
256 double currF = pathCost+HCost(currState);
258 if (
fequal(dfsLowerBound, solutionCost) && !oracle)
276 if (sd.
nodes >= nodeLimit)
278 if (env->GoalTest(currState, goal))
280 if (
fless(currF, solutionCost))
282 solutionPath = currPath;
283 solutionCost = currF;
288 std::vector<action> &acts = *actCache.getItem();
289 env->GetActions(currState, acts);
291 totalNodesTouched+=acts.size();
293 for (
size_t x = 0; x < acts.size(); x++)
295 if (acts[x] == forbidden && currPath.size() > 0)
297 double edgeCost = GCost(currState, acts[x]);
298 env->ApplyAction(currState, acts[x]);
299 currPath.push_back(acts[x]);
300 action rev = acts[x];
301 env->InvertAction(rev);
302 sd = DFBNBHelper(currState, pathCost+edgeCost, costLimit, sd, nodeLimit, rev);
304 env->UndoAction(currState, acts[x]);
306 actCache.returnItem(&acts);
310 template <
class state,
class action,
class environment,
bool DFS>
317 LowLevelSearch(solutionCost, -1, nodesUsed);
322 template <
class state,
class action,
class environment,
bool DFS>
325 if (nodeLimit == -1ull && costLimit == DBL_MAX)
329 else if (nodeLimit == -1)
331 debug_print(
" --+BFHS f: %1.5f; nodes: ∞; ", costLimit);
335 debug_print(
" --+BFHS f: %1.5f; nodes: %" PRId64
"; ", costLimit, nodeLimit);
343 q.Reset(env->GetMaxHash());
346 q.AddOpenNode(start, env->GetStateHash(start), 0.0, 0.0, (uint64_t)0);
348 while (sd.
nodes < nodeLimit && q.OpenSize() > 0)
354 uint64_t nodeid = q.Close();
356 totalNodesExpanded++;
358 double nextf = q.Lookup(nodeid).g + HCost(q.Lookup(nodeid).data);
368 if (env->GoalTest(q.Lookup(nodeid).data, goal))
370 solutionCost = q.Lookup(nodeid).g;
371 ExtractPathToStartFromID(nodeid, solutionStates);
373 reverse(solutionStates.begin(), solutionStates.end());
375 for (
int x = 0; x < solutionStates.size()-1; x++)
377 solutionPath.push_back(env->GetAction(solutionStates[x], solutionStates[x+1]));
380 nodesUsed = sd.
nodes;
381 return {q.Lookup(nodeid).g, q.Lookup(nodeid).g};
386 neighborID.resize(0);
387 neighborLoc.resize(0);
392 env->GetSuccessors(q.Lookup(nodeid).data, neighbors);
395 for (
size_t x = 0; x < neighbors.size(); x++)
398 neighborLoc.push_back(q.Lookup(env->GetStateHash(neighbors[x]), theID));
399 neighborID.push_back(theID);
400 edgeCosts.push_back(GCost(q.Lookup(nodeid).data, neighbors[x]));
404 for (
size_t x = 0; x < neighbors.size(); x++)
408 double childGCost = q.Lookup(nodeid).g+edgeCosts[x];
409 double childFCost = childGCost+HCost(neighbors[x]);
416 switch (neighborLoc[x])
421 if (
fless(childGCost, q.Lookup(neighborID[x]).g))
423 q.Lookup(neighborID[x]).parentID = nodeid;
424 q.Lookup(neighborID[x]).g = childGCost;
425 q.KeyChanged(neighborID[x]);
430 q.AddOpenNode(neighbors[x],
431 env->GetStateHash(neighbors[x]),
443 if (sd.
nodes >= nodeLimit)
453 nodesUsed = sd.
nodes;
457 debug_print(
"%" PRId64
" (new) %" PRId64
" (total), solution range: [%1.5f, ∞]\n", nodesUsed, totalNodesExpanded, v.
lowerBound);
469 template <
class state,
class action,
class environment,
bool DFS>
471 std::vector<state> &thePath)
475 thePath.push_back(q.Lookup(
node).data);
477 }
while (q.Lookup(
node).parentID !=
node);
478 thePath.push_back(q.Lookup(
node).data);
482 template <
class state,
class action,
class environment,
bool DFS>
486 return DFBNB(costLimit, nodeLimit, nodesUsed);
488 return BFHS(costLimit, nodeLimit, nodesUsed);
498 int T()
const {
return r * pow(2,
k);}
501 template <
class state,
class action,
class environment,
bool DFS>
503 std::vector<action> &thePath)
509 solutionPath.clear();
510 solutionCost = DBL_MAX;
518 std::map<int,double> lookup;
520 std::priority_queue<UBSNode> q;
524 double low = HCost(from);
532 int b = pow(alpha,k);
547 if (lookup.find(k) == lookup.end()) {
550 double high = lookup[k];
554 debug_print(
"Running (k=%d, r=%d) with budget %d; [global] low = %f, [loca] high = %f\n", k, r, b, low, high);
558 debug_print(
"Running (k=%d, r=%d) with budget %d; [global] low = %f, [loca] high = ∞\n", k, r, b, low);
565 if (exponentialGrowth)
566 C = low + (1<<(r-1));
574 else if (high != DBL_MAX) {
575 C = (low + high) / 2.0;
593 if (
flesseq(solutionCost, low))
595 thePath = solutionPath;
596 debug_print(
"proven solution cost %f\n", solutionCost);