/*=========================================================================
 *
 *  Copyright David Doria 2011 daviddoria@gmail.com
 *
 *  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.txt
 *
 *  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.
 *
 *=========================================================================*/

// Custom
#include "ImageProcessing/Mask.h"
#include "Helpers/ITKHelpers.h"
#include "PixelDescriptors/ImagePatchPixelDescriptor.h"
#include "NearestNeighbor/LinearSearchKNNProperty.hpp"
#include "Initializers/InitializeFromMaskImage.hpp"
#include "DifferenceFunctions/ImagePatchDifference.hpp"
#include "DifferenceFunctions/SumAbsolutePixelDifference.hpp"
#include "Interactive/TopPatchesDialog.h"
#include "Visitors/DescriptorVisitors/ImagePatchDescriptorVisitor.hpp"

// Boost
#include <boost/graph/grid_graph.hpp>
#include <boost/property_map/property_map.hpp>

// Qt
#include <QApplication>

// ITK
#include "itkImage.h"
#include "itkImageFileReader.h"

typedef itk::VectorImage<float, 2> ImageType;

struct DemoDriver
{

  typedef boost::grid_graph<2> VertexListGraphType;
  typedef boost::graph_traits<VertexListGraphType>::vertex_descriptor VertexDescriptorType;
  typedef ImagePatchPixelDescriptor<ImageType> ImagePatchPixelDescriptorType;
  typedef boost::property_map<VertexListGraphType, boost::vertex_index_t>::const_type IndexMapType;
  typedef boost::vector_property_map<ImagePatchPixelDescriptorType, IndexMapType> ImagePatchDescriptorMapType;
  typedef ImagePatchDescriptorVisitor<VertexListGraphType, ImageType, ImagePatchDescriptorMapType> VisitorType;
  typedef LinearSearchKNNProperty<ImagePatchDescriptorMapType,
                                  ImagePatchDifference<ImagePatchPixelDescriptorType, SumAbsolutePixelDifference<ImageType::PixelType> > > KNNSearchType;
  VertexListGraphType* graph;

  unsigned int PatchRadius;

  ImageType* Image;
  Mask* MaskImage;

  VisitorType* Visitor;

  KNNSearchType* KNNSearch;

  ImagePatchDescriptorMapType* ImagePatchDescriptorMap;

  DemoDriver(ImageType* const image, Mask* const mask) : graph(NULL), PatchRadius(15), Image(image), MaskImage(mask)
  {
    boost::array<std::size_t, 2> graphSideLengths = { { image->GetLargestPossibleRegion().GetSize()[0],
                                                        image->GetLargestPossibleRegion().GetSize()[1] } };
    //VertexListGraphType graph(graphSideLengths);
    graph = new VertexListGraphType(graphSideLengths);

    // Get the index map
    IndexMapType indexMap(get(boost::vertex_index, *graph));

    // Create the descriptor map. This is where the data for each pixel is stored.
    ImagePatchDescriptorMap = new ImagePatchDescriptorMapType(num_vertices(*graph), indexMap);

    Visitor = new VisitorType(Image, MaskImage, *ImagePatchDescriptorMap, PatchRadius);

    InitializeFromMaskImage<VisitorType, VertexDescriptorType>(MaskImage, Visitor);

    // Create the nearest neighbor finders
    KNNSearch = new KNNSearchType(*ImagePatchDescriptorMap, 1000, 2);
  }

  void DisplayTopPatches(VertexDescriptorType targetNode)
  {
    Visitor->DiscoverVertex(targetNode);

    std::vector<VertexDescriptorType> bestSourceNodes;
    typename boost::graph_traits<VertexListGraphType>::vertex_iterator vi,vi_end;
    tie(vi,vi_end) = vertices(*graph);
    (*KNNSearch)(vi, vi_end, targetNode, bestSourceNodes.begin());
    std::cout << "There are " << bestSourceNodes.size() << " bestSourceNodes." << std::endl;

    ImagePatchDifference<ImagePatchPixelDescriptorType, SumAbsolutePixelDifference<ImageType::PixelType> > patchDifferenceFunctor;
    float patchDifference = patchDifferenceFunctor(get(*ImagePatchDescriptorMap, targetNode),
                                                   get(*ImagePatchDescriptorMap, bestSourceNodes[0]));
    std::cout << "Best patch error: " << patchDifference << std::endl;

    // Compute the average of the valid pixels in the target region
    std::vector<itk::Index<2> > validPixelsTargetRegion = MaskImage->GetValidPixelsInRegion(get(*ImagePatchDescriptorMap,
                                                                                targetNode).GetRegion());
    typename ImageType::PixelType targetRegionSourcePixelVariance =
                ITKHelpers::VarianceOfPixelsAtIndices(Image, validPixelsTargetRegion);
    std::cout << "targetRegionSourcePixelVariance: " << targetRegionSourcePixelVariance << std::endl;

    // Compute the average of the pixels in the source region corresponding to hole pixels in the target region.
    std::vector<itk::Offset<2> > holeOffsets = MaskImage->GetHoleOffsetsInRegion(
            get(*ImagePatchDescriptorMap, targetNode).GetRegion());

    std::vector<itk::Index<2> > sourcePatchValidPixels =
           ITKHelpers::OffsetsToIndices(holeOffsets, get(*ImagePatchDescriptorMap, bestSourceNodes[0]).GetRegion().GetIndex());
    typename ImageType::PixelType sourceRegionTargetPixelVariance =
            ITKHelpers::VarianceOfPixelsAtIndices(Image, sourcePatchValidPixels);
    std::cout << "sourceRegionTargetPixelVariance: " << sourceRegionTargetPixelVariance << std::endl;

    TopPatchesDialog<ImageType>* topPatchesDialog = new TopPatchesDialog<ImageType>(Image, MaskImage, PatchRadius);
    topPatchesDialog->SetQueryNode(targetNode);
    topPatchesDialog->SetSourceNodes(bestSourceNodes);
    //topPatchesDialog->exec();
    topPatchesDialog->show();

    // Return the node to an invalid state
    ImagePatchPixelDescriptorType& descriptor = get(*ImagePatchDescriptorMap, targetNode);
    descriptor.SetStatus(PixelDescriptor::INVALID);
  }

};

int main(int argc, char *argv[])
{
  if(argc != 3)
    {
    std::cerr << "Required arguments: image mask" << std::endl;
    return EXIT_FAILURE;
    }

  std::string imageFileName = argv[1];
  std::string maskFileName = argv[2];

  typedef itk::ImageFileReader<ImageType> ImageReaderType;
  ImageReaderType::Pointer imageReader = ImageReaderType::New();
  imageReader->SetFileName(imageFileName);
  imageReader->Update();

  std::cout << "There are " << imageReader->GetOutput()->GetNumberOfComponentsPerPixel()
            << " components per image pixel." << std::endl;

  typedef itk::ImageFileReader<Mask> MaskReaderType;
  MaskReaderType::Pointer maskReader = MaskReaderType::New();
  maskReader->SetFileName(maskFileName);
  maskReader->Update();

  // Setup the GUI system
  QApplication app( argc, argv );

  DemoDriver demoDriver(imageReader->GetOutput(), maskReader->GetOutput());

  std::cout << "Good patch:" << std::endl;
  itk::Index<2> centerGood = {{503,156}};
  DemoDriver::VertexDescriptorType goodTargetNode = Helpers::ConvertFrom<DemoDriver::VertexDescriptorType,
                                                                         itk::Index<2> >(centerGood);
  demoDriver.DisplayTopPatches(goodTargetNode);

  std::cout << "Bad patch:" << std::endl;
   itk::Index<2> centerBad = {{503,146}}; // The top 1000 matches to this patch are completely wrong
  // itk::Index<2> centerBad = {{503,147}}; // This also has 0/1000 good matches
  //itk::Index<2> centerBad = {{503,155}}; // This works fine
  DemoDriver::VertexDescriptorType badTargetNode = Helpers::ConvertFrom<DemoDriver::VertexDescriptorType,
                                                                        itk::Index<2> >(centerBad);
  demoDriver.DisplayTopPatches(badTargetNode);

  app.exec();

  return EXIT_SUCCESS;
}


/*
 [auto_generated]
 boost/numeric/odeint/stepper/generation.hpp

 [begin_description]
 Forward header for the factory functions. Includes all files from the generation directory.
 [end_description]

 Copyright 2011 Karsten Ahnert
 Copyright 2011 Mario Mulansky

 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 BOOST_NUMERIC_ODEINT_STEPPER_GENERATION_HPP_INCLUDED
#define BOOST_NUMERIC_ODEINT_STEPPER_GENERATION_HPP_INCLUDED

#include <boost/numeric/odeint/stepper/generation/make_controlled.hpp>
#include <boost/numeric/odeint/stepper/generation/make_dense_output.hpp>

#include <boost/numeric/odeint/stepper/generation/generation_controlled_runge_kutta.hpp>
#include <boost/numeric/odeint/stepper/generation/generation_dense_output_runge_kutta.hpp>

#include <boost/numeric/odeint/stepper/generation/generation_runge_kutta_cash_karp54_classic.hpp>
#include <boost/numeric/odeint/stepper/generation/generation_runge_kutta_cash_karp54.hpp>
#include <boost/numeric/odeint/stepper/generation/generation_runge_kutta_dopri5.hpp>
#include <boost/numeric/odeint/stepper/generation/generation_runge_kutta_fehlberg78.hpp>

#include <boost/numeric/odeint/stepper/generation/generation_rosenbrock4.hpp>

#endif // BOOST_NUMERIC_ODEINT_STEPPER_GENERATION_HPP_INCLUDED


/* $Id: test_formula_function.cpp 48153 2011-01-01 15:57:50Z mordante $ */
/*
   Copyright (C) 2010 - 2011 by Mark de Wever <koraq@xs4all.nl>
   Part of the Battle for Wesnoth Project http://www.wesnoth.org/

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY.

   See the COPYING file for more details.
*/

#define GETTEXT_DOMAIN "wesnoth-test"

#include <boost/test/unit_test.hpp>

#include "formula_function.hpp"

#include <cmath>

BOOST_AUTO_TEST_SUITE(formula_function)

BOOST_AUTO_TEST_CASE(test_formula_function_substring)
{
	BOOST_CHECK_EQUAL(
			game_logic::formula("substring('hello world', 0)")
				.evaluate().as_string()
			, "hello world");

	BOOST_CHECK_EQUAL(
			game_logic::formula("substring('hello world', 6)")
				.evaluate().as_string()
			, "world");

	BOOST_CHECK_EQUAL(
			game_logic::formula("substring('hello world', 11)")
				.evaluate().as_string()
			, "");

	BOOST_CHECK_EQUAL(
			game_logic::formula("substring('hello world', -1)")
				.evaluate().as_string()
			, "d");

	BOOST_CHECK_EQUAL(
			game_logic::formula("substring('hello world', -5)")
				.evaluate().as_string()
			, "world");

	BOOST_CHECK_EQUAL(
			game_logic::formula("substring('hello world', -11)")
				.evaluate().as_string()
			, "hello world");

	BOOST_CHECK_EQUAL(
			game_logic::formula("substring('hello world', -12)")
				.evaluate().as_string()
			, "hello world");

	BOOST_CHECK_EQUAL(
			game_logic::formula("substring('hello world', 0, 0)")
				.evaluate().as_string()
			, "");

	BOOST_CHECK_EQUAL(
			game_logic::formula("substring('hello world', 0, -1)")
				.evaluate().as_string()
			, "");

	BOOST_CHECK_EQUAL(
			game_logic::formula("substring('hello world', 5, 1)")
				.evaluate().as_string()
			, " ");

	BOOST_CHECK_EQUAL(
			game_logic::formula("substring('hello world', 1, 9)")
				.evaluate().as_string()
			, "ello worl");

	BOOST_CHECK_EQUAL(
			game_logic::formula("substring('hello world', -10, 9)")
				.evaluate().as_string()
			, "ello worl");

}

BOOST_AUTO_TEST_CASE(test_formula_function_length)
{
	BOOST_CHECK_EQUAL(
			  game_logic::formula("length('')").evaluate().as_int()
			, 0);

	BOOST_CHECK_EQUAL(
			  game_logic::formula("length('hello world')").evaluate().as_int()
			, 11);
}

BOOST_AUTO_TEST_CASE(test_formula_function_concatenate)
{
	BOOST_CHECK_EQUAL(
			  game_logic::formula("concatenate(100)").evaluate().as_string()
			, "100");

	BOOST_CHECK_EQUAL(
			  game_logic::formula("concatenate(100, 200, 'a')")
				.evaluate().as_string()
			, "100200a");

	BOOST_CHECK_EQUAL(
			  game_logic::formula("concatenate([1,2,3])")
				.evaluate().as_string()
			, "1, 2, 3");

	BOOST_CHECK_EQUAL(
			  game_logic::formula(
					"concatenate([1.0, 1.00, 1.000, 1.2, 1.23, 1.234])")
						.evaluate().as_string()
			, "1.000, 1.000, 1.000, 1.200, 1.230, 1.234");
}

BOOST_AUTO_TEST_CASE(test_formula_function_sin_cos)
{
	const double pi = 4. * atan(1.);

	game_logic::map_formula_callable variables;

	for(size_t x = 0; x <= 360; ++x) {
		variables.add("x", variant(x));

		BOOST_CHECK_EQUAL(
			  game_logic::formula("sin(x)")
				.evaluate(variables).as_decimal()
			, static_cast<int>(1000. * sin(x * pi / 180.)));

		BOOST_CHECK_EQUAL(
			  game_logic::formula("cos(x)")
				.evaluate(variables).as_decimal()
			, static_cast<int>(1000. * cos(x * pi / 180.)));
	}
}

BOOST_AUTO_TEST_SUITE_END()


#ifndef VANILLA_INIT_H
#define VANILLA_INIT_H

#include <iostream>
#include <boost/multi_array.hpp>
#include "boost/array.hpp"
#include <boost/next_prior.hpp>
#include "boost/cstdlib.hpp"
#include <boost/random.hpp>
#include <boost/random/normal_distribution.hpp>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/variate_generator.hpp>
#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/io.hpp>
#include <ctime>

class init
{
public:
    template <typename Array>
    void ones(Array& A)
    {
        const auto n = A.data() + A.num_elements();
        for (auto i = A.data(); i != n; ++i){
            *i = 1.0;
        }
    }

public:
    template <typename Array>
    void normal(Array& A)
    {
        boost::mt19937 gene;
        boost::variate_generator<boost::mt19937, boost::normal_distribution<long double> > gen(gene, boost::normal_distribution<long double>(0.01, 0.02));
        const auto n = A.data() + A.num_elements();
        for (auto i = A.data(); i != n; ++i){
            *i = gen();
        }
    }

public:
    template <typename T>
    void normal(boost::numeric::ublas::matrix<T>& M)
    {
        boost::mt19937 gene;
        boost::variate_generator<boost::mt19937, boost::normal_distribution<long double > > gen(gene, boost::normal_distribution<long double>(0.01, 0.02));
        for (unsigned i = 0; i < M.size1(); ++ i){
            for (unsigned j = 0; j < M.size2(); ++ j){
                M(i, j) = gen();
            }
        }

    }
};
#endif


/*******************************************************************************
 *
 * Resolution of a system of linear constraints over the domain of intervals
 * is based on W. Harvey & P. J. Stuckey's paper: Improving linear constraint
 * propagation by changing constraint representation, in Constraints,
 * 8(2):173–207, 2003.
 *
 * Author: Arnaud J. Venet (arnaud.j.venet@nasa.gov)
 *
 * Contributors: Alexandre C. D. Wimmers (alexandre.c.wimmers@nasa.gov)
 *               Jorge Navas (jorge.navas@sri.com)
 * Notices:
 *
 * Copyright (c) 2011 United States Government as represented by the
 * Administrator of the National Aeronautics and Space Administration.
 * All Rights Reserved.
 *
 * Disclaimers:
 *
 * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF
 * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED
 * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS,
 * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
 * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE
 * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO
 * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN
 * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS,
 * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS
 * RESULTING FROM USE OF THE SUBJECT SOFTWARE.  FURTHER, GOVERNMENT AGENCY
 * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE,
 * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS."
 *
 * Waiver and Indemnity:  RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST
 * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL
 * AS ANY PRIOR RECIPIENT.  IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS
 * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH
 * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM,
 * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD
 * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS,
 * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW.
 * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE,
 * UNILATERAL TERMINATION OF THIS AGREEMENT.
 *
 ******************************************************************************/

#pragma once

#include <vector>
#include <set>
#include <map>
#include <boost/optional.hpp>
#include <crab/common/types.hpp>
#include <crab/common/debug.hpp>
#include <crab/common/stats.hpp>
#include <crab/common/bignums.hpp>
#include <crab/common/wrapint.hpp>
#include <crab/domains/linear_constraints.hpp>

namespace ikos {

  // Interval traits:
  // The solver is parametric on the kind of Interval
  namespace linear_interval_solver_impl {
    // gamma(i) \ gamma(j)
    template<typename Interval>
    inline Interval trim_interval(Interval i, Interval j);

    template<typename Interval, typename Number>
    inline Interval mk_interval(Number n, typename crab::wrapint::bitwidth_t bitwidth) {
      // default implementation ignores bitwidth
      return Interval(n);
    }

    template<typename Interval>
    Interval lower_half_line(Interval i, bool is_signed);

    template<typename Interval>
    Interval upper_half_line(Interval i, bool is_signed);
  }

  template< typename Number, typename VariableName, typename IntervalCollection >
  class linear_interval_solver {

  public:
    typedef typename IntervalCollection::value_type Interval;
    typedef variable< Number, VariableName > variable_t;
    typedef linear_expression< Number, VariableName > linear_expression_t;
    typedef linear_constraint< Number, VariableName > linear_constraint_t;
    typedef linear_constraint_system< Number, VariableName > linear_constraint_system_t;
    typedef typename variable_t::bitwidth_t bitwidth_t;

  private:
    typedef std::vector< linear_constraint_t > cst_table_t;
    typedef std::set< unsigned int > uint_set_t;
    typedef std::map< variable_t, uint_set_t > trigger_table_t;
    typedef typename linear_constraint_t::variable_set_t variable_set_t;

  private:
    class bottom_found { };

  private:
    std::size_t _max_cycles;
    std::size_t _max_op;
    bool _is_contradiction;
    bool _is_large_system;
    cst_table_t _cst_table;
    trigger_table_t _trigger_table;
    variable_set_t _refined_variables;
    std::size_t _op_count;

  private:
    static const std::size_t _large_system_cst_threshold = 3;
    // cost of one propagation cycle for a dense 3x3 system of constraints
    static const std::size_t _large_system_op_threshold = 27;

  private:
    void refine(variable_t v, Interval i, IntervalCollection& env) {
      crab::ScopedCrabStats __st__("Linear Interval Solver.Solving refinement");
      CRAB_LOG("integer-solver",
	       crab::outs() << "\tRefine " << v << " with " << i << "\n";);
      Interval old_i = env[v];
      Interval new_i = old_i & i;
      CRAB_LOG("integer-solver",
	       crab::outs() << "\tOld=" << old_i << " New=" << new_i << "\n";);
      if (new_i.is_bottom()) {
	throw bottom_found();
      }
      if (!(old_i == new_i)) {
	env.set(v, new_i);
	this->_refined_variables += v;
	++(this->_op_count);
      }
    }

    Interval compute_residual(const linear_constraint_t &cst, variable_t pivot,
                              IntervalCollection& env) {
      crab::ScopedCrabStats __st__("Linear Interval Solver.Solving computing residual");
      namespace interval_traits = linear_interval_solver_impl;
      bitwidth_t w = pivot.get_bitwidth();
      Interval residual= interval_traits::mk_interval<Interval>(cst.constant(), w);
      for (typename linear_constraint_t::iterator it = cst.begin(); it != cst.end(); ++it) {
	variable_t v = it->second;
	if (!(v == pivot)) {
	  residual = residual - (interval_traits::mk_interval<Interval>(it->first, w) * env[v]);
	  ++(this->_op_count);
	  if (residual.is_top()) break;
	}
      }
      return residual;
    }

    void propagate(const linear_constraint_t &cst, IntervalCollection& env) {
      crab::ScopedCrabStats __st__("Linear Interval Solver.Solving propagation");
      namespace interval_traits = linear_interval_solver_impl;

      CRAB_LOG("integer-solver",
	       linear_constraint_t tmp(cst);
	       crab::outs() << "Integer solver processing " << tmp << "\n";);

      for (typename linear_constraint_t::iterator it = cst.begin(), et = cst.end();
	   it != et; ++it) {
	Number c = it->first;
	variable_t pivot = it->second;
	Interval res = compute_residual(cst, pivot, env);
	Interval rhs = Interval::top();
	if (!res.is_top()) {
	  Interval ic = interval_traits::mk_interval<Interval>(c, pivot.get_bitwidth());
	  rhs = res / ic;
	}

	if (cst.is_equality()) {
	  refine(pivot, rhs, env);
	} else if (cst.is_inequality()) {
	  if (c > 0) {
	    refine(pivot, interval_traits::lower_half_line(rhs, cst.is_signed()), env);
	  } else {
	    refine(pivot, interval_traits::upper_half_line(rhs, cst.is_signed()), env);
	  }
	} else if (cst.is_strict_inequality()) {
	  // do nothing
	} else {
	  // cst is a disequation
	  Interval old_i = env[pivot];
	  Interval new_i = interval_traits::trim_interval(old_i, rhs);
	  if (new_i.is_bottom()) {
	    throw bottom_found();
	  }
	  if (!(old_i == new_i)) {
	    env.set(pivot, new_i);
	    this->_refined_variables += pivot;
	  }
	  ++(this->_op_count);
	}
      }
    }

    void solve_large_system(IntervalCollection& env) {
      this->_op_count = 0;
      this->_refined_variables.clear();
      for (typename cst_table_t::iterator it = this->_cst_table.begin();
           it != this->_cst_table.end(); ++it) {
	this->propagate(*it, env);
      }
      do {
	variable_set_t vars_to_process(this->_refined_variables);
	this->_refined_variables.clear();
	for (typename variable_set_t::iterator it = vars_to_process.begin();
               it != vars_to_process.end(); ++it) {
	  uint_set_t& csts = this->_trigger_table[*it];
	  for (typename uint_set_t::iterator cst_it = csts.begin();
                 cst_it != csts.end(); ++cst_it) {
	    this->propagate(this->_cst_table.at(*cst_it), env);
	  }
	}
      }
      while (!this->_refined_variables.empty() &&
             this->_op_count <= this->_max_op);
    }

    void solve_small_system(IntervalCollection& env) {
      std::size_t cycle = 0;
      do {
	++cycle;
	this->_refined_variables.clear();
	for (typename cst_table_t::iterator it = this->_cst_table.begin();
               it != this->_cst_table.end(); ++it) {
	  this->propagate(*it, env);
	}
      }
      while (!this->_refined_variables.empty() &&  cycle <= this->_max_cycles);
    }

  public:

    linear_interval_solver(const linear_constraint_system_t &csts, std::size_t max_cycles)
      : _max_cycles(max_cycles),
        _is_contradiction(false),
        _is_large_system(false),
        _op_count(0) {

      crab::ScopedCrabStats __st_a__("Linear Interval Solver");
      crab::ScopedCrabStats __st_b__("Linear Interval Solver.Preprocessing");
      std::size_t op_per_cycle = 0;
      for (typename linear_constraint_system_t::iterator it = csts.begin();
           it != csts.end(); ++it) {
	const linear_constraint_t &cst = *it;
	if (cst.is_contradiction()) {
	  this->_is_contradiction = true;
	  return;
	} else if (cst.is_tautology()) {
	  continue;
	} else {
	  std::size_t cst_size = cst.size();
	  if (cst.is_strict_inequality()) {
	    // convert e < c into {e <= c, e != c}
	    linear_constraint_t c1(cst.expression(), linear_constraint_t::kind_t::INEQUALITY);
	    linear_constraint_t c2(cst.expression(), linear_constraint_t::kind_t::DISEQUATION);
	    this->_cst_table.push_back(c1);
	    this->_cst_table.push_back(c2);
	    cst_size = c1.size() + c2.size();
	  } else {
	    this->_cst_table.push_back(cst);
	  }
	  // cost of one reduction step on the constraint in terms
	  // of accesses to the interval collection
	  op_per_cycle += cst_size * cst_size;
	}
      }

      this->_is_large_system = (this->_cst_table.size() >
                                _large_system_cst_threshold) ||
          (op_per_cycle > _large_system_op_threshold);

      if (!this->_is_contradiction && this->_is_large_system) {
	this->_max_op = op_per_cycle * max_cycles;
	for (unsigned int i = 0; i < this->_cst_table.size(); ++i) {
	  const linear_constraint_t& cst = this->_cst_table.at(i);
	  variable_set_t vars = cst.variables();
	  for (typename variable_set_t::iterator it = vars.begin(); it != vars.end(); ++it) {
	    this->_trigger_table[*it].insert(i);
	  }
	}
      }
    }

    void run(IntervalCollection& env) {
      crab::ScopedCrabStats __st_a__("Linear Interval Solver");
      crab::ScopedCrabStats __st_b__("Linear Interval Solver.Solving");
      if (this->_is_contradiction) {
        env.set_to_bottom();
      } else {
        try {
          if (this->_is_large_system) {
	    this->solve_large_system(env);
          } else {
            this->solve_small_system(env);
          }
        }
        catch (bottom_found& e) {
          env.set_to_bottom();
        }
      }
    }

  }; // class linear_interval_solver

} // namespace ikos


#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE LibmeshVariableField2Tester
#include <boost/test/included/unit_test.hpp>

#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <vector>

#include <LibmeshManager.hpp>
#include <LibmeshVariableField.hpp>

#include <Teuchos_Array.hpp>
#include <Teuchos_ArrayRCP.hpp>
#include <Teuchos_Comm.hpp>
#include <Teuchos_DefaultComm.hpp>
#include <Teuchos_DefaultMpiComm.hpp>
#include <Teuchos_RCP.hpp>

#include <Tpetra_CrsMatrix.hpp>
#include <Tpetra_MultiVector.hpp>

#include <libmesh/cell_hex8.h>
#include <libmesh/dof_map.h>
#include <libmesh/enum_elem_type.h>
#include <libmesh/equation_systems.h>
#include <libmesh/explicit_system.h>
#include <libmesh/libmesh.h>
#include <libmesh/linear_partitioner.h>
#include <libmesh/mesh.h>
#include <libmesh/mesh_generation.h>
#include <libmesh/node.h>
#include <libmesh/parallel.h>
#include <libmesh/point.h>
#include <libmesh/quadrature_gauss.h>
#include <libmesh/system.h>

//---------------------------------------------------------------------------//
BOOST_AUTO_TEST_CASE( checkLibmeshVariableField2 )
{
	const std::string argv_string = "unit_test --keep-cout";
	const char *argv_char = argv_string.c_str();
	Teuchos::GlobalMPISession mpiSession(
			&boost::unit_test::framework::master_test_suite().argc,
			&boost::unit_test::framework::master_test_suite().argv);
	auto comm = Teuchos::DefaultComm<int>::getComm();
	auto mpi_comm = Teuchos::rcp_dynamic_cast<const Teuchos::MpiComm<int>>(
			comm);
	auto opaque_comm = mpi_comm->getRawMpiComm();
	auto raw_comm = (*opaque_comm)();
    // Create the mesh.
    BOOST_VERIFY( !libMesh::initialized() );
    libMesh::LibMeshInit libmesh_init( 1, &argv_char, raw_comm );
    BOOST_VERIFY( libMesh::initialized() );
    BOOST_VERIFY( (int)libmesh_init.comm().rank() == comm->getRank() );
    Teuchos::RCP<libMesh::Mesh> mesh =
        Teuchos::rcp( new libMesh::Mesh( libmesh_init.comm() ) );
    libMesh::MeshTools::Generation::build_cube( *mesh, 4, 4, 4, 0.0, 1.0, 0.0,
                                                1.0, 0.0, 1.0, libMesh::HEX8 );

    // Parition the mesh.
    libMesh::LinearPartitioner partitioner;
    partitioner.partition( *mesh );

    // Check libmesh validity.
    mesh->libmesh_assert_valid_parallel_ids();

    // Make a libmesh system. We will put a first order linear basis on the
    // elements for all subdomains.
    std::string var_1_name = "test_var_1";
    std::string var_2_name = "test_var_2";
    libMesh::EquationSystems equation_systems( *mesh );
    libMesh::ExplicitSystem &system =
        equation_systems.add_system<libMesh::ExplicitSystem>( "Test System" );
    int var_1_id = system.add_variable( var_1_name );
    int var_2_id = system.add_variable( var_2_name );
    equation_systems.init();

    // Put some data in the variable.
    int sys_id = system.number();
    libMesh::MeshBase::node_iterator nodes_begin = mesh->local_nodes_begin();
    libMesh::MeshBase::node_iterator nodes_end = mesh->local_nodes_end();
    for ( auto node_it = nodes_begin; node_it != nodes_end; ++node_it )
    {
        auto dof_id = ( *node_it )->dof_number( sys_id, var_1_id, 0 );
        system.solution->set( dof_id, ( *node_it )->id() );
    }
    system.solution->close();
    system.update();

    // Create a vector from the variable over all subdomains.
    LibmeshAdapter::LibmeshManager manager( mesh,
                                             Teuchos::rcpFromRef( system ) );
    auto
        var_vec_1 = manager.createFieldMultiVector( var_1_name );
    auto
        var_vec_2 = manager.createFieldMultiVector( var_2_name );

    // Create a diagonal matrix.
    auto
        matrix = Teuchos::rcp(
            new Tpetra::CrsMatrix<double, int, unsigned long int>(
                var_vec_2->getMap(), 1 ) );
    Teuchos::Array<unsigned long int> support_ids;
    Teuchos::Array<double> support_vals( 1 );
    LibmeshAdapter::LibmeshEntity<libMesh::Node> entity;
    for ( auto node_it = nodes_begin; node_it != nodes_end; ++node_it )
    {
        manager.functionSpace()->entitySet()->getEntity( ( *node_it )->id(),
                                                         entity );
        manager.functionSpace()->shapeFunction()->entitySupportIds(
            entity, support_ids );
        BOOST_VERIFY( 1 == support_ids.size() );
        BOOST_VERIFY( ( *node_it )->id() == support_ids[0] );
        support_vals[0] = support_ids[0];
        matrix->insertGlobalValues( support_ids[0], support_ids(),
                                    support_vals() );
    }
    matrix->fillComplete( var_vec_1->getMap(), var_vec_2->getMap() );

    // Apply the matrix.
    var_vec_1
        ->pullDataFromApplication();
    matrix->apply( *var_vec_1, *var_vec_2 );
    var_vec_2
        ->pushDataToApplication();

    // Test the Libmesh variable.
    for ( auto node = nodes_begin; node != nodes_end; ++node )
    {
        auto dof_id = ( *node )->dof_number( sys_id, var_2_id, 0 );
        BOOST_VERIFY( system.solution->el( dof_id ) ==
                       ( *node )->id() * ( *node )->id() );
    }
}

//---------------------------------------------------------------------------//
// end of tstLibmeshVariableField2.cpp
//---------------------------------------------------------------------------//


/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

#include "MiniAppManager.h"

#include <vector>
#include <iostream>
#include <fstream>
#include <algorithm>
#include <string>

#include <itkImage.h>
#include <itkImageFileReader.h>
#include <itkExceptionObject.h>
#include <itkImageFileWriter.h>
#include <itkMetaDataObject.h>
#include <itkVectorImage.h>
#include <itkResampleImageFilter.h>

#include <mitkBaseDataIOFactory.h>
#include <mitkDiffusionImage.h>
#include <mitkQBallImage.h>
#include <mitkBaseData.h>
#include <mitkDiffusionCoreObjectFactory.h>
#include <mitkFiberTrackingObjectFactory.h>
#include <mitkFiberBundleX.h>
#include "ctkCommandLineParser.h"
#include <boost/lexical_cast.hpp>

#include <itkRadialMultishellToSingleshellImageFilter.h>
#include <itkADCAverageFunctor.h>
#include <itkBiExpFitFunctor.h>
#include <itkKurtosisFitFunctor.h>
#include <mitkNrrdDiffusionImageWriter.h>
#include <itkDwiGradientLengthCorrectionFilter.h>

int MultishellMethods(int argc, char* argv[])
{
  ctkCommandLineParser parser;
  parser.setArgumentPrefix("--", "-");
  parser.addArgument("in", "i", ctkCommandLineParser::String, "input file", us::Any(), false);
  parser.addArgument("out", "o", ctkCommandLineParser::String, "output file", us::Any(), false);
  parser.addArgument("adc", "D", ctkCommandLineParser::Bool, "ADC Average", us::Any(), false);
  parser.addArgument("akc", "K", ctkCommandLineParser::Bool, "Kurtosis Fit", us::Any(), false);
  parser.addArgument("biexp", "B", ctkCommandLineParser::Bool, "BiExp fit", us::Any(), false);
  parser.addArgument("targetbvalue", "b", ctkCommandLineParser::String, "target bValue (mean, min, max)", us::Any(), false);

  map<string, us::Any> parsedArgs = parser.parseArguments(argc, argv);
  if (parsedArgs.size()==0)
    return EXIT_FAILURE;

  // mandatory arguments
  string inName = us::any_cast<string>(parsedArgs["in"]);
  string outName = us::any_cast<string>(parsedArgs["out"]);
  bool applyADC = us::any_cast<bool>(parsedArgs["adc"]);
  bool applyAKC = us::any_cast<bool>(parsedArgs["akc"]);
  bool applyBiExp = us::any_cast<bool>(parsedArgs["biexp"]);
  string targetType = us::any_cast<string>(parsedArgs["targetbvalue"]);

  try
  {
    RegisterDiffusionCoreObjectFactory();
    RegisterFiberTrackingObjectFactory();

    MITK_INFO << "Loading " << inName;
    const std::string s1="", s2="";
    std::vector<mitk::BaseData::Pointer> infile = mitk::BaseDataIO::LoadBaseDataFromFile( inName, s1, s2, false );
    mitk::BaseData::Pointer baseData = infile.at(0);

    if ( dynamic_cast<mitk::DiffusionImage<short>*>(baseData.GetPointer()) )
    {
      MITK_INFO << "Writing " << outName;
      mitk::DiffusionImage<short>::Pointer dwi = dynamic_cast<mitk::DiffusionImage<short>*>(baseData.GetPointer());
      typedef itk::RadialMultishellToSingleshellImageFilter<short, short> FilterType;

      typedef itk::DwiGradientLengthCorrectionFilter  CorrectionFilterType;

      CorrectionFilterType::Pointer roundfilter = CorrectionFilterType::New();
      roundfilter->SetRoundingValue( 1000 );
      roundfilter->SetReferenceBValue(dwi->GetB_Value());
      roundfilter->SetReferenceGradientDirectionContainer(dwi->GetDirections());
      roundfilter->Update();

      dwi->SetB_Value( roundfilter->GetNewBValue() );
      dwi->SetDirections( roundfilter->GetOutputGradientDirectionContainer());

      // filter input parameter
      const mitk::DiffusionImage<short>::BValueMap
          &originalShellMap  = dwi->GetB_ValueMap();

      const mitk::DiffusionImage<short>::ImageType
          *vectorImage       = dwi->GetVectorImage();

      const mitk::DiffusionImage<short>::GradientDirectionContainerType::Pointer
          gradientContainer = dwi->GetDirections();

      const unsigned int
          &bValue            = dwi->GetB_Value();

      // filter call

      vnl_vector<double> bValueList(originalShellMap.size()-1);
      double targetBValue = bValueList.mean();

      mitk::DiffusionImage<short>::BValueMap::const_iterator it = originalShellMap.begin();
      ++it; int i = 0 ;
      for(; it != originalShellMap.end(); ++it)
        bValueList.put(i++,it->first);

      if( targetType == "mean" )
        targetBValue = bValueList.mean();
      else if( targetType == "min" )
        targetBValue = bValueList.min_value();
      else if( targetType == "max" )
        targetBValue = bValueList.max_value();

      if(applyADC)
      {
        FilterType::Pointer filter = FilterType::New();
        filter->SetInput(vectorImage);
        filter->SetOriginalGradientDirections(gradientContainer);
        filter->SetOriginalBValueMap(originalShellMap);
        filter->SetOriginalBValue(bValue);

        itk::ADCAverageFunctor::Pointer functor = itk::ADCAverageFunctor::New();
        functor->setListOfBValues(bValueList);
        functor->setTargetBValue(targetBValue);

        filter->SetFunctor(functor);
        filter->Update();
        // create new DWI image
        mitk::DiffusionImage<short>::Pointer outImage = mitk::DiffusionImage<short>::New();
        outImage->SetVectorImage( filter->GetOutput() );
        outImage->SetB_Value( targetBValue );
        outImage->SetDirections( filter->GetTargetGradientDirections() );
        outImage->InitializeFromVectorImage();

        mitk::NrrdDiffusionImageWriter<short>::Pointer writer = mitk::NrrdDiffusionImageWriter<short>::New();
        writer->SetFileName((string(outName) + "_ADC.dwi"));
        writer->SetInput(outImage);
        writer->Update();
      }
      if(applyAKC)
      {
        FilterType::Pointer filter = FilterType::New();
        filter->SetInput(vectorImage);
        filter->SetOriginalGradientDirections(gradientContainer);
        filter->SetOriginalBValueMap(originalShellMap);
        filter->SetOriginalBValue(bValue);

        itk::KurtosisFitFunctor::Pointer functor = itk::KurtosisFitFunctor::New();
        functor->setListOfBValues(bValueList);
        functor->setTargetBValue(targetBValue);

        filter->SetFunctor(functor);
        filter->Update();
        // create new DWI image
        mitk::DiffusionImage<short>::Pointer outImage = mitk::DiffusionImage<short>::New();
        outImage->SetVectorImage( filter->GetOutput() );
        outImage->SetB_Value( targetBValue );
        outImage->SetDirections( filter->GetTargetGradientDirections() );
        outImage->InitializeFromVectorImage();

        mitk::NrrdDiffusionImageWriter<short>::Pointer writer = mitk::NrrdDiffusionImageWriter<short>::New();
        writer->SetFileName((string(outName) + "_AKC.dwi"));
        writer->SetInput(outImage);
        writer->Update();
      }
      if(applyBiExp)
      {
        FilterType::Pointer filter = FilterType::New();
        filter->SetInput(vectorImage);
        filter->SetOriginalGradientDirections(gradientContainer);
        filter->SetOriginalBValueMap(originalShellMap);
        filter->SetOriginalBValue(bValue);

        itk::BiExpFitFunctor::Pointer functor = itk::BiExpFitFunctor::New();
        functor->setListOfBValues(bValueList);
        functor->setTargetBValue(targetBValue);

        filter->SetFunctor(functor);
        filter->Update();
        // create new DWI image
        mitk::DiffusionImage<short>::Pointer outImage = mitk::DiffusionImage<short>::New();
        outImage->SetVectorImage( filter->GetOutput() );
        outImage->SetB_Value( targetBValue );
        outImage->SetDirections( filter->GetTargetGradientDirections() );
        outImage->InitializeFromVectorImage();

        mitk::NrrdDiffusionImageWriter<short>::Pointer writer = mitk::NrrdDiffusionImageWriter<short>::New();
        writer->SetFileName((string(outName) + "_BiExp.dwi"));
        writer->SetInput(outImage);
        writer->Update();
      }
    }
  }
  catch (itk::ExceptionObject e)
  {
    MITK_INFO << e;
    return EXIT_FAILURE;
  }
  catch (std::exception e)
  {
    MITK_INFO << e.what();
    return EXIT_FAILURE;
  }
  catch (...)
  {
    MITK_INFO << "ERROR!?!";
    return EXIT_FAILURE;
  }
  MITK_INFO << "DONE";
  return EXIT_SUCCESS;
}
RegisterDiffusionMiniApp(MultishellMethods);


/*
 * Copyright 2016 Erik Crevel
 *
 * 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.
 */

#ifndef NORMALENCODINGDISTRIBUTION_HPP
#define NORMALENCODINGDISTRIBUTION_HPP

#include "EncodingDistribution.hpp"

#include <boost/math/distributions/normal.hpp>

class NormalEncodingDistribution : public EncodingDistribution
{
	int encodeRangeStart, encodeRangeSize;

	boost::math::normal dist;

	double start, end;
	double scale;

public:
    NormalEncodingDistribution(std::pair<int, int> _encodeRange, double _mu, double _sigma);

	std::pair<Range, Range> getRange(int _v) const override;
	std::pair<int, std::pair<Range, Range>> getValue(Range _r) const override;
};

#endif // NORMALENCODINGDISTRIBUTION_HPP


// Software License for MTL
//
// Copyright (c) 2007 The Trustees of Indiana University.
//               2008 Dresden University of Technology and the Trustees of Indiana University.
//               2010 SimuNova UG (haftungsbeschränkt), www.simunova.com.
// All rights reserved.
// Authors: Peter Gottschling and Andrew Lumsdaine
//
// This file is part of the Matrix Template Library
//
// See also license.mtl.txt in the distribution.

#include <iostream>
#include <complex>
#include <boost/numeric/mtl/mtl.hpp>
#include <boost/timer.hpp>
#include <boost/mpl/or.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_floating_point.hpp>
#include <boost/type_traits/is_integral.hpp>

using namespace std;
using namespace mtl;

int main(int argc, char* argv[])
{
    typedef complex<double>    cd_type;

    const int               rep= 10000;
    double                  n;
    dense_vector<cd_type>   v(10000, cd_type(3.0, 4.0));

    boost::timer rtime;
    for (int i= 0; i < rep; i++)
	n= two_norm(v);

    cout << "Run time = " << rtime.elapsed() / rep * 1000 << "ms\n"
	 << "Norm is " << n << "\n";

    return 0;
}


///////////////////////////////////////////////////////////////////////////////
// statistics::model::concept::log_likelihood.hpp                            //
//                                                                           //
//  Copyright 2009 Erwann Rogard. 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 BOOST_STATISTICS_MODEL_CONCEPT_HAS_LOG_LIKELIHOOD_HPP_ER_2009
#define BOOST_STATISTICS_MODEL_CONCEPT_HAS_LOG_LIKELIHOOD_HPP_ER_2009
#include <boost/concept_check.hpp>
#include <boost/mpl/empty_base.hpp>
#include <boost/statistics/model/wrap/aggregate/model_data.hpp>

namespace boost{
namespace statistics{
namespace model{

    template<
        typename T,
        typename M,
        typename X,
        typename Y,
        typename P,
        typename B = mpl::empty_base
    >
    class HasLogLikelihood : B
    {
        public:

        BOOST_CONCEPT_USAGE(HasLogLikelihood)
        {
            // TODO
            //T log_likelihood<T>(md, p);
        }

        private:

        model_data_<M,X,Y> md;
        P p;
    };

}// model
}// statistics
}// boost

#endif


/*
 * Copyright 2009-2020 The VOTCA Development Team (http://www.votca.org)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 *
 *     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.
 *
 */

#define BOOST_TEST_MAIN
#define BOOST_TEST_MODULE CudaMatrix_test

// Standard includes
#include <string>

// Third party includes
#include <boost/test/unit_test.hpp>

// Local VOTCA includes
#include "votca/xtp/cudapipeline.h"
#include "votca/xtp/eigen.h"

using namespace votca::xtp;

BOOST_AUTO_TEST_SUITE(CudaMatrix_test)

BOOST_AUTO_TEST_CASE(create_cudamatrix) {
  // Call the class to handle GPU resources
  CudaPipeline cp;

  // Call matrix multiplication GPU
  Eigen::MatrixXd A = Eigen::MatrixXd::Zero(2, 2);
  Eigen::MatrixXd B = Eigen::MatrixXd::Zero(3, 2);
  Eigen::MatrixXd X = Eigen::MatrixXd::Zero(3, 2);

  // Define matrices
  A << 1., 2., 3., 4.;
  B << 5., 6., 7., 8., 9., 10.;
  X << 23., 34., 31., 46., 39., 58.;

  // Copy matrix back and for to the GPU
  CudaMatrix cumatrix{B, cp.get_stream()};
  Eigen::MatrixXd tmp = cumatrix;
  Eigen::MatrixXd result = tmp * A;

  // Expected results
  BOOST_TEST(X.isApprox(result));
}
BOOST_AUTO_TEST_SUITE_END()


#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE "test_accumulator"

#include <boost/test/unit_test.hpp>
#include "nanocv/tasks/task_synthetic_shapes.h"
#include "nanocv/timer.h"
#include "nanocv/logger.h"
#include "nanocv/nanocv.h"
#include "nanocv/math/abs.hpp"
#include "nanocv/math/epsilon.hpp"
#include "nanocv/thread/thread.h"
#include "nanocv/accumulator.h"

namespace test
{
        using namespace ncv;

        bool check_fold(const samples_t& samples, ncv::fold_t fold)
        {
                return std::find_if(samples.begin(), samples.end(),
                       [&] (const sample_t& sample) { return sample.m_fold != fold; }) == samples.end();
        }
}

BOOST_AUTO_TEST_CASE(test_accumulator)
{
        using namespace ncv;

        ncv::init();

        const size_t cmd_samples = 256;
        const size_t cmd_outputs = 5;
        const scalar_t cmd_epsilon = math::epsilon1<scalar_t>();

        synthetic_shapes_task_t task(16, 16, cmd_outputs, color_mode::luma, cmd_samples);
        BOOST_CHECK_EQUAL(task.load(""), true);

        const samples_t samples = task.samples();
        BOOST_CHECK_EQUAL(samples.size(), cmd_samples);

        const string_t lmodel0;
        const string_t lmodel1 = lmodel0 + "linear:dims=32;act-snorm;";
        const string_t lmodel2 = lmodel1 + "linear:dims=32;act-snorm;";

        string_t cmodel;
        cmodel = cmodel + "conv:dims=4,rows=5,cols=5;pool-max;act-snorm;";
        cmodel = cmodel + "conv:dims=8,rows=3,cols=3;pool-max;act-snorm;";

        const string_t outlayer = "linear:dims=" + text::to_string(cmd_outputs) + ";";

        strings_t cmd_networks =
        {
                lmodel0 + outlayer,
                lmodel1 + outlayer,
                lmodel2 + outlayer,

                cmodel + outlayer
        };

        const rloss_t loss = ncv::get_losses().get("logistic");
        BOOST_CHECK_EQUAL(loss.operator bool(), true);

        // check various networks
        for (const string_t& cmd_network : cmd_networks)
        {
                log_info() << "<<< running network [" << cmd_network << "] ...";

                // create feed-forward network
                const rmodel_t model = ncv::get_models().get("forward-network", cmd_network);
                BOOST_CHECK_EQUAL(model.operator bool(), true);
                BOOST_CHECK_EQUAL(model->resize(task, true), true);

                // check various criteria
                const strings_t criteria = ncv::get_criteria().ids();
                for (const string_t& criterion : criteria)
                {
                        model->random_params();

                        const scalar_t lambda = 0.1;

                        // accumulators using 1 thread
                        accumulator_t lacc(*model, 1, criterion, criterion_t::type::value, lambda);
                        accumulator_t gacc(*model, 1, criterion, criterion_t::type::vgrad, lambda);

                        BOOST_CHECK_EQUAL(lacc.lambda(), lambda);
                        BOOST_CHECK_EQUAL(gacc.lambda(), lambda);

                        BOOST_CHECK_EQUAL(lacc.set_lambda(lambda), lambda);
                        BOOST_CHECK_EQUAL(gacc.set_lambda(lambda), lambda);

                        lacc.update(task, samples, *loss);
                        const scalar_t value1 = lacc.value();

                        BOOST_CHECK_EQUAL(lacc.count(), cmd_samples);

                        gacc.update(task, samples, *loss);
                        const scalar_t vgrad1 = gacc.value();
                        const vector_t pgrad1 = gacc.vgrad();

                        BOOST_CHECK_EQUAL(gacc.count(), cmd_samples);
                        BOOST_CHECK(std::isfinite(vgrad1));
                        BOOST_CHECK_LE(math::abs(vgrad1 - value1), cmd_epsilon);

                        // check results with multiple threads
                        for (size_t nthreads = 2; nthreads < 8 * ncv::n_threads(); nthreads ++)
                        {
                                accumulator_t laccx(*model, nthreads, criterion, criterion_t::type::value, lambda);
                                accumulator_t gaccx(*model, nthreads, criterion, criterion_t::type::vgrad, lambda);

                                BOOST_CHECK_EQUAL(laccx.lambda(), lambda);
                                BOOST_CHECK_EQUAL(gaccx.lambda(), lambda);

                                BOOST_CHECK_EQUAL(laccx.set_lambda(lambda), lambda);
                                BOOST_CHECK_EQUAL(gaccx.set_lambda(lambda), lambda);

                                laccx.update(task, samples, *loss);

                                BOOST_CHECK_EQUAL(laccx.count(), cmd_samples);
                                BOOST_CHECK_LE(math::abs(laccx.value() - value1), cmd_epsilon);

                                gaccx.update(task, samples, *loss);

                                BOOST_CHECK_EQUAL(gaccx.count(), cmd_samples);
                                BOOST_CHECK_LE(math::abs(gaccx.value() - vgrad1), cmd_epsilon);
                                BOOST_CHECK_LE((gaccx.vgrad() - pgrad1).lpNorm<Eigen::Infinity>(), cmd_epsilon);
                        }
                }
        }
}


