#include <string>
#include <map>
#include <math.h>
#include <unistd.h> // For sleep()

#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
#include <boost/python/dict.hpp>
#include <boost/python/tuple.hpp>
#include "boost/tuple/tuple.hpp"

#include "Client.h"

#define CENTER "center"
#define TWO_PI 2 * 3.14159

using namespace std;
using namespace ViconDataStreamSDK::CPP;
using namespace boost::python;

static Client *client_ptr;

bool streamreader_connect(const char* host) {

  // Make a new client
  client_ptr = new Client();

  for(int i=0; i != 3; ++i) { // repeat to check disconnecting doesn't wreck next connect
    // Connect to a server
    while(!client_ptr->IsConnected().Connected) {
      // Direct connection
      bool ok = (client_ptr->Connect(host).Result == Result::Success);

      if(!ok) {
        ; // connection failed, will try again
      }

      sleep(1);
    }
  }

  if (!client_ptr->IsConnected().Connected) {
    return false;
  }

  client_ptr->SetStreamMode(StreamMode::ServerPush);
  client_ptr->EnableMarkerData();
  client_ptr->EnableSegmentData();
  client_ptr->SetAxisMapping(Direction::Forward,
                           Direction::Left,
                           Direction::Up);
  return true;
}

dict streamreader_get_frame() {
  // "car_name" => (x,y,theta,t)
  // t = frame_number
  dict cars;

  while(client_ptr->GetFrame().Result != Result::Success) {
    sleep(1);
  }
  // timing information
  unsigned int frame_number = client_ptr->GetFrameNumber().FrameNumber;
  // Output_GetTimecode frame_time = client_ptr->GetTimecode(); // has .Hours, .Minutes, .Seconds, .Frames

  // Count the number of subjects
  unsigned int car_count = client_ptr->GetSubjectCount().SubjectCount;
  for(unsigned int car_index = 0; car_index < car_count; ++car_index) {
    string car_name = client_ptr->GetSubjectName(car_index).SubjectName;

    // Count the number of markers
    unsigned int marker_count = client_ptr->GetMarkerCount(car_name).MarkerCount;
    map<string, boost::tuples::tuple<float, float> > car_markers;
    for(unsigned int marker_index = 0; marker_index < marker_count; ++marker_index) {
      // Get the marker name
      string marker_name = client_ptr->GetMarkerName(car_name, marker_index).MarkerName;

      // Get the global marker translation
      Output_GetMarkerGlobalTranslation location = client_ptr->GetMarkerGlobalTranslation(car_name, marker_name);

      car_markers[marker_name] = boost::make_tuple(location.Translation[0], location.Translation[1]);
    }

    float theta = client_ptr->GetSegmentGlobalRotationHelical(car_name, car_name).Rotation[2];
    if(theta < 0) {
      theta += TWO_PI;
    }

    boost::tuples::tuple<float,float> center = car_markers[CENTER];
    cars[car_name] = make_tuple(boost::get<0>(center), boost::get<1>(center), theta, frame_number);
  }

  return cars;
}

BOOST_PYTHON_MODULE(streamreader)
{
    def("connect", streamreader_connect);
    def("get_frame", streamreader_get_frame);
}


// #ifdef HAVE_CONFIG_H
// #include "config.h"
// #endif

// #include <assert.h>
// #include <stdlib.h>
// #include <algorithm>
// #include <vector>
// #include <boost/tuple/tuple.hpp>
// #include <boost/tuple/tuple_comparison.hpp>

// #ifdef _OPENMP
// #include <omp.h>
// #endif

// #include <rysq.hpp>
// #include "cxx/sugar.hpp"
// #include "quadrature.h"
// #include "memory.h"

// using namespace rysq;

// parallel::Fock::Fock(const Quartet<Shell> &shells) : shells(shells) {}

// parallel::Fock::~Fock() {}

// void parallel::Fock::operator()(const std::vector<Center> &centers,
// 				const std::vector<Int4> &quartets,
// 				const matrix::Adapter &D,
// 				matrix::Adapter &F,
// 				const Parameters &parameters) {

//     if (quartets.empty()) return;

// #ifdef _OPENMP
// #pragma omp parallel
// #endif
//     {

// #ifdef _OPENMP
// 	int num_threads = omp_get_num_threads();
// 	int thread_num = omp_get_thread_num();
// #else
// 	int num_threads = 1;
// 	int thread_num = 0;
// #endif

// 	rysq::Fock fock(this->shells);

// 	int nij = shells.size(0,1);
// 	int nkl = shells.size(2,3);
// 	int nik = shells.size(0,2);
// 	int nil = shells.size(0,3);
// 	int njk = shells.size(1,2);
// 	int njl = shells.size(1,3);

// 	memory::Map<double> myMemory(32*1024);

// #ifdef _OPENMP
// #pragma omp for schedule(dynamic,1) nowait
// #endif
// 	for (uint q = 0; q < quartets.size(); ++q) {

// 	    int i, j, k, l;
// 	    util::unpack(quartets[q], i, j, k, l);

// 	    double *Fij = myMemory.get(i, j, nij);
// 	    double *Fkl = myMemory.get(k, l, nkl);
// 	    double *Fik = myMemory.get(i, k, nik);
// 	    double *Fil = myMemory.get(i, l, nil);
// 	    double *Fjk = myMemory.get(j, k, njk);
// 	    double *Fjl = myMemory.get(j, l, njl);

// 	    Quartet<Center> C(centers[i], centers[j], centers[k], centers[l]);

// 	    matrix::Density<6> D6 = matrix::index(D, i, j, k, l);
// 	    double *f[] = { Fij, Fkl, Fik, Fil, Fjk, Fjl };
// 	    matrix::Fock<6> F6(f);

// 	    Parameters p = parameters;
// 	    p.scale /= Quartet<Shell>::symmetry(i, j, k, l);

// 	    // fock(C, D6, F6, p);

// 	}

// 	typedef boost::tuple<int,int,double*,size_t> Block;
// 	std::vector<Block> blocks;
// 	typedef std::vector<Block>::iterator block_it;

// 	while (!myMemory.empty()) {
// 	    memory::Map<double>::Entry kv = myMemory.pop();
// 	    blocks.push_back(Block(kv.j, kv.i, kv.ptr, kv.n));
// 	}
// 	std::sort(blocks.begin(), blocks.end());

// 	std::vector<block_it> columns;
// 	typedef std::vector<block_it>::iterator column_it;
// 	block_it it = blocks.begin();

// 	while (it < blocks.end()) {
// 	    int j = it->get<0>();
// 	    columns.push_back(it);
// 	    while (it < blocks.end() && it->get<0>() == j) ++it;
// 	}
// 	columns.push_back(it);

// 	for (int t = 0; t < num_threads; ++t) {
// 	    int k = (thread_num + t)%num_threads;

// 	    for (column_it col = columns.begin(); col < columns.end() - 1; ++col) {
// 		block_it block = *col;
// 		int j = block->get<0>();
// 		if (j%num_threads != k) continue;

// 		while (block < *(col+1)) {
// 		    double *dest = F(block->get<1>(), block->get<0>());
// 		    double *source = block->get<2>();
// 		    size_t size = block->get<3>();
// 		    util::add(size, dest, source);
// 		    ++block;
// 		}
// 	    }
// #ifdef _OPENMP
// #pragma omp barrier
// #endif
// 	}

//     }

// }


/**
 * @file CameraTimeParamBlock.hpp
 * @brief Header file for the CameraTimeParamBlock class.
 * @author Jianzhu Huai
 */

#ifndef INCLUDE_OKVIS_CERES_CAMERATIMEPARAMBLOCK_HPP_
#define INCLUDE_OKVIS_CERES_CAMERATIMEPARAMBLOCK_HPP_

#include <okvis/ceres/ParameterBlockSized.hpp>
#include <Eigen/Core>
#include <okvis/Time.hpp>

namespace okvis {
/// \brief ceres Namespace for ceres-related functionality implemented in okvis.
namespace ceres {
const int nTimeDim = 1, nTimeMinDim = 1;
typedef double TimeOffset;  // can represent either T_d or T_r

/// \brief Wraps the parameter block for camera time offset estimate
class CameraTimeParamBlock
    : public ParameterBlockSized<nTimeDim, nTimeMinDim, TimeOffset> {
 public:
  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
  /// \brief The base class type.
  typedef ParameterBlockSized<nTimeDim, nTimeMinDim, TimeOffset> base_t;

  /// \brief The estimate type (9D vector).
  typedef TimeOffset estimate_t;

  /// \brief Default constructor (assumes not fixed).
  CameraTimeParamBlock();

  /// \brief Constructor with estimate and time.
  /// @param[in] timeOffset The fx,fy,cx,cy estimate.
  /// @param[in] id The (unique) ID of this block.
  /// @param[in] timestamp The timestamp of this state.
  CameraTimeParamBlock(const TimeOffset& timeOffset, uint64_t id,
                       const okvis::Time& timestamp);

  /// \brief Trivial destructor.
  virtual ~CameraTimeParamBlock();

  // setters
  /// @brief Set estimate of this parameter block.
  /// @param[in] timeOffset The estimate to set this to.
  virtual void setEstimate(const TimeOffset& timeOffset);

  /// \brief Set the time.
  /// @param[in] timestamp The timestamp of this state.
  void setTimestamp(const okvis::Time& timestamp) { timestamp_ = timestamp; }

  // getters
  /// @brief Get estimate.
  /// \return The estimate.
  virtual TimeOffset estimate() const;

  /// \brief Get the time.
  /// \return The timestamp of this state.
  okvis::Time timestamp() const { return timestamp_; }

  // minimal internal parameterization
  // x0_plus_Delta=Delta_Chi[+]x0
  /// \brief Generalization of the addition operation,
  ///        x_plus_delta = Plus(x, delta)
  ///        with the condition that Plus(x, 0) = x.
  /// @param[in] x0 Variable.
  /// @param[in] Delta_Chi Perturbation.
  /// @param[out] x0_plus_Delta Perturbed x.
  virtual void plus(const double* x0, const double* Delta_Chi,
                    double* x0_plus_Delta) const {
    Eigen::Map<const Eigen::Matrix<double, nTimeDim, 1> > x0_(x0);
    Eigen::Map<const Eigen::Matrix<double, nTimeDim, 1> > Delta_Chi_(Delta_Chi);
    Eigen::Map<Eigen::Matrix<double, nTimeDim, 1> > x0_plus_Delta_(
        x0_plus_Delta);
    x0_plus_Delta_ = x0_ + Delta_Chi_;
  }

  /// \brief The jacobian of Plus(x, delta) w.r.t delta at delta = 0.
  //  /// @param[in] x0 Variable.
  /// @param[out] jacobian The Jacobian.
  virtual void plusJacobian(const double* /*unused: x*/,
                            double* jacobian) const {
    Eigen::Map<
        Eigen::Matrix<double, nTimeMinDim, nTimeMinDim, Eigen::RowMajor> >
        identity(jacobian);
    identity.setIdentity();
  }

  // Delta_Chi=x0_plus_Delta[-]x0
  /// \brief Computes the minimal difference between a variable x and a
  /// perturbed variable x_plus_delta
  /// @param[in] x0 Variable.
  /// @param[in] x0_plus_Delta Perturbed variable.
  /// @param[out] Delta_Chi Minimal difference.
  /// \return True on success.
  virtual void minus(const double* x0, const double* x0_plus_Delta,
                     double* Delta_Chi) const {
    Eigen::Map<const Eigen::Matrix<double, nTimeDim, 1> > x0_(x0);
    Eigen::Map<Eigen::Matrix<double, nTimeDim, 1> > Delta_Chi_(Delta_Chi);
    Eigen::Map<const Eigen::Matrix<double, nTimeDim, 1> > x0_plus_Delta_(
        x0_plus_Delta);
    Delta_Chi_ = x0_plus_Delta_ - x0_;
  }

  /// \brief Computes the Jacobian from minimal space to naively
  /// overparameterised space as used by ceres.
  //  /// @param[in] x0 Variable.
  /// @param[out] jacobian the Jacobian (dimension minDim x dim).
  /// \return True on success.
  virtual void liftJacobian(const double* /*unused: x*/,
                            double* jacobian) const {
    Eigen::Map<Eigen::Matrix<double, nTimeMinDim, nTimeDim, Eigen::RowMajor> >
        identity(jacobian);
    identity.setIdentity();
  }

  /// @brief Return parameter block type as string
  virtual std::string typeInfo() const { return "CameraTimeParamBlock"; }

 private:
  okvis::Time timestamp_;  ///< Time of this state.
};

}  // namespace ceres
}  // namespace okvis

