//
// Copyright © 2017,2022-2023 Arm Ltd and Contributors. All rights reserved.
// SPDX-License-Identifier: MIT
//

#include <armnn/BackendHelper.hpp>
#include <armnn/BackendId.hpp>
#include <armnn/BackendOptions.hpp>
#include <armnn/BackendRegistry.hpp>
#include <armnn/LstmParams.hpp>
#include <armnn/QuantizedLstmParams.hpp>
#include <armnn/Tensor.hpp>
#include <armnn/Types.hpp>
#include <armnn/backends/ILayerSupport.hpp>
#include <armnn/backends/IBackendInternal.hpp>

#include <stddef.h>

namespace armnn
{

// Return LayerSupportHandle instead of the previous pointer to ILayerSupport.
LayerSupportHandle GetILayerSupportByBackendId(const armnn::BackendId& backend)
{
    BackendRegistry& backendRegistry = armnn::BackendRegistryInstance();

    if (!backendRegistry.IsBackendRegistered(backend))
    {
        return LayerSupportHandle(nullptr);
    }

    auto factoryFunc = backendRegistry.GetFactory(backend);
    auto backendObject = factoryFunc();
    return LayerSupportHandle(backendObject->GetLayerSupport(), backend);
}

Optional<const BackendOptions::BackendOption> GetCapability(const std::string& backendCapabilityName,
                                                            const BackendCapabilities& capabilities)
{
    for (size_t i=0; i < capabilities.GetOptionCount(); i++)
    {
        const auto& capability = capabilities.GetOption(i);
        if (backendCapabilityName == capability.GetName())
        {
            return capability;
        }
    }
    return EmptyOptional();
}

Optional<const BackendOptions::BackendOption> GetCapability(const std::string& backendCapabilityName,
                                                            const armnn::BackendId& backend)
{
    auto const& backendRegistry = armnn::BackendRegistryInstance();
    if (backendRegistry.IsBackendRegistered(backend))
    {
        auto factoryFunc = backendRegistry.GetFactory(backend);
        auto backendObject = factoryFunc();
        auto capabilities = backendObject->GetCapabilities();
        return GetCapability(backendCapabilityName, capabilities);
    }
    return EmptyOptional();
}

bool HasCapability(const std::string& name, const BackendCapabilities& capabilities)
{
    return GetCapability(name, capabilities).has_value();
}

bool HasCapability(const std::string& name, const armnn::BackendId& backend)
{
    return GetCapability(name, backend).has_value();
}

bool HasCapability(const BackendOptions::BackendOption& capability, const BackendCapabilities& capabilities)
{
    return HasMatchingCapability(capability, capabilities);
}

bool HasCapability(const BackendOptions::BackendOption& backendOption, const armnn::BackendId& backend)
{
    return HasMatchingCapability(backendOption, backend);
}

bool HasMatchingCapability(const BackendOptions::BackendOption& capability, const BackendCapabilities& capabilities)
{
    for (size_t i=0; i < capabilities.GetOptionCount(); i++)
    {
        const auto& backendCapability = capabilities.GetOption(i);
        if (capability.GetName() == backendCapability.GetName())
        {
            if (capability.GetValue().IsBool() && backendCapability.GetValue().IsBool())
            {
                return capability.GetValue().AsBool() == backendCapability.GetValue().AsBool();
            }
            else if (capability.GetValue().IsFloat() && backendCapability.GetValue().IsFloat())
            {
                return capability.GetValue().AsFloat() == backendCapability.GetValue().AsFloat();
            }
            else if (capability.GetValue().IsInt() && backendCapability.GetValue().IsInt())
            {
                return capability.GetValue().AsInt() == backendCapability.GetValue().AsInt();
            }
            else if (capability.GetValue().IsString() && backendCapability.GetValue().IsString())
            {
                return capability.GetValue().AsString() == backendCapability.GetValue().AsString();
            }
            else if (capability.GetValue().IsUnsignedInt() && backendCapability.GetValue().IsUnsignedInt())
            {
                return capability.GetValue().AsUnsignedInt() == backendCapability.GetValue().AsUnsignedInt();
            }
        }
    }
    return false;
}

bool HasMatchingCapability(const BackendOptions::BackendOption& backendOption, const armnn::BackendId& backend)
{
    auto const& backendRegistry = armnn::BackendRegistryInstance();
    if (backendRegistry.IsBackendRegistered(backend))
    {
        auto factoryFunc = backendRegistry.GetFactory(backend);
        auto backendObject = factoryFunc();
        auto capabilities = backendObject->GetCapabilities();
        return HasMatchingCapability(backendOption, capabilities);
    }
    return false;
}

unsigned int GetNumberOfCacheFiles(const armnn::BackendId& backend)
{
    auto const& backendRegistry = armnn::BackendRegistryInstance();
    if (backendRegistry.IsBackendRegistered(backend))
    {
        auto factoryFunc = backendRegistry.GetFactory(backend);
        auto backendObject = factoryFunc();
        return backendObject->GetNumberOfCacheFiles();
    }
    return 0;
}

bool LayerSupportHandle::IsBackendRegistered() const
{
    if (m_LayerSupport)
    {
        return true;
    }

    return false;
}

using TensorInfos = std::vector<TensorInfo>;

bool LayerSupportHandle::IsActivationSupported(const TensorInfo& input,
                                               const TensorInfo& output,
                                               const ActivationDescriptor& descriptor,
                                               Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, output};

