/*
// Copyright (c) 2000-2009, Texas Engineering Experiment Station (TEES), a
// component of the Texas A&M University System.

// All rights reserved.

// The information and source code contained herein is the exclusive
// property of TEES and may not be disclosed, examined or reproduced
// in whole or in part without explicit written authorization from TEES.
*/

#ifndef STAPL_ALGORITHMS_GENERATOR_HPP
#define STAPL_ALGORITHMS_GENERATOR_HPP

#include <type_traits>
#include <random>

#include <boost/mpl/has_xxx.hpp>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_int_distribution.hpp>

namespace stapl {

namespace generator_impl {

BOOST_MPL_HAS_XXX_TRAIT_DEF(state_type)

//////////////////////////////////////////////////////////////////////
/// @brief Static polymorphic functor that either returns a provided
/// generator or adjusts its state for a given starting offset through
/// the offsetting constructor interface.
//////////////////////////////////////////////////////////////////////
template<typename Index, typename Generator, bool HasState>
struct state_adjust_impl
{
  static Generator apply(Generator const& gen, Index const&)
  {
    return gen;
  };
};

template<typename Index, typename Generator>
struct state_adjust_impl<Index, Generator, true>
{
  static Generator apply(Generator const& gen, Index const& offset)
  {
    return Generator(gen, offset);
  }
};

//////////////////////////////////////////////////////////////////////
/// @brief Wrapper around @ref state_adjust_impl that detects presence of
/// @p state_type nested typename and either forwards its corresponding boolean
/// value to @ref state_adjust_impl or @p false if the typename does not exist.
//////////////////////////////////////////////////////////////////////
template<typename Index, typename Generator,
         bool = has_state_type<Generator>::value>
struct state_adjust
  : state_adjust_impl<Index, Generator, false>
{ };

template<typename Index, typename Generator>
struct state_adjust<Index, Generator, true>
  : state_adjust_impl<Index, Generator, Generator::state_type::value>
{ };

} // namespace generator_impl

//////////////////////////////////////////////////////////////////////
/// @brief Wrapper around a generator functor that calls the generator's
///   constructor to update its state to a specified offset, if the generator
///   has implemented the method.
///
/// This is used in the @ref generate() pAlgorithm to support generators that
/// produce values that vary based on the number of times the generator's
/// function operator has been invoked.
//////////////////////////////////////////////////////////////////////
template<typename Index, typename Value, typename Generator>
class offset_gen
{
private:
  Generator m_gen;

public:
  using index_type  = Index;
  using result_type = Value;

  offset_gen(Generator gen)
    : m_gen(std::move(gen))
  { }

  result_type operator()(index_type const& i) const
  {
    return generator_impl::state_adjust<Index, Generator>::apply(m_gen, i)();
  }

  void define_type(typer& t)
  {
    t.member(m_gen);
  }
}; // struct offset_gen

//////////////////////////////////////////////////////////////////////
/// @brief Generates a sequence of consecutive values.
/// @tparam T The value type of the elements generated.
//////////////////////////////////////////////////////////////////////
template<typename T>
class sequence
{
private:
  T counter, oldCtr, step;

public:
  using state_type = std::true_type;

  sequence(T start = 0, T st = 1)
    : counter(start), oldCtr(start), step(st)
  { }

  //////////////////////////////////////////////////////////////////////
  /// @brief Creates a functor that is initialized to generate elements
  ///   beginning at the offset position in the sequence.
  /// @param seq The sequence functor is passed in to allow offset-independent
  ///   state to be copied.
  /// @param offset The offset to be copied.
  //////////////////////////////////////////////////////////////////////
  sequence(sequence const& seq, std::size_t offset)
    : counter(seq.counter+offset * seq.step), oldCtr(counter), step(seq.step)
  { }

  void define_type(typer& t)
  {
    t.member(counter);
    t.member(oldCtr);
    t.member(step);
  }

  T operator()(void)
  {
    oldCtr = counter;
    counter += step;
    return oldCtr;
  }
}; // class sequence

//////////////////////////////////////////////////////////////////////
/// @brief Generates a sequence of random values.
///
/// @bug This is hacked to work deterministically with the testing framework
///   still doesn't work for parallel generation, but guarantees that two
///   successive sequentially generated sequences are the same.  Since functors
///   are both created before either is used.  call srand() once iteration
///   via operator() has begun.
//////////////////////////////////////////////////////////////////////
class random_sequence
{
private:
  int m_r;
  int m_offset;
  std::mt19937 m_gen;

public:
  using state_type = std::true_type;

  random_sequence(void)
    : m_r(RAND_MAX), m_offset(0), m_gen(std::random_device()())
  { }

  random_sequence(int i)
    : m_r(i), m_offset(0), m_gen(std::random_device()())
  { }

  //////////////////////////////////////////////////////////////////////
  /// @brief Creates a functor that is initialized to generate elements
  ///   beginning at the offset position in the sequence.
  /// @param seq The sequence functor is passed in to allow offset-independent
  ///   state to be copied.
  /// @param offset The offset to be copied.
  //////////////////////////////////////////////////////////////////////
  random_sequence(random_sequence const& seq, std::size_t offset)
    : m_r(seq.m_r), m_offset(offset)
  { }

  void define_type(typer& t)
  {
    t.member(m_r);
    t.member(m_offset);
    t.member(m_gen);
  }

  int operator()(void)
  { return std::uniform_int_distribution<int>(0, m_r)(m_gen); }
}; // class random_sequence

//////////////////////////////////////////////////////////////////////
/// @brief Generates a sequence of std::pair<K, V> elements.
/// @tparam KeyGenerator    Key's generator type.
/// @tparam ValueGenerator  Value's generator type.
/// @tparam Key             Key's value type.
/// @tparam Value           Value's value type.
//////////////////////////////////////////////////////////////////////
template<typename KeyGenerator, typename ValueGenerator,
         typename Key, typename Value>
class associative_sequence
{
private:
  using result_type = std::pair<Key, Value>;

  KeyGenerator   m_key_gen;
  ValueGenerator m_value_gen;
  std::size_t    m_offset;

public:
  using state_type = std::true_type;

  associative_sequence(KeyGenerator& kg, ValueGenerator& vg)
    : m_key_gen(kg), m_value_gen(vg), m_offset(0)
  { }

  //////////////////////////////////////////////////////////////////////
  /// @brief Creates a functor that is initialized to generate elements
  ///   beginning at the offset position in the sequence.
  /// @param seq The sequence functor is passed in to allow offset-independent
  ///   state to be copied.
  /// @param offset The offset to be copied.
  //////////////////////////////////////////////////////////////////////
  associative_sequence(associative_sequence const& seq, std::size_t offset)
    : m_key_gen(seq.m_key_gen, offset), m_value_gen(seq.m_value_gen, offset),
      m_offset(offset)
  { }

  result_type operator()(void)
  {
    return std::make_pair(m_key_gen(), m_value_gen());
  }

  void define_type(typer& t)
  {
    t.member(m_offset);
    t.member(m_key_gen);
    t.member(m_value_gen);
  }
}; // class associative_sequence

//////////////////////////////////////////////////////////////////////
/// @brief Generates a repeating sequence of values.
/// @tparam T Value type of the used counter for the sequence.
///
/// This differs from the repetitive_sequence by providing the start and end
/// values of the sequence to be repeated while repetitive_sequence accepts the
/// start value and the number of elements before the repeat occurs.
//////////////////////////////////////////////////////////////////////
template<typename T>
class block_sequence
{
private:
  T init, counter, end_counter, step;

public:
  using state_type = std::true_type;

  block_sequence(T start, T end, T st = 1)
    : init(start), counter(start), end_counter(end), step(st)
  { }

  //////////////////////////////////////////////////////////////////////
  /// @brief Creates a functor that is initialized to generate elements
  ///   beginning at the offset position in the sequence.
  /// @param seq The sequence functor is passed in to allow offset-independent
  ///   state to be copied.
  /// @param offset The offset to be copied.
  //////////////////////////////////////////////////////////////////////
  block_sequence(block_sequence const& seq, std::size_t offset)
    : init(seq.init),
      counter(init + (offset % (seq.end_counter - init + 1))),
      end_counter(seq.end_counter), step(seq.step)
  { }

  void define_type(typer &t)
  {
    t.member(init);
    t.member(counter);
    t.member(end_counter);
    t.member(step);
  }

  T operator()(void)
  {
    T oldCtr = counter;
    counter  = (counter <= (end_counter-step) ? counter + step : init);
    return oldCtr;
  }
}; // class block_sequence

//////////////////////////////////////////////////////////////////////
/// @brief Generates a sequence of unique random sorted values.
//////////////////////////////////////////////////////////////////////
class unique_sorted_sequence
{
private:
  using result_type = int;

  std::vector<result_type> m_data;
  std::size_t              m_offset;

  //////////////////////////////////////////////////////////////////////
  /// @brief Functor that binds a random number generator and a
  /// distribution together.
  ///
  /// Boost.Random doesn't provide this interface, and it is needed to
  /// generate a sequence of random numbers using std::generate.
  //////////////////////////////////////////////////////////////////////
  struct rand_wrapper
  {
    boost::random::mt19937 m_gen;
    boost::random::uniform_int_distribution<int> m_dist;

    // the seed used for the generator is a literal to ensure all locations
    // generate the same sequence.
    rand_wrapper()
      : m_gen(0),
        m_dist(std::numeric_limits<int>::min(), std::numeric_limits<int>::max())
    { }

    int operator()()
    {
      return m_dist(m_gen);
    }
  };

public:
  using state_type = std::true_type;

  //////////////////////////////////////////////////////////////////////
  /// @brief Generates the values in its constructor.
  //////////////////////////////////////////////////////////////////////
  template<typename Compare>
  unique_sorted_sequence(std::size_t n, Compare comp)
    : m_data(n), m_offset(0)
  {
    rand_wrapper rand_wrap;
    std::generate(m_data.begin(), m_data.end(), rand_wrap);

    // generate the # of missing data until the array is full
    std::size_t nb_unique = 0;
    do {
      std::sort(m_data.begin(), m_data.end(), comp);

      nb_unique = std::distance(m_data.begin(),
                         std::unique(m_data.begin() + nb_unique, m_data.end()));
      std::generate(m_data.begin() + nb_unique, m_data.end(), rand);
    } while (nb_unique != n);
  }

  //////////////////////////////////////////////////////////////////////
  /// @brief Creates a functor that is initialized to generate elements
  ///   beginning at the offset position in the sequence.
  /// @param seq The sequence functor is passed in to allow offset-independent
  ///   state to be copied.
  /// @param offset The offset to be copied.
  //////////////////////////////////////////////////////////////////////
  unique_sorted_sequence(unique_sorted_sequence const& seq, std::size_t offset)
    : m_data(seq.m_data), m_offset(offset)
  { }

  result_type operator()(void)
  {
    return m_data[m_offset++];
  }