#endif /* INCLUDE_OKVIS_CERES_CAMERATIMEPARAMBLOCK_HPP_ */


// __BEGIN_LICENSE__
//  Copyright (c) 2006-2013, United States Government as represented by the
//  Administrator of the National Aeronautics and Space Administration. All
//  rights reserved.
//
//  The NASA Vision Workbench is licensed under the Apache License,
//  Version 2.0 (the "License"); you may not use this file except in
//  compliance with the License. You may obtain a copy of the License at
//  http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
// __END_LICENSE__

#ifdef _MSC_VER
#pragma warning(disable:4244)
#pragma warning(disable:4267)
#pragma warning(disable:4996)
#endif

#ifdef NDEBUG
#undef NDEBUG
#endif

#include <vw/tools/hillshade.h>
#include <vw/FileIO/FileUtils.h>

#include <boost/program_options.hpp>
#include <boost/filesystem/path.hpp>

namespace po = boost::program_options;
namespace fs = boost::filesystem;

using namespace vw;

struct Options {
  Options() : nodata_value(std::numeric_limits<double>::quiet_NaN()), blur_sigma(std::numeric_limits<double>::quiet_NaN()) {}
  // Input
  std::string input_file_name;

  // Settings
  std::string output_file_name;
  double azimuth, elevation, scale;
  double nodata_value;
  double blur_sigma;
};

void handle_arguments( int argc, char *argv[], Options& opt ) {
  po::options_description desc("Description: Outputs image of a DEM lighted as specified\n\nUsage: hillshade [options] <input file> \n\nOptions");
  desc.add_options()
    ("input-file", po::value(&opt.input_file_name), "Explicitly specify the input file")
    ("output-file,o", po::value(&opt.output_file_name), "Specify the output file")
    ("azimuth,a", po::value(&opt.azimuth)->default_value(300), "Sets the direction tha the light source is coming from (in degrees).  Zero degrees is to the right, with positive degree counter-clockwise.")
    ("elevation,e", po::value(&opt.elevation)->default_value(20), "Set the elevation of the light source (in degrees).")
    ("scale,s", po::value(&opt.scale)->default_value(0), "Set the scale of a pixel (in the same units as the DTM height values.")
    ("nodata-value", po::value(&opt.nodata_value), "Remap the DEM default value to the min altitude value.")
    ("blur", po::value(&opt.blur_sigma), "Pre-blur the DEM with the specified sigma.")
    ("help,h", "Display this help message");

  po::positional_options_description p;
  p.add("input-file", 1);

  po::variables_map vm;
  try {
    po::store( po::command_line_parser( argc, argv ).options(desc).positional(p).run(), vm );
    po::notify( vm );
  } catch (const po::error& e) {
    vw_throw( ArgumentErr() << "Error parsing input:\n\t"
              << e.what() << desc );
  }

  if( vm.count("help") )
    vw_throw( ArgumentErr() << desc );

  if ( vm.count("input-file") != 1 )
    vw_throw( ArgumentErr() << "Error: Must specify exactly one input file!\n\n" << desc );

  if ( opt.output_file_name.empty() )
    opt.output_file_name =
      fs::path(opt.input_file_name).replace_extension().string() + "_HILLSHADE.tif";

  create_out_dir(opt.output_file_name);
}

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

  Options opt;
  try {
    handle_arguments( argc, argv, opt );
    do_multitype_hillshade(opt.input_file_name,
                           opt.output_file_name,
                           opt.azimuth, opt.elevation, opt.scale,
                           opt.nodata_value, opt.blur_sigma);

  } catch ( const ArgumentErr& e ) {
    vw_out() << e.what() << std::endl;
    return 1;
  } catch ( const Exception& e ) {
    vw_out() << e.what() << std::endl;
    return 1;
  }

  return 0;
}


#include "pwareascene.h"
#include "pwnode.h"
#include "pwconnector.h"
#include <QDebug>
#include <graphviz/gvc.h>
#include <graphviz/cgraph.h>
#include <boost/scope_exit.hpp>
#include <boost/lexical_cast.hpp>
#include <iostream>

void PwAreaScene::autoLayout() {
  auto NC = [](const char *p) -> char * { return const_cast<char *>(p); };
  auto pt2in = [](double v) -> double { return v / 72; };
  auto in2pt = [](double v) -> double { return v * 72; };

  const unsigned hspacing = 16;
  const unsigned vspacing = 0;

  GVC_t *gvc = gvContext();
  BOOST_SCOPE_EXIT(gvc) { gvFreeContext(gvc); } BOOST_SCOPE_EXIT_END;
  Agraph_t *g = agopen(NC("G"), Agdirected, 0);
  BOOST_SCOPE_EXIT(g) { agclose(g); } BOOST_SCOPE_EXIT_END;

  agattr(g, AGRAPH, NC("splines"), NC("line"));
  agattr(g, AGNODE, NC("shape"), NC("box"));

  Agsym_t *sym_fixedsize = agattr(g, AGNODE, NC("fixedsize"), NC(""));
  Agsym_t *sym_width = agattr(g, AGNODE, NC("width"), NC(""));
  Agsym_t *sym_height = agattr(g, AGNODE, NC("height"), NC(""));
  Agsym_t *sym_tailport = agattr(g, AGEDGE, NC("tailport"), NC(""));
  Agsym_t *sym_headport = agattr(g, AGEDGE, NC("headport"), NC(""));

  for (PwNode *node : this->nodes()) {
    std::string name = node->id().toStdString();
    QRectF bounds = node->boundingRect();
    double gw = pt2in(bounds.width() + hspacing);
    double gh = pt2in(bounds.height() + vspacing);
    Agnode_t *gn = agnode(g, NC(name.c_str()), true);
    agxset(gn, sym_fixedsize, NC("true"));
    agxset(gn, sym_width, NC(std::to_string(gw).c_str()));
    agxset(gn, sym_height, NC(std::to_string(gh).c_str()));
  }

  auto endpoint_port = [](PwEndpoint *ep) -> const char * {
    switch (ep->placement()) {
      case PwEndpoint::TopPlacement: return "n";
      case PwEndpoint::BottomPlacement: return "s";
      case PwEndpoint::LeftPlacement: return "w";
      case PwEndpoint::RightPlacement: return "e";
      default: Q_ASSERT(false);
    }
  };

  for (PwConnector *conn : this->connectors()) {
    PwEndpoint *epsrc = conn->sourceEndpoint();
    PwEndpoint *epdst = conn->targetEndpoint();
    std::string srcname = epsrc->parentNode()->id().toStdString();
    std::string dstname = epdst->parentNode()->id().toStdString();
    Agnode_t *gs = agnode(g, NC(srcname.c_str()), false);
    Agnode_t *gt = agnode(g, NC(dstname.c_str()), false);
    Agedge_t *e = agedge(g, gs, gt, NC(""), true);
    agxset(e, sym_tailport, NC(endpoint_port(epsrc)));
    agxset(e, sym_headport, NC(endpoint_port(epdst)));
  }

  if (0)
    agwrite(g, stdout);

  gvLayout(gvc, g, NC("dot"));

  double minx = HUGE_VAL;
  double maxy = 0;
  for (Agnode_t *gn = agfstnode(g); gn; gn = agnxtnode(g, gn)) {
    pointf gp = ND_coord(gn);
    double gh = in2pt(boost::lexical_cast<double>(agxget(gn, sym_height)));
    minx = std::min(gp.x, minx);
    maxy = std::max(gp.y + gh, maxy);
  }

  for (PwNode *node : this->nodes()) {
    std::string name = node->id().toStdString();
    Agnode_t *gn = agnode(g, NC(name.c_str()), false);
    pointf gp = ND_coord(gn);
    QPointF pt(gp.x - minx, maxy - gp.y);
    node->setPos(pt);
  }
}


//==================================================================================================
/*!
  @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_ARCH_COMMON_SIMD_FUNCTION_IF_ALLBITS_ELSE_HPP_INCLUDED
#define BOOST_SIMD_ARCH_COMMON_SIMD_FUNCTION_IF_ALLBITS_ELSE_HPP_INCLUDED
#include <boost/simd/detail/overload.hpp>

#include <boost/simd/meta/hierarchy/simd.hpp>
#include <boost/simd/meta/cardinal_of.hpp>
#include <boost/simd/meta/is_bitwise_logical.hpp>
#include <boost/simd/function/simd/genmask.hpp>
#include <boost/simd/function/simd/if_else.hpp>
#include <boost/simd/constant/allbits.hpp>

namespace boost { namespace simd { namespace ext
{
   namespace bd = boost::dispatch;
   namespace bs = boost::simd;
   BOOST_DISPATCH_OVERLOAD(if_allbits_else_
                          , (typename A0, typename A1, typename X)
                          , bd::cpu_
                          , bs::pack_<bd::unspecified_<A0>, X>
                          , bs::pack_<bd::arithmetic_<A1>, X>
                          )
   {
     template < typename A0_>
     typename enable_if< bs::is_bitwise_logical<A0_>, A1>::type
     BOOST_FORCEINLINE operator()(A0_ const& a0, A1 const& a1) const BOOST_NOEXCEPT
     {
       return bitwise_or(a1, genmask(a0));
     }

     template<class A0_>
     typename disable_if< bs::is_bitwise_logical<A0_>, A1>::type
     BOOST_FORCEINLINE operator()(A0_ const& a0, A1 const& a1) const BOOST_NOEXCEPT
     {
       return if_else(a0, Allbits<A1>(), a1);
     }
   };

} } }

#endif


//==============================================================================
//         Copyright 2003 - 2012   LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 - 2012   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
//==============================================================================
/*!
 * \file
**/
#ifndef BOOST_SIMD_TOOLBOX_SWAR_FUNCTIONS_COMPARATOR_HPP_INCLUDED
#define BOOST_SIMD_TOOLBOX_SWAR_FUNCTIONS_COMPARATOR_HPP_INCLUDED
#include <boost/simd/include/functor.hpp>
#include <boost/dispatch/include/functor.hpp>

