text:
/* ----------------------------------------------------------------------------

 * GTSAM Copyright 2010, Georgia Tech Research Corporation,
 * Atlanta, Georgia 30332-0415
 * All Rights Reserved
 * Authors: Frank Dellaert, et al. (see THANKS for the full author list)

 * See LICENSE for the license information

 * -------------------------------------------------------------------------- */

/**
 * @file    SO3.cpp
 * @brief   3*3 matrix representation of SO(3)
 * @author  Frank Dellaert
 * @author  Luca Carlone
 * @author  Duy Nguyen Ta
 * @date    December 2014
 */

#include <gtsam/base/concepts.h>
#include <gtsam/geometry/SO3.h>

#include <Eigen/SVD>

#include <cmath>
#include <iostream>
#include <limits>

namespace gtsam {

//******************************************************************************
namespace so3 {

GTSAM_EXPORT Matrix99 Dcompose(const SO3& Q) {
  Matrix99 H;
  auto R = Q.matrix();
  H << I_3x3 * R(0, 0), I_3x3 * R(1, 0), I_3x3 * R(2, 0),  //
      I_3x3 * R(0, 1), I_3x3 * R(1, 1), I_3x3 * R(2, 1),   //
      I_3x3 * R(0, 2), I_3x3 * R(1, 2), I_3x3 * R(2, 2);
  return H;
}

GTSAM_EXPORT Matrix3 compose(const Matrix3& M, const SO3& R, OptionalJacobian<9, 9> H) {
  Matrix3 MR = M * R.matrix();
  if (H) *H = Dcompose(R);
  return MR;
}

void ExpmapFunctor::init(bool nearZeroApprox) {
  nearZero =
      nearZeroApprox || (theta2 <= std::numeric_limits<double>::epsilon());
  if (!nearZero) {
    sin_theta = std::sin(theta);
    const double s2 = std::sin(theta / 2.0);
    one_minus_cos = 2.0 * s2 * s2;  // numerically better than [1 - cos(theta)]
  }
}

ExpmapFunctor::ExpmapFunctor(const Vector3& omega, bool nearZeroApprox)
    : theta2(omega.dot(omega)), theta(std::sqrt(theta2)) {
  const double wx = omega.x(), wy = omega.y(), wz = omega.z();
  W << 0.0, -wz, +wy, +wz, 0.0, -wx, -wy, +wx, 0.0;
  init(nearZeroApprox);
  if (!nearZero) {
    K = W / theta;
    KK = K * K;
  }
}

ExpmapFunctor::ExpmapFunctor(const Vector3& axis, double angle,
                             bool nearZeroApprox)
    : theta2(angle * angle), theta(angle) {
  const double ax = axis.x(), ay = axis.y(), az = axis.z();
  K << 0.0, -az, +ay, +az, 0.0, -ax, -ay, +ax, 0.0;
  W = K * angle;
  init(nearZeroApprox);
  if (!nearZero) {
    KK = K * K;
  }
}

SO3 ExpmapFunctor::expmap() const {
  if (nearZero)
    return SO3(I_3x3 + W);
  else
    return SO3(I_3x3 + sin_theta * K + one_minus_cos * KK);
}

DexpFunctor::DexpFunctor(const Vector3& omega, bool nearZeroApprox)
    : ExpmapFunctor(omega, nearZeroApprox), omega(omega) {
  if (nearZero) {
    dexp_ = I_3x3 - 0.5 * W;
  } else {
    a = one_minus_cos / theta;
    b = 1.0 - sin_theta / theta;
    dexp_ = I_3x3 - a * K + b * KK;
  }
}

Vector3 DexpFunctor::applyDexp(const Vector3& v, OptionalJacobian<3, 3> H1,
                               OptionalJacobian<3, 3> H2) const {
  if (H1) {
    if (nearZero) {
      *H1 = 0.5 * skewSymmetric(v);
    } else {
      // TODO(frank): Iserles hints that there should be a form I + c*K + d*KK
      const Vector3 Kv = K * v;
      const double Da = (sin_theta - 2.0 * a) / theta2;
      const double Db = (one_minus_cos - 3.0 * b) / theta2;
      *H1 = (Db * K - Da * I_3x3) * Kv * omega.transpose() -
            skewSymmetric(Kv * b / theta) +
            (a * I_3x3 - b * K) * skewSymmetric(v / theta);
    }
  }
  if (H2) *H2 = dexp_;
  return dexp_ * v;
}

Vector3 DexpFunctor::applyInvDexp(const Vector3& v, OptionalJacobian<3, 3> H1,
                                  OptionalJacobian<3, 3> H2) const {
  const Matrix3 invDexp = dexp_.inverse();
  const Vector3 c = invDexp * v;
  if (H1) {
    Matrix3 D_dexpv_omega;
    applyDexp(c, D_dexpv_omega);  // get derivative H of forward mapping
    *H1 = -invDexp * D_dexpv_omega;
  }
  if (H2) *H2 = invDexp;
  return c;
}

}  // namespace so3

//******************************************************************************
template <>
GTSAM_EXPORT
SO3 SO3::AxisAngle(const Vector3& axis, double theta) {
  return so3::ExpmapFunctor(axis, theta).expmap();
}

//******************************************************************************
template <>
GTSAM_EXPORT
SO3 SO3::ClosestTo(const Matrix3& M) {
  Eigen::JacobiSVD<Matrix3> svd(M, Eigen::ComputeFullU | Eigen::ComputeFullV);
  const auto& U = svd.matrixU();
  const auto& V = svd.matrixV();
  const double det = (U * V.transpose()).determinant();
  return SO3(U * Vector3(1, 1, det).asDiagonal() * V.transpose());
}

//******************************************************************************
template <>
GTSAM_EXPORT
SO3 SO3::ChordalMean(const std::vector<SO3>& rotations) {
  // See Hartley13ijcv:
  // Cost function C(R) = \sum sqr(|R-R_i|_F)
  // Closed form solution = ClosestTo(C_e), where C_e = \sum R_i !!!!
  Matrix3 C_e{Z_3x3};
  for (const auto& R_i : rotations) {
    C_e += R_i.matrix();
  }
  return ClosestTo(C_e);
}

//******************************************************************************
template <>
GTSAM_EXPORT
Matrix3 SO3::Hat(const Vector3& xi) {
  // skew symmetric matrix X = xi^
  Matrix3 Y = Z_3x3;
  Y(0, 1) = -xi(2);
  Y(0, 2) = +xi(1);
  Y(1, 2) = -xi(0);
  return Y - Y.transpose();
}

//******************************************************************************
template <>
GTSAM_EXPORT
Vector3 SO3::Vee(const Matrix3& X) {
  Vector3 xi;
  xi(0) = -X(1, 2);
  xi(1) = +X(0, 2);
  xi(2) = -X(0, 1);
  return xi;
}

//******************************************************************************
template <>
GTSAM_EXPORT
Matrix3 SO3::AdjointMap() const {
  return matrix_;
}

//******************************************************************************
template <>
GTSAM_EXPORT
SO3 SO3::Expmap(const Vector3& omega, ChartJacobian H) {
  if (H) {
    so3::DexpFunctor impl(omega);
    *H = impl.dexp();
    return impl.expmap();
  } else {
    return so3::ExpmapFunctor(omega).expmap();
  }
}

template <>
GTSAM_EXPORT
Matrix3 SO3::ExpmapDerivative(const Vector3& omega) {
  return so3::DexpFunctor(omega).dexp();
}

//******************************************************************************
/* Right Jacobian for Log map in SO(3) - equation (10.86) and following
 equations in G.S. Chirikjian, "Stochastic Models, Information Theory, and Lie
 Groups", Volume 2, 2008.

   logmap( Rhat * expmap(omega) ) \approx logmap(Rhat) + Jrinv * omega

 where Jrinv = LogmapDerivative(omega). This maps a perturbation on the
 manifold (expmap(omega)) to a perturbation in the tangent space (Jrinv *
 omega)
 */
template <>
GTSAM_EXPORT
Matrix3 SO3::LogmapDerivative(const Vector3& omega) {
  using std::cos;
  using std::sin;

  double theta2 = omega.dot(omega);
  if (theta2 <= std::numeric_limits<double>::epsilon()) return I_3x3;
  double theta = std::sqrt(theta2);  // rotation angle

  // element of Lie algebra so(3): W = omega^
  const Matrix3 W = Hat(omega);
  return I_3x3 + 0.5 * W +
         (1 / (theta * theta) - (1 + cos(theta)) / (2 * theta * sin(theta))) *
             W * W;
}

//******************************************************************************
template <>
GTSAM_EXPORT
Vector3 SO3::Logmap(const SO3& Q, ChartJacobian H) {
  using std::sin;
  using std::sqrt;

  // note switch to base 1
  const Matrix3& R = Q.matrix();
  const double &R11 = R(0, 0), R12 = R(0, 1), R13 = R(0, 2);
  const double &R21 = R(1, 0), R22 = R(1, 1), R23 = R(1, 2);
  const double &R31 = R(2, 0), R32 = R(2, 1), R33 = R(2, 2);

  // Get trace(R)
  const double tr = R.trace();

  Vector3 omega;

  // when trace == -1, i.e., when theta = +-pi, +-3pi, +-5pi, etc.
  // we do something special
  if (tr + 1.0 < 1e-10) {
    if (std::abs(R33 + 1.0) > 1e-5)
      omega = (M_PI / sqrt(2.0 + 2.0 * R33)) * Vector3(R13, R23, 1.0 + R33);
    else if (std::abs(R22 + 1.0) > 1e-5)
      omega = (M_PI / sqrt(2.0 + 2.0 * R22)) * Vector3(R12, 1.0 + R22, R32);
    else
      // if(std::abs(R.r1_.x()+1.0) > 1e-5)  This is implicit
      omega = (M_PI / sqrt(2.0 + 2.0 * R11)) * Vector3(1.0 + R11, R21, R31);
  } else {
    double magnitude;
    const double tr_3 = tr - 3.0;  // always negative
    if (tr_3 < -1e-7) {
      double theta = acos((tr - 1.0) / 2.0);
      magnitude = theta / (2.0 * sin(theta));
    } else {
      // when theta near 0, +-2pi, +-4pi, etc. (trace near 3.0)
      // use Taylor expansion: theta \approx 1/2-(t-3)/12 + O((t-3)^2)
      magnitude = 0.5 - tr_3 * tr_3 / 12.0;
    }
    omega = magnitude * Vector3(R32 - R23, R13 - R31, R21 - R12);
  }

  if (H) *H = LogmapDerivative(omega);
  return omega;
}

//******************************************************************************
// Chart at origin for SO3 is *not* Cayley but actual Expmap/Logmap

template <>
GTSAM_EXPORT
SO3 SO3::ChartAtOrigin::Retract(const Vector3& omega, ChartJacobian H) {
  return Expmap(omega, H);
}

template <>
GTSAM_EXPORT
Vector3 SO3::ChartAtOrigin::Local(const SO3& R, ChartJacobian H) {
  return Logmap(R, H);
}

//******************************************************************************
// local vectorize
static Vector9 vec3(const Matrix3& R) {
  return Eigen::Map<const Vector9>(R.data());
}

// so<3> generators
static std::vector<Matrix3> G3({SO3::Hat(Vector3::Unit(0)),
                                SO3::Hat(Vector3::Unit(1)),
                                SO3::Hat(Vector3::Unit(2))});

// vectorized generators
static const Matrix93 P3 =
    (Matrix93() << vec3(G3[0]), vec3(G3[1]), vec3(G3[2])).finished();

//******************************************************************************
template <>
GTSAM_EXPORT
Vector9 SO3::vec(OptionalJacobian<9, 3> H) const {
  const Matrix3& R = matrix_;
  if (H) {
    // As Luca calculated (for SO4), this is (I3 \oplus R) * P3
    *H << R * P3.block<3, 3>(0, 0), R * P3.block<3, 3>(3, 0),
        R * P3.block<3, 3>(6, 0);
  }
  return gtsam::vec3(R);
}
//******************************************************************************

}  // end namespace gtsam