#include <test/test-models/good/variational/hier_logistic_cp.hpp>
#include <stan/variational/advi.hpp>
#include <stan/callbacks/writer.hpp>
#include <stan/callbacks/stream_logger.hpp>
#include <gtest/gtest.h>
#include <test/unit/util.hpp>
#include <vector>
#include <string>
#include <iostream>
#include <boost/random/additive_combine.hpp> // L'Ecuyer RNG

typedef boost::ecuyer1988 rng_t;
typedef hier_logistic_cp_model_namespace::hier_logistic_cp_model Model_cp;

TEST(advi_test, hier_logistic_cp_constraint_meanfield) {
  // Create mock data_var_context
  std::fstream data_stream("src/test/test-models/good/variational/hier_logistic.data.R",
                           std::fstream::in);
  stan::io::dump data_var_context(data_stream);
  data_stream.close();

  std::stringstream output;
  output.clear();

  // Instantiate model
  Model_cp my_model(data_var_context);

  // RNG
  rng_t base_rng(0);

  // Dummy input
  Eigen::VectorXd cont_params = Eigen::VectorXd::Zero(my_model.num_params_r());

  // ADVI
  stan::variational::advi<Model_cp, stan::variational::normal_meanfield, rng_t> test_advi(my_model,
                                                     cont_params,
                                                     base_rng,
                                                     10,
                                                     100,
                                                     100,
                                                     1);

  stan::callbacks::writer writer;
  stan::callbacks::stream_logger logger(output, output, output, output, output);

  test_advi.run(0.01, false, 50, 1, 2e4,
                logger, writer, writer);
}


#include "DQM/TrackingMonitorClient/plugins/TrackingDQMClientHeavyIons.h"

#include "DQMServices/ClientConfig/interface/FitSlicesYTool.h"
#include "DQMServices/Core/interface/MonitorElement.h"
#include "FWCore/ParameterSet/interface/ParameterSet.h"
#include "FWCore/ServiceRegistry/interface/Service.h"
#include "FWCore/MessageLogger/interface/MessageLogger.h"

#include <TH1F.h>
#include <TClass.h>
#include <TString.h>
#include <string>
#include <cmath>
#include <climits>
#include <boost/tokenizer.hpp>

using namespace std;
using namespace edm;

typedef MonitorElement ME;

TrackingDQMClientHeavyIons::TrackingDQMClientHeavyIons(const edm::ParameterSet& pset){

  TopFolder_=pset.getParameter<std::string>("FolderName");
}

void TrackingDQMClientHeavyIons::dqmEndJob(DQMStore::IBooker & ibooker, DQMStore::IGetter & igetter) {

  typedef vector<string> vstring;

  // Update 2014-04-02
  // Migrated back to the endJob. the DQMFileSaver logic has
  // to be reviewed to guarantee that the endJob is properly
  // considered. The splitting per run is done centrally when
  // running the harvesting in production

  // Update 2009-09-23
  // Migrated all code from endJob to this function
  // endJob is not necessarily called in the proper sequence
  // and does not necessarily book histograms produced in
  // that step.
  // It more robust to do the histogram manipulation in
  // this endRun function
  // needed to access the DQMStore::save method

  ibooker.cd();
  ibooker.setCurrentFolder(TopFolder_);

  histName = "DCAStats_";
  DCAStats = ibooker.book2D(histName,histName,2,0,2,4,0,4);
  DCAStats->getTH2F()->GetYaxis()->SetBinLabel(1,"Mean");
  DCAStats->getTH2F()->GetYaxis()->SetBinLabel(2,"RMS, #sigma");
  DCAStats->getTH2F()->GetYaxis()->SetBinLabel(3,"Skewness ,#gamma_{1}");
  DCAStats->getTH2F()->GetYaxis()->SetBinLabel(4,"Kurtosis, #gamma_{2}");
  DCAStats->getTH2F()->GetXaxis()->SetBinLabel(1,"Longitudinal");
  DCAStats->getTH2F()->GetXaxis()->SetBinLabel(2,"Transverse");
  DCAStats->getTH2F()->SetOption("text");

  histName="LongDCASig_HeavyIonTk";
  ME* element = igetter.get(TopFolder_+"/"+histName);
  //Longitudinal First
  DCAStats->getTH2F()->SetBinContent(1,1,element->getTH1F()->GetMean());//mean
  DCAStats->getTH2F()->SetBinContent(1,2,element->getTH1F()->GetRMS());//rms
  DCAStats->getTH2F()->SetBinContent(1,3,element->getTH1F()->GetSkewness());//skewness
  DCAStats->getTH2F()->SetBinContent(1,4,element->getTH1F()->GetKurtosis());//kurtosis
  //Transverse
  histName="TransDCASig_HeavyIonTk";
  ME* element1 = igetter.get(TopFolder_+"/"+histName);
  //Longitudinal First
  DCAStats->getTH2F()->SetBinContent(2,1,element1->getTH1F()->GetMean());//mean
  DCAStats->getTH2F()->SetBinContent(2,2,element1->getTH1F()->GetRMS());//rms
  DCAStats->getTH2F()->SetBinContent(2,3,element1->getTH1F()->GetSkewness());//skewness
  DCAStats->getTH2F()->SetBinContent(2,4,element1->getTH1F()->GetKurtosis());//kurtosis

}


#include "Point3f.h"
#include <cmath>
#include <sstream>
#include <ostream>
#include <cmath>
#include "Constants.h"
#include <boost/lexical_cast.hpp>

namespace ccmc
{
	/**
	 * @param out
	 * @param point
	 * @return
	 */
	std::ostream& operator<<(std::ostream& out, const Point3f& point)
	{
		out << point.toString();
		return out;
	}

	/**
	 * TODO: finish documentation
	 * @param component1
	 * @param component2
	 * @param component3
	 */
	Point3f::Point3f(const float& component1, const float& component2, const float& component3)
	{
		this->component1 = component1;
		this->component2 = component2;
		this->component3 = component3;
		coordinates = Point3f::CARTESIAN;
	}

	/**
	 * TODO: finish documentation
	 * @param component1
	 * @param component2
	 * @param component3
	 */
	Point3f::Point3f(const float& component1, const float& component2, const float& component3, Coordinates c)
	{
		this->component1 = component1;
		this->component2 = component2;
		this->component3 = component3;
		coordinates = c;
	}

	Point3f::Point3f(const Point3f& p)
	{
		this->component1 = p.component1;
		this->component2 = p.component2;
		this->component3 = p.component3;
		coordinates = p.coordinates;
	}

	/**
	 * TODO: finish documentation
	 */
	Point3f::Point3f()
	{
		this->component1 = 0.0;
		this->component2 = 0.0;
		this->component3 = 0.0;
	}

	/**
	 * TODO: finish documentation
	 */
	Point3f::Point3f(Coordinates c)
	{
		this->component1 = 0.0;
		this->component2 = 0.0;
		this->component3 = 0.0;
		coordinates = c;
	}

	/**
	 * TODO: finish documentation
	 */
	Point3f::~Point3f()
	{

	}

	/**
	 * TODO: finish documentation
	 */
	Point3f Point3f::operator+(const Point3f& p) const
	{
		Point3f point;
		point.component1 = component1 + p.component1;
		point.component2 = component2 + p.component2;
		point.component3 = component3 + p.component3;
		point.coordinates = p.coordinates;

		return point;
	}
	/**
	 * Minus operator where sender is on the right
	 * TODO: test this
	 */
	Point3f Point3f::operator-(const Point3f& p) const
	{
		Point3f point;
		point.component1 = component1 - p.component1;
		point.component2 = component2 - p.component2;
		point.component3 = component3 - p.component3;
		point.coordinates = p.coordinates;

		return point;
	}

	/**
	 * TODO: finish documentation
	 */
	Point3f Point3f::operator*(float value) const
	{
		Point3f point;
		point.component1 = component1 * value;
		point.component2 = component2 * value;
		point.component3 = component3 * value;
		point.coordinates = coordinates;
		return point;
	}

	/**
	 * TODO: finish documentation
	 */
	Point3f Point3f::operator*(double value) const
	{
		Point3f point;
		point.component1 = component1 * value;
		point.component2 = component2 * value;
		point.component3 = component3 * value;
		point.coordinates = coordinates;
		return point;
	}

	/** compute the distance between this point, and Point p **/
	/**
	 * TODO: finish documentation
	 */
	float Point3f::distance(const Point3f& p) const
	{
		float dist;

		if (coordinates == Point3f::SPHERICAL)
		{
			//r p t
			float sinTheta1 = std::sin(ccmc::constants::DegreesToRadians*(90.f-component2));
			float cartesianComponent1 = component1 * sinTheta1 * std::cos(ccmc::constants::DegreesToRadians * component3);
			float cartesianComponent2 = component1 * sinTheta1 * std::sin(ccmc::constants::DegreesToRadians * component3);
			float cartesianComponent3 = component1 * std::cos(ccmc::constants::DegreesToRadians * (90.f - component2));

			float sinTheta2 = std::sin(ccmc::constants::DegreesToRadians*(90.f-p.component2));
			float pCartesianComponent1 = p.component1 * sinTheta1 * std::cos(ccmc::constants::DegreesToRadians * p.component3);
			float pCartesianComponent2 = p.component1 * sinTheta1 * std::sin(ccmc::constants::DegreesToRadians * p.component3);
			float pCartesianComponent3 = p.component1 * std::cos(ccmc::constants::DegreesToRadians * (90.f - p.component2));

			float diff1 = cartesianComponent1 - pCartesianComponent1;
			float diff2 = cartesianComponent2 - pCartesianComponent2;
			float diff3 = cartesianComponent3 - pCartesianComponent3;

			dist = std::sqrt(diff1 * diff1 + diff2 * diff2 + diff3 * diff3);
		} else
		{
			dist = std::sqrt((component1 - p.component1) * (component1 - p.component1) + (component2 - p.component2)
					* (component2 - p.component2) + (component3 - p.component3) * (component3 - p.component3));
		}
		return dist;
	}

	/**
	 * TODO: finish documentation
	 */
	void Point3f::normalize()
	{

		float mag = magnitude();
		if (std::abs(mag - 0.0) > .0000001)
		{
			this->component1 /= mag;
			this->component2 /= mag;
			this->component3 /= mag;
		}
	}

	/**
	 * Computes the magnitude of the cartesian vector
	 */
	float Point3f::magnitude()
	{
		return sqrt(component1 * component1 + component2 * component2 + component3 * component3);
	}

	/**
	 * TODO: finish documentation
	 */
	std::string Point3f::toString() const
	{
/*		std::string beg = "(";
		std::string mid = ",";
		std::string end = ")";
		std::ostringstream oss1;
		oss1 << component1;
		std::string scomponent1 = oss1.str();
		std::ostringstream oss2;
		oss2 << component2;
		std::string scomponent2 = oss2.str();
		std::ostringstream oss3;
		oss3 << component3;
		std::string scomponent3 = oss3.str();
		std::string str = beg + scomponent1 + mid + scomponent2 + mid + scomponent3 + end;
		return str;
		*/
		std::string temp_string = "";
		temp_string = "(" + boost::lexical_cast<std::string>(component1) + ",";
		temp_string += boost::lexical_cast<std::string>(component2) + ",";
		temp_string += boost::lexical_cast<std::string>(component3) + ")";
		return temp_string;
	}

	/**
	 * TODO: finish documentation
	 */
	void Point3f::setCoordinates(Point3f::Coordinates c)
	{
		coordinates = c;
	}

	/**
	 * TODO: finish documentation
	 */
	Point3f::Coordinates Point3f::getCoordinates()
	{
		return coordinates;
	}

	Point3f Point3f::getCartesian()
	{
		Point3f cartesian;
		float sinTheta1 = std::sin(ccmc::constants::DegreesToRadians*(90.f-component2));
		cartesian.component1 = component1 * sinTheta1 * std::cos(ccmc::constants::DegreesToRadians * component3);
		cartesian.component2 = component1 * sinTheta1 * std::sin(ccmc::constants::DegreesToRadians * component3);
		cartesian.component3 = component1 * std::cos(ccmc::constants::DegreesToRadians * (90.f - component2));
		return cartesian;

	}

}


#ifndef qbmove
#define qbmove

#include <boost/bind.hpp>
#include <gazebo/gazebo.hh>
#include <gazebo/physics/physics.hh>
#include <gazebo/common/common.hh>
#include <gazebo/common/PID.hh>
#include <stdio.h>
#include <gazebo/transport/transport.hh>
#include <gazebo/msgs/msgs.hh>
#include <gazebo/math/gzmath.hh>
#include "position_stiffness_request.pb.h"
#include "pos_current_echo_request.pb.h"

/* number of state variables */
#define N 2
/* number of output variables */
#define M 1
/* number of input variables */
#define U 2

