COMPMID-1522: Add ElementWiseOperation node in the graph API

Change-Id: Icb428bf3b5d3634fdddc57562cce670776e7f7a3
Reviewed-on: https://eu-gerrit-1.euhpc.arm.com/145814
Tested-by: Jenkins <bsgcomp@arm.com>
Reviewed-by: Anthony Barbier <anthony.barbier@arm.com>
diff --git a/arm_compute/graph/frontend/Layers.h b/arm_compute/graph/frontend/Layers.h
index cf80dd9..054410e 100644
--- a/arm_compute/graph/frontend/Layers.h
+++ b/arm_compute/graph/frontend/Layers.h
@@ -178,6 +178,71 @@
     unsigned int _num_groups;
 };
 
+/** Concat Layer */
+class ConcatLayer final : public ILayer
+{
+public:
+    /** Construct a concatenation layer
+     *
+     * @param[in] sub_stream1      First graph branch
+     * @param[in] sub_stream2      Second graph branch
+     * @param[in] rest_sub_streams Rest sub-graph branches
+     */
+    template <typename... Ts>
+    ConcatLayer(SubStream &&sub_stream1, SubStream &&sub_stream2, Ts &&... rest_sub_streams)
+        : _sub_streams()
+    {
+        _sub_streams.push_back(arm_compute::support::cpp14::make_unique<SubStream>(std::move(sub_stream1)));
+        _sub_streams.push_back(arm_compute::support::cpp14::make_unique<SubStream>(std::move(sub_stream2)));
+
+        utility::for_each([&](SubStream && sub_stream)
+        {
+            _sub_streams.push_back(arm_compute::support::cpp14::make_unique<SubStream>(std::move(sub_stream)));
+        },
+        std::move(rest_sub_streams)...);
+    }
+    /** Construct a concat layer
+     *
+     * @param[in] sub_stream Sub-stream
+     */
+    template <typename... Ts>
+    ConcatLayer(SubStream &&sub_stream)
+        : _sub_streams()
+    {
+        _sub_streams.push_back(arm_compute::support::cpp14::make_unique<SubStream>(std::move(sub_stream)));
+    }
+    NodeID create_layer(IStream &s) override
+    {
+        NodeID     nid           = EmptyNodeID;
+        NodeParams common_params = { name(), s.hints().target_hint };
+        if(_sub_streams.size() == 1 && _sub_streams.at(0) != nullptr)
+        {
+            nid = _sub_streams[0]->tail_node();
+        }
+        else
+        {
+            // Collect tail nodes and concatenate
+            std::vector<NodeIdxPair> nodes;
+            for(auto &ss : _sub_streams)
+            {
+                if(ss && (ss->tail_node() != EmptyNodeID))
+                {
+                    const auto tail_node = s.graph().node(ss->tail_node());
+                    if(tail_node != nullptr && tail_node->type() != NodeType::Output)
+                    {
+                        nodes.push_back({ ss->tail_node(), 0 });
+                    }
+                }
+            }
+            nid = GraphBuilder::add_concatenate_node(s.graph(), common_params, nodes, DataLayoutDimension::CHANNEL);
+        }
+        return nid;
+    }
+
+private:
+    std::vector<std::unique_ptr<SubStream>> _sub_streams;
+};
+
 /** Convolution Layer */
 class ConvolutionLayer final : public ILayer
 {
@@ -358,6 +423,34 @@
     TensorShape _shape;
 };
 
+class EltwiseLayer final : public ILayer
+{
+public:
+    /** Construct an element-wise operation layer
+     *
+     * @param[in] sub_stream0 First graph sub-stream
+     * @param[in] sub_stream1 First graph sub-stream
+     * @param[in] op          Element-wise operation to perform
+     */
+    EltwiseLayer(SubStream &&sub_stream0, SubStream &&sub_stream1, EltwiseOperation op)
+        : _ss0(std::move(sub_stream0)), _ss1(std::move(sub_stream1)), _op(op)
+    {
+    }
+
+    NodeID create_layer(IStream &s) override
+    {
+        NodeParams  common_params = { name(), s.hints().target_hint };
+        NodeIdxPair input0        = { _ss0.tail_node(), 0 };
+        NodeIdxPair input1        = { _ss1.tail_node(), 0 };
+
+        return GraphBuilder::add_elementwise_node(s.graph(), common_params, input0, input1, _op);
+    }
+
+private:
+    SubStream        _ss0;
+    SubStream        _ss1;
+    EltwiseOperation _op;
+};
 /** Flatten Layer */
 class FlattenLayer final : public ILayer
 {
@@ -592,80 +685,6 @@
 private:
     float _beta;
 };
