Skip to content

Commit 10260b9

Browse files
committed
Further simplify interface resolution
* Do not modify explicitly configured direction of Propagator * Avoid code duplication in pruneInterface() and validateConnectivity() Only implement pruneInterface() for stages that actually need to adapt their interface.
1 parent 4d8d32d commit 10260b9

File tree

4 files changed

+71
-118
lines changed

4 files changed

+71
-118
lines changed

core/include/moveit/task_constructor/container_p.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ class ContainerBasePrivate : public StagePrivate
105105

106106
void validateConnectivity() const override;
107107

108-
// containers derive their required interface from their children
108+
// Containers derive their required interface from their children
109109
// UNKNOWN until pruneInterface was called
110110
InterfaceFlags requiredInterface() const override { return required_interface_; }
111111

@@ -124,12 +124,12 @@ class ContainerBasePrivate : public StagePrivate
124124
// If, during pruneInterface() later, we notice that it's not needed, prune there.
125125
inline void setChildsPushBackwardInterface(Stage& child) {
126126
InterfaceFlags required = child.pimpl()->requiredInterface();
127-
bool allowed = (required & WRITES_PREV_END) || (required == UNKNOWN);
127+
bool allowed = (required & WRITES_PREV_END);
128128
child.pimpl()->setPrevEnds(allowed ? pending_backward_ : InterfacePtr());
129129
}
130130
inline void setChildsPushForwardInterface(Stage& child) {
131131
InterfaceFlags required = child.pimpl()->requiredInterface();
132-
bool allowed = (required & WRITES_NEXT_START) || (required == UNKNOWN);
132+
bool allowed = (required & WRITES_NEXT_START);
133133
child.pimpl()->setNextStarts(allowed ? pending_forward_ : InterfacePtr());
134134
}
135135
// report error about mismatching interface (start or end as determined by mask)
@@ -144,7 +144,7 @@ class ContainerBasePrivate : public StagePrivate
144144
auto& internalToExternalMap() { return internal_to_external_; }
145145
const auto& internalToExternalMap() const { return internal_to_external_; }
146146

147-
// set by containers in pruneInterface()
147+
// set in pruneInterface()
148148
InterfaceFlags required_interface_;
149149

150150
private:
@@ -249,7 +249,7 @@ class MergerPrivate : public ParallelContainerBasePrivate
249249
typedef std::function<void(SubTrajectory&&)> Spawner;
250250
MergerPrivate(Merger* me, const std::string& name);
251251

252-
InterfaceFlags requiredInterface() const override;
252+
void pruneInterface(InterfaceFlags accepted) override;
253253

254254
void onNewPropagateSolution(const SolutionBase& s);
255255
void onNewGeneratorSolution(const SolutionBase& s);

core/include/moveit/task_constructor/stage_p.h

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,10 @@ class StagePrivate
7676
* If the interface is unknown (because it is auto-detected from context), return UNKNOWN */
7777
virtual InterfaceFlags requiredInterface() const = 0;
7878

79-
/** validate correct interface usage and resolve ambiguous interfaces */
80-
virtual void pruneInterface(InterfaceFlags accepted);
81-
82-
void pruneStartInterface(InterfaceFlags start_flags) { pruneInterface(start_flags & START_IF_MASK); }
83-
void pruneEndInterface(InterfaceFlags end_flags) { pruneInterface(end_flags & END_IF_MASK); }
79+
/** Prune interface to comply with the given propagation direction
80+
*
81+
* PropagatingEitherWay uses this in restrictDirection() */
82+
virtual void pruneInterface(InterfaceFlags /* accepted */) {}
8483

8584
/// validate connectivity of children (after init() was done)
8685
virtual void validateConnectivity() const;
@@ -212,10 +211,10 @@ class PropagatingEitherWayPrivate : public ComputeBasePrivate
212211
friend class PropagatingEitherWay;
213212

214213
public:
215-
PropagatingEitherWay::Direction required_interface_dirs_;
214+
PropagatingEitherWay::Direction configured_dir_;
215+
InterfaceFlags required_interface_;
216216

