#ifndef SKYLARK_HASH_TRANSFORM_LOCAL_SPARSE_HPP
#define SKYLARK_HASH_TRANSFORM_LOCAL_SPARSE_HPP

#include <boost/dynamic_bitset.hpp>

namespace skylark { namespace sketch {

/* Specialization: local SpMat for input, output */
template <typename ValueType,
          template <typename> class IdxDistributionType,
          template <typename> class ValueDistribution>
struct hash_transform_t <
    base::sparse_matrix_t<ValueType>,
    base::sparse_matrix_t<ValueType>,
    IdxDistributionType,
    ValueDistribution > :
        public hash_transform_data_t<IdxDistributionType,
                                     ValueDistribution> {
    typedef size_t index_type;
    typedef ValueType value_type;
    typedef base::sparse_matrix_t<ValueType> matrix_type;
    typedef base::sparse_matrix_t<ValueType> output_matrix_type;
    typedef IdxDistributionType<index_type> idx_distribution_type;
    typedef ValueDistribution<value_type> value_distribution_type;
    typedef hash_transform_data_t<IdxDistributionType,
                                  ValueDistribution> data_type;

    /**
     * Regular constructor
     */
    hash_transform_t (int N, int S, base::context_t& context) :
        data_type(N, S, context) {

    }

    /**
     * Copy constructor
     */
    template <typename InputMatrixType,
              typename OutputMatrixType>
    hash_transform_t (hash_transform_t<InputMatrixType,
                                       OutputMatrixType,
                                       IdxDistributionType,
                                       ValueDistribution>& other) :
        data_type(other) {}

    /**
     * Constructor from data
     */
    hash_transform_t (hash_transform_data_t<IdxDistributionType,
                                            ValueDistribution>& other_data) :
        data_type(other_data) {}

    /**
     * Apply the sketching transform that is described in by the sketch_of_A.
     */
    template <typename Dimension>
    void apply (const matrix_type &A, output_matrix_type &sketch_of_A,
                Dimension dimension) const {
        try {
            apply_impl (A, sketch_of_A, dimension);
        } catch(boost::mpi::exception e) {
            SKYLARK_THROW_EXCEPTION (
                base::mpi_exception()
                    << base::error_msg(e.what()) );
        } catch (std::string e) {
            SKYLARK_THROW_EXCEPTION (
                base::combblas_exception()
                    << base::error_msg(e) );
        } catch (std::logic_error e) {
            SKYLARK_THROW_EXCEPTION (
                base::combblas_exception()
                    << base::error_msg(e.what()) );
        }
    }

    int get_N() const { return this->_N; } /**< Get input dimension. */
    int get_S() const { return this->_S; } /**< Get output dimension. */

    const sketch_transform_data_t* get_data() const { return this; }

private:
    /**
     * Apply the sketching transform that is described in by the sketch_of_A
     * columnwise.
     */
    void apply_impl (const matrix_type &A,
                     output_matrix_type &sketch_of_A,
                     columnwise_tag) const {

        index_type col_idx = 0;

        const int* indptr  = A.indptr();
        const int* indices = A.indices();
        const value_type* values = A.locked_values();

        index_type n_rows = data_type::_S;
        index_type n_cols = A.width();

        int nnz = 0;
        int *indptr_new = new int[n_cols + 1];
        std::vector<int> final_rows(A.nonzeros());
        std::vector<value_type> final_vals(A.nonzeros());

        indptr_new[0] = 0;
        std::vector<index_type> idx_map(n_rows, -1);

        for(index_type col = 0; col < A.width(); col++) {

            for(index_type idx = indptr[col]; idx < indptr[col + 1]; idx++) {

                index_type row = indices[idx];
                value_type val = values[idx] * data_type::row_value[row];
                row            = data_type::row_idx[row];

                //XXX: I think we should get rid of the if here...
                if(idx_map[row] == -1) {
                    idx_map[row] = nnz;
                    final_rows[nnz] = row;
                    final_vals[nnz] = val;
                    nnz++;
                } else {
                    final_vals[idx_map[row]] += val;
                }
            }

            indptr_new[col + 1] = nnz;

            // reset idx_map
            for(int i = indptr_new[col]; i < nnz; ++i)
                idx_map[final_rows[i]] = -1;
        }

        int *indices_new = new int[nnz];
        std::copy(final_rows.begin(), final_rows.begin() + nnz, indices_new);

        value_type *values_new = new value_type[nnz];
        std::copy(final_vals.begin(), final_vals.begin() + nnz, values_new);

        // let the sparse structure take ownership of the data
        sketch_of_A.attach(indptr_new, indices_new, values_new,
                           nnz, n_rows, n_cols, true);
    }

    /**
     * Apply the sketching transform that is described in by the sketch_of_A
     * rowwise.
     */
    void apply_impl (const matrix_type &A,
                     output_matrix_type &sketch_of_A,
                     rowwise_tag) const {

        index_type col_idx = 0;

        const int* indptr = A.indptr();
        const int* indices = A.indices();
        const value_type* values = A.locked_values();

        // target size
        index_type n_rows = A.height();
        index_type n_cols = data_type::_S;

        int nnz = 0;
        int *indptr_new = new int[n_cols + 1];
        std::vector<int> final_rows(A.nonzeros());
        std::vector<value_type> final_vals(A.nonzeros());

        indptr_new[0] = 0;

        // we adapt transversal order for this case
        //XXX: or transpose A (maybe better for cache)
        std::vector< std::vector<int> > inv_mapping(data_type::_S);
        for(int idx = 0; idx < data_type::row_idx.size(); ++idx) {
            inv_mapping[data_type::row_idx[idx]].push_back(idx);
        }

        std::vector<index_type> idx_map(n_rows, -1);

        for(index_type target_col = 0; target_col < data_type::_S;
            ++target_col) {

            std::vector<int>::iterator itr;
            for(itr = inv_mapping[target_col].begin();
                itr != inv_mapping[target_col].end(); itr++) {

                int col = *itr;

                for(index_type idx = indptr[col]; idx < indptr[col + 1]; idx++) {

                    index_type row = indices[idx];
                    value_type val = values[idx] * data_type::row_value[col];

                    //XXX: I think we should get rid of the if here...
                    if(idx_map[row] == -1) {
                        idx_map[row] = nnz;
                        final_rows[nnz] = row;
                        final_vals[nnz] = val;
                        nnz++;
                    } else {
                        final_vals[idx_map[row]] += val;
                    }
                }
            }

            indptr_new[target_col + 1] = nnz;

            // reset idx_map
            for(int i = indptr_new[target_col]; i < nnz; ++i)
                idx_map[final_rows[i]] = -1;
        }

        int *indices_new = new int[nnz];
        std::copy(final_rows.begin(), final_rows.begin() + nnz, indices_new);

        value_type *values_new = new value_type[nnz];
        std::copy(final_vals.begin(), final_vals.begin() + nnz, values_new);

        sketch_of_A.attach(indptr_new, indices_new, values_new,
                           nnz, n_rows, n_cols, true);
    }
};

} } /** namespace skylark::sketch */

#endif // SKYLARK_HASH_TRANSFORM_LOCAL_SPARSE_HPP


