Commit 057e13ff authored by Floris Berendsen's avatar Floris Berendsen
Browse files

WIP ENH: extended overlord to resolve non-unique component nodes based on

the interfaces of neigboring unique components
parent 693c0bbe
......@@ -61,7 +61,7 @@ public:
typedef boost::labeled_graph< boost::adjacency_list<
boost::vecS,
boost::vecS,
boost::directedS,
boost::bidirectionalS,
ComponentPropertyType,
ConnectionPropertyType
>,
......@@ -121,9 +121,11 @@ public:
bool ConnectionExists( ComponentNameType upstream, ComponentNameType downstream ) const;
// Returns a vector of the Component names at the outgoing direction
// TODO: should this be an iterator over the names?
ComponentNamesType GetOutputNames( const ComponentNameType name ) const;
// Returns a vector of the Component names at the incoming direction
ComponentNamesType GetInputNames(const ComponentNameType name) const;
void WriteBlueprint( const std::string filename );
private:
......
......@@ -282,6 +282,21 @@ Blueprint
return container;
}
Blueprint::ComponentNamesType
Blueprint
::GetInputNames(const ComponentNameType name) const
{
ComponentNamesType container;
//auto vertex = this->m_Graph.vertex(name);
//boost::in_edges(vertex, this->m_Graph);
InputIteratorPairType inputIteratorPair = boost::in_edges(this->m_Graph.vertex(name), this->m_Graph);
for (auto it = inputIteratorPair.first; it != inputIteratorPair.second; ++it)
{
container.push_back(this->m_Graph.graph()[it->m_source].name);
}
return container;
}
Blueprint::ConnectionIndexType
Blueprint
......
......@@ -23,7 +23,7 @@
#include "itkLightObject.h"
#include "itkObjectFactory.h"
#include "itkMacro.h"
#include "selxInterfaceStatus.h"
//#include "itkComponentBase.h"
#include <list>
#include <iostream>
......@@ -55,9 +55,7 @@ public:
typedef std::map< std::string, std::string > InterfaceCriteriaType;
enum interfaceStatus { success, noaccepter, noprovider, multiple };
virtual interfaceStatus AcceptConnectionFrom( const char *, ComponentBase * ) = 0;
virtual InterfaceStatus AcceptConnectionFrom( const char *, ComponentBase * ) = 0;
virtual int AcceptConnectionFrom( ComponentBase * ) = 0;
......@@ -66,7 +64,8 @@ public:
virtual bool MeetsCriterion( const CriterionType & criterion ) = 0;
virtual interfaceStatus CanAcceptConnectionFrom(ComponentBase*, const InterfaceCriteriaType) = 0;
virtual InterfaceStatus CanAcceptConnectionFrom(ComponentBase*, const InterfaceCriteriaType) = 0;
virtual InterfaceStatus CanProvideConnectionTo(ComponentBase*, const InterfaceCriteriaType) = 0;
//experimental:
virtual unsigned int CountAcceptingInterfaces(const InterfaceCriteriaType) = 0;
......
......@@ -69,8 +69,9 @@ public:
/** Check for multiple versus 1 or 0 components*/
bool HasMultipleComponents( void );
unsigned int RequireAcceptInterfaceFrom(ComponentBasePointer other, const InterfaceCriteriaType & interfaceCriteria);
unsigned int RequireAcceptingInterfaceFrom(ComponentBasePointer other, const InterfaceCriteriaType & interfaceCriteria);
unsigned int RequireProvidingInterfaceTo(ComponentBasePointer other, const InterfaceCriteriaType & interfaceCriteria);
/** Return Component or Nullptr*/
ComponentBasePointer GetComponent( void );
......
......@@ -37,6 +37,7 @@
#include "selxAnyFileReader.h"
#include "selxAnyFileWriter.h"
#include "selxInterfaceStatus.h"
#include "elxElastixFilter.h"
namespace selx
......
......@@ -47,18 +47,23 @@ private:
bool isSet;
};
template< typename ... RestInterfaces >
class Accepting
template <typename ... Interfaces>
class Accepting;
template <>
class Accepting<>
{
public:
static unsigned int CountMeetsCriteria(const ComponentBase::InterfaceCriteriaType) { return 0; }
ComponentBase::interfaceStatus ConnectFromImpl( const char *, ComponentBase * ) { return ComponentBase::interfaceStatus::noaccepter; } //no interface called interfacename ;
ComponentBase::interfaceStatus CanAcceptConnectionFrom(ComponentBase* other, const ComponentBase::InterfaceCriteriaType interfaceCriteria) { return ComponentBase::interfaceStatus::noaccepter; }
int ConnectFromImpl( ComponentBase * ) { return 0; } //Empty RestInterfaces does 0 successful connects ;
InterfaceStatus ConnectFromImpl(const char *, ComponentBase *) { return InterfaceStatus::noaccepter; } //no interface called interfacename ;
InterfaceStatus CanAcceptConnectionFrom(ComponentBase* other, const ComponentBase::InterfaceCriteriaType interfaceCriteria) { return InterfaceStatus::noaccepter; }
int ConnectFromImpl(ComponentBase *) { return 0; } //Empty RestInterfaces does 0 successful connects ;
protected:
bool HasInterface( const char * ) { return false; }
bool HasInterface(const char *) { return false; }
};
template< typename FirstInterface, typename ... RestInterfaces >
......@@ -66,8 +71,8 @@ class Accepting< FirstInterface, RestInterfaces ... > : public InterfaceAcceptor
{
public:
static unsigned int CountMeetsCriteria(const ComponentBase::InterfaceCriteriaType);
ComponentBase::interfaceStatus ConnectFromImpl( const char *, ComponentBase * );
ComponentBase::interfaceStatus CanAcceptConnectionFrom(ComponentBase* other, const ComponentBase::InterfaceCriteriaType interfaceCriteria);
InterfaceStatus ConnectFromImpl(const char *, ComponentBase *);
InterfaceStatus CanAcceptConnectionFrom(ComponentBase* other, const ComponentBase::InterfaceCriteriaType interfaceCriteria);
int ConnectFromImpl( ComponentBase * );
protected:
......@@ -75,11 +80,15 @@ protected:
bool HasInterface( const char * );
};
template< typename ... RestInterfaces >
class Providing
template <typename ... Interfaces>
class Providing;
template< >
class Providing<>
{
public:
static unsigned int CountMeetsCriteria(const ComponentBase::InterfaceCriteriaType) { return 0; }
InterfaceStatus CanProvideConnectionTo(ComponentBase* other, const ComponentBase::InterfaceCriteriaType interfaceCriteria) { return InterfaceStatus::noprovider; };
protected:
bool HasInterface( const char * ) { return false; }
......@@ -90,6 +99,7 @@ class Providing< FirstInterface, RestInterfaces ... > : public FirstInterface, p
{
public:
static unsigned int CountMeetsCriteria(const ComponentBase::InterfaceCriteriaType);
InterfaceStatus CanProvideConnectionTo(ComponentBase* other, const ComponentBase::InterfaceCriteriaType interfaceCriteria);
protected:
bool HasInterface( const char * );
......@@ -125,7 +135,7 @@ public:
using AcceptingInterfacesTypeList = AcceptingInterfaces;
using ProvidingInterfacesTypeList = ProvidingInterfaces;
virtual interfaceStatus AcceptConnectionFrom( const char *, ComponentBase * );
virtual InterfaceStatus AcceptConnectionFrom( const char *, ComponentBase * );
virtual int AcceptConnectionFrom( ComponentBase * );
......@@ -136,7 +146,8 @@ protected:
virtual bool HasProvidingInterface( const char * );
//experimental
virtual interfaceStatus CanAcceptConnectionFrom(ComponentBase* other, const InterfaceCriteriaType interfaceCriteria) override;
virtual InterfaceStatus CanAcceptConnectionFrom(ComponentBase* other, const InterfaceCriteriaType interfaceCriteria) override;
virtual InterfaceStatus CanProvideConnectionTo(ComponentBase* other, const InterfaceCriteriaType interfaceCriteria) override;
//
virtual unsigned int CountAcceptingInterfaces(const ComponentBase::InterfaceCriteriaType interfaceCriteria){ return AcceptingInterfaces::CountMeetsCriteria(interfaceCriteria); };
virtual unsigned int CountProvidingInterfaces(const ComponentBase::InterfaceCriteriaType interfaceCriteria){ return ProvidingInterfaces::CountMeetsCriteria(interfaceCriteria); };
......
......@@ -49,7 +49,7 @@ InterfaceAcceptor< InterfaceT >::CanAcceptConnectionFrom(ComponentBase * provide
//////////////////////////////////////////////////////////////////////////
template< typename AcceptingInterfaces, typename ProvidingInterfaces >
ComponentBase::interfaceStatus
InterfaceStatus
SuperElastixComponent< AcceptingInterfaces, ProvidingInterfaces >::AcceptConnectionFrom( const char * interfacename, ComponentBase * other )
{
return AcceptingInterfaces::ConnectFromImpl( interfacename, other );
......@@ -80,16 +80,23 @@ SuperElastixComponent< AcceptingInterfaces, ProvidingInterfaces >::HasProvidingI
}
template< typename AcceptingInterfaces, typename ProvidingInterfaces >
ComponentBase::interfaceStatus
InterfaceStatus
SuperElastixComponent< AcceptingInterfaces, ProvidingInterfaces >
::CanAcceptConnectionFrom(ComponentBase* other, const InterfaceCriteriaType interfaceCriteria)
{
return AcceptingInterfaces::CanAcceptConnectionFrom(other, interfaceCriteria);
}
template< typename AcceptingInterfaces, typename ProvidingInterfaces >
InterfaceStatus
SuperElastixComponent< AcceptingInterfaces, ProvidingInterfaces >
::CanProvideConnectionTo(ComponentBase* other, const InterfaceCriteriaType interfaceCriteria)
{
return ProvidingInterfaces::CanProvideConnectionTo(other, interfaceCriteria);
}
//////////////////////////////////////////////////////////////////////////
template< typename FirstInterface, typename ... RestInterfaces >
ComponentBase::interfaceStatus
InterfaceStatus
Accepting< FirstInterface, RestInterfaces ... >::ConnectFromImpl( const char * interfacename, ComponentBase * other )
{
// does our component have an accepting interface called interfacename?
......@@ -102,12 +109,12 @@ Accepting< FirstInterface, RestInterfaces ... >::ConnectFromImpl( const char * i
if( 1 == acceptIF->Connect( other ) )
{
//success. By terminating this function, we assume only one interface listens to interfacename and that one connection with the other component can be made by this name
return ComponentBase::interfaceStatus::success;
return InterfaceStatus::success;
}
else
{
// interfacename was found, but other component doesn't match
return ComponentBase::interfaceStatus::noprovider;
return InterfaceStatus::noprovider;
}
}
return Accepting< RestInterfaces ... >::ConnectFromImpl( interfacename, other );
......@@ -142,81 +149,43 @@ Accepting< FirstInterface, RestInterfaces ... >::HasInterface( const char * inte
}
template< typename FirstInterface, typename ... RestInterfaces >
ComponentBase::interfaceStatus
InterfaceStatus
Accepting< FirstInterface, RestInterfaces ... >::CanAcceptConnectionFrom(ComponentBase* other, const ComponentBase::InterfaceCriteriaType interfaceCriteria)
{
ComponentBase::interfaceStatus restInterfacesStatus = Accepting< RestInterfaces ... >::CanAcceptConnectionFrom(other, interfaceCriteria);
InterfaceStatus restInterfacesStatus = Accepting< RestInterfaces ... >::CanAcceptConnectionFrom(other, interfaceCriteria);
// if multiple interfaces were a success we do not have to check any further interfaces.
if (restInterfacesStatus == ComponentBase::interfaceStatus::multiple)
if (restInterfacesStatus == InterfaceStatus::multiple)
{
return ComponentBase::interfaceStatus::multiple;
return InterfaceStatus::multiple;
}
// if a previous interface was a success, we can have either success or multiple (successes)
else if (restInterfacesStatus == ComponentBase::interfaceStatus::success)
// We use the FirstInterface only (of each recursion level), thus the count can be 0 or 1
unsigned int interfaceMeetsCriteria = Count<FirstInterface>::MeetsCriteria(interfaceCriteria);
if (interfaceMeetsCriteria == 0) // InterfaceStatus::noaccepter;
{
unsigned int interfaceMeetsCriteria = Count<FirstInterface>::MeetsCriteria(interfaceCriteria);
if (interfaceMeetsCriteria == 0) // ComponentBase::interfaceStatus::noacceptor;
{
return ComponentBase::interfaceStatus::success;
}
else
{
InterfaceAcceptor< FirstInterface > * acceptIF = (this);
if (acceptIF->CanAcceptConnectionFrom(other))
{
return ComponentBase::interfaceStatus::multiple;
}
else // ComponentBase::interfaceStatus::noprovider
{
return ComponentBase::interfaceStatus::success;
}
}
// no new success, keep the status of previous recursion
return restInterfacesStatus;
}
// if a previous interface was noprovider, we can have either success or noprovider (we know that there was at least 1 acceptor)
else if (restInterfacesStatus == ComponentBase::interfaceStatus::noprovider)
else // This "FirstInterface" of the component is an acceptor interface that fulfills the criteria
{
unsigned int interfaceMeetsCriteria = Count<FirstInterface>::MeetsCriteria(interfaceCriteria);
if (interfaceMeetsCriteria == 0) // ComponentBase::interfaceStatus::noacceptor;
InterfaceAcceptor< FirstInterface > * acceptIF = (this);
if (acceptIF->CanAcceptConnectionFrom(other))
{
return ComponentBase::interfaceStatus::noprovider;
// if a previous interface was a success, we can have either success or multiple (successes)
if (restInterfacesStatus == InterfaceStatus::success)
return InterfaceStatus::multiple;
return InterfaceStatus::success;
}
else
{
InterfaceAcceptor< FirstInterface > * acceptIF = (this);
if (acceptIF->CanAcceptConnectionFrom(other))
{
return ComponentBase::interfaceStatus::success;
}
else // ComponentBase::interfaceStatus::noprovider
{
return ComponentBase::interfaceStatus::noprovider;
}
}
}
// if a previous interface was noaccepter, we can have noaccepter, success or noprovider
else if (restInterfacesStatus == ComponentBase::interfaceStatus::noaccepter)
{
unsigned int interfaceMeetsCriteria = Count<FirstInterface>::MeetsCriteria(interfaceCriteria);
if (interfaceMeetsCriteria == 0) // ComponentBase::interfaceStatus::noacceptor;
{
return ComponentBase::interfaceStatus::noaccepter;
}
else
else // InterfaceStatus::noprovider
{
InterfaceAcceptor< FirstInterface > * acceptIF = (this);
if (acceptIF->CanAcceptConnectionFrom(other))
{
return ComponentBase::interfaceStatus::success;
}
else // ComponentBase::interfaceStatus::noprovider
{
return ComponentBase::interfaceStatus::noprovider;
}
// The found acceptor interface is not identical to a providing interface of the other component
if (restInterfacesStatus == InterfaceStatus::noaccepter)
return InterfaceStatus::noprovider;
return restInterfacesStatus;
}
}
// never reached
return ComponentBase::interfaceStatus::noaccepter;
return InterfaceStatus::noaccepter;
}
......
......@@ -71,14 +71,20 @@ ComponentSelector::AddProvidingInterfaceCriteria(const InterfaceCriteriaType & i
}
// CompatibleInterfaces
unsigned int ComponentSelector::RequireAcceptInterfaceFrom(ComponentBasePointer other, const InterfaceCriteriaType & interfaceCriteria)
unsigned int ComponentSelector::RequireAcceptingInterfaceFrom(ComponentBasePointer other, const InterfaceCriteriaType & interfaceCriteria)
{
this->m_PossibleComponents.remove_if([&](ComponentBasePointer component){auto status = component->CanAcceptConnectionFrom(other, interfaceCriteria);
return status == ComponentBase::interfaceStatus::noaccepter || status == ComponentBase::interfaceStatus::noprovider;
return status == InterfaceStatus::noaccepter || status == InterfaceStatus::noprovider;
});
return 0;
}
unsigned int ComponentSelector::RequireProvidingInterfaceTo(ComponentBasePointer other, const InterfaceCriteriaType & interfaceCriteria)
{
this->m_PossibleComponents.remove_if([&](ComponentBasePointer component){auto status = component->CanProvideConnectionTo(other, interfaceCriteria);
return status == InterfaceStatus::noaccepter || status == InterfaceStatus::noprovider;
});
return 0;
}
ComponentSelector::ComponentBasePointer
ComponentSelector::GetComponent()
{
......
......@@ -53,6 +53,46 @@ Overlord::Configure()
std::cout << nonUniqueComponentNames.size() << " out of " << m_Blueprint->GetComponentNames().size()
<< " Components could not be uniquely selected" << std::endl << std::endl;
for (auto const & name : nonUniqueComponentNames)
{
// check all components that accept from component "name"
for (auto const & outgoingName : this->m_Blueprint->GetOutputNames(name))
{
// if the accepting component is also not uniquely selected, we do not try to check all valid combinations, since this would make the handshake logic too complicated
if (std::find(nonUniqueComponentNames.begin(), nonUniqueComponentNames.end(), outgoingName) != nonUniqueComponentNames.end())
{
Blueprint::ParameterMapType connectionProperties = this->m_Blueprint->GetConnection(name, outgoingName);
ComponentBase::InterfaceCriteriaType interfaceCriteria;
//TODO:
//1: this lambda function converts the blueprint properties: map<string,vector<string>> to interfacecriteria: map<string,string>, consider redesign.
//2: connection blueprint->addConnection("myfirstnode","mysecondnode",{{}}) creates connectionProperties {"",[]} which is not an empty map.
std::for_each(connectionProperties.begin(), connectionProperties.end(), [interfaceCriteria](Blueprint::ParameterMapType::value_type kv) mutable { if (kv.second.size() > 0) interfaceCriteria[kv.first] = kv.second[0]; });
auto outgoingComponent = this->m_ComponentSelectorContainer[outgoingName]->GetComponent();
this->m_ComponentSelectorContainer[name]->RequireProvidingInterfaceTo(outgoingComponent, interfaceCriteria);
}
}
// check all components that provide to component "name"
for (auto const & incomingName : this->m_Blueprint->GetInputNames(name))
{
// if the providing component is also not uniquely selected, we do not try to check all valid combinations, since this would make the handshake logic too complicated
if (std::find(nonUniqueComponentNames.begin(), nonUniqueComponentNames.end(), incomingName) != nonUniqueComponentNames.end())
{
Blueprint::ParameterMapType connectionProperties = this->m_Blueprint->GetConnection(incomingName, name);
ComponentBase::InterfaceCriteriaType interfaceCriteria;
//TODO:
//1: this lambda function converts the blueprint properties: map<string,vector<string>> to interfacecriteria: map<string,string>, consider redesign.
//2: connection blueprint->addConnection("myfirstnode","mysecondnode",{{}}) creates connectionProperties {"",[]} which is not an empty map.
std::for_each(connectionProperties.begin(), connectionProperties.end(), [interfaceCriteria](Blueprint::ParameterMapType::value_type kv) mutable { if (kv.second.size() > 0) interfaceCriteria[kv.first] = kv.second[0]; });
auto incomingComponent = this->m_ComponentSelectorContainer[incomingName]->GetComponent();
this->m_ComponentSelectorContainer[name]->RequireAcceptingInterfaceFrom(incomingComponent, interfaceCriteria);
}
}
}
this->m_isConfigured = true;
}
auto nonUniqueComponentNames = this->GetNonUniqueComponentNames();
......@@ -223,7 +263,7 @@ Overlord::ConnectComponents()
{
numberOfConnections
+= ( targetComponent->AcceptConnectionFrom( interfaceName.c_str(),
sourceComponent ) == ComponentBase::interfaceStatus::success ? 1 : 0 );
sourceComponent) == InterfaceStatus::success ? 1 : 0);
}
}
else
......
......@@ -92,27 +92,27 @@ TEST_F( InterfaceTest, DynamicCast )
TEST_F( InterfaceTest, ConnectByName )
{
ComponentBase::interfaceStatus IFstatus;
InterfaceStatus IFstatus;
EXPECT_NO_THROW( IFstatus = optimizer3p->AcceptConnectionFrom( "MetricValueInterface", metric3p ) );
EXPECT_EQ( IFstatus, ComponentBase::interfaceStatus::success );
EXPECT_EQ( IFstatus, InterfaceStatus::success );
EXPECT_NO_THROW( IFstatus = optimizer3p->AcceptConnectionFrom( "MetricValueInterface", metric4p ) );
EXPECT_EQ( IFstatus, ComponentBase::interfaceStatus::success );
EXPECT_EQ( IFstatus, InterfaceStatus::success );
EXPECT_NO_THROW( IFstatus = optimizer4p->AcceptConnectionFrom( "MetricValueInterface", metric3p ) );
EXPECT_EQ( IFstatus, ComponentBase::interfaceStatus::success );
EXPECT_EQ( IFstatus, InterfaceStatus::success );
EXPECT_NO_THROW( IFstatus = optimizer4p->AcceptConnectionFrom( "MetricValueInterface", metric4p ) );
EXPECT_EQ( IFstatus, ComponentBase::interfaceStatus::success );
EXPECT_EQ( IFstatus, InterfaceStatus::success );
EXPECT_NO_THROW( IFstatus = optimizer3p->AcceptConnectionFrom( "MetricDerivativeInterface", metric3p ) );
EXPECT_EQ( IFstatus, ComponentBase::interfaceStatus::success );
EXPECT_EQ( IFstatus, InterfaceStatus::success );
EXPECT_NO_THROW( IFstatus = optimizer3p->AcceptConnectionFrom( "MetricDerivativeInterface", metric4p ) );
EXPECT_EQ( IFstatus, ComponentBase::interfaceStatus::noprovider );
EXPECT_EQ( IFstatus, InterfaceStatus::noprovider );
EXPECT_NO_THROW( IFstatus = optimizer4p->AcceptConnectionFrom( "MetricDerivativeInterface", metric3p ) );
EXPECT_EQ( IFstatus, ComponentBase::interfaceStatus::noaccepter );
EXPECT_EQ( IFstatus, InterfaceStatus::noaccepter );
}
TEST_F( InterfaceTest, ConnectAll )
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment