IVGCVSW-3031 Finer grained backend optimization API

Change-Id: I9b93bc81b97f3d89fa046ba001854f732040e63a
Signed-off-by: Derek Lamberti <derek.lamberti@arm.com>
diff --git a/src/backends/backendsCommon/CMakeLists.txt b/src/backends/backendsCommon/CMakeLists.txt
index 1aa4d99..e1e387b 100644
--- a/src/backends/backendsCommon/CMakeLists.txt
+++ b/src/backends/backendsCommon/CMakeLists.txt
@@ -18,6 +18,8 @@
     MakeWorkloadHelper.hpp
     MemCopyWorkload.cpp
     MemCopyWorkload.hpp
+    OptimizationViews.cpp
+    OptimizationViews.hpp
     OutputHandler.cpp
     OutputHandler.hpp
     WorkloadDataCollector.hpp
diff --git a/src/backends/backendsCommon/IBackendInternal.hpp b/src/backends/backendsCommon/IBackendInternal.hpp
index b3ddb55..f49a210 100644
--- a/src/backends/backendsCommon/IBackendInternal.hpp
+++ b/src/backends/backendsCommon/IBackendInternal.hpp
@@ -10,6 +10,8 @@
 #include <ISubgraphViewConverter.hpp>
 #include <SubgraphView.hpp>
 
+#include "OptimizationViews.hpp"
+
 #include <vector>
 
 namespace armnn
@@ -54,8 +56,38 @@
     virtual Optimizations GetOptimizations() const = 0;
     virtual ILayerSupportSharedPtr GetLayerSupport() const = 0;
 
-    virtual SubgraphViewUniquePtr OptimizeSubgraphView(const SubgraphView& subgraph, bool& optimizationAttempted)
-        const = 0;
+    // @deprecated Use "OptimizationViews OptimizeSubgraphView(const SubgraphView&);" instead.
+    virtual SubgraphViewUniquePtr OptimizeSubgraphView(const SubgraphView& subgraph, bool& optimizationAttempted) const
+    {
+        optimizationAttempted=false;
+        return nullptr;
+    }
+
+    // Default implementation of OptimizeSubgraphView for backward compatibility with old API.
+    // Override this method with a custom optimization implementation.
+    virtual OptimizationViews OptimizeSubgraphView(const SubgraphView& subgraph)
+    {
+        bool attempted=false;
+        SubgraphViewUniquePtr optSubgraph = OptimizeSubgraphView(subgraph, attempted);
+
+        OptimizationViews result;
+        if (!attempted)
+        {
+            result.AddUntouchedSubgraph(SubgraphView(subgraph));
+        }
+        else
+        {
+            if (optSubgraph)
+            {
+                result.AddSubstituion({*optSubgraph.get(), subgraph});
+            }
+            else
+            {
+                result.AddFailedSubgraph(SubgraphView(subgraph));
+            }
+        }
+        return result;
+    }
 };
 
 using IBackendInternalUniquePtr = std::unique_ptr<IBackendInternal>;
diff --git a/src/backends/backendsCommon/OptimizationViews.cpp b/src/backends/backendsCommon/OptimizationViews.cpp
new file mode 100644
index 0000000..1190eea
--- /dev/null
+++ b/src/backends/backendsCommon/OptimizationViews.cpp
@@ -0,0 +1,67 @@
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "OptimizationViews.hpp"
+
+
+namespace armnn
+{
+
+bool OptimizationViews::Validate(const armnn::SubgraphView& originalSubgraph) const
+{
+    //This needs to verify that:
+    // 1) the sum of m_SuccesfulOptimizations & m_FailedOptimizations & m_UntouchedSubgraphs contains subgraphviews
+    //    which cover the entire space of the originalSubgraph.
+    // 2) Each SubstitutionPair contains matching inputs and outputs
+    bool valid = true;
+
+    // Create a copy of the layer list from the original subgraph and sort it
+    SubgraphView::Layers originalLayers = originalSubgraph.GetLayers();
+    originalLayers.sort();
+
+    // Create a new list based on the sum of all the subgraphs and sort it
+    SubgraphView::Layers countedLayers;
+    for (auto& failed : m_FailedOptimizations)
+    {
+        countedLayers.insert(countedLayers.end(), failed.GetLayers().begin(), failed.GetLayers().end());
+    }
+    for (auto& untouched : m_UntouchedSubgraphs)
+    {
+        countedLayers.insert(countedLayers.end(), untouched.GetLayers().begin(), untouched.GetLayers().end());
+    }
+    for (auto& successful : m_SuccesfulOptimizations)
+    {
+        countedLayers.insert(countedLayers.end(),
+                             successful.m_SubstitutableSubgraph.GetLayers().begin(),
+                             successful.m_SubstitutableSubgraph.GetLayers().end());
+    }
+    countedLayers.sort();
+
+    // Compare the two lists to make sure they match
+    valid &= originalLayers.size() == countedLayers.size();
+
+    auto oIt = originalLayers.begin();
+    auto cIt = countedLayers.begin();
+    for (size_t i=0; i < originalLayers.size() && valid; ++i, ++oIt, ++cIt)
+    {
+        valid &= (*oIt == *cIt);
+    }
+
+    // Compare the substitution subgraphs to ensure they are compatible
+    if (valid)
+    {
+        for (auto& substitution : m_SuccesfulOptimizations)
+        {
+            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();
+            valid &= validSubstitution;
+        }
+    }
+    return valid;
+}
+} //namespace armnn
diff --git a/src/backends/backendsCommon/OptimizationViews.hpp b/src/backends/backendsCommon/OptimizationViews.hpp
new file mode 100644
index 0000000..cf7051d
--- /dev/null
+++ b/src/backends/backendsCommon/OptimizationViews.hpp
@@ -0,0 +1,53 @@
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+#include <SubgraphView.hpp>
+
+namespace armnn
+{
+class OptimizationViews
+{
+public:
+    OptimizationViews() = default;
+
+    struct SubstitutionPair
+    {
+        /// Subgraph of Layers from the original graph which should be replaced
+        SubgraphView m_SubstitutableSubgraph;
+
+        /// A subgraph of new layers which will replace layers in m_SubstitutableSubgraph
+        SubgraphView m_ReplacementSubgraph;
+    };
+
+    using Subgraphs = std::vector<SubgraphView>;
+    using Substitutions = std::vector<SubstitutionPair>;
+
+    void AddSubstituion(SubstitutionPair&& substitution)
+    {
+        m_SuccesfulOptimizations.emplace_back(substitution);
+    }
+
+    void AddFailedSubgraph(SubgraphView&& subgraph)
+    {
+        m_FailedOptimizations.emplace_back(subgraph);
+    }
+
+    void AddUntouchedSubgraph(SubgraphView&& subgraph)
+    {
+        m_UntouchedSubgraphs.emplace_back(subgraph);
+    }
+
+    Substitutions GetSubstitutions() const { return m_SuccesfulOptimizations; }
+    Subgraphs GetFailedSubgraphs() const { return m_FailedOptimizations; }
+    Subgraphs GetUntouchedSubgraphs() const { return m_UntouchedSubgraphs; }
+    bool Validate(const SubgraphView& originalSubgraph) const;
+
+private:
+    Substitutions m_SuccesfulOptimizations;     ///< Proposed substitutions from successful optimizations
+    Subgraphs m_FailedOptimizations;            ///< Subgraphs from the original subgraph which cannot be supported
+    Subgraphs m_UntouchedSubgraphs;             ///< Subgraphs from the original subgraph which remain unmodified
+};
+} //namespace armnn
\ No newline at end of file
diff --git a/src/backends/backendsCommon/common.mk b/src/backends/backendsCommon/common.mk
index a1cc0c1..c993bfb 100644
--- a/src/backends/backendsCommon/common.mk
+++ b/src/backends/backendsCommon/common.mk
@@ -12,6 +12,7 @@
     CpuTensorHandle.cpp \
     LayerSupportBase.cpp \
     MemCopyWorkload.cpp \
+    OptimizationViews.cpp \
     OutputHandler.cpp \
     WorkloadData.cpp \
     WorkloadFactory.cpp \