/*
 * Copyright (c) 2021 Abit More, and contributors.
 *
 * The MIT License
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
#include <graphene/chain/market_object.hpp>

#include <boost/multiprecision/cpp_int.hpp>

#include <functional>

#include <fc/io/raw.hpp>

using namespace graphene::chain;

/*
target_CR = max( target_CR, MCR )

target_CR = new_collateral / ( new_debt / feed_price )
          = ( collateral - max_amount_to_sell ) * feed_price
            / ( debt - amount_to_get )
          = ( collateral - max_amount_to_sell ) * feed_price
            / ( debt - round_down(max_amount_to_sell * match_price ) )
          = ( collateral - max_amount_to_sell ) * feed_price
            / ( debt - (max_amount_to_sell * match_price - x) )

Note: x is the fraction, 0 <= x < 1

=>

max_amount_to_sell = ( (debt + x) * target_CR - collateral * feed_price )
                     / (target_CR * match_price - feed_price)
                   = ( (debt + x) * tCR / DENOM - collateral * fp_debt_amt / fp_coll_amt )
                     / ( (tCR / DENOM) * (mp_debt_amt / mp_coll_amt) - fp_debt_amt / fp_coll_amt )
                   = ( (debt + x) * tCR * fp_coll_amt * mp_coll_amt - collateral * fp_debt_amt * DENOM * mp_coll_amt)
                     / ( tCR * mp_debt_amt * fp_coll_amt - fp_debt_amt * DENOM * mp_coll_amt )

max_debt_to_cover = max_amount_to_sell * match_price
                  = max_amount_to_sell * mp_debt_amt / mp_coll_amt
                  = ( (debt + x) * tCR * fp_coll_amt * mp_debt_amt - collateral * fp_debt_amt * DENOM * mp_debt_amt)
                    / (tCR * mp_debt_amt * fp_coll_amt - fp_debt_amt * DENOM * mp_coll_amt)
*/
share_type call_order_object::get_max_debt_to_cover( price match_price,
                                                     price feed_price,
                                                     const uint16_t maintenance_collateral_ratio,
                                                     const optional<price>& maintenance_collateralization )const
{ try {
   // be defensive here, make sure feed_price is in collateral / debt format
   if( feed_price.base.asset_id != call_price.base.asset_id )
      feed_price = ~feed_price;

   FC_ASSERT( feed_price.base.asset_id == call_price.base.asset_id
              && feed_price.quote.asset_id == call_price.quote.asset_id );

   bool after_core_hardfork_1270 = maintenance_collateralization.valid();

   // be defensive here, make sure maintenance_collateralization is in collateral / debt format
   if( after_core_hardfork_1270 )
   {
      FC_ASSERT( maintenance_collateralization->base.asset_id == call_price.base.asset_id
                 && maintenance_collateralization->quote.asset_id == call_price.quote.asset_id );
   }

   // According to the feed protection rule (https://github.com/cryptonomex/graphene/issues/436),
   // a call order should only be called when its collateral ratio is not higher than required maintenance collateral ratio.
   // Although this should be guaranteed by the caller of this function, we still check here to be defensive.
   // Theoretically this check can be skipped for better performance.
   //
   // Before core-1270 hard fork, we check with call_price; afterwards, we check with collateralization().
   if( ( !after_core_hardfork_1270 && call_price > feed_price )
       || ( after_core_hardfork_1270 && collateralization() > *maintenance_collateralization ) )
      return 0;

   if( !target_collateral_ratio.valid() ) // target cr is not set
      return debt;

   uint16_t tcr = std::max( *target_collateral_ratio, maintenance_collateral_ratio ); // use mcr if target cr is too small

   price target_collateralization = ( after_core_hardfork_1270 ?
                                      feed_price * ratio_type( tcr, GRAPHENE_COLLATERAL_RATIO_DENOM ) :
                                      price() );

   // be defensive here, make sure match_price is in collateral / debt format
   if( match_price.base.asset_id != call_price.base.asset_id )
      match_price = ~match_price;

   FC_ASSERT( match_price.base.asset_id == call_price.base.asset_id
              && match_price.quote.asset_id == call_price.quote.asset_id );

   typedef boost::multiprecision::int256_t i256;
   i256 mp_debt_amt = match_price.quote.amount.value;
   i256 mp_coll_amt = match_price.base.amount.value;
   i256 fp_debt_amt = feed_price.quote.amount.value;
   i256 fp_coll_amt = feed_price.base.amount.value;

   // firstly we calculate without the fraction (x), the result could be a bit too small
   i256 numerator = fp_coll_amt * mp_debt_amt * debt.value * tcr
                  - fp_debt_amt * mp_debt_amt * collateral.value * GRAPHENE_COLLATERAL_RATIO_DENOM;
   if( numerator < 0 ) // feed protected, actually should not be true here, just check to be safe
      return 0;

   i256 denominator = fp_coll_amt * mp_debt_amt * tcr - fp_debt_amt * mp_coll_amt * GRAPHENE_COLLATERAL_RATIO_DENOM;
   if( denominator <= 0 ) // black swan
      return debt;

   // note: if add 1 here, will result in 1.5x imperfection rate;
   //       however, due to rounding, the result could still be a bit too big, thus imperfect.
   i256 to_cover_i256 = ( numerator / denominator );
   if( to_cover_i256 >= debt.value ) // avoid possible overflow
      return debt;
   share_type to_cover_amt = static_cast< int64_t >( to_cover_i256 );

   // stabilize
   // note: rounding up-down results in 3x imperfection rate in comparison to down-down-up
   asset to_pay = asset( to_cover_amt, debt_type() ) * match_price;
   asset to_cover = to_pay * match_price;
   to_pay = to_cover.multiply_and_round_up( match_price );

   if( to_cover.amount >= debt || to_pay.amount >= collateral ) // to be safe
      return debt;
   FC_ASSERT( to_pay.amount < collateral && to_cover.amount < debt );

   // Check whether the collateral ratio after filled is high enough
   // Before core-1270 hard fork, we check with call_price; afterwards, we check with collateralization().
   std::function<bool()> result_is_good = after_core_hardfork_1270 ?
      std::function<bool()>( [this,&to_cover,&to_pay,target_collateralization]() -> bool
      {
         price new_collateralization = ( get_collateral() - to_pay ) / ( get_debt() - to_cover );
         return ( new_collateralization > target_collateralization );
      }) :
      std::function<bool()>( [this,&to_cover,&to_pay,tcr,feed_price]() -> bool
      {
         price new_call_price = price::call_price( get_debt() - to_cover, get_collateral() - to_pay, tcr );
         return ( new_call_price > feed_price );
      });

   // if the result is good, we return.
   if( result_is_good() )
      return to_cover.amount;

   // be here, to_cover is too small due to rounding. deal with the fraction
   numerator += fp_coll_amt * mp_debt_amt * tcr; // plus the fraction
   to_cover_i256 = ( numerator / denominator ) + 1;
   if( to_cover_i256 >= debt.value ) // avoid possible overflow
      to_cover_i256 = debt.value;
   to_cover_amt = static_cast< int64_t >( to_cover_i256 );

   asset max_to_pay = ( ( to_cover_amt == debt.value ) ? get_collateral()
                        : asset( to_cover_amt, debt_type() ).multiply_and_round_up( match_price ) );
   if( max_to_pay.amount > collateral )
      max_to_pay.amount = collateral;

   asset max_to_cover = ( ( max_to_pay.amount == collateral ) ? get_debt() : ( max_to_pay * match_price ) );
   if( max_to_cover.amount >= debt ) // to be safe
   {
      max_to_pay.amount = collateral;
      max_to_cover.amount = debt;
   }

   if( max_to_pay <= to_pay || max_to_cover <= to_cover ) // strange data. should skip binary search and go on, but doesn't help much
      return debt;
   FC_ASSERT( max_to_pay > to_pay && max_to_cover > to_cover );

   asset min_to_pay = to_pay;
   asset min_to_cover = to_cover;

   // try with binary search to find a good value
   // note: actually binary search can not always provide perfect result here,
   //       due to rounding, collateral ratio is not always increasing while to_pay or to_cover is increasing
   bool max_is_ok = false;
   while( true )
   {
      // get the mean
      if( match_price.base.amount < match_price.quote.amount ) // step of collateral is smaller
      {
         to_pay.amount = ( min_to_pay.amount + max_to_pay.amount + 1 ) / 2; // should not overflow. round up here
         if( to_pay.amount == max_to_pay.amount )
            to_cover.amount = max_to_cover.amount;
         else
         {
            to_cover = to_pay * match_price;
            if( to_cover.amount >= max_to_cover.amount ) // can be true when max_is_ok is false
            {
               to_pay.amount = max_to_pay.amount;
               to_cover.amount = max_to_cover.amount;
            }
            else
            {
               to_pay = to_cover.multiply_and_round_up( match_price ); // stabilization, no change or become smaller
               FC_ASSERT( to_pay.amount < max_to_pay.amount );
            }
         }
      }
      else // step of debt is smaller or equal
      {
         to_cover.amount = ( min_to_cover.amount + max_to_cover.amount ) / 2; // should not overflow. round down here
         if( to_cover.amount == max_to_cover.amount )
            to_pay.amount = max_to_pay.amount;
         else
         {
            to_pay = to_cover.multiply_and_round_up( match_price );
            if( to_pay.amount >= max_to_pay.amount ) // can be true when max_is_ok is false
            {
               to_pay.amount = max_to_pay.amount;
               to_cover.amount = max_to_cover.amount;
            }
            else
            {
               to_cover = to_pay * match_price; // stabilization, to_cover should have increased
               if( to_cover.amount >= max_to_cover.amount ) // to be safe
               {
                  to_pay.amount = max_to_pay.amount;
                  to_cover.amount = max_to_cover.amount;
               }
            }
         }
      }

      // check again to see if we've moved away from the minimums, if not, use the maximums directly
      if( to_pay.amount <= min_to_pay.amount || to_cover.amount <= min_to_cover.amount
            || to_pay.amount > max_to_pay.amount || to_cover.amount > max_to_cover.amount )
      {
         to_pay.amount = max_to_pay.amount;
         to_cover.amount = max_to_cover.amount;
      }

      // check the mean
      if( to_pay.amount == max_to_pay.amount && ( max_is_ok || to_pay.amount == collateral ) )
         return to_cover.amount;
      FC_ASSERT( to_pay.amount < collateral && to_cover.amount < debt );

      // Check whether the result is good
      if( result_is_good() ) // good
      {
         if( to_pay.amount == max_to_pay.amount )
            return to_cover.amount;
         max_to_pay.amount = to_pay.amount;
         max_to_cover.amount = to_cover.amount;
         max_is_ok = true;
      }
      else // not good
      {
         if( to_pay.amount == max_to_pay.amount )
            break;
         min_to_pay.amount = to_pay.amount;
         min_to_cover.amount = to_cover.amount;
      }
   }

   // be here, max_to_cover is too small due to rounding. search forward
   for( uint64_t d1 = 0, d2 = 1, d3 = 1; ; d1 = d2, d2 = d3, d3 = d1 + d2 ) // 1,1,2,3,5,8,...
   {
      if( match_price.base.amount > match_price.quote.amount ) // step of debt is smaller
      {
         to_pay.amount += d2;
         if( to_pay.amount >= collateral )
            return debt;
         to_cover = to_pay * match_price;
         if( to_cover.amount >= debt )
            return debt;
         to_pay = to_cover.multiply_and_round_up( match_price ); // stabilization
         if( to_pay.amount >= collateral )
            return debt;
      }
      else // step of collateral is smaller or equal
      {
         to_cover.amount += d2;
         if( to_cover.amount >= debt )
            return debt;
         to_pay = to_cover.multiply_and_round_up( match_price );
         if( to_pay.amount >= collateral )
            return debt;
         to_cover = to_pay * match_price; // stabilization
         if( to_cover.amount >= debt )
            return debt;
      }

      // defensive check
      FC_ASSERT( to_pay.amount < collateral && to_cover.amount < debt );

      // Check whether the result is good
      if( result_is_good() ) // good
         return to_cover.amount;
   }

} FC_CAPTURE_AND_RETHROW( (*this)(feed_price)(match_price)(maintenance_collateral_ratio) ) }

FC_REFLECT_DERIVED_NO_TYPENAME( graphene::chain::limit_order_object,
                    (graphene::db::object),
                    (expiration)(seller)(for_sale)(sell_price)(deferred_fee)(deferred_paid_fee)
                  )

FC_REFLECT_DERIVED_NO_TYPENAME( graphene::chain::call_order_object, (graphene::db::object),
                    (borrower)(collateral)(debt)(call_price)(target_collateral_ratio) )

FC_REFLECT_DERIVED_NO_TYPENAME( graphene::chain::force_settlement_object,
                    (graphene::db::object),
                    (owner)(balance)(settlement_date)
                  )

FC_REFLECT_DERIVED_NO_TYPENAME( graphene::chain::collateral_bid_object, (graphene::db::object),
                    (bidder)(inv_swan_price) )

GRAPHENE_IMPLEMENT_EXTERNAL_SERIALIZATION( graphene::chain::limit_order_object )
GRAPHENE_IMPLEMENT_EXTERNAL_SERIALIZATION( graphene::chain::call_order_object )
GRAPHENE_IMPLEMENT_EXTERNAL_SERIALIZATION( graphene::chain::force_settlement_object )
GRAPHENE_IMPLEMENT_EXTERNAL_SERIALIZATION( graphene::chain::collateral_bid_object )


/*
 * voxel_filter.cpp
 *
 *  Created on: 06.09.2013
 *      Author: goa
 */

#include <ros/ros.h>
#include <dynamic_reconfigure/server.h>
#include <ppfplane/voxel_filter_nodeConfig.h>
#include <pcl/point_types.h>
//#include <pcl/point_cloud.h>
#include <pcl_ros/point_cloud.h>

// includes
#include <iostream>
#include <fstream>
#include <string>
#include "definitions.h"
// libraries
#include <Eigen/Dense>
#include <opencv2/core/core.hpp>
#include <CLI/CLI.hpp>
// classes
#include "Timer.h"
#include "Plane.h"
#include "graph/PlaneGraph.h"
#include "graph/ParallelPlaneGraph.h"
#include "PPF/PairDetector.h"
// function includes
//#include "io/load_ply_cloud.h"
//#include "visualize/pcshow.h"

#include <pcl/ModelCoefficients.h>
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/filters/extract_indices.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/features/normal_3d.h>
#include <pcl/kdtree/kdtree.h>
#include <pcl/sample_consensus/method_types.h>
#include <pcl/sample_consensus/model_types.h>
#include <pcl/segmentation/sac_segmentation.h>
#include <pcl/segmentation/extract_clusters.h>
#include <pcl/filters/project_inliers.h>

// PCL specific includes
#include <sensor_msgs/PointCloud2.h>
#include <pcl_conversions/pcl_conversions.h>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <visualization_msgs/Marker.h>

#include <dynamic_reconfigure/server.h>
#include "std_msgs/String.h"

class LineDetectNode
{
public:
  typedef pcl::PointXYZRGB Point;
  typedef pcl::PointCloud<Point> PointCloud;

  LineDetectNode()
  {
    pub_ = nh_.advertise<sensor_msgs::PointCloud2>("/point_final",1);
    sub_ = nh_.subscribe ("/norm_out", 1,  &LineDetectNode::cloudCallback, this);
    config_server_.setCallback(boost::bind(&LineDetectNode::dynReconfCallback, this, _1, _2));
  }

  ~LineDetectNode() {}

  void
  dynReconfCallback(ppfplane::voxel_filter_nodeConfig &config, uint32_t level)
  {

  }

  void
  cloudCallback(const sensor_msgs::PointCloud2ConstPtr &cloud_msg)
  {
    pcl::PointCloud<pcl::PointNormal> cloud_Test;
    pcl::fromROSMsg(*cloud_msg, cloud_Test);

    pcl::PointCloud<pcl::PointNormal>::Ptr cloudPTR(new pcl::PointCloud<pcl::PointNormal>);
    *cloudPTR = cloud_Test;

    std::cout<<cloudPTR->size()<<"\n";
  }

private:
  ros::NodeHandle nh_;
  ros::Subscriber sub_;
  ros::Publisher pub_;
  dynamic_reconfigure::Server<ppfplane::voxel_filter_nodeConfig> config_server_;

};