ext: cpp


text:
//==================================================================================================
/*!
  @file

  @copyright 2016 NumScale SAS
  @copyright 2016 J.T. Lapreste

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
//==================================================================================================
#ifndef BOOST_SIMD_FUNCTION_IS_NOT_LESS_EQUAL_HPP_INCLUDED
#define BOOST_SIMD_FUNCTION_IS_NOT_LESS_EQUAL_HPP_INCLUDED

#if defined(DOXYGEN_ONLY)
namespace boost { namespace simd
{

 /*!
    @ingroup group-predicates
    Function object implementing is_not_less_equal capabilities

    Returns @ref True  or @ref False depending on whether x is
    not less or equal to y or is.

    @par Semantic:

    @code
    as_logical_t<T> r = is_not_less_equal(x,y);
    @endcode

    is similar to:

    @code
    as_logical_t<T> r = !(x <= y);
    @endcode

    @par Note:

    Due to existence of nan, this is not equivalent to a call to @ref is_greater
    for floating types

    @par Alias:

    @c is_nle

  **/
  const boost::dispatch::functor<tag::is_not_less_equal_> is_not_less_equal = {};
} }
#endif

#include <boost/simd/function/scalar/is_not_less_equal.hpp>
#include <boost/simd/function/simd/is_not_less_equal.hpp>

