////////////////////////////////////////////////////////////////////
//
// $Id: Param.hxx 2021/06/13 22:13:22 kanai Exp $
//
// Copyright (c) 2021 Takashi Kanai
// Released under the MIT license
//
////////////////////////////////////////////////////////////////////

#ifndef _PARAM_HXX
#define _PARAM_HXX 1

#include "MyMesh.hxx"

#define EIGEN_NO_DEBUG

#include <Eigen/Sparse>
#include <Eigen/OrderingMethods>
typedef Eigen::Triplet<double> T;

#define RECTANGLE 4

#define SPARSELU 1
#define BICGSTAB 2
int sol = SPARSELU;

#define COTW 1
#define MVW  2
int wei = MVW;

#define SAVE_VERTEX 1
#define SAVE_TEXCOORD 2
int sav = SAVE_VERTEX;

#if 0
// Boundary vertex is fixed or not
class Fixed {
public:
  Fixed(): isFixed_(false) {};
  ~Fixed(){};
  bool isFixed() const { return isFixed_; };
  void setIsFixed( bool f ) { isFixed_ = f; };

private:
  bool isFixed_;
};

OpenMesh::VPropHandleT<Fixed> ffs;
#endif

#define FIXED_BOUNDARY 1
#define NATURAL_BOUNDARY 2
int bou = FIXED_BOUNDARY;

// 0: vertex i, 1-N: its neighbor vertices j
class VVWeights {

public:

  VVWeights(){};
  ~VVWeights(){ w_.clear(); };

  double w( int i ) { return w_[i]; };
  int size() const { return w_.size(); };
  std::vector<double>& ws() { return w_; };
  void addWeight( double d ) { w_.push_back(d); };
  // for orbifold
  // void addWeight( double d, int pid ) {
  //   w_.push_back(d);
  //   param_id_.push_back( pid );
  // };
  void addParamID( MyMesh::VertexHandle& vh, int id ) {
    param_id_.insert( make_pair( vh, id ) );
  };
  int param_id( MyMesh::VertexHandle& vh ) { return param_id_[vh]; };
  bool setWeight( int i, double d ) {
    if ( i >= (int) w_.size() ) return false;
    w_[i] = d;
    return true;
  };

  void Print() {
    cout << "vvw" << endl;
    cout << "weight size " << size() << endl;
    for ( int i = 0; i < w_.size(); ++i )
      {
        cout << w_[i] << endl;
      }
    cout << "param_id " << endl;
    for ( std::map<MyMesh::VertexHandle,int>::iterator pi = param_id_.begin();
          pi != param_id_.end(); ++pi )
      {
        cout << "vt " << pi->first.idx() << " id " << pi->second << endl;
      }
  };

private:

  std::vector<double> w_;
  // parameter id for orbifold
  // for OF_BOUNDARY vertex, values are 1 (true), or -1 (false)
  std::map<MyMesh::VertexHandle,int> param_id_;

};

//////////////////////////////////////////////////////////////////////////////

#include "Orbifold.hxx"

class Param {

public:

  double cotw( MyMesh::Point& p0, MyMesh::Point& p1, MyMesh::Point& p2 ) {
    OMVector3d c1( p1 - p0 );
    OMVector3d c2( p2 - p0 );
    //double sin = OpenMesh::cross( c1, c2 ).length();
    double sin = c1.cross( c2 ).norm();
    //double angle = std::fabs( std::atan2(sin, OpenMesh::dot(c1, c2)) );
    double angle = std::fabs( std::atan2(sin, c1.dot(c2)) );

    // std::cout << "\tcot " << 1.0 / std::tan( angle ) << " tan " << std::tan( M_PI_2 - angle ) << std::endl;
    // if ( 1.0 / std::tan( angle ) - std::tan( M_PI_2 - angle ) > 1.0e-05 )
    //   std::cout << "diff!" << std::endl;
    return std::tan( M_PI_2 - angle );
  };

  double tan2w( MyMesh::Point& p0, MyMesh::Point& p1, MyMesh::Point& p2 ) {
    OMVector3d c1( p1 - p0 );
    OMVector3d c2( p2 - p0 );
    //double sin = OpenMesh::cross( c1, c2 ).length();
    double sin = c1.cross( c2 ).norm();
    //double angle = std::fabs( std::atan2(sin, OpenMesh::dot(c1, c2)) );
    double angle = std::fabs( std::atan2(sin, c1.dot(c2)) );

    // std::cout << "\tcot " << 1.0 / std::tan( angle ) << " tan " << std::tan( M_PI_2 - angle ) << std::endl;
    // if ( 1.0 / std::tan( angle ) - std::tan( M_PI_2 - angle ) > 1.0e-05 )
    //   std::cout << "diff!" << std::endl;
    return std::tan( angle / 2.0 );
  };

  //
  // A weight has to be doubled for natural boundary as described in [Karni 05]
  //
  double computeCotangentWeight( MyMesh& mesh, MyMesh::VertexIHalfedgeIter& vih_it ) {
    OpenMesh::SmartHalfedgeHandle a( *vih_it );
    return computeCotangentWeight( mesh, a );
    //    return computeCotangentWeight( mesh, (OpenMesh::SmartHalfedgeHandle&) *vih_it );
  };

  double computeCotangentWeight( MyMesh& mesh, OpenMesh::SmartHalfedgeHandle& iheh ) {
    // right face
    //auto iheh( *vih_it ); // vih_it.handle();
    //MyMesh::HalfedgeHandle iheh( *vih_it ); // vih_it.handle();
    // if ( mesh.from_vertex_handle( iheh ) == vh ) std::cout << "i from" << std::endl;
    // else if ( mesh.to_vertex_handle( iheh ) == vh ) std::cout << "i to" << std::endl;
    //auto next_iheh = iheh.next();
    //MyMesh::HalfedgeHandle next_iheh = mesh.next_halfedge_handle( *vih_it );
    // if ( mesh.from_vertex_handle( next_iheh ) == vh ) std::cout << "next i from" << std::endl;
    // else if ( mesh.to_vertex_handle( next_iheh ) == vh ) std::cout << "next i to" << std::endl
    // MyMesh::Point p0, p1, p2;
    auto p0 = mesh.point( iheh.next().to() );
    auto p1 = mesh.point( iheh.from() );
    auto p2 = mesh.point( iheh.to() );
    // auto p0 = mesh.point( mesh.to_vertex_handle( next_iheh ) );
    // auto p1 = mesh.point( mesh.from_vertex_handle( iheh ) );
    // auto p2 = mesh.point( mesh.to_vertex_handle( iheh ) );
    double al = cotw( p0, p1, p2 );

    // left face
    // MyMesh::HalfedgeHandle mheh = mesh.opposite_halfedge_handle( iheh );
    // if ( mesh.from_vertex_handle( mheh ) == vh ) std::cout << "m from" << std::endl;
    // else if ( mesh.to_vertex_handle( mheh ) == vh ) std::cout << "m to" << std::endl;
    // MyMesh::HalfedgeHandle next_mheh = mesh.next_halfedge_handle( mheh );
    auto mheh = iheh.opp();
    auto p3 = mesh.point( mheh.next().to() );
    auto p4 = mesh.point( mheh.from() );
    auto p5 = mesh.point( mheh.to() );
    // p0 = mesh.point( mesh.to_vertex_handle( next_mheh ) );
    // p1 = mesh.point( mesh.from_vertex_handle( mheh ) );
    // p2 = mesh.point( mesh.to_vertex_handle( mheh ) );
    double be = cotw( p3, p4, p5 );

    //return (al + be) / 2.0;
    return (al + be);
  };

  double computeMeanValueWeight( MyMesh& mesh, MyMesh::VertexIHalfedgeIter& vih_it ) {
    OpenMesh::SmartHalfedgeHandle a( *vih_it );
    return computeMeanValueWeight( mesh, a );
    //return computeMeanValueWeight( mesh, (OpenMesh::SmartHalfedgeHandle&) *vih_it );
  };

  double computeMeanValueWeight( MyMesh& mesh, OpenMesh::SmartHalfedgeHandle& iheh ) {
    // gamma
    //auto iheh( *vih_it ); // vih_it.handle();
    // auto next_iheh = iheh.next();
    //MyMesh::HalfedgeHandle iheh( *vih_it ); // vih_it.handle();
    //MyMesh::HalfedgeHandle next_iheh = mesh.next_halfedge_handle( iheh );
    //MyMesh::Point p0, p1, p2;
    auto p0 = mesh.point( iheh.next().from() );
    auto p1 = mesh.point( iheh.next().to() );
    auto p2 = mesh.point( iheh.from() );
    // auto p0 = mesh.point( mesh.from_vertex_handle( next_iheh ) );
    // auto p1 = mesh.point( mesh.to_vertex_handle( next_iheh ) );
    // auto p2 = mesh.point( mesh.from_vertex_handle( iheh ) );
    double ga = tan2w( p0, p1, p2 );
#if 0
    std::cout << "\t gamma p0 " << mesh.from_vertex_handle( next_iheh ).idx() << " "
              << " p1 "  << mesh.to_vertex_handle( next_iheh ).idx() << " "
              << " p2 "  << mesh.from_vertex_handle( iheh ).idx() << std::endl;
#endif

    // delta
    auto mheh = iheh.opp();
    // MyMesh::HalfedgeHandle mheh = mesh.opposite_halfedge_handle( iheh );
    // MyMesh::HalfedgeHandle next_mheh = mesh.next_halfedge_handle( mheh );
    auto p3 = mesh.point( mheh.from() ); // i
    auto p4 = mesh.point( mheh.next().from() ); //j
    auto p5 = mesh.point( mheh.next().to() );
    // p0 = mesh.point( mesh.from_vertex_handle( mheh ) ); // i
    // p1 = mesh.point( mesh.from_vertex_handle( next_mheh ) ); //j
    // p2 = mesh.point( mesh.to_vertex_handle( next_mheh ) );
    double de = tan2w( p3, p4, p5 );
#if 0
    std::cout << "\t delta p0 " << mesh.from_vertex_handle( mheh ).idx() << " "
              << " p1 "  << mesh.from_vertex_handle( next_mheh ).idx() << " "
              << " p2 "  << mesh.to_vertex_handle( next_mheh ).idx() << std::endl;
#endif

    // return (ga + de) / (p0 - p1).length();
    return (ga + de) / (p3 - p4).norm();
  };

  void constructBoundary( MyMesh& mesh, std::vector<MyMesh::VertexHandle>& bverts ) {

    // find a boundary vertex
    MyMesh::VertexHandle vh0;
    for ( auto vh : mesh.vertices() )
      {
        if ( mesh.is_boundary( vh ) )
          {
            vh0 = vh; // v_it.handle();
            //std::cout << "boundary vertex " << vh0.idx() << std::endl;
            break;
          }
      }

#if 0
    MyMesh::VertexIter v_it, v_end(mesh.vertices_end());
    for (v_it=mesh.vertices_begin(); v_it!=v_end; ++v_it)
      {
        MyMesh::VertexHandle vh = *v_it;
        if ( mesh.is_boundary( vh ) )
          {
            vh0 = vh; // v_it.handle();
            //std::cout << "boundary vertex " << vh0.idx() << std::endl;
            break;
          }
      }
#endif

    std::vector<MyMesh::VertexHandle> bv_tmp;

    // construct boundary vertices
    MyMesh::VertexHandle vh = vh0, prev_vh;
    do {
      bv_tmp.push_back( vh );
      MyMesh::VertexVertexIter vv_it;
      for ( vv_it = mesh.vv_iter( vh ); vv_it.is_valid(); ++vv_it )
        {
          MyMesh::VertexHandle vc = *vv_it; // vv_it.handle();
          if ( mesh.is_boundary( vc ) && (prev_vh != vc) )
            {
              //std::cout << "\tfound! " << vc.idx() << std::endl;
              prev_vh = vh;
              vh = vc;
              break;
            }
        }
    } while ( vh != vh0 );
    std::cout << "#boundary vertices: " << bv_tmp.size() << std::endl;

#if 1
    // reverse direction
    bverts.push_back( bv_tmp[0] );
    for ( int i = bv_tmp.size()-1; i > 0; --i )
      bverts.push_back( bv_tmp[i] );
#endif
#if 0
    for ( int i = 0; i < bv_tmp.size(); ++i )
      bverts.push_back( bv_tmp[i] );
#endif
  };