int main (int argc, char** argv)
{
  ros::init (argc, argv, "voxel_filter_node");

  LineDetectNode vf;

  ros::spin();
}


#ifndef __RANGE_BASED_TUNNEL_LOC_HH__
#define __RANGE_BASED_TUNNEL_LOC_HH__

#include <cmath>
#include <vector>
#include <limits>
#include <numeric>
#include <iostream>
#include <Eigen/Dense>
#include <Eigen/Eigenvalues>
#include <pcl/point_types.h>
#include <pcl/octree/octree.h>
#include <pcl/registration/icp.h>
#include <sensor_msgs/LaserScan.h>
#include <sensor_msgs/PointCloud2.h>

#include <utils.hh>
#include <laser_proc.hh>

/*	This class provides pose estimate of the robot in a known environment.
	The class requires the map as point cloud, an initial estimate,
	and point cloud or scan data from sensors. There is no soft bound
	on the total number of sensors that can be integrated, however performance
	may degrade with excess amount of data. For aligning the sensor data
	with the map, 3DOF ICP is used with y-z-yaw being the free DOFs.
	It also provides an uncertainy measure defined as in Censi's ICRA 2009
	paper.

	This implementation is suitable for using with particle filters as well.
	The user is supposed to push sensor data once and with different initial
	poses carry the estimation. After each iteration pose, covariance and
	fitness of ICP can be fetched to vote for each particle in the wrapper
	class.
*/

// ### I should better assume orientation to be represented as quadternions
// and calculate uncertainty in that space. Also this will require me to
// return orientation in quat as well instead of dcm for the sake of
// consistancy.

// ### Be sure that IMU orientation is applied correctly to PC.

class RangeBasedTunnelLocalizer{
private:
	int _num_laser_pushes;	// Number of pushes since the last memory clean-up
	int _num_rgbd_pushes;	// (the same as above)
	pcl::PointCloud<pcl::PointXYZ>::Ptr _cloud;			// Collective pointcloud sensor data
	pcl::PointCloud<pcl::PointXYZ>::Ptr _cloud_aligned;	// '_pc' after being aligned
	pcl::octree::OctreePointCloudSearch<pcl::PointXYZ> *_octree;
	vector<pcl::PointXYZ> _matched_map_pts;
	Eigen::Matrix4d _pose;		// Pose of the robot (output of ICP registration given as homo. SE(3))
	Eigen::Matrix6d _fim;		// Fisher information matrix
	double _fitness_scores[3];	// average of large residuals (see the ### ??? function for detailed explanation)
	double _max_iters;			// maximum iterations of the ICP algorithm.
	double _yz_tol;				// translational tolerance value if updates of ICP is lower than which, iteration is stopped.
	double _yaw_tol;			// same as '_yz_tol' for yaw.
	// ### _skip_rays;			// number of rays to skip in ICP for performance improvement.

	bool _get_covariance(const sensor_msgs::LaserScan &data, Eigen::Matrix3d &cov);
	bool _get_covariance(const sensor_msgs::PointCloud2 &data, Eigen::Matrix6d &cov);

	// This function resets the internal flags, counters, clears the collvective
	// point cloud. This is called when 'push_X_data(...)' is called with 'reset' flag.
	bool _reset();
public:
	RangeBasedTunnelLocalizer(int max_iter = 33, double yz_tol = 0.01, double yaw_tol = 0.035);
	// ### Replace this with set_octree(...)
	// This function sets the internal map pointer. Changes in the referenced
	// map do reflect to the internal copy of the map pointer. Thus this function
	// call is of contant time complexity.
	bool set_map(const pcl::PointCloud<pcl::PointXYZ>::Ptr &map);
	// ### To be implemented.
	bool set_octree(const pcl::octree::OctreePointCloudSearch<pcl::PointXYZ> &octree_search);
	// This adds laser points to the collective sensor pointcloud.
	// 'rel_pose' is the pose of the laser scanner in the body frame
	// 'mask' is a char vector where '0' denotes that the corresponding
	// data should be negleceted. All data is used if sizes of 'ranges'
	// and 'mask' do not match. Otherwise only ranges where 'mask[i] ==
	// cluster_id' are processed. If 'clean_start' is set, '_reset()'
	// is called before every other operation.
	bool push_laser_data(const Eigen::Matrix4d &rel_pose, const sensor_msgs::LaserScan &data, const vector<char> &mask, char cluster_id, bool clean_start = false);
	bool push_laser_data(const LaserProc &data, bool clean_start = false);
	// This adds pointcloud, possibly from an rgbd sensor, to the
	// collvective sensor pointcloud. 'rel_pose' is the pose of
	// the RGBD sensor in the body frame. 'mask' is a char vector
	// where '0' denotes that the corresponding data should be
	// negleced. 'mask' should be indexed in row-major order. All data
	// is used if the sizes of 'data' and 'mask' do not match. Otherwise
	// only ranges where 'mask[i] == cluster_id' are processed.
	// If 'clean_start' is set, '_reset()' is called before every
	// other operation.
	bool push_rgbd_data(const Eigen::Matrix4d &rel_pose, const sensor_msgs::PointCloud2 &data, const vector<char> &mask, char cluster_id, bool clean_start = false);
	// This function runs the 3D ICP algorithm starting from the
	// given initial pose. 'get_pose', 'get_covariance' and
	// 'get_fitness_score' functions can be used to get the results.
	// In this implementation only y-z-yaw DOFs are updated. This
	// function s returns the number of iterations.
	int estimate_pose(const Eigen::Matrix4d &init_pose, double heading);
	// This function assumes that 'estimate_pose' function is called
	// beforehand. When properly called, it returns the pose in
	// world frame. Otherwise last pose residing from the most
	// recent estimate is returned.
	bool get_pose(Eigen::Matrix4d &pose);
	// This function, when it is called after the 'estimate_pose'
	// function, it returns the rigidly transforms the collective
	// pointcloud (obtained while running ICP) the estimated pose.
	// It does not have any effect on the execution of the estimation
	// process but provides material for visualization. ### If a rgbd
	// data is pushed and/or laser intensities are available, pointcloud
	// will include color information as well.
	bool get_registered_pointcloud(pcl::PointCloud<pcl::PointXYZ>::Ptr &pc);
	// This estimates the covariance of the measurement model
	// with Censi's method using the shape of the 3D point cloud.
	// Depending on the pushed data, either 2D method or a new 3D
	// method is used. See the related paper of Censi 2009 ICRA for
	// the former method. ### To be implemented ### If a 3D point
	// cloud is pushed, instead of lines, planes are used
	// in information gain of each ray. If 'apply_fitness_result = true'
	// covariance is modified to reflect the effect of '_fitness_scores'.
	// This always increases the covariance and gives are more
	// conservative estimate.
	bool get_covariance(Eigen::Matrix6d &cov, bool apply_fitness_result = false);
	// This function, independent of the covariance estimate,
	// gives a score of wellness of the fit. Higher values
	// mean a worse fit. For each direction residual vectors'
	// corresponding component is squared and accumulated.
	bool get_fitness_scores(double &y, double &z, double &yaw);
	// This function returns the sensor data map point correspondences.
	// Sensor points are at their transformed locations determined after
	// ICP. This function is intended for visualization purposes.
	bool get_correspondences(vector<pcl::PointXYZ> &sensor_pts, vector<pcl::PointXYZ> &map_pts);
};

#endif


/* Copyright (C) 2010-2019, The Regents of The University of Michigan.
 All rights reserved.

 This software was developed as part of the The Vulcan project in the Intelligent Robotics Lab
 under the direction of Benjamin Kuipers, kuipers@umich.edu. Use of this code is governed by an
 MIT-style License that can be found at "https://github.com/h2ssh/Vulcan".
*/

/**
 * \file     gl_color.cpp
 * \author   Collin Johnson
 *
 * Implementation of GLColor.
 */

#include "ui/common/ui_color.h"
#include <GL/gl.h>
#include <boost/algorithm/clamp.hpp>
#include <cstdint>
#include <cstdlib>

namespace vulcan
{
namespace ui
{

float extract_number(const std::string& colorString, std::size_t& startPos);

GLColor::GLColor(int red, int green, int blue, int alpha)
: red_(boost::algorithm::clamp(red, 0, 255) / 255.0f)
, green_(boost::algorithm::clamp(green, 0, 255) / 255.0f)
, blue_(boost::algorithm::clamp(blue, 0, 255) / 255.0f)
, alpha_(boost::algorithm::clamp(alpha, 0, 255) / 255.0f)
{
}

GLColor::GLColor(double red, double green, double blue, double alpha)
: red_(boost::algorithm::clamp(red, 0.0f, 1.0f))
, green_(boost::algorithm::clamp(green, 0.0f, 1.0f))
, blue_(boost::algorithm::clamp(blue, 0.0f, 1.0f))
, alpha_(boost::algorithm::clamp(alpha, 0.0f, 1.0f))
{
}

GLColor::GLColor(const std::string& colorString)
{
    std::size_t numberIndex = 0;

    red_ = extract_number(colorString, numberIndex);
    green_ = extract_number(colorString, numberIndex);
    blue_ = extract_number(colorString, numberIndex);
    alpha_ = extract_number(colorString, numberIndex);
}

void GLColor::set(float alphaScale) const
{
    alphaScale = boost::algorithm::clamp(alphaScale, 0.0f, 1.0f);
    glColor4f(red_, green_, blue_, alpha_ * alphaScale);
}

float extract_number(const std::string& colorString, size_t& startPos)
{
    const std::string numbers("0123456789");

    std::size_t numberStart = colorString.find_first_of(numbers, startPos);
    std::size_t numberEnd = colorString.find_first_not_of(numbers, numberStart);

    int number = 0;

    if (numberStart != numberEnd) {
        number = atoi(colorString.substr(numberStart, numberEnd - numberStart).c_str());
    }

    startPos = numberEnd;

    number = boost::algorithm::clamp(number, 0, 255);

    return static_cast<float>(number) / 255.0f;
}

}   // namespace ui
}   // namespace vulcan


#include "core/Initializer.h"
#include "core/Geometry.h"
#include "utils/dataprocess_utils.h"
#include "utils/matrix_utils.h"

#include <Eigen/Core>

#include "include/core/Viewer.h"
#include "include/core/MapDrawer.h"
#include "include/core/Map.h"

#include <thread>
#include <string>

#include "include/core/Ellipsoid.h"
#include "src/tum_rgbd/io.h"

#include <pcl/common/transforms.h>
#include <pcl/io/pcd_io.h>
typedef pcl::PointXYZRGB PointT;
typedef pcl::PointCloud<PointT> PointCloudPCL;

#include "src/config/Config.h"

using namespace std;
using namespace Eigen;

int main(int argc,char* argv[]) {

    if( argc != 3)
    {
        std::cout << "usage: " << argv[0] << " path_to_settings path_to_dataset" << std::endl;
        return 1;
    }
    string strSettingPath = string(argv[1]);
    string dataset_path(argv[2]);
    string strDetectionDir = dataset_path + "bbox/";

    std::cout << "- settings file: " << strSettingPath << std::endl;
    std::cout << "- dataset_path: " << dataset_path << std::endl;
    std::cout << "- strDetectionDir: " << strDetectionDir << std::endl;

    TUMRGBD::Dataset loader;
    loader.loadDataset(dataset_path);
    loader.loadDetectionDir(strDetectionDir);

    EllipsoidSLAM::System SLAM(strSettingPath, true);

    cv::Mat rgb,depth;
    VectorXd pose;
    while(!loader.empty())
    {
        bool valid = loader.readFrame(rgb,depth,pose);
        int current_id = loader.getCurrentID();

        Eigen::MatrixXd detMat = loader.getDetectionMat();
        double timestamp = loader.GetCurrentTimestamp();

        if(valid)
        {
            std::cout << "*****************************" << std::endl;
            std::cout << "Press [ENTER] to continue ... " << std::endl;
            std::cout << "*****************************" << std::endl;
            getchar();

            SLAM.TrackWithObjects(timestamp, pose, detMat, depth, rgb, true);        // Process frame.
            std::cout << std::endl;
        }

        std::cout << " -> " << loader.getCurrentID() << "/" << loader.getTotalNum() << std::endl;
    }

    std::cout << "Finished all data." << std::endl;

    // save objects
    string output_path("./objects.txt");
    SLAM.SaveObjectsToFile(output_path);
    SLAM.getTracker()->SaveObjectHistory("./object_history.txt");

    cout << "Use Ctrl+C to quit." << endl;
    while(1);

    cout << "End." << endl;
    return 0;
}


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

