#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include <boost/program_options.hpp>

#include "msa.hpp"
#include "model.hpp"
#include "MCseq.hpp"
#include "OptParam.hpp"
#include "AnaTraj.hpp"
using namespace std;

namespace po = boost::program_options;

int main(int argc, char *argv[])
{
  po::options_description desc("Allowed options");
  desc.add_options()
    ("help,h","produce help message")
    ("dos", po::value<string>(), "WL DOS file")
    ("param,p", po::value<string>(), "input LGM parameter file")
    ("param_out", po::value<string>(), "output LGM parameter file")
    ("logbase,l", po::value<string>(), "basename for log files")
    ("temp", po::value<double>(), "Temperature")
    ("mu_len", po::value<double>(), "Mu_len")
    ("mu_I", po::value<double>(), "Mu_I")
    ("mulcano", po::value<bool>(), "Multicanonical?")
    ("ftraj", po::value<string>(), "trajectory file to be analyzed")
    ("seed", po::value<int>(), "random seed")
    ("min_energy",po::value<double>(), "lower bound of energy range")
    ("max_energy",po::value<double>(), "upper bound of energy range")
    ("delta_energy",po::value<double>(), "max_energy = min_energy + delta_energy")
    ("min_cnt",po::value<int>(), "minimum count of each bin")
    ("ebin",po::value<int>(), "target energy bin")
    ;

  po::positional_options_description p;
  po::variables_map vm;
  po::store(po::command_line_parser(argc,argv).
	    options(desc).positional(p).run(), vm);
  po::notify(vm);

  if(vm.count("help")) {
    cerr << desc << endl;
    return 1;
  }
  string logbase = "ana";
  if(vm.count("logbase")) {
    logbase = vm["logbase"].as<string>();
  }
  cerr << "# LOGBASE= " << logbase << endl;

  Model model;
  if(vm.count("param")) {
    model.read_parameters(vm["param"].as<string>());
  } else {
    cerr << "Specify the parameter file!" << endl;
    exit(1);
  }

  int min_cnt = 100000000;
  if(vm.count("min_cnt")) {
    min_cnt = vm["min_cnt"].as<int>();
  }
  cerr << "minimum count of each bin= " << min_cnt << endl;

  bool erange = false;
  double min_energy=-1000, delta_energy=1.0;
  if(vm.count("min_energy")) {
    min_energy = vm["min_energy"].as<double>();
    erange = true;
  }
  if(vm.count("delta_energy")) {
    delta_energy = vm["delta_energy"].as<double>();
  } else if(vm.count("max_energy")) {
    delta_energy = vm["max_energy"].as<double>() - min_energy;
  }
  const double max_energy = min_energy + delta_energy;

  MCseq mcs(model);

  if(vm.count("seed")) {
    mcs.set_seed(vm["seed"].as<int>());
    cerr << "random seed= " << (vm["seed"].as<int>()) << endl;;
  }

  mcs.STATS_MULTICANONICAL = true;
  if(vm.count("mulcano")) {
    mcs.STATS_MULTICANONICAL = vm["mulcano"].as<bool>();
  }

  if(vm.count("dos")) {
    mcs.read_DOS(vm["dos"].as<string>(), true);
  } else {
    cerr << "Specify the DOS file with the '--dos' option!!" << endl;
    exit(1);
  }
  double temp = 1.0;
  if(vm.count("temp")) {
    temp = vm["temp"].as<double>();
  }
  model.set_temperature(temp);
  mcs.set_temperature(temp);
  cerr << "Temperature= " << temp << endl;

  AnaTraj atraj(model);
  string ftraj;
  if(vm.count("ftraj")) {
    ftraj = vm["ftraj"].as<string>();
    cerr << "# Trajectory file: " <<  ftraj << endl;
    atraj.set_trajectory_file(ftraj);
  }

  double Mu_len = 0;
  if(vm.count("mu_len")) {
    Mu_len = vm["mu_len"].as<double>();
  }
  cerr << "Mu_len= " << Mu_len << endl;
  model.set_mu_len(Mu_len);

  double Mu_I = 0;
  if(vm.count("mu_I")) {
    Mu_I = vm["mu_I"].as<double>();
  }
  cerr << "Mu_I= " << Mu_I << endl;
  model.set_mu_lenI(Mu_I);

  int Nseqs=0;
  mcs.init_stats(model);
  mcs.stats_full_nonbonded = false;
  const clock_t begin_time = clock();
  cerr << "# Sampling from Trajectory file " << endl;

  mcs.clear_EHist();

  while(atraj.pick_seq(model, mcs)) {
    if(mcs.Energy < mcs.MIN_ENERGY || mcs.Energy >= mcs.MAX_ENERGY) continue;

    const int bin = mcs.get_DOS_bindex(mcs.Energy);
    if(mcs.EHist[bin]>min_cnt) continue;
    mcs.EHist[bin]++;
    const double div = mcs.get_divergence(model);
    if(!erange
       || (erange && mcs.Energy >= min_energy && mcs.Energy < max_energy)) {
      const double e = mcs.Energy;
      const double w = mcs.count_stats(model);
      Nseqs++;
      if(Nseqs % 10000 == 0) cerr << Nseqs << " sequences processed." << endl;
    }
  }
  atraj.unset_trajectory_file();
  cerr << "total weight= " << mcs.WeightTotal << endl;
  mcs.finish_stats(model);
  const clock_t end_time = clock();

  int imin = -1;
  double ehist_min = 1e+100;
  for(map<int,double>::iterator it = mcs.DOS.begin();
      it != mcs.DOS.end(); ++it) {
    if(mcs.EHist[it->first] < ehist_min) {
      imin = it->first;
      ehist_min = mcs.EHist[it->first];
    }
  }
  cerr << "min_EHist/min_cnt= "
       << imin
       << "\t" << imin*mcs.DELTA_ENERGY
       << "\t" << ehist_min << "\t" << min_cnt << endl;

  double slenO0,slenI0;
  const double slen0 = model.get_seqlength(slenO0,slenI0);
  double egibbs0,ebonded0,enonbonded0;
  const double energy0 = model.get_energy(ebonded0,enonbonded0,egibbs0);
  cerr << "slen0 " << slen0 << "\t"
       << slenO0 << "\t"
       << slenI0 << "\t" << endl;
  const double SpecHeat = mcs.Evar/(temp*temp);
  double slenO,slenI;
  const double slen = model.get_seqlength_exp(slenO,slenI);
  cerr << "slen " << slen << "\t"
       << slenO << "\t"
       << slenI << "\t" << endl;

  double devO,devI;
  const double dev = model.get_deviation(devO,devI);
  double egibbs,ebonded,enonbonded;
  const double energy = model.get_energy_exp(ebonded,enonbonded,egibbs);
  const double ent0 = model.get_site_entropy();
  const double ent = model.get_site_entropy_exp();
  const double divO = model.get_divergence();
  const double divR = model.get_divergence_from_ref();
  cout << "Summary:\t"
       << Nseqs << "\t"
       << Mu_I << "\t"
       << mcs.Temperature << "\t"
       << SpecHeat << "\t"
       << slen - slen0 << "\t"
       << slenO - slenO0 << "\t"
       << slenI - slenI0 << "\t"
       << dev << "\t"
       << devO << "\t"
       << devI << "\t"
       << energy - energy0 << "\t"
       << ebonded - ebonded0 << "\t"
       << enonbonded - enonbonded0 << "\t"
       << egibbs << "\t"
       << ent - ent0 << "\t"
       << divO << "\t"
       << divR << endl;

  for(int i = 1; i <= model.length(); ++i) {
    cout << "Site\t" << i << "\t"
	 << model.ent_O[i] << "\t"
	 << model.div_O[i] << "\t"
      	 << model.ddiv_O[i] << "\t"
	 << model.div_OOs[i] << "\t"
      	 << model.ddiv_OOs[i] << "\t"
	 << model.mdiv_O[i] << "\t"
	 << model.site_energy_exp[i] << "\t"
	 << model.dev_I[i] << endl;
  }

  if(vm.count("param_out")) {
    const string pout = vm["param_out"].as<string>();
    cerr << "#  Writing parameters to " << pout << endl;
    model.write_parameters(pout);
    const string covout = logbase + ".cov";
    cerr << "#  Writing covariance matrix to " << covout << endl;
    model.dump_covariance_exp(covout);
  }

return 0;
}


//          Copyright Oliver Kowalke 2009.
// 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)

#include "boost/task/detail/wsq.hpp"

#include <boost/thread/locks.hpp>

namespace boost {
namespace tasks {
namespace detail {

wsq::wsq( fast_semaphore & fsem) :
	initial_size_( 32),
	array_( new callable[ initial_size_]),
	capacity_( initial_size_),
	mask_( initial_size_ - 1),
	head_idx_( 0),
	tail_idx_( 0),
	mtx_(),
	fsem_( fsem)
{}

bool
wsq::empty() const
{ return head_idx_.load() >= tail_idx_.load(); }

std::size_t
wsq::size() const
{ return tail_idx_.load() - head_idx_.load(); }

void
wsq::put( callable const& ca)
{
	unsigned int tail( tail_idx_.load() );
	if ( tail <= head_idx_.load() + mask_)
	{
		array_[tail & mask_] = ca;
		tail_idx_.fetch_add( 1);
	}
	else
	{
		lock_guard< recursive_mutex > lk( mtx_);
		unsigned int head( head_idx_.load() );
		int count( size() );

		if ( count >= mask_)
		{
			capacity_ <<= 1;
			shared_array< callable > array( new callable[capacity_]);
			for ( int i( 0); i != count; ++i)
				array[i] = array_[(i + head) & mask_];
			array_.swap( array);
			head_idx_.store( 0);
			tail = count;
			tail_idx_.store( tail);
			mask_ = (mask_ << 1) | 1;
		}
		array_[tail & mask_] = ca;
		tail_idx_.fetch_add( 1);
	}
	fsem_.post();
}

bool
wsq::try_take( callable & ca)
{
	unsigned int tail( tail_idx_.load() );
	if ( tail == 0)
		return false;
	tail -= 1;
	tail_idx_.exchange( tail);
	//tail_idx_.store( tail);
	if ( head_idx_.load() <= tail)
	{
		ca.swap( array_[tail & mask_]);
		return true;
	}
	else
	{
		lock_guard< recursive_mutex > lk( mtx_);
		if ( head_idx_.load() <= tail)
		{
			ca.swap( array_[tail & mask_]);
			return true;
		}
		else
		{
			tail_idx_.fetch_add( 1);
			return false;
		}
	}
}

bool
wsq::try_steal( callable & ca)
{
	recursive_mutex::scoped_try_lock lk( mtx_);
	if ( lk.owns_lock() )
	{
		unsigned int head( head_idx_.load() );
		head_idx_.exchange( head + 1);
		//head_idx_.store( head + 1);
		if ( head < tail_idx_.load() )
		{
			ca.swap( array_[head & mask_]);
			return true;
		}
		else
		{
			head_idx_.store( head);
			return false;
		}
	}
	return false;
}

}}}


