Tree.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * Copyright (C) 2011-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5 *
6 * ArmarX is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * ArmarX is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * @package RobotComponents
19 * @author Raphael Grimm ( raphael dot grimm at kit dot edu )
20 * @date 2015
21 * @copyright http://www.gnu.org/licenses/gpl.txt
22 * GNU General Public License
23 */
24
25#include "Tree.h"
26
27#include <limits>
28
30
31#include "../../util/Metrics.h"
32#include "WorkerNode.h"
33
34namespace armarx::addirrtstar
35{
36 const NodeId Tree::ROOT_ID{0, 0};
37
38 Tree::Tree(const VectorXf& startCfg)
39 {
40 init(FullIceTree{FullNodeDataListList{FullNodeDataList{FullNodeData{
41 startCfg, //config
42 ROOT_ID, //parent
43 std::numeric_limits<Ice::Float>::infinity(), //radius;
44 0.f //fromParentCost
45 }}},
46 Ice::LongSeq{-1}},
47 AdaptiveDynamicDomainParameters{1, 1, 1},
48 -1 //since this tree does no updates the id is not important
49 );
50 }
51
52 //init
53 void
54 Tree::init(const FullIceTree& iceTree,
55 AdaptiveDynamicDomainParameters newaddParams,
56 std::size_t newWorkerId)
57 {
58 addParams = newaddParams;
59 workerId = newWorkerId;
60
61 //goals
62 goalNodes.clear();
63
64 //updates
65 localUpdates.clear();
67 appliedUpdateIds.clear();
68 appliedUpdateIds = iceTree.updateIds;
69
70 //get storage (+ default objects)
71 nodes.clear();
72 nodeCount = 0;
73
74 for (const auto& workerNodes : iceTree.nodes)
75 {
76 nodeCount += workerNodes.size();
77 nodes.emplace_back();
78 nodes.back().resize(workerNodes.size());
79 }
80
81 ARMARX_CHECK_EXPRESSION(nodes.size() == iceTree.nodes.size());
82
83 //copy node data
84 for (std::size_t wId = 0; wId < nodes.size(); ++wId)
85 {
86 for (std::size_t nId = 0; nId < nodes.at(wId).size(); ++nId)
87 {
88 NodeType& localNode = nodes.at(wId).at(nId);
89 const FullNodeData& iceNode = iceTree.nodes.at(wId).at(nId);
90 localNode.config = iceNode.config;
91 localNode.parent = iceNode.parent;
92 localNode.radius = iceNode.radius;
93 localNode.fromParentCost = iceNode.fromParentCost;
94 //register as child !!This adds root as child of root!!
95 getNode(localNode.parent)
96 .children.insert(
97 NodeId{static_cast<Ice::Long>(wId), static_cast<Ice::Long>(nId)});
98 }
99 }
100
101 //remove root as child of root
103 //push all costs from root
105 }
106
107 void
109 {
110 if (appliedUpdateIds.size() < count)
111 {
112 appliedUpdateIds.resize(count, -1);
113 }
114
115 if (nodes.size() < count)
116 {
117 nodes.resize(count);
118 }
119 }
120
121 //updating
122 bool
123 Tree::canApplyUpdate(const Update& u)
124 {
125 ARMARX_CHECK_EXPRESSION(u.dependetOnUpdateIds.size() <= appliedUpdateIds.size());
126
127 for (std::size_t i = 0; i < u.dependetOnUpdateIds.size(); ++i)
128 {
129 if (appliedUpdateIds.at(i) < u.dependetOnUpdateIds.at(i))
130 {
131 return false;
132 }
133 }
134
135 return true;
136 }
137
138 void
139 Tree::applyUpdate(const Update& u)
140 {
141 const auto workerId = getUpdatesWorkerId(u);
144 ARMARX_CHECK_EXPRESSION(u.dependetOnUpdateIds.size() <= appliedUpdateIds.size());
146
147 //do we need more worker?
148 if (workerId > nodes.size())
149 {
150 nodes.resize(workerId);
151 }
152
153 //apply all nodeUpdates
154 for (const auto& nodeCreationUpdate : u.nodes)
155 {
156 applyNodeCreationUpdate(nodeCreationUpdate, workerId);
157 }
158
159 //apply rewireUpdates
160 for (const auto& rewireUpdate : u.rewires)
161 {
162 applyRewireUpdate(rewireUpdate);
163 }
164
165 //apply radiusUpdates
166 for (const auto& radiusUpdate : u.radii)
167 {
168 applyRadiusUpdate(radiusUpdate);
169 }
170
171 //add new goal nodes
172 applyGoalReachedUpdates(u.newGoalNodes);
173 //increment status
175 }
176
177 void
178 Tree::sendCurrentUpdate(TreeUpdateInterfacePrx& prx)
179 {
180 ARMARX_CHECK_EXPRESSION(static_cast<Ice::Long>(getLocalUpdates().size()) - 1 ==
182 getCurrentUpdateNonConst().dependetOnUpdateIds = appliedUpdateIds;
183 prx->updateTree(getCurrentUpdate());
184 //begin the next update
186 //the update of this tree now counts as applied
188 }
189
190 void
191 Tree::applyRadiusUpdate(const RadiusUpdate& u)
192 {
193 if (u.increase)
194 {
195 doIncreaseRadius(u.node);
196 }
197 else
198 {
199 doDecreaseRadius(u.node);
200 }
201 }
202
203 void
204 Tree::applyRewireUpdate(const RewireUpdate& rewireUpdate)
205 {
206 //only rewire if it improves the cost
207 const NodeId& child = rewireUpdate.child;
208 const NodeId& newParent = rewireUpdate.newParent;
209
210 const auto costOld = getNode(child).fromStartCost;
211 const auto costNew = getNode(newParent).fromStartCost + rewireUpdate.fromNewParentCost;
212
213 if (costOld < costNew ||
214 ((costOld == costNew) &&
215 (rewireUpdate.newParent.workerId > getNode(child).parent.workerId)) //corner case
216 )
217 {
218 //skip this update
219 return;
220 }
221
222 doSetNodeParent(child, newParent, rewireUpdate.fromNewParentCost);
223 }
224
225 void
227 {
228 localUpdates.emplace_back();
230 //dependent update ids gets set when the update is send
231 }
232
233 //changing the tree from the rrt algorithm
234 NodeId
235 Tree::addNode(ConfigType cfg, const NodeId& parent, float fromParentCost)
236 {
237 //add to current tree update
238 createNewNodeCreationUpdate(cfg, parent, fromParentCost);
239 //update parent
240 increaseRadius(parent);
241 //apply update
242 return doAddNode(cfg, parent, fromParentCost, workerId);
243 }
244
245 //change the tree
246 void
247 Tree::pushCosts(const NodeId& root)
248 {
249 for (const auto& child : getNode(root).children)
250 {
251 getNode(child).fromStartCost =
253 pushCosts(child);
254 }
255 }
256
257 NodeId
259 const NodeId& parent,
260 float fromParentCost,
261 std::size_t workerId)
262 {
263 NodeId id = getNextNodeIdFor(workerId);
264 auto& parentNode = getNode(parent);
265 ++nodeCount;
266 nodes.at(workerId).emplace_back(NodeType{
267 cfg,
268 parent,
269 std::numeric_limits<float>::infinity(), //radius
270 fromParentCost,
271 parentNode.fromStartCost + fromParentCost,
272 std::set<NodeId>{} //children
273 });
274
275 parentNode.children.insert(id);
276
277 return id;
278 }
279
280 void
281 Tree::doSetNodeParent(const NodeId& child,
282 const NodeId& newParent,
283 float fromParentCost,
284 bool updateFromStartCost)
285 {
286 const auto oldParent = getNode(child).parent;
287 getNode(child).parent = newParent;
288 //update forward edges
289 getNode(oldParent).children.erase(child);
290 getNode(newParent).children.insert(child);
291 //update costs
292 getNode(child).fromParentCost = fromParentCost;
293
294 if (updateFromStartCost)
295 {
296 getNode(child).fromStartCost = fromParentCost + getNode(newParent).fromStartCost;
297 pushCosts(child);
298 }
299 }
300
301 void
302 Tree::doDecreaseRadius(const NodeId& id)
303 {
304 if (getNode(id).radius < std::numeric_limits<float>::infinity())
305 {
306 getNode(id).radius =
307 std::max(getNode(id).radius * (1.f - addParams.alpha), addParams.minimalRadius);
308 }
309 else
310 {
311 getNode(id).radius = addParams.initialBorderRadius;
312 }
313 }
314
315 //querry the tree
316 std::vector<std::pair<NodeId, float>>
318 {
319 //change k to fit size
320 //k = std::min(k, size());
321 //calc all distances and use nth element + resize + shrik to fit to get the best k
322 std::vector<std::pair<NodeId, float>> idDistanceVector{};
323 idDistanceVector.reserve(size());
324
325 for (std::size_t workerLevelIndex = 0; workerLevelIndex < nodes.size(); ++workerLevelIndex)
326 {
327 for (std::size_t nodeLevelIndex = 0; nodeLevelIndex < nodes.at(workerLevelIndex).size();
328 ++nodeLevelIndex)
329 {
330 const NodeId id{static_cast<Ice::Long>(workerLevelIndex),
331 static_cast<Ice::Long>(nodeLevelIndex)};
332 const auto dist =
333 WorkerNode::distance(nodes.at(workerLevelIndex).at(nodeLevelIndex).config, cfg);
334 idDistanceVector.emplace_back(id, dist);
335 }
336 }
337
338 ARMARX_CHECK_EXPRESSION(idDistanceVector.size() == size());
339
340 //if we have <= k elements we dont need to search the smalles elements.
341 if (k < idDistanceVector.size())
342 {
343 std::nth_element(
344 idDistanceVector.begin(),
345 idDistanceVector.begin() + (k - 1),
346 idDistanceVector.end(),
347 [](const std::pair<NodeId, float>& lhs, const std::pair<NodeId, float>& rhs)
348 { return lhs.second < rhs.second; });
349 idDistanceVector.resize(k);
350 //we could be using a large amount of memory => try to free it
351 idDistanceVector.shrink_to_fit();
352 }
353
354 return idDistanceVector;
355 }
356
358 Tree::getNode(const NodeId& id)
359 {
360 const auto worker = static_cast<std::size_t>(id.workerId);
361 const auto node = static_cast<std::size_t>(id.numberOfNode);
362 ARMARX_CHECK_EXPRESSION(worker < nodes.size());
363 ARMARX_CHECK_EXPRESSION(node < nodes.at(worker).size());
364 return nodes.at(worker).at(node);
365 }
366
367 const Tree::NodeType&
368 Tree::getNode(const NodeId& id) const
369 {
370 const auto worker = static_cast<std::size_t>(id.workerId);
371 const auto node = static_cast<std::size_t>(id.numberOfNode);
372 ARMARX_CHECK_EXPRESSION(worker < nodes.size());
373 ARMARX_CHECK_EXPRESSION(node < nodes.at(worker).size());
374 return nodes.at(worker).at(node);
375 }
376
377 NodeId
378 Tree::getIdOfIndex(std::size_t index) const
379 {
380 if (index >= size())
381 {
382 throw std::out_of_range{"index >= size"};
383 }
384
385 Ice::Long worker = 0;
386
387 for (const auto& workerNodes : nodes)
388 {
389 if (index < workerNodes.size())
390 {
391 return {worker, static_cast<Ice::Long>(index)};
392 }
393
394 //adjust
395 worker++;
396 index -= workerNodes.size();
397 }
398
399 //since this tree should never decrease its size this line of code should never be called!
400 //it could be called if a thread is concurrently changing the size of nodes,
401 //causing iterators to be invalidated (thus causing ub while iterating in for(...))
402 throw std::logic_error{"Tree size decreased during id calculation!"};
403 }
404
405 float
407 {
408 auto min_elem = getBestCostIt();
409 return ((min_elem == goalNodes.end())
410 ? std::numeric_limits<float>::infinity()
411 : getNode(min_elem->node).fromStartCost + min_elem->costToGoToGoal);
412 }
413
414 //querry for paths
415 PathWithCost
417 {
418 auto min_elem = getBestCostIt();
419 ARMARX_CHECK_EXPRESSION(min_elem != goalNodes.end());
420 const auto id = min_elem->node;
421 return PathWithCost{
422 getPathTo(id), getNode(id).fromStartCost + min_elem->costToGoToGoal, "bestPath"};
423 }
424
425 PathWithCost
426 Tree::getNthPathWithCost(std::size_t n) const
427 {
429 //for client side request the index should be in bounds
430 return PathWithCost{
431 getPathTo(goalNodes.at(n).node), getNthPathCost(n), "Path_" + to_string(n)};
432 }
433
434 NodeIdList
435 Tree::getNthPathIds(std::size_t n) const
436 {
438 NodeIdList pathIds;
439 auto id = goalNodes.at(n).node;
440
441 //build reversed path
442 while (id != ROOT_ID)
443 {
444 const auto& node = getNode(id);
445 pathIds.emplace_back(id);
446 id = node.parent;
447 }
448
449 //add the start node
450 pathIds.emplace_back(ROOT_ID);
451 std::reverse(pathIds.begin(), pathIds.end());
452 return pathIds;
453 }
454
455 VectorXfSeq
456 Tree::getPathTo(NodeId id) const
457 {
458 VectorXfSeq path;
459
460 //build reversed path
461 while (id != ROOT_ID)
462 {
463 const auto& node = getNode(id);
464 path.emplace_back(node.config);
465 id = node.parent;
466 }
467
468 //add the start node
469 path.emplace_back(getNode(ROOT_ID).config);
470 std::reverse(path.begin(), path.end());
471 return path;
472 }
473
474 FullIceTree
476 {
477 FullNodeDataListList allNodes{};
478 allNodes.resize(nodes.size());
479
480 for (std::size_t workerLevelIndex = 0; workerLevelIndex < nodes.size(); ++workerLevelIndex)
481 {
482 FullNodeDataList& iceWorkerNodes = allNodes.at(workerLevelIndex);
483 const auto& workerNodes = nodes.at(workerLevelIndex);
484 iceWorkerNodes.resize(workerNodes.size());
485
486 for (std::size_t nodeLevelIndex = 0; nodeLevelIndex < iceWorkerNodes.size();
487 ++nodeLevelIndex)
488 {
489 const auto& localNode = workerNodes.at(nodeLevelIndex);
490 FullNodeData& iceNode = iceWorkerNodes.at(nodeLevelIndex);
491 iceNode.config = localNode.config;
492 iceNode.parent = localNode.parent;
493 iceNode.radius = localNode.radius;
494 iceNode.fromParentCost = localNode.fromParentCost;
495 }
496 }
497
498 return FullIceTree{allNodes, appliedUpdateIds};
499 }
500
501 void
502 Tree::addPendingUpdate(const Update& u)
503 {
504 //fill up last spaces with no update (-1)
505 // increaseWorkerCountTo(u.dependetOnUpdateIds.size());//can't be called here because it invalidates iterators on nodes
506 const auto nodeId = getUpdatesWorkerId(u);
507 const auto updateSubId = getUpdatesSubId(u);
508
509 if (hasPendingUpdate(nodeId, updateSubId))
510 {
511 return;
512 }
513
514 pendingUpdatesLookupTable[std::make_pair(nodeId, updateSubId)] = pendingUpdates.size();
515 pendingUpdates.emplace_back(u);
516 }
517} // namespace armarx::addirrtstar
uint8_t index
NodeId addNode(ConfigType cfg, const NodeId &parent, float fromParentCost)
Adds a node to the tree.
Definition Tree.cpp:235
std::deque< GoalInfo > goalNodes
List of nodes able to reach the goal configuration.
Definition Tree.h:871
PathWithCost getNthPathWithCost(std::size_t n) const
Definition Tree.cpp:426
FullIceTree getIceTree() const
Definition Tree.cpp:475
void init(const FullIceTree &iceTree, AdaptiveDynamicDomainParameters newaddParams, std::size_t newWorkerId)
Initailizes the tree from the given tree.
Definition Tree.cpp:54
NodeId doAddNode(ConfigType cfg, const NodeId &parent, float fromParentCost, std::size_t workerId)
Adds a node to the tree.
Definition Tree.cpp:258
void applyNodeCreationUpdate(const NodeCreationUpdate &u, std::size_t workerId)
Applies a node creation update to the tree.
Definition Tree.h:321
Ice::Long getCurrentUpdateId() const
Definition Tree.h:274
void sendCurrentUpdate(TreeUpdateInterfacePrx &prx)
Sends the current update to the given proxy.
Definition Tree.cpp:178
NodeId getNextNodeIdFor(std::size_t workerId)
Definition Tree.h:829
AdaptiveDynamicDomainParameters addParams
The parameters of adaptive dynamic domain)
Definition Tree.h:876
std::deque< GoalInfo >::const_iterator getBestCostIt() const
Definition Tree.h:749
std::size_t workerId
The worker id of this trees owner.
Definition Tree.h:881
Update & getCurrentUpdateNonConst()
Definition Tree.h:304
void applyGoalReachedUpdates(const GoalInfoList newGoalNodes)
Applies multiple goal reached updates to the tree.
Definition Tree.h:337
NodeType & getNode(const NodeId &id)
Definition Tree.cpp:358
void applyUpdate(const Update &u)
Applies the given update.
Definition Tree.cpp:139
std::deque< Update > pendingUpdates
Updates to apply to the tree.
Definition Tree.h:890
void doSetNodeParent(const NodeId &child, const NodeId &newParent, float fromParentCost, bool updateFromStartCost=true)
Sets the parent node of child to parent.
Definition Tree.cpp:281
void doDecreaseRadius(const NodeId &id)
Decreases a node's radius.
Definition Tree.cpp:302
std::size_t nodeCount
The number of nodes in the rrt.
Definition Tree.h:885
PathWithCost getBestPath() const
Definition Tree.cpp:416
std::deque< Update > localUpdates
Updates created by this tree.
Definition Tree.h:861
VectorXf ConfigType
The type of configurations.
Definition Tree.h:56
float getBestCost() const
Definition Tree.cpp:406
std::deque< std::deque< NodeType > > nodes
Holds all nodes.
Definition Tree.h:867
Tree()=default
Default ctor.
void applyRadiusUpdate(const RadiusUpdate &u)
Applies a radius update to the tree.
Definition Tree.cpp:191
void doIncreaseRadius(const NodeId &id)
Increases a node's radius.
Definition Tree.h:628
void createNewNodeCreationUpdate(const ConfigType &cfg, const NodeId &parent, float fromParentCost)
Adds a new node creation update to the current update.
Definition Tree.h:365
Ice::LongSeq appliedUpdateIds
List of ids of applied updates.
Definition Tree.h:854
const Update & getCurrentUpdate() const
Definition Tree.h:294
PendingUpdateLookuptableType pendingUpdatesLookupTable
Speeds up lookup for available updates.
Definition Tree.h:897
NodeIdList getNthPathIds(std::size_t n) const
Definition Tree.cpp:435
void increaseWorkerCountTo(std::size_t count)
Increases the storage of all data structures to be appropriate for count workers.
Definition Tree.cpp:108
bool hasPendingUpdate(std::size_t workerId, std::size_t updateId) const
Definition Tree.h:183
const std::deque< Update > & getLocalUpdates() const
Definition Tree.h:160
NodeId getIdOfIndex(std::size_t index) const
Definition Tree.cpp:378
void pushCosts(const NodeId &root)
Updates fromStartCosts for all children from root.
Definition Tree.cpp:247
void increaseRadius(const NodeId &id)
Increases a node's radius.
Definition Tree.h:570
void addPendingUpdate(const Update &u)
Adds a new update to the list of pending updates.
Definition Tree.cpp:502
bool canApplyUpdate(const Update &u)
Definition Tree.cpp:123
std::size_t size() const
Definition Tree.h:694
float getNthPathCost(std::size_t n) const
Definition Tree.h:799
VectorXfSeq getPathTo(NodeId id) const
Definition Tree.cpp:456
static const NodeId ROOT_ID
The root node's id.
Definition Tree.h:839
void prepareNextUpdate()
Prepares the next update.
Definition Tree.cpp:226
void applyRewireUpdate(const RewireUpdate &rewireUpdate)
Applies a rewire update to the tree.
Definition Tree.cpp:204
std::vector< std::pair< NodeId, float > > getKNearestNeighboursAndDistances(const ConfigType &cfg, std::size_t k)
Definition Tree.cpp:317
static float distance(const ConfigType &from, const ConfigType &to)
Calculates the euclidian distance between from and to.
Definition WorkerNode.h:218
#define ARMARX_CHECK_EXPRESSION(expression)
This macro evaluates the expression and if it turns out to be false it will throw an ExpressionExcept...
const std::string & to_string(const std::string &s)
Represents a node of thr rrt.
Definition Tree.h:62
float radius
The node's radius.
Definition Tree.h:74
float fromStartCost
Cost of the path (sttart node, this node)
Definition Tree.h:82
NodeId parent
The node's parent.
Definition Tree.h:70
ConfigType config
The node's configuration.
Definition Tree.h:66
std::set< NodeId > children
Link to all children nodes.
Definition Tree.h:86
float fromParentCost
Cost of the edge (parent node, this node)
Definition Tree.h:78