#include "ClContextControlFixture.hpp"
#include "ClWorkloadFactoryHelper.hpp"

#include "test/TensorHelpers.hpp"
#include "test/UnitTests.hpp"

#include <backendsCommon/CpuTensorHandle.hpp>
#include <cl/ClLayerSupport.hpp>
#include <cl/ClWorkloadFactory.hpp>
#include <cl/workloads/ClWorkloadUtils.hpp>
#include <reference/RefWorkloadFactory.hpp>
#include <backendsCommon/test/ActivationFixture.hpp>
#include <backendsCommon/test/LayerTests.hpp>

#include <arm_compute/core/CL/CLKernelLibrary.h>
#include <arm_compute/runtime/CL/CLScheduler.h>

#include <boost/test/unit_test.hpp>

#include <iostream>
#include <string>

BOOST_FIXTURE_TEST_SUITE(Compute_ArmComputeCl, ClContextControlFixture)
using FactoryType = armnn::ClWorkloadFactory;

// ============================================================================
// UNIT tests

// Activation
ARMNN_AUTO_TEST_CASE(ConstantLinearActivation, ConstantLinearActivationTest)

ARMNN_AUTO_TEST_CASE(ReLu1Uint8, BoundedReLuUint8UpperAndLowerBoundTest)
ARMNN_AUTO_TEST_CASE(ReLu6Uint8, BoundedReLuUint8UpperBoundOnlyTest)

ARMNN_AUTO_TEST_CASE(Logistic, SimpleSigmoidTest)
ARMNN_AUTO_TEST_CASE(LogisticUint8, SimpleSigmoidUint8Test)

// Batch To Space
ARMNN_AUTO_TEST_CASE(BatchToSpaceNdNhwcFloat321, BatchToSpaceNdNhwcFloat32Test1)
ARMNN_AUTO_TEST_CASE(BatchToSpaceNdNhwcFloat322, BatchToSpaceNdNhwcFloat32Test2)
ARMNN_AUTO_TEST_CASE(BatchToSpaceNdNhwcFloat323, BatchToSpaceNdNhwcFloat32Test3)

ARMNN_AUTO_TEST_CASE(BatchToSpaceNdNchwFloat321, BatchToSpaceNdNchwFloat32Test1)
ARMNN_AUTO_TEST_CASE(BatchToSpaceNdNchwFloat322, BatchToSpaceNdNchwFloat32Test2)
ARMNN_AUTO_TEST_CASE(BatchToSpaceNdNchwFloat323, BatchToSpaceNdNchwFloat32Test3)

ARMNN_AUTO_TEST_CASE(BatchToSpaceNdNhwcUint1, BatchToSpaceNdNhwcUintTest1)
ARMNN_AUTO_TEST_CASE(BatchToSpaceNdNhwcUint2, BatchToSpaceNdNhwcUintTest2)
ARMNN_AUTO_TEST_CASE(BatchToSpaceNdNhwcUint3, BatchToSpaceNdNhwcUintTest3)

ARMNN_AUTO_TEST_CASE(BatchToSpaceNdNchwUint1, BatchToSpaceNdNchwUintTest1)
ARMNN_AUTO_TEST_CASE(BatchToSpaceNdNchwUint2, BatchToSpaceNdNchwUintTest2)
ARMNN_AUTO_TEST_CASE(BatchToSpaceNdNchwUint3, BatchToSpaceNdNchwUintTest3)

// Fully Connected
ARMNN_AUTO_TEST_CASE(SimpleFullyConnected, FullyConnectedFloat32Test, false, false)
ARMNN_AUTO_TEST_CASE(SimpleFullyConnectedWithBias, FullyConnectedFloat32Test, true, false)
ARMNN_AUTO_TEST_CASE(SimpleFullyConnectedWithTranspose, FullyConnectedFloat32Test, false, true)
ARMNN_AUTO_TEST_CASE(FullyConnectedUint8, FullyConnectedUint8Test, false)
ARMNN_AUTO_TEST_CASE(FullyConnectedBiasedUint8, FullyConnectedUint8Test, true)

ARMNN_AUTO_TEST_CASE(FullyConnectedLarge, FullyConnectedLargeTest, false)
ARMNN_AUTO_TEST_CASE(FullyConnectedLargeTransposed, FullyConnectedLargeTest, true)

// Convolution
ARMNN_AUTO_TEST_CASE(SimpleConvolution1d, Convolution1dTest, true)

ARMNN_AUTO_TEST_CASE(SimpleConvolution2d, SimpleConvolution2d3x5Test, true, armnn::DataLayout::NCHW)
ARMNN_AUTO_TEST_CASE(SimpleConvolution2dNhwc, SimpleConvolution2d3x5Test, true, armnn::DataLayout::NHWC)
ARMNN_AUTO_TEST_CASE(SimpleConvolution2d3x3Uint8, SimpleConvolution2d3x3Uint8Test, true, armnn::DataLayout::NCHW)
ARMNN_AUTO_TEST_CASE(SimpleConvolution2d3x3Uint8Nhwc, SimpleConvolution2d3x3Uint8Test, true, armnn::DataLayout::NHWC)
ARMNN_AUTO_TEST_CASE(UnbiasedConvolution2d, SimpleConvolution2d3x5Test, false, armnn::DataLayout::NCHW)
ARMNN_AUTO_TEST_CASE(UnbiasedConvolution2dNhwc, SimpleConvolution2d3x5Test, false, armnn::DataLayout::NHWC)
ARMNN_AUTO_TEST_CASE(UnbiasedConvolution2dStride2x2Nhwc,
                     SimpleConvolution2d3x3Stride2x2Test, false, armnn::DataLayout::NHWC)

ARMNN_AUTO_TEST_CASE(UnbiasedConvolution2dSquare, SimpleConvolution2d3x3Test, false, armnn::DataLayout::NCHW)
ARMNN_AUTO_TEST_CASE(SimpleConvolution2dAsymmetricPadding, Convolution2dAsymmetricPaddingTest, armnn::DataLayout::NCHW)

ARMNN_AUTO_TEST_CASE(UnbiasedConvolution2dSquareNhwc, SimpleConvolution2d3x3Test, false, armnn::DataLayout::NHWC)
ARMNN_AUTO_TEST_CASE(SimpleConvolution2dAsymmetricPaddingNhwc,
                     Convolution2dAsymmetricPaddingTest,
                     armnn::DataLayout::NHWC)

ARMNN_AUTO_TEST_CASE(SimpleConvolution2dSquareNhwc, SimpleConvolution2d3x3NhwcTest, false)

// Depthwise Convolution
ARMNN_AUTO_TEST_CASE(DepthwiseConvolution2dDepthMul1,
                     DepthwiseConvolution2dDepthMul1Test, true, armnn::DataLayout::NCHW)
ARMNN_AUTO_TEST_CASE(UnbiasedDepthwiseConvolution2dDepthMul1,
                     DepthwiseConvolution2dDepthMul1Test, false, armnn::DataLayout::NCHW)
ARMNN_AUTO_TEST_CASE(DepthwiseConvolution2dDepthMul1Uint8,
                     DepthwiseConvolution2dDepthMul1Uint8Test, true, armnn::DataLayout::NCHW)
ARMNN_AUTO_TEST_CASE(UnbiasedDepthwiseConvolution2dDepthMul1Uint8,
                     DepthwiseConvolution2dDepthMul1Uint8Test, false, armnn::DataLayout::NCHW)

// NHWC Depthwise Convolution
ARMNN_AUTO_TEST_CASE(DepthwiseConvolution2dDepthMul1Nhwc,
                     DepthwiseConvolution2dDepthMul1Test, true, armnn::DataLayout::NHWC)
ARMNN_AUTO_TEST_CASE(UnbiasedDepthwiseConvolution2dDepthMul1Nhwc,
                     DepthwiseConvolution2dDepthMul1Test, false, armnn::DataLayout::NHWC)
ARMNN_AUTO_TEST_CASE(DepthwiseConvolution2dDepthMul1Uint8Nhwc,
                     DepthwiseConvolution2dDepthMul1Uint8Test, true, armnn::DataLayout::NHWC)
ARMNN_AUTO_TEST_CASE(UnbiasedDepthwiseConvolution2dDepthMul1Uint8Nhwc,
                     DepthwiseConvolution2dDepthMul1Uint8Test, false, armnn::DataLayout::NHWC)
ARMNN_AUTO_TEST_CASE(SimpleDepthwiseConvolution2d3x3Dilation3x3Nhwc,
                     SimpleDepthwiseConvolution2d3x3Dilation3x3NhwcTest)

ARMNN_AUTO_TEST_CASE(DepthwiseConvolution2dDepthNhwc, DepthwiseConvolution2dDepthNhwcTest, false)

ARMNN_AUTO_TEST_CASE(DepthwiseConvolution2dAsymmetric,
                     DepthwiseConvolution2dAsymmetricTest, true, armnn::DataLayout::NCHW)
ARMNN_AUTO_TEST_CASE(UnbiasedDepthwiseConvolution2dAsymmetric,
                     DepthwiseConvolution2dAsymmetricTest, false, armnn::DataLayout::NCHW)
ARMNN_AUTO_TEST_CASE(DepthwiseConvolution2dAsymmetricNhwc,
                     DepthwiseConvolution2dAsymmetricTest, true, armnn::DataLayout::NHWC)
ARMNN_AUTO_TEST_CASE(UnbiasedDepthwiseConvolution2dAsymmetricNhwc,
                     DepthwiseConvolution2dAsymmetricTest, false, armnn::DataLayout::NHWC)

// Splitter
ARMNN_AUTO_TEST_CASE(SimpleSplitter, SplitterTest)
ARMNN_AUTO_TEST_CASE(SimpleSplitterUint8, SplitterUint8Test)

ARMNN_AUTO_TEST_CASE(CopyViaSplitter, CopyViaSplitterTest)
ARMNN_AUTO_TEST_CASE(CopyViaSplitterUint8, CopyViaSplitterUint8Test)

// Concat
ARMNN_AUTO_TEST_CASE(SimpleConcat, ConcatTest)
ARMNN_AUTO_TEST_CASE(ConcatUint8, ConcatUint8Test)

// Normalization
ARMNN_AUTO_TEST_CASE(SimpleNormalizationAcross, SimpleNormalizationAcrossTest)
ARMNN_AUTO_TEST_CASE(SimpleNormalizationWithin, SimpleNormalizationWithinTest)
ARMNN_AUTO_TEST_CASE(SimpleNormalizationAcrossNhwc, SimpleNormalizationAcrossNhwcTest)

// Pooling
ARMNN_AUTO_TEST_CASE(SimpleMaxPooling2dSize3x3Stride2x4, SimpleMaxPooling2dSize3x3Stride2x4Test, true)
ARMNN_AUTO_TEST_CASE(SimpleMaxPooling2dSize3x3Stride2x4Uint8, SimpleMaxPooling2dSize3x3Stride2x4Uint8Test, true)