/**
 * xyz coordinates with a velocity component (dx, dy, dz)
 *
 * Copyright 2013 Bruce Ide
 *
 *  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.

 */

#include "xyz_coordinate.hpp"
#include <Eigen/Core>

#ifndef _HPP_XYZ_VELOCITY
#define _HPP_XYZ_VELOCITY

namespace fr {

  namespace coordinates {

    class xyz_velocity : public xyz_coordinate {
    protected:
      double dx, dy, dz;
    public:
      typedef xyz_coordinate super; // I kind of like implicit super in languages that support that...

      xyz_velocity(const double &x, const double &y, const double &z, const double &dx, const double &dy, const double &dz) : super(x,y,z), dx(dx), dy(dy), dz(dz)
      {
      }

      xyz_velocity(const xyz_velocity &copy) : super(copy.get_x(), copy.get_y(), copy.get_z()), dx(copy.dx), dy(copy.dy), dz(copy.dz)
      {
      }

      // Initializes deltas to zero in this case

      xyz_velocity(const xyz_coordinate &copy) : super(copy.get_x(), copy.get_y(), copy.get_z()), dx(0.0), dy(0.0), dz(0.0)
      {
      }

      // Converting the other way will lose some information, but I'll just
      // assume you wanted to do that.

      virtual operator xyz_coordinate()
      {
	xyz_coordinate retval(x,y,z);
	return retval;
      }

      virtual ~xyz_velocity()
      {
      }

      double get_dx() const { return dx; }
      double get_dy() const { return dy; }
      double get_dz() const { return dz; }

      Eigen::Vector3d get_deltas() const
      {
	Eigen::Vector3d retval;
	retval << dx,dy,dz;
	return retval;
      }

      Eigen::Matrix<double,6,1> get_vector() const
      {
	Eigen::Matrix<double,6,1> retval;
	retval << x,y,z,dx,dy,dz;
	return retval;
      }

    };

  }
}

#endif


//  Copyright (c) 2011-2013 Thomas Heller
//
//  SPDX-License-Identifier: BSL-1.0
//  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)

#if !defined(JACOBI_SMP_NO_pika)
#include <pika/init.hpp>
#endif

#include <pika/modules/program_options.hpp>

#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/qi_action.hpp>
#include <boost/spirit/include/qi_auxiliary.hpp>
#include <boost/spirit/include/qi_char.hpp>
#include <boost/spirit/include/qi_numeric.hpp>
#include <boost/spirit/include/qi_operator.hpp>
#include <boost/spirit/include/qi_parse.hpp>
#include <boost/spirit/include/qi_string.hpp>
#include <boost/spirit/include/support_istream_iterator.hpp>

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

using pika::program_options::options_description;
using pika::program_options::parse_command_line;
using pika::program_options::store;
using pika::program_options::value;
using pika::program_options::variables_map;

#include "jacobi_nonuniform.hpp"

namespace jacobi_smp {

    void jacobi_kernel_nonuniform(crs_matrix<double> const& A,
        std::vector<double>& dst, std::vector<double> const& src,
        std::vector<double> const& b, std::size_t row)
    {
        double result = b[row];
        double div = 1.0;
        const std::size_t begin = A.row_begin(row);
        const std::size_t end = A.row_end(row);

        for (std::size_t j = begin; j < end; ++j)
        {
            if (row == j)
                div = div / A.values[j];
            else
                result -= A.values[j] * src[A.indices[j]];
        }
        dst[row] = result * div;
    }
}    // namespace jacobi_smp

namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;

void init(
    jacobi_smp::crs_matrix<double>& M, std::size_t dim, std::size_t non_zeros)
{
    M.values.reserve(non_zeros);
    M.indices.reserve(non_zeros);
    M.rows.reserve(dim + 1);
    M.rows.push_back(0);
}

void add_entry(jacobi_smp::crs_matrix<double>& M, std::size_t& row,
    std::size_t& n, std::size_t j, std::size_t i, double v)
{
    M.values.push_back(v);
    M.indices.push_back(j);
    ++n;
    if (i != row)
    {
        row = i;
        M.rows.push_back(M.rows.back() + n);
        n = 0;
    }
}

int pika_main(variables_map& vm)
{
#if !defined(JACOBI_SMP_NO_pika)
    pika::scoped_finalize f;
#endif

    {
        std::size_t iterations = vm["iterations"].as<std::size_t>();
        std::size_t block_size = vm["block-size"].as<std::size_t>();
        std::string matrix = vm["matrix"].as<std::string>();
        std::string mode = vm["mode"].as<std::string>();

        jacobi_smp::crs_matrix<double> A;
        std::vector<double> x;
        std::vector<double> b;

        {
            std::ifstream file(matrix.c_str());
            file.unsetf(std::ios_base::skipws);
            using iterator = boost::spirit::istream_iterator;
            iterator begin(file);
            iterator end;

            std::size_t current_row = 0;
            std::size_t non_zero_row = 0;
            std::size_t dim = 0;
            std::size_t non_zero_entries = 0;

            qi::phrase_parse(begin, end,
                (qi::int_[phx::ref(dim) = qi::_1] >> qi::int_ >>
                    qi::int_[phx::ref(non_zero_entries) = qi::_1])[phx::bind(
                    init, phx::ref(A), dim, non_zero_entries)] >>
                    *(    // entry
                        (qi::int_ >> qi::int_ >> qi::double_)[phx::bind(
                            add_entry, phx::ref(A), phx::ref(current_row),
                            phx::ref(non_zero_row), qi::_1, qi::_2, qi::_3)]),
                qi::space |
                    (qi::lit("%") >> *(!qi::eol >> qi::char_) >> qi::eol));

            if (dim == 0)
            {
                std::cerr << "Parsed zero non zero values in matrix file "
                          << matrix << "\n";
                return 1;
            }

            std::cout << "A: " << dim << "x" << dim
                      << " number of non zeros: " << non_zero_entries << "\n";
        }
        if (vm.count("vector"))
        {
            std::string vector = vm["vector"].as<std::string>();
            std::ifstream file(vector.c_str());
            file.unsetf(std::ios_base::skipws);
            using iterator = boost::spirit::istream_iterator;
            iterator begin(file);
            iterator end;
            qi::phrase_parse(begin, end, *qi::double_, qi::ascii::space, b);
        }
        else
        {
            b = std::vector<double>(A.rows.size() - 1, 1.0);
        }
        std::cout << "b: " << b.size() << "\n";

        if (mode == "solve")
        {
            jacobi_smp::jacobi(A, b, iterations, block_size);
        }
        else if (mode == "statistics")
        {
            std::size_t min_per_row = (std::numeric_limits<std::size_t>::max)();
            std::size_t max_per_row = 0;
            double mean_per_row = 0.0;
            for (std::size_t r = 0; r < b.size(); ++r)
            {
                const std::size_t begin = A.row_begin(r);
                const std::size_t end = A.row_end(r);
                std::size_t n_row = end - begin;
                mean_per_row += double(n_row);
                if (n_row > max_per_row)
                {
                    max_per_row = n_row;
                }
                if (n_row < min_per_row)
                {
                    min_per_row = n_row;
                }
            }
            std::cout << "Matrix has " << A.values.size()
                      << " non zero entries\n";
            std::cout << "order: " << b.size() << "x" << b.size() << "\n";
            std::cout << "Entries per row:\n";
            std::cout << "\tmax " << max_per_row << "\n";
            std::cout << "\tmin " << min_per_row << "\n";
            std::cout << "\tmean " << mean_per_row / double(b.size()) << "\n";
            std::cout << "Density is: "
                      << double(A.values.size()) / double(b.size() * b.size())
                      << "\n";
        }
        else
        {
            std::cout << "Unknown mode " << mode << "\n";
            return 1;
        }
    }

    return 0;
}

int main(int argc, char** argv)
{
    options_description desc_cmd(
        "usage: " PIKA_APPLICATION_STRING " [options]");

    // clang-format off
    desc_cmd.add_options()
        ("iterations", value<std::size_t>()->default_value(1000),
         "Number of iterations")
        ("block-size", value<std::size_t>()->default_value(256),
         "Block size of the different chunks to calculate in parallel")
        ("matrix", value<std::string>(),
         "Filename of the input matrix (Matrix Market format)")
        ("vector", value<std::string>(), "Filename of the right hand side vector")
        ("mode", value<std::string>()->default_value("solve"),
        "Mode of the program, can be solve or statistics (default: solve)");
    // clang-format on

#if defined(JACOBI_SMP_NO_pika)
    variables_map vm;
    desc_cmd.add_options()("help", "This help message");
    store(parse_command_line(argc, argv, desc_cmd), vm);
    if (vm.count("help"))
    {
        std::cout << desc_cmd;
        return 1;
    }
    return pika_main(vm);
#else
    pika::init_params init_args;
    init_args.desc_cmdline = desc_cmd;

    return pika::init(pika_main, argc, argv, init_args);
#endif
}


#include <vector>
#include <iostream>
#include <fstream>
#include <string>
#include <iterator>
#include <regex>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/topological_sort.hpp>
#include <boost/graph/breadth_first_search.hpp>


//
//  bcdof.hpp
//  hybrid_fem_bie
//
//  Created by Max on 2/5/18.
//
//

#ifndef bcdof_hpp
#define bcdof_hpp

#include <stdio.h>
#include <Eigen/Eigen>
using namespace Eigen;
void bcdof(VectorXi node, int dim, VectorXi &index);

#endif /* bcdof_hpp */


#ifndef __HODLR_Node__
#define __HODLR_Node__

#include <Eigen/Dense>
#include "HODLR_Matrix.hpp"

class HODLR_Node
{
friend class HODLR_Tree;

// All methods are declared as private since all usage happens from
// the friend class HODLR_Tree:
private:
    HODLR_Node(int node_number, int level_number, int local_number,
               int n_start, int n_size, double tolerance);

    // Storing the information passed to constructor as attribute:
    int node_number, level_number, local_number;
    int n_start, n_size;
    // Storing the start locations and sizes for the children of the node:
    int c_start[2], c_size[2];
    // Tolerance for the computation carried out:
    double tolerance;

    // This stores the matrix directly(i.e at the leaf level)
    Mat K;

    // Variables and methods needed for HODLR solver
    Mat U[2], V[2];
    Mat U_factor[2], V_factor[2];
    Eigen::PartialPivLU<Mat> K_factor_LU;
    int rank[2];
    // Variables needed for symmetric factorization
    // Unitary matrices:
    Mat Q[2];
    Eigen::LLT<Mat> K_factor_LLT;

    // Methods for Leaf Nodes:
    void assembleLeafNode(HODLR_Matrix* A);
    void matmatProductLeaf(Mat x, Mat& b);

    // Methods for Non-leaf Nodes:
    void assembleNonLeafNode(HODLR_Matrix* A, bool is_sym);
    void matmatProductNonLeaf(Mat x, Mat& b);

    // Method to print the parameters of the node(mainly used to debug)
    void printNodeDetails();
};

#endif /*__HODLR_Node__*/


#ifndef BASIS_HPP
#define BASIS_HPP

#include <polyfem/Quadrature.hpp>
#include <polyfem/Types.hpp>

#include <Eigen/Dense>
#include <functional>

#include <vector>

namespace polyfem
{
	///
	/// @brief      Represents a virtual node of the FEM mesh as a weighted sum
	///             of real (unknown) nodes. This class stores the id, weights
	///             and positions of the real mesh nodes to use in the weighted
	///             sum.
	///
	class Local2Global
	{
	public:
		int index;	// global index of the actual node
		double val; // weight

		RowVectorNd node; // node position

		Local2Global()
			: index(-1), val(0)
		{
		}

		Local2Global(const int _index, const RowVectorNd &_node, const double _val)
			: index(_index), val(_val), node(_node)
		{
		}
	};

	///
	/// @brief      Represents one basis function and its gradient.
	///
	class Basis
	{

	public:
		typedef std::function<void(const Eigen::MatrixXd &uv, Eigen::MatrixXd &val)> Fun;

		Basis();

		///
		/// @brief      Initialize a basis function within an element
		///
		/// @param[in]  global_index  { Global index of the node associated to the basis }
		/// @param[in]  local_index   { Local index of the node within the element }
		/// @param[in]  node          { 1 x dim position of the node associated to the basis }
		///
		void init(const int order, const int global_index, const int local_index, const RowVectorNd &node);

		///
		/// @brief      Checks if global is empty or not
		///
		inline bool is_complete() const { return !global_.empty(); }

		///
		/// @brief      Evaluates the basis function over a set of uv
		///             parameters.
		///
		/// @param[in]  uv    { #uv x dim matrix of parameters to evaluate }
		/// @param[out] val   { #uv x 1 vector of computed values }
		///
		void eval_basis(const Eigen::MatrixXd &uv, Eigen::MatrixXd &val) const
		{
			assert(basis_);
			basis_(uv, val);
		}

		///
		/// @brief      Evaluate the gradient of the basis function.
		///
		/// @param[in]  uv    { #uv x dim matrix of parameters to evaluate }
		/// @param[out] val   { #uv x dim matrix of computed gradients }
		///
		void eval_grad(const Eigen::MatrixXd &uv, Eigen::MatrixXd &val) const
		{
			assert(grad_);
			grad_(uv, val);
		}

		//list of local to global mappings
		inline const std::vector<Local2Global> &global() const { return global_; }
		inline std::vector<Local2Global> &global() { return global_; }

		//setting the basis lambda and its gradint
		inline void set_basis(const Fun &fun) { basis_ = fun; }
		inline void set_grad(const Fun &fun) { grad_ = fun; }

		inline bool is_defined() const { return (basis_ ? true : false); }
		inline int order() const { return order_; }

		//output
		friend std::ostream &operator<<(std::ostream &os, const Basis &obj)
		{
			os << obj.local_index_ << ":\n";
			for (auto l2g : obj.global_)
				os << "\tl2g: " << l2g.index << " (" << l2g.node << ") " << l2g.val << "\n";

			return os;
		}

	private:
		std::vector<Local2Global> global_; // list of real nodes influencing the basis
		int local_index_;				   // local index inside the element (for debugging purposes)
		int order_;

		Fun basis_; //basis and gadient
		Fun grad_;
	};
} // namespace polyfem

#endif //BASIS_HPP


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

#include "python_types.hxx"

#include <vigra/numerictraits.hxx>
#include <vigra/tinyvector.hxx>

#include <boost/python.hpp>
#include <boost/python/raw_function.hpp>

#include <sstream>
#include <iomanip>

namespace python = boost::python;

namespace vigra
{

template<class Vector>
PyObject * Vector__str__(Vector const & v)
{
        std::stringstream s;
        if(v.size() == 1)
        {
            s << v[0];
        }
        else if(v.size() > 0)
        {
            s << "(";
            unsigned int i = 0;
            for(; i<v.size()-1; ++i)
                s << v[i] << ", ";
            s << v[i] << ")";
        }
        else
        {
            // should not happen, can only be created from C++ anyways:
            s << "<empty PythonVector>";
        }
        return PyUnicode_FromString(s.str().c_str());
}

template <class Vector>
PyObject * Vector__repr__(Vector const & v)
{
        std::stringstream s;
        s << std::setprecision(16)
          << "Vector" << v.size() << "(";
        unsigned char i = 0;
        for(; i<v.size()-1; ++i)
            s << v[i] << ", ";
        s << v[i] << ")";
        return PyUnicode_FromString(s.str().c_str());
}

template<class Vector>
double Vector__getitem__(Vector const & p, unsigned int i)
{
    if(i >= p.size())
    {
        PyErr_SetString(PyExc_IndexError,
            "PythonVector.__getitem__(): index out of bounds.");
        python::throw_error_already_set();
    }
    return p[i];
}

template<class Vector>
void Vector__setitem__(Vector & p, unsigned int i, double v)
{
    if(i >= p.size())
    {
        PyErr_SetString(PyExc_IndexError,
            "PythonVector.__setitem__(): index out of bounds.");
        python::throw_error_already_set();
    }
    p[i] = v;
}

template<class Vector>
typename vigra::NumericTraits<typename Vector::value_type>::Promote
pyDot(Vector const & l, Vector const & r)
{
    return dot(l, r);
}

template<class Vector>
typename NormTraits<Vector>::NormType
pyNorm(Vector const & v)
{
    return norm(v);
}

using python::self;

template <class Vector>
struct VectorFromPython
{
    typedef Vector Type;

    VectorFromPython()
    {
        python::converter::registry::insert(
            &convertible, &construct, python::type_id<Type>());
    }

    static void* convertible(PyObject* obj)
    {
        PyObject *seq = PySequence_Fast(obj, "vector-from-python conversion");
        bool possible = (seq != NULL);

        if(possible)
        {
            possible = (PySequence_Size(seq) == Type::static_size);
            for(int i = 0; possible && (i < Type::static_size); ++i)
                possible = python::extract<double>(
                    PySequence_Fast_GET_ITEM(seq, i)).check();
            Py_XDECREF(seq);
        }
        else
            PyErr_Clear();

        return possible ? obj : NULL;
    }

    static void construct(PyObject* obj, python::converter::rvalue_from_python_stage1_data* data)
    {
        Type * const storage = reinterpret_cast<Type *>((
            reinterpret_cast<python::converter::rvalue_from_python_storage<Type> *>(
                data))->storage.bytes);

        PyObject *seq = PySequence_Fast(obj, "vector-from-python conversion");
        for(int i = 0; i < Type::static_size; ++i)
        {
            (*storage)[i] = python::extract<double>(
                PySequence_Fast_GET_ITEM(seq, i))();
        }
        Py_XDECREF(seq);

        data->convertible = storage;
    }
};

template <class Vector>
struct VectorPickleSuite : python::pickle_suite
{
    static python::tuple getinitargs(Vector const& v)
    {
        switch(Vector::static_size)
        {
          case 2:
              return python::make_tuple(v[0], v[1]);
          case 3:
              return python::make_tuple(v[0], v[1], v[2]);
          case 4:
              return python::make_tuple(v[0], v[1], v[2], v[3]);
          default:
              ;
        }
        PyErr_SetString(
            PyExc_TypeError,
            "VectorPickleSuite can only pickle Vector2/3/4.");
        python::throw_error_already_set();
        return python::make_tuple(); // never reached
    }
};

template <class Vector>
void defineVectorFunctions(python::class_<Vector> & cl)
{
    typedef typename Vector::value_type Value;
      cl.def(self == self)
        .def(self != self)
        .def(self + self)
        .def(self - self)
        .def(-self)
        .def(self * self)
        .def(self += self)
        .def(self -= self)
        .def(self *= self)
        .def(Value() * self)
        .def(self * Value())
        .def(self / Value())
        .def(self *= Value())
        .def(self /= Value())
        .def("__len__", &Vector::size)
        .def("size", &Vector::size)
        .def("norm", &Vector::magnitude)
        .def("squaredMagnitude", &Vector::squaredMagnitude)
        .def("__getitem__", &Vector__getitem__<Vector>)
        .def("__setitem__", &Vector__setitem__<Vector>)
        .def("__str__", &Vector__str__<Vector>)
        .def("__repr__", &Vector__repr__<Vector>)
        .def_pickle(VectorPickleSuite<Vector>());
    ;
    cl.attr("magnitude") = cl.attr("norm");
    python::def("norm", &pyNorm<Vector>);
    python::def("dot", &pyDot<Vector>);
}

} // namespace vigra

void defVectorConverters()
{
    using namespace vigra;
    using namespace boost::python;

    VectorFromPython<Vector2>();
    VectorFromPython<Vector3>();

    def("norm", &pyNorm<double>);
    scope().attr("magnitude") = scope().attr("norm"); // install alias

#ifndef AVOID_DUPLICATE_DEFINITION_FROM_VIGRANUMPYCORE
    defineVectorFunctions(python::class_<Vector2>("Vector2")
                          .def(python::init<double, double>()));
    defineVectorFunctions(python::class_<Vector3>("Vector3")
                          .def(python::init<double, double, double>()));
#endif
}