  void computeBoundaryMapping( MyMesh& mesh,
                               std::vector<double>& paramx,  std::vector<double>& paramy ) {
    // property handle to store a flag
    mesh.add_property(fffs);

    // construct boundary vertices
    std::vector<MyMesh::VertexHandle> bverts;
    constructBoundary( mesh, bverts );

    // corner coordinates
    std::vector<double> cornerx(RECTANGLE);
    std::vector<double> cornery(RECTANGLE);
    std::vector<MyMesh::VertexHandle> cornerv;
    // fix two vertices of the coordinates (0,0) or (1,1)
    cornerx[0] = 0.0; cornerx[1] = 1.0; cornerx[2] = 1.0; cornerx[3] = 0.0;
    cornery[0] = 0.0; cornery[1] = 0.0; cornery[2] = 1.0; cornery[3] = 1.0;

    // compute boundary length
    double blength = 0.0;
    int bvn = bverts.size();
    for ( int i = 0; i < bvn-1; ++i )
      {
        // blength += (mesh.point( bverts[i] ) - mesh.point( bverts[i+1] )).length();
        blength += (mesh.point( bverts[i] ) - mesh.point( bverts[i+1] )).norm();
      }
    // blength += (mesh.point( bverts[bvn-1] ) - mesh.point( bverts[0] )).length();
    blength += (mesh.point( bverts[bvn-1] ) - mesh.point( bverts[0] )).norm();
    std::cout << "boundary length " << blength << std::endl;

    // determine corner vertices
    double l4 = blength / (double) RECTANGLE;
    double tl = 0.0;
    cornerv.push_back( bverts[0] );
    paramx[ bverts[0].idx() ] = cornerx[0];
    paramy[ bverts[0].idx() ] = cornery[0];
    // (0,0)
    Fixed& ff = mesh.property( fffs, bverts[0] );
    ff.setIsFixed( true );

    int count = 1;
    for ( int i = 0; i < bvn-1; ++i )
      {
        // tl += (mesh.point( bverts[i] ) - mesh.point( bverts[i+1] )).length();
        tl += (mesh.point( bverts[i] ) - mesh.point( bverts[i+1] )).norm();
        if ( (tl > l4) && (count < RECTANGLE) )
          {
            cornerv.push_back( bverts[i] );
            paramx[ bverts[i].idx() ] = cornerx[count];
            paramy[ bverts[i].idx() ] = cornery[count];
            if ( count == 2 ) // (1,1)
              {
                Fixed& ff = mesh.property( fffs, bverts[i] );
                ff.setIsFixed( true );
              }
            tl = 0.0;
            ++count;
          }
      }

    std::cout << "corner vertices: ";
    for ( int i = 0; i < 4; ++i ) std::cout << cornerv[i].idx() << " ";
    std::cout << std::endl;

    // compute inner boundary coordinates
    std::vector<MyMesh::VertexHandle> innerv;
    count = 1;
    for ( int i = 0; i < bvn; ++i )
      {
        innerv.push_back( bverts[i] );
        if ( cornerv[count] == bverts[i] )
          {
            // compute the length of poly line
            double pll = 0.0;
            for ( int j = 0; j < (int) innerv.size()-1; ++j )
              {
                // pll += (mesh.point( innerv[j] ) - mesh.point( bverts[j+1] )).length();
                pll += (mesh.point( innerv[j] ) - mesh.point( bverts[j+1] )).norm();
              }
            // compute the ratio of length and compute parameter
            double cll = 0.0;
            // std::cout << "count " << count << std::endl;
            for ( int j = 0; j < (int) innerv.size()-1; ++j )
              {
                double t = cll / pll;
                double px = (1 - t) * cornerx[count-1] + t * cornerx[count];
                double py = (1 - t) * cornery[count-1] + t * cornery[count];
                paramx[ innerv[j].idx() ] = px;
                paramy[ innerv[j].idx() ] = py;
                // std::cout << "\t t " << t << " param " << px << " " << py << std::endl;
                // cll += (mesh.point( innerv[j] ) - mesh.point( bverts[j+1] )).length();
                cll += (mesh.point( innerv[j] ) - mesh.point( bverts[j+1] )).norm();
              }

            // next poly line
            ++count;
            innerv.clear();
            innerv.push_back( bverts[i] );
          }
      }
    //
    // last poly line
    //
    innerv.push_back( bverts[0] );
    double pll = 0.0;
    for ( int j = 0; j < (int) innerv.size()-1; ++j )
      {
        // pll += (mesh.point( innerv[j] ) - mesh.point( bverts[j+1] )).length();
        pll += (mesh.point( innerv[j] ) - mesh.point( bverts[j+1] )).norm();
      }
    // compute the ratio of length and compute parameter
    double cll = 0.0;
    // std::cout << "count " << count << std::endl;
    for ( int j = 0; j < (int) innerv.size()-1; ++j )
      {
        double t = cll / pll;
        double px = (1 - t) * cornerx[RECTANGLE-1] + t * cornerx[0];
        double py = (1 - t) * cornery[RECTANGLE-1] + t * cornery[0];
        paramx[ innerv[j].idx() ] = px;
        paramy[ innerv[j].idx() ] = py;
        // std::cout << "\t t " << t << " param " << px << " " << py << std::endl;
        // cll += (mesh.point( innerv[j] ) - mesh.point( bverts[j+1] )).length();
        cll += (mesh.point( innerv[j] ) - mesh.point( bverts[j+1] )).norm();
      }
  };

  ////////////////////////////////////////////////////////////////////////////////////////

  void applyParam_FixedBoundary( MyMesh& mesh,
                                 std::vector<double>& paramx, std::vector<double>& paramy,
                                 int sol_, int wei_ ) {
    int n_vt = mesh.n_vertices();

    //
    // boundary mapping
    // compute 2D parameters for boundary
    //
    computeBoundaryMapping( mesh, paramx, paramy );

    // property handle to store weights
    OpenMesh::VPropHandleT<VVWeights> vvws;
    mesh.add_property(vvws);

    //
    // compute weights
    //
    // MyMesh::VertexIter v_it, v_end(mesh.vertices_end());
    // for (v_it=mesh.vertices_begin(); v_it!=v_end; ++v_it)
    for ( auto vh : mesh.vertices() )
      {
        // for check
        //std::cout << i << " " << v_it.handle().idx() << std::endl;
        //if ( i != v_it.handle().idx() ) std::cout << "ng" << std::endl;

        VVWeights& vvw = mesh.property(vvws, vh);
        //VVWeights& vvw = mesh.property(vvws,*v_it);
        double wd = 0.0;
        vvw.addWeight( wd );
        //MyMesh::VertexHandle vh = v_it.handle();
        //std::cout << "v " << i << std::endl;

#if 0
        MyMesh::VertexHandle vh = *v_it;
        std::cout << "i = " << vh.idx() << std::endl;
#endif
        //OpenMesh::SmartVertexHandle vh(*v_it);
        for ( auto vih : vh.incoming_halfedges() )
          {
            double wdc;
            if ( wei_ == COTW )
              wdc = computeCotangentWeight( mesh, vih );
            else if ( wei_ == MVW )
              wdc = computeMeanValueWeight( mesh, vih );
            vvw.addWeight( wdc );
            wd -= wdc;
          }
#if 0
        MyMesh::VertexIHalfedgeIter vih_it;
        for (vih_it=mesh.vih_iter( *v_it ); vih_it.is_valid(); ++vih_it)
          {
            double wdc;
            if ( wei_ == COTW )
              wdc = computeCotangentWeight( mesh, vih_it );
            else if ( wei_ == MVW )
              wdc = computeMeanValueWeight( mesh, vih_it );
            vvw.addWeight( wdc );
            wd -= wdc;
          }
#endif

        vvw.setWeight( 0, wd );

#if 0
        std::vector<double>& ws = vvw.ws();
        for ( int j = 0; j < ws.size(); ++j )
          std::cout << "\t " << ws[j] << std::endl;
        std::cout << std::endl;
#endif
      }

    //
    // compute inner parameters
    //
    // build up sparse matrix A
    std::cout << "Setup sparse matrix ..." << std::endl;
    std::vector<Eigen::Triplet<double> > tripletList;
    // MyMesh::VertexIter v_it, v_end(mesh.vertices_end());
    // for (v_it=mesh.vertices_begin(); v_it!=v_end; ++v_it)
    for ( auto vh : mesh.vertices() )
      {
        //MyMesh::VertexHandle vh = *v_it;
        int i = vh.idx();
        // if ( !(mesh.is_boundary(vh)) )
        if ( !(vh.is_boundary()) )
          {
            VVWeights& vvw = mesh.property(vvws, vh);
            tripletList.push_back( Eigen::Triplet<double>(i, i, vvw.w(0)) );
            int k=1;
            // MyMesh::VertexVertexIter vv_it;
            // for (k=1, vv_it=mesh.vv_iter( vh ); vv_it.is_valid(); ++vv_it, ++k)
            for ( auto vvh : vh.vertices() )
              {
                // MyMesh::VertexHandle vvh = *vv_it;
                int j = vvh.idx();
                tripletList.push_back( Eigen::Triplet<double>(i, j, vvw.w(k)) );
                ++k;
              }
          }
        else
          tripletList.push_back( Eigen::Triplet<double>(i, i, 1.0) );
      }

    Eigen::SparseMatrix<double> spmat( n_vt, n_vt );
    spmat.setFromTriplets( tripletList.begin(), tripletList.end() );
    spmat.makeCompressed();

    // setup vector b
    Eigen::VectorXd xx(n_vt), xy(n_vt), bx(n_vt), by(n_vt);
    for ( int i = 0; i < n_vt; ++i )
      {
        bx[i] = paramx[i];
        by[i] = paramy[i];
      }

    // to symmetric positive-definite matrix
    // toSpd( spmat, bverts, bx, by );

    // solve x
    if ( sol_ == BICGSTAB )
      {
        Eigen::BiCGSTAB<Eigen::SparseMatrix<double> > solver(spmat);
        std::cout << "solve xcoords ..." << std::endl;
        xx = solver.solve(bx);
        std::cout << "solve ycoords ..." << std::endl;
        xy = solver.solve(by);
      }
    else if ( sol_ == SPARSELU )
      {
        Eigen::SparseLU<Eigen::SparseMatrix<double>, Eigen::COLAMDOrdering<int> > solver;

        solver.analyzePattern(spmat);
        // Compute the numerical factorization
        solver.factorize(spmat);
        //Use the factors to solve the linear system
        std::cout << "solve xcoords ..." << std::endl;
        xx = solver.solve(bx);
        std::cout << "solve ycoords ..." << std::endl;
        xy = solver.solve(by);
      }
    for ( int i = 0; i < n_vt; ++i )
      {
        paramx[i] = xx[i];
        paramy[i] = xy[i];
      }

#if 0
    for (v_it=mesh.vertices_begin(); v_it!=v_end; ++v_it)
      {
        MyMesh::VertexHandle vh = *v_it;
        int i = vh.idx();
        Fixed& ff = mesh.property( fffs, vh );
        if ( ff.isFixed() )
          {
            std::cout << "i " << i << " param " << paramx[i] << " " << paramy[i] << std::endl;
          }
      }
#endif

    mesh.remove_property(vvws);

    std::cout << "done." << std::endl;
  };