#endif

ext: hpp


text:
//==============================================================================
//         Copyright 2003 - 2011 LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 - 2011 LRI    UMR 8623 CNRS/Univ Paris Sud XI
//
//          Distributed under the Boost Software License, Version 1.0.
//                 See accompanying file LICENSE.txt or copy at
//                     http://www.boost.org/LICENSE_1_0.txt
//==============================================================================
#ifndef BOOST_SIMD_SWAR_FUNCTIONS_SIMD_SSE_SSE4_1_SPLIT_MULTIPLIES_HPP_INCLUDED
#define BOOST_SIMD_SWAR_FUNCTIONS_SIMD_SSE_SSE4_1_SPLIT_MULTIPLIES_HPP_INCLUDED
#ifdef BOOST_SIMD_HAS_SSE4_1_SUPPORT

#include <boost/simd/swar/functions/split_multiplies.hpp>
#include <boost/simd/include/functions/simd/interleave_first.hpp>
#include <boost/simd/include/functions/simd/interleave_second.hpp>

namespace boost { namespace simd { namespace ext
{
  BOOST_DISPATCH_IMPLEMENT         ( split_multiplies_
                                   , boost::simd::tag::sse4_1_
                                   , (A0)(A1)
                                   , ((simd_<int32_<A0>,boost::simd::tag::sse_>))
                                     ((simd_<int32_<A0>,boost::simd::tag::sse_>))
                                     ((simd_<int64_<A1>,boost::simd::tag::sse_>))
                                     ((simd_<int64_<A1>,boost::simd::tag::sse_>))
                                   )
  {
    typedef void result_type;
    BOOST_FORCEINLINE result_type operator()(A0 const& a0, A0 const& a1, A1& a2, A1& a3) const
    {
      A1 lo = _mm_mul_epi32(a0, a1);
      A1 hi = _mm_mul_epi32(_mm_srli_si128(a0, 4), _mm_srli_si128(a1, 4));

      a2 = interleave_first(lo, hi);
      a3 = interleave_second(lo, hi);
    }
  };
} } }

