IVGCVSW-6591 AddLogicalBinaryLayer to PyArmNN

  * AddLogicalBinaryLayer to PyArmNN armnn_network.i
  * LogicalBinaryDescriptor to PyArmNN armnn_descriptors.i
  * Add layer to test_network_method_exists() in test_network.py
  * Add descriptor unit tests to test_descriptors.py

Signed-off-by: Cathal Corbett <cathal.corbett@arm.com>
Change-Id: I2f6288987332e1556235a9c16582e96b3a0fb641
diff --git a/python/pyarmnn/src/pyarmnn/__init__.py b/python/pyarmnn/src/pyarmnn/__init__.py
index 4499252..5f3e5ff 100644
--- a/python/pyarmnn/src/pyarmnn/__init__.py
+++ b/python/pyarmnn/src/pyarmnn/__init__.py
@@ -84,6 +84,8 @@
     ComparisonOperation_LessOrEqual, ComparisonOperation_NotEqual
 from ._generated.pyarmnn import UnaryOperation_Abs, UnaryOperation_Exp, UnaryOperation_Sqrt, UnaryOperation_Rsqrt, \
     UnaryOperation_Neg, ElementwiseUnaryDescriptor
+from ._generated.pyarmnn import LogicalBinaryOperation_LogicalAnd, LogicalBinaryOperation_LogicalOr, \
+    LogicalBinaryDescriptor
 from ._generated.pyarmnn import Convolution2dDescriptor, DepthToSpaceDescriptor, DepthwiseConvolution2dDescriptor, \
     DetectionPostProcessDescriptor, FakeQuantizationDescriptor, FillDescriptor, FullyConnectedDescriptor, \
     GatherDescriptor, InstanceNormalizationDescriptor, LstmDescriptor, L2NormalizationDescriptor, MeanDescriptor
diff --git a/python/pyarmnn/src/pyarmnn/swig/modules/armnn_descriptors.i b/python/pyarmnn/src/pyarmnn/swig/modules/armnn_descriptors.i
index a050722..8844cea 100644
--- a/python/pyarmnn/src/pyarmnn/swig/modules/armnn_descriptors.i
+++ b/python/pyarmnn/src/pyarmnn/swig/modules/armnn_descriptors.i
@@ -1036,6 +1036,25 @@
     bool operator ==(const TransposeConvolution2dDescriptor& rhs) const;
 };
 
+%feature("docstring",
+    "
+    A descriptor for the LogicalBinary layer. See `INetwork.AddLogicalBinaryLayer()`.
+
+    Contains:
+        m_Operation (int): Specifies the logical operation to execute.
+                           (0: `LogicalBinaryOperation_LogicalAnd`, 1: `LogicalBinaryOperation_LogicalOr`)
+                           Default: 0: `LogicalBinaryOperation_LogicalAnd`.
+
+    ") LogicalBinaryDescriptor;
+struct LogicalBinaryDescriptor
+{
+    LogicalBinaryDescriptor();
+    LogicalBinaryDescriptor(LogicalBinaryOperation operation);
+
+    LogicalBinaryOperation m_Operation;
+
+    bool operator ==(const LogicalBinaryDescriptor &rhs) const;
+};
 
 using ConcatDescriptor = OriginsDescriptor;
 using LogSoftmaxDescriptor = SoftmaxDescriptor;
diff --git a/python/pyarmnn/src/pyarmnn/swig/modules/armnn_network.i b/python/pyarmnn/src/pyarmnn/swig/modules/armnn_network.i
index b114edd..c978e14 100644
--- a/python/pyarmnn/src/pyarmnn/swig/modules/armnn_network.i
+++ b/python/pyarmnn/src/pyarmnn/swig/modules/armnn_network.i
@@ -993,6 +993,19 @@
     armnn::IConnectableLayer* AddFullyConnectedLayer(const armnn::FullyConnectedDescriptor& fullyConnectedDescriptor,
                                                      const char* name = nullptr);
 
+    %feature("docstring",
+        "
+        Adds a LogicalBinary layer to the network.
+
+        Args:
+            logicalBinaryDescriptor (LogicalBinaryDescriptor): Description of the LogicalBinary layer.
+            name (str): Optional name for the layer.
+
+        Returns:
+            IConnectableLayer: Interface for configuring the layer.
+        ") AddLogicalBinaryLayer;
+    armnn::IConnectableLayer* AddLogicalBinaryLayer(const armnn::LogicalBinaryDescriptor& logicalBinaryDescriptor,
+                                                    const char* name = nullptr);
 };
 
 %extend INetwork {
diff --git a/python/pyarmnn/test/test_descriptors.py b/python/pyarmnn/test/test_descriptors.py
index 663abc6..0360196 100644
--- a/python/pyarmnn/test/test_descriptors.py
+++ b/python/pyarmnn/test/test_descriptors.py
@@ -403,6 +403,10 @@
     assert desc.m_Operation == ann.UnaryOperation_Abs
 
 
+def test_logical_binary_descriptor_default_values():
+    desc = ann.LogicalBinaryDescriptor()
+    assert desc.m_Operation == ann.LogicalBinaryOperation_LogicalAnd
+
 def test_view_descriptor_incorrect_input():
     desc = ann.SplitterDescriptor(2, 3)
     with pytest.raises(RuntimeError) as err:
@@ -493,7 +497,8 @@
                                        'TransposeConvolution2dDescriptor',
                                        'ElementwiseUnaryDescriptor',
                                        'FillDescriptor',
-                                       'GatherDescriptor'])
+                                       'GatherDescriptor',
+                                       'LogicalBinaryDescriptor'])
 class TestDescriptorMassChecks:
 
     def test_desc_implemented(self, desc_name):
@@ -537,7 +542,8 @@
                                        'TransposeConvolution2dDescriptor',
                                        'ElementwiseUnaryDescriptor',
                                        'FillDescriptor',
-                                       'GatherDescriptor'])
+                                       'GatherDescriptor',
+                                       'LogicalBinaryDescriptor'])
 class TestDescriptorMassChecks:
 
     def test_desc_implemented(self, desc_name):
diff --git a/python/pyarmnn/test/test_network.py b/python/pyarmnn/test/test_network.py
index 4f37c47..1792041 100644
--- a/python/pyarmnn/test/test_network.py
+++ b/python/pyarmnn/test/test_network.py
@@ -208,6 +208,7 @@
     'AddGatherLayer',
     'AddInputLayer',
     'AddInstanceNormalizationLayer',
+    'AddLogicalBinaryLayer',
     'AddLogSoftmaxLayer',
     'AddL2NormalizationLayer',
     'AddLstmLayer',