namespace gazebo
{

  typedef const boost::shared_ptr<const position_stiffness_creator_msgs::msgs::PositionStiffnessRequest> PositionStiffnessRequestPtr;

  typedef const boost::shared_ptr<const pos_current_echo_creator_msgs::msgs::PosCurrentEchoRequest> PosCurrentEchoRequestPtr;

  class qbmovePlugin: public ModelPlugin
  {

	  	public:

	       void Load(physics::ModelPtr _parent, sdf::ElementPtr _sdf);

	       void stiff_pos_Callback(PositionStiffnessRequestPtr &msg);

	       void ref_generation(double q_e, double q_d);

	       double pwm_modulation(double u_pid);

	       void system_update(double* x, double* y, double u1, double u2);

	       double friction_torque_computation(double position, int index);

	       void OnUpdate(const common::UpdateInfo & /*_info*/);

           /* static variable used to move more qbmoves */
	       static int stat_value;

	    private:

           /* State vectors
              for each motor :
              -) 1st state: angular position value
	          -) 2nd state: angular speed value */

	       /* state vector motor1 */
	       double x1_k[N];
	       /* state vector motor2 */
	       double x2_k[N];

	       /* auxiliar vectors for state system update */
	       double x1[N];
	       double x2[N];

           /* Output vectors
              Angular position value is the only output considered (1st output) */

	       /* output vector motor 1 */
	       double y1_k[M];
	       /* output vector motor 2 */
	       double y2_k[M];

	       /* input vector motor 1 */
	       double u1_k[U];
	       /* input vector motor 2 */
	       double u2_k[U];

	       /* stiffness value from Gazebo topic command */
	       double val_stiffness;

	       /* position value from Gazebo command */
	       double val_position;

	       /* Pointer to the model */
	       physics::ModelPtr model;

	       /* Pointer to output shaft joint */
	       physics::JointPtr joint;

	       /* Pointer to motor 1 joint */
	       physics::JointPtr joint_motor1;

	       /* Pointer to motor 2 joint */
	       physics::JointPtr joint_motor2;

	       /* variable used to set motors' angles */
	       math::Angle a;

           /* link equilibrium reference */
	       double q_e;
	       /* stiffness preset reference */
	       double q_d;

	       /* motor 1 variables */
	       /* angular position reference */
	       double q1_ref ;
	       /* (k-2)-th step error */
	       double e_k_2;
	       /* (k-3)-th step error */
	       double e_k_3;
	       /* motor 1 old position */
	       double old_value_position_1;
	       /* q1_ref old position */
	       double old_q1_ref;
	       /* output value from Memory Block in the Simulink scheme (used for friction torque computation) */
	       double value_k_1;
	       /* motor 1 extern torque (second input) */
	       double tau_ext;

	       /* motor 2 variables */
	       /* angular position reference */
	       double q2_ref;
	       /* (k-2)-th step error */
	       double e2_k_2;
	       /* (k-3)-th step error */
	       double e2_k_3;
	       /* motor 2 old position */
	       double old_value_position_2;
	       /* q2_ref old position */
	       double old_q2_ref;
	       /* output value from Memory Block in the Simulink scheme (used for friction torque computation) */
	       double value2_k_1;
	       /* motor 2 extern torque (second input) */
	       double tau2_ext;

           /* output shaft angle to compute deformation angle */
	       double output_shaft_angle;
	       /* old value of output shaft angle */
	       double output_shaft_angle_old;
	       /* value to compute friction torque for output shaft */
	       double value_k_1_output_shaft;

           /* output shaft torque */
	       double tau_L;

	       /* Variables for Gazebo topics  */
	       //##########################
	       /* node variable */
	       transport::NodePtr node;
	       /* publisher variable */
	       transport::PublisherPtr pub;
	       /* subscriber variable */
      	   transport::SubscriberPtr sub;
      	   /* echo massage */
           pos_current_echo_creator_msgs::msgs::PosCurrentEchoRequest msg_echo;

           int num_qbmove;
	      //##########################

	       /* Pointer to the update event connection */
	       event::ConnectionPtr updateConnection;

  };

  /* Register this plugin with the simulator */
  GZ_REGISTER_MODEL_PLUGIN(qbmovePlugin)

}

#endif


#include <list>

#include "multiplicator.hh"
#include "float_value_factory.hh"
#include "sparse_matrix_value_generator.hh"
#include "compressed_sparse_row/compressed_sparse_row.hh"
#include "coordinate_list/coordinate_list.hh"
#include "dictionary_of_keys/dictionary_of_keys.hh"
#include "list_of_lists/scylla_driver/session.hh"
#include "list_of_lists/list_of_lists_wrapper.hh"

#define BOOST_TEST_MAIN
#define BOOST_TEST_MODULE simple_test
#include <boost/test/unit_test.hpp>

const char *IP_ADDRESS = "172.19.0.2";

enum class implementation {
    COORDINATE_LIST,
    COMPRESSED_SPARSE_ROW,
    DICTIONARY_OF_KEYS,
    LIST_OF_LISTS
};

std::list<matrix_value<float>> get_multiplied_vals(size_t dimension, size_t vals,
                                                   std::unique_ptr<multiplicator<float>> multiplicator, int seed) {
    std::shared_ptr factory = std::make_shared<float_value_factory>(0.0, 100.0, 0);

    multiplicator->load_matrix(sparse_matrix_value_generator<float>(dimension, dimension, vals, seed, factory));
    multiplicator->load_matrix(sparse_matrix_value_generator<float>(dimension, dimension, vals, 18121 * seed + 12, factory));

    multiplicator->multiply();

    std::list<matrix_value<float>> ret;

    for (int i = 1; i <= dimension; i++) {
        for (int j = 1; j <= dimension; j++) {
            auto result = multiplicator->get_result({i, j});
            if (result != 0) {
                ret.emplace_back(i, j, result);
            }
        }
    }

    return ret;
}

std::list<matrix_value<float>> get_result(implementation from, size_t dimension, size_t vals,
                                          std::shared_ptr<connector> conn, std::shared_ptr<scmd_session> conn2, int seed) {

    std::unique_ptr<multiplicator<float>> multiplicator;
    switch(from) {
        case implementation::COORDINATE_LIST:
            multiplicator = std::make_unique<COO<float>>(conn);
            break;
        case implementation::COMPRESSED_SPARSE_ROW:
            multiplicator = std::make_unique<CSR<float>>(conn);
            break;
        case implementation::DICTIONARY_OF_KEYS:
            multiplicator = std::make_unique<DOK<float>>(conn);
            break;
        case implementation::LIST_OF_LISTS:
            multiplicator = std::make_unique<LIL_wrapper<float>>(conn2);
            break;

    }

    return get_multiplied_vals(dimension, vals, std::move(multiplicator), seed);
}
BOOST_TEST_SPECIALIZED_COLLECTION_COMPARE(std::list<matrix_value<float>>)

BOOST_AUTO_TEST_SUITE(simple_cross_antitest)
    BOOST_AUTO_TEST_CASE(test_fail) {
        std::shared_ptr<connector> conn = std::make_shared<connector>(IP_ADDRESS);
        std::shared_ptr<scmd_session> conn2 = std::make_shared<scmd_session>(IP_ADDRESS);
        auto _coo = get_result(implementation::COORDINATE_LIST, 10, 10, conn, conn2, 1);
        auto _csr = get_result(implementation::COMPRESSED_SPARSE_ROW, 10, 10, conn, conn2, 111);

        BOOST_TEST(_coo != _csr);
    }
BOOST_AUTO_TEST_SUITE_END()

BOOST_AUTO_TEST_SUITE(simple_cross_test)
    BOOST_AUTO_TEST_CASE(test_all_implementations0) {
        std::shared_ptr<connector> conn = std::make_shared<connector>(IP_ADDRESS);
        std::shared_ptr<scmd_session> conn2 = std::make_shared<scmd_session>(IP_ADDRESS);
        auto _coo = get_result(implementation::COORDINATE_LIST, 3, 3, conn, conn2, 2);
        auto _csr = get_result(implementation::COMPRESSED_SPARSE_ROW, 3, 3, conn, conn2, 2);
        auto _dok = get_result(implementation::DICTIONARY_OF_KEYS, 3, 3, conn, conn2, 2);
        auto _lil = get_result(implementation::LIST_OF_LISTS, 3, 3, conn, conn2, 2);

        BOOST_TEST(_coo == _csr);;
        BOOST_TEST(_coo == _dok);
        BOOST_TEST(_coo == _lil);
    }

    BOOST_AUTO_TEST_CASE(test_all_implementations1) {
        std::shared_ptr<connector> conn = std::make_shared<connector>(IP_ADDRESS);
        std::shared_ptr<scmd_session> conn2 = std::make_shared<scmd_session>(IP_ADDRESS);
        auto _coo = get_result(implementation::COORDINATE_LIST, 10, 10, conn, conn2, 1);
        auto _csr = get_result(implementation::COMPRESSED_SPARSE_ROW, 10, 10, conn, conn2, 1);
        auto _dok = get_result(implementation::DICTIONARY_OF_KEYS, 10, 10, conn, conn2, 1);
        auto _lil = get_result(implementation::LIST_OF_LISTS, 10, 10, conn, conn2, 1);

        BOOST_TEST(_coo == _csr);
        BOOST_TEST(_coo == _dok);
        BOOST_TEST(_coo == _lil);
    }

    BOOST_AUTO_TEST_CASE(test_all_implementations2) {
        std::shared_ptr<connector> conn = std::make_shared<connector>(IP_ADDRESS);
        std::shared_ptr<scmd_session> conn2 = std::make_shared<scmd_session>(IP_ADDRESS);
        auto _coo = get_result(implementation::COORDINATE_LIST, 20, 20, conn, conn2, 3);
        auto _csr = get_result(implementation::COMPRESSED_SPARSE_ROW, 20, 20, conn, conn2, 3);
        auto _dok = get_result(implementation::DICTIONARY_OF_KEYS, 20, 20, conn, conn2, 3);
        auto _lil = get_result(implementation::LIST_OF_LISTS, 20, 20, conn, conn2, 3);

        BOOST_TEST(_coo == _csr);
        BOOST_TEST(_coo == _dok);
        BOOST_TEST(_coo == _lil);
    }

    BOOST_AUTO_TEST_CASE(test_all_implementations3) {
        std::shared_ptr<connector> conn = std::make_shared<connector>(IP_ADDRESS);
        std::shared_ptr<scmd_session> conn2 = std::make_shared<scmd_session>(IP_ADDRESS);
        auto _coo = get_result(implementation::COORDINATE_LIST, 6, 30, conn, conn2, 42);
        auto _csr = get_result(implementation::COMPRESSED_SPARSE_ROW, 6, 30, conn, conn2, 42);
        auto _dok = get_result(implementation::DICTIONARY_OF_KEYS, 6, 30, conn, conn2, 42);
        auto _lil = get_result(implementation::LIST_OF_LISTS, 6, 30, conn, conn2, 42);

        BOOST_TEST(_coo == _csr);
        BOOST_TEST(_coo == _dok);
        BOOST_TEST(_coo == _lil);
    }
BOOST_AUTO_TEST_SUITE_END()


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

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

BOOST_AUTO_TEST_SUITE(TensorflowLiteParser)

struct TransposeFixture : public ParserFlatbuffersFixture
{
    explicit TransposeFixture(const std::string & inputShape,
                              const std::string & permuteData,
                              const std::string & outputShape)
    {
        m_JsonString = R"(
            {
                  "version": 3,
                  "operator_codes": [
                    {
                      "builtin_code": "TRANSPOSE",
                      "version": 1
                    }
                  ],
                  "subgraphs": [
                    {
                      "tensors": [
                        {
                          "shape": )" + inputShape + R"(,
                          "type": "FLOAT32",
                          "buffer": 0,
                          "name": "inputTensor",
                          "quantization": {
                            "min": [
                              0.0
                            ],
                            "max": [
                              255.0
                            ],
                            "details_type": 0,
                            "quantized_dimension": 0
                          },
                          "is_variable": false
                        },
                        {
                          "shape": )" + outputShape + R"(,
                          "type": "FLOAT32",
                          "buffer": 1,
                          "name": "outputTensor",
                          "quantization": {
                            "details_type": 0,
                            "quantized_dimension": 0
                          },
                          "is_variable": false
                        })";
        if (!permuteData.empty())
        {
            m_JsonString += R"(,
                              {
                                "shape": [
                                  3
                                ],
                                "type": "INT32",
                                "buffer": 2,
                                "name": "permuteTensor",
                                "quantization": {
                                  "details_type": 0,
                                  "quantized_dimension": 0
                                },
                                "is_variable": false
                              })";
        }

        m_JsonString += R"(],
                      "inputs": [
                        0
                      ],
                      "outputs": [
                        1
                      ],
                      "operators": [
                        {
                          "opcode_index": 0,
                          "inputs": [
                            0)";
        if (!permuteData.empty())
        {
            m_JsonString += R"(,2)";
        }
        m_JsonString += R"(],
                          "outputs": [
                            1
                          ],
                          "builtin_options_type": "TransposeOptions",
                          "builtin_options": {
                          },
                          "custom_options_format": "FLEXBUFFERS"
                        }
                      ]
                    }
                  ],
                  "description": "TOCO Converted.",
                  "buffers": [
                    { },
                    { })";
        if (!permuteData.empty())
        {
            m_JsonString += R"(,{"data": )" + permuteData + R"( })";
        }
        m_JsonString += R"(
                  ]
                }
        )";
        Setup();
    }
};