  void applyParam_NaturalBoundary( MyMesh& mesh,
                                   std::vector<double>& paramx, std::vector<double>& paramy,
                                   int sol_, int wei_ ) {
    const int n_vt = mesh.n_vertices();

#if 0
    //
    // boundary mapping
    //
    // compute 2D parameters for boundary
    computeBoundaryMapping( mesh, paramx, paramy );
#endif

#if 1
    //for (v_it=mesh.vertices_begin(); v_it!=v_end; ++v_it)
    for ( auto vh : mesh.vertices() )
      {
        //MyMesh::VertexHandle vh = *v_it;
        //if ( !(mesh.is_boundary(vh)) )
        Fixed& ff = mesh.property( fffs, vh );
        if ( !(ff.isFixed()) ) // not fixed
          {
            paramx[vh.idx()] = paramy[vh.idx()] = 0.0;
          }
      }
#endif

    // property handle to store weights
    OpenMesh::VPropHandleT<VVWeights> vvws;
    mesh.add_property(vvws);

    //
    // compute weights
    //
    //MyMesh::VertexIter v_it, v_end(mesh.vertices_end());
    // for (v_it=mesh.vertices_begin(); v_it!=v_end; ++v_it)
    for ( auto vh : mesh.vertices() )
      {
        // for check
        //std::cout << i << " " << v_it.handle().idx() << std::endl;
        //if ( i != v_it.handle().idx() ) std::cout << "ng" << std::endl;

        VVWeights& vvw = mesh.property(vvws, vh);
        double wd = 0.0;
        vvw.addWeight( wd );
        //MyMesh::VertexHandle vh = v_it.handle();
        //std::cout << "v " << i << std::endl;

        // OpenMesh::SmartVertexHandle vh(*v_it);
        for ( auto vih : vh.incoming_halfedges() )
          {
            double wdc;
            if ( wei_ == COTW )
              wdc = computeCotangentWeight( mesh, vih );
            else if ( wei_ == MVW )
              wdc = computeMeanValueWeight( mesh, vih );
            vvw.addWeight( wdc );
            wd -= wdc;
          }
#if 0
        MyMesh::VertexIHalfedgeIter vih_it;
        for (vih_it=mesh.vih_iter( *v_it ); vih_it.is_valid(); ++vih_it)
          {
            double wdc;
            if ( wei_ == COTW )
              wdc = computeCotangentWeight( mesh, vih_it );
            else if ( wei_ == MVW )
              wdc = computeMeanValueWeight( mesh, vih_it );
            vvw.addWeight( wdc );
            wd -= wdc;
          }
#endif

        vvw.setWeight( 0, wd );

#if 0
        std::vector<double>& ws = vvw.ws();
        for ( int j = 0; j < ws.size(); ++j )
          std::cout << "\t " << ws[j] << std::endl;
        std::cout << std::endl;
#endif
      }

    //
    // compute inner parameters
    //
    // build up sparse matrix A
    std::cout << "Setup sparse matrix ..." << std::endl;
    std::vector<Eigen::Triplet<double> > tripletList;
    for ( auto vh : mesh.vertices() )
    // MyMesh::VertexIter v_it, v_end(mesh.vertices_end());
    // for (v_it=mesh.vertices_begin(); v_it!=v_end; ++v_it)
      {
        //MyMesh::VertexHandle vh = *v_it;
        int i = vh.idx();
        Fixed& ff = mesh.property( fffs, vh );
        if ( !(ff.isFixed()) ) // not fixed
          {
            VVWeights& vvw = mesh.property(vvws, vh);

            // set for x coord
            tripletList.push_back( Eigen::Triplet<double>(i, i, vvw.w(0)) );
            // set for y coord
            tripletList.push_back( Eigen::Triplet<double>(i+n_vt, i+n_vt, vvw.w(0)) );
            int k=1;
            for ( auto vvh : vh.vertices() )
            // MyMesh::VertexVertexIter vv_it;
            // for (k=1, vv_it=mesh.vv_iter( *v_it ); vv_it.is_valid(); ++vv_it, ++k)
              {
                // MyMesh::VertexHandle vvh = *vv_it;
                int j = vvh.idx();
                // set for x coord
                tripletList.push_back( Eigen::Triplet<double>(i, j, vvw.w(k)) );
                // set for y coord
                tripletList.push_back( Eigen::Triplet<double>(i+n_vt, j+n_vt, vvw.w(k)) );
                ++k;
              }

            // boundary vertices
            // if ( mesh.is_boundary(*v_it) )
            if ( vh.is_boundary() )
              {
#if 0
                std::cout << "id " << i << std::endl;
                for ( int j = 0; j < vvw.size(); ++j )
                  {
                    std::cout << "\t" << vvw.w(j) << std::endl;
                  }
#endif
                // get neighbor boundary vertices
                MyMesh::VertexVertexIter vv_it;
                vv_it=mesh.vv_iter( vh );
                MyMesh::VertexHandle sbvh = *vv_it, ebvh;
                while ( vv_it.is_valid() )
                  {
                    ebvh = *vv_it;
                    ++vv_it;
                  }
                int i1 = sbvh.idx();
                int i2 = ebvh.idx();

                if ( wei == COTW )
                  {
                    // std::cout << "i1 " << i1 << " " << mesh.is_boundary( sbvh ) << std::endl;
                    // std::cout << "i2 " << i2 << " " << mesh.is_boundary( ebvh ) << std::endl;

                    // for x coords
                    tripletList.push_back( Eigen::Triplet<double>(i, i2+n_vt, 1.0) );
                    tripletList.push_back( Eigen::Triplet<double>(i, i1+n_vt, -1.0) );
                    // tripletList.push_back( Eigen::Triplet<double>(i, i2+n_vt, -1.0) );
                    // tripletList.push_back( Eigen::Triplet<double>(i, i1+n_vt, 1.0) );

                    // for y coords
                    tripletList.push_back( Eigen::Triplet<double>(i+n_vt, i1, 1.0) );
                    tripletList.push_back( Eigen::Triplet<double>(i+n_vt, i2, -1.0) );
                    // tripletList.push_back( Eigen::Triplet<double>(i+n_vt, i1, -1.0) );
                    // tripletList.push_back( Eigen::Triplet<double>(i+n_vt, i2, 1.0) );
                  }
                else if ( wei == MVW )
                  {
                    MyMesh::Point p0 = mesh.point( vh );
                    MyMesh::Point p1 = mesh.point( sbvh );
                    MyMesh::Point p2 = mesh.point( ebvh );
                    // double ir1 = 1.0/((p1 - p0).length());
                    double ir1 = 1.0/((p1 - p0).norm());
                    // double ir2 = 1.0/((p2 - p0).length());
                    double ir2 = 1.0/((p2 - p0).norm());
                    // std::cout << ir1 << " " << ir2 << std::endl;
                    // for x coords
                    tripletList.push_back( Eigen::Triplet<double>(i, i2+n_vt, ir2) );
                    tripletList.push_back( Eigen::Triplet<double>(i, i1+n_vt, -ir1) );
                    tripletList.push_back( Eigen::Triplet<double>(i, i+n_vt, ir1 - ir2) );
                    // for y coords
                    tripletList.push_back( Eigen::Triplet<double>(i+n_vt, i1, ir1) );
                    tripletList.push_back( Eigen::Triplet<double>(i+n_vt, i2, -ir2) );
                    tripletList.push_back( Eigen::Triplet<double>(i+n_vt, i, ir2 - ir1) );
                  }
              }
          }
        else // fixed
          {
            // std::cout << "i = " << i << " param " << paramx[i] << " " << paramy[i] << std::endl;
            tripletList.push_back( Eigen::Triplet<double>(i, i, 1.0) );
            tripletList.push_back( Eigen::Triplet<double>(i+n_vt, i+n_vt, 1.0) );
          }
      }

    Eigen::SparseMatrix<double> spmat( 2*n_vt, 2*n_vt );
    spmat.setFromTriplets( tripletList.begin(), tripletList.end() );
    spmat.makeCompressed();

    // setup vector b
    //Eigen::VectorXd xx(n_vt), xy(n_vt), bx(n_vt), by(n_vt);
    Eigen::VectorXd xx(2*n_vt), bx(2*n_vt);
    for ( int i = 0; i < n_vt; ++i )
      {
        // set for x coord
        bx[i] = paramx[i];
        // set for y coord
        bx[i+n_vt] = paramy[i];
      }

    // solve x
    if ( sol_ == BICGSTAB )
      {
        Eigen::BiCGSTAB<Eigen::SparseMatrix<double> > solver(spmat);
        std::cout << "solve x and y coords ..." << std::endl;
        xx = solver.solve(bx);
        // std::cout << "solve ycoords ..." << std::endl;
        // xy = solver.solve(by);
      }
    else if ( sol_ == SPARSELU )
      {
        Eigen::SparseLU<Eigen::SparseMatrix<double>, Eigen::COLAMDOrdering<int> > solver;

        solver.analyzePattern(spmat);
        // Compute the numerical factorization
        solver.factorize(spmat);
        //Use the factors to solve the linear system
        std::cout << "solve x and y coords ..." << std::endl;
        xx = solver.solve(bx);
        // std::cout << "solve ycoords ..." << std::endl;
        // xy = solver.solve(by);
      }
    for ( int i = 0; i < n_vt; ++i )
      {
        paramx[i] = xx[i];
        paramy[i] = xx[i+n_vt];
      }

#if 0
    for (v_it=mesh.vertices_begin(); v_it!=v_end; ++v_it)
      {
        MyMesh::VertexHandle vh = *v_it;
        int i = vh.idx();
        Fixed& ff = mesh.property( fffs, vh );
        if ( ff.isFixed() )
          {
            std::cout << "i " << i << " param " << paramx[i] << " " << paramy[i] << std::endl;
          }
      }
#endif

    mesh.remove_property(vvws);

    std::cout << "done." << std::endl;
  };

  MyMesh::VertexIHalfedgeCWIter start_vih_cwiter( MyMesh::VertexHandle& vh,
                                                  MyMesh::VertexHandle& pvh,
                                                  MyMesh& mesh ) {
    int c = 0;
    MyMesh::VertexIHalfedgeCWIter vih_cwit = mesh.vih_cwiter( vh );
    while (1)
      {
        if ( mesh.from_vertex_handle( *vih_cwit ) == pvh )
          return vih_cwit;
        ++vih_cwit; ++c;
      }
  };

  MyMesh::VertexOHalfedgeCWIter start_voh_cwiter( MyMesh::VertexHandle& vh,
                                                  MyMesh::VertexHandle& pvh,
                                                  MyMesh& mesh ) {
    int c = 0;
    MyMesh::VertexOHalfedgeCWIter voh_cwit = mesh.voh_cwiter( vh );
    while (1)
      {
        if ( mesh.to_vertex_handle( *voh_cwit ) == pvh )
          return voh_cwit;
        ++voh_cwit; ++c;
      }
  };

  MyMesh::VertexOHalfedgeCCWIter start_voh_ccwiter( MyMesh::VertexHandle& vh,
                                                    MyMesh::VertexHandle& pvh,
                                                    MyMesh& mesh ) {
    int c = 0;
    MyMesh::VertexOHalfedgeCCWIter voh_ccwit = mesh.voh_ccwiter( vh );
    while (1)
      {
        if ( mesh.to_vertex_handle( *voh_ccwit ) == pvh )
          return voh_ccwit;
        ++voh_ccwit; ++c;
      }
  };

  MyMesh::VertexVertexIter start_vv_iter( MyMesh::VertexVertexIter vv_it,
                                          MyMesh::VertexHandle& pvt ) {
    int c = 0;
    while (1)
      {
        if ( *vv_it == pvt )
          {
            // cout << "count " << c << endl;
            return vv_it;
          }
        ++vv_it; ++c;
      }
  };

  //
  // set param_id to vvw of 1-ring neighbor vertices for boundary vertices
  //
  void setParamID_I( MyMesh::VertexHandle& vh,
                     VVWeights& vvw,
                     std::map<MyMesh::VertexHandle,int>& alt_param_id,
                     MyMesh& mesh,
                     std::vector<unsigned int>& vertex_type,
                     bool reverse ) {
    // if vh is OF_INTERNAL, apply add param_id to only 1-ring neighbor points
    // with OF_BOUNDARY or OF_CONESINGULARITY_PI2.
    // cout << "internal vt " << vh.idx() << " 1-ring neighbor start" << endl;
    for ( MyMesh::VertexVertexIter vv_it = mesh.vv_iter( vh ); vv_it.is_valid(); ++vv_it )
      {
        MyMesh::VertexHandle vvh = *vv_it;
        int id = vvh.idx();
        int rev_id = alt_param_id[vvh];
        // cout << "\tvertex " << id << endl;
        if ( (vertex_type[ id ] == OF_BOUNDARY) ||
             (vertex_type[ id ] == OF_CONESINGULARITY_PI2)  )
          {
            // if a 1-ring neighbor vertex is OF_BOUNDARY or OF_CONESINGULARITY_PI2,
            // set param_id to its original id or alt_param_id
            // TODO: 11/29 ここのところもう一度見直す
            if ( reverse == false )
              {
                // 11/29 下と交換
                // vvw.addParamID( vvh, id );
                vvw.addParamID( vvh, rev_id );
                // cout << "\tvt " << id << " type " << vertex_type[id] << " reverse " << reverse << " param " << rev_id << endl;
              }
            else
              {
                // 11/29 上と交換
                // vvw.addParamID( vvh, rev_id );
                vvw.addParamID( vvh, id );
                // cout << "\tvt " << id << " type " << vertex_type[id] << " reverse " << reverse << " param " << id << endl;
              }
          }
      }
    // cout << "internal 1-ring neighbor end" << endl;
  };

  void setParamID_B( MyMesh::VertexHandle& vh,
                     MyMesh::VertexHandle& pvh,
                     MyMesh::VertexHandle& nvh,
                     VVWeights& vvw,
                     std::map<MyMesh::VertexHandle,int>& alt_param_id,
                     MyMesh& mesh,
                     std::vector<unsigned int>& vertex_type,
                     bool reverse ) {
    // if vh is OF_BOUNDARY or OF_CONESINGULARITY_PI2, apply add param_id
    /// to all 1-ring neighbor points.
    // TODO: reverse と rev の関係について見直す
    // cout << "boundary 1-ring neighbor start" << endl;
    bool rev = reverse;
    MyMesh::VertexVertexIter vv_it = start_vv_iter( mesh.vv_iter( vh ), pvh );
    MyMesh::VertexHandle svh = *vv_it;
    // int i;
    // for ( i = 0, vv_it = mesh.vv_iter( vh ); vv_it.is_valid(); ++vv_it, ++i ) {
    do {
      MyMesh::VertexHandle vvh = *vv_it;
      int id = vvh.idx();

      // cout << "vertex " << id << endl;

      // set param_id to 1.0 (reverse=true) or -1.0 (reverse=false)
      if ( rev == false )
        {
          // 11/30 下と交換
          // vvw.addParamID( vvh, -1 );
          vvw.addParamID( vvh, 1 );
          // cout << "\tvt " << id << " type " << vertex_type[id] << " reverse " << rev << " param " << 1.0 << endl;
        }
      else // rev == true
        {
          // 11/30 上と交換
          // vvw.addParamID( vvh, 1 );
          vvw.addParamID( vvh, -1 );
          // cout << "\tvt " << id << " type " << vertex_type[id] << " reverse " << rev << " param " << -1.0 << endl;
        }
      ++vv_it;
      if ( !(vv_it.is_valid()) ) vv_it = mesh.vv_iter( vh ); // reset vv_it to start
      if ( *vv_it == nvh )
        {
          rev = ( rev == true ) ? false : true; // parameter is changed from nvt
        }
    } while ( *vv_it != svh );
    // cout << "boundary 1-ring neighbor end" << endl;
  };

