-
Notifications
You must be signed in to change notification settings - Fork 30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add World::State #265
Add World::State #265
Conversation
Codecov Report
@@ Coverage Diff @@
## master #265 +/- ##
==========================================
- Coverage 70.63% 70.56% -0.08%
==========================================
Files 186 188 +2
Lines 5510 5537 +27
Branches 863 869 +6
==========================================
+ Hits 3892 3907 +15
- Misses 1089 1097 +8
- Partials 529 533 +4
|
Just to clarify some things about the semantics in DART:
Since the |
Thanks for the comments @mxgrey . Indeed, what you described is precisely why I chose to use In fact, now might be a good time to discuss whether to put in collision groups or anything else, to make Additionally, I think I'll add |
You may want to consider putting information like collision groups and constraints into a Note that the |
Conflicts: tests/statespace/dart/test_MetaSkeletonStateSpaceSaver.cpp
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks mostly fine to me!
class World | ||
{ | ||
public: | ||
// Encapsulates the state of the World. | ||
struct State |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should State
also have some notion of the Skeleton
s it contains? Maybe the Skeleton
names?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One option is to index configurations
by Skeleton
name, i.e. switch from an std::vector
to an std::unordered_map
.
include/aikido/planner/World.hpp
Outdated
{ | ||
std::vector<dart::dynamics::Skeleton::Configuration> configurations; | ||
|
||
/// Returns true if two world states are the same. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any reason to use equals
rather than operator==
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see any reason why we couldn't use operator ==
here. If we define that, then we should also remember to define operator !=
. 🙃
Also, this likely should be flagged as const
.
src/planner/World.cpp
Outdated
{ | ||
if (state.configurations.size() != mSkeletons.size()) | ||
throw std::invalid_argument( | ||
"World::State and this World does not have the same number of " |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: does -> do
src/planner/WorldStateSaver.cpp
Outdated
|
||
WorldStateSaver::WorldStateSaver( | ||
WorldPtr world) | ||
: mWorld{world} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to initialize mWorldState
here instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WorldState
does not keep a pointer to a specific world, but when WorldStateSaver
is destroyed, we typically want to restore the state of a World
to a previous state. So I think we need to keep a pointer to the world?
src/planner/WorldStateSaver.cpp
Outdated
namespace aikido { | ||
namespace planner { | ||
|
||
WorldStateSaver::WorldStateSaver( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: can we also add basic tests for WorldStateSaver
?
tests/planner/test_World.cpp
Outdated
|
||
EXPECT_FALSE(mWorld->getState().equals(otherWorld->getState())); | ||
EXPECT_FALSE(otherWorld->getState().equals(mWorld->getState())); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: can we add a couple tests for setState
to verify that it throws errors?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This generally looks okay to me.
I don't think this pull request really solves the tricky question of what it means for two World
s to be equivalent. The current logic would treat two entirely different worlds as equivalent if they happen to contain the same number of Skeleton
s with the same dimension Configuration
s.
I also am not convinced that WorldStateSaver
is a good idea. When we were writing Magi we discovered that it is generally safer, more efficient, and easier to implement more granular state saving. I.e. only save the state over the parts of the environment that you modify in an ExecutableSolution
. I am fine with keeping this functionality for now, but generally think we should avoid using it in routine operation.
These are hard problems and I don't have a great solution. Maybe @psigen or @siddhss5 have better ideas.
class World | ||
{ | ||
public: | ||
// Encapsulates the state of the World. | ||
struct State |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One option is to index configurations
by Skeleton
name, i.e. switch from an std::vector
to an std::unordered_map
.
include/aikido/planner/World.hpp
Outdated
{ | ||
std::vector<dart::dynamics::Skeleton::Configuration> configurations; | ||
|
||
/// Returns true if two world states are the same. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see any reason why we couldn't use operator ==
here. If we define that, then we should also remember to define operator !=
. 🙃
Also, this likely should be flagged as const
.
/// WorldStateSaver is destructed. | ||
/// | ||
/// \param _space WorldState to save/restore | ||
explicit WorldStateSaver(WorldPtr world); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should be able to flag this argument as const
.
Also, I don't see a strong reason to make this accept a smart pointer rather than a reference or raw pointer.
|
||
virtual ~WorldStateSaver(); | ||
|
||
// WorldStateSaver is uncopyable, must use std::move |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see any harm in making this class copyable. What's the concern here?
src/planner/World.cpp
Outdated
} | ||
|
||
return true; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this whole function could be replaced with:
return configurations == other.configurations;
Something is also a bit funny about this. Shouldn't we verify that the two Configuration
s contain the same Skeleton
s somehow?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're not checking whether the skeletons are the same because the skeletons may be cloned ones. Shouldn't we want to be able to say that the two cloned worlds are in the same state if they have the same configurations?
src/planner/World.cpp
Outdated
for (size_t idx = 0; idx < state.configurations.size(); ++idx) | ||
{ | ||
std::lock_guard<std::mutex> lock(mSkeletons[idx]->getMutex()); | ||
mSkeletons[idx]->setConfiguration(state.configurations[idx]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a thought, outside the scope of this pull request: At some point we may want to abandon using per-Skeleton
locks and instead having a single lock for the entire World
. This wasn't an option before because we didn't have a World
object. 😉
@brianhou could you give it a (hopefully) final pass? :) |
@mkoval Thanks for the feedback! I agree that saving/restoring a smaller subset of the world which gets modified during planning is a better idea, which we're not currently doing in |
There also seems to be a bit of detailed comparison that needs to be done in order to say whether two skeletons have the same "state space", which is necessary when we are doing |
I think comparing |
src/planner/World.cpp
Outdated
{ | ||
World::State state; | ||
|
||
for (auto skeleton : mSkeletons) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this can be const auto& skeleton
?
"Skeleton " + name + " does not exist in state."); | ||
} | ||
|
||
for (const auto& skeleton : mSkeletons) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this loop be merged into the previous one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't want to merge these two because I don't want this to throw an error after modifying some of the skeletons.
for (const auto& skeleton : mSkeletons) | ||
{ | ||
std::lock_guard<std::mutex> lock(skeleton->getMutex()); | ||
skeleton->setConfiguration(state.configurations.at(skeleton->getName())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we use state.configurations[skeleton->getName()]
instead of at
? Since we've already checked that the keys should all exist, at
seems unnecessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, maybe we could merge the two loops and then just use at
instead of explicitly calling find
and then indexing? @jslee02 is it inefficient to catch the (possible) out_of_range
exception from at
and then trigger our own more helpful exception?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm. Can't do []
because []
is a non-const operator and I'm taking in const State&
.
https://stackoverflow.com/questions/15660838/error-no-match-for-operator-in-near-match
I'll keep it as is.
* Add World.equalConfiguration method. * Code format * Add WorldState * Add WorldStateSaver * Move MetaSkeletonStateSpaceSaver-impl to cpp file * Add tests for MetaSkeletonStateSpaceSaver * Remove unused header from test_MetaSkeletonStateSpaceSaver * Address Mike and Brian's comments * Modify format, docstring * Address Brian's comments
This PR addresses #261 . Based on discussion on #263, this PR creates
WorldState
struct and providesequals
method to compare with otherWorldState
s.Before creating a pull request
make format
Before merging a pull request
CHANGELOG.md