  void define_type(typer& t)
  {
    t.member(m_data);
    t.member(m_offset);
  }
}; // class unique_sorted_sequence

//////////////////////////////////////////////////////////////////////
/// @brief Functor to generate a sequence of default-constructed values.
/// @tparam T Returned value type for the sequence.
//////////////////////////////////////////////////////////////////////
template<typename T>
struct null_sequence
{
  T operator()(void) const { return T(); }
};

//////////////////////////////////////////////////////////////////////
/// @brief Functor to generate a sequence of default-constructed values.
/// @tparam int Returned value type for the sequence.
//////////////////////////////////////////////////////////////////////
template<>
struct null_sequence<int>
{
  int operator()(void) const { return 0; }
};

//////////////////////////////////////////////////////////////////////
/// @brief A sequence that repeats itself every 'repeat' elements.
/// @tparam T value type of the used counter for the sequence.
///
/// This differs from the block_sequence by providing the start value and the
/// number of elements before the repeat occurs while block_sequence accepts the
/// start and end values of the sequence to be repeated.
//////////////////////////////////////////////////////////////////////
template<typename T>
class repetitive_sequence
{
private:
  T counter, step, init;
  size_t el, restart_el;

public:
  using state_type = std::true_type;

  repetitive_sequence(T start, T st, size_t repeat)
    : counter(start), step(st), init(start), el(0), restart_el(repeat)
  { }

  //////////////////////////////////////////////////////////////////////
  /// @brief Creates a functor that is initialized to generate elements
  ///   beginning at the offset position in the sequence.
  /// @param seq The sequence functor is passed in to allow offset-independent
  ///   state to be copied.
  /// @param offset The offset to be copied.
  //////////////////////////////////////////////////////////////////////
  repetitive_sequence(repetitive_sequence const& seq, const std::size_t offset)
    : counter(seq.init + seq.step * offset % seq.restart_el),
      step(seq.step),
      init(seq.init),
      el(offset % seq.restart_el),
      restart_el(seq.restart_el)
  { }

  void define_type(typer& t)
  {
    t.member(counter);
    t.member(step);
    t.member(init);
    t.member(el);
    t.member(restart_el);
  }

  T operator()(void)
  {
    if (el==restart_el)
    {
      el = 0;
      counter = init;
    }

    T oldCtr = counter;
    counter += step;
    ++el;
    return oldCtr;
  }
}; // class repetitive_sequence

//////////////////////////////////////////////////////////////////////
/// @brief Generates a pattern of values that ranges from start to end by
/// step, then from end to start by -step. This pattern is repeated. The
/// start and end values can be repeated, or not, as specified.
/// Example sequence: 0 1 2 3 4 3 2 1 0 1 2 3 4 3 2 1 0...     (no repeat)
/// Example sequence: 0 1 2 3 4 4 3 2 1 0 1 2 3 4 4 3 2 1 0... (repeat end)
///
/// @tparam T Value type of the used counter for the sequence.
/// @param start The starting value to generate the sequence.
/// @param end The end value to generate the sequence.
/// @param step The increment to increase or decrease the value by while
/// moving from start to stop or stop to start, respectively.
/// @param repeat Whether to repeat the start or stop values when they are
/// reached. Provided as an enumeration wave_sequence::None, Start, Stop, Both
///
/// @example wave_sequence<int>(0, 4, 1, wave_sequence<int>::None)
/// @example wave_sequence<int>(0, 4, 1, wave_sequence<int>::Stop)
///
///
/// This differs from the repetitive_sequence by providing the start and end
/// values of the sequence to be repeated while repetitive_sequence accepts the
/// start value and the number of elements before the repeat occurs.
//////////////////////////////////////////////////////////////////////
template<typename T>
class wave_sequence
{
  public:
  // Used to specify that the start value, stop value, or both are repeated
  // when the step direction changes.
  enum Repeat
  {
    None, Start, Stop, Both
  };

  private:
  T init, counter, end_counter, step;
  bool repeatStart=false;
  bool repeatStop=false;
  bool repeated=true; // Have we repeated whatever end we are now at?

  public:
  using state_type = std::true_type;

  wave_sequence(T start, T end, T st = 1, Repeat r = Repeat::None)
    : init(start), counter(start+st), end_counter(end), step(-st)
  {
    if (r== Start || r==Both)
      repeatStart = true;
    if (r== Stop || r==Both)
      repeatStop  = true;
  }

  //////////////////////////////////////////////////////////////////////
  /// @brief Creates a functor that is initialized to generate elements
  ///   beginning at the offset position in the sequence.
  /// @param seq The sequence functor is passed in to allow offset-independent
  ///   state to be copied.
  /// @param offset The offset to be copied.
  //////////////////////////////////////////////////////////////////////
  wave_sequence(wave_sequence const& seq, std::size_t offset)
    : init(seq.init),
      counter(init + (offset % (seq.end_counter - init + 1))),
      end_counter(seq.end_counter), step(seq.step),
      repeatStart(seq.repeatStart), repeatStop(seq.repeatStop),
      repeated(seq.repeated)
  { }

  void define_type(typer &t)
  {
    t.member(init);
    t.member(counter);
    t.member(end_counter);
    t.member(step);
    t.member(repeatStart);
    t.member(repeatStop);
    t.member(repeated);
  }

  T operator()(void)
  {
    if (counter == end_counter)
    {
      if (repeatStop && !repeated)
      {
        repeated=true; // This value is a repeat.
      }
      else
      {
        step = -step; // Reverse our stepping direction.
        repeated = false; // Not a repeated value.
        counter += step;
      }
    }
    else if (counter == init)
    {
      if (repeatStart && !repeated)
      {
        repeated=true; // This value is a repeat.
      }
      else
      {
        step = -step; // Reverse our stepping direction.
        repeated = false; // Not a repeated value.
        counter += step;
      }
    }
    else
    {
      counter += step;
    }
    return counter;
  }
}; // class wave_sequence

} // stapl namespace

#endif


///////////////////////////////////////////////////////////////////////////////
//  Copyright 2018 John Maddock. Distributed under the Boost
//  Software License, Version 1.0. (See accompanying file
//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#ifndef BOOST_MULTIPRECISION_COMPLEX_ADAPTOR_HPP
#define BOOST_MULTIPRECISION_COMPLEX_ADAPTOR_HPP

#include <boost/multiprecision/number.hpp>
#include <boost/cstdint.hpp>
#include <boost/multiprecision/detail/digits.hpp>
#include <boost/functional/hash_fwd.hpp>
#include <boost/type_traits/is_complex.hpp>
#include <cmath>
#include <algorithm>
#include <complex>

namespace boost {
namespace multiprecision {
namespace backends {

template <class Backend>
struct complex_adaptor
{
 protected:
   Backend m_real, m_imag;

 public:
   Backend& real_data()
   {
      return m_real;
   }
   const Backend& real_data() const
   {
      return m_real;
   }
   Backend& imag_data()
   {
      return m_imag;
   }
   const Backend& imag_data() const
   {
      return m_imag;
   }

   typedef typename Backend::signed_types   signed_types;
   typedef typename Backend::unsigned_types unsigned_types;
   typedef typename Backend::float_types    float_types;
   typedef typename Backend::exponent_type  exponent_type;

   complex_adaptor() {}
   complex_adaptor(const complex_adaptor& o) : m_real(o.real_data()), m_imag(o.imag_data()) {}
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
   complex_adaptor(complex_adaptor&& o) : m_real(std::move(o.real_data())), m_imag(std::move(o.imag_data()))
   {}
#endif
   complex_adaptor(const Backend& val)
       : m_real(val)
   {}

   complex_adaptor(const std::complex<float>& val)
   {
      m_real = (long double)val.real();
      m_imag = (long double)val.imag();
   }
   complex_adaptor(const std::complex<double>& val)
   {
      m_real = (long double)val.real();
      m_imag = (long double)val.imag();
   }
   complex_adaptor(const std::complex<long double>& val)
   {
      m_real = val.real();
      m_imag = val.imag();
   }

   complex_adaptor& operator=(const complex_adaptor& o)
   {
      m_real = o.real_data();
      m_imag = o.imag_data();
      return *this;
   }
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
   complex_adaptor& operator=(complex_adaptor&& o) BOOST_NOEXCEPT
   {
      m_real = std::move(o.real_data());
      m_imag = std::move(o.imag_data());
      return *this;
   }
#endif
   template <class V>
   complex_adaptor& operator=(const V& v)
   {
      typedef typename mpl::front<unsigned_types>::type ui_type;
      m_real = v;
      m_imag = ui_type(0u);
      return *this;
   }
   template <class T>
   complex_adaptor& operator=(const std::complex<T>& val)
   {
      m_real = (long double)val.real();
      m_imag = (long double)val.imag();
      return *this;
   }
   complex_adaptor& operator=(const char* s)
   {
      typedef typename mpl::front<unsigned_types>::type ui_type;
      ui_type                                           zero = 0u;

      using default_ops::eval_fpclassify;

      if (s && (*s == '('))
      {
         std::string part;
         const char* p = ++s;
         while (*p && (*p != ',') && (*p != ')'))
            ++p;
         part.assign(s, p);
         if (part.size())
            real_data() = part.c_str();
         else
            real_data() = zero;
         s = p;
         if (*p && (*p != ')'))
         {
            ++p;
            while (*p && (*p != ')'))
               ++p;
            part.assign(s + 1, p);
         }
         else
            part.erase();
         if (part.size())
            imag_data() = part.c_str();
         else
            imag_data() = zero;

         if (eval_fpclassify(imag_data()) == (int)FP_NAN)
         {
            real_data() = imag_data();
         }
      }
      else
      {
         real_data() = s;
         imag_data() = zero;
      }
      return *this;
   }