/*!
 * \ingroup boost_simd_swar
 * \defgroup boost_simd_swar_comparator comparator
 *
 * \par Description
 * Compute the min and the max of the first two inputs if the third non zero,
 *  or by the max and the min if the third is zero.The function returns a value indicating if anything has changed
 *
 * \par Header file
 *
 * \code
 * #include <nt2/include/functions/comparator.hpp>
 * \endcode
 *
 *
 * \synopsis
 *
 * \code
 * namespace boost::simd
 * {
 *   template<class A0,class A1> inline
 *   typename boost::dispatch::meta::call<tag::comparator_(A0 const&,A0 const&,A1 const&)
 *                                       >::type
 *   comparator(A0 const& a0,A0 const& a1,A1 const& a2);
 *
 *   template<class A0,class A1> inline
 *   bool comparator(A0 const& a0,A0 const& a1,A1& a2,A0& a3,A0& a4);
 * }
 * \endcode
 *
 * \param a0 the first parameter of comparator
 * \param a1 the second parameter of comparator
 * \param a2 the third parameter of comparator, a scalar integer value
 * \param a3 the fourth parameter of comparator, min or max of a0 and a1, according a2 is non zero
 * \param a4 the fith parameter of comparator, max or min of a0 and a1, according a2 is non zero
 *
 * \return a bool value or a fusion vector of the bool and the two other results
 *
 * \par Notes
 * \par
 * This is a swar operation. As such it has not real interest outside
 * SIMD mode.
 * \par
 * Such an operation is a transform of an SIMD vector, that will return
 * vectors obtained on a non necessarily elementwise basis from the inputs
 * elements
 * \par
 * If usable and used in scalar mode, it reduces to the operation
 * on a one element vector.
 *
**/

namespace boost { namespace simd {
  struct ascending_ {};
  struct descending_{};
  namespace tag
  {
    /*!
     * \brief Define the tag comparator_ of functor comparator
     *        in namespace boost::simd::tag for toolbox boost.simd.swar
    **/
    struct comparator_ : ext::unspecified_<comparator_> { typedef ext::unspecified_<comparator_> parent; };
  }
  BOOST_DISPATCH_FUNCTION_IMPLEMENTATION(tag::comparator_, comparator, 3)
  BOOST_DISPATCH_FUNCTION_IMPLEMENTATION_TPL(tag::comparator_, comparator, (A0 const&)(A0 const&)(A1 const&)(A0&)(A0&), 2)
} }

#endif

// modified by jt the 25/12/2010


//=============================================================================================================
/**
 * @file     test_filtering.cpp
 * @author   Ruben Doerfel <Ruben.Doerfel@tu-ilmenau.de>
 * @since    0.1.0
 * @date     12, 2019
 *
 * @section  LICENSE
 *
 * Copyright (C) 2019, Ruben Doerfel. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that
 * the following conditions are met:
 *     * Redistributions of source code must retain the above copyright notice, this list of conditions and the
 *       following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
 *       the following disclaimer in the documentation and/or other materials provided with the distribution.
 *     * Neither the name of MNE-CPP authors nor the names of its contributors may be used
 *       to endorse or promote products derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 *
 * @brief     test for filterData function that calls rtproceesing and utils library.
 *
 */

//=============================================================================================================
// INCLUDES
//=============================================================================================================

#include <utils/generics/applicationlogger.h>

#include <iostream>
#include <vector>
#include <math.h>

#include <fiff/fiff.h>
#include <rtprocessing/helpers/filterkernel.h>
#include <rtprocessing/filter.h>

#include <Eigen/Dense>

//=============================================================================================================
// QT INCLUDES
//=============================================================================================================

#include <QtCore/QCoreApplication>
#include <QFile>
#include <QCommandLineParser>
#include <QtTest>

//=============================================================================================================
// USED NAMESPACES
//=============================================================================================================

using namespace FIFFLIB;
using namespace UTILSLIB;
using namespace RTPROCESSINGLIB;
using namespace Eigen;

//=============================================================================================================
/**
 * DECLARE CLASS TestFiltering
 *
 * @brief The TestFiltering class provides read filter read fiff verification tests
 *
 */
class TestFiltering: public QObject
{
    Q_OBJECT

public:
    TestFiltering();

private slots:
    void initTestCase();
    void compareData();
    void compareTimes();
    void cleanupTestCase();

private:
    double dEpsilon;
    int iOrder;

    MatrixXd mFirstInData;
    MatrixXd mFirstInTimes;
    MatrixXd mFirstFiltered;

    MatrixXd mRefInData;
    MatrixXd mRefInTimes;
    MatrixXd mRefFiltered;

};

//=============================================================================================================

TestFiltering::TestFiltering()
: dEpsilon(0.000001)
{
}

//=============================================================================================================

void TestFiltering::initTestCase()
{
    qInstallMessageHandler(UTILSLIB::ApplicationLogger::customLogWriter);
    qDebug() << "Epsilon" << dEpsilon;

    QFile t_fileIn(QCoreApplication::applicationDirPath() + "/mne-cpp-test-data/MEG/sample/sample_audvis_trunc_raw.fif");
    QFile t_fileOut(QCoreApplication::applicationDirPath() + "/mne-cpp-test-data/MEG/sample/rtfilter_filterdata_out_raw.fif");

    // Filter in Python is created with following function: mne.filter.design_mne_c_filter(raw.info['sfreq'], 5, 10, 1, 1)
    // This will create a filter with with 8193 elements/taps/Order. In order to be concise with the MNE-CPP implementation
    // the filter is cut to the Order used in mne-cpp (1024, see below).//
    // The actual filtering was performed with the function: mne.filter._overlap_add_filter(dataIn, filter_python, phase = 'linear')
    QFile t_fileRef(QCoreApplication::applicationDirPath() + "/mne-cpp-test-data/Result/ref_rtfilter_filterdata_raw.fif");

    // Make sure test folder exists
    QFileInfo t_fileOutInfo(t_fileOut);
    QDir().mkdir(t_fileOutInfo.path());

    //*********************************************************************************************************
    // First Read, Filter & Write
    //*********************************************************************************************************

    printf(">>>>>>>>>>>>>>>>>>>>>>>>> Read, Filter & Write >>>>>>>>>>>>>>>>>>>>>>>>>\n");

    // Setup for reading the raw data
    FiffRawData rawFirstInRaw;
    rawFirstInRaw = FiffRawData(t_fileIn);

    // Only filter MEG channels
    RowVectorXi vPicks = rawFirstInRaw.info.pick_types(true, true, false);
    RowVectorXd vCals;
    FiffStream::SPtr outfid = FiffStream::start_writing_raw(t_fileOut, rawFirstInRaw.info, vCals);

    //   Set up the reading parameters
    //   To read the whole file at once set

    fiff_int_t from = rawFirstInRaw.first_samp;
    fiff_int_t to = rawFirstInRaw.last_samp;

    // initialize filter settings
    QString sFilterName = "example_cosine";
    int type = FilterKernel::m_filterTypes.indexOf(FilterParameter("BPF"));
    double dSFreq = rawFirstInRaw.info.sfreq;
    double dCenterfreq = 10;
    double dBandwidth = 10;
    double dTransition = 1;
    iOrder = 1024;

    MatrixXd mDataFiltered;

    // Reading
    if(!rawFirstInRaw.read_raw_segment(mFirstInData, mFirstInTimes, from, to)) {
        printf("error during read_raw_segment\n");
    }

    // Filtering
    printf("Filtering...");
    mFirstFiltered = RTPROCESSINGLIB::filterData(mFirstInData,
                                                 type,
                                                 dCenterfreq,
                                                 dBandwidth,
                                                 dTransition,
                                                 dSFreq,
                                                 1024,
                                                 RTPROCESSINGLIB::FilterKernel::m_designMethods.indexOf(FilterParameter("Cosine")),
                                                 vPicks);
    printf("[done]\n");

    // Writing
    printf("Writing...");
    outfid->write_int(FIFF_FIRST_SAMPLE, &from);
    outfid->write_raw_buffer(mFirstFiltered,vCals);
    printf("[done]\n");

    outfid->finish_writing_raw();

    // Read filtered data from the filtered output file to check if read and write is working correctly
    FiffRawData rawSecondInRaw;
    rawSecondInRaw = FiffRawData(t_fileOut);

    // Reading
    if (!rawSecondInRaw.read_raw_segment(mFirstFiltered,mFirstInTimes,from,to,vPicks)) {
        printf("error during read_raw_segment\n");
    }

    printf("<<<<<<<<<<<<<<<<<<<<<<<<< Read, Filter & Write Finished <<<<<<<<<<<<<<<<<<<<<<<<<\n");

    //*********************************************************************************************************
    // Read MNE-PYTHON Results As Reference
    //*********************************************************************************************************

    printf(">>>>>>>>>>>>>>>>>>>>>>>>> Read MNE-PYTHON Results As Reference >>>>>>>>>>>>>>>>>>>>>>>>>\n");

    FiffRawData ref_in_raw;
    ref_in_raw = FiffRawData(t_fileRef);

    // Reading
    if (!ref_in_raw.read_raw_segment(mRefFiltered,mRefInTimes,from,to,vPicks)) {
        printf("error during read_raw_segment\n");
    }

    printf("<<<<<<<<<<<<<<<<<<<<<<<<< Read MNE-PYTHON Results Finished <<<<<<<<<<<<<<<<<<<<<<<<<\n");
}

//=============================================================================================================

void TestFiltering::compareData()
{
    //make sure to only read data after 1/2 filter Length
    int iLength = mFirstFiltered.cols()-int(iOrder/2);
    MatrixXd mDataDiff = mFirstFiltered.block(0,int(iOrder/2),mFirstFiltered.rows(),iLength) - mRefFiltered.block(0,int(iOrder/2),mRefFiltered.rows(),iLength);
    QVERIFY( mDataDiff.sum() < dEpsilon );
}

//=============================================================================================================

void TestFiltering::compareTimes()
{
    MatrixXd mTimesDiff = mFirstInTimes - mRefInTimes;
    QVERIFY( mTimesDiff.sum() < dEpsilon );
}

void TestFiltering::cleanupTestCase()
{
}

//=============================================================================================================
// MAIN
//=============================================================================================================

QTEST_GUILESS_MAIN(TestFiltering)
#include "test_filtering.moc"


#define BOOST_TEST_MODULE gd_solver_unit_tests

#include <boost/test/included/unit_test.hpp>
#include <armadillo>
#include "../src/numerical/gradient_descent/gd_solver.h"
#include "test_utils.cpp"
#include "../src/logging/easylogging++.h"

INITIALIZE_EASYLOGGINGPP

GDSolver solver(SIGNALS, 0.5, 5000);

BOOST_AUTO_TEST_CASE(test_common_cases)
{
    auto tester = SolverTester<GDSolver>(solver);
    tester.test_common();
}


// Distributed under the MIT License.
// See LICENSE.txt for details.

#include "Framework/TestingFramework.hpp"

#include <array>
#include <boost/variant/get.hpp> // IWYU pragma: keep
#include <cstddef>

#include "DataStructures/DataBox/DataBox.hpp"
#include "DataStructures/DataVector.hpp"
#include "DataStructures/Tensor/Tensor.hpp"
#include "Domain/Tags.hpp"  // IWYU pragma: keep
#include "Evolution/Systems/RadiationTransport/M1Grey/M1Closure.hpp"
#include "Evolution/Systems/RadiationTransport/M1Grey/Tags.hpp"  // IWYU pragma: keep
#include "Evolution/Systems/RadiationTransport/Tags.hpp"  // IWYU pragma: keep
#include "Framework/ActionTesting.hpp"
#include "Parallel/PhaseDependentActionList.hpp"  // IWYU pragma: keep
#include "ParallelAlgorithms/Actions/MutateApply.hpp"
#include "Utilities/Gsl.hpp"
#include "Utilities/MakeWithValue.hpp"
#include "Utilities/TMPL.hpp"

// IWYU pragma: no_forward_declare Tensor
// IWYU pragma: no_forward_declare ActionTesting::InitializeDataBox