ARMNN_AUTO_TEST_CASE(IgnorePaddingSimpleMaxPooling2d, IgnorePaddingSimpleMaxPooling2dTest)
ARMNN_AUTO_TEST_CASE(IgnorePaddingSimpleMaxPooling2dUint8, IgnorePaddingSimpleMaxPooling2dUint8Test)
ARMNN_AUTO_TEST_CASE(IgnorePaddingMaxPooling2dSize3, IgnorePaddingMaxPooling2dSize3Test)
ARMNN_AUTO_TEST_CASE(IgnorePaddingMaxPooling2dSize3Uint8, IgnorePaddingMaxPooling2dSize3Uint8Test)

ARMNN_AUTO_TEST_CASE(IgnorePaddingSimpleAveragePooling2d, IgnorePaddingSimpleAveragePooling2dTest)
ARMNN_AUTO_TEST_CASE(IgnorePaddingSimpleAveragePooling2dUint8, IgnorePaddingSimpleAveragePooling2dUint8Test)
ARMNN_AUTO_TEST_CASE(IgnorePaddingSimpleAveragePooling2dNoPadding, IgnorePaddingSimpleAveragePooling2dNoPaddingTest)
ARMNN_AUTO_TEST_CASE(IgnorePaddingSimpleAveragePooling2dNoPaddingUint8,
                     IgnorePaddingSimpleAveragePooling2dNoPaddingUint8Test)
ARMNN_AUTO_TEST_CASE(IgnorePaddingAveragePooling2dSize3, IgnorePaddingAveragePooling2dSize3Test)
ARMNN_AUTO_TEST_CASE(IgnorePaddingAveragePooling2dSize3Uint8, IgnorePaddingAveragePooling2dSize3Uint8Test)

ARMNN_AUTO_TEST_CASE(IgnorePaddingSimpleL2Pooling2d, IgnorePaddingSimpleL2Pooling2dTest)
ARMNN_AUTO_TEST_CASE(UNSUPPORTED_IgnorePaddingSimpleL2Pooling2dUint8, IgnorePaddingSimpleL2Pooling2dUint8Test)
ARMNN_AUTO_TEST_CASE(IgnorePaddingL2Pooling2dSize3, IgnorePaddingL2Pooling2dSize3Test)
ARMNN_AUTO_TEST_CASE(UNSUPPORTED_IgnorePaddingL2Pooling2dSize3Uint8, IgnorePaddingL2Pooling2dSize3Uint8Test)

ARMNN_AUTO_TEST_CASE(SimpleMaxPooling2d, SimpleMaxPooling2dTest, armnn::DataLayout::NCHW)
ARMNN_AUTO_TEST_CASE(SimpleMaxPooling2dNhwc, SimpleMaxPooling2dTest, armnn::DataLayout::NHWC)
ARMNN_AUTO_TEST_CASE(SimpleMaxPooling2dUint8, SimpleMaxPooling2dUint8Test, armnn::DataLayout::NCHW)
ARMNN_AUTO_TEST_CASE(SimpleMaxPooling2dUint8Nhwc, SimpleMaxPooling2dUint8Test, armnn::DataLayout::NHWC)

ARMNN_AUTO_TEST_CASE(SimpleAveragePooling2d, SimpleAveragePooling2dTest, armnn::DataLayout::NCHW)
ARMNN_AUTO_TEST_CASE(SimpleAveragePooling2dNhwc, SimpleAveragePooling2dTest, armnn::DataLayout::NHWC)
ARMNN_AUTO_TEST_CASE(SimpleAveragePooling2dUint8, SimpleAveragePooling2dUint8Test, armnn::DataLayout::NCHW)
ARMNN_AUTO_TEST_CASE(SimpleAveragePooling2dUint8Nhwc, SimpleAveragePooling2dUint8Test, armnn::DataLayout::NHWC)

ARMNN_AUTO_TEST_CASE(IgnorePaddingAveragePooling2dSize3x2Stride2x2,
                     IgnorePaddingAveragePooling2dSize3x2Stride2x2Test,
                     false)
ARMNN_AUTO_TEST_CASE(IgnorePaddingAveragePooling2dSize3x2Stride2x2NoPadding,
                     IgnorePaddingAveragePooling2dSize3x2Stride2x2Test,
                     true)
ARMNN_AUTO_TEST_CASE(LargeTensorsAveragePooling2d, LargeTensorsAveragePooling2dTest)
ARMNN_AUTO_TEST_CASE(LargeTensorsAveragePooling2dUint8, LargeTensorsAveragePooling2dUint8Test)

ARMNN_AUTO_TEST_CASE(SimpleL2Pooling2d, SimpleL2Pooling2dTest, armnn::DataLayout::NCHW)
ARMNN_AUTO_TEST_CASE(SimpleL2Pooling2dNhwc, SimpleL2Pooling2dTest, armnn::DataLayout::NHWC)
ARMNN_AUTO_TEST_CASE(UNSUPPORTED_SimpleL2Pooling2dUint8, SimpleL2Pooling2dUint8Test, armnn::DataLayout::NCHW)

ARMNN_AUTO_TEST_CASE(L2Pooling2dSize3Stride1, L2Pooling2dSize3Stride1Test)
ARMNN_AUTO_TEST_CASE(UNSUPPORTED_L2Pooling2dSize3Stride1Uint8, L2Pooling2dSize3Stride1Uint8Test)
ARMNN_AUTO_TEST_CASE(L2Pooling2dSize3Stride3, L2Pooling2dSize3Stride3Test)
ARMNN_AUTO_TEST_CASE(UNSUPPORTED_L2Pooling2dSize3Stride3Uint8, L2Pooling2dSize3Stride3Uint8Test)
ARMNN_AUTO_TEST_CASE(L2Pooling2dSize3Stride4, L2Pooling2dSize3Stride4Test)
ARMNN_AUTO_TEST_CASE(UNSUPPORTED_L2Pooling2dSize3Stride4Uint8, L2Pooling2dSize3Stride4Uint8Test)
ARMNN_AUTO_TEST_CASE(L2Pooling2dSize7, L2Pooling2dSize7Test)
ARMNN_AUTO_TEST_CASE(UNSUPPORTED_L2Pooling2dSize7Uint8, L2Pooling2dSize7Uint8Test)
ARMNN_AUTO_TEST_CASE(L2Pooling2dSize9, L2Pooling2dSize9Test)
ARMNN_AUTO_TEST_CASE(UNSUPPORTED_L2Pooling2dSize9Uint8, L2Pooling2dSize9Uint8Test)

// Add
ARMNN_AUTO_TEST_CASE(SimpleAdd, AdditionTest)
ARMNN_AUTO_TEST_CASE(AddBroadcast1Element, AdditionBroadcast1ElementTest)
ARMNN_AUTO_TEST_CASE(AddBroadcast, AdditionBroadcastTest)

ARMNN_AUTO_TEST_CASE(AdditionUint8, AdditionUint8Test)
ARMNN_AUTO_TEST_CASE(AddBroadcastUint8, AdditionBroadcastUint8Test)
ARMNN_AUTO_TEST_CASE(AddBroadcast1ElementUint8, AdditionBroadcast1ElementUint8Test)

// Sub
ARMNN_AUTO_TEST_CASE(SimpleSub, SubtractionTest)
ARMNN_AUTO_TEST_CASE(SubBroadcast1Element, SubtractionBroadcast1ElementTest)
ARMNN_AUTO_TEST_CASE(SubBroadcast, SubtractionBroadcastTest)

ARMNN_AUTO_TEST_CASE(SubtractionUint8, SubtractionUint8Test)
ARMNN_AUTO_TEST_CASE(SubBroadcastUint8, SubtractionBroadcastUint8Test)
ARMNN_AUTO_TEST_CASE(SubBroadcast1ElementUint8, SubtractionBroadcast1ElementUint8Test)

// Div
ARMNN_AUTO_TEST_CASE(SimpleDivision, DivisionTest)
ARMNN_AUTO_TEST_CASE(DivisionByZero, DivisionByZeroTest)
ARMNN_AUTO_TEST_CASE(DivisionBroadcast1Element, DivisionBroadcast1ElementTest)
ARMNN_AUTO_TEST_CASE(DivisionBroadcast1DVector, DivisionBroadcast1DVectorTest)
// NOTE: quantized division is not supported by CL and not required by the
//       android NN api

// Mul
ARMNN_AUTO_TEST_CASE(SimpleMultiplication, MultiplicationTest)
ARMNN_AUTO_TEST_CASE(MultiplicationBroadcast1Element, MultiplicationBroadcast1ElementTest)
ARMNN_AUTO_TEST_CASE(MultiplicationBroadcast1DVector, MultiplicationBroadcast1DVectorTest)
ARMNN_AUTO_TEST_CASE(MultiplicationUint8, MultiplicationUint8Test)
ARMNN_AUTO_TEST_CASE(MultiplicationBroadcast1ElementUint8, MultiplicationBroadcast1ElementUint8Test)
ARMNN_AUTO_TEST_CASE(MultiplicationBroadcast1DVectorUint8, MultiplicationBroadcast1DVectorUint8Test)

// Batch Norm
ARMNN_AUTO_TEST_CASE(BatchNorm, BatchNormTest)
ARMNN_AUTO_TEST_CASE(BatchNormNhwc, BatchNormNhwcTest)

// L2 Normalization
ARMNN_AUTO_TEST_CASE(L2Normalization1d, L2Normalization1dTest, armnn::DataLayout::NCHW)
ARMNN_AUTO_TEST_CASE(L2Normalization2d, L2Normalization2dTest, armnn::DataLayout::NCHW)
ARMNN_AUTO_TEST_CASE(L2Normalization3d, L2Normalization3dTest, armnn::DataLayout::NCHW)
ARMNN_AUTO_TEST_CASE(L2Normalization4d, L2Normalization4dTest, armnn::DataLayout::NCHW)

ARMNN_AUTO_TEST_CASE(L2Normalization1dNhwc, L2Normalization1dTest, armnn::DataLayout::NHWC)
ARMNN_AUTO_TEST_CASE(L2Normalization2dNhwc, L2Normalization2dTest, armnn::DataLayout::NHWC)
ARMNN_AUTO_TEST_CASE(L2Normalization3dNhwc, L2Normalization3dTest, armnn::DataLayout::NHWC)
ARMNN_AUTO_TEST_CASE(L2Normalization4dNhwc, L2Normalization4dTest, armnn::DataLayout::NHWC)

// Resize Bilinear - NCHW data layout
ARMNN_AUTO_TEST_CASE(ResizeBilinearNop, ResizeBilinearNopTest, armnn::DataLayout::NCHW)
ARMNN_AUTO_TEST_CASE(SimpleResizeBilinear, SimpleResizeBilinearTest, armnn::DataLayout::NCHW)
ARMNN_AUTO_TEST_CASE(ResizeBilinearSqMin, ResizeBilinearSqMinTest, armnn::DataLayout::NCHW)
ARMNN_AUTO_TEST_CASE(ResizeBilinearMin, ResizeBilinearMinTest, armnn::DataLayout::NCHW)
ARMNN_AUTO_TEST_CASE(ResizeBilinearMag, ResizeBilinearMagTest, armnn::DataLayout::NCHW)

// Resize Bilinear - NHWC data layout
ARMNN_AUTO_TEST_CASE(ResizeBilinearNopNhwc, ResizeBilinearNopTest, armnn::DataLayout::NHWC)
ARMNN_AUTO_TEST_CASE(SimpleResizeBilinearNhwc, SimpleResizeBilinearTest, armnn::DataLayout::NHWC)
ARMNN_AUTO_TEST_CASE(ResizeBilinearSqMinNhwc, ResizeBilinearSqMinTest, armnn::DataLayout::NHWC)
ARMNN_AUTO_TEST_CASE(ResizeBilinearMinNhwc, ResizeBilinearMinTest, armnn::DataLayout::NHWC)
ARMNN_AUTO_TEST_CASE(ResizeBilinearMagNhwc, ResizeBilinearMagTest, armnn::DataLayout::NHWC)