  int applyParam_Orbifold( MyMesh& mesh,
                           Orbifold& orbi,
                           // std::vector<MyMesh::VertexHandle>& cs_vertices,
                           std::vector<double>& paramx, std::vector<double>& paramy,
                           int sol_, int wei_ ) {

    cout << "compute orbifold parameterization ... " << endl;

    int n_vt = mesh.n_vertices();

    // set orbifold boundary
    orbi.calcBoundaries();

    // cone singularity vertices
    std::vector<MyMesh::VertexHandle>& cs_vertices = orbi.cs_vertices();

    // parameters setup
    std::vector<std::vector<MyMesh::VertexHandle> >& path = orbi.path();

    // the number of parameter vertices
    // - mesh.n_vertices() + path[2].size()-2 + path[3].size()-2 + 1 (cs_vertex[3])
    // - two parameters in each vertex of type OF_BOUNDARY or OF_CONESINGULARITY_PI2
    static int n_param = mesh.n_vertices() + path[2].size()-2 + path[3].size()-2 + 1;
    // cout << "vertices " << mesh.n_vertices() << " parameters " << n_param << endl;
    paramx.resize( n_param );
    paramy.resize( n_param );

    // cout << "0----------------------------------------------------------" << endl;
    // set a param_id pair and a center for OF_BOUNDARY vertex
    std::map<MyMesh::VertexHandle,int> alt_param_id;
    int param_id = mesh.n_vertices(); // alt_param_id starts from mesh.n_vertices()
    for ( int i = 0; i < path.size() / 2; ++i ) // search for only two paths
      {
        // cone singularities are not concerned
        for ( int j = 1; j < path[i].size() - 1; ++j )
          {
            MyMesh::VertexHandle vt = path[i][j];
            alt_param_id.insert( make_pair(vt, param_id) );
            // cout << "\t\t " << vt.idx() << " " << alt_param_id[vt] << endl;
            ++param_id;
          }
      }
    // set a param_id pair for  OF_CONESINGULARITY_PI2 vertex
    // alt parameter is last one (n_param - 1)
    MyMesh::VertexHandle cs_vt = cs_vertices[1];
    alt_param_id.insert( make_pair(cs_vt, param_id) );
    ++param_id;

    // cout << "parameters " << n_param << " counts " << param_id << endl;

    // property handle to store weights
    OpenMesh::VPropHandleT<VVWeights> vvws;
    mesh.add_property(vvws);

    std::vector<unsigned int>& vertex_type = orbi.vertex_type();

    // cout << "1----------------------------------------------------------" << endl;
    // make consistent path from path no.0 and no.1
    std::vector<MyMesh::VertexHandle> path01;
    for ( int i = 0; i < path.size() / 2; ++i )
      for ( int j = 0; j < path[i].size(); ++j )
        if ( (i != 1) || (j != 0) ) path01.push_back( path[i][j] );

    // determine param_id for OF_BOUNDARY and OF_CONESINGULARITY_PI2 vertices of 1-ring neighbors
    for ( int i = 1; i < path01.size() - 1; ++i )
      {
    // for ( int i = 0; i < path.size()/2; ++i )
    //   {
    //     for ( int j = 1; j < path[i].size(); ++j )
    //       {
        // MyMesh::VertexHandle vh = path[i][j];    // current boundary vertex
        // MyMesh::VertexHandle pvh = path[i][j-1]; // prev boundary vertex
        // MyMesh::VertexHandle nvh = path[i][j+1]; // next boundary vertex
        MyMesh::VertexHandle vh = path01[i];    // current boundary vertex
        MyMesh::VertexHandle pvh = path01[i-1]; // prev boundary vertex
        MyMesh::VertexHandle nvh = path01[i+1]; // next boundary vertex

        // bool reverse = ( i > 1 ) ? true : false;
        // Since i < 2, reverse is always false.
        bool reverse = false;

        // processing OF_BOUNDARY point
        // cout << "(a) boundary vt " << vh.idx() << endl;
        if ( vertex_type[vh.idx()] == OF_BOUNDARY )
          {
            VVWeights& vvw = mesh.property(vvws, vh);
            setParamID_B( vh, pvh, nvh, vvw, alt_param_id, mesh, vertex_type, reverse );
            // vvw.Print();
          }

        // 1-ring neighbor vertices
        // start vv_it is set to prev boundary vertex
        MyMesh::VertexVertexIter vv_it = start_vv_iter( mesh.vv_iter( vh ), pvh );
        // cout << "vt " << vt.idx() << " pvt " << pvt.idx() << " start " << svt.idx() << endl;
        MyMesh::VertexHandle svh = *vv_it;
        // cout << "svh " << svh.idx() << endl;
        do {
          // processing 1-ring neighbors of OF_BOUNDARY point
          MyMesh::VertexHandle vvh = *vv_it;
          // if ( (vvh != pvh) && (vvh != nvh) )
          if ( vertex_type[vvh.idx()] == OF_INTERNAL )
            {
              // cout << "(b) should be internal vt " << vvh.idx() << endl;
              VVWeights& vvvw = mesh.property(vvws, vvh);
              setParamID_I( vvh, vvvw, alt_param_id, mesh, vertex_type, reverse );
            }

          ++vv_it;
          if ( !(vv_it.is_valid()) ) vv_it = mesh.vv_iter( vh ); // reset vv_it to start
          if ( *vv_it == nvh )
            {
              // cout << "evh " << nvh.idx() << endl;
              reverse = ( reverse == true ) ? false : true; // parameter is changed from nvt
            }
        } while ( *vv_it != svh );
        // }
      }
    // cout << "2----------------------------------------------------------" << endl;

    // set cone sigularities fixed
    //std::vector<MyMesh::VertexHandle>& cs_vertices = orbi.cs_vertices();
    int i0 = cs_vertices[0].idx();
    int i1 = cs_vertices[1].idx();
    int i2 = cs_vertices[2].idx();
    int i3 = alt_param_id[cs_vertices[1]];
    paramx[i0] = 0.0; paramy[i0] = 0.0;
    paramx[i1] = 1.0; paramy[i1] = 0.0;
    paramx[i2] = 1.0; paramy[i2] = 1.0;
    paramx[i3] = 0.0; paramy[i3] = 1.0;

    // cout << "cs " << cs_vertices[0].idx() << " " << cs_vertices[1].idx() << " "
    //      << cs_vertices[2].idx() << " " << n_param - 1 << endl;

    //
    // compute weights
    //
    MyMesh::VertexIter v_it, v_end(mesh.vertices_end());
    for (v_it=mesh.vertices_begin(); v_it!=v_end; ++v_it)
      {
        // for check
        //std::cout << i << " " << v_it.handle().idx() << std::endl;
        //if ( i != v_it.handle().idx() ) std::cout << "ng" << std::endl;

        VVWeights& vvw = mesh.property(vvws,*v_it);
        double wd = 0.0;
        vvw.addWeight( wd );
        //MyMesh::VertexHandle vh = v_it.handle();
        //std::cout << "v " << i << std::endl;

        MyMesh::VertexIHalfedgeIter vih_it;
        for (vih_it=mesh.vih_iter( *v_it ); vih_it.is_valid(); ++vih_it)
          {
            double wdc;
            if ( wei_ == COTW )
              wdc = computeCotangentWeight( mesh, vih_it );
            else if ( wei_ == MVW )
              wdc = computeMeanValueWeight( mesh, vih_it );
            vvw.addWeight( wdc );
            wd -= wdc;
          }

        vvw.setWeight( 0, wd );

#if 0
        std::vector<double>& ws = vvw.ws();
        for ( int j = 0; j < ws.size(); ++j )
          std::cout << "\t " << ws[j] << std::endl;
        std::cout << std::endl;
#endif
      }

    //
    // compute inner parameters
    //
    // build up sparse matrix A
    std::cout << "Setup sparse matrix ..." << std::endl;
    std::vector<Eigen::Triplet<double> > tripletList;
    for (v_it=mesh.vertices_begin(); v_it!=v_end; ++v_it)
      {
        MyMesh::VertexHandle vh = *v_it;
        int i = vh.idx();
        if ( vertex_type[i] == OF_INTERNAL ) // internal vertex
          {
            VVWeights& vvw = mesh.property(vvws,*v_it);

            // set for x coord
            tripletList.push_back( Eigen::Triplet<double>(i, i, vvw.w(0)) );
            // set for y coord
            tripletList.push_back( Eigen::Triplet<double>(i+n_param, i+n_param, vvw.w(0)) );

            int k;
            MyMesh::VertexVertexIter vv_it;
            // cout << "internal vt " << i << endl;
            for (k=1, vv_it=mesh.vv_iter( *v_it ); vv_it.is_valid(); ++vv_it, ++k)
              {
                MyMesh::VertexHandle vvh = *vv_it;
                int id = vvh.idx();
                int j;
                if ( (vertex_type[id] == OF_BOUNDARY) ||
                     (vertex_type[id] == OF_CONESINGULARITY_PI2))
                  j = vvw.param_id( vvh );
                else
                  j = id;

                // if ( (vertex_type[id] == OF_BOUNDARY) ||
                //      (vertex_type[id] == OF_CONESINGULARITY_PI2))
                // cout << "\tvt " << id << " type " << vertex_type[id] << " param id " << j << " w " << vvw.w(k) << endl;

                // set for x coord
                tripletList.push_back( Eigen::Triplet<double>(i, j, vvw.w(k)) );
                // set for y coord
                tripletList.push_back( Eigen::Triplet<double>(i+n_param, j+n_param, vvw.w(k)) );
              }
          }
        else if ( vertex_type[i] == OF_CONESINGULARITY_PI ) // fixed
          {
            // original parameter id for cs_vertices[0] or cs_vertices[2]
            // set for x coord
            tripletList.push_back( Eigen::Triplet<double>(i, i, 1.0) );
            // set for y coord
            tripletList.push_back( Eigen::Triplet<double>(i+n_param, i+n_param, 1.0) );
          }
        else if ( vertex_type[i] == OF_CONESINGULARITY_PI2 ) // fixed
          {
            // original parameter id for cs_vertices[1]
            // set for x coord
            tripletList.push_back( Eigen::Triplet<double>(i, i, 1.0) );
            // set for y coord
            tripletList.push_back( Eigen::Triplet<double>(i+n_param, i+n_param, 1.0) );

            // altanative parameter id for cs_vertices[3]
            int id = alt_param_id[vh];
            // set for x coord
            tripletList.push_back( Eigen::Triplet<double>(id, id, 1.0) );
            // set for y coord
            tripletList.push_back( Eigen::Triplet<double>(id+n_param, id+n_param, 1.0) );
          }
        else // vertex_type[i] == OF_BOUNDARY
          {
#if 0
            cout << "boundary vt " << i << endl;

            VVWeights& vvw = mesh.property(vvws, *v_it);
            vvw.Print();

            //tripletList.push_back( Eigen::Triplet<double>(i, i, vvw.w(0)) );
            double sum_wei = 0.0;  // weight for non-reverse
            double sum_wei_rev = 0.0; // weight for reverse
            int rev_i = alt_param_id[ vh ];

            //
            // eq.9a
            //
            // R(90)
            int k;
            MyMesh::VertexVertexIter vv_it;
            for (k=1, vv_it=mesh.vv_iter( *v_it ); vv_it.is_valid(); ++vv_it, ++k)
              {
                MyMesh::VertexHandle vvh = *vv_it;
                int j = vvh.idx();
                int rev = vvw.param_id( vvh );
                // cout << "vt id " << j << " reverse " << rev << endl;
                // classify weights to two according to the reverse flag
                if ( rev == -1 ) // non-reverse
                  {
                    sum_wei -= vvw.w(k);
                    // set for x coord
                    tripletList.push_back( Eigen::Triplet<double>(i, j, vvw.w(k)) );
                    // set for y coord
                    tripletList.push_back( Eigen::Triplet<double>(i+n_param, j+n_param, vvw.w(k)) );
                  }
                else // reverse
                  {
                    sum_wei_rev -= vvw.w(k);
                    // - wij * y_j
                    // set for x coord
                    int jj;
                    if ( (vertex_type[j] == OF_BOUNDARY) ||
                         (vertex_type[j] == OF_CONESINGULARITY_PI2) )
                      jj = alt_param_id[vvh];
                    else // internal
                      jj = j;
                    tripletList.push_back( Eigen::Triplet<double>(i, jj+n_param, -vvw.w(k)) );
                    // + wij * x_j
                    // set for y coord
                    tripletList.push_back( Eigen::Triplet<double>(i+n_param, jj, vvw.w(k)) );
                  }
              }
            // non-reverse weight
            // + sum wij * x_i
            // set for x coord
            tripletList.push_back( Eigen::Triplet<double>(i, i, sum_wei) );
            // + sum wij * y_i
            // set for y coord
            tripletList.push_back( Eigen::Triplet<double>(i+n_param, i+n_param, sum_wei) );

            // reverse weight
            // + sum wij * y_i
            // set for x coord
            tripletList.push_back( Eigen::Triplet<double>(i, rev_i+n_param, -sum_wei_rev) );
            // - sum wij * x_i
            // set for y coord
            tripletList.push_back( Eigen::Triplet<double>(i+n_param, rev_i, sum_wei_rev) );

            cout << "i " << i << " rev_i " << rev_i << " wei " << sum_wei << " wei-rev " << sum_wei_rev << " wei (original) " << vvw.w(0) << endl;

#endif
          }
      }

    //
    // build up sparse matrix A (cont.)
    // eq.9a
    //
    // k = 0: path no.0, k = 1: path no.2
    for ( int k = 0; k < 2; ++k )
      {
        int l = (k == 0) ? 0 : 2;
        for ( int j = 1; j < path[l].size() - 1; ++j )
          {
            MyMesh::VertexHandle vh = path[l][j];
            int i = vh.idx();
            int rev_i = alt_param_id[vh];

            // cout << "boundary vt " << i << endl;

            VVWeights& vvw = mesh.property(vvws, vh);
            // vvw.Print();

            double sum_wei = 0.0;  // weight for non-reverse
            double sum_wei_rev = 0.0; // weight for reverse

            int m;
            MyMesh::VertexVertexIter vv_it;
            for (m=1, vv_it=mesh.vv_iter( vh ); vv_it.is_valid(); ++vv_it, ++m)
              {
                MyMesh::VertexHandle vvh = *vv_it;
                int j = vvh.idx();
                int rev = vvw.param_id( vvh );

                // classify weights to two according to the reverse flag
                if ( rev == -1 ) // non-reverse
                  {
                    sum_wei -= vvw.w(m);
                    // set for x coord
                    tripletList.push_back( Eigen::Triplet<double>(i, j, vvw.w(m)) );
                    // set for y coord
                    tripletList.push_back( Eigen::Triplet<double>(i+n_param, j+n_param, vvw.w(m)) );
                  }
                else // reverse
                  {
                    sum_wei_rev -= vvw.w(m);
                    int jj;
                    if ( (vertex_type[j] == OF_BOUNDARY) ||
                         (vertex_type[j] == OF_CONESINGULARITY_PI2) )
                      jj = alt_param_id[vvh];
                    else // internal
                      jj = j;

                    if ( k == 0 )
                      {
                        // R(-90)
                        // - wij * y_j
                        // set for x coord
                        tripletList.push_back( Eigen::Triplet<double>(i, jj+n_param, vvw.w(m)) );
                        // + wij * x_j
                        // set for y coord
                        tripletList.push_back( Eigen::Triplet<double>(i+n_param, jj, -vvw.w(m)) );
                      }
                    else
                      {
                        // R(90)
                        // - wij * y_j
                        // set for x coord
                        tripletList.push_back( Eigen::Triplet<double>(i, jj+n_param, -vvw.w(m)) );
                        // + wij * x_j
                        // set for y coord
                        tripletList.push_back( Eigen::Triplet<double>(i+n_param, jj, vvw.w(m)) );
                      }
                  }
              }
            // non-reverse weight
            // + sum wij * x_i
            // set for x coord
            tripletList.push_back( Eigen::Triplet<double>(i, i, sum_wei) );
            // + sum wij * y_i
            // set for y coord
            tripletList.push_back( Eigen::Triplet<double>(i+n_param, i+n_param, sum_wei) );

            // reverse weight
            if ( k == 0 )
              {
                // R(-90)
                // + sum wij * y_i
                // set for x coord
                tripletList.push_back( Eigen::Triplet<double>(i, rev_i+n_param, sum_wei_rev) );
                // - sum wij * x_i
                // set for y coord
                tripletList.push_back( Eigen::Triplet<double>(i+n_param, rev_i, -sum_wei_rev) );
              }
            else
              {
                // R(90)
                // + sum wij * y_i
                // set for x coord
                tripletList.push_back( Eigen::Triplet<double>(i, rev_i+n_param, -sum_wei_rev) );
                // - sum wij * x_i
                // set for y coord
                tripletList.push_back( Eigen::Triplet<double>(i+n_param, rev_i, sum_wei_rev) );
              }

            // cout << "i " << i << " rev_i " << rev_i << " wei " << sum_wei << " wei-rev " << sum_wei_rev << " wei (original) " << vvw.w(0) << endl;

          }
      }

    //
    // build up sparse matrix A (cont.)
    // eq.9b
    //
    // k = 0: path no.0, k = 1: path no.2
    for ( int k = 0; k < 2; ++k )
      {
        // int cen_param_id = (k == 0) ? cs_vertices[1].idx() : alt_param_id[cs_vertices[1]];
        int cen_param_id = (k == 0) ? cs_vertices[0].idx() : cs_vertices[2].idx();
        int l = (k == 0) ? 0 : 2;
        for ( int j = 1; j < path[l].size() - 1; ++j )
          {
            MyMesh::VertexHandle vh = path[l][j];
            int i = vh.idx();
            int rev_i = alt_param_id[vh];

            if ( k == 0 ) // l = 0
              {
                // R(-90)
                // x
                tripletList.push_back( Eigen::Triplet<double>(rev_i, rev_i, 1.0) );
                tripletList.push_back( Eigen::Triplet<double>(rev_i, cen_param_id, -1.0) );
                tripletList.push_back( Eigen::Triplet<double>(rev_i, i+n_param, 1.0) );
                tripletList.push_back( Eigen::Triplet<double>(rev_i, cen_param_id+n_param, -1.0) );
                // y
                tripletList.push_back( Eigen::Triplet<double>(rev_i+n_param, rev_i+n_param, -1.0) );
                tripletList.push_back( Eigen::Triplet<double>(rev_i+n_param, cen_param_id+n_param, 1.0) );
                tripletList.push_back( Eigen::Triplet<double>(rev_i+n_param, i, 1.0) );
                tripletList.push_back( Eigen::Triplet<double>(rev_i+n_param, cen_param_id, -1.0) );
              }
            else // l = 2
              {
                // R(90)
                // x
                tripletList.push_back( Eigen::Triplet<double>(rev_i, rev_i, -1.0) );
                tripletList.push_back( Eigen::Triplet<double>(rev_i, cen_param_id, 1.0) );
                tripletList.push_back( Eigen::Triplet<double>(rev_i, i+n_param, 1.0) );
                tripletList.push_back( Eigen::Triplet<double>(rev_i, cen_param_id+n_param, -1.0) );
                // y
                tripletList.push_back( Eigen::Triplet<double>(rev_i+n_param, rev_i+n_param, 1.0) );
                tripletList.push_back( Eigen::Triplet<double>(rev_i+n_param, cen_param_id+n_param, -1.0) );
                tripletList.push_back( Eigen::Triplet<double>(rev_i+n_param, i, 1.0) );
                tripletList.push_back( Eigen::Triplet<double>(rev_i+n_param, cen_param_id, -1.0) );
              }
          }
      }

    Eigen::SparseMatrix<double> spmat( 2*n_param, 2*n_param );
    spmat.setFromTriplets( tripletList.begin(), tripletList.end() );
    spmat.makeCompressed();

    // cout << "matrix A" << endl;
    // cout << spmat << endl;

    // cout << "before param " << endl;
    // for ( int i = 0; i < paramx.size(); ++i )
    //   {
    //     cout << i << " " << paramx[i] << " " << paramy[i] << endl;
    //   }

    // setup vector b
    //Eigen::VectorXd xx(n_param), xy(n_param), bx(n_param), by(n_param);
    Eigen::VectorXd xx(2*n_param), bx(2*n_param);
    for ( int i = 0; i < n_param; ++i )
      {
        // set for x coord
        bx[i] = paramx[i];
        // set for y coord
        bx[i+n_param] = paramy[i];
      }

    // solve x
    if ( sol_ == BICGSTAB )
      {
        Eigen::BiCGSTAB<Eigen::SparseMatrix<double> > solver(spmat);
        std::cout << "solve x and y coords ..." << std::endl;
        xx = solver.solve(bx);
        // std::cout << "solve ycoords ..." << std::endl;
        // xy = solver.solve(by);
      }
    else if ( sol_ == SPARSELU )
      {
        Eigen::SparseLU<Eigen::SparseMatrix<double>, Eigen::COLAMDOrdering<int> > solver;

        solver.analyzePattern(spmat);
        // Compute the numerical factorization
        solver.factorize(spmat);
        //Use the factors to solve the linear system
        std::cout << "solve x and y coords ..." << std::endl;
        xx = solver.solve(bx);
        // std::cout << "solve ycoords ..." << std::endl;
        // xy = solver.solve(by);
      }

    for ( int i = 0; i < n_param; ++i )
      {
        paramx[i] = xx[i];
        paramy[i] = xx[i+n_param];
      }

#if 0
    cout << "computed param " << endl;
    for ( int i = 0; i < paramx.size(); ++i )
      {
        cout << i << " " << paramx[i] << " " << paramy[i] << endl;
      }
#endif

    mesh.remove_property(vvws);

    //
    // "cut" mesh along the path
    //

#if 0
    // make consistent path from path no.0 and no.1
    std::vector<MyMesh::VertexHandle> path01;
    for ( int i = 0; i < path.size() / 2; ++i )
      for ( int j = 0; j < path[i].size(); ++j )
        if ( (i != 1) || (j != 0) ) path01.push_back( path[i][j] );
#endif

    // extract right side faces of a path
    std::vector<MyMesh::FaceHandle> right_faces;
    // for OF_BOUNDARY and OF_CONESINGULARITY_PI2 vertices,
    // not for access OF_CONESINGULARITY_PI vertices
    for ( int i = 1; i < path01.size() - 1; ++i )
      {
        MyMesh::VertexHandle vh = path01[i];    // current boundary vertex
        MyMesh::VertexHandle pvh = path01[i-1]; // prev boundary vertex
        MyMesh::VertexHandle nvh = path01[i+1]; // next boundary vertex

        // right faces
        // cout << "vt " << vh.idx() << " cw in halfedge circulator " << endl;
        MyMesh::VertexIHalfedgeCWIter vih_cwit = start_vih_cwiter( vh, pvh, mesh );
        while ( mesh.from_vertex_handle( *vih_cwit ) != nvh )
          {
            MyMesh::VertexHandle ivh = mesh.from_vertex_handle( *vih_cwit );
            MyMesh::FaceHandle fh = mesh.face_handle( *vih_cwit );
            right_faces.push_back( fh );
            // cout << "\tivt " << ivh.idx() << " fc " << fh.idx() << endl;
            ++vih_cwit;
            if ( !(vih_cwit->is_valid()) ) vih_cwit = mesh.vih_cwiter( vh );
          }

        // erase duplicate elements
        std::sort(right_faces.begin(), right_faces.end());
        right_faces.erase(std::unique(right_faces.begin(), right_faces.end()), right_faces.end());

        // left faces
        // cout << "vt " << vh.idx() << " ccw out halfedge circulator " << endl;
        MyMesh::VertexOHalfedgeCCWIter voh_ccwit = start_voh_ccwiter( vh, pvh, mesh );
        while ( mesh.to_vertex_handle( *voh_ccwit ) != nvh )
          {
            MyMesh::VertexHandle ovh = mesh.to_vertex_handle( *voh_ccwit );
            MyMesh::FaceHandle fh = mesh.face_handle( *voh_ccwit );
            // cout << "\tovt " << ovh.idx() << " fc " << fh.idx() << endl;
            ++voh_ccwit;
            if ( !(voh_ccwit->is_valid()) ) voh_ccwit = mesh.voh_ccwiter( vh );
          }
      }

    // create new vertex handles for path vertices with having
    // the same positions to the original vertices
    // OF_BOUNDARY vertices
    for ( int i = 0; i < path.size() / 2; ++i ) // search for only two paths
      {
        for ( int j = 1; j < path[i].size() - 1; ++j )
          {
            MyMesh::VertexHandle vh = path[i][j];    // current boundary vertex
            // new vertex
            MyMesh::VertexHandle new_vh = mesh.add_vertex( mesh.point( vh ) );
            // color
            if ( mesh.has_vertex_colors() )
              {
                MyMesh::Color c = mesh.color(vh);
                mesh.set_color( new_vh, c );
              }
            // cout << "new bd vt " << new_vh.idx() << " param_id " << alt_param_id[vh] << endl;
          }
      }
    // OF_CONESINGULARITY_PI2 vertex
    cs_vt = cs_vertices[1];
    // new vertex
    MyMesh::VertexHandle new_cs_vh = mesh.add_vertex( mesh.point(cs_vt) );
    // color
    if ( mesh.has_vertex_colors() )
      {
        MyMesh::Color cc = mesh.color(cs_vt);
        mesh.set_color( new_cs_vh, cc );
      }
    // cout << "new cs vt " << new_cs_vh.idx() << " param_id " << alt_param_id[cs_vt] << endl;

    // create vertex handles for new faces
    std::vector<std::vector<MyMesh::VertexHandle> > faces_vhandles( right_faces.size() );
    for ( int i = 0; i < right_faces.size(); ++i )
      {
        // cout << "i = " << i << endl;
        for ( MyMesh::FaceVertexIter fv_it = mesh.fv_iter( right_faces[i] );
              fv_it.is_valid(); ++fv_it )
          {
            MyMesh::VertexHandle fvh = *fv_it; // vv_it.handle();
            if ( (vertex_type[fvh.idx()] == OF_BOUNDARY) ||
                 (vertex_type[fvh.idx()] == OF_CONESINGULARITY_PI2) )
              {
                int new_id = alt_param_id[fvh];
                MyMesh::VertexHandle nfvh = mesh.vertex_handle(new_id);
                // cout << "new_id " << new_id << " created " << nfvh.idx() << endl;
                faces_vhandles[i].push_back( nfvh );
              }
            else // internal
              {
                faces_vhandles[i].push_back( fvh );
              }
          }
      }

    // change path vertices to new ones
    for ( int i = path.size() / 2; i < path.size(); ++i ) // search for only two paths
      {
        for ( int j = 0; j < path[i].size(); ++j )
          {
            if ( ((i == path.size() / 2) && (j != 0)) ||
                 ((i == path.size() - 1) && (j != path[i].size()-1)) )
              {
                MyMesh::VertexHandle ovh = path[i][j];
                path[i][j] = mesh.vertex_handle( alt_param_id[ovh] );
              }
          }
      }

    // delete right_faces and add new right faces
    mesh.request_face_status();
    // mesh.request_edge_status();
    // mesh.request_vertex_status();

    for ( int i = 0; i < right_faces.size(); ++i )
      {
        // cout << "delete face " << right_faces[i].idx() << endl;
        mesh.delete_face( right_faces[i], false );
        MyMesh::FaceHandle new_face = mesh.add_face( faces_vhandles[i] );
        // cout << "new face " << new_face.idx() << endl;
      }

    // cut done.
    mesh.garbage_collection();

    return 0;
  };

};