namespace {

template <typename Metavariables>
struct mock_component {
  using metavariables = Metavariables;
  using chare_type = ActionTesting::MockArrayChare;
  using array_index = size_t;
  using Closure = typename RadiationTransport::M1Grey::ComputeM1Closure<
      typename Metavariables::neutrino_species>;
  using simple_tags = db::AddSimpleTags<tmpl::flatten<
      tmpl::list<typename Closure::return_tags, typename Closure::argument_tags,
                 domain::Tags::Coordinates<3, Frame::Inertial>>>>;
  using phase_dependent_action_list = tmpl::list<
      Parallel::PhaseActions<
          typename Metavariables::Phase, Metavariables::Phase::Initialization,
          tmpl::list<ActionTesting::InitializeDataBox<simple_tags>>>,
      Parallel::PhaseActions<
          typename Metavariables::Phase, Metavariables::Phase::Testing,
          tmpl::list<Actions::MutateApply<
              typename RadiationTransport::M1Grey::ComputeM1Closure<
                  typename metavariables::neutrino_species>>>>>;
};

struct Metavariables {
  using component_list = tmpl::list<mock_component<Metavariables>>;
  using neutrino_species = tmpl::list<neutrinos::ElectronNeutrinos<1>,
                                      neutrinos::HeavyLeptonNeutrinos<0>>;
  enum class Phase { Initialization, Testing, Exit };
};
}  // namespace

SPECTRE_TEST_CASE("Unit.RadiationTransport.M1Grey.Actions", "[Unit][M1Grey]") {
  using component = mock_component<Metavariables>;

  const DataVector x{-2.0, -1.0, 0.0, 1.0, 2.0};
  const DataVector y{-2.0, -1.0, 0.0, 1.0, 2.0};
  const DataVector z{-2.0, -1.0, 0.0, 1.0, 2.0};

  // Closure output variables (initialization only,
  // use the same value for all species)
  const DataVector xi{0.5, 0.5, 0.5, 0.5, 0.5};
  const auto tildeP = make_with_value<tnsr::II<DataVector, 3>>(x, 0.5);
  const DataVector J{0.5, 0.5, 0.5, 0.5, 0.5};
  const DataVector Hn{0.5, 0.5, 0.5, 0.5, 0.5};
  const DataVector Hx{0.5, 0.5, 0.5, 0.5, 0.5};
  const DataVector Hy{0.5, 0.5, 0.5, 0.5, 0.5};
  const DataVector Hz{0.5, 0.5, 0.5, 0.5, 0.5};
  // Closure input variables
  // First neutrino species (set to optically thick)
  const DataVector E0{1.0, 1.0, 1.0, 1.0, 1.0};
  const DataVector Sx0{0.0, 0.0, 0.0, 0.0, 0.0};
  const DataVector Sy0{0.0, 0.0, 0.0, 0.0, 0.0};
  const DataVector Sz0{0.0, 0.0, 0.0, 0.0, 0.0};
  // Second neutrino species (set to optically thin)
  const DataVector E1{1.0, 1.0, 1.0, 1.0, 1.0};
  const DataVector Sx1{0.0, 0.0, 0.0, 1.0, 1.0};
  const DataVector Sy1{0.0, 0.0, 1.0, 0.0, 0.0};
  const DataVector Sz1{1.0, 1.0, 0.0, 0.0, 0.0};

  // Fluid and metric variables
  const DataVector vx{0.0, 0.0, 0.0, 0.0, 0.0};
  const DataVector vy{0.0, 0.0, 0.0, 0.0, 0.0};
  const DataVector vz{0.0, 0.0, 0.0, 0.0, 0.0};
  const DataVector W{1.0, 1.0, 1.0, 1.0, 1.0};
  auto metric = make_with_value<tnsr::ii<DataVector, 3>>(x, 0.0);
  auto inverse_metric = make_with_value<tnsr::II<DataVector, 3>>(x, 0.0);
  get<0, 0>(metric) = 1.;
  get<1, 1>(metric) = 1.;
  get<2, 2>(metric) = 1.;
  get<0, 0>(inverse_metric) = 1.;
  get<1, 1>(inverse_metric) = 1.;
  get<2, 2>(inverse_metric) = 1.;

  ActionTesting::MockRuntimeSystem<Metavariables> runner{{}};
  ActionTesting::emplace_component_and_initialize<component>(
      &runner, 0,
      {Scalar<DataVector>{xi}, Scalar<DataVector>{xi}, tildeP, tildeP,
       Scalar<DataVector>{J}, Scalar<DataVector>{J}, Scalar<DataVector>{Hn},
       Scalar<DataVector>{Hn},
       tnsr::i<DataVector, 3, Frame::Inertial>{{{Hx, Hy, Hz}}},
       tnsr::i<DataVector, 3, Frame::Inertial>{{{Hx, Hy, Hz}}},
       Scalar<DataVector>{E0}, Scalar<DataVector>{E1},
       tnsr::i<DataVector, 3, Frame::Inertial>{{{Sx0, Sy0, Sz0}}},
       tnsr::i<DataVector, 3, Frame::Inertial>{{{Sx1, Sy1, Sz1}}},
       tnsr::I<DataVector, 3, Frame::Inertial>{{{vx, vy, vz}}},
       Scalar<DataVector>{W}, metric, inverse_metric,
       tnsr::I<DataVector, 3, Frame::Inertial>{{{x, y, z}}}});
  ActionTesting::set_phase(make_not_null(&runner),
                           Metavariables::Phase::Testing);

  runner.next_action<component>(0);

  // Check that first species return xi=0 (optically thick)
  const DataVector expected_xi0{0.0, 0.0, 0.0, 0.0, 0.0};
  CHECK_ITERABLE_APPROX(
      (ActionTesting::get_databox_tag<
           component, RadiationTransport::M1Grey::Tags::ClosureFactor<
                          neutrinos::ElectronNeutrinos<1>>>(runner, 0)
           .get()),
      expected_xi0);
  // Check that second species return xi=1 (optically thin)
  const DataVector expected_xi1{1.0, 1.0, 1.0, 1.0, 1.0};
  CHECK_ITERABLE_APPROX(
      (ActionTesting::get_databox_tag<
           component, RadiationTransport::M1Grey::Tags::ClosureFactor<
                          neutrinos::HeavyLeptonNeutrinos<0>>>(runner, 0)
           .get()),
      expected_xi1);
}


//  chrono_io
//
//  (C) Copyright Howard Hinnant
//  (C) Copyright 2010 Vicente J. Botet Escriba
//  Use, modification and distribution are subject to the Boost Software
//  License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt).
//
// This code was adapted by Vicente from Howard Hinnant's experimental work
// on chrono i/o under lvm/libc++  to Boost

#ifndef BOOST_CHRONO_IO_V1_CHRONO_IO_HPP
#define BOOST_CHRONO_IO_V1_CHRONO_IO_HPP

#include <boost/chrono/chrono.hpp>
#include <boost/chrono/clock_string.hpp>
#include <boost/chrono/detail/no_warning/signed_unsigned_cmp.hpp>
#include <boost/chrono/detail/scan_keyword.hpp>
#include <boost/chrono/process_cpu_clocks.hpp>
#include <boost/chrono/thread_clock.hpp>
#include <boost/integer/common_factor_rt.hpp>
#include <boost/mpl/if.hpp>
#include <boost/ratio/ratio_io.hpp>
#include <boost/type_traits/is_scalar.hpp>
#include <boost/type_traits/is_signed.hpp>
#include <boost/utility/enable_if.hpp>
#include <locale>