217-
inline PropagatingEitherWayPrivate(PropagatingEitherWay* me,
218-
PropagatingEitherWay::Direction required_interface_dirs_,
217+
inline PropagatingEitherWayPrivate(PropagatingEitherWay* me, PropagatingEitherWay::Direction configured_dir_,
219218
const std::string& name);
220219

221220
InterfaceFlags requiredInterface() const override;

core/src/container.cpp

Lines changed: 21 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -425,51 +425,39 @@ void SerialContainerPrivate::connect(StagePrivate& stage1, StagePrivate& stage2)
425425

426426
// called by parent asking for pruning of this' interface
427427
void SerialContainerPrivate::pruneInterface(InterfaceFlags accepted) {
428+
// we need to have some children to do the actual work
428429
if (children().empty())
429-
throw InitStageException(*me(), "container is empty");
430+
throw InitStageException(*me(), "no children");
430431

431-
// TODO(v4hn): if ever there is a use case to start pruning
432-
// with a specified end interface, this would need to be extended
433-
if (!(accepted & (READS_START | WRITES_PREV_END)))
434-
return; // The start interface direction is not decided
432+
if (!(accepted & START_IF_MASK))
433+
throw InitStageException(*me(), "unknown start interface");
435434

436435
Stage& first = *children().front();
437436
Stage& last = *children().back();
438437

439-
// sweep through children once: infer and connect interfaces
440-
first.pimpl()->pruneStartInterface(accepted);
438+
// FIRST child
439+
first.pimpl()->pruneInterface(accepted & START_IF_MASK);
440+
// connect first child's (start) push interface
441441
setChildsPushBackwardInterface(first);
442+
// connect first child's (start) pull interface
443+
if (const InterfacePtr& target = first.pimpl()->starts())
444+
starts_.reset(new Interface(
445+
[this, target](Interface::iterator it, bool updated) { this->copyState(it, target, updated); }));
442446

447+
// process all children and connect them
443448
for (auto it = ++children().begin(), previous_it = children().begin(); it != children().end(); ++it, ++previous_it) {
444449
StagePrivate* child_impl = (**it).pimpl();
445450
StagePrivate* previous_impl = (**previous_it).pimpl();
446-
child_impl->pruneStartInterface(invert(previous_impl->requiredInterface()));
451+
child_impl->pruneInterface(invert(previous_impl->requiredInterface()) & START_IF_MASK);
447452
connect(*previous_impl, *child_impl);
448453
}
449454

450-
// potentially connect outmost push interface to pending_ buffer
455+
// connect last child's (end) push interface
451456
setChildsPushForwardInterface(last);
452-
453-
if ((accepted & END_IF_MASK) != UNKNOWN &&
454-
(last.pimpl()->requiredInterface() & END_IF_MASK) != (accepted & END_IF_MASK)) {
455-
boost::format desc(
456-
"requested end interface for container (%1%) does not agree with inferred end interface of last child (%2%)");
457-
desc % flowSymbol<END_IF_MASK>(accepted) % flowSymbol<END_IF_MASK>(last.pimpl()->requiredInterface());
458-
throw InitStageException(*me(), desc.str());
459-
}
460-
461-
// if first/last pull, this needs to pull to and forward to the children
462-
if (const InterfacePtr& target = first.pimpl()->starts())
463-
starts_.reset(new Interface(
464-
[this, target](Interface::iterator it, bool updated) { this->copyState(it, target, updated); }));
465-
else
466-
starts_.reset();
467-
457+
// connect last child's (end) pull interface
468458
if (const InterfacePtr& target = last.pimpl()->ends())
469459
ends_.reset(new Interface(
470460
[this, target](Interface::iterator it, bool updated) { this->copyState(it, target, updated); }));
471-
else
472-
ends_.reset();
473461

474462
required_interface_ = first.pimpl()->interfaceFlags() & START_IF_MASK | last.pimpl()->interfaceFlags() & END_IF_MASK;
475463
}
@@ -582,11 +570,9 @@ ParallelContainerBasePrivate::ParallelContainerBasePrivate(ParallelContainerBase
582570
: ContainerBasePrivate(me, name) {}
583571

584572
void ParallelContainerBasePrivate::pruneInterface(InterfaceFlags accepted) {
573+
// we need to have some children to do the actual work
585574
if (children().empty())
586-
throw InitStageException(*me(), "trying to prune empty container");
587-
588-
if (accepted == UNKNOWN)
589-
return; // nothing to prune
575+
throw InitStageException(*me(), "no children");
590576

591577
InitStageException exceptions;
592578
InterfaceFlags interface;
@@ -789,32 +775,21 @@ void Fallbacks::onNewSolution(const SolutionBase& s) {
789775

790776
MergerPrivate::MergerPrivate(Merger* me, const std::string& name) : ParallelContainerBasePrivate(me, name) {}
791777

792-
InterfaceFlags MergerPrivate::requiredInterface() const {
793-
if (children().size() < 2)
794-
throw InitStageException(*me_, "Need 2 children at least.");
795-
796-
InterfaceFlags required = ParallelContainerBasePrivate::requiredInterface();
797-
798-
// all children need to share a common interface
799-
for (const Stage::pointer& stage : children()) {
800-
InterfaceFlags current = stage->pimpl()->requiredInterface();
801-
if (current != required)
802-
throw InitStageException(*stage, "Interface does not match the common one.");
803-
}
804-
805-
switch (required) {
778+
void MergerPrivate::pruneInterface(InterfaceFlags accepted) {
779+
ContainerBasePrivate::pruneInterface(accepted);
780+
switch (interfaceFlags()) {
806781
case PROPAGATE_FORWARDS:
807782
case PROPAGATE_BACKWARDS:
808783
case UNKNOWN:
809784
break; // these are supported
785+
810786
case GENERATE:
811787
throw InitStageException(*me_, "Generator stages not yet supported.");
812788
case CONNECT:
813789
throw InitStageException(*me_, "Cannot merge connecting stages. Use Connect.");
814790
default:
815791
throw InitStageException(*me_, "Children's interface not supported.");
816792
}
817-
return required;
818793
}
819794

820795
Merger::Merger(const std::string& name) : Merger(new MergerPrivate(this, name)) {}

core/src/stage.cpp

Lines changed: 38 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -112,28 +112,6 @@ InterfaceFlags StagePrivate::interfaceFlags() const {
112112
return f;
113113
}
114114

115-
void StagePrivate::pruneInterface(InterfaceFlags accepted) {
116-
const InterfaceFlags accepted_start{ accepted & START_IF_MASK };
117-
const InterfaceFlags accepted_end{ accepted & END_IF_MASK };
118-
119-
const InterfaceFlags required{ requiredInterface() };
120-
const InterfaceFlags required_start{ required & START_IF_MASK };
121-
const InterfaceFlags required_end{ required & END_IF_MASK };
122-
123-
if (required == UNKNOWN)
124-
throw std::logic_error("stage type does not specify interface, but also does not override pruneInterface. "
125-
"Who sets up its interfaces?");
126-
127-
// only one side needs to be specified but the value has to be compatible with this stage
128-
if (((accepted_start != UNKNOWN) && (accepted_start & required_start) != required_start) ||
129-
((accepted_end != UNKNOWN) && (accepted_end & required_end) != required_end)) {
130-
boost::format desc("interface %1% %2% does not match inferred interface %3% %4%");
131-
desc % flowSymbol<START_IF_MASK>(required_start) % flowSymbol<END_IF_MASK>(required_end);
132-
desc % flowSymbol<START_IF_MASK>(accepted_start) % flowSymbol<END_IF_MASK>(accepted_end);
133-
throw InitStageException(*me(), desc.str());
134-
}
135-
}
136-
137115
void StagePrivate::validateConnectivity() const {
138116
// check that the required interface is provided
139117
InterfaceFlags required = requiredInterface();
@@ -416,47 +394,53 @@ ComputeBase::ComputeBase(ComputeBasePrivate* impl) : Stage(impl) {}
416394

417395
PropagatingEitherWayPrivate::PropagatingEitherWayPrivate(PropagatingEitherWay* me, PropagatingEitherWay::Direction dir,
418396
const std::string& name)
419-
: ComputeBasePrivate(me, name), required_interface_dirs_(dir) {}
397+
: ComputeBasePrivate(me, name), configured_dir_(dir) {
398+
initInterface(dir);
399+
}
420400

421401
// initialize pull interfaces to match requested propagation directions
422402
void PropagatingEitherWayPrivate::initInterface(PropagatingEitherWay::Direction dir) {
423-
if (required_interface_dirs_ != PropagatingEitherWay::AUTO && dir != required_interface_dirs_) {
424-
auto flow = [](PropagatingEitherWay::Direction dir) -> const char* {
425-
switch (dir) {
426-
case PropagatingEitherWay::AUTO:
427-
return flowSymbol<START_IF_MASK>(InterfaceFlags{ READS_START, WRITES_PREV_END });
428-
case PropagatingEitherWay::FORWARD:
429-
return flowSymbol<START_IF_MASK>(InterfaceFlags{ READS_START });
430-
case PropagatingEitherWay::BACKWARD:
431-
return flowSymbol<START_IF_MASK>(InterfaceFlags{ WRITES_PREV_END });
432-
}
433-
};
434-
435-
boost::format desc("propagation direction %1% incompatible with inferred direction %2%");
436-
desc % flow(required_interface_dirs_) % flow(dir);
437-
throw InitStageException(*me(), desc.str());
403+
switch (dir) {
404+
case PropagatingEitherWay::FORWARD:
405+
required_interface_ = PROPAGATE_FORWARDS;
406+
if (!starts_) // keep existing interface if possible
407+
starts_.reset(
408+
new Interface([this](Interface::iterator it, bool /*updated*/) { this->dropFailedStarts(it); }));
409+
ends_.reset();
410+
return;
411+
case PropagatingEitherWay::BACKWARD:
412+
required_interface_ = PROPAGATE_BACKWARDS;
413+
starts_.reset();
414+
if (!ends_) // keep existing interface if possible
415+
ends_.reset(new Interface([this](Interface::iterator it, bool /*updated*/) { this->dropFailedEnds(it); }));
416+
return;
417+
case PropagatingEitherWay::AUTO:
418+
required_interface_ = UNKNOWN;
419+
return;
438420
}
439-
440-
if (dir == PropagatingEitherWay::FORWARD)
441-
starts_.reset(new Interface([this](Interface::iterator it, bool /* updated */) { this->dropFailedStarts(it); }));
442-
else if (dir == PropagatingEitherWay::BACKWARD)
443-
ends_.reset(new Interface([this](Interface::iterator it, bool /* updated */) { this->dropFailedEnds(it); }));
444-
445-
required_interface_dirs_ = dir;
446421
}
447422

448423
void PropagatingEitherWayPrivate::pruneInterface(InterfaceFlags accepted) {
449424
if (accepted == UNKNOWN)
450-
throw InitStageException(*me(), "cannot prune to unknown interface");
425+
throw InitStageException(*me(), "cannot initialize to unknown interface");
426+
427+
auto dir = PropagatingEitherWay::AUTO;
451428
if ((accepted & START_IF_MASK) == READS_START || (accepted & END_IF_MASK) == WRITES_NEXT_START)
452-
initInterface(PropagatingEitherWay::FORWARD);
429+
dir = PropagatingEitherWay::FORWARD;
453430
else if ((accepted & START_IF_MASK) == WRITES_PREV_END || (accepted & END_IF_MASK) == READS_END)
454-
initInterface(PropagatingEitherWay::BACKWARD);
431+
dir = PropagatingEitherWay::BACKWARD;
455432
else {
456-
boost::format desc("propagator cannot act with interfaces start(%1%), end(%2%)");
433+
boost::format desc("propagator cannot handle external interface %1% %2%");
434+
desc % flowSymbol<START_IF_MASK>(accepted) % flowSymbol<END_IF_MASK>(accepted);
435+
throw InitStageException(*me(), desc.str());
436+
}
437+
if (configured_dir_ != PropagatingEitherWay::AUTO && dir != configured_dir_) {
438+
boost::format desc("configured interface (%1% %2%) does not match external one (%3% %4%)");
439+
desc % flowSymbol<START_IF_MASK>(required_interface_) % flowSymbol<END_IF_MASK>(required_interface_);
457440
desc % flowSymbol<START_IF_MASK>(accepted) % flowSymbol<END_IF_MASK>(accepted);
458441
throw InitStageException(*me(), desc.str());
459442
}
443+
initInterface(dir);
460444
}
461445

462446
void PropagatingEitherWayPrivate::validateConnectivity() const {
@@ -475,14 +459,7 @@ void PropagatingEitherWayPrivate::validateConnectivity() const {
475459
}
476460

477461
InterfaceFlags PropagatingEitherWayPrivate::requiredInterface() const {
478-
switch (required_interface_dirs_) {
479-
case PropagatingEitherWay::FORWARD:
480-
return PROPAGATE_FORWARDS;
481-
case PropagatingEitherWay::BACKWARD:
482-
return PROPAGATE_BACKWARDS;
483-
case PropagatingEitherWay::AUTO:
484-
return UNKNOWN;
485-
}
462+
return required_interface_;
486463
}
487464

488465
void PropagatingEitherWayPrivate::dropFailedStarts(Interface::iterator state) {
@@ -540,9 +517,11 @@ PropagatingEitherWay::PropagatingEitherWay(PropagatingEitherWayPrivate* impl) :
540517

541518
void PropagatingEitherWay::restrictDirection(PropagatingEitherWay::Direction dir) {
542519
auto impl = pimpl();
543-
if (impl->required_interface_dirs_ != AUTO)
520+
if (impl->configured_dir_ == dir)
521+
return;
522+
if (impl->configured_dir_ != AUTO)
544523
throw std::runtime_error("Cannot change direction after being connected");
545-
524+
impl->configured_dir_ = dir;
546525
impl->initInterface(dir);
547526
}
548527

0 commit comments

Comments
 (0)