/*
 * Copyright 2017, Justin Carpentier, LAAS-CNRS
 *
 * This file is part of eigenpy.
 * eigenpy is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation, either version 3 of
 * the License, or (at your option) any later version.
 * eigenpy is distributed in the hope that it will be
 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.  You should
 * have received a copy of the GNU Lesser General Public License along
 * with eigenpy.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef __eigenpy_basic_preconditioners_hpp__
#define __eigenpy_basic_preconditioners_hpp__

#include "eigenpy/fwd.hpp"
#include <Eigen/IterativeLinearSolvers>

namespace eigenpy
{

  namespace bp = boost::python;

  template<typename Preconditioner>
  struct PreconditionerBaseVisitor
  : public bp::def_visitor< PreconditionerBaseVisitor<Preconditioner> >
  {
    typedef Eigen::MatrixXd MatrixType;
    typedef Eigen::VectorXd VectorType;

    template<class PyClass>
    void visit(PyClass& cl) const
    {
      cl
      .def(bp::init<>("Default constructor"))
      .def(bp::init<MatrixType>(bp::arg("A"),"Initialize the preconditioner with matrix A for further Az=b solving."))
#if EIGEN_VERSION_AT_LEAST(3,3,0)
      .def("info",&Preconditioner::info,
           "Returns success if the Preconditioner has been well initialized.")
#endif
      .def("solve",&solve,bp::arg("b"),
           "Returns the solution A * z = b where the preconditioner is an estimate of A^-1.")

      .def("compute",&Preconditioner::template compute<MatrixType>,bp::arg("mat"),
           "Initialize the preconditioner from the matrix value.",
           bp::return_value_policy<bp::reference_existing_object>())
      .def("factorize",&Preconditioner::template factorize<MatrixType>,bp::arg("mat"),
           "Initialize the preconditioner from the matrix value, i.e factorize the mat given as input to approximate its inverse.",
           bp::return_value_policy<bp::reference_existing_object>())
      ;

    }

  private:

    static VectorType solve(Preconditioner & self, const VectorType & b)
    {
      return self.solve(b);
    }

  };

  template<typename Scalar>
  struct DiagonalPreconditionerVisitor : PreconditionerBaseVisitor<Eigen::DiagonalPreconditioner<Scalar> >
  {
    typedef Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> MatrixType;
    typedef Eigen::DiagonalPreconditioner<Scalar> Preconditioner;

    template<class PyClass>
    void visit(PyClass& cl) const
    {
      cl
      .def(PreconditionerBaseVisitor<Preconditioner>())
      .def("rows",&Preconditioner::rows,"Returns the number of rows in the preconditioner.")
      .def("cols",&Preconditioner::cols,"Returns the number of cols in the preconditioner.")
      ;

    }

    static void expose()
    {
      bp::class_<Preconditioner>("DiagonalPreconditioner",
                                 "A preconditioner based on the digonal entrie.\n"
                                 "This class allows to approximately solve for A.x = b problems assuming A is a diagonal matrix.",
                                 bp::no_init)
      ;

    }
  };

#if EIGEN_VERSION_AT_LEAST(3,3,5)
  template<typename Scalar>
  struct LeastSquareDiagonalPreconditionerVisitor : PreconditionerBaseVisitor<Eigen::LeastSquareDiagonalPreconditioner<Scalar> >
  {
    typedef Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> MatrixType;
    typedef Eigen::LeastSquareDiagonalPreconditioner<Scalar> Preconditioner;

    template<class PyClass>
    void visit(PyClass&) const
    {
    }

    static void expose()
    {
      bp::class_<Preconditioner>("LeastSquareDiagonalPreconditioner",
                                 "Jacobi preconditioner for LeastSquaresConjugateGradient.\n"
                                 "his class allows to approximately solve for A' A x  = A' b problems assuming A' A is a diagonal matrix.",
                                 bp::no_init)
      .def(DiagonalPreconditionerVisitor<Scalar>())
      ;

    }
  };
#endif

  struct IdentityPreconditionerVisitor : PreconditionerBaseVisitor<Eigen::IdentityPreconditioner >
  {
    typedef Eigen::IdentityPreconditioner Preconditioner;

    template<class PyClass>
    void visit(PyClass&) const
    {
    }

    static void expose()
    {
      bp::class_<Preconditioner>("IdentityPreconditioner",
                                 bp::no_init)
      .def(PreconditionerBaseVisitor<Preconditioner>())
      ;

    }
  };

} // namespace eigenpy

#endif // ifndef __eigenpy_basic_preconditioners_hpp__


//  Copyright Neil Groves 2009. Use, modification and
//  distribution is subject to the Boost Software License, Version
//  1.0. (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//
//
// For more information, see http://www.boost.org/libs/range/
//
#include <boost/range/algorithm/set_algorithm.hpp>

#include <boost/test/test_tools.hpp>
#include <boost/test/unit_test.hpp>

#include <boost/assign.hpp>
#include <boost/bind.hpp>
#include <algorithm>
#include <functional>
#include <list>
#include <numeric>
#include <deque>
#include <vector>

namespace boost
{
    namespace
    {
        template<class Container1, class Iterator, class Container2>
        void check_result(
            Container1& reference,
            Iterator    reference_result,
            Container2& test_cont,
            Iterator    test_result
            )
        {
            BOOST_CHECK_EQUAL(
                std::distance<Iterator>(reference.begin(), reference_result),
                std::distance<Iterator>(test_cont.begin(), test_result)
                );

            BOOST_CHECK_EQUAL_COLLECTIONS(
                reference.begin(), reference.end(),
                test_cont.begin(), test_cont.end()
                );
        }

        template<class Container1, class Container2>
        void test(Container1& cont1, Container2& cont2)
        {
            typedef BOOST_DEDUCED_TYPENAME Container1::value_type value_t;
            typedef BOOST_DEDUCED_TYPENAME std::vector<value_t>::iterator iterator_t;

            std::vector<value_t> reference(cont1.size() + cont2.size());
            std::vector<value_t> test_cont(reference);

            iterator_t reference_result
                = std::set_intersection(cont1.begin(), cont1.end(),
                                        cont2.begin(), cont2.end(),
                                        reference.begin());

            iterator_t test_result
                = boost::set_intersection(cont1, cont2, test_cont.begin());

            check_result(reference, reference_result,
                         test_cont, test_result);

            test_result = boost::set_intersection(
                            boost::make_iterator_range(cont1), cont2,
                            test_cont.begin());

            check_result(reference, reference_result,
                         test_cont, test_result);

            test_result = boost::set_intersection(
                            cont1, boost::make_iterator_range(cont2),
                            test_cont.begin());

            check_result(reference, reference_result,
                         test_cont, test_result);

            test_result = boost::set_intersection(
                            boost::make_iterator_range(cont1),
                            boost::make_iterator_range(cont2),
                            test_cont.begin());

            check_result(reference, reference_result,
                         test_cont, test_result);
        }

        template<class Container, class BinaryPredicate>
        void sort_container(Container& cont, BinaryPredicate pred)
        {
            typedef BOOST_DEDUCED_TYPENAME Container::value_type value_t;

            std::vector<value_t> temp(cont.begin(), cont.end());
            std::sort(temp.begin(), temp.end(), pred);
            cont.assign(temp.begin(), temp.end());
        }

        template<class Container1,
                 class Container2,
                 class BinaryPredicate>
        void test_pred(Container1 cont1, Container2 cont2,
                       BinaryPredicate pred)
        {
            typedef BOOST_DEDUCED_TYPENAME Container1::value_type value_t;
            typedef BOOST_DEDUCED_TYPENAME std::vector<value_t>::iterator iterator_t;

            sort_container(cont1, pred);
            sort_container(cont2, pred);

            std::vector<value_t> reference(cont1.size() + cont2.size());
            std::vector<value_t> test_cont(reference);

            iterator_t reference_result
                = std::set_intersection(cont1.begin(), cont1.end(),
                                        cont2.begin(), cont2.end(),
                                        reference.begin(),
                                        pred);

            iterator_t test_result
                = boost::set_intersection(cont1, cont2, test_cont.begin(), pred);

            check_result(reference, reference_result,
                         test_cont, test_result);

            test_result = boost::set_intersection(
                            boost::make_iterator_range(cont1), cont2,
                            test_cont.begin(), pred);

            check_result(reference, reference_result,
                         test_cont, test_result);

            test_result = boost::set_intersection(
                            cont1, boost::make_iterator_range(cont2),
                            test_cont.begin(), pred);

            check_result(reference, reference_result,
                         test_cont, test_result);

            test_result = boost::set_intersection(
                            boost::make_iterator_range(cont1),
                            boost::make_iterator_range(cont2),
                            test_cont.begin(), pred);

            check_result(reference, reference_result,
                         test_cont, test_result);
        }

        template<class Container1, class Container2>
        void test_set_intersection_impl(
            Container1& cont1,
            Container2& cont2
            )
        {
            test(cont1, cont2);
            test_pred(cont1, cont2, std::less<int>());
            test_pred(cont1, cont2, std::greater<int>());
        }

        template<class Container1, class Container2>
        void test_set_intersection_impl()
        {
            using namespace boost::assign;

            Container1 cont1;
            Container2 cont2;

            test_set_intersection_impl(cont1, cont2);

            cont1.clear();
            cont2.clear();
            cont1 += 1;
            test_set_intersection_impl(cont1, cont2);

            cont1.clear();
            cont2.clear();
            cont2 += 1;
            test_set_intersection_impl(cont1, cont2);

            cont1.clear();
            cont2.clear();
            cont1 += 1,2,3,4,5,6,7,8,9;
            cont2 += 2,3,4;
            test_set_intersection_impl(cont1, cont2);

            cont1.clear();
            cont2.clear();
            cont1 += 2,3,4;
            cont2 += 1,2,3,4,5,6,7,8,9;
            test_set_intersection_impl(cont1, cont2);
        }

        void test_set_intersection()
        {
            test_set_intersection_impl< std::vector<int>, std::vector<int> >();
            test_set_intersection_impl< std::list<int>, std::list<int> >();
            test_set_intersection_impl< std::deque<int>, std::deque<int> >();
            test_set_intersection_impl< std::vector<int>, std::list<int> >();
            test_set_intersection_impl< std::list<int>, std::vector<int> >();
        }
    }
}

boost::unit_test::test_suite*
init_unit_test_suite(int argc, char* argv[])
{
    boost::unit_test::test_suite* test
        = BOOST_TEST_SUITE( "RangeTestSuite.algorithm.set_intersection" );

    test->add( BOOST_TEST_CASE( &boost::test_set_intersection ) );

    return test;
}


#include <QtCore/qglobal.h>
#include <QMessageBox>
#include "opengl_tools.h"

#include "Messages_interface.h"
#ifdef USE_SURFACE_MESH
#include "Kernel_type.h"
#include "Scene_surface_mesh_item.h"
#else
#include "Scene_polyhedron_item.h"
#endif
#include "Scene_polyhedron_selection_item.h"
#include "Scene_points_with_normal_item.h"
#include "Scene_polylines_item.h"

#include <CGAL/Three/Scene_interface.h>
#include <CGAL/Three/Polyhedron_demo_plugin_helper.h>
#include "ui_Selection_widget.h"

#include <QAction>
#include <QMainWindow>
#include <QApplication>

#include <map>

#include <boost/graph/adjacency_list.hpp>
#include <CGAL/boost/graph/split_graph_into_polylines.h>
#include <CGAL/Polygon_mesh_processing/border.h>
#include <CGAL/Polygon_mesh_processing/repair.h>
#include <Scene.h>

#ifdef USE_SURFACE_MESH
typedef Scene_surface_mesh_item Scene_face_graph_item;
#else
typedef Scene_polyhedron_item Scene_face_graph_item;
#endif

typedef Scene_face_graph_item::Face_graph Face_graph;
typedef boost::property_map<Face_graph,CGAL::vertex_point_t>::type VPmap;

struct Is_terminal
{
  template <typename VertexDescriptor, typename Graph>
  bool operator ()(VertexDescriptor , const Graph& )
  {
    return false; // degree(vd,g) != 2; is a bad test in case of parallel edges
  }
};

template <typename Graph>
struct Polyline_visitor
{
  Scene_polylines_item* item;
  const Graph& points_pmap;

  Polyline_visitor(Scene_polylines_item* item_,
                   const Graph& points_property_map)
    : item(item_),
      points_pmap(points_property_map)
  {}

  void start_new_polyline()
  {
    item->polylines.push_back( Scene_polylines_item::Polyline() );
  }

  void add_node(typename boost::graph_traits<Graph>::vertex_descriptor vd)
  {
    item->polylines.back().push_back(points_pmap[vd]);
  }
  void end_polyline(){}
};
using namespace CGAL::Three;
class Polyhedron_demo_selection_plugin :
  public QObject,
  public Polyhedron_demo_plugin_helper
{
  Q_OBJECT
    Q_INTERFACES(CGAL::Three::Polyhedron_demo_plugin_interface)
    Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.PluginInterface/1.0")
public:
  bool applicable(QAction*) const {
    return qobject_cast<Scene_face_graph_item*>(scene->item(scene->mainSelectionIndex()))
        || qobject_cast<Scene_polyhedron_selection_item*>(scene->item(scene->mainSelectionIndex()));
  }
  void print_message(QString message) { messages->information(message); }
  QList<QAction*> actions() const { return QList<QAction*>() << actionSelection; }

  void init(QMainWindow* mainWindow, CGAL::Three::Scene_interface* scene_interface, Messages_interface* m) {
    mw = mainWindow;
    scene = scene_interface;
    messages = m;
    actionSelection = new QAction(tr("Selection"), mw);
    connect(actionSelection, SIGNAL(triggered()), this, SLOT(selection_action()));
    last_mode = 0;
    dock_widget = new QDockWidget("Selection", mw);
    dock_widget->setVisible(false);

    ui_widget.setupUi(dock_widget);
    addDockWidget(dock_widget);

    connect(ui_widget.Select_all_button,  SIGNAL(clicked()), this, SLOT(on_Select_all_button_clicked()));
    connect(ui_widget.Select_all_NTButton,  SIGNAL(clicked()), this, SLOT(on_Select_all_NTButton_clicked()));
    connect(ui_widget.Add_to_selection_button,  SIGNAL(clicked()), this, SLOT(on_Add_to_selection_button_clicked()));
    connect(ui_widget.Clear_button,  SIGNAL(clicked()), this, SLOT(on_Clear_button_clicked()));
    connect(ui_widget.Clear_all_button,  SIGNAL(clicked()), this, SLOT(on_Clear_all_button_clicked()));
    connect(ui_widget.Inverse_selection_button,  SIGNAL(clicked()), this, SLOT(on_Inverse_selection_button_clicked()));
    connect(ui_widget.Select_isolated_components_button,  SIGNAL(clicked()), this, SLOT(on_Select_isolated_components_button_clicked()));
    connect(ui_widget.Get_minimum_button,  SIGNAL(clicked()), this, SLOT(on_Get_minimum_button_clicked()));
    connect(ui_widget.Create_selection_item_button,  SIGNAL(clicked()), this, SLOT(on_Create_selection_item_button_clicked()));
    connect(ui_widget.Selection_type_combo_box, SIGNAL(currentIndexChanged(int)),
            this, SLOT(on_Selection_type_combo_box_changed(int)));
    connect(ui_widget.lassoCheckBox, &QCheckBox::toggled,
            this, &Polyhedron_demo_selection_plugin::on_LassoCheckBox_changed);
    connect(ui_widget.Insertion_radio_button, SIGNAL(toggled(bool)), this, SLOT(on_Insertion_radio_button_toggled(bool)));
    connect(ui_widget.Brush_size_spin_box, SIGNAL(valueChanged(int)), this, SLOT(on_Brush_size_spin_box_changed(int)));
    connect(ui_widget.validateButton, SIGNAL(clicked()), this, SLOT(on_validateButton_clicked()));
    connect(ui_widget.Expand_reduce_button, SIGNAL(clicked()), this, SLOT(on_Expand_reduce_button_clicked()));
    connect(ui_widget.Select_sharp_edges_button, SIGNAL(clicked()), this, SLOT(on_Select_sharp_edges_button_clicked()));
    connect(ui_widget.selectionOrEuler, SIGNAL(currentChanged(int)), this, SLOT(on_SelectionOrEuler_changed(int)));
    connect(ui_widget.editionBox, SIGNAL(currentIndexChanged(int)), this, SLOT(on_editionBox_changed(int)));

    ui_widget.Add_to_selection_button->hide();
    ui_widget.Select_all_NTButton->hide();
    QObject* scene = dynamic_cast<QObject*>(scene_interface);
    if(scene) {
      connect(scene, SIGNAL(itemAboutToBeDestroyed(CGAL::Three::Scene_item*)), this, SLOT(item_about_to_be_destroyed(CGAL::Three::Scene_item*)));
      connect(scene, SIGNAL(newItem(int)), this, SLOT(new_item_created(int)));
    }
  }
  virtual void closure()
  {
    dock_widget->hide();
  }
Q_SIGNALS:
  void save_handleType();
  void set_operation_mode(int);
public Q_SLOTS:

  void connectItem(Scene_polyhedron_selection_item* new_item)
  {
    connect(this, SIGNAL(save_handleType()),new_item, SLOT(save_handleType()));
    connect(new_item, SIGNAL(updateInstructions(QString)), this, SLOT(setInstructions(QString)));
    connect(this, SIGNAL(set_operation_mode(int)),new_item, SLOT(set_operation_mode(int)));
    int item_id = scene->addItem(new_item);
    QObject* scene_ptr = dynamic_cast<QObject*>(scene);
    if (scene_ptr)
      connect(new_item,SIGNAL(simplicesSelected(CGAL::Three::Scene_item*)), scene_ptr, SLOT(setSelectedItem(CGAL::Three::Scene_item*)));
    connect(new_item,SIGNAL(isCurrentlySelected(Scene_facegraph_item_k_ring_selection*)), this, SLOT(isCurrentlySelected(Scene_facegraph_item_k_ring_selection*)));
    scene->setSelectedItem(item_id);
    on_SelectionOrEuler_changed(ui_widget.selectionOrEuler->currentIndex());
    if(last_mode == 0)
      on_Selection_type_combo_box_changed(ui_widget.Selection_type_combo_box->currentIndex());
  }
  // If the selection_item or the polyhedron_item associated to the k-ring_selector is currently selected,
  // set the k-ring_selector as currently selected. (A k-ring_selector tha tis not "currently selected" will
  // not process selection events)
  void isCurrentlySelected(Scene_facegraph_item_k_ring_selection* item)
  {
    if(scene->item_id(selection_item_map.find(item->poly_item)->second) == scene->mainSelectionIndex() ||
       scene->item_id(item->poly_item)== scene->mainSelectionIndex() )
      item->setCurrentlySelected(true);
    else
      item->setCurrentlySelected(false);
  }

  void setInstructions(QString s)
  {
    ui_widget.instructionsLabel->setText(s);
  }

  void selection_action() {
    dock_widget->show();
    dock_widget->raise();
    Scene_face_graph_item* poly_item = getSelectedItem<Scene_face_graph_item>();
    if(!poly_item || selection_item_map.find(poly_item) != selection_item_map.end()) { return; }
    Scene_polyhedron_selection_item* new_item = new Scene_polyhedron_selection_item(poly_item, mw);
    new_item->setName(QString("%1 (selection)").arg(poly_item->name()));
    connectItem(new_item);
  }

  Scene_polyhedron_selection_item* onTheFlyItem() {
    Scene_face_graph_item* poly_item = qobject_cast<Scene_face_graph_item*>(scene->item(scene->mainSelectionIndex()));
    if(!poly_item)
      return NULL;
    Scene_polyhedron_selection_item* new_item = new Scene_polyhedron_selection_item(poly_item, mw);
    new_item->setName(QString("%1 (selection)").arg(poly_item->name()));
    connectItem(new_item);
    return new_item;

  }
  // Select all
  void on_Select_all_button_clicked() {
    Scene_polyhedron_selection_item* selection_item = getSelectedItem<Scene_polyhedron_selection_item>();
    if(!selection_item)
      selection_item = onTheFlyItem();
    if(!selection_item)
    {
      print_message("Error: there is no selected polyhedron selection item!");
      return;
    }

    selection_item->select_all();
  }

  void on_Select_all_NTButton_clicked()
  {
    Scene_polyhedron_selection_item* selection_item = getSelectedItem<Scene_polyhedron_selection_item>();
    if(!selection_item)
      selection_item = onTheFlyItem();
    if(!selection_item) {
      print_message("Error: there is no selected polyhedron selection item!");
      return;
    }

    selection_item->select_all_NT();
  }

  void on_Add_to_selection_button_clicked()
  {

    Scene_polyhedron_selection_item* selection_item = getSelectedItem<Scene_polyhedron_selection_item>();
    if(!selection_item) {
      print_message("Error: there is no selected polyhedron selection item!");
      return;
    }

    selection_item->add_to_selection();
  }
  // Clear selection
  void on_Clear_button_clicked() {
    Scene_polyhedron_selection_item* selection_item = getSelectedItem<Scene_polyhedron_selection_item>();
    if(!selection_item) {
      print_message("Error: there is no selected polyhedron selection item!");
      return;
    }

    selection_item->clear();
  }
  void on_Clear_all_button_clicked(){
    Scene_polyhedron_selection_item* selection_item = getSelectedItem<Scene_polyhedron_selection_item>();
    if(!selection_item) {
      print_message("Error: there is no selected polyhedron selection item!");
      return;
    }

    selection_item->clear_all();
  }
  void on_Inverse_selection_button_clicked()
  {
    Scene_polyhedron_selection_item* selection_item = getSelectedItem<Scene_polyhedron_selection_item>();
    if(!selection_item) {
      print_message("Error: there is no selected polyhedron selection item!");
      return;
    }
    selection_item->inverse_selection();
  }
  // Isolated component related functions
  void on_Select_isolated_components_button_clicked() {
    Scene_polyhedron_selection_item* selection_item = getSelectedItem<Scene_polyhedron_selection_item>();
    if(!selection_item)
      selection_item = onTheFlyItem();
    if(!selection_item) {
      print_message("Error: there is no selected polyhedron selection item!");
      return;
    }

    boost::optional<std::size_t> minimum =
      selection_item->select_isolated_components(ui_widget.Threshold_size_spin_box->value());
    if(minimum) {
      ui_widget.Threshold_size_spin_box->setValue((int) *minimum);
    }
  }
  void on_Get_minimum_button_clicked() {
    Scene_polyhedron_selection_item* selection_item = getSelectedItem<Scene_polyhedron_selection_item>();
    if(!selection_item)
      selection_item = onTheFlyItem();
    if(!selection_item) {
      print_message("Error: there is no selected polyhedron selection item!");
      return;
    }
    boost::optional<std::size_t> minimum = selection_item->get_minimum_isolated_component();
    if(minimum) {
      ui_widget.Threshold_size_spin_box->setValue((int) *minimum);
    }
  }
  // Create selection item for selected polyhedron item
  void on_Create_selection_item_button_clicked() {
    Scene_face_graph_item* poly_item = getSelectedItem<Scene_face_graph_item>();
    if(!poly_item) {
      print_message("Error: there is no selected polyhedron item!");
      return;
    }
    // all other arrangements (putting inside selection_item_map), setting names etc,
    // other params (e.g. k_ring) will be set inside new_item_created
    Scene_polyhedron_selection_item* new_item = new Scene_polyhedron_selection_item(poly_item, mw);
    new_item->setName(QString("%1 (selection)").arg(poly_item->name()));
    ui_widget.selectionOrEuler->setCurrentIndex(last_mode);
    connectItem(new_item);
  }
  void on_LassoCheckBox_changed(bool b)
  {
    for(Selection_item_map::iterator it = selection_item_map.begin(); it != selection_item_map.end(); ++it)
    {
      it->second->set_lasso_mode(b);
    }
  }
  void on_Selection_type_combo_box_changed(int index) {
    typedef Scene_polyhedron_selection_item::Active_handle Active_handle;
    for(Selection_item_map::iterator it = selection_item_map.begin(); it != selection_item_map.end(); ++it) {
      it->second->set_active_handle_type(static_cast<Active_handle::Type>(index));
      Q_EMIT save_handleType();
      switch(index)
      {
      case 0:
      case 1:
      case 2:
        ui_widget.lassoCheckBox->show();
        break;
      default:
        ui_widget.lassoCheckBox->hide();
        ui_widget.lassoCheckBox->setChecked(false);
        it->second->set_lasso_mode(false);
        break;
      }
      if(index == 1)
      {
        ui_widget.Select_all_NTButton->show();
        ui_widget.Add_to_selection_button->hide();
        Q_EMIT set_operation_mode(-1);
      }
      else if(index == 4)
      {
        it->second->setPathSelection(true);
        ui_widget.Add_to_selection_button->show();
        ui_widget.Select_all_NTButton->hide();
        Q_EMIT set_operation_mode(-2);
      }
      else
      {
        ui_widget.Add_to_selection_button->hide();
        ui_widget.Select_all_NTButton->hide();
        it->second->setPathSelection(false);
        Q_EMIT set_operation_mode(-1);
      }
    }
  }
  void on_Insertion_radio_button_toggled(bool toggle){
    for(Selection_item_map::iterator it = selection_item_map.begin(); it != selection_item_map.end(); ++it) {
      it->second->set_is_insert(toggle);
    }
  }
  void on_Brush_size_spin_box_changed(int value) {
    for(Selection_item_map::iterator it = selection_item_map.begin(); it != selection_item_map.end(); ++it) {
      it->second->set_k_ring(value);
    }
  }

  void on_validateButton_clicked() {
    switch(ui_widget.operationsBox->currentIndex())
    {
    //Create Point Set Item from Selected Vertices
    case 0:
    {
      Scene_polyhedron_selection_item* selection_item = getSelectedItem<Scene_polyhedron_selection_item>();
      if(!selection_item) {
        print_message("Error: there is no selected polyhedron selection item!");
        return;
      }
      if(selection_item->selected_vertices.empty()) {
        print_message("Error: there is no selected vertex in polyhedron selection item!");
        return;
      }
      Scene_points_with_normal_item* point_item = new Scene_points_with_normal_item();
      point_item->setName(QString("%1-points").arg(selection_item->name()));
      Face_graph *poly = selection_item->polyhedron();
      VPmap vpm = get(CGAL::vertex_point,*poly);

      for(Scene_polyhedron_selection_item::Selection_set_vertex::iterator begin = selection_item->selected_vertices.begin();
         begin != selection_item->selected_vertices.end(); ++begin) {
        point_item->point_set()->insert(get(vpm,*begin));
      }
      scene->setSelectedItem( scene->addItem(point_item) );
      break;
    }
      //Create Polyline Item from Selected Edges
    case 1:
    {
      Scene_polyhedron_selection_item* selection_item = getSelectedItem<Scene_polyhedron_selection_item>();
      if(!selection_item) {
        print_message("Error: there is no selected polyhedron selection item!");
        return;
      }
      if(selection_item->selected_edges.empty()) {
        print_message("Error: there is no selected edge in polyhedron selection item!");
        return;
      }
      Scene_polylines_item* polyline_item = new Scene_polylines_item();
      polyline_item->setName(QString("%1-edges").arg(selection_item->name()));

      typedef boost::adjacency_list < boost::listS,
          boost::vecS,
          boost::undirectedS,
          Kernel::Point_3 > Edge_graph;

      Edge_graph edge_graph;
      std::map<fg_vertex_descriptor, Edge_graph::vertex_descriptor> p2vd;
      std::map<fg_vertex_descriptor, Edge_graph::vertex_descriptor>::iterator it_find;
      bool insert_OK;

      Face_graph * poly = selection_item->polyhedron();
      VPmap vpm = get(CGAL::vertex_point,*poly);
      for(Scene_polyhedron_selection_item::Selection_set_edge::iterator begin = selection_item->selected_edges.begin();
          begin != selection_item->selected_edges.end(); ++begin)
      {
        fg_vertex_descriptor source = target(opposite(halfedge(*begin,*poly),*poly),*poly);
        boost::tie(it_find, insert_OK)
            = p2vd.insert(std::make_pair(source, Edge_graph::vertex_descriptor()));
        if (insert_OK)
        {
          it_find->second = add_vertex(edge_graph);
          edge_graph[it_find->second] = get(vpm,source);
        }
        Edge_graph::vertex_descriptor src=it_find->second;

        fg_vertex_descriptor targ = target(halfedge(*begin,*poly),*poly);
        boost::tie(it_find, insert_OK)
            = p2vd.insert(std::make_pair(targ, Edge_graph::vertex_descriptor()));
        if (insert_OK)
        {
          it_find->second = add_vertex(edge_graph);
          edge_graph[it_find->second] = get(vpm,targ);
        }
        Edge_graph::vertex_descriptor tgt=it_find->second;
        boost::add_edge(src, tgt, edge_graph);
      }

      Polyline_visitor<Edge_graph> polyline_visitor(polyline_item, edge_graph);
      CGAL::split_graph_into_polylines( edge_graph,
                                        polyline_visitor,
                                        Is_terminal() );
      scene->setSelectedItem( scene->addItem(polyline_item) );
      scene->itemChanged(polyline_item);
      break;
    }
      //Create Polyhedron Item from Selected Facets
    case 2:
    {
      Scene_polyhedron_selection_item* selection_item = getSelectedItem<Scene_polyhedron_selection_item>();
      if(!selection_item) {
        print_message("Error: there is no selected polyhedron selection item!");
        return;
      }

      Scene_face_graph_item* poly_item = new Scene_face_graph_item();
      if(selection_item->export_selected_facets_as_polyhedron(poly_item->polyhedron())) {
        poly_item->setName(QString("%1-facets").arg(selection_item->name()));
        poly_item->invalidateOpenGLBuffers(); // for init()
        scene->setSelectedItem( scene->addItem(poly_item) );
        scene->itemChanged(poly_item);
      }
      else {
        delete poly_item;
        print_message("Error: polyhedron item is not created!");
      }
      break;
    }
      //Erase Selected Facets from Polyhedron Item
    case 3:
    {
      Scene_polyhedron_selection_item* selection_item = getSelectedItem<Scene_polyhedron_selection_item>();
      if(!selection_item) {
        print_message("Error: there is no selected polyhedron selection item!");
        return;
      }

      selection_item->erase_selected_facets();
      break;
    }
      //Keep connected components of Selected Facets
    case 4:
    {
      Scene_polyhedron_selection_item* selection_item = getSelectedItem<Scene_polyhedron_selection_item>();
      if (!selection_item) {
        print_message("Error: there is no selected polyhedron selection item!");
        return;
      }
      selection_item->keep_connected_components();
      break;
    }
      //Convert from Edge Selection to Facet Selection
    case 5:
    {
      Scene_polyhedron_selection_item* selection_item = getSelectedItem<Scene_polyhedron_selection_item>();
      if(!selection_item) {
        print_message("Error: there is no selected polyhedron selection item!");
        return;
      }
      if(selection_item->selected_edges.empty()) {
        print_message("Error: there is no selected edge in this polyhedron selection item!");
        return;
      }
      const Face_graph& poly = *selection_item->polyhedron();
      BOOST_FOREACH(Scene_polyhedron_selection_item::fg_edge_descriptor ed, selection_item->selected_edges)
      {
        selection_item->selected_facets.insert(face(halfedge(ed, poly), poly));
        selection_item->selected_facets.insert(face(opposite(halfedge(ed, poly), poly), poly));
      }
      selection_item->invalidateOpenGLBuffers();
      selection_item->itemChanged();
      break;
    }
      //Convert from Edge Selection to Point Selection
    case 6:
    {
      Scene_polyhedron_selection_item* selection_item = getSelectedItem<Scene_polyhedron_selection_item>();
      if(!selection_item) {
        print_message("Error: there is no selected polyhedron selection item!");
        return;
      }
      if(selection_item->selected_edges.empty()) {
        print_message("Error: there is no selected edge in this polyhedron selection item!");
        return;
      }
      const Face_graph& poly = *selection_item->polyhedron();

      BOOST_FOREACH(Scene_polyhedron_selection_item::fg_edge_descriptor ed, selection_item->selected_edges)
      {
        selection_item->selected_vertices.insert(target(halfedge(ed, poly), poly));
        selection_item->selected_vertices.insert(source(halfedge(ed, poly), poly));
      }
      selection_item->invalidateOpenGLBuffers();
      selection_item->itemChanged();
      break;
    }
      //Convert from Facet Selection to Bounding Edge Selection
    case 7:
    {
      Scene_polyhedron_selection_item* selection_item = getSelectedItem<Scene_polyhedron_selection_item>();
      if(!selection_item) {
        print_message("Error: there is no selected polyhedron selection item!");
        return;
      }
      if(selection_item->selected_facets.empty()) {
        print_message("Error: there is no selected facet in this polyhedron selection item!");
        return;
      }
      const Face_graph& poly = *selection_item->polyhedron();
      std::vector<Scene_polyhedron_selection_item::fg_halfedge_descriptor> boundary_edges;
      CGAL::Polygon_mesh_processing::border_halfedges(selection_item->selected_facets, poly, std::back_inserter(boundary_edges));
      BOOST_FOREACH(Scene_polyhedron_selection_item::fg_halfedge_descriptor h, boundary_edges)
      {
        selection_item->selected_edges.insert(edge(h, poly));
      }
      selection_item->invalidateOpenGLBuffers();
      selection_item->itemChanged();
      break;
    }
      //Convert from Facet Selection to Points Selection
    case 8:
    {
      Scene_polyhedron_selection_item* selection_item = getSelectedItem<Scene_polyhedron_selection_item>();
      if(!selection_item) {
        print_message("Error: there is no selected polyhedron selection item!");
        return;
      }
      if(selection_item->selected_facets.empty()) {
        print_message("Error: there is no selected facet in this polyhedron selection item!");
        return;
      }
      const Face_graph& poly = *selection_item->polyhedron();
      BOOST_FOREACH(Scene_polyhedron_selection_item::fg_face_descriptor fh, selection_item->selected_facets)
      {
        BOOST_FOREACH(Scene_polyhedron_selection_item::fg_halfedge_descriptor h, CGAL::halfedges_around_face(halfedge(fh,poly), poly) )
        {
          selection_item->selected_vertices.insert(target(h, poly));
        }
      }
      selection_item->invalidateOpenGLBuffers();
      selection_item->itemChanged();
      break;
    }
    default :
      break;
    }
    return;
  }

  void on_SelectionOrEuler_changed(int index)
  {
    Scene_polyhedron_selection_item* selection_item = getSelectedItem<Scene_polyhedron_selection_item>();
    if(selection_item)
      selection_item->on_Ctrlz_pressed();
    last_mode = index;
    switch(index)
    {
    //Selection mode
    case 0:
      Q_EMIT set_operation_mode(-1);
      on_Selection_type_combo_box_changed(ui_widget.Selection_type_combo_box->currentIndex());
      break;
      //Edition mode
    case 1:
    {
      VPmap vpmap = get(CGAL::vertex_point, *selection_item->polyhedron());
      bool is_valid = true;
      BOOST_FOREACH(boost::graph_traits<Face_graph>::face_descriptor fd, faces(*selection_item->polyhedron()))
      {
        if (CGAL::is_degenerate_triangle_face(fd,
                                              *selection_item->polyhedron(),
                                              vpmap,
                                              CGAL::Kernel_traits< boost::property_traits<VPmap>::value_type >::Kernel()))
        {
          is_valid = false;
          break;
        }
      }
      if(!is_valid)
      {
        QMessageBox::warning(mw,
                             tr("Degenerated Face_graph"),
                             tr("Degenerated faces have been detected. Problems may occur "
                                "for operations other tha \"Move point\". "));
      }
      Q_EMIT save_handleType();
      on_editionBox_changed(ui_widget.editionBox->currentIndex());
      break;
    }
    }
  }

  void on_editionBox_changed(int mode )
  {
    Scene_polyhedron_selection_item* selection_item = getSelectedItem<Scene_polyhedron_selection_item>();
    if(selection_item)
      selection_item->on_Ctrlz_pressed();
    if(ui_widget.selectionOrEuler->currentIndex() == 0)
    {
      Q_EMIT set_operation_mode(-1);
    }
    else
    {
      Q_EMIT set_operation_mode(mode);
    }
    switch(mode)
    {
    //Join vertex
    case 0:
    //Split vertex
    case 1:
    {
      QPixmap pm(":/cgal/Polyhedron_3/resources/euler_vertex.png");
      ui_widget.docImage_Label->setPixmap(pm);
      break;
    }
    //Join face
    case 3:
    //Split face
    case 4:
    {
      QPixmap pm(":/cgal/Polyhedron_3/resources/euler_facet.png");
      ui_widget.docImage_Label->setPixmap(pm);
      break;
    }
    //Collapse edge
    case 5:
    {
      QPixmap pm(":/cgal/Polyhedron_3/resources/general_collapse.png");
      ui_widget.docImage_Label->setPixmap(pm);
      break;
    }
    //Add center vertex
    case 7:
    //Remove center vertex
    case 8:
    {
      QPixmap pm(":/cgal/Polyhedron_3/resources/euler_center.png");
      ui_widget.docImage_Label->setPixmap(pm);
      break;
    }
    //Add vertex and face to border
    case 9:
    {
      QPixmap pm(":/cgal/Polyhedron_3/resources/add_facet1.png");
      ui_widget.docImage_Label->setPixmap(pm);
      break;
    }
    //add facet to border
    case 10:
    {
      QPixmap pm(":/cgal/Polyhedron_3/resources/add_facet2.png");
      ui_widget.docImage_Label->setPixmap(pm);
      break;
    }
    default:
      ui_widget.docImage_Label->clear();
      break;
    }
    on_LassoCheckBox_changed(ui_widget.lassoCheckBox->isChecked());
  }
  void on_Select_sharp_edges_button_clicked() {
    Scene_polyhedron_selection_item* selection_item = getSelectedItem<Scene_polyhedron_selection_item>();
    if(!selection_item)
      selection_item = onTheFlyItem();
    if (!selection_item) {
      print_message("Error: there is no selected polyhedron selection item!");
      return;
    }

    double angle = ui_widget.Sharp_angle_spinbox->value();
    selection_item->select_sharp_edges(angle);
    scene->itemChanged(selection_item);
  }

  void on_Expand_reduce_button_clicked() {
    Scene_polyhedron_selection_item* selection_item = getSelectedItem<Scene_polyhedron_selection_item>();
    if(!selection_item) {
      print_message("Error: there is no selected polyhedron selection item!");
      return;
    }

    int steps = ui_widget.Expand_reduce_spin_box->value();
    selection_item->expand_or_reduce(steps);
  }
  // To handle empty selection items coming from loader
  void new_item_created(int item_id) {
    typedef Scene_polyhedron_selection_item::Active_handle Active_handle;
    Scene_polyhedron_selection_item* selection_item =
      qobject_cast<Scene_polyhedron_selection_item*>(scene->item(item_id));
    if(!selection_item) { return; }

    Scene_face_graph_item* poly_item = getSelectedItem<Scene_face_graph_item>();
    if(!poly_item) {
      CGAL_assertion(selection_item->polyhedron_item() == NULL); // which means it is coming from selection_io loader
      print_message("Error: please select corresponding polyhedron item from Geometric Objects list.");
      scene->erase(item_id);
      return;
    }

    if(selection_item->polyhedron_item() == NULL) { //coming from selection_io loader
      if(!selection_item->actual_load(poly_item, mw)) {
        print_message("Error: loading selection item is not successful!");
        scene->erase(item_id);
        return;
      }
      selection_item->invalidateOpenGLBuffers();
      scene->itemChanged(selection_item);
    }
    // now set default params both for selection items coming from selection_io, or on_Create_selection_item_button_clicked
    Active_handle::Type aht = static_cast<Active_handle::Type>(ui_widget.Selection_type_combo_box->currentIndex());
    bool is_insert = ui_widget.Insertion_radio_button->isChecked();
    int k_ring = ui_widget.Brush_size_spin_box->value();

    selection_item->set_active_handle_type(aht);
    selection_item->set_is_insert(is_insert);
    selection_item->set_k_ring(k_ring);
    selection_item->setRenderingMode(Flat);
    if(selection_item->name() == "unamed") {
      selection_item->setName(tr("%1 (selection)").arg(poly_item->name()));
    }

    selection_item_map.insert(std::make_pair(poly_item, selection_item));
    connect(this, SIGNAL(save_handleType()),selection_item, SLOT(save_handleType()));
    connect(selection_item, SIGNAL(updateInstructions(QString)), this, SLOT(setInstructions(QString)));
    connect(this, SIGNAL(set_operation_mode(int)),selection_item, SLOT(set_operation_mode(int)));
    QObject* scene_ptr = dynamic_cast<QObject*>(scene);
    if (scene_ptr)
      connect(selection_item,SIGNAL(simplicesSelected(CGAL::Three::Scene_item*)), scene_ptr, SLOT(setSelectedItem(CGAL::Three::Scene_item*)));
    connect(selection_item,SIGNAL(isCurrentlySelected(Scene_facegraph_item_k_ring_selection*)), this, SLOT(isCurrentlySelected(Scene_facegraph_item_k_ring_selection*)));
    on_LassoCheckBox_changed(ui_widget.lassoCheckBox->isChecked());
    on_SelectionOrEuler_changed(ui_widget.selectionOrEuler->currentIndex());
    if(last_mode == 0)
      on_Selection_type_combo_box_changed(ui_widget.Selection_type_combo_box->currentIndex());
  }
  void item_about_to_be_destroyed(CGAL::Three::Scene_item* scene_item) {
    // if polyhedron item
    Scene_face_graph_item* poly_item = qobject_cast<Scene_face_graph_item*>(scene_item);
    if(poly_item) {
      std::pair<Selection_item_map::iterator, Selection_item_map::iterator> res =
        selection_item_map.equal_range(poly_item);

      for(Selection_item_map::iterator begin = res.first; begin != res.second; ) {
        Scene_polyhedron_selection_item* selection_item = begin->second;
        selection_item_map.erase(begin++); // first erase from map, because scene->erase will cause a call to this function
        scene->erase( scene->item_id(selection_item) );
      }
    }
    // if polyhedron selection item
    Scene_polyhedron_selection_item* selection_item = qobject_cast<Scene_polyhedron_selection_item*>(scene_item);
    if(selection_item) {
      Scene_face_graph_item* poly_item = selection_item->polyhedron_item();
      std::pair<Selection_item_map::iterator, Selection_item_map::iterator> res =
        selection_item_map.equal_range(poly_item);
      for(Selection_item_map::iterator begin = res.first; begin != res.second; ++begin) {
        if(begin->second == selection_item) {
          selection_item_map.erase(begin); break;
        }
      }
    }
  }

private:
  Messages_interface* messages;
  QAction* actionSelection;

  QDockWidget* dock_widget;
  Ui::Selection ui_widget;
typedef std::multimap<Scene_face_graph_item*, Scene_polyhedron_selection_item*> Selection_item_map;
  Selection_item_map selection_item_map;
  int last_mode;
}; // end Polyhedron_demo_selection_plugin

//Q_EXPORT_PLUGIN2(Polyhedron_demo_selection_plugin, Polyhedron_demo_selection_plugin)

#include "Selection_plugin.moc"


/******************************************************************************
 * Author:   Laurent Kneip                                                    *
 * Contact:  kneip.laurent@gmail.com                                          *
 * License:  Copyright (c) 2013 Laurent Kneip, ANU. All rights reserved.      *
 *                                                                            *
 * Redistribution and use in source and binary forms, with or without         *
 * modification, are permitted provided that the following conditions         *
 * are met:                                                                   *
 * * Redistributions of source code must retain the above copyright           *
 *   notice, this list of conditions and the following disclaimer.            *
 * * Redistributions in binary form must reproduce the above copyright        *
 *   notice, this list of conditions and the following disclaimer in the      *
 *   documentation and/or other materials provided with the distribution.     *
 * * Neither the name of ANU nor the names of its contributors may be         *
 *   used to endorse or promote products derived from this software without   *
 *   specific prior written permission.                                       *
 *                                                                            *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"*
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE  *
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE *
 * ARE DISCLAIMED. IN NO EVENT SHALL ANU OR THE CONTRIBUTORS BE LIABLE        *
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT         *
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY  *
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF     *
 * SUCH DAMAGE.                                                               *
 ******************************************************************************/