// Constant
ARMNN_AUTO_TEST_CASE(Constant, ConstantTest)
ARMNN_AUTO_TEST_CASE(ConstantUint8, ConstantUint8SimpleQuantizationScaleNoOffsetTest)

// Concat
ARMNN_AUTO_TEST_CASE(Concatenation1d, Concatenation1dTest)
ARMNN_AUTO_TEST_CASE(Concatenation1dUint8, Concatenation1dUint8Test)

ARMNN_AUTO_TEST_CASE(Concatenation2dDim0, Concatenation2dDim0Test)
ARMNN_AUTO_TEST_CASE(Concatenation2dDim0Uint8, Concatenation2dDim0Uint8Test)
ARMNN_AUTO_TEST_CASE(Concatenation2dDim1, Concatenation2dDim1Test)
ARMNN_AUTO_TEST_CASE(Concatenation2dDim1Uint8, Concatenation2dDim1Uint8Test)

ARMNN_AUTO_TEST_CASE(Concatenation2dDim0DiffInputDims, Concatenation2dDim0DiffInputDimsTest)
ARMNN_AUTO_TEST_CASE(Concatenation2dDim0DiffInputDimsUint8, Concatenation2dDim0DiffInputDimsUint8Test)
ARMNN_AUTO_TEST_CASE(Concatenation2dDim1DiffInputDims, Concatenation2dDim1DiffInputDimsTest)
ARMNN_AUTO_TEST_CASE(Concatenation2dDim1DiffInputDimsUint8, Concatenation2dDim1DiffInputDimsUint8Test)

ARMNN_AUTO_TEST_CASE(Concatenation3dDim0, Concatenation3dDim0Test)
ARMNN_AUTO_TEST_CASE(Concatenation3dDim0Uint8, Concatenation3dDim0Uint8Test)
ARMNN_AUTO_TEST_CASE(Concatenation3dDim1, Concatenation3dDim1Test)
ARMNN_AUTO_TEST_CASE(Concatenation3dDim1Uint8, Concatenation3dDim1Uint8Test)
ARMNN_AUTO_TEST_CASE(Concatenation3dDim2, Concatenation3dDim2Test, false)
ARMNN_AUTO_TEST_CASE(Concatenation3dDim2Uint8, Concatenation3dDim2Uint8Test, false)

ARMNN_AUTO_TEST_CASE(Concatenation3dDim0DiffInputDims, Concatenation3dDim0DiffInputDimsTest)
ARMNN_AUTO_TEST_CASE(Concatenation3dDim0DiffInputDimsUint8, Concatenation3dDim0DiffInputDimsUint8Test)
ARMNN_AUTO_TEST_CASE(Concatenation3dDim1DiffInputDims, Concatenation3dDim1DiffInputDimsTest)
ARMNN_AUTO_TEST_CASE(Concatenation3dDim1DiffInputDimsUint8, Concatenation3dDim1DiffInputDimsUint8Test)
ARMNN_AUTO_TEST_CASE(Concatenation3dDim2DiffInputDims, Concatenation3dDim2DiffInputDimsTest, false)
ARMNN_AUTO_TEST_CASE(Concatenation3dDim2DiffInputDimsUint8, Concatenation3dDim2DiffInputDimsUint8Test, false)

ARMNN_AUTO_TEST_CASE(Concatenation4dDim0, Concatenation4dDim0Test)
ARMNN_AUTO_TEST_CASE(Concatenation4dDim1, Concatenation4dDim1Test)
ARMNN_AUTO_TEST_CASE(Concatenation4dDim3, Concatenation4dDim3Test, false)
ARMNN_AUTO_TEST_CASE(Concatenation4dDim0Uint8, Concatenation4dDim0Uint8Test)
ARMNN_AUTO_TEST_CASE(Concatenation4dDim1Uint8, Concatenation4dDim1Uint8Test)
ARMNN_AUTO_TEST_CASE(Concatenation4dDim3Uint8, Concatenation4dDim3Uint8Test, false)

ARMNN_AUTO_TEST_CASE(Concatenation4dDiffShapeDim0, Concatenation4dDiffShapeDim0Test)
ARMNN_AUTO_TEST_CASE(Concatenation4dDiffShapeDim1, Concatenation4dDiffShapeDim1Test)
ARMNN_AUTO_TEST_CASE(Concatenation4dDiffShapeDim3, Concatenation4dDiffShapeDim3Test, false)
ARMNN_AUTO_TEST_CASE(Concatenation4dDiffShapeDim0Uint8, Concatenation4dDiffShapeDim0Uint8Test)
ARMNN_AUTO_TEST_CASE(Concatenation4dDiffShapeDim1Uint8, Concatenation4dDiffShapeDim1Uint8Test)
ARMNN_AUTO_TEST_CASE(Concatenation4dDiffShapeDim3Uint8, Concatenation4dDiffShapeDim3Uint8Test, false)

// Floor
ARMNN_AUTO_TEST_CASE(SimpleFloor, SimpleFloorTest)

// Reshape
ARMNN_AUTO_TEST_CASE(SimpleReshapeFloat32, SimpleReshapeFloat32Test)
ARMNN_AUTO_TEST_CASE(SimpleReshapeUint8, SimpleReshapeUint8Test)

// Pad
ARMNN_AUTO_TEST_CASE(PadFloat322d, PadFloat322dTest)
ARMNN_AUTO_TEST_CASE(PadFloat323d, PadFloat323dTest)
ARMNN_AUTO_TEST_CASE(PadFloat324d, PadFloat324dTest)

// Permute
ARMNN_AUTO_TEST_CASE(SimplePermuteFloat32, SimplePermuteFloat32Test)
ARMNN_AUTO_TEST_CASE(SimplePermuteUint8, SimplePermuteUint8Test)
ARMNN_AUTO_TEST_CASE(PermuteFloat32ValueSet1, PermuteFloat32ValueSet1Test)
ARMNN_AUTO_TEST_CASE(PermuteFloat32ValueSet2, PermuteFloat32ValueSet2Test)
ARMNN_AUTO_TEST_CASE(PermuteFloat32ValueSet3, PermuteFloat32ValueSet3Test)

// Lstm
ARMNN_AUTO_TEST_CASE(LstmLayerFloat32WithCifgWithPeepholeNoProjection,
                     LstmLayerFloat32WithCifgWithPeepholeNoProjectionTest)
ARMNN_AUTO_TEST_CASE(LstmLayerFloat32NoCifgNoPeepholeNoProjection,
                     LstmLayerFloat32NoCifgNoPeepholeNoProjectionTest)
ARMNN_AUTO_TEST_CASE(LstmLayerFloat32NoCifgWithPeepholeWithProjection,
                     LstmLayerFloat32NoCifgWithPeepholeWithProjectionTest)

// Convert from Float16 to Float32
ARMNN_AUTO_TEST_CASE(SimpleConvertFp16ToFp32, SimpleConvertFp16ToFp32Test)
// Convert from Float32 to Float16
ARMNN_AUTO_TEST_CASE(SimpleConvertFp32ToFp16, SimpleConvertFp32ToFp16Test)

ARMNN_AUTO_TEST_CASE(AdditionAfterMaxPool, AdditionAfterMaxPoolTest)

//Max
ARMNN_AUTO_TEST_CASE(MaximumSimple, MaximumSimpleTest)
ARMNN_AUTO_TEST_CASE(MaximumBroadcast1Element, MaximumBroadcast1ElementTest)
ARMNN_AUTO_TEST_CASE(MaximumBroadcast1DVector, MaximumBroadcast1DVectorTest)
ARMNN_AUTO_TEST_CASE(MaximumUint8, MaximumUint8Test)
ARMNN_AUTO_TEST_CASE(MaximumBroadcast1ElementUint8, MaximumBroadcast1ElementUint8Test)
ARMNN_AUTO_TEST_CASE(MaximumBroadcast1DVectorUint8, MaximumBroadcast1DVectorUint8Test)

// Mean
ARMNN_AUTO_TEST_CASE(MeanUint8Simple, MeanUint8SimpleTest)
ARMNN_AUTO_TEST_CASE(MeanUint8SimpleAxis, MeanUint8SimpleAxisTest)
ARMNN_AUTO_TEST_CASE(MeanUint8KeepDims, MeanUint8KeepDimsTest)
ARMNN_AUTO_TEST_CASE(MeanUint8MultipleDims, MeanUint8MultipleDimsTest)
ARMNN_AUTO_TEST_CASE(MeanVtsUint8, MeanVtsUint8Test)

ARMNN_AUTO_TEST_CASE(MeanFloatSimple, MeanFloatSimpleTest)
ARMNN_AUTO_TEST_CASE(MeanFloatSimpleAxis, MeanFloatSimpleAxisTest)
ARMNN_AUTO_TEST_CASE(MeanFloatKeepDims, MeanFloatKeepDimsTest)
ARMNN_AUTO_TEST_CASE(MeanFloatMultipleDims, MeanFloatMultipleDimsTest)
ARMNN_AUTO_TEST_CASE(MeanVtsFloat1, MeanVtsFloat1Test)
ARMNN_AUTO_TEST_CASE(MeanVtsFloat2, MeanVtsFloat2Test)
ARMNN_AUTO_TEST_CASE(MeanVtsFloat3, MeanVtsFloat3Test)

// Minimum
ARMNN_AUTO_TEST_CASE(MinimumBroadcast1Element1, MinimumBroadcast1ElementTest1)
ARMNN_AUTO_TEST_CASE(MinimumBroadcast1Element2, MinimumBroadcast1ElementTest2)
ARMNN_AUTO_TEST_CASE(MinimumBroadcast1DVectorUint8, MinimumBroadcast1DVectorUint8Test)

// Greater
ARMNN_AUTO_TEST_CASE(SimpleGreater, GreaterSimpleTest)
ARMNN_AUTO_TEST_CASE(GreaterBroadcast1Element, GreaterBroadcast1ElementTest)
ARMNN_AUTO_TEST_CASE(GreaterBroadcast1DVector, GreaterBroadcast1DVectorTest)
ARMNN_AUTO_TEST_CASE(GreaterUint8, GreaterUint8Test)
ARMNN_AUTO_TEST_CASE(GreaterBroadcast1ElementUint8, GreaterBroadcast1ElementUint8Test)
ARMNN_AUTO_TEST_CASE(GreaterBroadcast1DVectorUint8, GreaterBroadcast1DVectorUint8Test)

// Softmax
ARMNN_AUTO_TEST_CASE(SimpleSoftmaxBeta1, SimpleSoftmaxTest, 1.0f)
ARMNN_AUTO_TEST_CASE(SimpleSoftmaxBeta2, SimpleSoftmaxTest, 2.0f)
ARMNN_AUTO_TEST_CASE(SimpleSoftmaxBeta1Uint8, SimpleSoftmaxUint8Test, 1.0f)
ARMNN_AUTO_TEST_CASE(SimpleSoftmaxBeta2Uint8, SimpleSoftmaxUint8Test, 2.0f)

ARMNN_AUTO_TEST_CASE(Simple3dSoftmax, Simple3dSoftmaxTest, 1.0f)
ARMNN_AUTO_TEST_CASE(Simple3dSoftmaxUint8, Simple3dSoftmaxUint8Test, 1.0f)

ARMNN_AUTO_TEST_CASE(Simple4dSoftmax, Simple4dSoftmaxTest, 1.0f)
ARMNN_AUTO_TEST_CASE(Simple4dSoftmaxUint8, Simple4dSoftmaxUint8Test, 1.0f)