-
-/** Branch Layer */
-class BranchLayer final : public ILayer
-{
-public:
-    /** Construct a branch layer
-     *
-     * @param[in] merge_method     Branch merging method
-     * @param[in] sub_stream1      First graph branch
-     * @param[in] sub_stream2      Second graph branch
-     * @param[in] rest_sub_streams Rest sub-graph branches
-     */
-    template <typename... Ts>
-    BranchLayer(BranchMergeMethod merge_method, SubStream &&sub_stream1, SubStream &&sub_stream2, Ts &&... rest_sub_streams)
-        : _branch_merge_method(merge_method), _sub_streams()
-    {
-        _sub_streams.push_back(arm_compute::support::cpp14::make_unique<SubStream>(std::move(sub_stream1)));
-        _sub_streams.push_back(arm_compute::support::cpp14::make_unique<SubStream>(std::move(sub_stream2)));
-
-        utility::for_each([&](SubStream && sub_stream)
-        {
-            _sub_streams.push_back(arm_compute::support::cpp14::make_unique<SubStream>(std::move(sub_stream)));
-        },
-        std::move(rest_sub_streams)...);
-    }
-    /** Construct a branch layer
-     *
-     * @param[in] sub_stream Sub-stream
-     */
-    template <typename... Ts>
-    BranchLayer(SubStream &&sub_stream)
-        : _branch_merge_method(BranchMergeMethod::DEPTH_CONCATENATE), _sub_streams()
-    {
-        _sub_streams.push_back(arm_compute::support::cpp14::make_unique<SubStream>(std::move(sub_stream)));
-    }
-    NodeID create_layer(IStream &s) override
-    {
-        NodeID     nid           = EmptyNodeID;
-        NodeParams common_params = { name(), s.hints().target_hint };
-        if(_sub_streams.size() == 1 && _sub_streams.at(0) != nullptr)
-        {
-            nid = _sub_streams[0]->tail_node();
-        }
-        else if(_branch_merge_method == BranchMergeMethod::DEPTH_CONCATENATE)
-        {
-            // Collect tail nodes and concatenate
-            std::vector<NodeIdxPair> nodes;
-            for(auto &ss : _sub_streams)
-            {
-                if(ss && (ss->tail_node() != EmptyNodeID))
-                {
-                    const auto tail_node = s.graph().node(ss->tail_node());
-                    if(tail_node != nullptr && tail_node->type() != NodeType::Output)
-                    {
-                        nodes.push_back({ ss->tail_node(), 0 });
-                    }
-                }
-            }
-            nid = GraphBuilder::add_concatenate_node(s.graph(), common_params, nodes, DataLayoutDimension::CHANNEL);
-        }
-        else
-        {
-            ARM_COMPUTE_ERROR_ON(_sub_streams.size() != 2);
-            NodeIdxPair input0 = { _sub_streams[0]->tail_node(), 0 };
-            NodeIdxPair input1 = { _sub_streams[1]->tail_node(), 0 };
-            nid                = GraphBuilder::add_elementwise_node(s.graph(), common_params, input0, input1, EltwiseOperation::Add);
-        }
-        return nid;
-    }
-
-private:
-    BranchMergeMethod                       _branch_merge_method;
-    std::vector<std::unique_ptr<SubStream>> _sub_streams;
-};
 } // namespace frontend
 } // namespace graph
 } // namespace arm_compute
diff --git a/arm_compute/graph/frontend/Types.h b/arm_compute/graph/frontend/Types.h
index f9505e2..79ce52e 100644
--- a/arm_compute/graph/frontend/Types.h
+++ b/arm_compute/graph/frontend/Types.h
@@ -40,6 +40,7 @@
 using graph::PermutationVector;
 
 using graph::ActivationLayerInfo;
+using graph::EltwiseOperation;
 using graph::FullyConnectedLayerInfo;
 using graph::NormalizationLayerInfo;
 using graph::NormType;
@@ -56,13 +57,6 @@
 using graph::InterpolationPolicy;
 using graph::Size2D;
 
-/** Branch layer merging method */
-enum class BranchMergeMethod
-{
-    DEPTH_CONCATENATE, /**< Concatenate across depth */
-    ADD                /**< Adds the results of each stream */
-};
-
 /** Hints that can be passed to the stream to expose parameterization */
 struct StreamHints
 {