namespace boost {

namespace chrono {

template <class CharT> class duration_punct : public std::locale::facet {
public:
  typedef std::basic_string<CharT> string_type;
  enum { use_long, use_short };

private:
  bool use_short_;
  string_type long_seconds_;
  string_type long_minutes_;
  string_type long_hours_;
  string_type short_seconds_;
  string_type short_minutes_;
  string_type short_hours_;

  template <class Period> string_type short_name(Period) const {
    return ::boost::ratio_string<Period, CharT>::short_name() + short_seconds_;
  }

  string_type short_name(ratio<1>) const { return short_seconds_; }
  string_type short_name(ratio<60>) const { return short_minutes_; }
  string_type short_name(ratio<3600>) const { return short_hours_; }

  template <class Period> string_type long_name(Period) const {
    return ::boost::ratio_string<Period, CharT>::long_name() + long_seconds_;
  }

  string_type long_name(ratio<1>) const { return long_seconds_; }
  string_type long_name(ratio<60>) const { return long_minutes_; }
  string_type long_name(ratio<3600>) const { return long_hours_; }

  void init_C();

public:
  static std::locale::id id;

  explicit duration_punct(int use = use_long) : use_short_(use == use_short) {
    init_C();
  }

  duration_punct(int use, const string_type &long_seconds,
                 const string_type &long_minutes, const string_type &long_hours,
                 const string_type &short_seconds,
                 const string_type &short_minutes,
                 const string_type &short_hours);

  duration_punct(int use, const duration_punct &d);

  template <class Period> string_type short_name() const {
    return short_name(typename Period::type());
  }

  template <class Period> string_type long_name() const {
    return long_name(typename Period::type());
  }

  template <class Period> string_type plural() const {
    return long_name(typename Period::type());
  }

  template <class Period> string_type singular() const {
    return string_type(long_name(typename Period::type()), 0,
                       long_name(typename Period::type()).size() - 1);
  }

  template <class Period> string_type name() const {
    if (use_short_)
      return short_name<Period>();
    else {
      return long_name<Period>();
    }
  }
  template <class Period, class D> string_type name(D v) const {
    if (use_short_)
      return short_name<Period>();
    else {
      if (v == -1 || v == 1)
        return singular<Period>();
      else
        return plural<Period>();
    }
  }

  bool is_short_name() const { return use_short_; }
  bool is_long_name() const { return !use_short_; }
};

template <class CharT> std::locale::id duration_punct<CharT>::id;

template <class CharT> void duration_punct<CharT>::init_C() {
  short_seconds_ = CharT('s');
  short_minutes_ = CharT('m');
  short_hours_ = CharT('h');
  const CharT s[] = {'s', 'e', 'c', 'o', 'n', 'd', 's'};
  const CharT m[] = {'m', 'i', 'n', 'u', 't', 'e', 's'};
  const CharT h[] = {'h', 'o', 'u', 'r', 's'};
  long_seconds_.assign(s, s + sizeof(s) / sizeof(s[0]));
  long_minutes_.assign(m, m + sizeof(m) / sizeof(m[0]));
  long_hours_.assign(h, h + sizeof(h) / sizeof(h[0]));
}

template <class CharT>
duration_punct<CharT>::duration_punct(int use, const string_type &long_seconds,
                                      const string_type &long_minutes,
                                      const string_type &long_hours,
                                      const string_type &short_seconds,
                                      const string_type &short_minutes,
                                      const string_type &short_hours)
    : use_short_(use == use_short), long_seconds_(long_seconds),
      long_minutes_(long_minutes), long_hours_(long_hours),
      short_seconds_(short_seconds), short_minutes_(short_minutes),
      short_hours_(short_hours) {}

template <class CharT>
duration_punct<CharT>::duration_punct(int use, const duration_punct &d)
    : use_short_(use == use_short), long_seconds_(d.long_seconds_),
      long_minutes_(d.long_minutes_), long_hours_(d.long_hours_),
      short_seconds_(d.short_seconds_), short_minutes_(d.short_minutes_),
      short_hours_(d.short_hours_) {}

template <class CharT, class Traits>
std::basic_ostream<CharT, Traits> &
duration_short(std::basic_ostream<CharT, Traits> &os) {
  typedef duration_punct<CharT> Facet;
  std::locale loc = os.getloc();
  if (std::has_facet<Facet>(loc)) {
    const Facet &f = std::use_facet<Facet>(loc);
    if (f.is_long_name())
      os.imbue(std::locale(loc, new Facet(Facet::use_short, f)));
  } else
    os.imbue(std::locale(loc, new Facet(Facet::use_short)));
  return os;
}

template <class CharT, class Traits>
std::basic_ostream<CharT, Traits> &
duration_long(std::basic_ostream<CharT, Traits> &os) {
  typedef duration_punct<CharT> Facet;
  std::locale loc = os.getloc();
  if (std::has_facet<Facet>(loc)) {
    const Facet &f = std::use_facet<Facet>(loc);
    if (f.is_short_name())
      os.imbue(std::locale(loc, new Facet(Facet::use_long, f)));
  }
  return os;
}

template <class CharT, class Traits, class Rep, class Period>
std::basic_ostream<CharT, Traits> &
operator<<(std::basic_ostream<CharT, Traits> &os,
           const duration<Rep, Period> &d) {
  typedef duration_punct<CharT> Facet;
  std::locale loc = os.getloc();
  if (!std::has_facet<Facet>(loc))
    os.imbue(std::locale(loc, new Facet));
  const Facet &f = std::use_facet<Facet>(os.getloc());
  return os << d.count() << ' ' << f.template name<Period>(d.count());
}

namespace chrono_detail {
template <class Rep, bool = is_scalar<Rep>::value>
struct duration_io_intermediate {
  typedef Rep type;
};

template <class Rep> struct duration_io_intermediate<Rep, true> {
  typedef
      typename mpl::if_c<is_floating_point<Rep>::value, long double,
                         typename mpl::if_c<is_signed<Rep>::value, long long,
                                            unsigned long long>::type>::type
          type;
};

template <typename intermediate_type>
typename enable_if<is_integral<intermediate_type>, bool>::type
reduce(intermediate_type &r, unsigned long long &den,
       std::ios_base::iostate &err) {
  typedef typename common_type<intermediate_type, unsigned long long>::type
      common_type_t;

  // Reduce r * num / den
  common_type_t t =
      integer::gcd<common_type_t>(common_type_t(r), common_type_t(den));
  r /= t;
  den /= t;
  if (den != 1) {
    // Conversion to Period is integral and not exact
    err |= std::ios_base::failbit;
    return false;
  }
  return true;
}
template <typename intermediate_type>
typename disable_if<is_integral<intermediate_type>, bool>::type
reduce(intermediate_type &, unsigned long long &, std::ios_base::iostate &) {
  return true;
}

} // namespace chrono_detail

template <class CharT, class Traits, class Rep, class Period>
std::basic_istream<CharT, Traits> &
operator>>(std::basic_istream<CharT, Traits> &is, duration<Rep, Period> &d) {
  // std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
  typedef duration_punct<CharT> Facet;
  std::locale loc = is.getloc();
  // std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
  if (!std::has_facet<Facet>(loc)) {
    // std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
    is.imbue(std::locale(loc, new Facet));
  }
  // std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
  loc = is.getloc();
  const Facet &f = std::use_facet<Facet>(loc);
  typedef typename chrono_detail::duration_io_intermediate<Rep>::type
      intermediate_type;
  intermediate_type r;
  std::ios_base::iostate err = std::ios_base::goodbit;
  // read value into r
  // std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
  is >> r;
  // std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
  if (is.good()) {
    // std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
    // now determine unit
    typedef std::istreambuf_iterator<CharT, Traits> in_iterator;
    in_iterator i(is);
    in_iterator e;
    // std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
    if (i != e && *i == ' ') // mandatory ' ' after value
    {
      // std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
      ++i;
      if (i != e) {
        // std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
        // unit is num / den (yet to be determined)
        unsigned long long num = 0;
        unsigned long long den = 0;
        if (*i == '[') {
          // std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
          // parse [N/D]s or [N/D]seconds format
          ++i;
          CharT x;
          is >> num >> x >> den;
          if (!is.good() || (x != '/')) {
            // std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
            is.setstate(is.failbit);
            return is;
          }
          i = in_iterator(is);
          if (*i != ']') {
            // std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
            is.setstate(is.failbit);
            return is;
          }
          ++i;
          const std::basic_string<CharT> units[] = {
              f.template singular<ratio<1>>(), f.template plural<ratio<1>>(),
              f.template short_name<ratio<1>>()};
          // std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
          const std::basic_string<CharT> *k = chrono_detail::scan_keyword(
              i, e, units, units + sizeof(units) / sizeof(units[0]),
              //~ std::use_facet<std::ctype<CharT> >(loc),
              err);
          // std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
          is.setstate(err);
          switch ((k - units) / 3) {
          case 0:
            // std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
            break;
          default:
            is.setstate(err);
            // std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
            return is;
          }
        } else {
          // std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
          // parse SI name, short or long
          const std::basic_string<CharT> units[] = {
              f.template singular<atto>(),
              f.template plural<atto>(),
              f.template short_name<atto>(),
              f.template singular<femto>(),
              f.template plural<femto>(),
              f.template short_name<femto>(),
              f.template singular<pico>(),
              f.template plural<pico>(),
              f.template short_name<pico>(),
              f.template singular<nano>(),
              f.template plural<nano>(),
              f.template short_name<nano>(),
              f.template singular<micro>(),
              f.template plural<micro>(),
              f.template short_name<micro>(),
              f.template singular<milli>(),
              f.template plural<milli>(),
              f.template short_name<milli>(),
              f.template singular<centi>(),
              f.template plural<centi>(),
              f.template short_name<centi>(),
              f.template singular<deci>(),
              f.template plural<deci>(),
              f.template short_name<deci>(),
              f.template singular<deca>(),
              f.template plural<deca>(),
              f.template short_name<deca>(),
              f.template singular<hecto>(),
              f.template plural<hecto>(),
              f.template short_name<hecto>(),
              f.template singular<kilo>(),
              f.template plural<kilo>(),
              f.template short_name<kilo>(),
              f.template singular<mega>(),
              f.template plural<mega>(),
              f.template short_name<mega>(),
              f.template singular<giga>(),
              f.template plural<giga>(),
              f.template short_name<giga>(),
              f.template singular<tera>(),
              f.template plural<tera>(),
              f.template short_name<tera>(),
              f.template singular<peta>(),
              f.template plural<peta>(),
              f.template short_name<peta>(),
              f.template singular<exa>(),
              f.template plural<exa>(),
              f.template short_name<exa>(),
              f.template singular<ratio<1>>(),
              f.template plural<ratio<1>>(),
              f.template short_name<ratio<1>>(),
              f.template singular<ratio<60>>(),
              f.template plural<ratio<60>>(),
              f.template short_name<ratio<60>>(),
              f.template singular<ratio<3600>>(),
              f.template plural<ratio<3600>>(),
              f.template short_name<ratio<3600>>()};
          // std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
          const std::basic_string<CharT> *k = chrono_detail::scan_keyword(
              i, e, units, units + sizeof(units) / sizeof(units[0]),
              //~ std::use_facet<std::ctype<CharT> >(loc),
              err);
          // std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
          switch ((k - units) / 3) {
          case 0:
            num = 1ULL;
            den = 1000000000000000000ULL;
            break;
          case 1:
            num = 1ULL;
            den = 1000000000000000ULL;
            break;
          case 2:
            num = 1ULL;
            den = 1000000000000ULL;
            break;
          case 3:
            num = 1ULL;
            den = 1000000000ULL;
            break;
          case 4:
            num = 1ULL;
            den = 1000000ULL;
            break;
          case 5:
            num = 1ULL;
            den = 1000ULL;
            break;
          case 6:
            num = 1ULL;
            den = 100ULL;
            break;
          case 7:
            num = 1ULL;
            den = 10ULL;
            break;
          case 8:
            num = 10ULL;
            den = 1ULL;
            break;
          case 9:
            num = 100ULL;
            den = 1ULL;
            break;
          case 10:
            num = 1000ULL;
            den = 1ULL;
            break;
          case 11:
            num = 1000000ULL;
            den = 1ULL;
            break;
          case 12:
            num = 1000000000ULL;
            den = 1ULL;
            break;
          case 13:
            num = 1000000000000ULL;
            den = 1ULL;
            break;
          case 14:
            num = 1000000000000000ULL;
            den = 1ULL;
            break;
          case 15:
            num = 1000000000000000000ULL;
            den = 1ULL;
            break;
          case 16:
            num = 1;
            den = 1;
            break;
          case 17:
            num = 60;
            den = 1;
            break;
          case 18:
            num = 3600;
            den = 1;
            break;
          default:
            // std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
            is.setstate(err | is.failbit);
            return is;
          }
        }
        // std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
        // unit is num/den
        // r should be multiplied by (num/den) / Period
        // Reduce (num/den) / Period to lowest terms
        unsigned long long gcd_n1_n2 =
            integer::gcd<unsigned long long>(num, Period::num);
        unsigned long long gcd_d1_d2 =
            integer::gcd<unsigned long long>(den, Period::den);
        num /= gcd_n1_n2;
        den /= gcd_d1_d2;
        unsigned long long n2 = Period::num / gcd_n1_n2;
        unsigned long long d2 = Period::den / gcd_d1_d2;
        if (num > (std::numeric_limits<unsigned long long>::max)() / d2 ||
            den > (std::numeric_limits<unsigned long long>::max)() / n2) {
          // std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
          // (num/den) / Period overflows
          is.setstate(err | is.failbit);
          return is;
        }
        num *= d2;
        den *= n2;

        typedef
            typename common_type<intermediate_type, unsigned long long>::type
                common_type_t;

        // std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
        // num / den is now factor to multiply by r
        if (!chrono_detail::reduce(r, den, err)) {
          // std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
          is.setstate(err | is.failbit);
          return is;
        }

        // if (r > ((duration_values<common_type_t>::max)() / num))
        // std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
        if (chrono::detail::gt(
                r, ((duration_values<common_type_t>::max)() / num))) {
          // Conversion to Period overflowed
          // std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
          is.setstate(err | is.failbit);
          return is;
        }
        // std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
        common_type_t t = r * num;
        t /= den;
        // std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;

        if (t > duration_values<common_type_t>::zero()) {
          // std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
          if ((duration_values<Rep>::max)() < Rep(t)) {
            // std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
            // Conversion to Period overflowed
            is.setstate(err | is.failbit);
            return is;
          }
        }
        // std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
        // Success!  Store it.
        d = duration<Rep, Period>(Rep(t));
        is.setstate(err);
        // std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
        return is;
      } else {
        // std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
        is.setstate(is.failbit | is.eofbit);
        return is;
      }
    } else {
      // std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
      if (i == e)
        is.setstate(is.failbit | is.eofbit);
      else
        is.setstate(is.failbit);
      // std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
      return is;
    }
  } else {
    // std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
    // is.setstate(is.failbit);
    return is;
  }
}

template <class CharT, class Traits, class Clock, class Duration>
std::basic_ostream<CharT, Traits> &
operator<<(std::basic_ostream<CharT, Traits> &os,
           const time_point<Clock, Duration> &tp) {
  return os << tp.time_since_epoch() << clock_string<Clock, CharT>::since();
}

template <class CharT, class Traits, class Clock, class Duration>
std::basic_istream<CharT, Traits> &
operator>>(std::basic_istream<CharT, Traits> &is,
           time_point<Clock, Duration> &tp) {
  Duration d;
  is >> d;
  if (is.good()) {
    const std::basic_string<CharT> units = clock_string<Clock, CharT>::since();
    std::ios_base::iostate err = std::ios_base::goodbit;
    typedef std::istreambuf_iterator<CharT, Traits> in_iterator;
    in_iterator i(is);
    in_iterator e;
    std::ptrdiff_t k = chrono_detail::scan_keyword(
                           i, e, &units, &units + 1,
                           //~ std::use_facet<std::ctype<CharT> >(is.getloc()),
                           err) -
                       &units;
    is.setstate(err);
    if (k == 1) {
      is.setstate(err | is.failbit);
      // failed to read epoch string
      return is;
    }
    tp = time_point<Clock, Duration>(d);
  } else
    is.setstate(is.failbit);
  return is;
}
} // namespace chrono

} // namespace boost