   int compare(const complex_adaptor& o) const
   {
      // They are either equal or not:
      return (m_real.compare(o.real_data()) == 0) && (m_imag.compare(o.imag_data()) == 0) ? 0 : 1;
   }
   template <class T>
   int compare(const T& val) const
   {
      using default_ops::eval_is_zero;
      return (m_real.compare(val) == 0) && eval_is_zero(m_imag) ? 0 : 1;
   }
   void swap(complex_adaptor& o)
   {
      real_data().swap(o.real_data());
      imag_data().swap(o.imag_data());
   }
   std::string str(std::streamsize dig, std::ios_base::fmtflags f) const
   {
      using default_ops::eval_is_zero;
      if (eval_is_zero(imag_data()))
         return m_real.str(dig, f);
      return "(" + m_real.str(dig, f) + "," + m_imag.str(dig, f) + ")";
   }
   void negate()
   {
      m_real.negate();
      m_imag.negate();
   }
};

template <class Backend, class T>
inline typename enable_if<is_arithmetic<T>, bool>::type eval_eq(const complex_adaptor<Backend>& a, const T& b) BOOST_NOEXCEPT
{
   return a.compare(b) == 0;
}

template <class Backend>
inline void eval_add(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& o)
{
   eval_add(result.real_data(), o.real_data());
   eval_add(result.imag_data(), o.imag_data());
}
template <class Backend>
inline void eval_subtract(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& o)
{
   eval_subtract(result.real_data(), o.real_data());
   eval_subtract(result.imag_data(), o.imag_data());
}
template <class Backend>
inline void eval_multiply(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& o)
{
   Backend t1, t2, t3;
   eval_multiply(t1, result.real_data(), o.real_data());
   eval_multiply(t2, result.imag_data(), o.imag_data());
   eval_subtract(t3, t1, t2);
   eval_multiply(t1, result.real_data(), o.imag_data());
   eval_multiply(t2, result.imag_data(), o.real_data());
   eval_add(t1, t2);
   result.real_data() = BOOST_MP_MOVE(t3);
   result.imag_data() = BOOST_MP_MOVE(t1);
}
template <class Backend>
inline void eval_divide(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& z)
{
   // (a+bi) / (c + di)
   using default_ops::eval_add;
   using default_ops::eval_divide;
   using default_ops::eval_fabs;
   using default_ops::eval_is_zero;
   using default_ops::eval_multiply;
   using default_ops::eval_subtract;
   Backend t1, t2;

   if (eval_is_zero(z.imag_data()))
   {
      eval_divide(result.real_data(), z.real_data());
      eval_divide(result.imag_data(), z.real_data());
      return;
   }

   eval_fabs(t1, z.real_data());
   eval_fabs(t2, z.imag_data());
   if (t1.compare(t2) < 0)
   {
      eval_divide(t1, z.real_data(), z.imag_data()); // t1 = c/d
      eval_multiply(t2, z.real_data(), t1);
      eval_add(t2, z.imag_data()); // denom = c * (c/d) + d
      Backend t_real(result.real_data());
      // real = (a * (c/d) + b) / (denom)
      eval_multiply(result.real_data(), t1);
      eval_add(result.real_data(), result.imag_data());
      eval_divide(result.real_data(), t2);
      // imag = (b * c/d - a) / denom
      eval_multiply(result.imag_data(), t1);
      eval_subtract(result.imag_data(), t_real);
      eval_divide(result.imag_data(), t2);
   }
   else
   {
      eval_divide(t1, z.imag_data(), z.real_data()); // t1 = d/c
      eval_multiply(t2, z.imag_data(), t1);
      eval_add(t2, z.real_data()); // denom = d * d/c + c

      Backend r_t(result.real_data());
      Backend i_t(result.imag_data());

      // real = (b * d/c + a) / denom
      eval_multiply(result.real_data(), result.imag_data(), t1);
      eval_add(result.real_data(), r_t);
      eval_divide(result.real_data(), t2);
      // imag = (-a * d/c + b) / denom
      eval_multiply(result.imag_data(), r_t, t1);
      result.imag_data().negate();
      eval_add(result.imag_data(), i_t);
      eval_divide(result.imag_data(), t2);
   }
}
template <class Backend, class T>
inline typename boost::disable_if_c<boost::is_same<complex_adaptor<Backend>, T>::value>::type eval_add(complex_adaptor<Backend>& result, const T& scalar)
{
   using default_ops::eval_add;
   eval_add(result.real_data(), scalar);
}
template <class Backend, class T>
inline typename boost::disable_if_c<boost::is_same<complex_adaptor<Backend>, T>::value>::type eval_subtract(complex_adaptor<Backend>& result, const T& scalar)
{
   using default_ops::eval_subtract;
   eval_subtract(result.real_data(), scalar);
}
template <class Backend, class T>
inline typename boost::disable_if_c<boost::is_same<complex_adaptor<Backend>, T>::value>::type eval_multiply(complex_adaptor<Backend>& result, const T& scalar)
{
   using default_ops::eval_multiply;
   eval_multiply(result.real_data(), scalar);
   eval_multiply(result.imag_data(), scalar);
}
template <class Backend, class T>
inline typename boost::disable_if_c<boost::is_same<complex_adaptor<Backend>, T>::value>::type eval_divide(complex_adaptor<Backend>& result, const T& scalar)
{
   using default_ops::eval_divide;
   eval_divide(result.real_data(), scalar);
   eval_divide(result.imag_data(), scalar);
}
// Optimised 3 arg versions:
template <class Backend, class T>
inline typename boost::disable_if_c<boost::is_same<complex_adaptor<Backend>, T>::value>::type eval_add(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& a, const T& scalar)
{
   using default_ops::eval_add;
   eval_add(result.real_data(), a.real_data(), scalar);
   result.imag_data() = a.imag_data();
}
template <class Backend, class T>
inline typename boost::disable_if_c<boost::is_same<complex_adaptor<Backend>, T>::value>::type eval_subtract(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& a, const T& scalar)
{
   using default_ops::eval_subtract;
   eval_subtract(result.real_data(), a.real_data(), scalar);
   result.imag_data() = a.imag_data();
}
template <class Backend, class T>
inline typename boost::disable_if_c<boost::is_same<complex_adaptor<Backend>, T>::value>::type eval_multiply(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& a, const T& scalar)
{
   using default_ops::eval_multiply;
   eval_multiply(result.real_data(), a.real_data(), scalar);
   eval_multiply(result.imag_data(), a.imag_data(), scalar);
}
template <class Backend, class T>
inline typename boost::disable_if_c<boost::is_same<complex_adaptor<Backend>, T>::value>::type eval_divide(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& a, const T& scalar)
{
   using default_ops::eval_divide;
   eval_divide(result.real_data(), a.real_data(), scalar);
   eval_divide(result.imag_data(), a.imag_data(), scalar);
}

template <class Backend>
inline bool eval_is_zero(const complex_adaptor<Backend>& val) BOOST_NOEXCEPT
{
   using default_ops::eval_is_zero;
   return eval_is_zero(val.real_data()) && eval_is_zero(val.imag_data());
}
template <class Backend>
inline int eval_get_sign(const complex_adaptor<Backend>&)
{
   BOOST_STATIC_ASSERT_MSG(sizeof(Backend) == UINT_MAX, "Complex numbers have no sign bit."); // designed to always fail
   return 0;
}

template <class Result, class Backend>
inline typename disable_if_c<boost::is_complex<Result>::value>::type eval_convert_to(Result* result, const complex_adaptor<Backend>& val)
{
   using default_ops::eval_convert_to;
   using default_ops::eval_is_zero;
   if (!eval_is_zero(val.imag_data()))
   {
      BOOST_THROW_EXCEPTION(std::runtime_error("Could not convert imaginary number to scalar."));
   }
   eval_convert_to(result, val.real_data());
}

template <class Backend, class T>
inline void assign_components(complex_adaptor<Backend>& result, const T& a, const T& b)
{
   result.real_data() = a;
   result.imag_data() = b;
}

//
// Native non-member operations:
//
template <class Backend>
inline void eval_sqrt(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& val)
{
   // Use the following:
   // sqrt(z) = (s, zi / 2s)       for zr >= 0
   //           (|zi| / 2s, +-s)   for zr <  0
   // where s = sqrt{ [ |zr| + sqrt(zr^2 + zi^2) ] / 2 },
   // and the +- sign is the same as the sign of zi.
   using default_ops::eval_abs;
   using default_ops::eval_add;
   using default_ops::eval_divide;
   using default_ops::eval_get_sign;
   using default_ops::eval_is_zero;

   if (eval_is_zero(val.imag_data()) && (eval_get_sign(val.real_data()) >= 0))
   {
      static const typename mpl::front<typename Backend::unsigned_types>::type zero = 0u;
      eval_sqrt(result.real_data(), val.real_data());
      result.imag_data() = zero;
      return;
   }

   const bool __my_real_part_is_neg(eval_get_sign(val.real_data()) < 0);

   Backend __my_real_part_fabs(val.real_data());
   if (__my_real_part_is_neg)
      __my_real_part_fabs.negate();

   Backend t, __my_sqrt_part;
   eval_abs(__my_sqrt_part, val);
   eval_add(__my_sqrt_part, __my_real_part_fabs);
   eval_ldexp(t, __my_sqrt_part, -1);
   eval_sqrt(__my_sqrt_part, t);

   if (__my_real_part_is_neg == false)
   {
      eval_ldexp(t, __my_sqrt_part, 1);
      eval_divide(result.imag_data(), val.imag_data(), t);
      result.real_data() = __my_sqrt_part;
   }
   else
   {
      const bool __my_imag_part_is_neg(eval_get_sign(val.imag_data()) < 0);

      Backend __my_imag_part_fabs(val.imag_data());
      if (__my_imag_part_is_neg)
         __my_imag_part_fabs.negate();

      eval_ldexp(t, __my_sqrt_part, 1);
      eval_divide(result.real_data(), __my_imag_part_fabs, t);
      if (__my_imag_part_is_neg)
         __my_sqrt_part.negate();
      result.imag_data() = __my_sqrt_part;
   }
}

template <class Backend>
inline void eval_abs(Backend& result, const complex_adaptor<Backend>& val)
{
   Backend t1, t2;
   eval_multiply(t1, val.real_data(), val.real_data());
   eval_multiply(t2, val.imag_data(), val.imag_data());
   eval_add(t1, t2);
   eval_sqrt(result, t1);
}

template <class Backend>
inline void eval_pow(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& b, const complex_adaptor<Backend>& e)
{
   using default_ops::eval_acos;
   using default_ops::eval_cos;
   using default_ops::eval_exp;
   using default_ops::eval_get_sign;
   using default_ops::eval_is_zero;
   using default_ops::eval_multiply;
   using default_ops::eval_sin;

   if (eval_is_zero(e))
   {
      typename mpl::front<typename Backend::unsigned_types>::type one(1);
      result = one;
      return;
   }
   else if (eval_is_zero(b))
   {
      if (eval_is_zero(e.real_data()))
      {
         Backend n          = std::numeric_limits<number<Backend> >::quiet_NaN().backend();
         result.real_data() = n;
         result.imag_data() = n;
      }
      else if (eval_get_sign(e.real_data()) < 0)
      {
         Backend n          = std::numeric_limits<number<Backend> >::infinity().backend();
         result.real_data() = n;
         typename mpl::front<typename Backend::unsigned_types>::type zero(0);
         if (eval_is_zero(e.imag_data()))
            result.imag_data() = zero;
         else
            result.imag_data() = n;
      }
      else
      {
         typename mpl::front<typename Backend::unsigned_types>::type zero(0);
         result = zero;
      }
      return;
   }
   complex_adaptor<Backend> t;
   eval_log(t, b);
   eval_multiply(t, e);
   eval_exp(result, t);
}

template <class Backend>
inline void eval_exp(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
{
   using default_ops::eval_cos;
   using default_ops::eval_exp;
   using default_ops::eval_is_zero;
   using default_ops::eval_multiply;
   using default_ops::eval_sin;

   if (eval_is_zero(arg.imag_data()))
   {
      eval_exp(result.real_data(), arg.real_data());
      typename mpl::front<typename Backend::unsigned_types>::type zero(0);
      result.imag_data() = zero;
      return;
   }
   eval_cos(result.real_data(), arg.imag_data());
   eval_sin(result.imag_data(), arg.imag_data());
   Backend e;
   eval_exp(e, arg.real_data());
   if (eval_is_zero(result.real_data()))
      eval_multiply(result.imag_data(), e);
   else if (eval_is_zero(result.imag_data()))
      eval_multiply(result.real_data(), e);
   else
      eval_multiply(result, e);
}

template <class Backend>
inline void eval_log(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
{
   using default_ops::eval_add;
   using default_ops::eval_atan2;
   using default_ops::eval_get_sign;
   using default_ops::eval_is_zero;
   using default_ops::eval_log;
   using default_ops::eval_multiply;

   if (eval_is_zero(arg.imag_data()) && (eval_get_sign(arg.real_data()) >= 0))
   {
      eval_log(result.real_data(), arg.real_data());
      typename mpl::front<typename Backend::unsigned_types>::type zero(0);
      result.imag_data() = zero;
      return;
   }

   Backend t1, t2;
   eval_multiply(t1, arg.real_data(), arg.real_data());
   eval_multiply(t2, arg.imag_data(), arg.imag_data());
   eval_add(t1, t2);
   eval_log(t2, t1);
   eval_ldexp(result.real_data(), t2, -1);
   eval_atan2(result.imag_data(), arg.imag_data(), arg.real_data());
}

template <class Backend>
inline void eval_log10(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
{
   using default_ops::eval_divide;
   using default_ops::eval_log;

   typedef typename mpl::front<typename Backend::unsigned_types>::type ui_type;

   Backend ten;
   ten = ui_type(10);
   Backend l_ten;
   eval_log(l_ten, ten);
   eval_log(result, arg);
   eval_divide(result, l_ten);
}

template <class Backend>
inline void eval_sin(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
{
   using default_ops::eval_cos;
   using default_ops::eval_cosh;
   using default_ops::eval_sin;
   using default_ops::eval_sinh;

   Backend t1, t2;
   eval_sin(t1, arg.real_data());
   eval_cosh(t2, arg.imag_data());
   eval_multiply(result.real_data(), t1, t2);

   eval_cos(t1, arg.real_data());
   eval_sinh(t2, arg.imag_data());
   eval_multiply(result.imag_data(), t1, t2);
}

template <class Backend>
inline void eval_cos(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
{
   using default_ops::eval_cos;
   using default_ops::eval_cosh;
   using default_ops::eval_sin;
   using default_ops::eval_sinh;

   Backend t1, t2;
   eval_cos(t1, arg.real_data());
   eval_cosh(t2, arg.imag_data());
   eval_multiply(result.real_data(), t1, t2);

   eval_sin(t1, arg.real_data());
   eval_sinh(t2, arg.imag_data());
   eval_multiply(result.imag_data(), t1, t2);
   result.imag_data().negate();
}

template <class Backend>
inline void eval_tan(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
{
   complex_adaptor<Backend> c;
   eval_cos(c, arg);
   eval_sin(result, arg);
   eval_divide(result, c);
}

template <class Backend>
inline void eval_asin(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
{
   using default_ops::eval_add;
   using default_ops::eval_multiply;

   if (eval_is_zero(arg))
   {
      result = arg;
      return;
   }

   complex_adaptor<Backend> t1, t2;
   assign_components(t1, arg.imag_data(), arg.real_data());
   t1.real_data().negate();
   eval_asinh(t2, t1);

   assign_components(result, t2.imag_data(), t2.real_data());
   result.imag_data().negate();
}

template <class Backend>
inline void eval_acos(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
{
   typedef typename mpl::front<typename Backend::unsigned_types>::type ui_type;

   using default_ops::eval_asin;

   Backend half_pi, t1;
   t1 = static_cast<ui_type>(1u);
   eval_asin(half_pi, t1);
   eval_asin(result, arg);
   result.negate();
   eval_add(result.real_data(), half_pi);
}

template <class Backend>
inline void eval_atan(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
{
   typedef typename mpl::front<typename Backend::unsigned_types>::type ui_type;
   ui_type                                                             one = (ui_type)1u;

   using default_ops::eval_add;
   using default_ops::eval_is_zero;
   using default_ops::eval_log;
   using default_ops::eval_subtract;

   complex_adaptor<Backend> __my_z_times_i, t1, t2, t3;
   assign_components(__my_z_times_i, arg.imag_data(), arg.real_data());
   __my_z_times_i.real_data().negate();

   eval_add(t1, __my_z_times_i, one);
   eval_log(t2, t1);
   eval_subtract(t1, one, __my_z_times_i);
   eval_log(t3, t1);
   eval_subtract(t1, t3, t2);

   eval_ldexp(result.real_data(), t1.imag_data(), -1);
   eval_ldexp(result.imag_data(), t1.real_data(), -1);
   if (!eval_is_zero(result.real_data()))
      result.real_data().negate();
}

template <class Backend>
inline void eval_sinh(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
{
   using default_ops::eval_cos;
   using default_ops::eval_cosh;
   using default_ops::eval_sin;
   using default_ops::eval_sinh;

   Backend t1, t2;
   eval_cos(t1, arg.imag_data());
   eval_sinh(t2, arg.real_data());
   eval_multiply(result.real_data(), t1, t2);

   eval_cosh(t1, arg.real_data());
   eval_sin(t2, arg.imag_data());
   eval_multiply(result.imag_data(), t1, t2);
}

template <class Backend>
inline void eval_cosh(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
{
   using default_ops::eval_cos;
   using default_ops::eval_cosh;
   using default_ops::eval_sin;
   using default_ops::eval_sinh;

   Backend t1, t2;
   eval_cos(t1, arg.imag_data());
   eval_cosh(t2, arg.real_data());
   eval_multiply(result.real_data(), t1, t2);

   eval_sin(t1, arg.imag_data());
   eval_sinh(t2, arg.real_data());
   eval_multiply(result.imag_data(), t1, t2);
}

template <class Backend>
inline void eval_tanh(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
{
   using default_ops::eval_divide;
   complex_adaptor<Backend> s, c;
   eval_sinh(s, arg);
   eval_cosh(c, arg);
   eval_divide(result, s, c);
}

template <class Backend>
inline void eval_asinh(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
{
   typedef typename mpl::front<typename Backend::unsigned_types>::type ui_type;
   ui_type                                                             one = (ui_type)1u;

   using default_ops::eval_add;
   using default_ops::eval_log;
   using default_ops::eval_multiply;

   complex_adaptor<Backend> t1, t2;
   eval_multiply(t1, arg, arg);
   eval_add(t1, one);
   eval_sqrt(t2, t1);
   eval_add(t2, arg);
   eval_log(result, t2);
}

template <class Backend>
inline void eval_acosh(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
{
   typedef typename mpl::front<typename Backend::unsigned_types>::type ui_type;
   ui_type                                                             one = (ui_type)1u;

   using default_ops::eval_add;
   using default_ops::eval_divide;
   using default_ops::eval_log;
   using default_ops::eval_multiply;
   using default_ops::eval_subtract;

   complex_adaptor<Backend> __my_zp(arg);
   eval_add(__my_zp.real_data(), one);
   complex_adaptor<Backend> __my_zm(arg);
   eval_subtract(__my_zm.real_data(), one);

   complex_adaptor<Backend> t1, t2;
   eval_divide(t1, __my_zm, __my_zp);
   eval_sqrt(t2, t1);
   eval_multiply(t2, __my_zp);
   eval_add(t2, arg);
   eval_log(result, t2);
}

template <class Backend>
inline void eval_atanh(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
{
   typedef typename mpl::front<typename Backend::unsigned_types>::type ui_type;
   ui_type                                                             one = (ui_type)1u;

   using default_ops::eval_add;
   using default_ops::eval_divide;
   using default_ops::eval_log;
   using default_ops::eval_multiply;
   using default_ops::eval_subtract;

   complex_adaptor<Backend> t1, t2, t3;
   eval_add(t1, arg, one);
   eval_log(t2, t1);
   eval_subtract(t1, one, arg);
   eval_log(t3, t1);
   eval_subtract(t2, t3);

   eval_ldexp(result.real_data(), t2.real_data(), -1);
   eval_ldexp(result.imag_data(), t2.imag_data(), -1);
}

template <class Backend>
inline void eval_conj(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
{
   result = arg;
   result.imag_data().negate();
}

template <class Backend>
inline void eval_proj(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
{
   using default_ops::eval_get_sign;

   typedef typename mpl::front<typename Backend::unsigned_types>::type ui_type;
   ui_type                                                             zero = (ui_type)0u;

   int c1 = eval_fpclassify(arg.real_data());
   int c2 = eval_fpclassify(arg.imag_data());
   if (c1 == FP_INFINITE)
   {
      result.real_data() = arg.real_data();
      if (eval_get_sign(result.real_data()) < 0)
         result.real_data().negate();
      result.imag_data() = zero;
      if (eval_get_sign(arg.imag_data()) < 0)
         result.imag_data().negate();
   }
   else if (c2 == FP_INFINITE)
   {
      result.real_data() = arg.imag_data();
      if (eval_get_sign(result.real_data()) < 0)
         result.real_data().negate();
      result.imag_data() = zero;
      if (eval_get_sign(arg.imag_data()) < 0)
         result.imag_data().negate();
   }
   else
      result = arg;
}

template <class Backend>
inline void eval_real(Backend& result, const complex_adaptor<Backend>& arg)
{
   result = arg.real_data();
}
template <class Backend>
inline void eval_imag(Backend& result, const complex_adaptor<Backend>& arg)
{
   result = arg.imag_data();
}

template <class Backend, class T>
inline void eval_set_imag(complex_adaptor<Backend>& result, const T& arg)
{
   result.imag_data() = arg;
}

template <class Backend, class T>
inline void eval_set_real(complex_adaptor<Backend>& result, const T& arg)
{
   result.real_data() = arg;
}

template <class Backend>
inline std::size_t hash_value(const complex_adaptor<Backend>& val)
{
   std::size_t result  = hash_value(val.real_data());
   std::size_t result2 = hash_value(val.imag_data());
   boost::hash_combine(result, result2);
   return result;
}

} // namespace backends

using boost::multiprecision::backends::complex_adaptor;

template <class Backend>
struct number_category<complex_adaptor<Backend> > : public boost::mpl::int_<boost::multiprecision::number_kind_complex>
{};

template <class Backend, expression_template_option ExpressionTemplates>
struct component_type<number<complex_adaptor<Backend>, ExpressionTemplates> >
{
   typedef number<Backend, ExpressionTemplates> type;
};

template <class Backend, expression_template_option ExpressionTemplates>
struct complex_result_from_scalar<number<Backend, ExpressionTemplates> >
{
   typedef number<complex_adaptor<Backend>, ExpressionTemplates> type;
};

}

} // namespace boost::multiprecision

#endif


/**
 * \file
 * \author stvdedal@gmail.com
 *
 * \brief
 * Program for testing gspan algorithm
 */

#include "gspan.hpp"

#include <boost/graph/adjacency_list.hpp>

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <list>
#include <vector>
#include <map>
#include <set>
#include <algorithm>
#include <functional>

#include <cctype>
#include <cstdlib>

using namespace boost;

void
print_usage(std::ostream& s)
{
    // line width 80
    // --------------------------------------------------------------------------------
    s <<
      "Usage: gspan [options]\n"
      "Graph-based substructure pattern mining.\n"
      "Depending on the graph count in input, there are two modes:\n"
      "  1. input contains one graph. Mined patterns belong to this one;\n"
      "       in this case only --mincount=NUM option is used\n"
      "  2. input contains many graphs. Mined patterns belong to some graph in input;\n"
      "       in this case --minsupp=NUM option is used, as more useful.\n"
      "Options:\n"
      "  -i, --input FILE        file to read, default stdin\n"
      "  -o, --output FILE       file to write, default stdout\n"
      "  -c, --mincount NUM      minimal count, integer value, default 1\n"
      "  -s, --minsupp NUM       minimal support, 0..1\n"
      "  -l, --legacy            use tgf format for input and output (slower!)\n"
      "  -e, --embeddings [opts] none, autgrp, all. default is none\n"
      "  -h, --help              this help"
      << std::endl;
}

void error_usage()
{
    print_usage(std::cerr);
    exit(1);
}

std::ifstream input_fstream;
std::ofstream output_fstream;
std::istream* input_stream = &std::cin;
std::ostream* output_stream = &std::cout;
bool no_output = false;
bool use_legacy = false;
enum OutputMappings {
    OUTPUT_MAPPING_NONE,
    OUTPUT_MAPPING_ONE_AUTOMORPH,
    OUTPUT_MAPPING_ALL
} output_mappings = OUTPUT_MAPPING_NONE;

static std::size_t pattern_no = 0;

/**
 * Vertex and edge properties are used by algorithm.
 * To optimize comparison, they are integers (not strings)
 *
 * vertex values are addressed by boost::vertex_name
 * edge values   are addressed by boost::edge_name
 */
std::vector<std::string> v_values;
std::vector<std::string> e_values;

std::size_t
map_string_to_integer(std::vector<std::string>& values,
                      const std::string& value)
{
    auto valit = std::find(values.begin(), values.end(), value);
    if (valit == values.end()) {
        valit = values.insert(values.end(), value);
    }
    return valit - values.begin();
}

using VP = property<vertex_name_t, std::size_t>;
using EP =
    property<edge_index_t, std::size_t, property<edge_name_t, std::size_t> >;

using InputGraph = adjacency_list<vecS, vecS, undirectedS, VP, EP, std::size_t>;
using InputGraphVertex = graph_traits<InputGraph>::vertex_descriptor;
using InputGraphEdge = graph_traits<InputGraph>::edge_descriptor;
using GspanTraits = gspan_traits<InputGraph, vertex_name_t, edge_name_t>;

template <typename MG, typename SBG>
void
print_mapping(const MG& mg,
              const SBG& s,
              std::size_t map_no,
              std::size_t autmorph_no)
{
    std::ostream& os = *output_stream;

    //os << std::endl;
    const InputGraph& ig = *s.input_graph();
    os << "m " << map_no << " #automorh " << autmorph_no << " "<<ig[graph_bundle]<< std::endl;
    for (auto v_mg : vertices(mg)) {
        auto v_ig = get_v_ig(s, v_mg);
        os << "v " << v_index(mg, v_mg) << " ";
        //os << ig[graph_bundle] << " ";
        os << get(get(vertex_index, ig), v_ig) << std::endl;
    }
    for (auto e_mg : edges(mg)) {
        auto e_ig = get_e_ig(s, e_mg);
        os << "e " << e_index(mg, e_mg) << " ";
        //os << ig[graph_bundle] << " ";
        os << get(get(edge_index, ig), e_ig) << std::endl;
    }
}

void
write_egf(const GspanTraits::MG& mg, const GspanTraits::SG& sg, int support)
{
    ++pattern_no;

    if (no_output)
        return;

    std::ostream& os = *output_stream;

    //os << std::endl;
    os << "p " << pattern_no << " # occurence " << support << std::endl;
    for (auto v : vertices(mg))
        os << "v " << v_index(mg, v) << " " << v_values[v_bundle(mg, v)]
           << std::endl;
    for (auto e : edges(mg))
        os << "e " << e_index(mg, e) << " " << source_index(mg, e) << " "
           << target_index(mg, e) << " " << e_values[e_bundle(mg, e)] << std::endl;

    if (output_mappings != OUTPUT_MAPPING_NONE) {
        std::size_t map_no = 0;
        for (const auto& g_sbgs : sg) {
            for (const auto& grp : g_sbgs.second.aut_list) {
                std::size_t autmorph_no = 0;
                for (const auto& s : grp) {
                    print_mapping(mg, *s, ++map_no, ++autmorph_no);
                    if (output_mappings == OUTPUT_MAPPING_ONE_AUTOMORPH)
                        break;
                }
            }
        }
    }
}

void
write_tgf(const GspanTraits::MG& mg, const GspanTraits::SG& sg, int support)
{
    ++pattern_no;

    if (no_output)
        return;
    std::ostream& os = *output_stream;

    using MGE = GspanTraits::MG::edge_descriptor;
    std::vector<MGE> mg_edges; // to reverse (for matching with gbolt)

    mg_edges.reserve(num_edges(mg));
    for (auto e : edges(mg))
        mg_edges.push_back(e);

    os << "t # " << pattern_no - 1 << " * " << support << std::endl;
    for (auto v : vertices(mg))
        os << "v " << v_index(mg, v) << " " << v_bundle(mg, v) << std::endl;

    using RevIt = std::vector<MGE>::const_reverse_iterator;
    for (RevIt ei = mg_edges.rbegin(); ei != mg_edges.rend(); ++ei) {
        MGE e = *ei;
        os << "e " << source_index(mg, e) << " " << target_index(mg, e)
           << " " << e_bundle(mg, e) << std::endl;
    }

    std::set<std::size_t> graph_ids;
    for (const auto& g_sbgs : sg) {
        const InputGraph& ig = *g_sbgs.first;
        graph_ids.insert(ig[graph_bundle]);
    }

    os << "x ";
    for (std::size_t graph_id : graph_ids) {
        os << graph_id << " ";
    }

    os << std::endl << std::endl;
}

inline
std::string&
remove_comment(std::string& s)
{
    s.erase(std::find(s.begin(), s.end(), '#'), s.end());
    return s;
}

inline
std::string&
remove_whitespaces_left(std::string& s)
{
    using namespace std;
    s.erase(s.begin(), find_if(s.begin(), s.end(), not1(ptr_fun(&::isblank))));
    return s;
}

inline
std::string&
remove_whitespaces_right(std::string& s)
{
    using namespace std;
    auto rit = find_if(s.rbegin(), s.rend(), not1(ptr_fun(&::isblank)));
    s.erase(rit.base(), s.end());
    return s;
}

bool read_egf(std::list<InputGraph>& container, std::istream& is)
{
    std::map<std::size_t, InputGraphVertex> vmap;
    std::size_t line_no = 0;
    std::string line;

    while (getline(is, line)) {
        ++line_no;
        remove_comment(line);
        remove_whitespaces_left(line);
        remove_whitespaces_right(line);
        if (line.empty())
            continue;
        char tag = 0;
        std::stringstream ss(line);
        ss >> tag;
        switch (tag) {
        case 't': {
            vmap.clear();
            container.push_back(InputGraph());
            std::size_t graph_id = 0;
            ss >> graph_id;
            if (!ss) {
                std::cerr << "invalid or missed <graph_id>, at line " << line_no
                          << std::endl;
                return false;
            }
            container.back()[graph_bundle] = graph_id;
        }
        break;
        case 'v': {
            if (container.empty()) {
                std::cerr << "invalid format: 't' tag missed" << std::endl;
                return false;
            }
            InputGraph& g = container.back();
            InputGraphVertex v = add_vertex(g);
            std::size_t vertex_id = 0;
            ss >> vertex_id;
            if (!ss) {
                std::cerr << "invalid or missed <vertex_id>, at line " << line_no
                          << std::endl;
                return false;
            }

            std::string value;
            getline(ss, value);
            remove_whitespaces_left(value);
            put(get(vertex_name, g), v, map_string_to_integer(v_values, value));
            vmap[vertex_id] = v;
        }
        break;
        case 'e': {
            if (container.empty()) {
                std::cerr << "invalid format: 't' tag missed" << std::endl;
                return false;
            }
            InputGraph& g = container.back();
            std::size_t edge_id = 0;
            if (!(ss >> edge_id)) {
                std::cerr << "invalid or missed <edge_id>, at line " << line_no
                          << std::endl;
                return false;
            }
            std::size_t src_id;
            if (!(ss >> src_id) || vmap.find(src_id) == vmap.end()) {
                std::cerr << "invalid or missed <vertex_id_1>, at line " << line_no
                          << std::endl;
                return false;
            }
            std::size_t dst_id;
            if (!(ss >> dst_id) || vmap.find(dst_id) == vmap.end()) {
                std::cerr << "invalid or missed <vertex_id_2>, at line " << line_no
                          << std::endl;
                return false;
            }

            InputGraphVertex u = vmap[src_id];
            InputGraphVertex v = vmap[dst_id];
            InputGraphEdge e = add_edge(u, v, g).first;
            put(get(edge_index, g), e, edge_id);

            std::string value;
            getline(ss, value);
            remove_whitespaces_left(value);
            put(get(edge_name, g), e, map_string_to_integer(e_values, value));
        }
        break;
        default:
            std::cerr << "invalid or missed <tag>, at line " << line_no << std::endl;
            return false;
        }
    }

    return true;
}

bool read_tgf(std::list<InputGraph>& container, std::istream& is)
{
    std::map<std::size_t, InputGraphVertex> vmap;
    std::size_t line_no = 0;
    std::string line;

    while (getline(is, line)) {
        ++line_no;
        if (line.empty())
            continue;
        char tag = 0;
        std::stringstream ss(line);
        ss >> tag;
        switch (tag) {
        case 't': {
            vmap.clear();
            container.push_back(InputGraph());
            char nsign = 0;
            std::size_t graph_id = 0;
            ss >> nsign >> graph_id;
            if (!ss || nsign != '#') {
                std::cerr << "invalid or missed <graph_id>, at line " << line_no
                          << std::endl;
                return false;
            }
            container.back()[graph_bundle] = graph_id;
        }
        break;
        case 'v': {
            if (container.empty()) {
                std::cerr << "invalid format: 't' tag missed" << std::endl;
                return false;
            }
            InputGraph& g = container.back();
            InputGraphVertex v = add_vertex(g);
            std::size_t vertex_id = 0;
            ss >> vertex_id;
            if (!ss || vertex_id >= num_vertices(g)) {
                std::cerr << "invalid or missed <vertex_id>, at line " << line_no
                          << std::endl;
                return false;
            }

            std::size_t ival;
            if (!(ss >> ival)) {
                std::cerr << "invalid or missed vertex value (integer), at line " << line_no
                          << std::endl;
                return false;
            }
            put(get(vertex_name, g), v, ival);
            vmap[vertex_id] = v;
        }
        break;
        case 'e': {
            if (container.empty()) {
                std::cerr << "invalid format: 't' tag missed" << std::endl;
                return false;
            }
            InputGraph& g = container.back();
            std::size_t src_id;
            if (!(ss >> src_id) || vmap.find(src_id) == vmap.end()) {
                std::cerr << "invalid or missed <vertex_id_1>, at line " << line_no
                          << std::endl;
                return false;
            }
            std::size_t dst_id;
            if (!(ss >> dst_id) || vmap.find(dst_id) == vmap.end()) {
                std::cerr << "invalid or missed <vertex_id_2>, at line " << line_no
                          << std::endl;
                return false;
            }

            InputGraphVertex u = vmap[src_id];
            InputGraphVertex v = vmap[dst_id];
            InputGraphEdge e = add_edge(u, v, g).first;
            put(get(edge_index, g), e, num_edges(g) - 1);

            std::size_t ival;
            if (!(ss >> ival)) {
                std::cerr << "invalid or missed edge value (integer), at line " << line_no
                          << std::endl;
                return false;
            }
            put(get(edge_name, g), e, ival);
        }
        break;
        default:
            std::cerr << "invalid or missed <tag>, at line " << line_no << std::endl;
            return false;
        }
    }

    return true;
}

struct input_statistics {
    std::size_t graph_count;
    struct {
        std::size_t avg;
        std::size_t min;
        std::size_t max;
    } v, e;
};

void calculate_statistics(const std::list<InputGraph>& container,
                          input_statistics* stat)
{
    stat->graph_count = 0;
    stat->v.avg = 0;
    stat->v.min = 0;
    stat->v.max = 0;
    stat->e.avg = 0;
    stat->e.min = 0;
    stat->e.max = 0;
    if (container.empty()) {
        return;
    }
    stat->v.max = stat->v.min = num_vertices(container.front());
    stat->e.max = stat->e.min = num_edges(container.front());
    for (const InputGraph& g : container) {
        ++stat->graph_count;
        std::size_t vn = num_vertices(g);
        std::size_t en = num_edges(g);
        stat->v.avg += vn;
        stat->e.avg += en;
        if (stat->v.min > vn) {
            stat->v.min = vn;
        }
        if (stat->v.max < vn) {
            stat->v.max = vn;
        }
        if (stat->e.min > en) {
            stat->e.min = en;
        }
        if (stat->e.max < en) {
            stat->e.max = en;
        }
    }
    stat->v.avg /= stat->graph_count;
    stat->e.avg /= stat->graph_count;
}

int
main(int argc, char** argv)
{
    std::size_t mincount = 0;
    bool minsupp_exist = true;
    double minsupp = 1.0;

    for (int i = 1; i < argc; ++i) {
        std::string opt(argv[i]);
        if (opt == "--help" || opt == "-h") {
            print_usage(std::cout);
            return 0;
        }
        else if (opt == "--input" || opt == "-i") {
            if (++i >= argc || input_fstream.is_open())
                error_usage();
            input_fstream.open(argv[i]);
            input_stream = &input_fstream;
            continue;
        }
        else if (opt == "--output" || opt == "-o") {
            if (++i >= argc || output_fstream.is_open())
                error_usage();
            std::string file(argv[i]);
            if (file != "/dev/null") {
                output_fstream.open(file);
                output_stream = &output_fstream;
            }
            else {
                no_output = true;
            }
            continue;
        }
        else if (opt == "--mincount" || opt == "-c") {
            if (++i >= argc)
                error_usage();
            if (! (std::stringstream(argv[i]) >> mincount)) {
                error_usage();
            }
            continue;
        }
        else if (opt == "--minsupp" || opt == "-s") {
            if (++i >= argc)
                error_usage();
            if (! (std::stringstream(argv[i]) >> minsupp)) {
                error_usage();
            }
            minsupp_exist = true;
            continue;
        }
        else if (opt == "--legacy" || opt == "-l") {
            use_legacy = true;
        }
        else if (opt == "--embeddings" || opt == "-e") {
            if (++i >= argc)
                error_usage();
            std::string param(argv[i]);
            if (param == "all")
                output_mappings = OUTPUT_MAPPING_ALL;
            else if (param == "autgrp")
                output_mappings = OUTPUT_MAPPING_ONE_AUTOMORPH;
            else if (param == "none")
                output_mappings = OUTPUT_MAPPING_NONE;
            else
                error_usage();
            continue;
        }
        else {
            error_usage();
        }
    }

    std::list<InputGraph> input_graphs;

    if (!(use_legacy ? read_tgf : read_egf)(input_graphs, *input_stream))
        return 1;

    input_statistics stat;
    calculate_statistics(input_graphs, &stat);

    if (minsupp_exist) {
        mincount = stat.graph_count * minsupp;
    }

    std::cerr << std::endl;
    std::cerr << "# input data statistics:\n"
              << "# graph count          = " << stat.graph_count << std::endl
              << "# vertices avg,min,max = "
              << stat.v.avg << ", " << stat.v.min << ", " << stat.v.max << std::endl
              << "# edges avg,min,max    = "
              << stat.e.avg << ", " << stat.e.min << ", " << stat.e.max << std::endl
              << "# min_count            = " << mincount << std::endl << std::endl;

    if (input_graphs.size() == 1)
        gspan_one_graph(input_graphs.back(),
                        mincount,
                        use_legacy ? write_tgf : write_egf,
                        vertex_name,
                        edge_name);
    else
        gspan_many_graphs(input_graphs.begin(),
                          input_graphs.end(),
                          mincount,
                          use_legacy ? write_tgf : write_egf,
                          vertex_name,
                          edge_name);

    std::cerr << std::endl;
    std::cerr << "# mined " << pattern_no << " patterns" << std::endl;
}


#include "modeling.hpp"
#include "utils/logging.hpp"
#include <boost/format.hpp>
#include <boost/foreach.hpp>
#include <cstdio>
#include "expr_ops.hpp"
#include "sco_common.hpp"
#include "macros.h"
#include <iostream>
#include <sstream>

using namespace std;

namespace sco {

void ConvexObjective::addAffExpr(const AffExpr& affexpr) {
  exprInc(quad_, affexpr);
}
void ConvexObjective::addQuadExpr(const QuadExpr& quadexpr) {
  exprInc(quad_, quadexpr);
}
void ConvexObjective::addHinge(const AffExpr& affexpr, double coeff) {
  Var hinge = model_->addVar("hinge", 0, INFINITY);
  vars_.push_back(hinge);
  ineqs_.push_back(affexpr);
  exprDec(ineqs_.back(), hinge);
  AffExpr hinge_cost = exprMult(AffExpr(hinge), coeff);
  exprInc(quad_, hinge_cost);
}
void ConvexObjective::addAbs(const AffExpr& affexpr, double coeff) {
  Var neg = model_->addVar("neg", 0, INFINITY);
  Var pos = model_->addVar("pos", 0, INFINITY);
  vars_.push_back(neg);
  vars_.push_back(pos);
  AffExpr neg_plus_pos;
  neg_plus_pos.coeffs = vector<double>(2, coeff);
  neg_plus_pos.vars.push_back(neg);
  neg_plus_pos.vars.push_back(pos);
  exprInc(quad_, neg_plus_pos);
  AffExpr affeq = affexpr;
  affeq.vars.push_back(neg);
  affeq.vars.push_back(pos);
  affeq.coeffs.push_back(1);
  affeq.coeffs.push_back(-1);
  eqs_.push_back(affeq);
}
void ConvexObjective::addHinges(const AffExprVector& ev) {
  for (size_t i=0; i < ev.size(); ++i) addHinge(ev[i],1);
}
void ConvexObjective::addL1Norm(const AffExprVector& ev) {
  for (size_t i=0; i < ev.size(); ++i) addAbs(ev[i],1);
}
void ConvexObjective::addL2Norm(const AffExprVector& ev) {
  for (size_t i=0; i < ev.size(); ++i) exprInc(quad_, exprSquare(ev[i]));
}
void ConvexObjective::addMax(const AffExprVector& ev) {
  Var m = model_->addVar("max", -INFINITY, INFINITY);
  for (size_t i=0; i < ev.size(); ++i) {
    ineqs_.push_back(ev[i]);
    exprDec(ineqs_.back(), m);
  }
}

void ConvexObjective::addConstraintsToModel() {
  cnts_.reserve(eqs_.size() + ineqs_.size());
  BOOST_FOREACH(const AffExpr& aff, eqs_) {
    cnts_.push_back(model_->addEqCnt(aff, ""));
  }
  BOOST_FOREACH(const AffExpr& aff, ineqs_) {
    cnts_.push_back(model_->addIneqCnt(aff, ""));
  }
}

void ConvexObjective::removeFromModel() {
  model_->removeCnts(cnts_);
  model_->removeVars(vars_);
  model_ = NULL;
}
ConvexObjective::~ConvexObjective() {
  if (inModel()) removeFromModel();
}

void ConvexConstraints::addEqCnt(const AffExpr& aff) {
  eqs_.push_back(aff);
}

void ConvexConstraints::addIneqCnt(const AffExpr& aff) {
  ineqs_.push_back(aff);
}

void ConvexConstraints::addConstraintsToModel() {
  cnts_.reserve(eqs_.size() + ineqs_.size());
  BOOST_FOREACH(const AffExpr& aff, eqs_) {
    cnts_.push_back(model_->addEqCnt(aff, ""));
  }
  BOOST_FOREACH(const AffExpr& aff, ineqs_) {
    cnts_.push_back(model_->addIneqCnt(aff, ""));
  }
}

void ConvexConstraints::removeFromModel() {
  model_->removeCnts(cnts_);
  model_ = NULL;
}

vector<double> ConvexConstraints::violations(const vector<double>& x) {
  DblVec out;
  out.reserve(eqs_.size() + ineqs_.size());
  BOOST_FOREACH(const AffExpr& aff, eqs_) out.push_back(fabs(aff.value(x.data())));
  BOOST_FOREACH(const AffExpr& aff, ineqs_) out.push_back(pospart(aff.value(x.data())));
  return out;
}
double ConvexConstraints::violation(const vector<double>& x) {
  return vecSum(violations(x));
}

ConvexConstraints::~ConvexConstraints() {
  if (inModel()) removeFromModel();
}

double ConvexObjective::value(const vector<double>& x)  {
  return quad_.value(x);
}

vector<double> Constraint::violations(const DblVec& x) {
  DblVec val = value(x);
  DblVec out(val.size());

  if (type() == EQ) {
    for (size_t i=0; i < val.size(); ++i) out[i] = fabs(val[i]);
  }
  else { // type() == INEQ
    for (size_t i=0; i < val.size(); ++i) out[i] = pospart(val[i]);
  }

  return out;
}

double Constraint::violation(const DblVec& x) {
  return vecSum(violations(x));
}

OptProb::OptProb() : model_(createModel()) {}

VarVector OptProb::createVariables(const vector<string>& var_names) {
  return createVariables(var_names, DblVec(var_names.size(), -INFINITY), DblVec(var_names.size(), INFINITY));
}
VarVector OptProb::createVariables(const vector<string>& var_names, const DblVec& lb, const DblVec& ub) {
  size_t n_add = var_names.size(), n_cur = vars_.size();
  assert(lb.size() == n_add);
  assert(ub.size() == n_add);
  vars_.reserve(n_cur + n_add);
  lower_bounds_.reserve(n_cur + n_add);
  upper_bounds_.reserve(n_cur + n_add);
  for (size_t i=0; i < var_names.size(); ++i) {
    vars_.push_back(model_->addVar(var_names[i], lb[i], ub[i]));
    lower_bounds_.push_back(lb[i]);
    upper_bounds_.push_back(ub[i]);
  }
  model_->update();
  return VarVector(vars_.end()-n_add, vars_.end());
}
void OptProb::setLowerBounds(const vector<double>& lb) {
  assert(lb.size() == vars_.size());
  lower_bounds_ = lb;
}
void OptProb::setUpperBounds(const vector<double>& ub) {
  assert(ub.size() == vars_.size());
  upper_bounds_ = ub;
}
void OptProb::setLowerBounds(const vector<double>& lb, const vector<Var>& vars) {
  setVec(lower_bounds_, vars, lb);
}
void OptProb::setUpperBounds(const vector<double>& ub, const vector<Var>& vars) {
  setVec(upper_bounds_, vars, ub);
}

void OptProb::addCost(CostPtr cost) {
  costs_.push_back(cost);
}
void OptProb::addConstraint(ConstraintPtr cnt) {
  if (cnt->type() == EQ) addEqConstraint(cnt);
  else addIneqConstraint(cnt);
}
void OptProb::addEqConstraint(ConstraintPtr cnt) {
  assert (cnt->type() == EQ);
  eqcnts_.push_back(cnt);
}
void OptProb::addIneqConstraint(ConstraintPtr cnt) {
  assert (cnt->type() == INEQ);
  ineqcnts_.push_back(cnt);
}
vector<ConstraintPtr> OptProb::getConstraints() const {
  vector<ConstraintPtr> out;
  out.reserve(eqcnts_.size() + ineqcnts_.size());
  out.insert(out.end(), eqcnts_.begin(), eqcnts_.end());
  out.insert(out.end(), ineqcnts_.begin(), ineqcnts_.end());
  return out;
}
void OptProb::addLinearConstraint(const AffExpr& expr, ConstraintType type) {
  if (type == EQ) model_->addEqCnt(expr, "");
  else model_->addIneqCnt(expr, "");
}

vector<double> OptProb::getCentralFeasiblePoint(const vector<double>& x) {
  assert(x.size() == lower_bounds_.size());
  DblVec center(x.size());
  for (int i=0; i < x.size(); ++i) center[i] = (lower_bounds_[i] + upper_bounds_[i])/2;
  return getClosestFeasiblePoint(center);
}
vector<double> OptProb::getClosestFeasiblePoint(const vector<double>& x) {
  LOG_DEBUG("getClosestFeasiblePoint");
  assert(vars_.size() == x.size());
  QuadExpr obj;
  printf(" ---Inside modelling.cpp---");
  for (int i = 0; i < x.size(); i++){
      printf("\nX[%d] = %f",i,x[i]);
  }

  for (int i=0; i < x.size(); ++i) {
    exprInc(obj, exprSquare(exprSub(AffExpr(vars_[i]),x[i])));
  }
  model_->setVarBounds(vars_, lower_bounds_, upper_bounds_);
  model_->setObjective(obj);
  CvxOptStatus status = model_->optimize();
  if(status != CVX_SOLVED) {
    model_->writeToFile("/tmp/fail.lp");
    PRINT_AND_THROW("couldn't find a feasible point. there's probably a problem with variable bounds (e.g. joint limits). wrote to /tmp/fail.lp");
  }
  return model_->getVarValues(vars_);
}

}


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

//#ifdef HAS_CGAL

#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <algorithm>
#include <cassert>

#include "PolyhedronUtils.h"
//#include <dolfin/common/constants.h>
//#include <dolfin/geometry/Point.h>
//#include <dolfin/log/log.h>
//#include <dolfin/log/LogStream.h>

#include <CGAL/Cartesian_d.h>
#include <CGAL/Polyhedron_incremental_builder_3.h>
#include <CGAL/Min_sphere_of_spheres_d.h>
#include <CGAL/Min_sphere_of_spheres_d_traits_3.h>

//#define BOOST_FILESYSTEM_NO_DEPRECATED
//#include <boost/filesystem.hpp>
//#include <boost/tuple/tuple.hpp>
//#include <boost/tuple/tuple_comparison.hpp>
//#include <boost/tokenizer.hpp>
//#include <boost/algorithm/string.hpp>

namespace polyhcsg
{

//static inline double strToDouble(const std::string& s, bool print=false)
//{
//  std::istringstream is(s);
//  double val;
//  is >> val;
//
//  if (print)
//    std::cout << "to_double " << s << " : " << val << std::endl;
//
//  return val;
//}
//
//dolfin::LogStream& operator << (dolfin::LogStream& stream,
//                                const boost::tuple<double,
//                                double, double>& obj)
//{
//  stream << obj.get<0>() << " " << obj.get<1>() << " " << obj.get<2>();
//  return stream;
//}
//
//template <class HDS>
//class BuildFromSTL : public CGAL::Modifier_base<HDS>
//{
//public:
//  BuildFromSTL(std::string filename) : _filename(filename){}
//  void operator()(HDS& hds)
//  {
//    std::cout << "Reading surface from " << _filename << std::endl;
//
//    CGAL::Polyhedron_incremental_builder_3<HDS> builder( hds, true);
//    builder.begin_surface(100000, 100000);
//
//    typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
//
//    std::ifstream file(_filename.c_str());
//    if (!file.is_open())
//    {
//      dolfin_error("PolyhedronUtils.cpp",
//                   "open .stl file to read 3D surface",
//                   "Failed to open file");
//    }
//
//    std::size_t num_vertices = 0;
//    std::map<boost::tuple<double, double, double>, std::size_t> vertex_map;
//    std::vector<std::vector<std::size_t> > facets;
//    std::string line;
//    const boost::char_separator<char> sep(" ");
//
//    // Read the first line and trim away whitespaces
//    std::getline(file, line);
//    boost::algorithm::trim(line);
//
//    if (line.substr(0, 5) != "solid")
//    {
//      dolfin_error("PolyhedronUtils.cpp",
//                   "open .stl file to read 3D surface",
//                   "File does not start with \"solid\"");
//    }
//
//    // TODO: Read name of solid
//
//    std::getline(file, line);
//    boost::algorithm::trim(line);
//
//    while (file.good())
//    {
//      //bool has_normal = false;
//      //Point normal;
//
//      // Read the line "facet normal n1 n2 n3"
//      {
//        tokenizer tokens(line, sep);
//        tokenizer::iterator tok_iter = tokens.begin();
//
//        if (*tok_iter != "facet")
//          dolfin_error("PolyhedronUtils.cpp",
//                       "open .stl file to read 3D surface",
//                       "Expected keyword \"facet\"");
//        ++tok_iter;
//
//        // Check if a normal different from zero is given
//        if (tok_iter != tokens.end())
//        {
//          //std::cout << "Expecting normal" << std::endl;
//
//          if  (*tok_iter != "normal")
//            dolfin_error("PolyhedronUtils.cpp",
//                         "open .stl file to read 3D surface",
//                         "Expected keyword \"normal\"");
//          ++tok_iter;
//
//          //std::cout << "Read line: " << line << std::endl;
//
//          // for (std::size_t i = 0; i < 3; ++i)
//          // {
//          //   normal[i] = strToDouble(*tok_iter);
//          //   ++tok_iter;
//          // }
//
//
//          //std::cout << "Normal: " << normal << std::endl;
//          // if (normal.norm() > DOLFIN_EPS)
//          //   has_normal = true;
//
//          // if (tok_iter != tokens.end())
//          //   dolfin_error("PolyhedronUtils.cpp",
//          //                "open .stl file to read 3D surface",
//          //                "Expected end of line");
//        }
//      }
//
//      // Read "outer loop" line
//      std::getline(file, line);
//      boost::algorithm::trim(line);
//
//      if (line != "outer loop")
//        dolfin_error("PolyhedronUtils.cpp",
//                     "open .stl file to read 3D surface",
//                     "Expected key word outer loop");
//
//      std::vector<std::size_t> v_indices(3);
//
//      // Read lines with vertices
//      for (std::size_t i = 0; i < 3; ++i)
//      {
//        std::getline(file, line);
//        boost::algorithm::trim(line);
//
//        //std::cout << "read line: " << line << std::endl;
//
//        tokenizer tokens(line, sep);
//        tokenizer::iterator tok_iter = tokens.begin();
//
//        if (*tok_iter != "vertex")
//        {
//          dolfin_error("PolyhedronUtils.cpp",
//                       "open .stl file to read 3D surface",
//                       "Expected key word vertex");
//        }
//        ++tok_iter;
//
//        const double x = strToDouble(*tok_iter); ++tok_iter;
//        const double y = strToDouble(*tok_iter); ++tok_iter;
//        const double z = strToDouble(*tok_iter); ++tok_iter;
//
//        boost::tuple<double, double, double> v(x, y, z);
//
//        if (vertex_map.count(v) > 0)
//          v_indices[i] = vertex_map[v];
//        else
//        {
//          vertex_map[v] = num_vertices;
//          v_indices[i] = num_vertices;
//          builder.add_vertex(csg::Exact_Point_3(x, y, z));
//          num_vertices++;
//        }
//      }
//
//      // TODO
//      // if (has_normal)
//      // {
//      //   std::cout << "Has normal" << std::endl;
//      // }
//
//      builder.add_facet(v_indices.begin(), v_indices.end());
//
//      // Read 'endloop' line
//      std::getline(file, line);
//      boost::algorithm::trim(line);
//      if (line != "endloop")
//      {
//        dolfin_error("PolyhedronUtils.cpp",
//                     "open .stl file to read 3D surface",
//                     "Expected key word endloop");
//      }
//
//      std::getline(file, line);
//      boost::algorithm::trim(line);
//      if (line != "endfacet")
//      {
//        dolfin_error("PolyhedronUtils.cpp",
//                     "open .stl file to read 3D surface",
//                     "Expected key word endfacet");
//      }
//
//      std::getline(file, line);
//      boost::algorithm::trim(line);
//
//      if (line.substr(0, 5) != "facet")
//        break;
//    }
//
//    // Read the 'endsolid' line
//    tokenizer tokens(line, sep);
//    tokenizer::iterator tok_iter = tokens.begin();
//
//    if (*tok_iter != "endsolid")
//    {
//      dolfin_error("PolyhedronUtils.cpp",
//                   "open .stl file to read 3D surface",
//                   "Expected key word endsolid");
//    }
//    ++tok_iter;
//
//    builder.end_surface();
//
//    // TODO: Check name of solid
//
//    std::cout << "Done reading surface" << std::endl;
//  }
//    const std::string _filename;
//};
////-----------------------------------------------------------------------------
//void PolyhedronUtils::readSurfaceFile(std::string filename,
//                                      csg::Exact_Polyhedron_3& p)
//{
//  boost::filesystem::path fpath(filename);
//  if (fpath.extension() == ".stl")
//  {
//    readSTLFile(filename, p);
//  }
//  else if(fpath.extension() == ".off")
//  {
//    // TODO: Let cgal parse the file
//  }
//  else
//  {
//    dolfin_error("PolyhedronUtils.cpp",
//                 "open file to read 3D surface",
//                 "Unknown file type");
//  }
//}
////-----------------------------------------------------------------------------
//void PolyhedronUtils::readSTLFile(std::string filename,
//                                  csg::Exact_Polyhedron_3& p)
//{
//  BuildFromSTL<csg::Exact_HalfedgeDS> stl_builder(filename);
//  p.delegate(stl_builder);
//}
////-----------------------------------------------------------------------------
//CGAL::Bbox_3 PolyhedronUtils::getBoundingBox(csg::Polyhedron_3& polyhedron)
//{
//  csg::Polyhedron_3::Vertex_iterator it = polyhedron.vertices_begin();
//
//  // Initialize bounding box with the first point
//  csg::Polyhedron_3::Point_3 p0 = it->point();
//  CGAL::Bbox_3 b(p0[0], p0[1], p0[2], p0[0], p0[1], p0[2]);
//  ++it;
//
//  for (; it != polyhedron.vertices_end(); ++it)
//  {
//    csg::Polyhedron_3::Point_3 p1 = it->point();
//    b = b + CGAL::Bbox_3(p1[0], p1[1], p1[2], p1[0], p1[1], p1[2]);
//  }
//
//  return b;
//}
//-----------------------------------------------------------------------------
//double PolyhedronUtils::getBoundingSphereRadius(csg::Polyhedron_3& polyhedron)
//{
//  typedef double FT;
//  typedef CGAL::Cartesian_d<FT> K;
//  typedef CGAL::Min_sphere_of_spheres_d_traits_d<K, FT, 3> MinSphereTraits;
//  typedef CGAL::Min_sphere_of_spheres_d<MinSphereTraits> Min_sphere;
//  typedef MinSphereTraits::Sphere Sphere;
//  typedef K::Point_d Point_d;
//
//  std::vector<Sphere> S;
//  FT coord[3];
//
//  for (csg::Polyhedron_3::Vertex_iterator it=polyhedron.vertices_begin();
//       it != polyhedron.vertices_end(); ++it)
//  {
//    coord[0] = it->point().x();
//    coord[1] = it->point().y();
//    coord[2] = it->point().z();
//    Point_d p(3, coord,coord+3);
//    S.push_back(Sphere(p, 0.0));
//  }
//
//  Min_sphere ms(S.begin(), S.end());
//  CGAL_assertion(ms.is_valid());
//
//  return CGAL::to_double(ms.radius());
//}
//-----------------------------------------------------------------------------
template<typename Polyhedron>
static inline double
get_edge_length(typename Polyhedron::Halfedge::Halfedge_handle halfedge)
{
  return CGAL::to_double((halfedge->vertex()->point() -
    halfedge->opposite()->vertex()->point()).squared_length());
}
//-----------------------------------------------------------------------------
template <typename Polyhedron>
static inline double get_triangle_area(typename Polyhedron::Facet_handle facet)
{
  const typename Polyhedron::Halfedge_handle edge = facet->halfedge();
  const typename Polyhedron::Point_3 a = edge->vertex()->point();
  const typename Polyhedron::Point_3 b = edge->next()->vertex()->point();
  const typename Polyhedron::Point_3 c
    = edge->next()->next()->vertex()->point();
  return CGAL::to_double(CGAL::cross_product(b-a, c-a).squared_length());
}
//-----------------------------------------------------------------------------
template<typename Polyhedron>
static inline double
get_min_edge_length(typename Polyhedron::Facet_handle facet)
{
  typename Polyhedron::Facet::Halfedge_around_facet_circulator half_edge
    = facet->facet_begin();
  double min_length = CGAL::to_double((half_edge->vertex()->point()
      - half_edge->opposite()->vertex()->point()).squared_length());

  half_edge++;
  min_length = std::min(min_length, get_edge_length<Polyhedron>(half_edge));

  half_edge++;
  min_length = std::min(min_length, get_edge_length<Polyhedron>(half_edge));

  return min_length;
}
//-----------------------------------------------------------------------------
template<typename Polyhedron>
bool facet_is_degenerate(typename Polyhedron::Facet_handle facet,
                         const double threshold)
{
  return get_min_edge_length<Polyhedron>(facet) < threshold
      || get_triangle_area<Polyhedron>(facet) < threshold;
}
//-----------------------------------------------------------------------------
template<typename Polyhedron>
static int number_of_degenerate_facets(Polyhedron& p, const double threshold)
{
  int count = 0;
  for (typename Polyhedron::Facet_iterator facet = p.facets_begin();
       facet != p.facets_end(); facet++)
  {
    assert(facet->is_triangle());
    if ( facet_is_degenerate<Polyhedron>(facet, threshold) )
      count++;
  }
  return count;
}
//-----------------------------------------------------------------------------
template <typename Polyhedron>
static typename Polyhedron::Halfedge_handle
get_longest_edge(typename Polyhedron::Facet_handle facet)
{
  typename Polyhedron::Halfedge_handle edge = facet->halfedge();
  double length = get_edge_length<Polyhedron>(edge);

  {
    typename Polyhedron::Halfedge_handle e_tmp = edge->next();
    if (get_edge_length<Polyhedron>(e_tmp) > length)
    {
      length = get_edge_length<Polyhedron>(e_tmp);
      edge = e_tmp;
    }
  }

  {
    typename Polyhedron::Halfedge_handle e_tmp = edge->next()->next();
    if ( get_edge_length<Polyhedron>(e_tmp) > length )
    {
      length = get_edge_length<Polyhedron>(e_tmp);
      edge = e_tmp;
    }
  }

  return edge;
}
//-----------------------------------------------------------------------------
template <typename Polyhedron>
double shortest_edge(Polyhedron& p)
{
  double shortest = std::numeric_limits<double>::max();
  for (typename Polyhedron::Halfedge_iterator halfedge = p.halfedges_begin();
       halfedge != p.halfedges_end(); halfedge++)
  {
    const double length = get_edge_length<Polyhedron>(halfedge);
    shortest = std::min(shortest, length);
  }

  return shortest;
}
//-----------------------------------------------------------------------------
template <typename Polyhedron>
static void remove_edge(Polyhedron& p, typename
                        Polyhedron::Halfedge_handle& edge)
{

  // // FIXME: Is it possible to do this in a smarter way than a linear scan
  // for (csg::Polyhedron_3::Facet_iterator facet = p.facets_begin();
  //      facet != p.facets_end(); facet++)
  // {
  //   if ( facet_is_degenerate<csg::Polyhedron_3>(facet, threshold) )
  //   {
  //     //print_facet(facet);

  //     // Find a short edge
  //     csg::Polyhedron_3::Halfedge::Halfedge_handle shortest_edge = facet->facet_begin();
  //     csg::Polyhedron_3::Facet::Halfedge_around_facet_circulator current_edge = facet->facet_begin();
  //     double min_length = get_edge_length(current_edge);

  //     for (int i = 0; i < 2; i++)
  //     {
  //     current_edge++;
  //     if (get_edge_length(current_edge) < min_length)
  //     {
  //       shortest_edge = current_edge;
  //       min_length = get_edge_length(current_edge);
  //     }
  //     }

  // Join small triangles with neighbor facets
  edge = p.join_facet(edge->next());
  p.join_facet(edge->opposite()->prev());

  // The joined facets are now quads
  // Join the two close vertices
  p.join_vertex(edge);
}
//-----------------------------------------------------------------------------
template <typename Polyhedron>
static void remove_short_edges(Polyhedron& p, const double threshold)
{
  while (true)
  {
    bool removed = false;
    for (typename Polyhedron::Halfedge_iterator halfedge = p.halfedges_begin();
     halfedge != p.halfedges_end(); halfedge++)
    {
      if (get_edge_length<Polyhedron>(halfedge) < threshold)
      {
    remove_edge<Polyhedron>(p, halfedge);
    removed = true;
    break;
      }
    }

    if (!removed)
      break;
  }
}
//-----------------------------------------------------------------------------
template <typename Polyhedron>
static typename Polyhedron::Point_3
facet_midpoint(typename Polyhedron::Facet_handle facet)
{
  typename Polyhedron::Point_3 p(CGAL::ORIGIN);

  typename Polyhedron::Facet::Halfedge_around_facet_circulator half_edge
    = facet->facet_begin();

  for (std::size_t i = 0; i < facet->facet_degree(); i++)
  {
    p = p + (half_edge->vertex()->point() - CGAL::ORIGIN);
    half_edge++;
  }

  p = CGAL::ORIGIN
    + (p - CGAL::ORIGIN)/static_cast<double>(facet->facet_degree());

  // std::std::cout << "Center coordinates computed: " << p << std::endl;

  // half_edge = facet->facet_begin();
  // for (std::size_t i = 0; i < facet->facet_degree(); i++)
  // {
  //   std::std::cout << "Distance to point << " << half_edge->vertex()->point() << " = " << (half_edge->vertex()->point() - p).squared_length() << std::endl;
  //   half_edge++;
  // }

  return p;
}
//-----------------------------------------------------------------------------
template <typename Polyhedron>
static void
remove_triangle(Polyhedron& p, typename Polyhedron::Facet_handle facet)
{
  assert(facet->is_triangle());

  // std::cout << "Removing triangle" << endl;
  // print_facet<Polyhedron>(facet);

  // Find the longest edge
  typename Polyhedron::Halfedge_handle edge = get_longest_edge<Polyhedron>(facet);

  // std::cout << "Longest edge" << std::endl;
  // print_halfedge<Polyhedron>(edge);

  // std::cout << "Opposite triangle" << std::endl;
  // print_facet<Polyhedron>(edge->opposite()->facet());

  edge = p.join_facet(edge);
  // std::cout << "Edge after join: " << std::endl;
  // print_halfedge<Polyhedron>(edge);

  // std::cout << "Facet after join" << std::endl;
  // print_facet<Polyhedron>(edge->facet());

  typename Polyhedron::Point_3 new_center = facet_midpoint<Polyhedron>(edge->facet());

  edge = p.create_center_vertex(edge);

  edge->vertex()->point() = new_center;

  // std::std::cout << "Center vertex: " << edge->vertex()->point() << std::endl;

  // for (std::size_t i=0; i < 4; i++)
  // {
  //   print_facet<Polyhedron>(edge->facet());
  //   edge = edge->next()->opposite();
  // }
}
//-----------------------------------------------------------------------------
template<typename Polyhedron>
void remove_small_triangles(Polyhedron& p, const double threshold)
{
  int n = number_of_degenerate_facets(p, threshold);

  while ((n > 0) && (p.size_of_facets() > 0))
  {
    for ( typename Polyhedron::Facet_iterator facet = p.facets_begin();
            facet != p.facets_end();
            facet++ )
    {
      assert(facet->is_triangle());

      std::cout << "Number of facets: " << p.size_of_facets() << std::endl;

      if (get_triangle_area<Polyhedron>(facet) < threshold)
      {
        std::cout << "Small triangle detected" << std::endl;
        //print_facet<Polyhedron>(facet);
        remove_triangle<Polyhedron>(p, facet);
        std::cout << "Number of facets: " << p.size_of_facets() << std::endl;
        remove_short_edges(p, threshold);
        std::cout << "Number of facets: " << p.size_of_facets() << std::endl;
        n = number_of_degenerate_facets<Polyhedron>(p, threshold);
        break;
      }
    }
  }
}
//-----------------------------------------------------------------------------
void remove_degenerate_facets(Polyhedron& p, const double threshold)
{
  int degenerate_facets = number_of_degenerate_facets(p, threshold);

  //std::cout << "Number of degenerate facets: " << degenerate_facets << std::endl;
  // FIXME: Use has_degenerate_facets() when debugging is done
  if (degenerate_facets > 0)
  {
    assert(p.is_pure_triangle());

    shortest_edge(p);

    //std::cout << "Removing triangles with short edges" << std::endl;
    remove_short_edges(p, threshold);

    //std::cout << "Number of degenerate facets: "
         << number_of_degenerate_facets(p, threshold) << std::endl;

    //std::cout << "Removing small triangles" << std::endl;
    //remove_small_triangles(p, threshold);

    //std::cout << "Number of degenerate facets: "
    //     << number_of_degenerate_facets(p, threshold) << std::endl;

    // Removal of triangles should preserve the triangular structure
    // of the polyhedron
    assert(p.is_pure_triangle());
  }
}
//-----------------------------------------------------------------------------
bool has_degenerate_facets(Polyhedron& p, double threshold)
{
  for (Polyhedron::Facet_iterator facet = p.facets_begin();
       facet != p.facets_end(); facet++)
  {
    assert(facet->is_triangle());
    if (facet_is_degenerate<Polyhedron>(facet, threshold))
      return true;
  }
  return false;
}

} // namespace polyhcsg