IVGCVSW-6633 SubgraphView uses IConnectableLayer rather than Layer in its m_Layers

 * Added IInputSlot, IOutputSlot and IConnectableLayer to SubgraphView
 * Deprecated old member functions
 * Removed deprecated calls in ArmNN
 * Added GetOwningIConnectableLayer function to IOutputSlot
 * Updates ArmNN Core Major version for IOutputSlot ABI break
 * Updated Minor version of TfliteParser, OnnxParser and Delegate

Signed-off-by: Francis Murtagh <francis.murtagh@arm.com>
Change-Id: I2a8611bfabf5ae09d3602fe6a4bef166e18117b9
diff --git a/src/backends/aclCommon/ArmComputeSubgraphUtils.hpp b/src/backends/aclCommon/ArmComputeSubgraphUtils.hpp
index 4367de1..74ab789 100644
--- a/src/backends/aclCommon/ArmComputeSubgraphUtils.hpp
+++ b/src/backends/aclCommon/ArmComputeSubgraphUtils.hpp
@@ -19,14 +19,15 @@
 //
 // this helper only works if all layers where the inputs connect to are not selected
 //
-SubgraphView::InputSlots CreateInputsFrom(const std::vector<Layer*>& layers)
+
+SubgraphView::IInputSlots CreateIInputsFrom(const std::vector<armnn::IConnectableLayer*>& layers)
 {
-    SubgraphView::InputSlots result;
+    SubgraphView::IInputSlots result;
     for (auto&& layer : layers)
     {
-        for (auto&& it = layer->BeginInputSlots(); it != layer->EndInputSlots(); ++it)
+        for (unsigned int i = 0 ; i < layer->GetNumInputSlots(); ++i)
         {
-            result.push_back(&(*it));
+            result.push_back(&(layer->GetInputSlot(i)));
         }
     }
     return result;
@@ -35,14 +36,15 @@
 //
 // this helper only works if all layers where the outputs connect to are not selected
 //
-SubgraphView::OutputSlots CreateOutputsFrom(const std::vector<Layer*>& layers)
+
+SubgraphView::IOutputSlots CreateIOutputsFrom(const std::vector<armnn::IConnectableLayer*>& layers)
 {
-    SubgraphView::OutputSlots result;
-    for (auto&& layer : layers)
+    SubgraphView::IOutputSlots result;
+    for (auto &&layer: layers)
     {
-        for (auto&& it = layer->BeginOutputSlots(); it != layer->EndOutputSlots(); ++it)
+        for (unsigned int i = 0; i < layer->GetNumOutputSlots(); ++i)
         {
-            result.push_back(&(*it));
+            result.push_back(&(layer->GetOutputSlot(i)));
         }
     }
     return result;
@@ -83,9 +85,9 @@
     for (const auto& pair : untouched)
     {
         Layer* layer = pair.second;
-        SubgraphView subgraphView(CreateInputsFrom({layer}),
-                                  CreateOutputsFrom({layer}),
-                                  {layer});
+        SubgraphView subgraphView({layer},
+                                  CreateIInputsFrom({layer}),
+                                  CreateIOutputsFrom({layer}));
         optimizationViews.AddUntouchedSubgraph(std::move(subgraphView));
     }
 }
@@ -100,9 +102,9 @@
     replacementLayer->SetAdditionalInfoForObject(
         std::make_shared<ActivationDescriptor>(activationDesc));
 
-    SubgraphView substitutionSubgraph(CreateInputsFrom({baseLayer}),
-                                      CreateOutputsFrom({activationLayer}),
-                                      {baseLayer, activationLayer});
+    SubgraphView substitutionSubgraph({baseLayer, activationLayer},
+                                      CreateIInputsFrom({baseLayer}),
+                                      CreateIOutputsFrom({activationLayer}));
     SubgraphView replacementSubgraph(replacementLayer);
 
     optimizationViews.AddSubstitution({substitutionSubgraph, replacementSubgraph});
@@ -208,6 +210,11 @@
               activationLayer,
               activationDesc);
 
+    SubgraphView substitutionSubgraph({baseLayer, activationLayer},
+                                      CreateIInputsFrom({baseLayer}),
+                                      CreateIOutputsFrom({activationLayer}));
+    SubgraphView replacementSubgraph(replacementLayer);
+
     return replacementLayer;
 }
 
@@ -316,12 +323,12 @@
 // as currently only one axis is supported.
 //
 template<typename LayerType>
-std::vector<Layer*> ChainReduceLayers(OptimizationViews& optimizationViews,
+std::vector<IConnectableLayer*> ChainReduceLayers(OptimizationViews& optimizationViews,
                                       LayerType* baseLayer,
                                       ReduceDescriptor& desc)
 {
     // Vector of new chained layers, used for substitution.
-    std::vector<Layer*> layers;
+    std::vector<IConnectableLayer*> layers;
 
     // Vector of axes so each layer is reshaped correctly.
     std::vector<uint32_t> axes;
@@ -348,9 +355,11 @@
 
         // Add new layer to graph.
         std::string layerName = "reduce_layer_" + std::to_string(i);
+
         Layer* replacementLayer = PolymorphicDowncast<Layer*>(
             optimizationViews.GetINetwork()->AddReduceLayer(newReduceDescriptor,
                                                             layerName.c_str()));
+
         // Connect previous layer with new layer.
         // The first and last layer will be connected when the subgraph is replaced.
         if (!layers.empty())
@@ -370,7 +379,8 @@
     }
 
     // Check if the TensorInfo from the last layer equals the inferred output from the original layer.
-    ARMNN_ASSERT(baseLayer->GetOutputSlot(0).GetTensorInfo() == layers.back()->GetOutputSlot().GetTensorInfo());
+    ARMNN_ASSERT(baseLayer->GetOutputSlot(0).GetTensorInfo() ==
+                 PolymorphicDowncast<Layer*>(layers.back())->GetOutputSlot().GetTensorInfo());
 
     return layers;
 }