#endif
#endif


text:
#pragma once
#include <boost/filesystem.hpp>
#include <lmdb/libraries/liblmdb/lmdb.h>
#include <rai/common/errors.hpp>
#include <rai/common/numbers.hpp>
#include <rai/common/util.hpp>
#include <rai/secure/lmdb.hpp>

namespace rai
{

class Store
{
public:
    Store(rai::ErrorCode&, const boost::filesystem::path&);
    Store(const rai::Store&) = delete;
    bool Put(MDB_txn*, MDB_dbi, MDB_val*, MDB_val*);
    bool Get(MDB_txn*, MDB_dbi, MDB_val*, MDB_val*) const;
    bool Del(MDB_txn*, MDB_dbi, MDB_val*, MDB_val*);

    rai::MdbEnv env_;

    /***************************************************************************
     Key: rai::Account
     Value: rai::AccountInfo
     **************************************************************************/
    MDB_dbi accounts_;

    /***************************************************************************
     Key: rai::BlockHash
     Value: rai::Block,rai::BlockHash
     **************************************************************************/
    MDB_dbi blocks_;

    /***************************************************************************
     Key: rai::Account, uint64_t
     Value: rai::BlockHash
     **************************************************************************/
    MDB_dbi blocks_index_;

    /***************************************************************************
     Meta information, such as version.
     Key: uint32_t
     Value: uint32_t
     **************************************************************************/
     MDB_dbi meta_;

    /***************************************************************************
     Key: rai::Account, rai::BlockHash
     Value: rai::ReceivableInfo
     **************************************************************************/
    MDB_dbi receivables_;

    /***************************************************************************
     Key: rai::Account,rai::BlockHash
     Value: rai::RewardableInfo
     **************************************************************************/
    MDB_dbi rewardables_;

    /***************************************************************************
     Key: rai::BlockHash
     Value: rai::Block
     **************************************************************************/
    MDB_dbi rollbacks_;

    /***************************************************************************
     Key: rai::Account, uint64_t
     Value: rai::Block,rai::Block
     **************************************************************************/
    MDB_dbi forks_;