struct TransposeFixtureWithPermuteData : TransposeFixture
{
    TransposeFixtureWithPermuteData() : TransposeFixture("[ 2, 2, 3 ]",
                                                         "[ 0, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0 ]",
                                                         "[ 2, 3, 2 ]") {}
};

BOOST_FIXTURE_TEST_CASE(TransposeWithPermuteData, TransposeFixtureWithPermuteData)
{
    RunTest<3, armnn::DataType::Float32>(
      0,
      {{"inputTensor", {  1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }}},
      {{"outputTensor", {  1, 4, 2, 5, 3, 6, 7, 10, 8, 11, 9, 12 }}});

    BOOST_TEST((m_Parser->GetNetworkOutputBindingInfo(0, "outputTensor").second.GetShape()
                == armnn::TensorShape({2,3,2})));
}

struct TransposeFixtureWithoutPermuteData : TransposeFixture
{
    TransposeFixtureWithoutPermuteData() : TransposeFixture("[ 2, 2, 3 ]",
                                                            "",
                                                            "[ 2, 3, 2 ]") {}
};

BOOST_FIXTURE_TEST_CASE(TransposeWithoutPermuteDims, TransposeFixtureWithoutPermuteData)
{
    RunTest<3, armnn::DataType::Float32>(
        0,
        {{"inputTensor", {  1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }}},
        {{"outputTensor", {  1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }}});

    BOOST_TEST((m_Parser->GetNetworkOutputBindingInfo(0, "outputTensor").second.GetShape()
                == armnn::TensorShape({2,3,2})));
}

BOOST_AUTO_TEST_SUITE_END()


/* Copyright © 2017 Apple Inc. All rights reserved.
 *
 * Use of this source code is governed by a BSD-3-clause license that can
 * be found in the LICENSE.txt file or at https://opensource.org/licenses/BSD-3-Clause
 */
#define BOOST_TEST_MODULE
#include <boost/test/unit_test.hpp>
#include <core/util/test_macros.hpp>
#include <vector>
#include <iostream>
#include <typeinfo>       // operator typeid

#include <core/data/flexible_type/flexible_type.hpp>
#include <core/data/flexible_type/ndarray.hpp>

using namespace turi;
using namespace flexible_type_impl;
namespace tt = boost::test_tools;

template <typename T>
void nd_assert_equal(const ndarray<T>& a, const ndarray<T>& b) {
  BOOST_CHECK(a.is_valid());
  BOOST_CHECK(b.is_valid());

  BOOST_TEST(a.num_elem() == b.num_elem());
  BOOST_TEST(a.shape() == b.shape());
  if (a.shape().size() > 0) {
    std::vector<size_t> idx(a.shape().size(), 0);
    do {
      double aval = a.at(a.index(idx));
      double bval = b.at(b.index(idx));
      BOOST_TEST(aval == bval);
    } while(a.increment_index(idx));
  }
}

template <typename T>
void test_save_load(const ndarray<T>& a) {
  oarchive oarc;
  oarc << a;
  iarchive iarc(oarc.buf, oarc.off);
  ndarray<T> b;
  iarc >> b;
  nd_assert_equal(a, b);
  BOOST_TEST(b.is_valid() == true);
  BOOST_TEST(b.is_full() == true);
}

BOOST_AUTO_TEST_CASE(test_empty) {
 ndarray<int> i;
 BOOST_TEST(i.is_valid());
 BOOST_TEST(i.is_full());
 test_save_load(i);

 ndarray<int> array1({1,1,2,3,
                      4,5,6,7},
                      {2,4},
                      {4,1});
 BOOST_TEST(array1.empty() == false);
 ndarray<int> array2;
 BOOST_TEST(array2.empty() == true);
}

BOOST_AUTO_TEST_CASE(test_canonical) {
 ndarray<int> fortran({0,5,1,6,2,7,3,8,4,9},
                      {2,5},
                      {1,2});
 std::cout << fortran << "\n";
 BOOST_TEST(fortran.is_valid());
 BOOST_TEST(fortran.is_full());
 ndarray<int> c = fortran.canonicalize();

 std::vector<size_t> desired_stride{5,1};
 std::vector<size_t> desired_shape{2,5};
 std::vector<int> desired_elements{0,1,2,3,4,5,6,7,8,9};
 BOOST_TEST(c.stride() == desired_stride, tt::per_element());
 BOOST_TEST(c.shape() == desired_shape, tt::per_element());
 BOOST_TEST(c.elements() == desired_elements, tt::per_element());
 BOOST_TEST(c.is_valid() == true);
 BOOST_TEST(c.is_full() == true);
 BOOST_TEST(c.is_canonical() == true);
 nd_assert_equal(c, fortran);

 test_save_load(fortran);
 test_save_load(c);
}

BOOST_AUTO_TEST_CASE(test_subarray) {
 ndarray<int> subarray({0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16},
                      {2,2},
                      {1,4}); // top left corner of array
 std::cout << subarray << "\n";
 BOOST_TEST(subarray.is_valid());
 BOOST_TEST(subarray.is_full() == false);
 BOOST_TEST(subarray.is_canonical() == false);
 ndarray<int> c = subarray.canonicalize();

 std::vector<int> desired_elements{0,4,1,5};
 std::vector<size_t> desired_shape{2,2};
 std::vector<size_t> desired_stride{2,1};
 BOOST_TEST(c.elements() == desired_elements, tt::per_element());
 BOOST_TEST(c.shape() == desired_shape, tt::per_element());
 BOOST_TEST(c.stride() == desired_stride, tt::per_element());
 BOOST_TEST(c.is_valid() == true);
 BOOST_TEST(c.is_full() == true);
 BOOST_TEST(c.is_canonical() == true);
 nd_assert_equal(c, subarray);

 test_save_load(subarray);
 test_save_load(c);
}

BOOST_AUTO_TEST_CASE(test_print) {
 ndarray<int> array({0,1,2,3,4,5},
                      {2,3},
                      {3,1}); // top left corner of array
 std::cout << "print test " << array << "\n";
}

BOOST_AUTO_TEST_CASE(test_subarray2) {
 ndarray<int> subarray({0,1,2,3,
                        4,5,6,7,
                        8,9,10,11,
                        12,13,14,15,16},
                      {2,2},
                      {1,4},
                      2); // top right corner of array
 BOOST_TEST(subarray.is_valid());
 BOOST_TEST(subarray.is_full() == false);
 BOOST_TEST(subarray.is_canonical() == false);
 ndarray<int> c = subarray.canonicalize();

 std::vector<int> desired_elements{2,6,3,7};
 std::vector<size_t> desired_shape{2,2};
 std::vector<size_t> desired_stride{2,1};
 BOOST_TEST(c.elements() == desired_elements, tt::per_element());
 BOOST_TEST(c.shape() == desired_shape, tt::per_element());
 BOOST_TEST(c.stride() == desired_stride, tt::per_element());
 BOOST_TEST(c.is_valid() == true);
 BOOST_TEST(c.is_full() == true);
 BOOST_TEST(c.is_canonical() == true);
 nd_assert_equal(c, subarray);

 test_save_load(subarray);
 test_save_load(c);
}

BOOST_AUTO_TEST_CASE(test_invalid) {
 TS_ASSERT_THROWS(ndarray<int>({0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16},
                               {2,3},
                               {2,8}), std::string);

 TS_ASSERT_THROWS(ndarray<int>({0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16},
                               {3,8},
                               {1,1}), std::string);
}

BOOST_AUTO_TEST_CASE(test_bad_shapes) {
 ndarray<int> a({0,1,2,3,4,5,6,7,8,9},
                {0,0},
                {1,5});
 BOOST_TEST(a.elements().size() == 0);
 ndarray<int> b({0,1,2,3,4,5,6,7,8,9},
                {1,0},
                {1,5});
 BOOST_TEST(b.elements().size() == 0);
}
BOOST_AUTO_TEST_CASE(test_odd_stride) {
 // a stride of 0 is technically valid
 // though a little odd
 {
   ndarray<int> zero_stride({0,1,2,3,4,5,6,7,8,9},
                           {2,5},
                           {1,0});
   BOOST_TEST(zero_stride.is_valid() == true);
   BOOST_TEST(zero_stride.is_full() == false);
   BOOST_TEST(zero_stride.is_canonical() == false);
   ndarray<int> zero_stride_c = zero_stride.canonicalize();
   std::vector<int> desired_elements{0,0,0,0,0,1,1,1,1,1};
   std::vector<size_t> desired_shape{2,5};
   std::vector<size_t> desired_stride{5,1};
   BOOST_TEST(zero_stride_c.elements() == desired_elements, tt::per_element());
   BOOST_TEST(zero_stride_c.shape() == desired_shape, tt::per_element());
   BOOST_TEST(zero_stride_c.stride() == desired_stride, tt::per_element());
   test_save_load(zero_stride);
 }

 // test dim 1
 {
   ndarray<int> dim1(std::vector<int>{0,1,2},
                     {1,1,3},
                     {0,0,1});
   BOOST_TEST(dim1.is_valid() == true);
   BOOST_TEST(dim1.is_full() == true);
   BOOST_TEST(dim1.is_canonical() == false);
   ndarray<int> dim1_c = dim1.canonicalize();
   std::vector<int> desired_elements{0,1,2};
   std::vector<size_t> desired_shape{1,1,3};
   std::vector<size_t> desired_stride{3,3,1};
   BOOST_TEST(dim1_c.elements() == desired_elements, tt::per_element());
   BOOST_TEST(dim1_c.shape() == desired_shape, tt::per_element());
   BOOST_TEST(dim1_c.stride() == desired_stride, tt::per_element());
   test_save_load(dim1);
 }
 // another test dim 1
 {
   ndarray<int> dim1({0,2,4,1,3,5},
                     {3,1,1,2},
                     {1,0,0,3});
   std::cout << dim1 << "\n";
   BOOST_TEST(dim1.is_valid() == true);
   BOOST_TEST(dim1.is_full() == true);
   BOOST_TEST(dim1.is_canonical() == false);
   ndarray<int> dim1_c = dim1.canonicalize();
   std::vector<int> desired_elements{0,1,2,3,4,5};
   std::vector<size_t> desired_shape{3,1,1,2};
   std::vector<size_t> desired_stride{2,2,2,1};
   BOOST_TEST(dim1_c.elements() == desired_elements, tt::per_element());
   BOOST_TEST(dim1_c.shape() == desired_shape, tt::per_element());
   BOOST_TEST(dim1_c.stride() == desired_stride, tt::per_element());
   test_save_load(dim1);
   test_save_load(dim1_c);
 }
}

BOOST_AUTO_TEST_CASE(test_add) {
 ndarray<int> array1({1,1,2,3,
                      4,5,6,7},
                      {2,4},
                      {4,1});
 ndarray<int> array2({1,4,
                      1,5,
                      2,6,
                      3,7},
                      {2,4},
                      {1,2});
 std::cout << array1 << "\n";
 std::cout << array2 << "\n";
 array1 += array2;
 std::vector<int> desired_elements{1+1,1+1,2+2,3+3,4+4,5+5,6+6,7+7};
 std::vector<size_t> desired_shape{2,4};
 std::vector<size_t> desired_stride{4,1};
 BOOST_TEST(array1.elements() == desired_elements, tt::per_element());
 BOOST_TEST(array1.shape() == desired_shape, tt::per_element());
 BOOST_TEST(array1.stride() == desired_stride, tt::per_element());

 array2 += 5;
 std::vector<int> desired_elements2{1+5,4+5, 1+5,5+5, 2+5,6+5,3+5,7+5} ;
 BOOST_TEST(array2.elements() == desired_elements2, tt::per_element());
}