@@ -381,14 +391,14 @@
 template<typename LayerType>
 void ReplaceLayers(OptimizationViews& optimizationViews,
                    LayerType* baseLayer,
-                   std::vector<Layer*>& layers)
+                   std::vector<IConnectableLayer*>& layers)
 {
-    std::list<Layer*> replacementLayers(layers.begin(), layers.end());
+    std::list<IConnectableLayer*> replacementLayers(layers.begin(), layers.end());
 
     SubgraphView substitutionSubgraph(baseLayer);
-    SubgraphView replacementSubgraph(CreateInputsFrom({replacementLayers.front()}),
-                                     CreateOutputsFrom({replacementLayers.back()}),
-                                     std::move(replacementLayers));
+    SubgraphView replacementSubgraph(std::move(replacementLayers),
+                                     CreateIInputsFrom({replacementLayers.front()}),
+                                     CreateIOutputsFrom({replacementLayers.back()}));
 
     optimizationViews.AddSubstitution({substitutionSubgraph, replacementSubgraph});
 }
diff --git a/src/backends/backendsCommon/OptimizationViews.cpp b/src/backends/backendsCommon/OptimizationViews.cpp
index eee2c67..e81a691 100644
--- a/src/backends/backendsCommon/OptimizationViews.cpp
+++ b/src/backends/backendsCommon/OptimizationViews.cpp
@@ -17,24 +17,28 @@
     bool valid = true;
 
     // Create a copy of the layer list from the original subgraph and sort it
-    SubgraphView::Layers originalLayers = originalSubgraph.GetLayers();
+    SubgraphView::IConnectableLayers originalLayers = originalSubgraph.GetIConnectableLayers();
     originalLayers.sort();
 
     // Create a new list based on the sum of all the subgraphs and sort it
-    SubgraphView::Layers countedLayers;
+    SubgraphView::IConnectableLayers countedLayers;
     for (auto& failed : m_FailedOptimizations)
     {
-        countedLayers.insert(countedLayers.end(), failed.GetLayers().begin(), failed.GetLayers().end());
+        countedLayers.insert(countedLayers.end(),
+                             failed.GetIConnectableLayers().begin(),
+                             failed.GetIConnectableLayers().end());
     }
     for (auto& untouched : m_UntouchedSubgraphs)
     {
-        countedLayers.insert(countedLayers.end(), untouched.GetLayers().begin(), untouched.GetLayers().end());
+        countedLayers.insert(countedLayers.end(),
+                             untouched.GetIConnectableLayers().begin(),
+                             untouched.GetIConnectableLayers().end());
     }
     for (auto& successful : m_SuccesfulOptimizations)
     {
         countedLayers.insert(countedLayers.end(),
-                             successful.m_SubstitutableSubgraph.GetLayers().begin(),
-                             successful.m_SubstitutableSubgraph.GetLayers().end());
+                             successful.m_SubstitutableSubgraph.GetIConnectableLayers().begin(),
+                             successful.m_SubstitutableSubgraph.GetIConnectableLayers().end());
     }
     countedLayers.sort();
 
@@ -56,8 +60,8 @@
             bool validSubstitution = true;
             const SubgraphView& replacement = substitution.m_ReplacementSubgraph;
             const SubgraphView& old = substitution.m_SubstitutableSubgraph;
-            validSubstitution &= replacement.GetInputSlots().size() == old.GetInputSlots().size();
-            validSubstitution &= replacement.GetOutputSlots().size() == old.GetOutputSlots().size();
+            validSubstitution &= replacement.GetIInputSlots().size() == old.GetIInputSlots().size();
+            validSubstitution &= replacement.GetIOutputSlots().size() == old.GetIOutputSlots().size();
             valid &= validSubstitution;
         }
     }
diff --git a/src/backends/backendsCommon/test/MockBackend.cpp b/src/backends/backendsCommon/test/MockBackend.cpp
index d95cfc3..2ce14f9 100644
--- a/src/backends/backendsCommon/test/MockBackend.cpp
+++ b/src/backends/backendsCommon/test/MockBackend.cpp
@@ -130,21 +130,21 @@
     OptimizationViews optimizationViews;
 
     // Get the layers of the input sub-graph
-    const SubgraphView::Layers& subgraphLayers = subgraph.GetLayers();
+    const SubgraphView::IConnectableLayers& subgraphLayers = subgraph.GetIConnectableLayers();
 
     // Parse the layers