/**
 * \file OptimizationFunctor.hpp
 * \brief Generic functor base for use with the Eigen-nonlinear optimization
 *        toolbox.
 */

#ifndef OPENGV_OPTIMIZATIONFUNCTOR_HPP_
#define OPENGV_OPTIMIZATIONFUNCTOR_HPP_

#include <stdlib.h>
#include <Eigen/Eigen>
#include <Eigen/src/Core/util/DisableStupidWarnings.h>

using namespace std;
using namespace Eigen;

/**
 * \brief The namespace of this library.
 */
namespace opengv
{

/**
 * Generic functor base for use with the Eigen-nonlinear optimization
 * toolbox. Please refer to the Eigen-documentation for further information.
 */
template<typename _Scalar, int NX=Dynamic, int NY=Dynamic>
struct OptimizationFunctor
{
  /** undocumented */
  typedef _Scalar Scalar;
  /** undocumented */
  enum
  {
    InputsAtCompileTime = NX,
    ValuesAtCompileTime = NY
  };
  /** undocumented */
  typedef Matrix<Scalar,InputsAtCompileTime,1> InputType;
  /** undocumented */
  typedef Matrix<Scalar,ValuesAtCompileTime,1> ValueType;
  /** undocumented */
  typedef Matrix<Scalar,ValuesAtCompileTime,InputsAtCompileTime> JacobianType;