    /***************************************************************************
     Key: uint32_t,uint32_t
     Value: rai::WalletInfo
     **************************************************************************/
    MDB_dbi wallets_;

    /***************************************************************************
     Key: rai::BlockHash
     Value: rai::Block/junk
     **************************************************************************/
    MDB_dbi sources_;

    /***************************************************************************
     Key: rai::Account
     Value: rai::AliasInfo
     **************************************************************************/
    MDB_dbi alias_;

    /***************************************************************************
     Key: rai::Account, uint64_t
     Value: rai::AliasBlock
     **************************************************************************/
    MDB_dbi alias_block_;

    /***************************************************************************
     Key: rai::AliasIndex
     Value: uint8_t
     **************************************************************************/
    MDB_dbi alias_index_;

    /***************************************************************************
     Key: rai::AliasIndex
     Value: uint8_t
     **************************************************************************/
    MDB_dbi alias_dns_index_;

    /***************************************************************************
     Key: rai::Account
     Value: rai::AccountTokensInfo
     **************************************************************************/
    MDB_dbi account_tokens_info_;

    /***************************************************************************
     Key: rai::Account, uint64_t
     Value: rai::TokenBlock
     **************************************************************************/
    MDB_dbi token_block_;

    /***************************************************************************
     Key: rai::AccountTokenLinkKey
     Value: uint64_t
     **************************************************************************/
    MDB_dbi account_token_link_;

    /***************************************************************************
     Key: rai::Account, rai::Chain, rai::TokenAddress
     Value: rai::AccountTokenInfo
     **************************************************************************/
    MDB_dbi account_token_info_;
};
} // namespace rai

max_stars_repo_name: raicoincommunity/Raicoin

max_issues_repo_name: raicoincommunity/Raicoin

max_forks_repo_name: raicoincommunity/Raicoin


text:
//
// Copyright © 2017 Arm Ltd. All rights reserved.
// SPDX-License-Identifier: MIT
//

#include <boost/test/unit_test.hpp>
#include "ParserFlatbuffersFixture.hpp"
#include "../TfLiteParser.hpp"

#include <string>
#include <iostream>

BOOST_AUTO_TEST_SUITE(TensorflowLiteParser)

struct FullyConnectedFixture : public ParserFlatbuffersFixture
{
    explicit FullyConnectedFixture(const std::string& inputShape,
                                           const std::string& outputShape,
                                           const std::string& filterShape,
                                           const std::string& filterData,
                                           const std::string biasShape = "",
                                           const std::string biasData = "")
    {
        std::string inputTensors = "[ 0, 2 ]";
        std::string biasTensor = "";
        std::string biasBuffer = "";
        if (biasShape.size() > 0 && biasData.size() > 0)
        {
            inputTensors = "[ 0, 2, 3 ]";
            biasTensor = R"(
                        {
                            "shape": )" + biasShape + R"( ,
                            "type": "INT32",
                            "buffer": 3,
                            "name": "biasTensor",
                            "quantization": {
                                "min": [ 0.0 ],
                                "max": [ 255.0 ],
                                "scale": [ 1.0 ],
                                "zero_point": [ 0 ],
                            }
                        } )";
            biasBuffer = R"(
                    { "data": )" + biasData + R"(, }, )";
        }
        m_JsonString = R"(
            {
                "version": 3,
                "operator_codes": [ { "builtin_code": "FULLY_CONNECTED" } ],
                "subgraphs": [ {
                    "tensors": [
                        {
                            "shape": )" + inputShape + R"(,
                            "type": "UINT8",
                            "buffer": 0,
                            "name": "inputTensor",
                            "quantization": {
                                "min": [ 0.0 ],
                                "max": [ 255.0 ],
                                "scale": [ 1.0 ],
                                "zero_point": [ 0 ],
                            }
                        },
                        {
                            "shape": )" + outputShape + R"(,
                            "type": "UINT8",
                            "buffer": 1,
                            "name": "outputTensor",
                            "quantization": {
                                "min": [ 0.0 ],
                                "max": [ 511.0 ],
                                "scale": [ 2.0 ],
                                "zero_point": [ 0 ],
                            }
                        },
                        {
                            "shape": )" + filterShape + R"(,
                            "type": "UINT8",
                            "buffer": 2,
                            "name": "filterTensor",
                            "quantization": {
                                "min": [ 0.0 ],
                                "max": [ 255.0 ],
                                "scale": [ 1.0 ],
                                "zero_point": [ 0 ],
                            }
                        }, )" + biasTensor + R"(
                    ],
                    "inputs": [ 0 ],
                    "outputs": [ 1 ],
                    "operators": [
                        {
                            "opcode_index": 0,
                            "inputs": )" + inputTensors + R"(,
                            "outputs": [ 1 ],
                            "builtin_options_type": "FullyConnectedOptions",
                            "builtin_options": {
                                "fused_activation_function": "NONE"
                            },
                            "custom_options_format": "FLEXBUFFERS"
                        }
                    ],
                } ],
                "buffers" : [
                    { },
                    { },
                    { "data": )" + filterData + R"(, }, )"
                       + biasBuffer + R"(
                ]
            }
        )";
        SetupSingleInputSingleOutput("inputTensor", "outputTensor");
    }
};