    return m_LayerSupport->IsLayerSupported(LayerType::Activation,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsAdditionSupported(const TensorInfo& input0,
                                             const TensorInfo& input1,
                                             const TensorInfo& output,
                                             Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input0, input1, output};

    return m_LayerSupport->IsLayerSupported(LayerType::Addition,
                                            infos,
                                            BaseDescriptor(),
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsArgMinMaxSupported(const TensorInfo& input,
                                              const TensorInfo& output,
                                              const ArgMinMaxDescriptor& descriptor,
                                              Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, output};

    return m_LayerSupport->IsLayerSupported(LayerType::ArgMinMax,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsBatchMatMulSupported(const TensorInfo& input0,
                                                const TensorInfo& input1,
                                                const TensorInfo& output,
                                                const BatchMatMulDescriptor& descriptor,
                                                Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input0, input1, output};

    return m_LayerSupport->IsLayerSupported(LayerType::BatchMatMul,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsBatchNormalizationSupported(const TensorInfo& input,
                                                       const TensorInfo& output,
                                                       const TensorInfo& mean,
                                                       const TensorInfo& var,
                                                       const TensorInfo& beta,
                                                       const TensorInfo& gamma,
                                                       const BatchNormalizationDescriptor& descriptor,
                                                       Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, output, mean, var, beta, gamma};

    return m_LayerSupport->IsLayerSupported(LayerType::BatchNormalization,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsBatchToSpaceNdSupported(const TensorInfo& input,
                                                   const TensorInfo& output,
                                                   const BatchToSpaceNdDescriptor& descriptor,
                                                   Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, output};

    return m_LayerSupport->IsLayerSupported(LayerType::BatchToSpaceNd,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsCastSupported(const TensorInfo& input,
                                         const TensorInfo& output,
                                         Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, output};

    return m_LayerSupport->IsLayerSupported(LayerType::Cast,
                                            infos,
                                            BaseDescriptor(),
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsChannelShuffleSupported(const TensorInfo &input,
                                                   const TensorInfo &output,
                                                   const ChannelShuffleDescriptor &descriptor,
                                                   Optional<std::string &> reasonIfUnsupported)
{
    TensorInfos infos{input, output};

    return m_LayerSupport->IsLayerSupported(LayerType::ChannelShuffle,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsComparisonSupported(const TensorInfo& input0,
                                               const TensorInfo& input1,
                                               const TensorInfo& output,
                                               const ComparisonDescriptor& descriptor,
                                               Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input0, input1, output};

    return m_LayerSupport->IsLayerSupported(LayerType::Comparison,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsConcatSupported(const std::vector<const TensorInfo*> inputs,
                                           const TensorInfo& output,
                                           const OriginsDescriptor& descriptor,
                                           Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos;
    for (const TensorInfo* inputInfo : inputs)
    {
        infos.push_back(*inputInfo);
    }
    infos.push_back(output);

    return m_LayerSupport->IsLayerSupported(LayerType::Concat,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsConstantSupported(const TensorInfo& output,
                                             Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{output};

    return m_LayerSupport->IsLayerSupported(LayerType::Constant,
                                            infos,
                                            BaseDescriptor(),
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsConvertFp16ToFp32Supported(const TensorInfo& input,
                                                      const TensorInfo& output,
                                                      Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, output};

    return m_LayerSupport->IsLayerSupported(LayerType::ConvertFp16ToFp32,
                                            infos,
                                            BaseDescriptor(),
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsConvertFp32ToFp16Supported(const TensorInfo& input,
                                                      const TensorInfo& output,
                                                      Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, output};

    return m_LayerSupport->IsLayerSupported(LayerType::ConvertFp32ToFp16,
                                            infos,
                                            BaseDescriptor(),
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsConvolution2dSupported(const TensorInfo& input,
                                                  const TensorInfo& output,
                                                  const Convolution2dDescriptor& descriptor,
                                                  const TensorInfo& weights,
                                                  const Optional<TensorInfo>& biases,
                                                  Optional<std::string&> reasonIfUnsupported)
{
    TensorInfo biasesVal =  biases.has_value() ? biases.value() : TensorInfo();
    TensorInfos infos{input, output, weights, biasesVal};

    Optional<const BackendOptions::BackendOption> capability ;
    if (!m_BackendId.IsUndefined())
    {
        capability = GetCapability("NonConstWeights", m_BackendId);
        if (!capability.has_value() || capability.value().GetValue().AsBool() == false)
        {
            if (!weights.IsConstant())
            {
                if (reasonIfUnsupported.has_value())
                {
                    reasonIfUnsupported.value() =
                        "Backend is not capable of supporting dynamic weights (NonConstWeights) and "
                        "Convolution2d weights are set as dynamic (non constant). ";
                }
                return false;
            }
            if (descriptor.m_BiasEnabled && !biasesVal.IsConstant())
            {
                if (reasonIfUnsupported.has_value())
                {
                    reasonIfUnsupported.value() =
                            "Backend is not capable of supporting dynamic biases (NonConstWeights) and "
                            "Convolution2d biases are set as dynamic (non constant). ";
                }
                return false;
            }

            // At the first stage we will only print a warning. this is to give
            // backend developers a chance to adopt and read weights from input slots.
            ARMNN_LOG(warning) << "The backend makes use of a deprecated interface to read constant tensors. "
                                  "If you are a backend developer please find more information in our "
                                  "doxygen documentation on github https://github.com/ARM-software/armnn "
                                  "under the keyword 'ConstTensorsAsInputs'.";
        }
    }

    return m_LayerSupport->IsLayerSupported(LayerType::Convolution2d,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsConvolution3dSupported(const TensorInfo& input,
                                                  const TensorInfo& output,
                                                  const Convolution3dDescriptor& descriptor,
                                                  const TensorInfo& weights,
                                                  const Optional<TensorInfo>& biases,
                                                  Optional<std::string&> reasonIfUnsupported)
{
    TensorInfo biasesVal =  biases.has_value() ? biases.value() : TensorInfo();
    TensorInfos infos{input, output, weights, biasesVal};

    return m_LayerSupport->IsLayerSupported(LayerType::Convolution3d,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsDebugSupported(const TensorInfo& input,
                                          const TensorInfo& output,
                                          Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, output};

    return m_LayerSupport->IsLayerSupported(LayerType::Debug,
                                            infos,
                                            BaseDescriptor(),
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsDepthToSpaceSupported(const TensorInfo& input,
                                                 const TensorInfo& output,
                                                 const DepthToSpaceDescriptor& descriptor,
                                                 Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, output};

    return m_LayerSupport->IsLayerSupported(LayerType::DepthToSpace,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsDepthwiseConvolutionSupported(
        const TensorInfo& input,
        const TensorInfo& output,
        const DepthwiseConvolution2dDescriptor& descriptor,
        const TensorInfo& weights,
        const Optional<TensorInfo>& biases,
        Optional<std::string&> reasonIfUnsupported)
{
    TensorInfo biasesVal =  biases.has_value() ? biases.value() : TensorInfo();
    TensorInfos infos{input, output, weights, biasesVal};

    Optional<const BackendOptions::BackendOption> capability ;
    if (!m_BackendId.IsUndefined())
    {
        capability = GetCapability("NonConstWeights", m_BackendId);
        if (!capability.has_value() || capability.value().GetValue().AsBool() == false)
        {
            if (!weights.IsConstant())
            {
                if (reasonIfUnsupported.has_value())
                {
                    reasonIfUnsupported.value() =
                            "Backend is not capable of supporting dynamic weights (NonConstWeights) and "
                            "DepthwiseConvolution2d weights are set as dynamic (non constant). ";
                }
                return false;
            }
            if (descriptor.m_BiasEnabled && !biasesVal.IsConstant())
            {
                if (reasonIfUnsupported.has_value())
                {
                    reasonIfUnsupported.value() =
                            "Backend is not capable of supporting dynamic biases (NonConstWeights) and "
                            "DepthwiseConvolution2d biases are set as dynamic (non constant). ";
                }
                return false;
            }
            // At the first stage we will only print a warning. this is to give
            // backend developers a chance to adopt and read weights from input slots.
            ARMNN_LOG(warning) << "The backend makes use of a deprecated interface to read constant tensors. "
                                  "If you are a backend developer please find more information in our "
                                  "doxygen documentation on github https://github.com/ARM-software/armnn "
                                  "under the keyword 'ConstTensorsAsInputs'.";
        }
    }

    return m_LayerSupport->IsLayerSupported(LayerType::DepthwiseConvolution2d,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsDequantizeSupported(const TensorInfo& input,
                                               const TensorInfo& output,
                                               Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, output};

    return m_LayerSupport->IsLayerSupported(LayerType::Dequantize,
                                            infos,
                                            BaseDescriptor(),
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsDetectionPostProcessSupported(const TensorInfo& boxEncodings,
                                                         const TensorInfo& scores,
                                                         const TensorInfo& anchors,
                                                         const TensorInfo& detectionBoxes,
                                                         const TensorInfo& detectionClasses,
                                                         const TensorInfo& detectionScores,
                                                         const TensorInfo& numDetections,
                                                         const DetectionPostProcessDescriptor& descriptor,
                                                         Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{boxEncodings, scores, anchors, detectionBoxes, detectionClasses, detectionScores, numDetections};

    return m_LayerSupport->IsLayerSupported(LayerType::DetectionPostProcess,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsDilatedDepthwiseConvolutionSupported(
        const TensorInfo& input,
        const TensorInfo& output,
        const DepthwiseConvolution2dDescriptor& descriptor,
        const TensorInfo& weights,
        const Optional<TensorInfo>& biases,
        Optional<std::string&> reasonIfUnsupported)
{
    TensorInfo biasesVal =  biases.has_value() ? biases.value() : TensorInfo();
    TensorInfos infos{input, output, weights, biasesVal};

    Optional<const BackendOptions::BackendOption> capability ;
    if (!m_BackendId.IsUndefined())
    {
        capability = GetCapability("NonConstWeights", m_BackendId);
        if (!capability.has_value() || capability.value().GetValue().AsBool() == false)
        {
            if (!weights.IsConstant())
            {
                if (reasonIfUnsupported.has_value())
                {
                    reasonIfUnsupported.value() =
                            "Backend is not capable of supporting dynamic weights (NonConstWeights) and "
                            "DilatedDepthwiseConvolution2d weights are set as dynamic (non constant). ";
                }
                return false;
            }
            if (descriptor.m_BiasEnabled && !biasesVal.IsConstant())
            {
                if (reasonIfUnsupported.has_value())
                {
                    reasonIfUnsupported.value() =
                            "Backend is not capable of supporting dynamic biases (NonConstWeights) and "
                            "DilatedDepthwiseConvolution2d biases are set as dynamic (non constant). ";
                }
                return false;
            }
            // At the first stage we will only print a warning. this is to give
            // backend developers a chance to adopt and read weights from input slots.
            ARMNN_LOG(warning) << "The backend makes use of a deprecated interface to read constant tensors. "
                                  "If you are a backend developer please find more information in our "
                                  "doxygen documentation on github https://github.com/ARM-software/armnn "
                                  "under the keyword 'ConstTensorsAsInputs'.";
        }
    }

    return m_LayerSupport->IsLayerSupported(LayerType::DepthwiseConvolution2d,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsDivisionSupported(const TensorInfo& input0,
                                             const TensorInfo& input1,
                                             const TensorInfo& output,
                                             Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input0, input1, output};

    return m_LayerSupport->IsLayerSupported(LayerType::Division,
                                            infos,
                                            BaseDescriptor(),
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsElementwiseBinarySupported(const TensorInfo &input0,
                                                      const TensorInfo &input1,
                                                      const TensorInfo &output,
                                                      const ElementwiseBinaryDescriptor &descriptor,
                                                      Optional<std::string &> reasonIfUnsupported)
{
    TensorInfos infos{input0, input1, output};

    return m_LayerSupport->IsLayerSupported(LayerType::ElementwiseBinary,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsElementwiseUnarySupported(const TensorInfo& input,
                                                     const TensorInfo& output,
                                                     const ElementwiseUnaryDescriptor& descriptor,
                                                     Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, output};

    return m_LayerSupport->IsLayerSupported(LayerType::ElementwiseUnary,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsFakeQuantizationSupported(const TensorInfo& input,
                                                     const FakeQuantizationDescriptor& descriptor,
                                                     Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input};

    return m_LayerSupport->IsLayerSupported(LayerType::FakeQuantization,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsFillSupported(const TensorInfo& input,
                                         const TensorInfo& output,
                                         const FillDescriptor& descriptor,
                                         Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, output};

    return m_LayerSupport->IsLayerSupported(LayerType::Fill,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsFloorSupported(const TensorInfo& input,
                                          const TensorInfo& output,
                                          Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, output};

    return m_LayerSupport->IsLayerSupported(LayerType::Floor,
                                            infos,
                                            BaseDescriptor(),
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsFullyConnectedSupported(const TensorInfo& input,
                                                   const TensorInfo& output,
                                                   const TensorInfo& weights,
                                                   const TensorInfo& biases,
                                                   const FullyConnectedDescriptor& descriptor,
                                                   Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, output, weights, biases};

    Optional<const BackendOptions::BackendOption> capability;
    if (!m_BackendId.IsUndefined())
    {
        capability = GetCapability("NonConstWeights", m_BackendId);
        if (!capability.has_value() || capability.value().GetValue().AsBool() == false)
        {
            if (!descriptor.m_ConstantWeights)
            {
                if (reasonIfUnsupported.has_value())
                {
                    reasonIfUnsupported.value() =
                            "Backend is not capable of supporting dynamic weights (NonConstWeights) and "
                            "FullyConnected descriptor indicates that weights are dynamic (non constant). ";
                }
                return false;
            }
            if (!weights.IsConstant())
            {
                if (reasonIfUnsupported.has_value())
                {
                    reasonIfUnsupported.value() =
                            "Backend is not capable of supporting dynamic weights (NonConstWeights) and "
                            "FullyConnected weights are set as dynamic (non constant). ";
                }

                return false;
            }
            if (descriptor.m_BiasEnabled && !biases.IsConstant())
            {
                if (reasonIfUnsupported.has_value())
                {
                    reasonIfUnsupported.value() =
                            "Backend is not capable of supporting dynamic biases (NonConstWeights) and "
                            "FullyConnected biases are set as dynamic (non constant). ";
                }
                return false;
            }

            // At the first stage we will only print a warning. this is to give
            // backend developers a chance to adopt and read weights from input slots.
            ARMNN_LOG(warning) << "The backend makes use of a deprecated interface to read constant tensors. "
                                  "If you are a backend developer please find more information in our "
                                  "doxygen documentation on github https://github.com/ARM-software/armnn "
                                  "under the keyword 'ConstTensorsAsInputs'.";
        }
    }

    return m_LayerSupport->IsLayerSupported(LayerType::FullyConnected,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsGatherSupported(const TensorInfo& input0,
                                           const TensorInfo& input1,
                                           const TensorInfo& output,
                                           const GatherDescriptor& descriptor,
                                           Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input0, input1, output};

    return m_LayerSupport->IsLayerSupported(LayerType::Gather,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsGatherNdSupported(const TensorInfo& input0,
                                             const TensorInfo& input1,
                                             const TensorInfo& output,
                                             Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input0, input1, output};

    return m_LayerSupport->IsLayerSupported(LayerType::GatherNd,
                                            infos,
                                            BaseDescriptor(),
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsInputSupported(const TensorInfo& input,
                                          Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input};

    return m_LayerSupport->IsLayerSupported(LayerType::Input,
                                            infos,
                                            BaseDescriptor(),
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsInstanceNormalizationSupported(
        const TensorInfo& input,
        const TensorInfo& output,
        const InstanceNormalizationDescriptor& descriptor,
        Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, output};

    return m_LayerSupport->IsLayerSupported(LayerType::InstanceNormalization,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsL2NormalizationSupported(const TensorInfo& input,
                                                    const TensorInfo& output,
                                                    const L2NormalizationDescriptor& descriptor,
                                                    Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, output};

    return m_LayerSupport->IsLayerSupported(LayerType::L2Normalization,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsLogicalBinarySupported(const TensorInfo& input0,
                                                  const TensorInfo& input1,
                                                  const TensorInfo& output,
                                                  const LogicalBinaryDescriptor& descriptor,
                                                  Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input0, input1, output};

    return m_LayerSupport->IsLayerSupported(LayerType::LogicalBinary,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsLogicalUnarySupported(const TensorInfo& input,
                                                 const TensorInfo& output,
                                                 const ElementwiseUnaryDescriptor& descriptor,
                                                 Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, output};

    return m_LayerSupport->IsLayerSupported(LayerType::ElementwiseUnary,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsLogSoftmaxSupported(const TensorInfo& input,
                                               const TensorInfo& output,
                                               const LogSoftmaxDescriptor& descriptor,
                                               Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, output};

    return m_LayerSupport->IsLayerSupported(LayerType::LogSoftmax,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsLstmSupported(const TensorInfo& input,
                                         const TensorInfo& outputStateIn,
                                         const TensorInfo& cellStateIn,
                                         const TensorInfo& scratchBuffer,
                                         const TensorInfo& outputStateOut,
                                         const TensorInfo& cellStateOut,
                                         const TensorInfo& output,
                                         const LstmDescriptor& descriptor,
                                         const LstmInputParamsInfo& paramsInfo,
                                         Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, outputStateIn, cellStateIn, scratchBuffer, outputStateOut, cellStateOut, output};

    return m_LayerSupport->IsLayerSupported(LayerType::Lstm,
                                            infos,
                                            descriptor,
                                            paramsInfo,
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsMaximumSupported(const TensorInfo& input0,
                                            const TensorInfo& input1,
                                            const TensorInfo& output,
                                            Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input0, input1, output};

    return m_LayerSupport->IsLayerSupported(LayerType::Maximum,
                                            infos,
                                            BaseDescriptor(),
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsMeanSupported(const TensorInfo& input,
                                         const TensorInfo& output,
                                         const MeanDescriptor& descriptor,
                                         Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, output};

    return m_LayerSupport->IsLayerSupported(LayerType::Mean,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsMemCopySupported(const TensorInfo& input,
                                            const TensorInfo& output,
                                            Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, output};

    return m_LayerSupport->IsLayerSupported(LayerType::MemCopy,
                                            infos,
                                            BaseDescriptor(),
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsMemImportSupported(const TensorInfo& input,
                                              const TensorInfo& output,
                                              Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, output};

    return m_LayerSupport->IsLayerSupported(LayerType::MemImport,
                                            infos,
                                            BaseDescriptor(),
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsMergeSupported(const TensorInfo& input0,
                                          const TensorInfo& input1,
                                          const TensorInfo& output,
                                          Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input0, input1, output};

    return m_LayerSupport->IsLayerSupported(LayerType::Merge,
                                            infos,
                                            BaseDescriptor(),
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsMinimumSupported(const TensorInfo& input0,
                                            const TensorInfo& input1,
                                            const TensorInfo& output,
                                            Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input0, input1, output};

    return m_LayerSupport->IsLayerSupported(LayerType::Minimum,
                                            infos,
                                            BaseDescriptor(),
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsMultiplicationSupported(const TensorInfo& input0,
                                                   const TensorInfo& input1,
                                                   const TensorInfo& output,
                                                   Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input0, input1, output};

    return m_LayerSupport->IsLayerSupported(LayerType::Multiplication,
                                            infos,
                                            BaseDescriptor(),
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsNormalizationSupported(const TensorInfo& input,
                                                  const TensorInfo& output,
                                                  const NormalizationDescriptor& descriptor,
                                                  Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, output};

    return m_LayerSupport->IsLayerSupported(LayerType::Normalization,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsOutputSupported(const TensorInfo& output,
                                           Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{output};

    return m_LayerSupport->IsLayerSupported(LayerType::Output,
                                            infos,
                                            BaseDescriptor(),
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsPadSupported(const TensorInfo& input,
                                        const TensorInfo& output,
                                        const PadDescriptor& descriptor,
                                        Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, output};

    return m_LayerSupport->IsLayerSupported(LayerType::Pad,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsPermuteSupported(const TensorInfo& input,
                                            const TensorInfo& output,
                                            const PermuteDescriptor& descriptor,
                                            Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, output};

    return m_LayerSupport->IsLayerSupported(LayerType::Permute,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsPooling2dSupported(const TensorInfo& input,
                                              const TensorInfo& output,
                                              const Pooling2dDescriptor& descriptor,
                                              Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, output};

    return m_LayerSupport->IsLayerSupported(LayerType::Pooling2d,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsPooling3dSupported(const TensorInfo& input,
                                              const TensorInfo& output,
                                              const Pooling3dDescriptor& descriptor,
                                              Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, output};

    return m_LayerSupport->IsLayerSupported(LayerType::Pooling3d,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsPreCompiledSupported(const TensorInfo& input,
                                                const PreCompiledDescriptor& descriptor,
                                                Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input};

    return m_LayerSupport->IsLayerSupported(LayerType::PreCompiled,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsPreluSupported(const TensorInfo& input,
                                          const TensorInfo& alpha,
                                          const TensorInfo& output,
                                          Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, alpha, output};

    return m_LayerSupport->IsLayerSupported(LayerType::Prelu,
                                            infos,
                                            BaseDescriptor(),
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsQuantizeSupported(const TensorInfo& input,
                                             const TensorInfo& output,
                                             Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, output};

    return m_LayerSupport->IsLayerSupported(LayerType::Quantize,
                                            infos,
                                            BaseDescriptor(),
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsQLstmSupported(const TensorInfo& input,
                                          const TensorInfo& previousOutputIn,
                                          const TensorInfo& previousCellStateIn,
                                          const TensorInfo& outputStateOut,
                                          const TensorInfo& cellStateOut,
                                          const TensorInfo& output,
                                          const QLstmDescriptor& descriptor,
                                          const LstmInputParamsInfo& paramsInfo,
                                          Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, previousOutputIn, previousCellStateIn, outputStateOut, cellStateOut, output};

    return m_LayerSupport->IsLayerSupported(LayerType::QLstm,
                                            infos,
                                            descriptor,
                                            paramsInfo,
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsQuantizedLstmSupported(const TensorInfo& input,
                                                  const TensorInfo& previousCellStateIn,
                                                  const TensorInfo& previousOutputIn,
                                                  const TensorInfo& cellStateOut,
                                                  const TensorInfo& output,
                                                  const QuantizedLstmInputParamsInfo& paramsInfo,
                                                  Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, previousCellStateIn, previousOutputIn, cellStateOut, output};

    return m_LayerSupport->IsLayerSupported(LayerType::QuantizedLstm,
                                            infos,
                                            BaseDescriptor(),
                                            EmptyOptional(),
                                            paramsInfo,
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsRankSupported(const TensorInfo& input,
                                         const TensorInfo& output,
                                         Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, output};

    return m_LayerSupport->IsLayerSupported(LayerType::Rank,
                                            infos,
                                            BaseDescriptor(),
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsReduceSupported(const TensorInfo& input,
                                           const TensorInfo& output,
                                           const ReduceDescriptor& descriptor,
                                           Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, output};

    return m_LayerSupport->IsLayerSupported(LayerType::Reduce,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsReshapeSupported(const TensorInfo& input,
                                            const TensorInfo& output,
                                            const ReshapeDescriptor& descriptor,
                                            Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, output};

    return m_LayerSupport->IsLayerSupported(LayerType::Reshape,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsResizeSupported(const TensorInfo& input,
                                           const TensorInfo& output,
                                           const ResizeDescriptor& descriptor,
                                           Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, output};

    return m_LayerSupport->IsLayerSupported(LayerType::Resize,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsReverseV2Supported(const armnn::TensorInfo &input0,
                                              const armnn::TensorInfo &input1,
                                              const armnn::TensorInfo &output,
                                              Optional<std::string &> reasonIfUnsupported)
{
    TensorInfos infos{input0, input1, output};

    return m_LayerSupport->IsLayerSupported(LayerType::ReverseV2,
                                            infos,
                                            BaseDescriptor(),
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsShapeSupported(const TensorInfo& input,
                                          const TensorInfo& output,
                                          Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, output};

    return m_LayerSupport->IsLayerSupported(LayerType::Shape,
                                            infos,
                                            BaseDescriptor(),
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsSliceSupported(const TensorInfo& input,
                                          const TensorInfo& output,
                                          const SliceDescriptor& descriptor,
                                          Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, output};

    return m_LayerSupport->IsLayerSupported(LayerType::Slice,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsSoftmaxSupported(const TensorInfo& input,
                                            const TensorInfo& output,
                                            const SoftmaxDescriptor& descriptor,
                                            Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, output};

    return m_LayerSupport->IsLayerSupported(LayerType::Softmax,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsSpaceToBatchNdSupported(const TensorInfo& input,
                                                   const TensorInfo& output,
                                                   const SpaceToBatchNdDescriptor& descriptor,
                                                   Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, output};

    return m_LayerSupport->IsLayerSupported(LayerType::SpaceToBatchNd,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsSpaceToDepthSupported(const TensorInfo& input,
                                                 const TensorInfo& output,
                                                 const SpaceToDepthDescriptor& descriptor,
                                                 Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, output};

    return m_LayerSupport->IsLayerSupported(LayerType::SpaceToDepth,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsSplitterSupported(const TensorInfo& input,
                                             const std::vector<std::reference_wrapper<TensorInfo>>& outputs,
                                             const ViewsDescriptor& descriptor,
                                             Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input};
    for (TensorInfo outInfo : outputs)
    {
        infos.push_back(outInfo);
    }

    return m_LayerSupport->IsLayerSupported(LayerType::Splitter,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsStackSupported(const std::vector<const TensorInfo*>& inputs,
                                          const TensorInfo& output,
                                          const StackDescriptor& descriptor,
                                          Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos;
    for (const TensorInfo* inputInfo : inputs)
    {
        infos.push_back(*inputInfo);
    }
    infos.push_back(output);

    return m_LayerSupport->IsLayerSupported(LayerType::Stack,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsStandInSupported(const std::vector<const TensorInfo*>& inputs,
                                            const std::vector<const TensorInfo*>& outputs,
                                            const StandInDescriptor& descriptor,
                                            Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos;
    for (const TensorInfo* inputInfo : inputs)
    {
        infos.push_back(*inputInfo);
    }
    for (const TensorInfo* outputInfo : outputs)
    {
        infos.push_back(*outputInfo);
    }

    return m_LayerSupport->IsLayerSupported(LayerType::StandIn,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}


bool LayerSupportHandle::IsStridedSliceSupported(const TensorInfo& input,
                                                 const TensorInfo& output,
                                                 const StridedSliceDescriptor& descriptor,
                                                 Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, output};

    return m_LayerSupport->IsLayerSupported(LayerType::StridedSlice,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsSubtractionSupported(const TensorInfo& input0,
                                                const TensorInfo& input1,
                                                const TensorInfo& output,
                                                Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input0, input1, output};

    return m_LayerSupport->IsLayerSupported(LayerType::Subtraction,
                                            infos,
                                            BaseDescriptor(),
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsSwitchSupported(const TensorInfo& input0,
                                           const TensorInfo& input1,
                                           const TensorInfo& output0,
                                           const TensorInfo& output1,
                                           Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input0, input1, output0, output1};

    return m_LayerSupport->IsLayerSupported(LayerType::Switch,
                                            infos,
                                            BaseDescriptor(),
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsTileSupported(const TensorInfo& input,
                                         const TensorInfo& output,
                                         const armnn::TileDescriptor &descriptor,
                                         Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, output};

    return m_LayerSupport->IsLayerSupported(LayerType::Tile,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsTransposeConvolution2dSupported(
        const TensorInfo& input,
        const TensorInfo& output,
        const TransposeConvolution2dDescriptor& descriptor,
        const TensorInfo& weights,
        const Optional<TensorInfo>& biases,
        Optional<std::string&> reasonIfUnsupported)
{
    TensorInfo biasesVal =  biases.has_value() ? biases.value() : TensorInfo();
    TensorInfos infos{input, output, weights, biasesVal};

    return m_LayerSupport->IsLayerSupported(LayerType::TransposeConvolution2d,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsTransposeSupported(const TensorInfo& input,
                                              const TensorInfo& output,
                                              const TransposeDescriptor& descriptor,
                                              Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, output};

    return m_LayerSupport->IsLayerSupported(LayerType::Transpose,
                                            infos,
                                            descriptor,
                                            EmptyOptional(),
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

bool LayerSupportHandle::IsUnidirectionalSequenceLstmSupported(const TensorInfo& input,
                                                               const TensorInfo& outputStateIn,
                                                               const TensorInfo& cellStateIn,
                                                               const TensorInfo& outputStateOut,
                                                               const TensorInfo& cellStateOut,
                                                               const TensorInfo& output,
                                                               const LstmDescriptor& descriptor,
                                                               const LstmInputParamsInfo& paramsInfo,
                                                               Optional<std::string&> reasonIfUnsupported)
{
    TensorInfos infos{input, outputStateIn, cellStateIn, outputStateOut, cellStateOut, output};

    return m_LayerSupport->IsLayerSupported(LayerType::UnidirectionalSequenceLstm,
                                            infos,
                                            descriptor,
                                            paramsInfo,
                                            EmptyOptional(),
                                            reasonIfUnsupported);
}

}