#endif // BOOST_CHRONO_CHRONO_IO_HPP


#pragma once

#include <iostream>
#include <string>
#include <map>

#include <boost/multiprecision/cpp_int.hpp>
using namespace boost::multiprecision;

#include "print_or_log.hpp"

namespace Poco
{
    class DatabaseSharding
    {
    public:
        std::vector<std::string> get_shard_users(std::string user_id);
    private:
        std::map<std::string, uint256_t> fair_partitioning();
        std::pair<std::string, uint256_t> get_fair_user_id(std::string user_id);
        uint32_t get_amount_of_shards();
        std::pair<uint256_t, uint256_t> get_fair_shard_range(std::string user_id);
    };

    class NetworkSharding /* TODO */
    {
    public:

    private:

    };
}


// kate: replace-tabs off; indent-width 4; indent-mode normal
// vim: ts=4:sw=4:noexpandtab
/*

Copyright (c) 2010--2012,
François Pomerleau and Stephane Magnenat, ASL, ETHZ, Switzerland
You can contact the authors at <f dot pomerleau at gmail dot com> and
<stephane at magnenat dot net>

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the <organization> nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL ETH-ASL BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

*/

#include "pointmatcher/PointMatcher.h"
#include "pointmatcher/IO.h"
#include <cassert>
#include <iostream>
#include <fstream>
#include <boost/format.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>

using namespace std;
using namespace PointMatcherSupport;

void validateArgs(int argc, char *argv[]);

/**
  * Code example for ICP taking a sequence of point clouds relatively close
  * and computing the transformation between them.
  */
int main(int argc, char *argv[])
{
	validateArgs(argc, argv);

	typedef PointMatcher<float> PM;
	typedef PointMatcherIO<float> PMIO;
	typedef PM::TransformationParameters TP;
	typedef PM::DataPoints DP;
	typedef Parametrizable::Parameter Parameter;

	const int maxMapPointCount = 200000;

	string outputFileName(argv[0]);

	// Main algorithm definition
	PM::ICP icp;

	// load YAML config
	ifstream ifs(argv[1]);
	validateFile(argv[1]);
	icp.loadFromYaml(ifs);

	PMIO::FileInfoVector list(argv[2]);

	PM::DataPoints mapPointCloud, newCloud;
	TP tp;

	for(unsigned i=0; i < list.size(); i++)
	{
		cout << "---------------------\nLoading: " << list[i].readingFileName << endl;
		newCloud = DP::load(list[i].readingFileName);

		if(mapPointCloud.features.rows() == 0)
		{
			mapPointCloud = newCloud;
		}
		else
		{

			// call ICP
			try
			{
				tp = icp(mapPointCloud, newCloud);
				//tp = icp.getDeltaTransform();
				//cout << "Transformation: "<< tp << endl;
				cout << "match ratio: " << icp.errorMinimizer->getWeightedPointUsedRatio() << endl;

				newCloud.features = tp.inverse()*newCloud.features;

				PM::DataPointsFilter* densityFilter(
					PM::get().DataPointsFilterRegistrar.create(
						"SurfaceNormalDataPointsFilter",
						map_list_of
							("binSize", "10")
							("epsilon", "5")
							("keepNormals", "0")
							("keepDensities", "1")
					)
				);

				PM::DataPointsFilter* maxDensitySubsample(
					PM::get().DataPointsFilterRegistrar.create(
						"MaxDensityDataPointsFilter",
						map_list_of
							("maxDensity", toParam(30))
					)
				);

				// Merge point clouds to map
				mapPointCloud.concatenate(newCloud);
				mapPointCloud = densityFilter->filter(mapPointCloud);
				mapPointCloud = maxDensitySubsample->filter(mapPointCloud);

				// Controle the size of the point cloud
				const double probToKeep = maxMapPointCount/(double)mapPointCloud.features.cols();
				if(probToKeep < 1.0)
				{
					PM::DataPointsFilter* randSubsample(
						PM::get().DataPointsFilterRegistrar.create(
							"RandomSamplingDataPointsFilter",
							map_list_of
								("prob", toParam(probToKeep))
						)
					);
					mapPointCloud = randSubsample->filter(mapPointCloud);
				}
			}
			catch (PM::ConvergenceError& error)
			{
				cout << "ERROR PM::ICP failed to converge: " << endl;
				cout << "   " << error.what() << endl;
				//cout << "Reseting tracking" << endl;
				//icp.resetTracking(newCloud);
			}

			stringstream outputFileNameIter;
			outputFileNameIter << outputFileName << "_" << i;

			cout << "outputFileName: " << outputFileNameIter.str() << endl;
			mapPointCloud.save(outputFileNameIter.str());
		}
	}

	return 0;
}

void validateArgs(int argc, char *argv[])
{
	if (!(argc == 3))
	{
		cerr << "Error in command line, usage " << argv[0] << " icpConfiguration.yaml listOfFiles.csv" << endl;
		cerr << endl << "Example:" << endl;
		cerr << argv[0] << " ../examples/data/default.yaml ../examples/data/carCloudList.csv" << endl << endl;

		abort();
	}
}


#include <miopen/conv/invokers/impl_gemm.hpp>

#include <miopen/conv/data_invoke_params.hpp>
#include <miopen/algorithm.hpp>
#include <miopen/handle.hpp>
#include <miopen/tensor_ops.hpp>

#include <boost/any.hpp>

namespace miopen {
namespace conv {

InvokerFactory MakeImplGemmDataInvokerFactory(const ConvolutionContext& ctx)
{
    if(ctx.direction.IsForward())
    {
        return [](const std::vector<Kernel>& kernels) {
            return [=](Handle& handle, const boost::any& primitive_parameters) {
                const auto data_ctx = boost::any_cast<conv::DataInvokeParams>(primitive_parameters);
                const auto& tensors = data_ctx.tensors;
                handle.Run(kernels[0])(tensors.in, tensors.w, tensors.out);
            };
        };
    }
    else
    {
        const auto& conv       = ctx.conv_problem.GetConv();
        const auto& lowp_quant = conv.lowp_quant;

        return [conv, lowp_quant](const std::vector<Kernel>& kernels) {
            return [=](Handle& handle, const boost::any& primitive_parameters) {
                const auto data_ctx = boost::any_cast<conv::DataInvokeParams>(primitive_parameters);
                const auto& tensors = data_ctx.tensors;
                const auto& workSpace = data_ctx.workSpace;

                // Miminum checks. Only check what is required to select
                // proper invocation procedure & workspace sanity.
                auto kernel = handle.Run(kernels[0]);

                float elapsed = 0;
                // clang-format off
                if((tensors.outDesc.GetType() == miopenHalf ||
                    tensors.outDesc.GetType() == miopenBFloat16) &&
                   (kernel.GetName() == "gridwise_convolution_backward_data_implicit_gemm_v1r1_xdlops_nchw_kcyx_nkhw" ||
                    kernel.GetName() == "gridwise_convolution_backward_data_implicit_gemm_v1r1_xdlops_gnchw_gkcyx_gnkhw" ||
                    kernel.GetName() == "gridwise_convolution_backward_data_implicit_gemm_v1r1_nchw_kcyx_nkhw" ||
                    kernel.GetName() == "gridwise_convolution_backward_data_implicit_gemm_v1r1_ncdhw_kczyx_nkdhw"))
                // clang-format on
                {
                    float zero = 0.f;
                    TensorDescriptor workspaceDesc(
                        miopenFloat, tensors.outDesc.GetLengths(), tensors.outDesc.GetStrides());
                    SetTensor(handle, workspaceDesc, workSpace, &zero);
                    if(handle.IsProfilingEnabled())
                        elapsed += handle.GetKernelTime();

                    kernel(tensors.in, tensors.w, workSpace);
                    if(handle.IsProfilingEnabled())
                        elapsed += handle.GetKernelTime();

                    CastTensor(handle,
                               &lowp_quant,
                               workspaceDesc,
                               workSpace,
                               tensors.outDesc,
                               tensors.out,
                               0,
                               0);
                    if(handle.IsProfilingEnabled())
                        elapsed += handle.GetKernelTime();
                }
                // clang-format off
                else if((kernel.GetName() == "gridwise_convolution_implicit_gemm_v4_nchw_kc1x1_nkhw_lds_double_buffer") ||
                        (kernel.GetName() == "gridwise_convolution_implicit_gemm_v4r4_xdlops_nchw_kc1x1_nkhw_lds_double_buffer"))
                // clang-format on
                {
                    bool hasStride =
                        (tensors.inDesc.GetLengths()[2] != tensors.outDesc.GetLengths()[2]) ||
                        (tensors.inDesc.GetLengths()[3] != tensors.outDesc.GetLengths()[3]);
                    /// \todo set zero within implicitGEMM kernel
                    if(hasStride)
                    {
                        MIOPEN_LOG_I2("hasStride, call SetTensor with zero");
                        float zero = 0.f;
                        SetTensor(handle, tensors.outDesc, tensors.out, &zero);

                        if(handle.IsProfilingEnabled())
                            elapsed += handle.GetKernelTime();
                    }

                    kernel(tensors.in, tensors.w, tensors.out);

                    if(handle.IsProfilingEnabled())
                        elapsed += handle.GetKernelTime();
                }
                // clang-format off
                else if(kernel.GetName() == "gridwise_convolution_backward_data_implicit_gemm_v1r1_xdlops_nchw_kcyx_nkhw" ||
                        kernel.GetName() == "gridwise_convolution_backward_data_implicit_gemm_v1r1_xdlops_gnchw_gkcyx_gnkhw")
                // clang-format on
                {
                    float zero = 0.f;
                    SetTensor(handle, tensors.outDesc, tensors.out, &zero);
                    if(handle.IsProfilingEnabled())
                        elapsed += handle.GetKernelTime();

                    kernel(tensors.in, tensors.w, tensors.out);
                    if(handle.IsProfilingEnabled())
                        elapsed += handle.GetKernelTime();
                }
                // clang-format off
                else if(
                    kernel.GetName() == "gridwise_convolution_backward_data_implicit_gemm_v1r1_nchw_kcyx_nkhw" ||
                    kernel.GetName() == "gridwise_convolution_backward_data_implicit_gemm_v1r1_ncdhw_kczyx_nkdhw")
                // clang-format on
                {
                    // this kernel accumulate results into input tensor, therefore need to set zero
                    bool is_1x1_s1 = false;
                    if(miopen::all_of(conv.GetConvPads(), [](auto v) { return v == 0; }) &&
                       miopen::all_of(conv.GetConvStrides(), [](auto v) { return v == 1; }))
                    {
                        if(tensors.wDesc.GetLengths()[2] == 1 && tensors.wDesc.GetLengths()[3] == 1)
                        { // filter = 1
                            if(tensors.wDesc.GetSize() == 4 ||
                               (tensors.wDesc.GetSize() == 5 && tensors.wDesc.GetLengths()[4] == 1))
                            {
                                is_1x1_s1 = true;
                            }
                        }
                    }

                    if(!is_1x1_s1)
                    {
                        float zero = 0.f;
                        SetTensor(handle, tensors.outDesc, tensors.out, &zero);
                        if(handle.IsProfilingEnabled())
                            elapsed += handle.GetKernelTime();
                    }

                    kernel(tensors.in, tensors.w, tensors.out);
                    if(handle.IsProfilingEnabled())
                        elapsed += handle.GetKernelTime();
                }
                // clang-format off
                else if(
                    kernel.GetName() == "gridwise_convolution_backward_data_implicit_gemm_v4r1_nchw_kcyx_nkhw" ||
                    kernel.GetName() == "gridwise_convolution_backward_data_implicit_gemm_v4r1_ncdhw_kczyx_nkdhw")
                // clang-format on
                {
                    // \todo this kernel doesn't always need to set-zero
                    bool filterGeStride = false;
                    if(miopen::all_of(conv.GetConvPads(), [](auto v) { return v == 0; }))
                    {
                        if(tensors.wDesc.GetSize() == 4)
                        { // 2d
                            if(tensors.wDesc.GetLengths()[2] >= conv.GetConvStrides()[0] &&
                               tensors.wDesc.GetLengths()[3] >= conv.GetConvStrides()[1])
                            {
                                filterGeStride = true;
                            }
                        }
                        else
                        { // 3d
                            if(tensors.wDesc.GetLengths()[2] >= conv.GetConvStrides()[0] &&
                               tensors.wDesc.GetLengths()[3] >= conv.GetConvStrides()[1] &&
                               tensors.wDesc.GetLengths()[4] >= conv.GetConvStrides()[2])
                            {
                                filterGeStride = true;
                            }
                        }
                    }

                    if(!filterGeStride)
                    {
                        float zero = 0.f;
                        SetTensor(handle, tensors.outDesc, tensors.out, &zero);

                        if(handle.IsProfilingEnabled())
                            elapsed += handle.GetKernelTime();
                    }

                    // a group kernels (compiled from same source code) will be launched
                    for(const auto& k : kernels)
                    {
                        handle.Run(k)(tensors.in, tensors.w, tensors.out);
                        elapsed += handle.GetKernelTime();
                    }
                }
                else
                {
                    MIOPEN_THROW(
                        "Error running implicit GEMM backward data convolution (none workspace?)");
                }

                if(handle.IsProfilingEnabled())
                {
                    handle.ResetKernelTime();
                    handle.AccumKernelTime(elapsed);
                }
            };
        };
    }
}

} // namespace conv
} // namespace miopen