  /** undocumented */
  const int m_inputs;
  /** undocumented */
  const int m_values;

  /** undocumented */
  OptimizationFunctor() :
      m_inputs(InputsAtCompileTime),
      m_values(ValuesAtCompileTime) {}
  /** undocumented */
  OptimizationFunctor(int inputs, int values) :
      m_inputs(inputs),
      m_values(values) {}

  /** undocumented */
  int inputs() const
  {
    return m_inputs;
  }
  /** undocumented */
  int values() const
  {
    return m_values;
  }
};

}

#endif /* OPENGV_OPTIMIZATIONFUNCTOR_HPP_ */


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

#ifndef bempp_modified_aca_hpp
#define bempp_modified_aca_hpp

#include "../common/common.hpp"
#include "bempp/common/config_ahmed.hpp"

#ifdef WITH_AHMED

#ifdef __INTEL_COMPILER
#pragma warning(disable:381)
#endif

#include <apprx.h>

#ifdef __INTEL_COMPILER
#pragma warning(default:381)
#endif

#include <boost/scoped_array.hpp>
#include <limits>

namespace Bempp
{

// returns true if a pivot could be found (there were any nonapproximated
// rows or columns), false otherwise
template <class abs_T>
bool select_pivot_with_min_norm2(unsigned n, const abs_T* norm2,
                                 const int* apprx_times /* S or Z */,
                                 unsigned& pivot)
{
    pivot = n; // invalid value
    abs_T min_norm2 = std::numeric_limits<abs_T>::max();
    for (unsigned i = 0; i < n; ++i)
        if (apprx_times[i] >= 0 && norm2[i] < min_norm2) {
            min_norm2 = norm2[i];
            pivot = i;
        }
    return (pivot != n);
}

template<class T, class MATGEN_T>
bool ACAs(MATGEN_T& MatGen, unsigned b1, unsigned n1, unsigned b2, unsigned n2,
          double eps, unsigned kmax, unsigned i0, unsigned& k, T* &U, T* &V,
          const cluster* c1, const cluster* c2)
{
    typedef typename num_traits<T>::abs_type abs_T;
    unsigned no = 0; // number of crosses calculated so far
    unsigned klast;  // unused
    const unsigned maxit = std::min(n1, n2);

    abs_T scale = MatGen.scale(b1, n1, b2, n2, c1, c2); // set initial scale

    U = new T[(kmax+1)*n1]; // these arrays are expected to be
    V = new T[(kmax+1)*n2]; // deallocated by the caller
    assert(U != NULL && V != NULL);

    // arrays storing number of successful approximations of rows and columns
    boost::scoped_array<int> Z(new int[n1]), S(new int[n2]);
    for (unsigned l=0; l<n1; ++l)
        Z[l] = 0;
    for (unsigned l=0; l<n2; ++l)
        S[l] = 0;

    boost::scoped_array<T> orig_row(new T[n2]);
    boost::scoped_array<T> orig_col(new T[n1]);

    boost::scoped_array<abs_T> orig_row_norm2(new abs_T[n2]);
    boost::scoped_array<abs_T> orig_col_norm2(new abs_T[n1]);

    abs_T nrms2 = 0.; // squared Frobenius norm of U V^H

    const unsigned ROW = 0, COL = 1;
    const unsigned NORMAL = 0, FIRST_SHOT = 1, SECOND_SHOT = 2;
    unsigned mode = ROW;
    unsigned stage = NORMAL;

    k = 0;
    unsigned next_pivot = i0;

    // The relativeScale() function is expected to return an estimate of the
    // magnitude of the largest element in the block, relative to the magnitude
    // of the largest element in the whole matrix.
    // If the result is deemed small enough relative to eps, the block is taken to
    // be zero and its elements are not evaluate.
    // This can be useful in the approximation of strongly decaying kernels.
    // abs_T relscale = MatGen.relativeScale(b1, n1, b2, n2, c1, c2);
    // if (relscale < 1e-2 * eps)
    //     return true;

    do {
        ACA_status status;
        abs_T nrmlsk2; // product of squared norms of new columns of U and V
        bool retry_if_zero = (stage == NORMAL); // don't retry if shooting
        // compute a cross
        if (mode == ROW)
            status = ACA_row_step(
                        MatGen, b1, n1, b2, n2, klast, next_pivot, k, no,
                        Z.get(), S.get(), U, V, nrmlsk2, scale, c1, c2,
                        retry_if_zero, orig_row.get(), orig_col.get());
        else
            status = ACA_col_step(
                        MatGen, b1, n1, b2, n2, next_pivot, k, no,
                        Z.get(), S.get(), U, V, nrmlsk2, scale, c1, c2,
                        retry_if_zero, orig_row.get(), orig_col.get());
        // std::cout << "status = " << status << std::endl;

        bool stpcrit = false;
        if (status == ACA_STATUS_SUCCESS) {
            // check stopping criterion
            T sum = 0.;                            // update nrms2
            for (unsigned l=0; l<k; ++l)
                sum += blas::scpr(n1, U+l*n1, U+k*n1) * blas::scpr(n2, V+k*n2, V+l*n2);
            nrms2 += 2. * Re(sum) + nrmlsk2;

            stpcrit = (nrmlsk2 < eps * eps * nrms2);
            // adjust scale (estimated entry size of the next remainder)
            scale = sqrt(nrmlsk2/(n1*n2));
            // std::cout << "nrmlsk2: " << nrmlsk2 << ", nrms2: " << nrms2 << ", scale = " << scale
            //           << std::endl;

            ++k;
        } else if (status == ACA_STATUS_EARLY_EXIT)
            stpcrit = true;
        else {
            // in the last step no non-zero row/column could be found
            assert(status == ACA_STATUS_REMAINDER_IS_ZERO);
            return true;
        }

        if (stpcrit) {
            if (stage == SECOND_SHOT)
                return true;
            else if (stage == FIRST_SHOT) {
                if (mode == ROW) {
                    // select column pivot
                    bool found = select_pivot_with_min_norm2(
                                n2, orig_row_norm2.get(), S.get(), next_pivot);
                    if (!found) // no nonapproximated column could be found
                        return true;
                    mode = COL;
                } else {
                    // select row pivot
                    bool found = select_pivot_with_min_norm2(
                                n1, orig_col_norm2.get(), Z.get(), next_pivot);
                    if (!found) // no nonapproximated row could be found
                        return true;
                    mode = ROW;
                }
                stage = SECOND_SHOT;
            } else {
                assert(stage == NORMAL);
                for (unsigned i = 0; i < n2; ++i)
                    orig_row_norm2[i] = abs2(orig_row[i]);
                for (unsigned i = 0; i < n1; ++i)
                    orig_col_norm2[i] = abs2(orig_col[i]);
                if (mode == ROW) {
                    // select row pivot
                    bool found = select_pivot_with_min_norm2(
                                n1, orig_col_norm2.get(), Z.get(), next_pivot);
                    if (!found) // no nonapproximated row could be found
                        return true;
                }
                else {
                    // select column pivot
                    bool found = select_pivot_with_min_norm2(
                                n2, orig_row_norm2.get(), S.get(), next_pivot);
                    if (!found) // no nonapproximated column could be found
                        return true;
                }
                stage = FIRST_SHOT;
                // mode stays the same
            }
        } else
            stage = NORMAL;
            // mode stays the same

        // std::cout << "Stage: " << stage << ", mode: " << mode << "\n";
    } while (no < maxit && k < kmax);

    // std::cout << "Giving up" << std::endl;
    return false;
}

template<class T,class T1,class T2, class MATGEN_T>
void apprx_unsym_shooting(
        MATGEN_T& MatGen, mblock<T>* &mbl, bemblcluster<T1,T2>* bl,
        double eps, unsigned rankmax)
{
    apprx_unsym_generic(&ACAs<T, MATGEN_T>, MatGen, mbl, bl, eps, rankmax);
}

} // namespace Bempp

#endif // WITH_AHMED

#endif