ARMNN_COMPARE_REF_AUTO_TEST_CASE(CompareSoftmaxBeta1WithReference, CompareSoftmaxTest, 1.0f)
ARMNN_COMPARE_REF_AUTO_TEST_CASE(CompareSoftmaxBeta2WithReference, CompareSoftmaxTest, 2.0f)
ARMNN_COMPARE_REF_AUTO_TEST_CASE(CompareSoftmaxUint8, CompareSoftmaxUint8Test, 1.0f)

// Space To Batch Nd
ARMNN_AUTO_TEST_CASE(SpaceToBatchNdSimpleFloat32, SpaceToBatchNdSimpleFloat32Test)
ARMNN_AUTO_TEST_CASE(SpaceToBatchNdMultiChannelsFloat32, SpaceToBatchNdMultiChannelsFloat32Test)
ARMNN_AUTO_TEST_CASE(SpaceToBatchNdMultiBlockFloat32, SpaceToBatchNdMultiBlockFloat32Test)
ARMNN_AUTO_TEST_CASE(SpaceToBatchNdPaddingFloat32, SpaceToBatchNdPaddingFloat32Test)

ARMNN_AUTO_TEST_CASE(SpaceToBatchNdSimpleUint8, SpaceToBatchNdSimpleUint8Test)
ARMNN_AUTO_TEST_CASE(SpaceToBatchNdMultiChannelsUint8, SpaceToBatchNdMultiChannelsUint8Test)
ARMNN_AUTO_TEST_CASE(SpaceToBatchNdMultiBlockUint8, SpaceToBatchNdMultiBlockUint8Test)
ARMNN_AUTO_TEST_CASE(SpaceToBatchNdPaddingUint8, SpaceToBatchNdPaddingUint8Test)

ARMNN_AUTO_TEST_CASE(SpaceToBatchNdSimpleNHWCFloat32, SpaceToBatchNdSimpleNHWCFloat32Test)
ARMNN_AUTO_TEST_CASE(SpaceToBatchNdMultiChannelsNHWCFloat32, SpaceToBatchNdMultiChannelsNHWCFloat32Test)
ARMNN_AUTO_TEST_CASE(SpaceToBatchNdMultiBlockNHWCFloat32, SpaceToBatchNdMultiBlockNHWCFloat32Test)
ARMNN_AUTO_TEST_CASE(SpaceToBatchNdPaddingNHWCFloat32, SpaceToBatchNdPaddingNHWCFloat32Test)

ARMNN_AUTO_TEST_CASE(SpaceToBatchNdSimpleNHWCUint8, SpaceToBatchNdSimpleNHWCUint8Test)
ARMNN_AUTO_TEST_CASE(SpaceToBatchNdMultiChannelsNHWCUint8, SpaceToBatchNdMultiChannelsNHWCUint8Test)
ARMNN_AUTO_TEST_CASE(SpaceToBatchNdMultiBlockNHWCUint8, SpaceToBatchNdMultiBlockNHWCUint8Test)
ARMNN_AUTO_TEST_CASE(SpaceToBatchNdPaddingNHWCUint8, SpaceToBatchNdPaddingNHWCUint8Test)

// Strided Slice
ARMNN_AUTO_TEST_CASE(StridedSlice4DFloat32, StridedSlice4DFloat32Test)
ARMNN_AUTO_TEST_CASE(StridedSlice4DReverseFloat32, StridedSlice4DReverseFloat32Test)
ARMNN_AUTO_TEST_CASE(StridedSliceSimpleStrideFloat32, StridedSliceSimpleStrideFloat32Test)
ARMNN_AUTO_TEST_CASE(StridedSliceSimpleRangeMaskFloat32, StridedSliceSimpleRangeMaskFloat32Test)
ARMNN_AUTO_TEST_CASE(StridedSliceShrinkAxisMaskFloat32, StridedSliceShrinkAxisMaskFloat32Test)
ARMNN_AUTO_TEST_CASE(StridedSlice3DFloat32, StridedSlice3DFloat32Test)
ARMNN_AUTO_TEST_CASE(StridedSlice3DReverseFloat32, StridedSlice3DReverseFloat32Test)
ARMNN_AUTO_TEST_CASE(StridedSlice2DFloat32, StridedSlice2DFloat32Test)
ARMNN_AUTO_TEST_CASE(StridedSlice2DReverseFloat32, StridedSlice2DReverseFloat32Test)

ARMNN_AUTO_TEST_CASE(StridedSlice4DUint8, StridedSlice4DUint8Test)
ARMNN_AUTO_TEST_CASE(StridedSlice4DReverseUint8, StridedSlice4DReverseUint8Test)
ARMNN_AUTO_TEST_CASE(StridedSliceSimpleStrideUint8, StridedSliceSimpleStrideUint8Test)
ARMNN_AUTO_TEST_CASE(StridedSliceSimpleRangeMaskUint8, StridedSliceSimpleRangeMaskUint8Test)
ARMNN_AUTO_TEST_CASE(StridedSliceShrinkAxisMaskUint8, StridedSliceShrinkAxisMaskUint8Test)
ARMNN_AUTO_TEST_CASE(StridedSlice3DUint8, StridedSlice3DUint8Test)
ARMNN_AUTO_TEST_CASE(StridedSlice3DReverseUint8, StridedSlice3DReverseUint8Test)
ARMNN_AUTO_TEST_CASE(StridedSlice2DUint8, StridedSlice2DUint8Test)
ARMNN_AUTO_TEST_CASE(StridedSlice2DReverseUint8, StridedSlice2DReverseUint8Test)

// ============================================================================
// COMPARE tests

ARMNN_COMPARE_REF_AUTO_TEST_CASE(CompareConv2dWithReference, CompareConvolution2dTest)

ARMNN_COMPARE_REF_AUTO_TEST_CASE(CompareDepthwiseConv2dWithReferenceFloat32,
                                 CompareDepthwiseConvolution2dFloatTest,
                                 armnn::DataLayout::NCHW)
ARMNN_COMPARE_REF_AUTO_TEST_CASE(CompareDepthwiseConv2dWithReferenceUint8,
                                 CompareDepthwiseConvolution2dUint8Test,
                                 armnn::DataLayout::NCHW)

ARMNN_COMPARE_REF_AUTO_TEST_CASE(CompareDepthwiseConv2dWithReferenceFloat32Nhwc,
                                 CompareDepthwiseConvolution2dFloatTest,
                                 armnn::DataLayout::NHWC)
ARMNN_COMPARE_REF_AUTO_TEST_CASE(CompareDepthwiseConv2dWithReferenceUint8Nhwc,
                                 CompareDepthwiseConvolution2dUint8Test,
                                 armnn::DataLayout::NHWC)

ARMNN_COMPARE_REF_AUTO_TEST_CASE(CompareNormalizationWithinWithReference, CompareNormalizationTest,
                                 armnn::NormalizationAlgorithmChannel::Within,
                                 armnn::NormalizationAlgorithmMethod::LocalBrightness)
ARMNN_COMPARE_REF_AUTO_TEST_CASE(CompareNormalizationAcrossWithReference, CompareNormalizationTest,
                                 armnn::NormalizationAlgorithmChannel::Across,
                                 armnn::NormalizationAlgorithmMethod::LocalBrightness)

ARMNN_COMPARE_REF_AUTO_TEST_CASE(CompareMaxPooling2dWithRef, ComparePooling2dTest, armnn::PoolingAlgorithm::Max)

ARMNN_COMPARE_REF_AUTO_TEST_CASE(CompareAveragePooling2dWithRef, ComparePooling2dTest, armnn::PoolingAlgorithm::Average)
ARMNN_COMPARE_REF_AUTO_TEST_CASE(CompareAveragePooling2dWithRefUint8, ComparePooling2dUint8Test,
                                 armnn::PoolingAlgorithm::Average)

ARMNN_COMPARE_REF_AUTO_TEST_CASE(CompareL2Pooling2dWithRef, ComparePooling2dTest, armnn::PoolingAlgorithm::L2)

ARMNN_COMPARE_REF_AUTO_TEST_CASE(CompareAddition, CompareAdditionTest)

ARMNN_COMPARE_REF_AUTO_TEST_CASE(CompareMultiplicationWithRef, CompareMultiplicationTest)

ARMNN_COMPARE_REF_AUTO_TEST_CASE(CompareBatchNorm, CompareBatchNormTest)

ARMNN_COMPARE_REF_AUTO_TEST_CASE(CompareReLu1, CompareBoundedReLuTest, 1.0f, -1.0f)
ARMNN_COMPARE_REF_AUTO_TEST_CASE(CompareReLu6, CompareBoundedReLuTest, 6.0f, 0.0f)

// ============================================================================
// FIXTURE tests

ARMNN_COMPARE_REF_FIXTURE_TEST_CASE(CompareSigmoidActivationWithReference, ActivationFixture,
                                    CompareActivationTest, armnn::ActivationFunction::Sigmoid, 5u)

ARMNN_COMPARE_REF_FIXTURE_TEST_CASE(CompareTanhActivationWithReference, ActivationFixture,
                                    CompareActivationTest, armnn::ActivationFunction::TanH, 5u)

ARMNN_COMPARE_REF_FIXTURE_TEST_CASE(CompareLinearActivationWithReference, ActivationFixture,
                                    CompareActivationTest, armnn::ActivationFunction::Linear, 5u)

ARMNN_COMPARE_REF_FIXTURE_TEST_CASE(CompareReLuActivationWithReference, ActivationFixture,
                                    CompareActivationTest, armnn::ActivationFunction::ReLu, 5u)

ARMNN_COMPARE_REF_FIXTURE_TEST_CASE(CompareBoundedReLuActivationWithReference, ActivationFixture,
                                    CompareActivationTest, armnn::ActivationFunction::BoundedReLu, 5u)
ARMNN_COMPARE_REF_FIXTURE_TEST_CASE(CompareBoundedReLuActivationWithReferenceUint8, ActivationFixture,
                                    CompareActivationUint8Test, armnn::ActivationFunction::BoundedReLu)

ARMNN_COMPARE_REF_FIXTURE_TEST_CASE(CompareSoftReLuActivationWithReference, ActivationFixture,
                                    CompareActivationTest, armnn::ActivationFunction::SoftReLu, 5u)

ARMNN_COMPARE_REF_FIXTURE_TEST_CASE(CompareLeakyReLuActivationWithReference, ActivationFixture,
                                    CompareActivationTest, armnn::ActivationFunction::LeakyReLu, 5u)

ARMNN_COMPARE_REF_FIXTURE_TEST_CASE(CompareAbsActivationWithReference, ActivationFixture,
                                    CompareActivationTest, armnn::ActivationFunction::Abs, 5u)

ARMNN_COMPARE_REF_FIXTURE_TEST_CASE(CompareSqrtActivationWithReference, PositiveActivationFixture,
                                    CompareActivationTest, armnn::ActivationFunction::Sqrt, 5u)

ARMNN_COMPARE_REF_FIXTURE_TEST_CASE(CompareSquareActivationWithReference, ActivationFixture,
                                    CompareActivationTest, armnn::ActivationFunction::Square, 5u)

BOOST_AUTO_TEST_SUITE_END()


//
//   Project Name:        Kratos
//   Last modified by:    $Author: nagel $
//   Date:                $Date: 2009-01-12 08:17:36 $
//   Revision:            $Revision: 1.10 $
//
//

// System includes

// External includes
#include <boost/python.hpp>

// Project includes
#include "includes/define.h"
#include "custom_python/add_constitutive_laws_to_python.h"

#include "includes/node.h"
#include "includes/variables.h"
#include "includes/mesh.h"
#include "includes/condition.h"
#include "python/pointer_vector_set_python_interface.h"
#include "python/variable_indexing_python.h"

//constitutive laws
#include "includes/constitutive_law.h"
#include "constitutive_laws/umat.h"