BOOST_AUTO_TEST_CASE(test_sub) {
 ndarray<int> array1({1,1,2,3,
                      4,5,6,7},
                      {2,4},
                      {4,1});
 ndarray<int> array2({1,4,
                      1,5,
                      2,6,
                      3,7},
                      {2,4},
                      {1,2});
 std::cout << array1 << "\n";
 std::cout << array2 << "\n";
 array1 -= array2;
 std::vector<int> desired_elements{1-1,1-1,2-2,3-3,4-4,5-5,6-6,7-7};
 std::vector<size_t> desired_shape{2,4};
 std::vector<size_t> desired_stride{4,1};
 BOOST_TEST(array1.elements() == desired_elements, tt::per_element());
 BOOST_TEST(array1.shape() == desired_shape, tt::per_element());
 BOOST_TEST(array1.stride() == desired_stride, tt::per_element());

 array2 -= 5;
 std::vector<int> desired_elements2{1-5,4-5, 1-5,5-5, 2-5,6-5,3-5,7-5} ;
 BOOST_TEST(array2.elements() == desired_elements2, tt::per_element());
}

BOOST_AUTO_TEST_CASE(test_multiply) {
 ndarray<int> array1({1,1,2,3,
                      4,5,6,7},
                      {2,4},
                      {4,1});
 ndarray<int> array2({1,4,
                      1,5,
                      2,6,
                      3,7},
                      {2,4},
                      {1,2});
 array1 *= array2;
 std::vector<int> desired_elements{1*1,1*1,2*2,3*3,4*4,5*5,6*6,7*7};
 std::vector<size_t> desired_shape{2,4};
 std::vector<size_t> desired_stride{4,1};
 BOOST_TEST(array1.elements() == desired_elements, tt::per_element());
 BOOST_TEST(array1.shape() == desired_shape, tt::per_element());
 BOOST_TEST(array1.stride() == desired_stride, tt::per_element());

 array2 *= 5;
 std::vector<int> desired_elements2{1*5,4*5, 1*5,5*5, 2*5,6*5,3*5,7*5} ;
 BOOST_TEST(array2.elements() == desired_elements2, tt::per_element());
}

BOOST_AUTO_TEST_CASE(test_divide) {
 ndarray<int> array1({1,1,2,3,
                      4,5,6,7},
                      {2,4},
                      {4,1});
 ndarray<int> array2({1,4,
                      1,5,
                      2,6,
                      3,7},
                      {2,4},
                      {1,2});
 array1 /= array2;
 std::vector<int> desired_elements{1/1,1/1,2/2,3/3,4/4,5/5,6/6,7/7};
 std::vector<size_t> desired_shape{2,4};
 std::vector<size_t> desired_stride{4,1};
 BOOST_TEST(array1.elements() == desired_elements, tt::per_element());
 BOOST_TEST(array1.shape() == desired_shape, tt::per_element());
 BOOST_TEST(array1.stride() == desired_stride, tt::per_element());

 array2 /= 5;
 std::vector<int> desired_elements2{1/5,4/5, 1/5,5/5, 2/5,6/5,3/5,7/5} ;
 BOOST_TEST(array2.elements() == desired_elements2, tt::per_element());
}

BOOST_AUTO_TEST_CASE(test_mod) {
 ndarray<int> array1({1,1,2,3,
                      4,5,6,7},
                      {2,4},
                      {4,1});
 ndarray<int> array2({1,4,
                      1,5,
                      2,6,
                      3,7},
                      {2,4},
                      {1,2});
 array1 %= array2;
 std::vector<int> desired_elements{1%1,1%1,2%2,3%3,4%4,5%5,6%6,7%7};
 std::vector<size_t> desired_shape{2,4};
 std::vector<size_t> desired_stride{4,1};
 BOOST_TEST(array1.elements() == desired_elements, tt::per_element());
 BOOST_TEST(array1.shape() == desired_shape, tt::per_element());
 BOOST_TEST(array1.stride() == desired_stride, tt::per_element());

 array2 %= 5;
 std::vector<int> desired_elements2{1%5,4%5, 1%5,5%5, 2%5,6%5,3%5,7%5} ;
 BOOST_TEST(array2.elements() == desired_elements2, tt::per_element());
}

BOOST_AUTO_TEST_CASE(test_mod_float) {
 ndarray<double> array1({1,1,2,3,
                      4,5,6,7},
                      {2,4},
                      {4,1});
 double c = 0.6;
 array1 %= c;
 std::vector<double> desired_elements{fmod(1,c),fmod(1,c),fmod(2,c),fmod(3,c),
                                      fmod(4,c),fmod(5,c),fmod(6,c),fmod(7,c)};
 std::vector<size_t> desired_shape{2,4};
 std::vector<size_t> desired_stride{4,1};
 BOOST_TEST(array1.elements() == desired_elements, tt::per_element());
 BOOST_TEST(array1.shape() == desired_shape, tt::per_element());
 BOOST_TEST(array1.stride() == desired_stride, tt::per_element());
}

BOOST_AUTO_TEST_CASE(test_flexible_type_conversions1) {
 flex_list array1{flexible_type(flex_vec{1,1,1,1}),
                  flexible_type(flex_vec{2,2,2,2}),
                  flexible_type(flex_vec{3,3,3,3}),
                  flexible_type(flex_vec{4,4,4,4})};
 flexible_type f1(array1);
 flex_nd_vec target1({1,1,1,1,
                      2,2,2,2,
                      3,3,3,3,
                      4,4,4,4},
                      {4,4});
 flex_nd_vec fconv1 = f1.to<flex_nd_vec>();

 BOOST_TEST(fconv1.elements() == target1.elements(), tt::per_element());
 BOOST_TEST(fconv1.shape() == target1.shape(), tt::per_element());
 BOOST_TEST(fconv1.stride() == target1.stride(), tt::per_element());
 test_save_load(fconv1);
}

BOOST_AUTO_TEST_CASE(test_flexible_type_conversions2) {
 flexible_type two(2.0);
 flexible_type four(4);
 flex_list array1{flexible_type(flex_vec{1,1,1,1}),
                  flexible_type(flex_list{two,two,two,two}),
                  flexible_type(flex_nd_vec({3,3,3,3})),
                  flexible_type(flex_list{four,four,four,four})};
 flexible_type f1(array1);
 flex_nd_vec target1({1,1,1,1,
                      2,2,2,2,
                      3,3,3,3,
                      4,4,4,4},
                      {4,4});
 flex_nd_vec fconv1 = f1.to<flex_nd_vec>();

 BOOST_TEST(fconv1.elements() == target1.elements(), tt::per_element());
 BOOST_TEST(fconv1.shape() == target1.shape(), tt::per_element());
 BOOST_TEST(fconv1.stride() == target1.stride(), tt::per_element());
 test_save_load(fconv1);
}

BOOST_AUTO_TEST_CASE(test_flexible_type_conversions_3d) {
 flex_nd_vec nd1({1,1,1,1,
                  2,2,2,2,
                  3,3,3,3},
                  {3,4});
 flex_list array1{flexible_type(nd1),
                  flexible_type(nd1),
                  flexible_type(nd1),
                  flexible_type(nd1)};
 flexible_type f1(array1);

 flex_nd_vec target1({1,1,1,1,
                      2,2,2,2,
                      3,3,3,3,
                      1,1,1,1,
                      2,2,2,2,
                      3,3,3,3,
                      1,1,1,1,
                      2,2,2,2,
                      3,3,3,3,
                      1,1,1,1,
                      2,2,2,2,
                      3,3,3,3},
                      {4,3,4});
 flex_nd_vec fconv1 = f1.to<flex_nd_vec>();

 BOOST_TEST(fconv1.elements() == target1.elements(), tt::per_element());
 BOOST_TEST(fconv1.shape() == target1.shape(), tt::per_element());
 BOOST_TEST(fconv1.stride() == target1.stride(), tt::per_element());
 test_save_load(fconv1);
}

BOOST_AUTO_TEST_CASE(test_flexible_type_conversions_fail1) {
 flexible_type two(2.0);
 flexible_type four(4);
 flex_list array1{flexible_type(flex_vec{1,1,1,1}),
                  flexible_type(flex_list{two,two,two,two}),
                  flexible_type(flex_vec{3,3,3}),
                  flexible_type(flex_list{four,four,four,four})};
 flexible_type f1(array1);
 TS_ASSERT_THROWS(f1.to<flex_nd_vec>(), std::string);

 flex_list array2{flexible_type(flex_vec{1,1,1,1}),
                  flexible_type(flex_list{two,two,two,two, two})};
 flexible_type f2(array2);
 TS_ASSERT_THROWS(f2.to<flex_nd_vec>(), std::string);

 flex_list array3{flexible_type(flex_list{two,two,two,two, two}),
                  flexible_type(flex_vec{1,1,1,1})};
 flexible_type f3(array3);
 TS_ASSERT_THROWS(f3.to<flex_nd_vec>(), std::string);

 flex_list array4{flexible_type(flex_list{two,two,two,two, two}),
                  flexible_type(1)};
 flexible_type f4(array4);
 TS_ASSERT_THROWS(f4.to<flex_nd_vec>(), std::string);
}

BOOST_AUTO_TEST_CASE(test_image_conversion) {
 flex_nd_vec nd1({1,1,1,1,
                 2,2,2,2,
                 3,3,3,3,
                 1,1,1,1,
                 2,2,2,2,
                 3,3,3,3,
                 1,1,1,1,
                 2,2,2,2,
                 3,3,3,3,
                 1,1,1,1,
                 2,2,2,2,
                 3,3,3,3},
                 {4,3,4});
 auto rt1 = flexible_type(flexible_type(nd1).to<flex_image>()).to<flex_nd_vec>();
 BOOST_TEST(nd1.elements() == rt1.elements(), tt::per_element());
 BOOST_TEST(nd1.shape() == rt1.shape(), tt::per_element());
 BOOST_TEST(nd1.stride() == rt1.stride(), tt::per_element());

 flex_nd_vec nd2({1,1,1,
                 2,2,2,
                 3,3,3,
                 1,1,1,
                 2,2,2,
                 3,3,3,
                 1,1,1,
                 2,2,2,
                 3,3,3,
                 1,1,1,
                 2,2,2,
                 3,3,3,},
                 {4,3,3});
 auto rt2 = flexible_type(flexible_type(nd2).to<flex_image>()).to<flex_nd_vec>();
 BOOST_TEST(nd2.elements() == rt2.elements(), tt::per_element());
 BOOST_TEST(nd2.shape() == rt2.shape(), tt::per_element());
 BOOST_TEST(nd2.stride() == rt2.stride(), tt::per_element());

 flex_nd_vec nd3({1, 2, 3,
                 1, 2, 3,
                 1, 2, 3,
                 1, 2, 3,},
                 {4,3});
 auto rt3 = flexible_type(flexible_type(nd3).to<flex_image>()).to<flex_nd_vec>();
 BOOST_TEST(nd3.elements() == rt3.elements(), tt::per_element());
 BOOST_TEST(nd3.shape() == rt3.shape(), tt::per_element());
 BOOST_TEST(nd3.stride() == rt3.stride(), tt::per_element());
}

BOOST_AUTO_TEST_CASE(test_equality) {
 flex_nd_vec array1({1,1,2,3,
                      4,5,6,7},
                      {2,4},
                      {4,1});
 flex_nd_vec array2({1,4,
                      1,5,
                      2,6,
                      3,7},
                      {2,4},
                      {1,2});
 flexible_type f1(array1);
 flexible_type f2(array2);
 BOOST_TEST(array1 == array2);
 BOOST_TEST(f1 == f2);
}

BOOST_AUTO_TEST_CASE(test_equality_subarray) {
 flex_nd_vec array1({1,1,2,3,
                      4,5,6,7},
                      {1,2},
                      {4,1});
 flex_nd_vec array2({1,4,
                      1,5,
                      2,6,
                      3,7},
                      {1,2},
                      {1,2});
 flexible_type f1(array1);
 flexible_type f2(array2);
 BOOST_TEST(array1 == array2);
 BOOST_TEST(f1 == f2);
}

BOOST_AUTO_TEST_CASE(test_equality_fail) {
 flex_nd_vec array1({1,1,2,3,
                      4,5,6,7},
                      {1,2},
                      {4,1});
 flex_nd_vec array2({1,4,
                      1,5,
                      2,6,
                      3,7},
                      {2,1},
                      {2,1});
 flexible_type f1(array1);
 flexible_type f2(array2);
 BOOST_TEST(array1 != array2);
 BOOST_TEST(f1 != f2);
 // check both == and !=
 bool t = f1 == f2;
 BOOST_TEST(t == false);
}