#endif // _PARAM_HXX


#ifndef PWALK_WALK_HPP_
#define PWALK_WALK_HPP_

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

namespace pwalk {

template <typename Dtype>
class Walker {
public:
  Walker(const Eigen::Matrix<Dtype, Eigen::Dynamic, 1>& initialization, const Eigen::Matrix<Dtype, Eigen::Dynamic, Eigen::Dynamic>& cons_A, const Eigen::Matrix<Dtype, Eigen::Dynamic, 1>& cons_b) : nb_dim_(cons_A.cols()), nb_cons_(cons_A.rows()), nb_curr_samples_(1), initialization_(initialization), cons_A_(cons_A), cons_b_(cons_b), curr_sample_(initialization){}

  virtual ~Walker(){}

  virtual bool doSample(Eigen::Matrix<Dtype, Eigen::Dynamic, 1>& new_sample, Dtype lazy = Dtype(0.5)){
    return false;
  }

  // check whether a given point is in th polytope
  bool checkInPolytope(const Eigen::Matrix<Dtype, Eigen::Dynamic, 1>& new_sample){
    return (cons_A_ * new_sample - cons_b_).maxCoeff() < 0;
  }

  // getter for dimension
  int getNbDim() {
    return nb_dim_;
  }

  // getter for nb current samples
  int getNbCurrSamples() {
    return nb_curr_samples_;
  }