-    SubgraphView::Layers supportedLayers;
-    SubgraphView::Layers unsupportedLayers;
-    SubgraphView::Layers untouchedLayers;
+    SubgraphView::IConnectableLayers supportedLayers;
+    SubgraphView::IConnectableLayers unsupportedLayers;
+    SubgraphView::IConnectableLayers untouchedLayers;
     std::for_each(subgraphLayers.begin(),
                   subgraphLayers.end(),
-                  [&](Layer* layer)
+                  [&](IConnectableLayer* layer)
     {
-        bool supported = IsLayerSupported(layer);
+        bool supported = IsLayerSupported(PolymorphicDowncast<Layer*>(layer));
         if (supported)
         {
             // Layer supported, check if it's optimizable
-            bool optimizable = IsLayerOptimizable(layer);
+            bool optimizable = IsLayerOptimizable(PolymorphicDowncast<Layer*>(layer));
             if (optimizable)
             {
                 // Layer fully supported
diff --git a/src/backends/backendsCommon/test/OptimizeSubgraphViewTests.cpp b/src/backends/backendsCommon/test/OptimizeSubgraphViewTests.cpp
index 4dd6bc9..8036b41 100644
--- a/src/backends/backendsCommon/test/OptimizeSubgraphViewTests.cpp
+++ b/src/backends/backendsCommon/test/OptimizeSubgraphViewTests.cpp
@@ -56,6 +56,18 @@
     return output;
 }
 
+// Convert from vector of Slots* (Input/Output) to vector of ISlots* (IInput/IOutput)
+template <typename SlotType, typename ResultSlotType>
+std::vector<ResultSlotType*> ConvertSlotsToISlots(const std::vector<SlotType*> input)
+{
+    std::vector<ResultSlotType*> output;
+    for (auto slot : input)
+    {
+        output.push_back(PolymorphicDowncast<ResultSlotType*>(slot));
+    }
+    return output;
+}
+
 // Convenience function to add an input layer to a graph
 Layer* AddInputLayer(Graph& graph,
                      const std::string& layerName,
@@ -125,19 +137,20 @@
 void CheckSubstitution(const OptimizationViews::SubstitutionPair& substitution,
                        const ExpectedSubgraphSize& expectedSubstitutableSubgraphSize,
                        const ExpectedSubgraphSize& expectedReplacementSubgraphSize,
-                       const SubgraphView::InputSlots& expectedSubstitutableInputSlots,
-                       const SubgraphView::OutputSlots& expectedSubstitutableOutputSlots,
-                       const SubgraphView::Layers& expectedSubstitutableLayers)
+                       const SubgraphView::IInputSlots& expectedSubstitutableInputSlots,
+                       const SubgraphView::IOutputSlots& expectedSubstitutableOutputSlots,
+                       const SubgraphView::IConnectableLayers& expectedSubstitutableLayers)
 {
-    const SubgraphView&              substitutableSubgraph            = substitution.m_SubstitutableSubgraph;
-    const SubgraphView::InputSlots&  substitutableSubgraphInputSlots  = substitutableSubgraph.GetInputSlots();
-    const SubgraphView::OutputSlots& substitutableSubgraphOutputSlots = substitutableSubgraph.GetOutputSlots();
-    const SubgraphView::Layers&      substitutableSubgraphLayers      = substitutableSubgraph.GetLayers();
+    const SubgraphView& substitutableSubgraph = substitution.m_SubstitutableSubgraph;
+    const SubgraphView::IInputSlots& substitutableSubgraphInputSlots = substitutableSubgraph.GetIInputSlots();
+    const SubgraphView::IOutputSlots& substitutableSubgraphOutputSlots = substitutableSubgraph.GetIOutputSlots();
+    const SubgraphView::IConnectableLayers& substitutableSubgraphLayers =
+            substitutableSubgraph.GetIConnectableLayers();
 
-    const SubgraphView&              replacementSubgraph            = substitution.m_ReplacementSubgraph;
-    const SubgraphView::InputSlots&  replacementSubgraphInputSlots  = replacementSubgraph.GetInputSlots();
-    const SubgraphView::OutputSlots& replacementSubgraphOutputSlots = replacementSubgraph.GetOutputSlots();
-    const SubgraphView::Layers&      replacementSubgraphLayers      = replacementSubgraph.GetLayers();
+    const SubgraphView& replacementSubgraph                          = substitution.m_ReplacementSubgraph;
+    const SubgraphView::IInputSlots& replacementSubgraphInputSlots   = replacementSubgraph.GetIInputSlots();
+    const SubgraphView::IOutputSlots& replacementSubgraphOutputSlots = replacementSubgraph.GetIOutputSlots();
+    const SubgraphView::IConnectableLayers& replacementSubgraphLayers = replacementSubgraph.GetIConnectableLayers();
 
     CHECK(substitutableSubgraphInputSlots.size()  == expectedSubstitutableSubgraphSize.m_NumInputSlots);
     CHECK(substitutableSubgraphOutputSlots.size() == expectedSubstitutableSubgraphSize.m_NumOutputSlots);
@@ -157,7 +170,7 @@
 
     CHECK(std::all_of(replacementSubgraphLayers.begin(),
                            replacementSubgraphLayers.end(),
-                           [](const Layer* layer)
+                           [](const IConnectableLayer* layer)
     {
         return layer->GetType() == LayerType::PreCompiled;
     }));
@@ -166,13 +179,13 @@
 // Convenience function to check that the given failed subgraph matches the specified expected values
 void CheckFailedSubgraph(const SubgraphView& failedSubgraph,
                          const ExpectedSubgraphSize& expectedFailedSubgraphSize,
-                         const SubgraphView::InputSlots& expectedFailedInputSlots,
-                         const SubgraphView::OutputSlots& expectedFailedOutputSlots,
-                         const SubgraphView::Layers& expectedFailedLayers)
+                         const SubgraphView::IInputSlots& expectedFailedInputSlots,
+                         const SubgraphView::IOutputSlots& expectedFailedOutputSlots,
+                         const SubgraphView::IConnectableLayers& expectedFailedLayers)
 {
-    const SubgraphView::InputSlots&  failedSubgraphInputSlots  = failedSubgraph.GetInputSlots();
-    const SubgraphView::OutputSlots& failedSubgraphOutputSlots = failedSubgraph.GetOutputSlots();
-    const SubgraphView::Layers&      failedSubgraphLayers      = failedSubgraph.GetLayers();
+    const SubgraphView::IInputSlots&  failedSubgraphInputSlots  = failedSubgraph.GetIInputSlots();
+    const SubgraphView::IOutputSlots& failedSubgraphOutputSlots = failedSubgraph.GetIOutputSlots();
+    const SubgraphView::IConnectableLayers& failedSubgraphLayers = failedSubgraph.GetIConnectableLayers();
 
     CHECK(failedSubgraphInputSlots.size()  == expectedFailedSubgraphSize.m_NumInputSlots);
     CHECK(failedSubgraphOutputSlots.size() == expectedFailedSubgraphSize.m_NumOutputSlots);
@@ -186,13 +199,13 @@
 // Convenience function to check that the given untouched subgraph matches the specified expected values
 void CheckUntouchedSubgraph(const SubgraphView& untouchedSubgraph,
                             const ExpectedSubgraphSize& expectedUntouchedSubgraphSize,
-                            const SubgraphView::InputSlots& expectedUntouchedInputSlots,
-                            const SubgraphView::OutputSlots& expectedUntouchedOutputSlots,
-                            const SubgraphView::Layers& expectedUntouchedLayers)
+                            const SubgraphView::IInputSlots& expectedUntouchedInputSlots,
+                            const SubgraphView::IOutputSlots& expectedUntouchedOutputSlots,
+                            const SubgraphView::IConnectableLayers& expectedUntouchedLayers)
 {
-    const SubgraphView::InputSlots&  untouchedSubgraphInputSlots  = untouchedSubgraph.GetInputSlots();
-    const SubgraphView::OutputSlots& untouchedSubgraphOutputSlots = untouchedSubgraph.GetOutputSlots();
-    const SubgraphView::Layers&      untouchedSubgraphLayers      = untouchedSubgraph.GetLayers();
+    const SubgraphView::IInputSlots& untouchedSubgraphInputSlots = untouchedSubgraph.GetIInputSlots();
+    const SubgraphView::IOutputSlots& untouchedSubgraphOutputSlots = untouchedSubgraph.GetIOutputSlots();
+    const SubgraphView::IConnectableLayers& untouchedSubgraphLayers = untouchedSubgraph.GetIConnectableLayers();
 
     CHECK(untouchedSubgraphInputSlots.size()  == expectedUntouchedSubgraphSize.m_NumInputSlots);
     CHECK(untouchedSubgraphOutputSlots.size() == expectedUntouchedSubgraphSize.m_NumOutputSlots);
@@ -552,9 +565,9 @@
     SubgraphView::SubgraphViewPtr subgraphPtr = BuildFullyUnsupportedSubgraph1(graph, layersInGraph);
     CHECK((subgraphPtr != nullptr));
 
-    const SubgraphView::InputSlots&  subgraphInputSlots  = subgraphPtr->GetInputSlots();
-    const SubgraphView::OutputSlots& subgraphOutputSlots = subgraphPtr->GetOutputSlots();
-    const SubgraphView::Layers&      subgraphLayers      = subgraphPtr->GetLayers();
+    const SubgraphView::IInputSlots& subgraphInputSlots = subgraphPtr->GetIInputSlots();
+    const SubgraphView::IOutputSlots& subgraphOutputSlots = subgraphPtr->GetIOutputSlots();
+    const SubgraphView::IConnectableLayers& subgraphLayers = subgraphPtr->GetIConnectableLayers();
 
     CHECK(subgraphInputSlots.size()  == 1);
     CHECK(subgraphOutputSlots.size() == 1);
@@ -616,9 +629,9 @@
     SubgraphView::SubgraphViewPtr subgraphPtr = BuildFullyUnsupportedSubgraph2(graph, layersInGraph);
     CHECK((subgraphPtr != nullptr));
 
-    const SubgraphView::InputSlots&  subgraphInputSlots  = subgraphPtr->GetInputSlots();
-    const SubgraphView::OutputSlots& subgraphOutputSlots = subgraphPtr->GetOutputSlots();
-    const SubgraphView::Layers&      subgraphLayers      = subgraphPtr->GetLayers();
+    const SubgraphView::IInputSlots& subgraphInputSlots = subgraphPtr->GetIInputSlots();
+    const SubgraphView::IOutputSlots& subgraphOutputSlots = subgraphPtr->GetIOutputSlots();
+    const SubgraphView::IConnectableLayers& subgraphLayers = subgraphPtr->GetIConnectableLayers();
 
     CHECK(subgraphInputSlots.size()  == 1);
     CHECK(subgraphOutputSlots.size() == 1);
@@ -659,7 +672,7 @@
     const OptimizationViews::Subgraphs& failedSubgraphs = optimizationViews.GetFailedSubgraphs();
     CHECK(failedSubgraphs.size() == 1);
 
-    std::list<Layer*> expectedFailedLayers{ layersInGraph.at("pooling1 layer"),
+    std::list<IConnectableLayer*> expectedFailedLayers{ layersInGraph.at("pooling1 layer"),
                                             layersInGraph.at("pooling2 layer"),
                                             layersInGraph.at("pooling3 layer") };
 
@@ -671,7 +684,7 @@
                         subgraphOutputSlots,
                         subgraphLayers);
 
-    const SubgraphView::Layers& failedSubgraphLayers = failedSubgraph.GetLayers();
+    const SubgraphView::IConnectableLayers& failedSubgraphLayers = failedSubgraph.GetIConnectableLayers();
 
     CHECK_EQ(failedSubgraphLayers.front() + 0, expectedFailedLayers.front() + 0);
     CHECK_EQ(failedSubgraphLayers.front() + 1, expectedFailedLayers.front() + 1);
@@ -694,9 +707,9 @@
     SubgraphViewSelector::SubgraphViewPtr subgraphPtr = BuildFullyOptimizableSubgraph1(graph, layersInGraph);
     CHECK((subgraphPtr != nullptr));
 
-    const SubgraphView::InputSlots&  subgraphInputSlots  = subgraphPtr->GetInputSlots();
-    const SubgraphView::OutputSlots& subgraphOutputSlots = subgraphPtr->GetOutputSlots();
-    const SubgraphView::Layers&      subgraphLayers      = subgraphPtr->GetLayers();
+    const SubgraphView::IInputSlots& subgraphInputSlots = subgraphPtr->GetIInputSlots();
+    const SubgraphView::IOutputSlots& subgraphOutputSlots = subgraphPtr->GetIOutputSlots();
+    const SubgraphView::IConnectableLayers& subgraphLayers = subgraphPtr->GetIConnectableLayers();
 
     CHECK(subgraphInputSlots.size()  == 1);
     CHECK(subgraphOutputSlots.size() == 1);
@@ -759,13 +772,13 @@
     SubgraphViewSelector::SubgraphViewPtr subgraphPtr = BuildFullyOptimizableSubgraph2(graph, layersInGraph);
     CHECK((subgraphPtr != nullptr));
 
-    const SubgraphView::InputSlots&  subgraphInputSlots  = subgraphPtr->GetInputSlots();
-    const SubgraphView::OutputSlots& subgraphOutputSlots = subgraphPtr->GetOutputSlots();
-    const SubgraphView::Layers&      subgraphLayers      = subgraphPtr->GetLayers();
+    const SubgraphView::IInputSlots& subgraphInputSlots = subgraphPtr->GetIInputSlots();
+    const SubgraphView::IOutputSlots& subgraphOutputSlots = subgraphPtr->GetIOutputSlots();
+    const SubgraphView::IConnectableLayers& subgraphLayers = subgraphPtr->GetIConnectableLayers();
 
-    CHECK(subgraphPtr->GetInputSlots().size()  == 1);
-    CHECK(subgraphPtr->GetOutputSlots().size() == 1);
-    CHECK(subgraphPtr->GetLayers().size()      == 5);
+    CHECK(subgraphPtr->GetIInputSlots().size()  == 1);
+    CHECK(subgraphPtr->GetIOutputSlots().size() == 1);
+    CHECK(subgraphPtr->GetIConnectableLayers().size() == 5);
 
     CHECK(Contains(layersInGraph, "conv1 layer"));
     CHECK(Contains(layersInGraph, "conv2 layer"));
@@ -798,7 +811,7 @@
     const OptimizationViews::Substitutions& substitutions = optimizationViews.GetSubstitutions();
     CHECK(substitutions.size() == 1);
 
-    std::list<Layer*> expectedSubstitutableLayers{ layersInGraph.at("conv1 layer"),
+    std::list<IConnectableLayer*> expectedSubstitutableLayers{ layersInGraph.at("conv1 layer"),
                                                    layersInGraph.at("conv2 layer"),
                                                    layersInGraph.at("conv3 layer"),
                                                    layersInGraph.at("conv4 layer"),
@@ -813,7 +826,8 @@
                       subgraphOutputSlots,
                       expectedSubstitutableLayers);
 
-    const SubgraphView::Layers& substitutableSubgraphLayers = substitution.m_SubstitutableSubgraph.GetLayers();
+    const SubgraphView::IConnectableLayers& substitutableSubgraphLayers =
+            substitution.m_SubstitutableSubgraph.GetIConnectableLayers();
 
     CHECK_EQ(substitutableSubgraphLayers.front() + 0, expectedSubstitutableLayers.front() + 0);
     CHECK_EQ(substitutableSubgraphLayers.front() + 1, expectedSubstitutableLayers.front() + 1);
@@ -845,9 +859,9 @@
     SubgraphViewSelector::SubgraphViewPtr subgraphPtr = BuildPartiallySupportedSubgraph(graph, layersInGraph);
     CHECK((subgraphPtr != nullptr));
 
-    const SubgraphView::InputSlots&  subgraphInputSlots  = subgraphPtr->GetInputSlots();
-    const SubgraphView::OutputSlots& subgraphOutputSlots = subgraphPtr->GetOutputSlots();
-    const SubgraphView::Layers&      subgraphLayers      = subgraphPtr->GetLayers();
+    const SubgraphView::IInputSlots& subgraphInputSlots = subgraphPtr->GetIInputSlots();
+    const SubgraphView::IOutputSlots& subgraphOutputSlots = subgraphPtr->GetIOutputSlots();
+    const SubgraphView::IConnectableLayers& subgraphLayers = subgraphPtr->GetIConnectableLayers();
 
     CHECK(subgraphInputSlots.size()  == 1);
     CHECK(subgraphOutputSlots.size() == 1);
@@ -885,25 +899,30 @@
     CHECK(substitutions.size() == 2);
     // Sort into a consistent order
     std::sort(substitutions.begin(), substitutions.end(), [](auto s1, auto s2) {
-        return strcmp(s1.m_SubstitutableSubgraph.GetLayers().front()->GetName(),
-                      s2.m_SubstitutableSubgraph.GetLayers().front()->GetName()) < 0;
+        return strcmp(s1.m_SubstitutableSubgraph.GetIConnectableLayers().front()->GetName(),
+                      s2.m_SubstitutableSubgraph.GetIConnectableLayers().front()->GetName()) < 0;
     });
 
     std::vector<ExpectedSubgraphSize> expectedSubstitutableSubgraphSizes{ { 1, 1, 1 },
                                                                           { 1, 1, 1 } };
     std::vector<ExpectedSubgraphSize> expectedReplacementSubgraphSizes{ { 1, 1, 1 },
                                                                         { 1, 1, 1 } };
-    std::vector<SubgraphView::InputSlots> expectedSubstitutableInputSlots
+    std::vector<SubgraphView::IInputSlots> expectedSubstitutableInputSlots
     {
-        ConvertReferenceTypeToPointerType(layersInGraph.at("conv1 layer")->GetInputSlots()),
-        ConvertReferenceTypeToPointerType(layersInGraph.at("conv2 layer")->GetInputSlots())
+            ConvertSlotsToISlots<InputSlot, IInputSlot>(
+        ConvertReferenceTypeToPointerType(layersInGraph.at("conv1 layer")->GetInputSlots())),
+            ConvertSlotsToISlots<InputSlot, IInputSlot>(
+        ConvertReferenceTypeToPointerType(layersInGraph.at("conv2 layer")->GetInputSlots()))
     };
-    std::vector<SubgraphView::OutputSlots> expectedSubstitutableOutputSlots
+
+    std::vector<SubgraphView::IOutputSlots> expectedSubstitutableOutputSlots
     {
-        ConvertReferenceTypeToPointerType(layersInGraph.at("conv1 layer")->GetOutputSlots()),
-        ConvertReferenceTypeToPointerType(layersInGraph.at("conv2 layer")->GetOutputSlots())
+        ConvertSlotsToISlots<OutputSlot, IOutputSlot>(
+                ConvertReferenceTypeToPointerType(layersInGraph.at("conv1 layer")->GetOutputSlots())),
+        ConvertSlotsToISlots<OutputSlot, IOutputSlot>(
+                ConvertReferenceTypeToPointerType(layersInGraph.at("conv2 layer")->GetOutputSlots()))
     };
-    std::vector<SubgraphView::Layers> expectedSubstitutableLayers
+    std::vector<SubgraphView::IConnectableLayers> expectedSubstitutableLayers
     {
         { layersInGraph.at("conv1 layer") },
         { layersInGraph.at("conv2 layer") }
@@ -927,22 +946,27 @@
     CHECK(failedSubgraphs.size() == 2);
     // Sort into a consistent order
     std::sort(failedSubgraphs.begin(), failedSubgraphs.end(), [](auto s1, auto s2) {
-        return strcmp(s1.GetLayers().front()->GetName(), s2.GetLayers().front()->GetName()) < 0;
+        return strcmp(s1.GetIConnectableLayers().front()->GetName(),
+                      s2.GetIConnectableLayers().front()->GetName()) < 0;
     });
 
     std::vector<ExpectedSubgraphSize> expectedFailedSubgraphSizes{ { 1, 1, 2 },
                                                                    { 1, 1, 1 } };
-    std::vector<SubgraphView::InputSlots> expectedFailedInputSlots
+    std::vector<SubgraphView::IInputSlots> expectedFailedInputSlots
     {
-        ConvertReferenceTypeToPointerType(layersInGraph.at("pooling1 layer")->GetInputSlots()),
-        ConvertReferenceTypeToPointerType(layersInGraph.at("pooling3 layer")->GetInputSlots())
+        ConvertSlotsToISlots<InputSlot, IInputSlot>(
+        ConvertReferenceTypeToPointerType(layersInGraph.at("pooling1 layer")->GetInputSlots())),
+        ConvertSlotsToISlots<InputSlot, IInputSlot>(
+        ConvertReferenceTypeToPointerType(layersInGraph.at("pooling3 layer")->GetInputSlots()))
     };
-    std::vector<SubgraphView::OutputSlots> expectedFailedOutputSlots
+    std::vector<SubgraphView::IOutputSlots> expectedFailedOutputSlots
     {
-        ConvertReferenceTypeToPointerType(layersInGraph.at("pooling2 layer")->GetOutputSlots()),
-        ConvertReferenceTypeToPointerType(layersInGraph.at("pooling3 layer")->GetOutputSlots())
+        ConvertSlotsToISlots<OutputSlot, IOutputSlot>(
+        ConvertReferenceTypeToPointerType(layersInGraph.at("pooling2 layer")->GetOutputSlots())),
+        ConvertSlotsToISlots<OutputSlot, IOutputSlot>(
+        ConvertReferenceTypeToPointerType(layersInGraph.at("pooling3 layer")->GetOutputSlots()))
     };
-    std::vector<SubgraphView::Layers> expectedFailedLayers
+    std::vector<SubgraphView::IConnectableLayers> expectedFailedLayers
     {
         { layersInGraph.at("pooling1 layer"),
           layersInGraph.at("pooling2 layer") },
@@ -975,9 +999,9 @@
     SubgraphViewSelector::SubgraphViewPtr subgraphPtr = BuildFullyUnoptimizableSubgraph1(graph, layersInGraph);
     CHECK((subgraphPtr != nullptr));
 
-    const SubgraphView::InputSlots&  subgraphInputSlots  = subgraphPtr->GetInputSlots();
-    const SubgraphView::OutputSlots& subgraphOutputSlots = subgraphPtr->GetOutputSlots();
-    const SubgraphView::Layers&      subgraphLayers      = subgraphPtr->GetLayers();
+    const SubgraphView::IInputSlots& subgraphInputSlots = subgraphPtr->GetIInputSlots();
+    const SubgraphView::IOutputSlots& subgraphOutputSlots = subgraphPtr->GetIOutputSlots();
+    const SubgraphView::IConnectableLayers& subgraphLayers = subgraphPtr->GetIConnectableLayers();
 
     CHECK(subgraphInputSlots.size()  == 1);
     CHECK(subgraphOutputSlots.size() == 1);
@@ -1039,9 +1063,9 @@
     SubgraphViewSelector::SubgraphViewPtr subgraphPtr = BuildPartiallyOptimizableSubgraph1(graph, layersInGraph);
     CHECK((subgraphPtr != nullptr));
 
-    const SubgraphView::InputSlots&  subgraphInputSlots  = subgraphPtr->GetInputSlots();
-    const SubgraphView::OutputSlots& subgraphOutputSlots = subgraphPtr->GetOutputSlots();
-    const SubgraphView::Layers&      subgraphLayers      = subgraphPtr->GetLayers();
+    const SubgraphView::IInputSlots& subgraphInputSlots = subgraphPtr->GetIInputSlots();
+    const SubgraphView::IOutputSlots& subgraphOutputSlots = subgraphPtr->GetIOutputSlots();
+    const SubgraphView::IConnectableLayers& subgraphLayers = subgraphPtr->GetIConnectableLayers();
 
     CHECK(subgraphInputSlots.size()  == 1);
     CHECK(subgraphOutputSlots.size() == 1);
@@ -1079,8 +1103,9 @@
     CHECK(substitutions.size() == 3);
     // Sort into a consistent order
     std::sort(substitutions.begin(), substitutions.end(),
-        [](auto s1, auto s2) { return strcmp(s1.m_SubstitutableSubgraph.GetLayers().front()->GetName(),
-                                             s2.m_SubstitutableSubgraph.GetLayers().front()->GetName()) < 0; });
+        [](auto s1, auto s2)
+        { return strcmp(s1.m_SubstitutableSubgraph.GetIConnectableLayers().front()->GetName(),
+                        s2.m_SubstitutableSubgraph.GetIConnectableLayers().front()->GetName()) < 0; });
 
     std::vector<ExpectedSubgraphSize> expectedSubstitutableSubgraphSizes{ { 1, 1, 1 },
                                                                           { 1, 1, 1 },
@@ -1088,19 +1113,25 @@
     std::vector<ExpectedSubgraphSize> expectedReplacementSubgraphSizes{ { 1, 1, 1 },
                                                                         { 1, 1, 1 },
                                                                         { 1, 1, 1 } };
-    std::vector<SubgraphView::InputSlots> expectedSubstitutableInputSlots
+    std::vector<SubgraphView::IInputSlots> expectedSubstitutableInputSlots
     {
-        ConvertReferenceTypeToPointerType(layersInGraph.at("conv1 layer")->GetInputSlots()),
-        ConvertReferenceTypeToPointerType(layersInGraph.at("conv3 layer")->GetInputSlots()),
-        ConvertReferenceTypeToPointerType(layersInGraph.at("conv5 layer")->GetInputSlots())
+        ConvertSlotsToISlots<InputSlot, IInputSlot>(
+        ConvertReferenceTypeToPointerType(layersInGraph.at("conv1 layer")->GetInputSlots())),
+        ConvertSlotsToISlots<InputSlot, IInputSlot>(
+        ConvertReferenceTypeToPointerType(layersInGraph.at("conv3 layer")->GetInputSlots())),
+        ConvertSlotsToISlots<InputSlot, IInputSlot>(
+        ConvertReferenceTypeToPointerType(layersInGraph.at("conv5 layer")->GetInputSlots()))
     };
-    std::vector<SubgraphView::OutputSlots> expectedSubstitutableOutputSlots
+    std::vector<SubgraphView::IOutputSlots> expectedSubstitutableOutputSlots
     {
-        ConvertReferenceTypeToPointerType(layersInGraph.at("conv1 layer")->GetOutputSlots()),
-        ConvertReferenceTypeToPointerType(layersInGraph.at("conv3 layer")->GetOutputSlots()),
-        ConvertReferenceTypeToPointerType(layersInGraph.at("conv5 layer")->GetOutputSlots())
+        ConvertSlotsToISlots<OutputSlot, IOutputSlot>(
+        ConvertReferenceTypeToPointerType(layersInGraph.at("conv1 layer")->GetOutputSlots())),
+        ConvertSlotsToISlots<OutputSlot, IOutputSlot>(
+        ConvertReferenceTypeToPointerType(layersInGraph.at("conv3 layer")->GetOutputSlots())),
+        ConvertSlotsToISlots<OutputSlot, IOutputSlot>(
+        ConvertReferenceTypeToPointerType(layersInGraph.at("conv5 layer")->GetOutputSlots()))
     };
-    std::vector<SubgraphView::Layers> expectedSubstitutableLayers
+    std::vector<SubgraphView::IConnectableLayers> expectedSubstitutableLayers
     {
         { layersInGraph.at("conv1 layer") },
         { layersInGraph.at("conv3 layer") },
@@ -1131,22 +1162,27 @@
     CHECK(untouchedSubgraphs.size() == 2);
     // Sort into a consistent order
     std::sort(untouchedSubgraphs.begin(), untouchedSubgraphs.end(), [](auto s1, auto s2) {
-        return strcmp(s1.GetLayers().front()->GetName(), s2.GetLayers().front()->GetName()) < 0;
+        return strcmp(s1.GetIConnectableLayers().front()->GetName(),
+                      s2.GetIConnectableLayers().front()->GetName()) < 0;
     });
 
     std::vector<ExpectedSubgraphSize> expectedUntouchedSubgraphSizes{ { 1, 1, 1 },
                                                                       { 1, 1, 1 } };
-    std::vector<SubgraphView::InputSlots> expectedUntouchedInputSlots
+    std::vector<SubgraphView::IInputSlots> expectedUntouchedInputSlots
     {
-        ConvertReferenceTypeToPointerType(layersInGraph.at("conv2 layer unoptimizable")->GetInputSlots()),
-        ConvertReferenceTypeToPointerType(layersInGraph.at("conv4 layer unoptimizable")->GetInputSlots())
+            ConvertSlotsToISlots<InputSlot, IInputSlot>(
+        ConvertReferenceTypeToPointerType(layersInGraph.at("conv2 layer unoptimizable")->GetInputSlots())),
+            ConvertSlotsToISlots<InputSlot, IInputSlot>(
+        ConvertReferenceTypeToPointerType(layersInGraph.at("conv4 layer unoptimizable")->GetInputSlots()))
     };
-    std::vector<SubgraphView::OutputSlots> expectedUntouchedOutputSlots
+    std::vector<SubgraphView::IOutputSlots> expectedUntouchedOutputSlots
     {
-        ConvertReferenceTypeToPointerType(layersInGraph.at("conv2 layer unoptimizable")->GetOutputSlots()),
-        ConvertReferenceTypeToPointerType(layersInGraph.at("conv4 layer unoptimizable")->GetOutputSlots())
+            ConvertSlotsToISlots<OutputSlot, IOutputSlot>(
+        ConvertReferenceTypeToPointerType(layersInGraph.at("conv2 layer unoptimizable")->GetOutputSlots())),
+            ConvertSlotsToISlots<OutputSlot, IOutputSlot>(
+        ConvertReferenceTypeToPointerType(layersInGraph.at("conv4 layer unoptimizable")->GetOutputSlots()))
     };
-    std::vector<SubgraphView::Layers> expectedUntouchedLayers
+    std::vector<SubgraphView::IConnectableLayers> expectedUntouchedLayers
     {
         { layersInGraph.at("conv2 layer unoptimizable") },
         { layersInGraph.at("conv4 layer unoptimizable") }
@@ -1173,9 +1209,9 @@
     SubgraphViewSelector::SubgraphViewPtr subgraphPtr = BuildPartiallyOptimizableSubgraph2(graph, layersInGraph);
     CHECK((subgraphPtr != nullptr));
 
-    const SubgraphView::InputSlots&  subgraphInputSlots  = subgraphPtr->GetInputSlots();
-    const SubgraphView::OutputSlots& subgraphOutputSlots = subgraphPtr->GetOutputSlots();
-    const SubgraphView::Layers&      subgraphLayers      = subgraphPtr->GetLayers();
+    const SubgraphView::IInputSlots& subgraphInputSlots = subgraphPtr->GetIInputSlots();
+    const SubgraphView::IOutputSlots& subgraphOutputSlots = subgraphPtr->GetIOutputSlots();
+    const SubgraphView::IConnectableLayers& subgraphLayers = subgraphPtr->GetIConnectableLayers();
 
     CHECK(subgraphInputSlots.size()  == 2);
     CHECK(subgraphOutputSlots.size() == 1);
@@ -1214,15 +1250,21 @@
     ExpectedSubgraphSize expectedSubstitutableSubgraphSizes{ 2, 1, 3 };
     ExpectedSubgraphSize expectedReplacementSubgraphSizes{ 2, 1, 1 };
 
-    SubgraphView::InputSlots expectedSubstitutableInputSlots = {
-        ConvertReferenceTypeToPointerType(layersInGraph.at("conv1 layer")->GetInputSlots()[0]),
-        ConvertReferenceTypeToPointerType(layersInGraph.at("conv3 layer")->GetInputSlots()[0])
-    };
-    SubgraphView::OutputSlots expectedSubstitutableOutputSlots =
+    SubgraphView::IInputSlots expectedSubstitutableInputSlots
     {
-        ConvertReferenceTypeToPointerType(layersInGraph.at("add layer")->GetOutputSlots()[0])
+            ConvertSlotsToISlots<InputSlot, IInputSlot>({
+                    ConvertReferenceTypeToPointerType(layersInGraph.at("conv1 layer")->GetInputSlots()[0])})[0],
+            ConvertSlotsToISlots<InputSlot, IInputSlot>({
+                    ConvertReferenceTypeToPointerType(layersInGraph.at("conv3 layer")->GetInputSlots()[0])})[0]
     };
-    SubgraphView::Layers expectedSubstitutableLayers
+
+    SubgraphView::IOutputSlots expectedSubstitutableOutputSlots
+    {
+            ConvertSlotsToISlots<OutputSlot, IOutputSlot>(
+                    ConvertReferenceTypeToPointerType(layersInGraph.at("add layer")->GetOutputSlots()))
+    };
+
+    SubgraphView::IConnectableLayers expectedSubstitutableLayers
     {
         layersInGraph.at("conv1 layer"),
         layersInGraph.at("conv3 layer"),
@@ -1250,15 +1292,17 @@
     CHECK(untouchedSubgraphs.size() == 1);
 
     std::vector<ExpectedSubgraphSize> expectedUntouchedSubgraphSizes{ { 1, 1, 1 } };
-    std::vector<SubgraphView::InputSlots> expectedUntouchedInputSlots
+    std::vector<SubgraphView::IInputSlots> expectedUntouchedInputSlots
     {
-        ConvertReferenceTypeToPointerType(layersInGraph.at("conv2 layer unoptimizable")->GetInputSlots())
+            ConvertSlotsToISlots<InputSlot, IInputSlot>(
+        ConvertReferenceTypeToPointerType(layersInGraph.at("conv2 layer unoptimizable")->GetInputSlots()))
     };
-    std::vector<SubgraphView::OutputSlots> expectedUntouchedOutputSlots
+    std::vector<SubgraphView::IOutputSlots> expectedUntouchedOutputSlots
     {
-        ConvertReferenceTypeToPointerType(layersInGraph.at("conv2 layer unoptimizable")->GetOutputSlots())
+            ConvertSlotsToISlots<OutputSlot, IOutputSlot>(
+        ConvertReferenceTypeToPointerType(layersInGraph.at("conv2 layer unoptimizable")->GetOutputSlots()))
     };
-    std::vector<SubgraphView::Layers> expectedUntouchedLayers
+    std::vector<SubgraphView::IConnectableLayers> expectedUntouchedLayers
     {
         { layersInGraph.at("conv2 layer unoptimizable") }
     };
diff --git a/src/backends/cl/ClBackend.cpp b/src/backends/cl/ClBackend.cpp
index 339c1aa..cf5f500 100644
--- a/src/backends/cl/ClBackend.cpp
+++ b/src/backends/cl/ClBackend.cpp
@@ -227,18 +227,18 @@
 {
     OptimizationViews optimizationViews;
 
-    auto it = subgraph.end();
+    auto it = subgraph.endIConnectable();
     bool isFastMathEnabled = false;
     std::map<LayerGuid, Layer*> untouched;
 
-    while (it != subgraph.begin())
+    while (it != subgraph.beginIConnectable())
     {
         --it;
-        Layer& base = **it;
+        Layer& base = *(PolymorphicDowncast<Layer*>(*it));
         untouched.insert({base.GetGuid(), &base});
     }
 
-    it = subgraph.end();
+    it = subgraph.endIConnectable();
 #if defined(ARMCOMPUTECL_ENABLED)
     IBackendInternal::IBackendSpecificModelContextPtr modelContextPtr = CreateBackendSpecificModelContext(modelOptions);
 
@@ -251,10 +251,10 @@
         }
     }
 #endif
-    while (it != subgraph.begin())
+    while (it != subgraph.beginIConnectable())
     {
         --it;
-        Layer& base = **it;
+        Layer& base = *(PolymorphicDowncast<Layer*>(*it));
 
         // Fuse activation into previous layer if supported by backend
         if ((base.GetType() == LayerType::DepthwiseConvolution2d || base.GetType() == LayerType::Convolution2d
@@ -498,9 +498,9 @@
             if (!reduceDescriptor.m_vAxis.empty() && reduceDescriptor.m_vAxis.size() > 1)
             {
                 // Add new layers to the graph and connect them.
-                std::vector<Layer*> layers = ChainReduceLayers<ReduceLayer>(optimizationViews,
-                                                                            baseLayer,
-                                                                            reduceDescriptor);
+                std::vector<IConnectableLayer*> layers = ChainReduceLayers<ReduceLayer>(optimizationViews,
+                                                                                        baseLayer,
+                                                                                        reduceDescriptor);
 
                 // Replace existing baselayer with new subgraph.
                 ReplaceLayers<ReduceLayer>(optimizationViews, baseLayer, layers);
diff --git a/src/backends/neon/NeonBackend.cpp b/src/backends/neon/NeonBackend.cpp
index aa5ba03..54af14e 100644
--- a/src/backends/neon/NeonBackend.cpp
+++ b/src/backends/neon/NeonBackend.cpp
@@ -132,21 +132,21 @@
 {
     OptimizationViews optimizationViews;
 
-    auto it = subgraph.end();
+    auto it = subgraph.endIConnectable();
     std::map<LayerGuid, Layer*> untouched;
 
-    while (it != subgraph.begin())
+    while (it != subgraph.beginIConnectable())
     {
         --it;
-        Layer& base = **it;
+        Layer& base = *(PolymorphicDowncast<Layer*>(*it));
         untouched.insert({base.GetGuid(), &base});
     }
 
-    it = subgraph.end();
-    while (it != subgraph.begin())
+    it = subgraph.endIConnectable();
+    while (it != subgraph.beginIConnectable())
     {
         --it;
-        Layer& base = **it;
+        Layer& base = *(PolymorphicDowncast<Layer*>(*it));
 
         // Fuse activation into previous layer if supported by backend
         if ((base.GetType() == LayerType::DepthwiseConvolution2d || base.GetType() == LayerType::Convolution2d
@@ -390,9 +390,9 @@
             if (!reduceDescriptor.m_vAxis.empty() && reduceDescriptor.m_vAxis.size() > 1)
             {
                 // Add new layers to the graph and connect them.
-                std::vector<Layer*> layers = ChainReduceLayers<ReduceLayer>(optimizationViews,
-                                                                            baseLayer,
-                                                                            reduceDescriptor);
+                std::vector<IConnectableLayer*> layers = ChainReduceLayers<ReduceLayer>(optimizationViews,
+                                                                                        baseLayer,
+                                                                                        reduceDescriptor);
 
                 // Replace existing baselayer with new subgraph.
                 ReplaceLayers<ReduceLayer>(optimizationViews, baseLayer, layers);