namespace Kratos
{

namespace Python
{

using namespace boost::python;

typedef ConstitutiveLaw ConstitutiveLawBaseType;
typedef Mesh<Node<3>, Properties, Element, Condition> MeshType;

void  AddConstitutiveLawsToPython()
{
    class_< ConstitutiveLaw, boost::noncopyable >
    ( "ConstitutiveLaw", init<>() )
    ;

    class_< Umat, bases< ConstitutiveLawBaseType >, boost::noncopyable >
    ( "Umat", init<>() )
    ;
}
}  // namespace Python.
} // Namespace Kratos


#include <cstdint>
#include <type_traits>
#include <initializer_list>
#include <tuple>
#include <Eigen/Dense>

#include <kvasir/mpl/mpl.hpp>

// Helper functions
namespace mpl = kvasir::mpl;

template < typename Comp = mpl::is_same<>, typename IsSame = mpl::is_same<>,
           typename C = mpl::identity >
using distinct = mpl::fork< mpl::size<>,               // Fork 1: size of input
                            mpl::stable_sort<          // Fork 2: size of unique list
                                Comp,                  // Comparison for sorting the list
                                mpl::remove_adjacent<  // Remove non unique items
                                    IsSame,            // Comparison for uniqueness
                                    mpl::size<>        // Get the size
                                    > >,
                            mpl::is_same<  // Check if the sizes are the same
                                C          // Continuation
                                > >;

template < std::size_t... S >
constexpr std::size_t sum()
{
    std::size_t result = 0;

    for (auto s : {S...})
        result += s;

    return result;
}

template < bool... >
struct bool_pack
{
};

template < bool... Bs >
constexpr bool all_true()
{
    return std::is_same< bool_pack< true, Bs... >, bool_pack< Bs..., true > >::value;
}

namespace states
{
// Core states definitions
enum class nominal
{
    position,
    velocity,
    attitude,
    bias_acc,
    bias_gyro
};

enum class error
{
    position,
    velocity,
    attitude,
    bias_acc,
    bias_gyro
};
}  // namespace states

// Tag to easily detect the base class
struct sensor_base_tag
{
};

// A sensor needs to include ...
template < std::size_t MeasurementSize, std::size_t NumLinearStates = 0,
           std::size_t NumRotationStates = 0 >
struct sensor_base : sensor_base_tag
{
    static constexpr auto measurement_vector_size()
    {
        return std::integral_constant< std::size_t, MeasurementSize >{};
    }

    static constexpr auto num_linear_states()
    {
        return std::integral_constant< std::size_t, NumLinearStates >{};
    }

    static constexpr auto num_quaternion_states()
    {
        return std::integral_constant< std::size_t, NumRotationStates >{};
    }
};

// msf2 specs, takes a list of unique sensors
template < typename... Sensors >
struct msf2_sensors
{
    // Check that input list is existing
    static_assert(sizeof...(Sensors) > 0,
                  "There are no sensors defined and there must be at least one.");

    // Check that input list is actually sensors
    static_assert(all_true< std::is_base_of< sensor_base_tag, Sensors >::value... >(),
                  "Not all elements in the sensor list is a sensor, did you forget to "
                  "inherit from sensor_base?");

    // Check that input list is contains only unique sensors
    static_assert(mpl::call< distinct<>, Sensors... >::value,
                  "The list does not only contain unique sensors, remove duplicates.");

    // Define core state sizes
    static constexpr std::size_t num_sensor_states =
        sum< Sensors::num_linear_states()... >() +         // Get num linear state
        4 * sum< Sensors::num_quaternion_states()... >();  // Get num
                                                           // rotational
                                                           // states

    // Define error state sizes
    static constexpr std::size_t num_sensor_error_states =
        sum< Sensors::num_linear_states()... >() +         // Get num linear state
        3 * sum< Sensors::num_quaternion_states()... >();  // Get num
                                                           // rotational
                                                           // states

    // Storage for sensors with state
    using sensor_storage = std::tuple< Sensors... >;
};

template < typename... Sensors >
class msf2
{
private:
    using sensors_t = msf2_sensors< Sensors... >;

    static constexpr std::size_t num_core_states = 16;
    static constexpr std::size_t num_core_error_states = 15;
    static constexpr std::size_t num_states = num_core_states + sensors_t::num_sensor_states;
    static constexpr std::size_t num_error_states =
        num_core_error_states + sensors_t::num_sensor_error_states;

    using state_t = Eigen::Matrix< double, num_states, 1 >;
    using error_state_t = Eigen::Matrix< double, num_error_states, 1 >;
    using covariance = Eigen::Matrix< double, num_error_states, num_error_states >;

    state_t state;
    error_state_t error_state;
    typename sensors_t::sensor_storage sensor_storage;

public:
    // Convenience functions to get parts of state vector
    template < states::nominal T >
    constexpr std::size_t get()
    {
        return 1;
    }

    template < states::error T >
    constexpr std::size_t get()
    {
        return 2;
    }

    template < class Sensor >
    constexpr Sensor& get_sensor()
    {
        return std::get<Sensor>(sensor_storage);
    }

    template < typename T >
    constexpr std::size_t get_linear()
    {
        static_assert(std::is_base_of< sensor_base_tag, T >::value,
                      "Only sensors can be an argument in get_linear< ... >().");
        static_assert(T::num_linear_states() > 0,
                      "Can't get sensor state, this sensor has no extra linear "
                      "states defined.");

        return 9001;
    }

    template < typename T >
    constexpr std::size_t get_attitude()
    {
        static_assert(std::is_base_of< sensor_base_tag, T >::value,
                      "Only sensors can be an argument in get_rotation< ... >().");
        static_assert(T::num_quaternion_states() > 0,
                      "Can't get sensor state, this sensor has no extra quaternion "
                      "states defined.");

        return 10001;
    }
};

#include <iostream>

// Make some sensors
// Fake sensors, just to make it happy
struct sensor1 : sensor_base< 1,   // Measurement size (1)
                              0,   // Number of extra linear states
                              0 >  // Number of extra rotational states (1 state
                                   // = 1 extra quaternion)
{
    void hello()
    {
        std::cout << "Hello from sensor1\n";
    }
};

struct sensor2 : sensor_base< 3, 1, 0 >
{
    void hello()
    {
        std::cout << "Hello from sensor2\n";
    }
};

struct sensor3 : sensor_base< 1, 1, 1 >
{
    void hello()
    {
        std::cout << "Hello from sensor3\n";
    }
};

// Create an MSF specification from it
// Create the MSF2 filter
using msf = msf2< sensor1, sensor2, sensor3 >;

int main()
{
    msf my_msf;

    // Try get stuff
    std::cout << "val : " << my_msf.get_attitude< sensor3 >() << "\n";
    std::cout << "val2: " << sizeof(sensor3) << "\n";
    std::cout << "val3: " << sizeof(msf) / 8 << "\n";
    my_msf.get_sensor<sensor3>().hello() ;

    return 0;
}


#include <iostream>
#include <vector>
#include <cassert>
#include <cstring>
#include <limits>
#include <mpi.h>
//#include <Eigen/Eigenvalues>

enum KernelType {CubicSpline = 0, WendlandC2 = 1, WendlandC4 = 2};

#include "particle_simulator.hpp"
#include "hdr_time.hpp"
#include "hdr_run.hpp"
#ifdef USE_INTRINSICS
#include "vector_x86.hpp"
#endif
#include "hdr_dimension.hpp"
#include "hdr_kernel.hpp"
#include "hdr_sph.hpp"
#include "hdr_hgas.hpp"
#include "hdr_bhns.hpp"

class SPHAnalysis : public HelmholtzGas {
public:
    SPHAnalysis() {
        this->id    = 0;
        this->istar = 0;
        this->mass  = 0.;
        this->pos   = 0.;
        this->vel   = 0.;
        this->uene  = 0.;
        this->alph  = 0.;
        this->alphu = 0.;
        this->ksr   = 0.;
        for(PS::S32 k = 0; k < NR::NumberOfNucleon; k++) {
            this->cmps[k] = 0.;
        }
    }

    void readAscii(FILE * fp) {
        fscanf(fp, "%lld%lld%lf", &this->id, &this->istar, &this->mass);      //  3
        fscanf(fp, "%lf%lf%lf", &this->pos[0], &this->pos[1], &this->pos[2]); //  6
        fscanf(fp, "%lf%lf%lf", &this->vel[0], &this->vel[1], &this->vel[2]); //  9
        fscanf(fp, "%lf%lf%lf", &this->acc[0], &this->acc[1], &this->acc[2]); // 12
        fscanf(fp, "%lf%lf%lf", &this->uene, &this->alph, &this->alphu);      // 15
        fscanf(fp, "%lf%lf%6d", &this->dens, &this->ksr,  &this->np);         // 18
        fscanf(fp, "%lf%lf%lf", &this->vsnd, &this->pres, &this->temp);       // 21
        fscanf(fp, "%lf%lf%lf", &this->divv, &this->rotv, &this->bswt);       // 24
        fscanf(fp, "%lf%lf%lf", &this->pot,  &this->abar, &this->zbar);       // 27
        fscanf(fp, "%lf",       &this->enuc);                                 // 28
        fscanf(fp, "%lf%lf%lf", &this->vsmx, &this->udot, &this->dnuc);       // 31
        for(PS::S32 k = 0; k < NuclearReaction::NumberOfNucleon; k++) {       // 32 -- 44
            fscanf(fp, "%lf", &this->cmps[k]);
        }
        fscanf(fp, "%lf", &this->pot3);
        fscanf(fp, "%lf%lf%lf", &this->tempmax[0], &this->tempmax[1], &this->tempmax[2]);
        fscanf(fp, "%lf", &this->entr);
    }

};

int main(int argc, char ** argv) {
    PS::Initialize(argc, argv);

    PS::ParticleSystem<SPHAnalysis> sph;
    sph.initialize();
    sph.createParticle(0);
    sph.setNumberOfParticleLocal(0);

    char idir[1024], odir[1024];
    PS::S64 ibgn, iend;
    FILE * fp = fopen(argv[1], "r");
    fscanf(fp, "%s", idir);
    fscanf(fp, "%s", odir);
    fscanf(fp, "%lld%lld", &ibgn, &iend);
    fclose(fp);

    char ofile[1024];
    sprintf(ofile, "%s/melement.log", odir);
    FILE *fout = fopen(ofile, "w");
    for(PS::S64 itime = ibgn; itime <= iend; itime++) {
        char tfile[1024];
        FILE *fp = NULL;
        PS::S64 tdir = 0;
        for(PS::S64 iidir = 0; iidir < 100; iidir++) {
            sprintf(tfile, "%s/t%02d/sph_t%04d_p%06d_i%06d.dat", idir, iidir, itime,
                    PS::Comm::getNumberOfProc(), 0);
            fp = fopen(tfile, "r");
            if(fp != NULL) {
                tdir = iidir;
                break;
            }
        }
        if(fp == NULL) {
            continue;
        }
        fclose(fp);

        char sfile[1024];
        sprintf(sfile, "%s/t%02d/sph_t%04d", idir, tdir, itime);
        sph.readParticleAscii(sfile, "%s_p%06d_i%06d.dat");

        NR::Nucleon MassCmpsLoc;
        for(PS::S64 i = 0; i < sph.getNumberOfParticleLocal(); i++) {
            for(PS::S64 k = 0; k < NR::NumberOfNucleon; k++) {
                MassCmpsLoc[k] += sph[i].mass * sph[i].cmps[k];
            }
        }
        NR::Nucleon MassCmpsGlb;
        fprintf(fout, "%6d", itime);
        for(PS::S64 k = 0; k < NR::NumberOfNucleon; k++) {
            MassCmpsGlb[k] = PS::Comm::getSum(MassCmpsLoc[k]);
            fprintf(fout, " %+.3e", MassCmpsGlb[k] / CodeUnit::SolarMass);
        }
        fprintf(fout, "\n");
    }
    fclose(fout);

    PS::Finalize();

    return 0;
}