  // getter for current sample
  Eigen::Matrix<Dtype, Eigen::Dynamic, 1>& getCurrSample() {
    return curr_sample_;
  }

protected:

  // Dimension
  const int nb_dim_;
  // number of constraints
  const int nb_cons_;
  // current sample size
  int nb_curr_samples_;
  // Initial vector
  const Eigen::Matrix<Dtype, Eigen::Dynamic, 1>& initialization_;
  // constraints matrix A
  const Eigen::Matrix<Dtype, Eigen::Dynamic, Eigen::Dynamic>& cons_A_;
  // constraint vector b
  const Eigen::Matrix<Dtype, Eigen::Dynamic, 1>& cons_b_;
  // Current vector
  Eigen::Matrix<Dtype, Eigen::Dynamic, 1> curr_sample_;
};

} // namespace pwalk

#endif // PWALK_WALK_HPP_


//////////////////////////////////////////////////////////////////////////////
///   Copyright 2003 and onward LASMEA UMR 6602 CNRS/U.B.P Clermont-Ferrand
///   Copyright 2009 and onward LRI    UMR 8623 CNRS/Univ Paris Sud XI
///
///          Distributed under the Boost Software License, Version 1.0
///                 See accompanying file LICENSE.txt or copy at
///                     http://www.boost.org/LICENSE_1_0.txt
//////////////////////////////////////////////////////////////////////////////
#ifndef NT2_TOOLBOX_IEEE_FUNCTION_SCALAR_COPYSIGN_HPP_INCLUDED
#define NT2_TOOLBOX_IEEE_FUNCTION_SCALAR_COPYSIGN_HPP_INCLUDED
#include <nt2/sdk/meta/strip.hpp>

#include <nt2/include/functions/abs.hpp>
#include <nt2/include/functions/signnz.hpp>

#include <nt2/toolbox/ieee/details/math.hpp>
#include <boost/math/special_functions/sign.hpp>

/////////////////////////////////////////////////////////////////////////////
// Implementation when type A0 is arithmetic_
/////////////////////////////////////////////////////////////////////////////
NT2_REGISTER_DISPATCH(tag::copysign_, tag::cpu_,
                          (A0)(A1),
                          (arithmetic_<A0>)(arithmetic_<A1>)
                         )

namespace nt2 { namespace ext
{
  template<class Dummy>
  struct call<tag::copysign_(tag::arithmetic_,tag::arithmetic_),
              tag::cpu_, Dummy> : callable
  {
    template<class Sig> struct result;
    template<class This,class A0,class A1>
      struct result<This(A0,A1)> : meta::strip<A0>{};

    NT2_FUNCTOR_CALL(2)
    {
      return nt2::abs(a0)*signnz(a1);
    }
  };
} }

/////////////////////////////////////////////////////////////////////////////
// Implementation when type A0 is double
/////////////////////////////////////////////////////////////////////////////
NT2_REGISTER_DISPATCH(tag::copysign_, tag::cpu_,
                          (A0)(A1),
                          (double_<A0>)(double_<A1>)
                         )

namespace nt2 { namespace ext
{
  template<class Dummy>
  struct call<tag::copysign_(tag::double_,tag::double_),
              tag::cpu_, Dummy> : callable
  {
    template<class Sig> struct result;
    template<class This,class A0,class A1>
      struct result<This(A0,A1)> : meta::strip<A0>{};

    NT2_FUNCTOR_CALL(2)
    {
    #ifdef NT2_TOOLBOX_IEEE_HAS_COPYSIGN
      return ::copysign(a0, a1);
    #elif defined(NT2_TOOLBOX_IEEE_HAS__COPYSIGN)
      return ::_copysign(a0, a1);
    #else
      return boost::math::copysign(a0, a1);
    #endif
    }
  };
} }

/////////////////////////////////////////////////////////////////////////////
// Implementation when type A0 is float
/////////////////////////////////////////////////////////////////////////////
NT2_REGISTER_DISPATCH(tag::copysign_, tag::cpu_,
                          (A0)(A1),
                          (float_<A0>)(float_<A1>)
                         )

namespace nt2 { namespace ext
{
  template<class Dummy>
  struct call<tag::copysign_(tag::float_,tag::float_),
              tag::cpu_, Dummy> : callable
  {
    template<class Sig> struct result;
    template<class This,class A0,class A1>
      struct result<This(A0,A1)> : meta::strip<A0>{};

    NT2_FUNCTOR_CALL(2)
    {
    #ifdef NT2_TOOLBOX_IEEE_HAS_COPYSIGNF
      return ::copysignf(a0, a1);
    #elif defined(NT2_TOOLBOX_IEEE_HAS__COPYSIGNF)
      return ::_copysignf(a0, a1);
    #else
        return boost::math::copysign(a0, a1);
    #endif
    }
  };
} }

#endif
// modified by jt the 26/12/2010


//=======================================================================
// Copyright 2007 Aaron Windsor
//
// 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 <iostream>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/properties.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/ref.hpp>
#include <vector>

#include <boost/graph/boyer_myrvold_planar_test.hpp>
#include <boost/graph/is_kuratowski_subgraph.hpp>

using namespace boost;

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

  typedef adjacency_list
    < vecS,
      vecS,
      undirectedS,
      property<vertex_index_t, int>,
      property<edge_index_t, int>
    >
    graph;

  // Create a K_6 (complete graph on 6 vertices), which
  // contains both Kuratowski subgraphs as minors.
  graph g(6);
  add_edge(0,1,g);
  add_edge(0,2,g);
  add_edge(0,3,g);
  add_edge(0,4,g);
  add_edge(0,5,g);
  add_edge(1,2,g);
  add_edge(1,3,g);
  add_edge(1,4,g);
  add_edge(1,5,g);
  add_edge(2,3,g);
  add_edge(2,4,g);
  add_edge(2,5,g);
  add_edge(3,4,g);
  add_edge(3,5,g);
  add_edge(4,5,g);

  // Initialize the interior edge index
  property_map<graph, edge_index_t>::type e_index = get(edge_index, g);
  graph_traits<graph>::edges_size_type edge_count = 0;
  graph_traits<graph>::edge_iterator ei, ei_end;
  for(tie(ei, ei_end) = edges(g); ei != ei_end; ++ei)
    put(e_index, *ei, edge_count++);

  // Test for planarity - we know it is not planar, we just want to
  // compute the kuratowski subgraph as a side-effect
  typedef std::vector< graph_traits<graph>::edge_descriptor >
    kuratowski_edges_t;
  kuratowski_edges_t kuratowski_edges;
  if (boyer_myrvold_planarity_test(boyer_myrvold_params::graph = g,
                                   boyer_myrvold_params::kuratowski_subgraph =
                                       std::back_inserter(kuratowski_edges)
                                   )
      )
    std::cout << "Input graph is planar" << std::endl;
  else
    {
      std::cout << "Input graph is not planar" << std::endl;

      std::cout << "Edges in the Kuratowski subgraph: ";
      kuratowski_edges_t::iterator ki, ki_end;
      ki_end = kuratowski_edges.end();
      for(ki = kuratowski_edges.begin(); ki != ki_end; ++ki)
        {
          std::cout << *ki << " ";
        }
      std::cout << std::endl;

      std::cout << "Is a kuratowski subgraph? ";
      if (is_kuratowski_subgraph
          (g, kuratowski_edges.begin(), kuratowski_edges.end())
          )
        std::cout << "Yes." << std::endl;
      else
        std::cout << "No." << std::endl;
    }

  return 0;
}


