Commit 0e23bb37 authored by Floris Berendsen's avatar Floris Berendsen
Browse files

ENH: WIP: Compose Blueprints SuperElastix/SuperElastix#28

parent 9e413ef7
......@@ -60,6 +60,9 @@ public:
bool ConnectionExists( ComponentNameType upstream, ComponentNameType downstream ) const;
// "functional" composition of blueprints is done by adding settings of other to this blueprint. Redefining/overwriting properties is not allowed and returns false.
bool ComposeWith(std::unique_ptr<Blueprint> const &other);
// Returns a vector of the Component names at the incoming direction
ComponentNamesType GetInputNames( const ComponentNameType name ) const;
......
......@@ -102,6 +102,14 @@ Blueprint
}
bool
Blueprint
::ComposeWith(std::unique_ptr<Blueprint> const &other )
{
return this->m_Pimple->ComposeWith(other);
}
Blueprint::ComponentNamesType
Blueprint
::GetOutputNames( const ComponentNameType name ) const
......
......@@ -93,7 +93,16 @@ inline edge_label_writer< ParameterMapType >
return edge_label_writer< ParameterMapType >(p);
}
//Used in CloneGraph
struct Blueprint::BlueprintImpl::vertex_copier {
ComponentPropertyType& from;
ComponentPropertyType& to;
void operator()(Blueprint::BlueprintImpl::GraphType::vertex_descriptor input, Blueprint::BlueprintImpl::GraphType::vertex_descriptor output) const {
//TODO !
//to[output] = { from[input]};
}
};
bool
Blueprint::BlueprintImpl
::SetComponent( ComponentNameType name, ParameterMapType parameterMap )
......@@ -219,6 +228,82 @@ Blueprint::BlueprintImpl
return boost::edge_by_label( upstream, downstream, this->m_Graph ).second;
}
Blueprint::BlueprintImpl::GraphType
Blueprint::BlueprintImpl
::CloneGraph(void) const
{
GraphType clone;
// TODO!
// boost::copy_graph(this->m_Graph, clone, boost::vertex_copy(vertex_copier()));
return clone;
}
bool
Blueprint::BlueprintImpl
::ComposeWith(std::unique_ptr<Blueprint> const &other)
{
// Make a backup of the current blueprint status in case composition fails
GraphType graph_backup = this->CloneGraph();
for (auto const & componentName : other->GetComponentNames())
{
// Does other blueprint use component with a name that already exists?
if (this->ComponentExists(componentName))
{
// Component exists, check if properties can be merged
auto ownProperties = this->GetComponent(componentName);
auto othersProperties = other->GetComponent(componentName);
for (auto const & othersEntry : othersProperties)
{
// Does other use a property key that already exists in this component?
if (ownProperties.count(othersEntry.first))
{
auto && ownValues = ownProperties[othersEntry.first];
auto && otherValues = othersEntry.second;
// Are the property values equal?
if (ownValues.size() != otherValues.size())
{
// No, based on the number of values we see that it is different. Blueprints cannot be Composed
this->m_Graph = graph_backup;
return false;
}
else
{
ParameterValueType::const_iterator ownValue;
ParameterValueType::const_iterator otherValue;
for (ownValue = ownValues.begin(), otherValue = otherValues.begin(); ownValue != ownValues.end(); ++ownValue, ++otherValue)
{
if (*otherValue != *ownValue)
{
// No, at least one value is different. Blueprints cannot be Composed
this->m_Graph = graph_backup;
return false;
}
}
}
}
else
{
// Property key doesn't exist yet, add entry to this component
auto ownProperties = this->GetComponent(componentName);
ownProperties[othersEntry.first] = othersEntry.second;
this->SetComponent(componentName, ownProperties);
}
}
}
else
{
// Create Component copying properties of other
this->SetComponent(componentName, other->GetComponent(componentName));
}
}
return true;
}
Blueprint::ComponentNamesType
Blueprint::BlueprintImpl
......
......@@ -25,6 +25,8 @@
#include "boost/graph/directed_graph.hpp"
#include "boost/graph/labeled_graph.hpp"
#include "boost/graph/copy.hpp" // for ComposeWith
#include "selxBlueprint.h"
namespace selx {
......@@ -46,6 +48,8 @@ struct Blueprint::BlueprintImpl {
ParameterMapType parameterMap;
};
struct vertex_copier;
typedef boost::labeled_graph<
boost::adjacency_list<
boost::vecS,
......@@ -89,6 +93,8 @@ struct Blueprint::BlueprintImpl {
bool ConnectionExists( ComponentNameType upstream, ComponentNameType downstream ) const;
bool ComposeWith(std::unique_ptr<Blueprint> const &other);
// Returns a vector of the Component names at the incoming direction
ComponentNamesType GetInputNames( const ComponentNameType name ) const;
......@@ -99,6 +105,8 @@ struct Blueprint::BlueprintImpl {
ConnectionIndexType GetConnectionIndex( ComponentNameType upsteam, ComponentNameType downstream ) const;
GraphType CloneGraph(void ) const;
GraphType m_Graph;
};
......
......@@ -105,6 +105,51 @@ TEST_F( BlueprintTest, SetGetDeleteConnection )
}
TEST_F(BlueprintTest, Compose)
{
std::unique_ptr< Blueprint > baseBlueprint;
EXPECT_NO_THROW(baseBlueprint = std::unique_ptr< Blueprint >(new Blueprint()));
baseBlueprint->SetComponent("Component0", { { "OperationType", { "Transform" } } });
baseBlueprint->SetComponent("Component1", { { "OperationType", { "Source" } }, { "Dimensionality", { "3" } } });
// compose-in a new 3rd component Component2
std::unique_ptr< Blueprint > nonConflictingBlueprint0;
EXPECT_NO_THROW(nonConflictingBlueprint0 = std::unique_ptr< Blueprint >(new Blueprint()));
nonConflictingBlueprint0->SetComponent("Component2", { { "OperationType", { "Sink" } } });
EXPECT_TRUE(baseBlueprint->ComposeWith(nonConflictingBlueprint0));
// compose-in additional properties of Component0 and Component1
std::unique_ptr< Blueprint > nonConflictingBlueprint1;
EXPECT_NO_THROW(nonConflictingBlueprint1 = std::unique_ptr< Blueprint >(new Blueprint()));
nonConflictingBlueprint1->SetComponent("Component0", { { "TranformationGroup", { "Diffeomorphic" } }, { "PixelType", { "float" } } });
nonConflictingBlueprint1->SetComponent("Component1", { { "NameOfClass", { "ImageSourceClass" } } });
EXPECT_TRUE( baseBlueprint->ComposeWith(nonConflictingBlueprint1) );
// compose-in existing component with existing property key, but equal property value(s). Nothing happens actually (i.e. idempotency)
std::unique_ptr< Blueprint > nonConflictingBlueprint2;
EXPECT_NO_THROW(nonConflictingBlueprint2 = std::unique_ptr< Blueprint >(new Blueprint()));
nonConflictingBlueprint2->SetComponent("Component0", { { "PixelType", { "float" } } });
EXPECT_TRUE(baseBlueprint->ComposeWith(nonConflictingBlueprint2));
// trying to overwrite properties fails
std::unique_ptr< Blueprint > conflictingBlueprint0;
EXPECT_NO_THROW(conflictingBlueprint0 = std::unique_ptr< Blueprint >(new Blueprint()));
conflictingBlueprint0->SetComponent("Component1", { { "Dimensionality", { "2" } }, { "PixelType", { "float" } } });
EXPECT_FALSE(baseBlueprint->ComposeWith(conflictingBlueprint0));
}
//TEST_F( BlueprintTest, WriteBlueprint )
//{
// std::unique_ptr< Blueprint > blueprint;
......
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