struct FullyConnectedWithNoBiasFixture : FullyConnectedFixture
{
    FullyConnectedWithNoBiasFixture()
        : FullyConnectedFixture("[ 1, 4, 1, 1 ]",     // inputShape
                                "[ 1, 1 ]",           // outputShape
                                "[ 1, 4 ]",           // filterShape
                                "[ 2, 3, 4, 5 ]")     // filterData
    {}
};

BOOST_FIXTURE_TEST_CASE(FullyConnectedWithNoBias, FullyConnectedWithNoBiasFixture)
{
    RunTest<2, armnn::DataType::QAsymmU8>(
        0,
        { 10, 20, 30, 40 },
        { 400/2 });
}

struct FullyConnectedWithBiasFixture : FullyConnectedFixture
{
    FullyConnectedWithBiasFixture()
        : FullyConnectedFixture("[ 1, 4, 1, 1 ]",     // inputShape
                                "[ 1, 1 ]",           // outputShape
                                "[ 1, 4 ]",           // filterShape
                                "[ 2, 3, 4, 5 ]",     // filterData
                                "[ 1 ]",              // biasShape
                                "[ 10, 0, 0, 0 ]" )   // biasData
    {}
};

BOOST_FIXTURE_TEST_CASE(ParseFullyConnectedWithBias, FullyConnectedWithBiasFixture)
{
    RunTest<2, armnn::DataType::QAsymmU8>(
        0,
        { 10, 20, 30, 40 },
        { (400+10)/2 });
}

struct FullyConnectedWithBiasMultipleOutputsFixture : FullyConnectedFixture
{
    FullyConnectedWithBiasMultipleOutputsFixture()
            : FullyConnectedFixture("[ 1, 4, 2, 1 ]",     // inputShape
                                    "[ 2, 1 ]",           // outputShape
                                    "[ 1, 4 ]",           // filterShape
                                    "[ 2, 3, 4, 5 ]",     // filterData
                                    "[ 1 ]",              // biasShape
                                    "[ 10, 0, 0, 0 ]" )   // biasData
    {}
};

BOOST_FIXTURE_TEST_CASE(FullyConnectedWithBiasMultipleOutputs, FullyConnectedWithBiasMultipleOutputsFixture)
{
    RunTest<2, armnn::DataType::QAsymmU8>(
            0,
            { 1, 2, 3, 4, 10, 20, 30, 40 },
            { (40+10)/2, (400+10)/2 });
}

struct DynamicFullyConnectedWithBiasMultipleOutputsFixture : FullyConnectedFixture
{
    DynamicFullyConnectedWithBiasMultipleOutputsFixture()
        : FullyConnectedFixture("[ 1, 4, 2, 1 ]",     // inputShape
                                "[ ]",               // outputShape
                                "[ 1, 4 ]",           // filterShape
                                "[ 2, 3, 4, 5 ]",     // filterData
                                "[ 1 ]",              // biasShape
                                "[ 10, 0, 0, 0 ]" )   // biasData
    { }
};

BOOST_FIXTURE_TEST_CASE(
    DynamicFullyConnectedWithBiasMultipleOutputs,
    DynamicFullyConnectedWithBiasMultipleOutputsFixture)
{
    RunTest<2,
            armnn::DataType::QAsymmU8,
            armnn::DataType::QAsymmU8>(0,
                                      { { "inputTensor", { 1, 2, 3, 4, 10, 20, 30, 40} } },
                                      { { "outputTensor", { (40+10)/2, (400+10)/2 } } },
                                      true);
}

BOOST_AUTO_TEST_SUITE_END()