// (C) Copyright 2007-2009 Andrew Sutton
//
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0 (See accompanying file
// LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)

#include <vector>

#include <boost/graph/undirected_graph.hpp>
#include <boost/graph/directed_graph.hpp>
#include <boost/graph/degree_centrality.hpp>
#include <boost/graph/exterior_property.hpp>

using namespace std;
using namespace boost;

// useful types
// number of vertices in the graph
static const unsigned N = 5;

template < typename Graph >
void build_graph(
    Graph& g, vector< typename graph_traits< Graph >::vertex_descriptor >& v)
{
    // add vertices
    for (size_t i = 0; i < N; ++i)
    {
        v[i] = add_vertex(g);
    }

    // add edges
    add_edge(v[0], v[1], g);
    add_edge(v[1], v[2], g);
    add_edge(v[2], v[0], g);
    add_edge(v[3], v[4], g);
    add_edge(v[4], v[0], g);
}

template < typename Graph > void test_undirected()
{
    typedef typename graph_traits< Graph >::vertex_descriptor Vertex;

    typedef exterior_vertex_property< Graph, unsigned > CentralityProperty;
    typedef typename CentralityProperty::container_type CentralityContainer;
    typedef typename CentralityProperty::map_type CentralityMap;

    Graph g;
    vector< Vertex > v(N);
    build_graph(g, v);

    CentralityContainer cents(num_vertices(g));
    CentralityMap cm(cents, g);
    all_degree_centralities(g, cm);

    BOOST_ASSERT(cm[v[0]] == 3);
    BOOST_ASSERT(cm[v[1]] == 2);
    BOOST_ASSERT(cm[v[2]] == 2);
    BOOST_ASSERT(cm[v[3]] == 1);
    BOOST_ASSERT(cm[v[4]] == 2);
}

template < typename Graph > void test_influence()
{
    typedef typename graph_traits< Graph >::vertex_descriptor Vertex;

    typedef exterior_vertex_property< Graph, unsigned > CentralityProperty;
    typedef typename CentralityProperty::container_type CentralityContainer;
    typedef typename CentralityProperty::map_type CentralityMap;

    Graph g;

    vector< Vertex > v(N);
    build_graph(g, v);

    CentralityContainer cents(num_vertices(g));
    CentralityMap cm(cents, g);
    all_influence_values(g, cm);

    BOOST_ASSERT(cm[v[0]] == 1);
    BOOST_ASSERT(cm[v[1]] == 1);
    BOOST_ASSERT(cm[v[2]] == 1);
    BOOST_ASSERT(cm[v[3]] == 1);
    BOOST_ASSERT(cm[v[4]] == 1);
}

template < typename Graph > void test_prestige()
{
    typedef typename graph_traits< Graph >::vertex_descriptor Vertex;

    typedef exterior_vertex_property< Graph, unsigned > CentralityProperty;
    typedef typename CentralityProperty::container_type CentralityContainer;
    typedef typename CentralityProperty::map_type CentralityMap;

    Graph g;

    vector< Vertex > v(N);
    build_graph(g, v);

    CentralityContainer cents(num_vertices(g));
    CentralityMap cm(cents, g);
    all_prestige_values(g, cm);

    BOOST_ASSERT(cm[v[0]] == 2);
    BOOST_ASSERT(cm[v[1]] == 1);
    BOOST_ASSERT(cm[v[2]] == 1);
    BOOST_ASSERT(cm[v[3]] == 0);
    BOOST_ASSERT(cm[v[4]] == 1);
}

int main(int, char*[])
{
    typedef undirected_graph<> Graph;
    typedef directed_graph<> Digraph;

    test_undirected< Graph >();
    test_influence< Digraph >();
    test_prestige< Digraph >();
}


/******************************************************************************
 *
 * AMDiS - Adaptive multidimensional simulations
 *
 * Copyright (C) 2013 Dresden University of Technology. All Rights Reserved.
 * Web: https://fusionforge.zih.tu-dresden.de/projects/amdis
 *
 * Authors:
 * Simon Vey, Thomas Witkowski, Andreas Naumann, Simon Praetorius, et al.
 *
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 *
 *
 * This file is part of AMDiS
 *
 * See also license.opensource.txt in the distribution.
 *
 ******************************************************************************/

// Written by Simon Praetorius

#ifndef ITL_DETAIL_INCLUDE
#define ITL_DETAIL_INCLUDE

#include <boost/math/special_functions/sign.hpp>

namespace itl
{

  namespace details
  {

    /// Compute the Givens rotation matrix parameters for a and b.
    //     template<typename T>
    //     void rotmat(const T& a, const T& b , T& c, T& s)
    //     {
    //       using std::abs; using std::sqrt; using mtl::conj;
    //
    //       const T zero = math::zero(T());
    //       if (a == zero) {
    // 	c = 0.0;
    // 	s = 1.0;
    //       } else {
    // 	double temp = abs(a) / sqrt( conj(a)*a + conj(b)*b );
    // 	c = temp;
    // 	s = temp * (b / a);
    //       }
    //     }

    inline void rotmat(const double& a, const double& b , double& c, double& s)
    {
      using std::abs;
      using std::sqrt;
      if ( b == 0.0 )
      {
        c = 1.0;
        s = 0.0;
      }
      else if ( abs(b) > abs(a) )
      {
        double temp = a / b;
        s = 1.0 / sqrt( 1.0 + temp*temp );
        c = temp * s;
      }
      else
      {
        double temp = b / a;
        c = 1.0 / sqrt( 1.0 + temp*temp );
        s = temp * c;
      }
    }
  }
}

#endif // ITL_DETAIL_INCLUDE


//
// Copyright (c) 2015 Singular Inversions Inc. (facegen.com)
// Use, modification and distribution is subject to the MIT License,
// see accompanying file LICENSE.txt or facegen.com/base_library_license.txt
//
// Authors:     Andrew Beatty
// Created:     Jan 27, 2009
//
// Not currently threadsafe.

#include "stdafx.h"

#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_real.hpp>
#include <boost/random/uniform_int.hpp>
#include <boost/random/variate_generator.hpp>
#include "FgRandom.hpp"
#include "FgDiagnostics.hpp"
#include "FgImage.hpp"
#include "FgImgDisplay.hpp"
#include "FgMath.hpp"
#include "FgAffine1.hpp"
#include "FgMain.hpp"

using namespace std;

struct      RNG
{
    boost::random::mt19937      gen;
    RNG() : gen(42u) {}
};

static RNG rng;

uint32
fgRandUint32()
{return rng.gen(); }

uint
fgRandUint(uint size)
{
    uint    lim = numeric_limits<uint>::max(),
            max = lim - (lim%size),
            ret;
    while ((ret = rng.gen()) > max) {}
    return ret % size;
}

uint64
fgRandUint64()
{
    uint64  hi = rng.gen(),
            lo = rng.gen();
    return (lo + (hi << 32));
}

double
fgRand()
{return double(fgRandUint64()) / double(numeric_limits<uint64>::max()); }

void
fgRandSeedRepeatable(uint seed)
{rng.gen = boost::random::mt19937(seed); }

double
fgRandNormal()
{
    // Polar (Box-Muller) method; See Knuth v2, 3rd ed, p122.
    double  x, y, r2;
    do {
        x = -1 + 2 * fgRand();
        y = -1 + 2 * fgRand();
        // see if it is in the unit circle:
        r2 = x * x + y * y;
    }
    while (r2 > 1.0 || r2 == 0);
    // Box-Muller transform:
    return y * sqrt (-2.0 * log (r2) / r2);
}

FgDbls
fgRandNormals(size_t num,double mean,double stdev)
{
    FgDbls      ret(num);
    for (size_t ii=0; ii<num; ++ii)
        ret[ii] = mean + stdev * fgRandNormal();
    return ret;
}

static
char
randChar()
{
    uint    val = fgRandUint(26+26+10);
    if (val < 10)
        return char(48+val);
    val -= 10;
    if (val < 26)
        return char(65+val);
    val -= 26;
    FGASSERT(val < 26);
    return char(97+val);
}

string
fgRandString(uint numChars)
{
    string  ret;
    for (uint ii=0; ii<numChars; ++ii)
        ret = ret + randChar();
    return ret;
}

void
fgRandomTest(const FgArgs &)
{
    fgout << fgnl << "sizeof(RNG) = " << sizeof(RNG);
    // Create a histogram of normal samples:
    fgRandSeedRepeatable();
    size_t          numStdevs = 6,
                    binsPerStdev = 50,
                    numSamples = 1000000,
                    sz = numStdevs * 2 * binsPerStdev;
    vector<size_t>  histogram(sz,0);
    FgAffine1D      randToHist(FgVectD2(-double(numStdevs),numStdevs),FgVectD2(0,sz));
    for (size_t ii=0; ii<numSamples; ++ii) {
        int         rnd = fgRound(randToHist * fgRandNormal());
        if ((rnd >= 0) && (rnd < int(sz)))
            ++histogram[rnd]; }

    // Make a bar graph of it:
    // numSamples = binScale * stdNormIntegral * binsPerStdev
    double          binScale = double(numSamples) / (fgSqrt_2pi() * binsPerStdev),
                    hgtRatio = 0.9;
    FgImgRgbaUb     img(sz,sz,FgRgbaUB(0));
    for (size_t xx=0; xx<sz; ++xx) {
        size_t      hgt = fgRound(histogram[xx] * sz * hgtRatio / binScale);
        for (size_t yy=0; yy<hgt; ++yy)
            img.xy(xx,yy) = FgRgbaUB(255); }

    // Superimpose a similarly scaled Gaussian:
    FgAffine1D      histToRand = randToHist.inverse();
    for (size_t xx=0; xx<sz; ++xx) {
        double      val = std::exp(-0.5 * fgSqr(histToRand * (xx + 0.5)));
        size_t      hgt = fgRound(val * sz * hgtRatio);
        img.xy(xx,hgt) = FgRgbaUB(255,0,0,255); }

    // Display:
    fgImgFlipVertical(img);
    fgImgDisplay(img);
}

// */


/*
 * Copyright (c) 2011-2014 Burkhard Ritter
 * This code is distributed under the two-clause BSD License.
 */
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE qca test
#include <boost/test/unit_test.hpp>
#include "qca.hpp"

bool equal(double a, double b, double epsilon=1E-8)
{
    return std::abs(a-b) < epsilon;
}

BOOST_AUTO_TEST_CASE ( test_construct_qca_ising_system )
{
    QcaIsing s;

    s.l.wire(1,1,1,1);
    s.update();
    BOOST_CHECK (s.basis.size() == 2);

    s.l.wire(2,1,1,1);
    s.update();
    BOOST_CHECK (s.basis.size() == 4);

    s.l.wire(6,1,1,1);
    s.update();
    BOOST_CHECK (s.basis.size() == 64);
}

BOOST_AUTO_TEST_CASE ( test_sigma_operator )
{
    const size_t N_c = 5;

    QcaIsing s;
    s.l.wire(N_c,1,1,1);
    s.update();

    State state("10010");
    std::vector<double> expected_spins = {1,-1,-1,1,-1};

    SparseVector<double> a(s.basis.size());
    a.reserve(1);
    a.insert(s.basis(state)) = 1;

    std::vector<double> spins(N_c);
    for (size_t j=0; j<N_c; j++)
    {
        SMatrix m = a.adjoint() * s.sigma(j) * a;
        assert(m.size() == 1);
        spins[j] = m.coeffRef(0,0);
        // std::cerr << "Spin " << j+1 << ": " << spins[j] << std::endl;
    }
    BOOST_CHECK (expected_spins == spins);
}

BOOST_AUTO_TEST_CASE ( test_spin_and_polarization_are_the_same )
{
    QcaIsing s;
    s.beta = 1;
    s.t = 1E-3;
    s.l.wire(3,0.01,0.02,1);
    s.update();

    std::vector<double> spins = {s.measureSpin(0),
                                 s.measureSpin(1),
                                 s.measureSpin(2)};
    std::vector<double> Ps = {s.measurePolarization(0),
                              s.measurePolarization(1),
                              s.measurePolarization(2)};
    for (size_t i=0; i<3; i++)
    {
        // std::cerr << "Spin[" << i << "] = " << spins[i]
        //           << ", Polarization[" << i << "] = " << Ps[i] << std::endl;
        BOOST_CHECK (equal(spins[i], Ps[i]));
    }
}

BOOST_AUTO_TEST_CASE ( test_simple_physical_limits )
{
    QcaIsing s;
    s.beta = 1;
    s.t = 1E-3;
    s.l.wire(3,0.01,0.02,0);
    s.update();

    /*
     * Different input polarizations.
     */
    // P^D = 0
    std::vector<double> Ps1 = {s.measurePolarization(0),
                               s.measurePolarization(1),
                               s.measurePolarization(2)};
    for (size_t i=0; i<3; i++)
        BOOST_CHECK (equal(0, Ps1[i]));
    // P^D = 1
    s.l.wire(3,0.01,0.02,1);
    s.update();
    std::vector<double> Ps2 = {s.measurePolarization(0),
                               s.measurePolarization(1),
                               s.measurePolarization(2)};
    for (size_t i=0; i<3; i++)
        BOOST_CHECK (Ps2[i]>0.5);
    for (size_t i=1; i<3; i++)
        BOOST_CHECK (Ps2[i]<Ps2[i-1]);
    // P^D = -1
    s.l.wire(3,0.01,0.02,-1);
    s.update();
    std::vector<double> Ps3 = {s.measurePolarization(0),
                               s.measurePolarization(1),
                               s.measurePolarization(2)};
    for (size_t i=0; i<3; i++)
    {
        BOOST_CHECK (Ps3[i]<-0.5);
        BOOST_CHECK (equal(Ps2[i], -Ps3[i]));
    }
    for (size_t i=1; i<3; i++)
        BOOST_CHECK (Ps3[i]>Ps3[i-1]);

    /*
     * Different temperatures.
     */
    s.l.wire(3,0.01,0.02,1);
    s.update();
    // High temperature
    s.beta = 0.01;
    std::vector<double> Ps4 = {s.measurePolarization(0),
                               s.measurePolarization(1),
                               s.measurePolarization(2)};
    // Medium temperature
    s.beta = 1;
    std::vector<double> Ps5 = {s.measurePolarization(0),
                               s.measurePolarization(1),
                               s.measurePolarization(2)};
    // Low temperature
    s.beta = 100;
    std::vector<double> Ps6 = {s.measurePolarization(0),
                               s.measurePolarization(1),
                               s.measurePolarization(2)};
    for (size_t i=0; i<3; i++)
    {
        BOOST_CHECK (Ps4[i] < Ps5[i]);
        BOOST_CHECK (Ps5[i] < Ps6[i]);
        BOOST_CHECK (Ps4[i] < 0.1);
    }

    /*
     * Hopping versus Coulomb potential.
     *
     * Large hopping should wash out any polarization.
     */
    // Small hopping
    s.l.wire(3,0.01,0.02,1);
    s.t = 1E-3;
    s.beta = 1;
    s.update();
    std::vector<double> Ps7 = {s.measurePolarization(0),
                               s.measurePolarization(1),
                               s.measurePolarization(2)};
    // Medium hopping
    s.t = 1;
    s.update();
    std::vector<double> Ps8 = {s.measurePolarization(0),
                               s.measurePolarization(1),
                               s.measurePolarization(2)};
    // Large hopping, on the order of V_1
    s.t = 100;
    s.update();
    std::vector<double> Ps9 = {s.measurePolarization(0),
                               s.measurePolarization(1),
                               s.measurePolarization(2)};
    // Medium hopping, small V_1
    s.l.wire(3,0.1,0.2,1);
    s.t = 1;
    s.update();
    std::vector<double> Ps10 = {s.measurePolarization(0),
                                s.measurePolarization(1),
                                s.measurePolarization(2)};
    // Medium hopping, medium V_1
    s.l.wire(3,0.01,0.02,1);
    s.t = 1;
    s.update();
    std::vector<double> Ps11 = {s.measurePolarization(0),
                                s.measurePolarization(1),
                                s.measurePolarization(2)};
    // Medium hopping, large V_1
    s.l.wire(3,0.001,0.002,1);
    s.t = 1;
    s.update();
    std::vector<double> Ps12 = {s.measurePolarization(0),
                                s.measurePolarization(1),
                                s.measurePolarization(2)};
    for (size_t i=0; i<3; i++)
    {
        BOOST_CHECK (Ps7[i] > Ps8[i]);
        BOOST_CHECK (Ps8[i] > Ps9[i]);
        BOOST_CHECK (Ps9[i] < 1E-2);
        BOOST_CHECK (Ps10[i] < Ps11[i]);
        BOOST_CHECK (Ps11[i] < Ps12[i]);
        BOOST_CHECK (Ps12[i] > 0.95);
    }

    /*
     * Larger inter-cell spacing means smaller polarization.
     */
    s.l.wire(3,0.01,0.02,1);
    s.t = 1E-3;
    s.beta = 1;
    s.update();
    std::vector<double> Ps13 = {s.measurePolarization(0),
                                s.measurePolarization(1),
                                s.measurePolarization(2)};
    s.l.wire(3,0.01,0.04,1);
    s.update();
    std::vector<double> Ps14 = {s.measurePolarization(0),
                                s.measurePolarization(1),
                                s.measurePolarization(2)};
    s.l.wire(3,0.01,1,1);
    s.update();
    std::vector<double> Ps15 = {s.measurePolarization(0),
                                s.measurePolarization(1),
                                s.measurePolarization(2)};
    for (size_t i=0; i<3; i++)
    {
        BOOST_CHECK (Ps13[i] > Ps14[i]);
        BOOST_CHECK (Ps14[i] > Ps15[i]);
        BOOST_CHECK (Ps15[i] < 1E-3);
    }
}

BOOST_AUTO_TEST_CASE ( test_tprime_gets_set_and_calculated_correctly )
{
    /*
     * t^{\prime} = \frac{ 4 t^2 }{ \Delta V }
     *            = \frac{ 8 t^2 }{ (2 - \sqrt{2}) V_1 }
     *            = \frac{ 4 t^2 }{ 0.29289 V_1 }
     */
    double t;
    double V1;

    QcaIsing s;
    s.q = 0.5;
    s.beta = 1;

    t = 1;
    V1 = 100;

    s.t = t;
    s.l.wire(3,1.0/V1,1,1);
    s.update();

    // std::cerr << "t' = " << s.tprime << std::endl;
    BOOST_CHECK(equal(s.tprime, 0.13656854249492380195));

    t = 3;
    V1 = 40;
    s.t = t;
    s.l.wire(3,1.0/V1,1,1);
    s.update();

    // std::cerr << "t' = " << s.tprime << std::endl;
    BOOST_CHECK(equal(s.tprime, 3.07279220613578554391));

    t = 10;
    V1 = 200;
    s.t = t;
    s.l.wire(3,1.0/V1,1,1);
    s.update();

    // std::cerr << "t' = " << s.tprime << std::endl;
    BOOST_CHECK(equal(s.tprime, 6.82842712474619009758));
}

BOOST_AUTO_TEST_CASE ( test_bond_and_ising_models_are_the_same_in_some_limits )
{
    QcaIsing s_i;
    s_i.q = 0.5;
    s_i.beta = 1;
    s_i.t = 1;
    s_i.l.wire(3,0.001,0.005,1);
    s_i.update();

    QcaBond s_b;
    s_b.q = 0.5;
    s_b.beta = 1;
    s_b.t = 1;
    s_b.l.wire(3,0.001,0.005,1);
    s_b.update();

    std::vector<double> Ps_i = {s_i.measurePolarization(0),
                                s_i.measurePolarization(1),
                                s_i.measurePolarization(2)};
    std::vector<double> Ps_b = {s_b.measurePolarization(0),
                                s_b.measurePolarization(1),
                                s_b.measurePolarization(2)};
    for (size_t i=0; i<3; i++)
    {
        std::cerr << "Ps_i[" << i << "] = " << Ps_i[i]
                  << ", Ps_b[" << i << "] = " << Ps_b[i] << std::endl;
    }
    // TODO
}


#include "itkImage.h"
#include "itkImageFileWriter.h"
#include "itkNumericTraits.h"

#include "vnl/vnl_matrix_ref.h"
#include "vnl/vnl_matrix.h"
#include "tkdCmdParser.h"

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/small_world_generator.hpp>
#include <boost/random/linear_congruential.hpp>
#include <boost/graph/graph_utility.hpp>

/**
 * Date: 16-11-2009
 */
class CreateSmallWorld {

public:

	typedef double PixelType;
	typedef itk::Image< PixelType, 2 > ImageType;
	typedef vnl_matrix_ref< PixelType > DataMatrixType;
	typedef itk::ImageFileWriter< ImageType > WriterType;

	typedef boost::adjacency_list<> GraphType;
	typedef boost::small_world_iterator< boost::minstd_rand, GraphType > SWGenerator;

	/**
	 * Run.
	 */
	void run( const std::string& output, unsigned int size, unsigned int k, PixelType probability, bool verbose )
	{
		WriterType::Pointer writer = WriterType::New();

		writer->SetFileName( output.c_str() );
		writer->SetInput( GetMatrix( size, k, probability, verbose ) );

		try {
			writer->Update();
		} catch ( itk::ExceptionObject& e ) {
			std::cerr << "Error writing: " << output << std::endl;
			std::cerr << e.GetDescription() << std::endl;
		}

	}

protected:

	/**
	 * Return regular matrix.
	 */
	ImageType::Pointer GetMatrix( unsigned int matrixSize, unsigned int k, PixelType probability, bool verbose )
	{
		ImageType::Pointer outputImage = ImageType::New();
		ImageType::SizeType size;
		ImageType::RegionType region;
		size[ 0 ] = matrixSize;
		size[ 1 ] = matrixSize;

		region.SetSize( size );
		outputImage->SetRegions( region );
		outputImage->Allocate();

		boost::minstd_rand generator;

		GraphType g( SWGenerator( generator, matrixSize, k, probability ), SWGenerator(), matrixSize );

		boost::property_map< GraphType, boost::vertex_index_t >::type vertices
			= boost::get( boost::vertex_index, g );

		for( boost::graph_traits< GraphType >::edge_iterator e = edges( g ).first; e != edges( g ).second; ++e )
	    {
			ImageType::IndexType index;
			index[0] = boost::get( vertices, boost::source( *e, g ) );
	    	index[1] = boost::get( vertices, boost::target( *e, g ) );
	    	outputImage->SetPixel( index, static_cast< PixelType >( 1.0 ) );
	    }

		if ( verbose )
			boost::print_graph( g );

		return outputImage;
	}
};

/**
 * Create regular matrix.
 */
int main( int argc, char ** argv ) {
	tkd::CmdParser p( "create_smallworld", "Construct smallworld graph." );

	std::string output;
	int size = 10;
	int k = 2;
	float probability = 0.03;
	bool verbose;

	p.AddArgument( output, "output" ) ->AddAlias( "o" ) ->SetInput( "filename" ) ->SetDescription( "Output matrix file name" ) ->SetRequired(
			true ) -> SetMinMax( 1, 1 );

	p.AddArgument( size, "size" ) ->AddAlias( "s" ) ->SetInput( "uint" ) ->SetDescription( "Number of nodes [ default: 10 ]" );

	p.AddArgument( k, "k" ) ->AddAlias( "k" ) ->SetInput( "uint" ) ->SetDescription( "K [ default: 2 ]" );

	p.AddArgument( probability, "probability" ) ->AddAlias( "p" ) ->SetInput( "float" ) ->SetDescription( "Rewire probability [ default: 0.03 ]" );

	p.AddArgument( verbose, "verbose" ) ->AddAlias( "v" ) ->SetInput( "bool" ) ->SetDescription( "Print graph to screen" );

	if ( !p.Parse( argc, argv ) ) {
		p.PrintUsage( std::cout );
		return EXIT_FAILURE;
	}

	CreateSmallWorld createSmallWorld;

	createSmallWorld.run( output, size, k, probability, verbose );

	return EXIT_SUCCESS;
}


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

#include <iostream>
#include <vector>
#include <madym/mdm_Image3D.h>
#include <madym/mdm_ParamSummaryStats.h>
#include <madym/tests/mdm_test_utils.h>

BOOST_AUTO_TEST_SUITE(test_mdm)

BOOST_AUTO_TEST_CASE(test_summaryStats) {
	BOOST_TEST_MESSAGE("======= Testing class mdm_ParamSummaryStats =======");

	mdm_Image3D img;
	int nx = 5, ny = 1, nz = 1;
	img.setDimensions(nx, ny, nz);

	for (int i = 0; i < nx; i++)
		img.setVoxel(i, i + 1);

	//Create stats object
	mdm_ParamSummaryStats stats;

	//Don't set ROI, it should use all voxels
	stats.makeStats(img, "dummy");

	//Check the stats values - data array is {1, 2, 3, 4, 5}
	BOOST_TEST_MESSAGE("Test whole ROI: median");
	BOOST_CHECK_CLOSE(stats.stats().mean_, 3.0, 0.00001);
	BOOST_TEST_MESSAGE("Test whole ROI: stddev");
	BOOST_CHECK_CLOSE(stats.stats().stddev_, 1.5811, 0.1);
	BOOST_TEST_MESSAGE("Test whole ROI: median");
	BOOST_CHECK_CLOSE(stats.stats().median_, 3.0, 0.00001);
	BOOST_TEST_MESSAGE("Test whole ROI: lowerQ");
	BOOST_CHECK_CLOSE(stats.stats().lowerQ_, 1.5, 0.00001);
	BOOST_TEST_MESSAGE("Test whole ROI: median");
	BOOST_CHECK_CLOSE(stats.stats().upperQ_, 4.5, 0.00001);
	BOOST_TEST_MESSAGE("Test whole ROI: median");
	BOOST_CHECK_CLOSE(stats.stats().iqr_, 3.0, 0.00001);
	BOOST_TEST_MESSAGE("Test whole ROI: validVoxels");
	BOOST_CHECK_EQUAL(stats.stats().validVoxels_, 5);
	BOOST_TEST_MESSAGE("Test whole ROI: invalidVoxels");
	BOOST_CHECK_EQUAL(stats.stats().invalidVoxels_, 0);

	//Repeat the test with scale set
	double scale = 2.0;
	stats.makeStats(img, "dummy", scale);

	//data array is{ 2, 4, 6, 8, 10 }
	BOOST_TEST_MESSAGE("Test whole ROI: median");
	BOOST_CHECK_CLOSE(stats.stats().mean_, scale*3.0, 0.00001);
	BOOST_TEST_MESSAGE("Test whole ROI: stddev");
	BOOST_CHECK_CLOSE(stats.stats().stddev_, scale*1.5811, 0.1);
	BOOST_TEST_MESSAGE("Test whole ROI: median");
	BOOST_CHECK_CLOSE(stats.stats().median_, scale*3.0, 0.00001);
	BOOST_TEST_MESSAGE("Test whole ROI: lowerQ");
	BOOST_CHECK_CLOSE(stats.stats().lowerQ_, scale*1.5, 0.00001);
	BOOST_TEST_MESSAGE("Test whole ROI: median");
	BOOST_CHECK_CLOSE(stats.stats().upperQ_, scale*4.5, 0.00001);
	BOOST_TEST_MESSAGE("Test whole ROI: median");
	BOOST_CHECK_CLOSE(stats.stats().iqr_, scale*3.0, 0.00001);
	BOOST_TEST_MESSAGE("Test whole ROI: validVoxels");
	BOOST_CHECK_EQUAL(stats.stats().validVoxels_, 5);
	BOOST_TEST_MESSAGE("Test whole ROI: invalidVoxels");
	BOOST_CHECK_EQUAL(stats.stats().invalidVoxels_, 0);

	//Now set an ROI and repeat the test
	mdm_Image3D roi;
	roi.setDimensions(nx, ny, nz);

	for (int i = 0; i < 4; i++)
		roi.setVoxel(i, 1);

	stats.setROI(roi);
	stats.makeStats(img, "dummy");

	//Should now only use {1, 2, 3, 4}
	BOOST_TEST_MESSAGE("Test whole ROI: median");
	BOOST_CHECK_CLOSE(stats.stats().mean_, 2.5, 0.00001);
	BOOST_TEST_MESSAGE("Test whole ROI: stddev");
	BOOST_CHECK_CLOSE(stats.stats().stddev_, 1.2910, 0.1);
	BOOST_TEST_MESSAGE("Test whole ROI: median");
	BOOST_CHECK_CLOSE(stats.stats().median_, 2.5, 0.00001);
	BOOST_TEST_MESSAGE("Test whole ROI: lowerQ");
	BOOST_CHECK_CLOSE(stats.stats().lowerQ_, 1.25, 0.00001);
	BOOST_TEST_MESSAGE("Test whole ROI: median");
	BOOST_CHECK_CLOSE(stats.stats().upperQ_, 3.75, 0.00001);
	BOOST_TEST_MESSAGE("Test whole ROI: median");
	BOOST_CHECK_CLOSE(stats.stats().iqr_, 2.5, 0.00001);
	BOOST_TEST_MESSAGE("Test whole ROI: validVoxels");
	BOOST_CHECK_EQUAL(stats.stats().validVoxels_, 4);
	BOOST_TEST_MESSAGE("Test whole ROI: invalidVoxels");
	BOOST_CHECK_EQUAL(stats.stats().invalidVoxels_, 0);

	//Set some negative values
	for (int i = 0; i < 3; i++)
		img.setVoxel(i, 1.0 / double(i + 1));

	img.setVoxel(3, -1);
	stats.makeStats(img, "dummy", 1.0, true);

	//Should now only use {1, 2, 3}
	BOOST_TEST_MESSAGE("Test whole ROI: median");
	BOOST_CHECK_CLOSE(stats.stats().mean_, 2.0, 0.00001);
	BOOST_TEST_MESSAGE("Test whole ROI: stddev");
	BOOST_CHECK_CLOSE(stats.stats().stddev_, 1, 0.1);
	BOOST_TEST_MESSAGE("Test whole ROI: median");
	BOOST_CHECK_CLOSE(stats.stats().median_, 2.0, 0.00001);
	BOOST_TEST_MESSAGE("Test whole ROI: lowerQ");
	BOOST_CHECK_CLOSE(stats.stats().lowerQ_, 1.0, 0.00001);
	BOOST_TEST_MESSAGE("Test whole ROI: median");
	BOOST_CHECK_CLOSE(stats.stats().upperQ_, 3.0, 0.00001);
	BOOST_TEST_MESSAGE("Test whole ROI: median");
	BOOST_CHECK_CLOSE(stats.stats().iqr_, 2.0, 0.00001);
	BOOST_TEST_MESSAGE("Test whole ROI: validVoxels");
	BOOST_CHECK_EQUAL(stats.stats().validVoxels_, 3);
	BOOST_TEST_MESSAGE("Test whole ROI: invalidVoxels");
	BOOST_CHECK_EQUAL(stats.stats().invalidVoxels_, 1);
}

BOOST_AUTO_TEST_SUITE_END() //


/* boost random/cauchy_distribution.hpp header file
 *
 * Copyright Jens Maurer 2000-2001
 * Permission to use, copy, modify, sell, and distribute this software
 * is hereby granted without fee provided that the above copyright notice
 * appears in all copies and that both that copyright notice and this
 * permission notice appear in supporting documentation,
 *
 * Jens Maurer makes no representations about the suitability of this
 * software for any purpose. It is provided "as is" without express or
 * implied warranty.
 *
 * See http://www.boost.org for most recent version including documentation.
 *
 * $Id: cauchy_distribution.hpp 11696 2001-11-14 21:53:38Z jmaurer $
 *
 * Revision history
 *  2001-02-18  moved to individual header files
 */

#ifndef BOOST_RANDOM_CAUCHY_DISTRIBUTION_HPP
#define BOOST_RANDOM_CAUCHY_DISTRIBUTION_HPP

#include <cmath>
#include <boost/random/uniform_01.hpp>

namespace boost {

#if defined(__GNUC__) && (__GNUC__ < 3)
// Special gcc workaround: gcc 2.95.x ignores using-declarations
// in template classes (confirmed by gcc author Martin v. Loewis)
  using std::tan;
#endif

// Cauchy distribution: p(x) = sigma/(pi*(sigma**2 + (x-median)**2))
template<class UniformRandomNumberGenerator, class RealType = double>
class cauchy_distribution
{
public:
  typedef UniformRandomNumberGenerator base_type;
  typedef RealType result_type;

  cauchy_distribution(base_type & rng, result_type median = 0,
                      result_type sigma = 1)
    : _rng(rng), _median(median), _sigma(sigma) { }
  // compiler-generated copy constructor is fine
  // uniform_01 cannot be assigned, neither can this class
  result_type operator()()
  {
    const double pi = 3.14159265358979323846;
#ifndef BOOST_NO_STDC_NAMESPACE
    using std::tan;
#endif
    return _median + _sigma * tan(pi*(_rng()-0.5));
  }
#ifndef BOOST_NO_OPERATORS_IN_NAMESPACE
  friend bool operator==(const cauchy_distribution& x,
                         const cauchy_distribution& y)
  {
    return x._median == y._median && x._sigma == y._sigma && x._rng == y._rng;
  }
#else
  // Use a member function
  bool operator==(const cauchy_distribution& rhs) const
  {
    return _median == rhs._median && _sigma == rhs._sigma && _rng == rhs._rng;
  }
#endif
private:
  uniform_01<base_type, result_type> _rng;
  result_type _median, _sigma;
};

} // namespace boost

#endif // BOOST_RANDOM_CAUCHY_DISTRIBUTION_HPP