// Boost.Geometry (aka GGL, Generic Geometry Library)

// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.

// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CALCULATE_DISTANCE_POLICY_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CALCULATE_DISTANCE_POLICY_HPP

#include <boost/geometry/algorithms/comparable_distance.hpp>

namespace boost { namespace geometry
{

#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace overlay
{

/*!
    \brief Policy calculating distance
    \details get_turn_info has an optional policy to get some
        extra information.
        This policy calculates the distance (using default distance strategy)
 */
struct calculate_distance_policy
{
    static bool const include_no_turn = false;
    static bool const include_degenerate = false;
    static bool const include_opposite = false;

    template
    <
        typename Info,
        typename Point1,
        typename Point2,
        typename IntersectionInfo,
        typename DirInfo
    >
    static inline void apply(Info& info, Point1 const& p1, Point2 const& p2,
                IntersectionInfo const&, DirInfo const&)
    {
        info.operations[0].enriched.distance
                    = geometry::comparable_distance(info.point, p1);
        info.operations[1].enriched.distance
                    = geometry::comparable_distance(info.point, p2);
    }

};

}} // namespace detail::overlay
#endif //DOXYGEN_NO_DETAIL

}} // namespace boost::geometry

#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CALCULATE_DISTANCE_POLICY_HPP


//---------------------------------------------------------------------------//
// Copyright (c) 2018-2020 Mikhail Komarov <nemo@nil.foundation>
// Copyright (c) 2019 Aleksey Moskvin <zerg1996@yandex.ru>
//
// Distributed under the Boost Software License, Version 1.0
// See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
//---------------------------------------------------------------------------//

#ifndef CRYPTO3_VARLENGTH_BLOCK_STREAM_PROCESSOR_HPP
#define CRYPTO3_VARLENGTH_BLOCK_STREAM_PROCESSOR_HPP

#include <array>
#include <iterator>

#include <boost/crypto3/detail/pack.hpp>
#include <boost/crypto3/detail/digest.hpp>

#include <boost/integer.hpp>
#include <boost/static_assert.hpp>
#include <boost/utility/enable_if.hpp>

#include <boost/range/algorithm/copy.hpp>

namespace boost {
    namespace crypto3 {
        namespace codec {
            template<typename Mode, typename StateAccumulator, typename Params>
            struct varlength_block_stream_processor {
            private:
                typedef Mode mode_type;
                typedef StateAccumulator accumulator_type;
                typedef Params params_type;

                constexpr static const std::size_t input_block_bits = mode_type::input_block_bits;
                typedef typename mode_type::input_block_type input_block_type;

                constexpr static const std::size_t input_value_bits = mode_type::input_value_bits;
                typedef typename input_block_type::value_type input_value_type;

                constexpr static const std::size_t output_block_bits = mode_type::output_block_bits;
                typedef typename mode_type::output_block_type output_block_type;

                constexpr static const std::size_t output_value_bits = mode_type::output_value_bits;
                typedef typename output_block_type::value_type output_value_type;

            public:
                typedef typename params_type::endian_type endian_type;

                constexpr static const std::size_t value_bits = params_type::value_bits;
                typedef typename boost::uint_t<value_bits>::least value_type;
                BOOST_STATIC_ASSERT(input_block_bits % value_bits == 0);
                constexpr static const std::size_t block_values = input_block_bits / value_bits;
                typedef std::array<value_type, block_values> value_array_type;

            private:
                constexpr static const std::size_t length_bits = params_type::length_bits;
                // FIXME: do something more intelligent than capping at 64
                constexpr static const std::size_t length_type_bits =
                    length_bits < input_block_bits ? input_block_bits : length_bits > 64 ? 64 : length_bits;
                typedef typename boost::uint_t<length_type_bits>::least length_type;

                BOOST_STATIC_ASSERT(!length_bits || length_bits % input_block_bits == 0);
                BOOST_STATIC_ASSERT(output_block_bits % value_bits == 0);

                BOOST_STATIC_ASSERT(!length_bits || value_bits <= length_bits);

            public:
                varlength_block_stream_processor(StateAccumulator &s) : state(s) {
                }

                template<typename InputIterator>
                inline void operator()(InputIterator first, InputIterator last, std::random_access_iterator_tag) {
                    input_block_type block =
                        {};    // TODO: fill it with zero value for base32/64, and find true size for base58
                    ::boost::crypto3::detail::pack_to<endian_type, value_bits, input_value_bits>(
                            first, last, std::inserter(block, block.begin()));
                    state(block);
                }

                template<typename InputIterator, typename Category>
                inline void operator()(InputIterator first, InputIterator last, Category) {
                    input_block_type block = {0};
                    ::boost::crypto3::detail::pack_to<endian_type, value_bits, input_value_bits>(
                            first, last, block.begin());
                    state(block);
                }

                template<typename ValueType,
                         typename = typename std::enable_if<std::is_same<ValueType, input_value_type>::value>::type>
                inline void operator()(const ValueType &value) {
                    state(value);
                }

                template<typename InputIterator>
                inline void operator()(InputIterator first, InputIterator last) {
                    typedef typename std::iterator_traits<InputIterator>::iterator_category cat;
                    return operator()(first, last, cat());
                }

                template<typename ValueType>
                inline void operator()(const std::initializer_list<ValueType> &il) {
                    return operator()(il.begin(), il.end());
                }

                void reset() {
                }

                StateAccumulator &state;
            };
        }    // namespace codec
    }    // namespace crypto3
}    // namespace boost

#endif    // CRYPTO3_FIXED_BLOCK_STREAM_PROCESSOR_HPP


//==============================================================================
//         Copyright 2003 - 2012   LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 - 2012   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 NT2_LINALG_FUNCTIONS_LAPACK_GENERAL_GEESX_HPP_INCLUDED
#define NT2_LINALG_FUNCTIONS_LAPACK_GENERAL_GEESX_HPP_INCLUDED

#include <nt2/linalg/functions/geesx.hpp>
#include <nt2/linalg/details/lapack/declare/geesx.hpp>
#include <nt2/linalg/functions/details/combine.hpp>
#include <boost/assert.hpp>
#include <boost/dispatch/attributes.hpp>
#include <nt2/include/constants/one.hpp>
#include <nt2/include/functions/height.hpp>
#include <nt2/include/functions/scalar/max.hpp>
#include <nt2/include/functions/of_size.hpp>
#include <nt2/include/functions/resize.hpp>
#include <nt2/include/functions/sqr.hpp>
#include <nt2/include/functions/width.hpp>
#include <nt2/linalg/details/utility/envblocksize.hpp>
#include <nt2/linalg/details/utility/f77_wrapper.hpp>
#include <nt2/linalg/details/utility/workspace.hpp>
#include <nt2/core/container/table/table.hpp>

namespace nt2 { namespace ext
{

//---------------------------------------------Real-double------------------------------------------------//

  /// INTERNAL ONLY - Compute the workspace
  BOOST_DISPATCH_IMPLEMENT  ( geesx_, tag::cpu_
                            , (A0)(S0)(A1)(S1)(A2)(S2)
                            , ((container_<nt2::tag::table_,  double_<A0>, S0 >))             //a
                              ((container_<nt2::tag::table_,  complex_<double_<A1> >, S1 >))  //w
                              ((container_<nt2::tag::table_,  double_<A2>, S2 >))             //u
                            )
  {
    typedef nt2_la_int result_type;

    BOOST_FORCEINLINE result_type operator()( A0& a, A1& w, A2& u) const
    {
      char sort =  'N';
      char sense = 'N';
      char jobu  = 'V';
      nt2_la_int sdim_ = 0;
      result_type info = 0;
      details::workspace<typename A0::value_type> wk;
      nt2_la_int n = nt2::width(a);
      BOOST_ASSERT_MSG(n == nt2_la_int(nt2::height(a)), "input must be square");
      nt2_la_int lda = nt2::max(a.leading_size(), One<size_t>());
      nt2_la_int ldu = nt2::max(u.leading_size(), One<size_t>());
      nt2_la_int liwork = -1;
      NT2_F77NAME(dgeesx) ( &jobu, &sort
                          , &nt2::details::selectall2, &sense
                          , &n, 0 /*a*/
                          , &lda, &sdim_
                          , 0/*wr*/, 0/*wi*/
                          , 0/*u*/, &ldu
                          , 0, 0
                          , wk.main(), details::query()
                          , wk.integers(), &liwork
                          , wk.logicals(), &info);
      nt2_la_int ebs = details::EnvBlockSize(9, "NAME", " ", 0, 0, 0, 0);
      nt2_la_int wn =  nt2::max(ebs, n)*(n+1);
      wk.resize_main(wn);
      wk.resize_integers(1);
      wk.resize_logicals(1);
      info = nt2::geesx(a, w, u, wk);
      return info;
     }
  };

