GraphMemorySegment.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
19 * @author
20 * @date
21 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22 * GNU General Public License
23 */
24#include "GraphMemorySegment.h"
25
26#include <limits>
27#include <unordered_map>
28#include <unordered_set>
29
31
33
34memoryx::GraphMemorySegment::GraphMemorySegment(CollectionInterfacePrx entityCollection,
36 bool useMongoIds) :
37 PersistentEntitySegment(entityCollection, ic, useMongoIds), GraphMemorySegmentBase()
38{
39}
40
44
45Ice::StringSeq
46memoryx::GraphMemorySegment::getScenes(const Ice::Current& c) const
47{
48 std::unordered_set<std::string> names{};
49 const auto ids = getAllEntityIds(c);
50
51 for (const auto& id : ids)
52 {
53 auto elem = getNodeById(id, c);
54
55 if (elem)
56 {
57 names.insert(elem->getScene());
58 }
59 }
60
61 return Ice::StringSeq{names.begin(), names.end()};
62}
63
64memoryx::GraphNodeBaseList
65memoryx::GraphMemorySegment::getNodesByScene(const std::string& sceneName, const Ice::Current& c)
66{
67 memoryx::GraphNodeBaseList result{};
69
70 for (auto& elem : filtered)
71 {
72 auto ptr = memoryx::GraphNodeBasePtr::dynamicCast(elem);
73
74 if (ptr)
75 {
76 result.push_back(ptr);
77 }
78 }
79
80 return result;
81}
82
83memoryx::GraphNodeBasePtr
84memoryx::GraphMemorySegment::getNodeById(const std::string& entityId, const Ice::Current& c)
85{
86 return memoryx::GraphNodeBasePtr::dynamicCast(getEntityById(entityId, c));
87}
88
89memoryx::GraphNodeBasePtr
90memoryx::GraphMemorySegment::getNodeById(const std::string& entityId, const Ice::Current& c) const
91{
92 return memoryx::GraphNodeBasePtr::dynamicCast(getEntityById(entityId, c));
93}
94
95memoryx::GraphNodeBasePtr
96memoryx::GraphMemorySegment::getNodeByName(const std::string& entityName, const Ice::Current& c)
97{
98 return memoryx::GraphNodeBasePtr::dynamicCast(getEntityByName(entityName, c));
99}
100
101memoryx::GraphNodeBaseList
103{
104 memoryx::GraphNodeBaseList nodes{};
105 const auto ids = getAllEntityIds(c);
106
107 for (const auto& id : ids)
108 {
109 auto elem = getNodeById(id, c);
110
111 if (elem)
112 {
113 nodes.push_back(elem);
114 }
115 }
116
117 return nodes;
118}
119
120void
121memoryx::GraphMemorySegment::clearScene(const std::string& sceneName, const Ice::Current& c)
122{
123 ARMARX_INFO_S << "GraphMemorySegment: clearing scene " << sceneName << "...";
125
126 for (auto& elem : filtered)
127 {
128 removeEntity(elem->getId(c));
129 }
130
131 ARMARX_INFO_S << "GraphMemorySegment: clearing scene " << sceneName << ". Removed "
132 << filtered.size() << " elements";
133}
134
135bool
136memoryx::GraphMemorySegment::removeNode(const std::string& nodeId, const Ice::Current&)
137{
138 GraphNodeBasePtr node = getNodeById(nodeId);
139 auto allnodes = getAllNodes();
140 for (auto& curNode : allnodes)
141 {
142 if (curNode->removeAdjacentNode(nodeId))
143 {
144 updateEntity(curNode->getId(), curNode);
145 }
146 }
147 if (node)
148 {
149 removeEntity(nodeId);
150 return true;
151 }
152 return false;
153}
154
155bool
156memoryx::GraphMemorySegment::removeEdge(const std::string& startNodeId,
157 const std::string& endNodeId,
158 const Ice::Current&)
159{
160 GraphNodeBasePtr startNode = getNodeById(startNodeId);
161 if (startNode)
162 {
163 if (startNode->removeAdjacentNode(endNodeId))
164 {
165 updateEntity(startNodeId, startNode);
166 return true;
167 }
168 }
169 return false;
170}
171
172std::string
173memoryx::GraphMemorySegment::addNode(const memoryx::GraphNodeBasePtr& node, const Ice::Current& c)
174{
175 ARMARX_INFO_S << "GraphMemorySegment adding node " << (node ? node->getName() : "NULL node");
176 return addEntity(node, c);
177}
178
179bool
180memoryx::GraphMemorySegment::addEdge(const std::string& fromId,
181 const std::string& toId,
182 const Ice::Current& c)
183{
184 ARMARX_INFO_S << "GraphMemorySegment adding edge " << fromId << " -> " << toId << "...";
185 auto fromNode = getNodeById(fromId, c);
186
187 if (!fromNode)
188 {
189 ARMARX_ERROR_S << "GraphMemorySegment addEdge: Id " << fromId
190 << " does not reference a node";
191 return false;
192 }
193
194 auto toNode = getNodeById(toId, c);
195
196 if (!toNode)
197 {
198 ARMARX_ERROR_S << "GraphMemorySegment addEdge: Id " << toId << " does not reference a node";
199 return false;
200 }
201
202 //this does not change the data stored in the segment
203 fromNode->addAdjacentNode(getEntityRefById(toId, c), c);
204 //update memory
205 updateEntity(fromId, fromNode, c);
206 ARMARX_INFO_S << "GraphMemorySegment adding edge " << fromId << " -> " << toId << "done!";
207 return true;
208}
209
210bool
211memoryx::GraphMemorySegment::hasScene(const ::std::string& sceneName, const ::Ice::Current& c)
212{
214 0;
215}
216
217bool
218memoryx::GraphMemorySegment::hasNodeWithName(const ::std::string& sceneName,
219 const ::std::string& nodeName,
220 const ::Ice::Current&)
221{
222 auto nodes = getNodesByScene(sceneName);
223
224 for (const auto& node : nodes)
225 {
226 if (node->getName() == nodeName)
227 {
228 return true;
229 }
230 }
231
232 return false;
233}
234
235memoryx::GraphNodeBasePtr
237 const ::std::string& nodeName,
238 const ::Ice::Current&)
239{
240 auto nodes = getNodesByScene(sceneName);
241
242 for (const auto& node : nodes)
243 {
244 if (node->getName() == nodeName)
245 {
246 return node;
247 }
248 }
249
250 return memoryx::GraphNodeBasePtr{};
251}
252
253//std::string memoryx::GraphMemorySegment::getIdOfNearestNode(const ::std::string& sceneName, ::Ice::Float x, ::Ice::Float y, const ::Ice::Current&)
254//{
255// auto distQuad = [x, y](armarx::FramedPoseBasePtr && node)
256// {
257// float deltaX = x - node->position->x;
258// float deltaY = y - node->position->y;
259// return deltaX * deltaX + deltaY * deltaY;
260// };
261
262// auto nodes = getNodesByScene(sceneName);
263// std::string nearestId {};
264// float distance = std::numeric_limits<float>::max();
265
266// for (const auto& nodeBase : nodes)
267// {
268// GraphNodePtr node = GraphNodePtr::dynamicCast(nodeBase);
269// if (node->isMetaEntity())
270// {
271// continue;
272// }
273
274// if (node->getPose()->frame == armarx::GlobalFrame || node->getPose()->frame.empty())
275// {
276// float currentDistance = distQuad(node->getPose());
277
278// if (currentDistance < distance)
279// {
280// nearestId = node->getId();
281// distance = currentDistance;
282// }
283// }
284// }
285
286// if (nearestId.empty())
287// {
288// ARMARX_WARNING_S << "Could not find nearest node for " << VAROUT(x) << VAROUT(y) << VAROUT(type) << VAROUT(sceneName);
289// }
290
291// return nearestId;
292//}
293
294memoryx::GraphNodeBaseList
295memoryx::GraphMemorySegment::aStar(const ::std::string& idFrom,
296 const ::std::string& idTo,
297 const ::Ice::Current&)
298{
299 //check everything
300 auto start = getNodeById(idFrom);
301 auto goal = getNodeById(idTo);
302
303 if (!start)
304 {
305 std::stringstream s{};
306 s << "aStar: Node from: No node with ID: " << idFrom;
307 ARMARX_ERROR_S << s.str();
308 throw memoryx::EntityNotFoundException{s.str()};
309 }
310
311 if (!goal)
312 {
313 std::stringstream s{};
314 ARMARX_ERROR_S << s.str();
315 s << "aStar: Node to: No node with ID: " << idTo;
316 throw memoryx::EntityNotFoundException{s.str()};
317 }
318
319 ARMARX_VERBOSE_S << "memoryx::GraphMemorySegment::aStar from " << start->getPose()->frame
320 << " to " << goal->getPose()->frame;
321
322
323 if (start->getScene() != goal->getScene())
324 {
325 std::stringstream s{};
326 ARMARX_ERROR_S << s.str();
327 s << "aStar: Nodes from and to belong to different scenes: " << start->getScene() << " | "
328 << goal->getScene();
329 throw armarx::InvalidArgumentException{s.str()};
330 }
331
332 /// TODO add some mutex
333 //copy state (in case the state gets altered during search) + memoryx::GraphNodeBasePtr now can be compared (ptr addresses are unique)
334 std::unordered_map<std::string, memoryx::GraphNodeBasePtr> nodes{};
335
336 for (const auto& node : getNodesByScene(start->getScene()))
337 {
338 nodes[node->getId()] = node;
339 }
340
341 //override start and goal to keep uniqueness
342 nodes[start->getId()] = start;
343 nodes[goal->getId()] = goal;
344
345
346 //init
347 auto dist = [](memoryx::GraphNodeBasePtr n1, memoryx::GraphNodeBasePtr n2)
348 {
349 auto p1 = n1->getPose();
350 auto p2 = n2->getPose();
351 const float dX = p1->position->x - p2->position->x;
352 const float dY = p1->position->y - p2->position->y;
353 return std::sqrt(dX * dX + dY * dY);
354 };
355
356 memoryx::GraphNodeBaseList path{};
357 memoryx::GraphNodeBaseList closedSet{};
358 memoryx::GraphNodeBaseList openSet{};
359 openSet.push_back(start);
360
361 std::unordered_map<std::string, float> gScore;
362 gScore[start->getId()] = 0.f;
363 std::unordered_map<std::string, float> fScore;
364 fScore[start->getId()] = gScore.at(start->getId()) + dist(start, goal);
365 std::unordered_map<std::string, memoryx::GraphNodeBasePtr> cameFrom;
366 cameFrom[goal->getId()] = start; //in case start==goal
367
368 ARMARX_VERBOSE_S << "memoryx::GraphMemorySegment::aStar from " << idFrom << " to " << idTo
369 << ". Start path search.";
370
371 while (!openSet.empty())
372 {
373 //find best neighbour
374 auto currentIT = std::min_element(
375 openSet.begin(),
376 openSet.end(),
377 [&fScore](const memoryx::GraphNodeBasePtr& a, const memoryx::GraphNodeBasePtr& b)
378 { return fScore.at(a->getId()) < fScore.at(b->getId()); });
379 assert(currentIT != openSet.end());
380 memoryx::GraphNodeBasePtr current = *currentIT;
381
382
383 //check if done
384 if (current->getId() == goal->getId())
385 {
386 auto cameFromNode = goal;
387
388 while (cameFromNode->getId() != start->getId())
389 {
390 path.insert(path.begin(), cameFromNode);
391 cameFromNode = cameFrom.at(cameFromNode->getId());
392 }
393
394 path.insert(path.begin(), start);
395 break;
396 }
397
398 openSet.erase(currentIT);
399 closedSet.push_back(current);
400
401 //update
402 for (int i = 0; i < current->getOutdegree(); i++)
403 {
404 auto neighbor = nodes.at(current->getAdjacentNode(i)->getEntity()->getId());
405
406 assert(neighbor);
407
408 if (std::find(closedSet.begin(), closedSet.end(), neighbor) != closedSet.end())
409 {
410 continue;
411 }
412
413 float tentativeGScore = gScore.at(current->getId()) + dist(current, neighbor);
414 bool notInOS = std::find(openSet.begin(), openSet.end(), neighbor) == openSet.end();
415
416 if (notInOS || tentativeGScore < gScore.at(neighbor->getId()))
417 {
418 cameFrom[neighbor->getId()] = current;
419 gScore[neighbor->getId()] = tentativeGScore;
420 fScore[neighbor->getId()] = tentativeGScore + dist(neighbor, goal);
421
422 if (notInOS)
423 {
424 openSet.push_back(neighbor);
425 }
426 }
427 }
428 }
429
430 ARMARX_VERBOSE_S << "memoryx::GraphMemorySegment::aStar from " << idFrom << " to " << idTo
431 << ". Done!";
432 return path;
433}
constexpr T c
memoryx::GraphNodeBaseList getNodesByScene(const std::string &sceneName, const Ice::Current &c=Ice::emptyCurrent) override
bool addEdge(const std::string &fromId, const std::string &toId, const Ice::Current &c=Ice::emptyCurrent) override
memoryx::GraphNodeBaseList getAllNodes(const Ice::Current &c=Ice::emptyCurrent) override
::memoryx::GraphNodeBaseList aStar(const ::std::string &idFrom, const ::std::string &idTo, const ::Ice::Current &=Ice::emptyCurrent) override
Ice::StringSeq getScenes(const Ice::Current &c=Ice::emptyCurrent) const override
::memoryx::GraphNodeBasePtr getNodeFromSceneByName(const ::std::string &sceneName, const ::std::string &nodeName, const ::Ice::Current &=Ice::emptyCurrent) override
GraphMemorySegment(CollectionInterfacePrx entityCollection, Ice::CommunicatorPtr ic, bool useMongoIds=true)
bool hasScene(const ::std::string &sceneName, const ::Ice::Current &c=Ice::emptyCurrent) override
bool hasNodeWithName(const ::std::string &sceneName, const ::std::string &nodeName, const ::Ice::Current &=Ice::emptyCurrent) override
bool removeNode(const std::string &, const Ice::Current &) override
memoryx::GraphNodeBasePtr getNodeByName(const std::string &entityName, const Ice::Current &c=Ice::emptyCurrent) override
void clearScene(const std::string &sceneName, const Ice::Current &c=Ice::emptyCurrent) override
std::string addNode(const memoryx::GraphNodeBasePtr &node, const Ice::Current &c=Ice::emptyCurrent) override
memoryx::GraphNodeBasePtr getNodeById(const std::string &entityId, const Ice::Current &c=Ice::emptyCurrent) override
bool removeEdge(const std::string &startNodeId, const std::string &endNodeId, const Ice::Current &) override
static const std::string GRAPH_NODE_ATTR_SCENE
Definition GraphNode.h:33
PersistentEntitySegment(CollectionInterfacePrx entityCollection, Ice::CommunicatorPtr ic, bool useMongoIds=true)
std::string addEntity(const EntityBasePtr &entity, const ::Ice::Current &c=Ice::emptyCurrent) override
addEntity add new entity and return the newly generated entity ID
EntityBasePtr getEntityById(const ::std::string &entityId, const ::Ice::Current &=Ice::emptyCurrent) const override
EntityIdList getAllEntityIds(const ::Ice::Current &=Ice::emptyCurrent) const override
EntityBaseList getEntitiesByAttrValue(const ::std::string &attrName, const ::std::string &attrValue, const ::Ice::Current &=Ice::emptyCurrent) const override
void removeEntity(const ::std::string &entityId, const ::Ice::Current &=Ice::emptyCurrent) override
removeEntity removes an entity with the ID entityId
EntityRefBasePtr getEntityRefById(const std::string &id, const Ice::Current &) const override
void updateEntity(const ::std::string &entityId, const EntityBasePtr &update, const ::Ice::Current &=Ice::emptyCurrent) override
EntityBasePtr getEntityByName(const ::std::string &name, const ::Ice::Current &=Ice::emptyCurrent) const override
#define ARMARX_ERROR_S
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:216
#define ARMARX_INFO_S
Definition Logging.h:202
#define ARMARX_VERBOSE_S
Definition Logging.h:207
::IceInternal::Handle<::Ice::Communicator > CommunicatorPtr
Definition IceManager.h:49