  /// INTERNAL ONLY - Workspace is ready
  BOOST_DISPATCH_IMPLEMENT  ( geesx_, tag::cpu_
                            , (A0)(S0)(A1)(S1)(A2)(S2)(WK)
                            , ((container_<nt2::tag::table_,  double_<A0>, S0 >))             //a
                              ((container_<nt2::tag::table_,  complex_<double_<A1> > , S1 >)) //w
                              ((container_<nt2::tag::table_,  double_<A2>, S2 >))             //u
                              (unspecified_<WK>)                                              //workspace
                            )
  {
     typedef nt2_la_int result_type;

     BOOST_FORCEINLINE result_type operator()( A0& a, A1& w, A2& u, WK& wk) const
     {
       result_type info;
       char sort =  'N';
       char sense = 'N';
       char jobu  = 'V';
       nt2_la_int sdim_ = 0;
       nt2_la_int n = nt2::width(a);
       BOOST_ASSERT_MSG(n == nt2_la_int(nt2::height(a)), "input must be square");
       nt2_la_int lda = nt2::max(a.leading_size(), One<size_t>());
       nt2_la_int ldu = nt2::max(u.leading_size(), One<size_t>());
       nt2::container::table<double> wr(of_size(n, 1)), wi(of_size(n, 1));
       nt2_la_int ebs = details::EnvBlockSize(9, "NAME", " ", 0, 0, 0, 0);
       nt2_la_int wn =  nt2::max(ebs, n)*(n+1);
       nt2_la_int wint = wk.integers_need();
       NT2_F77NAME(dgeesx) ( &jobu, &sort
                           , nt2::details::selectall2, &sense
                           , &n, a.data()
                           , &lda, &sdim_
                           , wr.data(), wi.data()
                           , u.data(), &ldu
                           , 0, 0
                           , wk.main(), &wn
                           , wk.integers(), &wint
                           , wk.logicals(), &info);
       combine_eigens(wr, wi, w);
       return info;
     }
  };

//---------------------------------------------Real-single------------------------------------------------//
  /// INTERNAL ONLY - Compute the workspace
  BOOST_DISPATCH_IMPLEMENT  ( geesx_, tag::cpu_
                            , (A0)(S0)(A1)(S1)(A2)(S2)
                            , ((container_<nt2::tag::table_,  single_<A0>, S0 >))              //a
                              ((container_<nt2::tag::table_,  complex_<single_<A1> > , S1 >))  //w
                              ((container_<nt2::tag::table_,  single_<A2>, S2 >))              //u
                            )
  {
    typedef nt2_la_int result_type;

    BOOST_FORCEINLINE result_type operator()( A0& a, A1& w, A2& u) const
    {
      result_type info = 0;
      char sort =  'N';
      char sense = 'N';
      char jobu =  'V';
      details::workspace<typename A0::value_type> wk;
      nt2_la_int n = nt2::width(a);
      BOOST_ASSERT_MSG(n == nt2_la_int(nt2::height(a)), "input must be square");
      nt2_la_int lda   = a.leading_size();
      nt2_la_int ldu   = nt2::max(u.leading_size(), One<size_t>());
      nt2_la_int sdim_ = 0;
      nt2_la_int liwork = -1;
      NT2_F77NAME(sgeesx) ( &jobu, &sort
                          , &nt2::details::selectall2, &sense
                          , &n, 0 /*a*/
                          , &lda, &sdim_
                          , 0/*wr*/, 0/*wi*/
                          , 0/*u*/, &ldu
                          , 0, 0
                          , wk.main(), details::query()
                          , wk.integers(), &liwork
                          , wk.logicals(), &info);
      nt2_la_int ebs = details::EnvBlockSize(9, "NAME", " ", 0, 0, 0, 0);
      nt2_la_int wn =  nt2::max(ebs, n)*(n+1);
      wk.resize_main(wn);
      wk.resize_integers(1);
      wk.resize_logicals(1);
      info = nt2::geesx(a, w, u, wk);
      return info;
     }
  };

  /// INTERNAL ONLY - Workspace is ready
  BOOST_DISPATCH_IMPLEMENT  ( geesx_, tag::cpu_
                            , (A0)(S0)(A1)(S1)(A2)(S2)(WK)
                            , ((container_<nt2::tag::table_,  single_<A0>, S0 >))             //a
                              ((container_<nt2::tag::table_,  complex_<single_<A1> >, S1 >))  //w
                              ((container_<nt2::tag::table_,  single_<A2>, S2 >))             //u
                              (unspecified_<WK>)                                              //workspace
                            )
  {
     typedef nt2_la_int result_type;

    BOOST_FORCEINLINE result_type operator()( A0& a, A1& w, A2& u, WK& wk) const
     {
       result_type info = 0;
       char sort =  'N';
       char sense = 'N';
       char jobu  = 'V';
       nt2_la_int n = nt2::width(a);
       BOOST_ASSERT_MSG(n == nt2_la_int(nt2::height(a)), "input must be square");
       nt2_la_int lda = a.leading_size();
       nt2_la_int ldu = nt2::max(u.leading_size(), One<size_t>());
       nt2_la_int sdim_ = 0;
       nt2::container::table<float> wr(of_size(n, 1)), wi(of_size(n, 1));
       nt2_la_int ebs = details::EnvBlockSize(9, "NAME", " ", 0, 0, 0, 0);
       nt2_la_int wn =  nt2::max(ebs, n)*(n+1);
       nt2_la_int wint = wk.integers_need();
       NT2_F77NAME(sgeesx) ( &jobu, &sort
                           , nt2::details::selectall2, &sense
                           , &n, a.data()
                           , &lda, &sdim_
                           , wr.data(), wi.data()
                           , u.data(), &ldu
                           , 0, 0
                           , wk.main(), &wn
                           , wk.integers(), &wint
                           , wk.logicals(), &info);

       combine_eigens(wr, wi, w);
       return info;
     }
  };

  //////////////////////////////////////// Complex /////////////////////////////////////////////////////////

//---------------------------------------------Complex-single------------------------------------------------//

  /// INTERNAL ONLY - Compute the workspace
  BOOST_DISPATCH_IMPLEMENT  ( geesx_, tag::cpu_
                            , (A0)(S0)(A1)(S1)(A2)(S2)
                            , ((container_<nt2::tag::table_,  complex_<single_<A0> >, S0 >)) //a
                              ((container_<nt2::tag::table_,  complex_<single_<A1> >, S1 >)) //w
                              ((container_<nt2::tag::table_,  complex_<single_<A2> >, S2 >)) //u
                            )
  {
    typedef nt2_la_int result_type;

    BOOST_FORCEINLINE result_type operator()( A0& a, A1& w, A2& u) const
    {
      char sort =  'N';
      char sense = 'N';
      char jobu  = 'V';
      result_type info;
      details::workspace<typename A0::value_type> wk;
      nt2_la_int n = nt2::width(a);
      BOOST_ASSERT_MSG(n == nt2_la_int(nt2::width(a)), "input must be square");
      nt2_la_int lda = nt2::max(a.leading_size(), One<size_t>());
      nt2_la_int ldu = nt2::max(u.leading_size(), One<size_t>());
      nt2_la_int sdim_ = 0;
      NT2_F77NAME(cgeesx) ( &jobu, &sort
                          , nt2::details::selectall, &sense
                          , &n, 0
                          , &lda, &sdim_
                          , 0, 0
                          , &ldu, 0
                          , 0, wk.main()
                          , details::query(), wk.reals()
                          , wk.logicals(), &info);
      wk.prepare_main();
      wk.resize_main(nt2::sqr(n+1));
      wk.resize_reals(n);
      wk.resize_logicals(n);
      info = nt2::geesx(a, w, u, wk);
      return info;
    }
  };

  /// INTERNAL ONLY - Workspace is ready
  BOOST_DISPATCH_IMPLEMENT  ( geesx_, tag::cpu_
                            , (A0)(S0)(A1)(S1)(A2)(S2)(WK)
                            , ((container_<nt2::tag::table_,  complex_<single_<A0> >, S0 >)) //a
                              ((container_<nt2::tag::table_,  complex_<single_<A1> >, S1 >)) //ws
                              ((container_<nt2::tag::table_,  complex_<single_<A2> >, S2 >)) //u
                              (unspecified_<WK>)                                             //workspace
                            )
 {
     typedef nt2_la_int result_type;

    BOOST_FORCEINLINE result_type operator()( A0& a, A1& w, A2& u, WK& wk) const
    {
      char sort =  'N';
      char sense = 'N';
      char jobu  = 'V';
      result_type info;
      nt2_la_int n = nt2::width(a);
      BOOST_ASSERT_MSG(n == nt2_la_int(nt2::width(a)), "input must be square");
      nt2_la_int lda = nt2::max(a.leading_size(), One<size_t>());
      nt2_la_int ldu = nt2::max(u.leading_size(), One<size_t>());
      nt2_la_int sdim_ = 0;
      nt2_la_int wn = nt2::sqr(n+1);
      NT2_F77NAME(cgeesx) ( &jobu, &sort
                          , nt2::details::selectall, &sense
                          , &n, a.data()
                          , &lda, &sdim_
                          , w.data(), u.data()
                          , &ldu, 0
                          , 0, wk.main()
                          , &wn, wk.reals()
                          , wk.logicals(), &info
                          );
      return info;
    }
  };

//---------------------------------------------Complex-double------------------------------------------------//

  /// INTERNAL ONLY - Compute the workspace
  BOOST_DISPATCH_IMPLEMENT  ( geesx_, tag::cpu_
                            , (A0)(S0)(A1)(S1)(A2)(S2)
                            , ((container_<nt2::tag::table_,  complex_<double_<A0> >, S0 >)) //a
                              ((container_<nt2::tag::table_,  complex_<double_<A1> >, S1 >)) //w
                              ((container_<nt2::tag::table_,  complex_<double_<A2> >, S2 >)) //u
                            )
  {
    typedef nt2_la_int result_type;

    BOOST_FORCEINLINE result_type operator()( A0& a, A1& w
                                            , A2& u
                                            ) const
    {
      char sort =  'N';
      char sense = 'N';
      char jobu  = 'V';
      result_type info;
      details::workspace<typename A0::value_type> wk;
      nt2_la_int n = nt2::width(a);
      BOOST_ASSERT_MSG(n == nt2_la_int(nt2::width(a)), "input must be square");
      nt2_la_int lda = a.leading_size();
      nt2_la_int ldu =  nt2::max(u.leading_size(), One<size_t>());
      nt2_la_int sdim_ = 0;
      NT2_F77NAME(zgeesx) ( &jobu, &sort
                          , nt2::details::selectall, &sense
                          , &n, 0
                          , &lda, &sdim_
                          , 0, 0
                          , &ldu, 0
                          , 0, wk.main()
                          , details::query(), wk.reals()
                          , wk.logicals(), &info);
      wk.prepare_main();
      wk.resize_reals(n);
      wk.resize_logicals(n);
      wk.resize_main(nt2::sqr(n+1));
      info = nt2::geesx(a, w, u, wk);
      return info;
    }
  };

  /// INTERNAL ONLY - Workspace is ready
  BOOST_DISPATCH_IMPLEMENT  ( geesx_, tag::cpu_
                            , (A0)(S0)(A1)(S1)(A2)(S2)(WK)
                            , ((container_<nt2::tag::table_,  complex_<double_<A0> >, S0 >)) //a
                              ((container_<nt2::tag::table_,  complex_<double_<A1> >, S1 >)) //w
                              ((container_<nt2::tag::table_,  complex_<double_<A2> >, S2 >)) //u
                              (unspecified_<WK>)                                             //workspace
                            )
 {
     typedef nt2_la_int result_type;

    BOOST_FORCEINLINE result_type operator()( A0& a, A1& w, A2& u, WK& wk) const
    {
      char sort =  'N';
      char sense = 'N';
      char jobu  = 'V';
      result_type info;
      nt2_la_int n = nt2::width(a);
      BOOST_ASSERT_MSG(n == nt2_la_int(nt2::width(a)), "input must be square");
      nt2_la_int lda = a.leading_size();
      nt2_la_int ldu =  nt2::max(u.leading_size(), One<size_t>());
      nt2_la_int sdim_ = 0;
      w.resize(of_size(n, 1));
      u.resize(of_size(n, n));
      nt2_la_int wn =  nt2::sqr(n+1);
      NT2_F77NAME(zgeesx) ( &jobu, &sort
                          , nt2::details::selectall, &sense
                          , &n, a.data()
                          , &lda, &sdim_
                          , w.data(), u.data()
                          , &ldu, 0
                          , 0, wk.main()
                          , &wn, wk.reals()
                          , wk.logicals(), &info
                          );
      return info;
     }
  };

} }

#endif