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

#pragma once

#include <boost/optional.hpp>
#include <crab/common/types.hpp>
#include <crab/common/stats.hpp>
#include <crab/common/bignums.hpp>
#include <crab/domains/linear_constraints.hpp>
#include <crab/domains/linear_interval_solver.hpp>
#include <crab/domains/separate_domains.hpp>
#include <crab/domains/operators_api.hpp>
#include <crab/domains/backward_assign_operations.hpp>

namespace ikos {

  template< typename Number >
  class bound;

  template< typename Number >
  class bound: public writeable {

    template < typename Any > friend class bound;

  public:
    typedef bound< Number > bound_t;

  private:
    bool _is_infinite;
    Number _n;

  private:
    bound();

    bound(bool is_infinite, Number n): _is_infinite(is_infinite), _n(n) {
      if (is_infinite){
        if (n > 0)
          this->_n = 1;
        else
          this->_n = -1;
      }
    }

  public:
    static bound_t min(bound_t x, bound_t y) {
      return (x.operator<=(y) ? x : y);
    }

    static bound_t min(bound_t x, bound_t y, bound_t z) {
      return min(x, min(y, z));
    }

    static bound_t min(bound_t x, bound_t y, bound_t z, bound_t t) {
      return min(x, min(y, z, t));
    }

    static bound_t max(bound_t x, bound_t y) {
      return (x.operator<=(y) ? y : x);
    }

    static bound_t max(bound_t x, bound_t y, bound_t z) {
      return max(x, max(y, z));
    }

    static bound_t max(bound_t x, bound_t y, bound_t z, bound_t t) {
      return max(x, max(y, z, t));
    }

    static bound_t plus_infinity() {
      return bound_t(true, 1);
    }

    static bound_t minus_infinity() {
      return bound_t(true, -1);
    }

  public:
    bound(int n): _is_infinite(false), _n(n) { }

    bound(std::string s): _n(1) {
      if (s == "+oo") {
        this->_is_infinite = true;
      } else if (s == "-oo") {
        this->_is_infinite = true;
        this->_n = -1;
      } else {
        this->_is_infinite = false;
        this->_n = Number(s);
      }
    }

    bound(Number n): _is_infinite(false), _n(n) { }

    bound(const bound_t& o): writeable(), _is_infinite(o._is_infinite), _n(o._n) { }

    bound_t& operator=(const bound_t &o){
      if (this != &o) {
        this->_is_infinite = o._is_infinite;
        this->_n = o._n;
      }
      return *this;
    }

    bool is_infinite() const {
      return this->_is_infinite;
    }

    bool is_finite() const {
      return !this->_is_infinite;
    }

    bool is_plus_infinity() const {
      return (this->is_infinite() && this->_n > 0);
    }

    bool is_minus_infinity() const {
      return (this->is_infinite() && this->_n < 0);
    }

    bound_t operator-() const {
      return bound_t(this->_is_infinite, -this->_n);
    }

    bound_t operator+(bound_t x) const {
      if (this->is_finite() && x.is_finite()) {
        return bound_t(this->_n + x._n);
      } else if (this->is_finite() && x.is_infinite()) {
        return x;
      } else if (this->is_infinite() && x.is_finite()) {
        return *this;
      } else if (this->_n == x._n) {
        return *this;
      } else {
        CRAB_ERROR("Bound: undefined operation -oo + +oo");
      }
    }

    bound_t& operator+=(bound_t x)  {
      return this->operator=(this->operator+(x));
    }

    bound_t operator-(bound_t x) const {
      return this->operator+(x.operator-());
    }

    bound_t& operator-=(bound_t x)  {
      return this->operator=(this->operator-(x));
    }

    bound_t operator*(bound_t x) const {
      if (x._n == 0)
        return x;
      else if (this->_n == 0)
        return *this;
      else
        return bound_t(this->_is_infinite || x._is_infinite, this->_n * x._n);
    }

    bound_t& operator*=(bound_t x)  {
      return this->operator=(this->operator*(x));
    }

    bound_t operator/(bound_t x) const {
      if (x._n == 0) {
        CRAB_ERROR("Bound: division by zero");
      } else if (this->is_finite() && x.is_finite()) {
        return bound_t(false, _n / x._n);
      } else if (this->is_finite() && x.is_infinite()) {
        if (this->_n > 0) {
          return x;
        } else if (this->_n == 0) {
          return *this;
        } else {
          return x.operator-();
        }
      } else if (this->is_infinite() && x.is_finite()) {
        if (x._n > 0) {
          return *this;
        } else {
          return this->operator-();
        }
      } else {
        return bound_t(true, this->_n * x._n);
      }
    }

    bound_t& operator/=(bound_t x) {
      return this->operator=(this->operator/(x));
    }

    bool operator<(bound_t x) const {
      return !this->operator>=(x);
    }

    bool operator>(bound_t x) const {
      return !this->operator<=(x);
    }

    bool operator==(bound_t x) const {
      return (this->_is_infinite == x._is_infinite && this->_n == x._n);
    }

    bool operator!=(bound_t x) const {
      return !this->operator==(x);
    }

    /*	operator<= and operator>= use a somewhat optimized implementation.
     *	results include up to 20% improvements in performance in the octagon domain
     *	over a more naive implementation.
     */
    bool operator<=(bound_t x) const {
      if(this->_is_infinite xor x._is_infinite){
        if(this->_is_infinite){
          return this->_n < 0;
        }
        return x._n > 0;
      }
      return this->_n <= x._n;
    }

    bool operator>=(bound_t x) const {
      if(this->_is_infinite xor x._is_infinite){
        if(this->_is_infinite){
          return this->_n > 0;
        }
        return x._n < 0;
      }
      return this->_n >= x._n;
    }

    bound_t abs() const {
      if (this->operator>=(0)) {
        return *this;
      } else {
        return this->operator-();
      }
    }

    boost::optional< Number > number() const {
      if (this->is_infinite()) {
        return boost::optional< Number >();
      } else {
        return boost::optional< Number >(this->_n);
      }
    }

    void write(crab::crab_os& o) {
      if (this->is_plus_infinity()) {
        o << "+oo";
      } else if (this->is_minus_infinity()) {
        o << "-oo";
      } else {
        o << this->_n;
      }
    }

  }; // class bound

  typedef bound< z_number > z_bound;
  typedef bound< q_number > q_bound;

  namespace bounds_impl {
    // Conversion between z_bound and q_bound
    // template<class B1, class B2>
    // inline void convert_bounds(B1 b1, B2& b2);

    inline void convert_bounds(z_bound b1, z_bound &b2)
    { std::swap (b1,b2); }
    inline void convert_bounds(q_bound b1, q_bound &b2)
    { std::swap (b1,b2); }
    inline void convert_bounds(z_bound b1, q_bound &b2)
    {
      if (b1.is_plus_infinity())
	b2 = q_bound::plus_infinity();
      else if (b1.is_minus_infinity())
	b2 = q_bound::minus_infinity();
      else
	b2 = q_bound (q_number(*b1.number()));
    }
    inline void convert_bounds(q_bound b1, z_bound &b2)
    {
      if (b1.is_plus_infinity())
	b2 = z_bound::plus_infinity();
      else if (b1.is_minus_infinity())
	b2 = z_bound::minus_infinity();
      else
	b2 = z_bound ((*(b1.number())).round_to_lower ());
    }
  }

  template< typename Number >
  class interval;

  template< typename Number >
  class interval: public writeable {

  public:
    typedef bound< Number > bound_t;
    typedef interval< Number > interval_t;

  private:
    bound_t _lb;
    bound_t _ub;

  public:
    static interval_t top() {
      return interval_t(bound_t::minus_infinity(), bound_t::plus_infinity());
    }

    static interval_t bottom() {
      return interval_t();
    }

  private:
    interval(): _lb(0), _ub(-1) { }

    static Number abs(Number x) { return x < 0 ? -x : x; }

    static Number max(Number x, Number y) { return x.operator<=(y) ? y : x; }

    static Number min(Number x, Number y) { return x.operator<(y) ? x : y; }

  public:
    interval(bound_t lb, bound_t ub): _lb(lb), _ub(ub) {
      if (lb > ub) {
        this->_lb = 0;
        this->_ub = -1;
      }
    }

    interval(bound_t b): _lb(b), _ub(b) {
      if (b.is_infinite()) {
        this->_lb = 0;
        this->_ub = -1;
      }
    }

    interval(Number n): _lb(n), _ub(n) { }

    interval(std::string b): _lb(b), _ub(b) {
      if (this->_lb.is_infinite()) {
        this->_lb = 0;
        this->_ub = -1;
      }
    }

    interval(const interval_t& i): writeable(), _lb(i._lb), _ub(i._ub) { }

    interval_t& operator=(interval_t i){
      this->_lb = i._lb;
      this->_ub = i._ub;
      return *this;
    }

    bound_t lb() const {
      return this->_lb;
    }

    bound_t ub() const {
      return this->_ub;
    }

    bool is_bottom() const {
      return (this->_lb > this->_ub);
    }

    bool is_top() const {
      return (this->_lb.is_infinite() && this->_ub.is_infinite());
    }

    interval_t lower_half_line() const {
      return interval_t(bound_t::minus_infinity(), this->_ub);
    }

    interval_t upper_half_line() const {
      return interval_t(this->_lb, bound_t::plus_infinity());
    }

    bool operator==(interval_t x) const {
      if (is_bottom()) {
        return x.is_bottom();
      } else {
        return (this->_lb == x._lb) && (this->_ub == x._ub);
      }
    }

    bool operator!=(interval_t x) const {
      return !this->operator==(x);
    }

    bool operator<=(interval_t x) const {
      if (this->is_bottom()) {
        return true;
      } else if (x.is_bottom()) {
        return false;
      } else {
        return (x._lb <= this->_lb) && (this->_ub <= x._ub);
      }
    }

    interval_t operator|(interval_t x) const {
      if (this->is_bottom()) {
        return x;
      } else if (x.is_bottom()) {
        return *this;
      } else {
	return interval_t(bound_t::min(this->_lb, x._lb),
                            bound_t::max(this->_ub, x._ub));
      }
    }

    interval_t operator&(interval_t x) const {
      if (this->is_bottom() || x.is_bottom()) {
        return this->bottom();
      } else {
        return interval_t(bound_t::max(this->_lb, x._lb),
                          bound_t::min(this->_ub, x._ub));
      }
    }

    interval_t operator||(interval_t x) const {
      if (this->is_bottom()) {
	return x;
      } else if (x.is_bottom()) {
	return *this;
      } else {
        return interval_t(x._lb < this->_lb ?
                          bound_t::minus_infinity() :
                          this->_lb,
                          this->_ub < x._ub ?
                          bound_t::plus_infinity() :
                          this->_ub);
      }
    }

    template<typename Thresholds>
    interval_t widening_thresholds (interval_t x, const Thresholds &ts) {
      if (this->is_bottom()) {
	return x;
      } else if (x.is_bottom()) {
	return *this;
      } else {
        bound_t lb = (x._lb < this->_lb ? ts.get_prev (x._lb) : this->_lb);
        bound_t ub = (this->_ub < x._ub ? ts.get_next (x._ub) :  this->_ub);
        return interval_t(lb, ub);
      }
    }

    interval_t operator&&(interval_t x) const {
      if (this->is_bottom() || x.is_bottom()) {
        return this->bottom();
      } else {
        return interval_t(this->_lb.is_infinite() && x._lb.is_finite() ?
                          x._lb : this->_lb,
                          this->_ub.is_infinite() && x._ub.is_finite() ?
                          x._ub : this->_ub);
      }
    }

    interval_t operator+(interval_t x) const {
      if (this->is_bottom() || x.is_bottom()) {
        return this->bottom();
      } else {
	return interval_t(this->_lb + x._lb, this->_ub + x._ub);
      }
    }

    interval_t& operator+=(interval_t x) {
      return this->operator=(this->operator+(x));
    }

    interval_t operator-() const {
      if (this->is_bottom()) {
        return this->bottom();
      } else {
        return interval_t(-this->_ub, -this->_lb);
      }
    }

    interval_t operator-(interval_t x) const {
      if (this->is_bottom() || x.is_bottom()) {
        return this->bottom();
      } else {
        return interval_t(this->_lb - x._ub, this->_ub - x._lb);
      }
    }

    interval_t& operator-=(interval_t x) {
      return this->operator=(this->operator-(x));
    }

    interval_t operator*(interval_t x) const {
      if (this->is_bottom() || x.is_bottom()) {
        return this->bottom();
      } else {
        bound_t ll = this->_lb * x._lb;
        bound_t lu = this->_lb * x._ub;
        bound_t ul = this->_ub * x._lb;
        bound_t uu = this->_ub * x._ub;
        return interval_t(bound_t::min(ll, lu, ul, uu),
                          bound_t::max(ll, lu, ul, uu));
      }
    }

    interval_t& operator*=(interval_t x) {
      return this->operator=(this->operator*(x));
    }

    interval_t operator/(interval_t x) const;

    interval_t& operator/=(interval_t x) {
      return this->operator=(this->operator/(x));
    }

    boost::optional< Number > singleton() const {
      if (!this->is_bottom() && this->_lb == this->_ub) {
        return this->_lb.number();
      } else {
        return boost::optional< Number >();
      }
    }

    bool operator[](Number n) const {
      if (this->is_bottom()) {
        return false;
      } else {
        bound_t b(n);
        return (this->_lb <= b) && (b <= this->_ub);
      }
    }

    void write(crab::crab_os& o) {
      if (is_bottom()) {
        o << "_|_";
      } else {
        o << "[" << _lb << ", " << _ub << "]";
      }
    }

    // division and remainder operations

    interval_t UDiv(interval_t x ) const {
      if (this->is_bottom() || x.is_bottom()) {
        return this->bottom();
      } else {
        return this->top();
      }
    }

    interval_t SRem(interval_t x)  const {
      if (this->is_bottom() || x.is_bottom()) {
        return this->bottom();
      } else {
        return this->top();
      }
    }

    interval_t URem(interval_t x)  const {
      if (this->is_bottom() || x.is_bottom()) {
        return this->bottom();
      } else {
        return this->top();
      }
    }

    // bitwise operations
    interval_t And(interval_t x) const {
      if (this->is_bottom() || x.is_bottom()) {
        return this->bottom();
      } else {
        return this->top();
      }
    }

    interval_t Or(interval_t x)  const {
      if (this->is_bottom() || x.is_bottom()) {
        return this->bottom();
      } else {
        return this->top();
      }
    }

    interval_t Xor(interval_t x) const { return this->Or(x); }

    interval_t Shl(interval_t x) const {
      if (this->is_bottom() || x.is_bottom()) {
        return this->bottom();
      } else {
        return this->top();
      }
    }

    interval_t LShr(interval_t  x) const {
      if (this->is_bottom() || x.is_bottom()) {
        return this->bottom();
      } else {
        return this->top();
      }
    }

    interval_t AShr(interval_t  x) const {
      if (this->is_bottom() || x.is_bottom()) {
        return this->bottom();
      } else {
        return this->top();
      }
    }

  };//  class interval

  template<>
  inline interval< q_number > interval< q_number >::
  operator/(interval< q_number > x) const {
    if (this->is_bottom() || x.is_bottom()) {
      return this->bottom();
    } else {
      boost::optional< q_number > d = x.singleton();
      if (d && *d == 0) {
        // [_, _] / 0 = _|_
        return this->bottom();
      } else if (x[0]) {
        boost::optional< q_number > n = this->singleton();
        if (n && *n == 0) {
          // 0 / [_, _] = 0
          return interval_t(q_number(0));
        } else {
          return this->top();
        }
      } else {
        bound_t ll = this->_lb / x._lb;
        bound_t lu = this->_lb / x._ub;
        bound_t ul = this->_ub / x._lb;
        bound_t uu = this->_ub / x._ub;
        return interval_t(bound_t::min(ll, lu, ul, uu),
                          bound_t::max(ll, lu, ul, uu));
      }
    }
  }

  template<>
  inline interval< z_number > interval< z_number >::
  operator/(interval< z_number > x) const {
    if (this->is_bottom() || x.is_bottom()) {
      return this->bottom();
    } else {
      // Divisor is a singleton:
      //   the linear interval solver can perform many divisions where
      //   the divisor is a singleton interval. We optimize for this case.
      if (boost::optional<z_number> n = x.singleton()) {
	z_number c = *n;
	if (c == 1) {
	  return *this;
	} else if (c > 0) {
	  return interval_t(_lb / c, _ub / c);
	} else if (c < 0) {
	  return interval_t(_ub / c, _lb / c);
	} else {}
      }
      // Divisor is not a singleton
      typedef interval< z_number > z_interval;
      if (x[0]) {
        z_interval l(x._lb, z_bound(-1));
        z_interval u(z_bound(1), x._ub);
        return (this->operator/(l) | this->operator/(u));
      } else if (this->operator[](0)) {
        z_interval l(this->_lb, z_bound(-1));
        z_interval u(z_bound(1), this->_ub);
        return ((l / x) | (u / x) | z_interval(z_number(0)));
      } else {
        // Neither the dividend nor the divisor contains 0
        z_interval a = (this->_ub < 0) ?
            (*this + ((x._ub < 0) ?
                      (x + z_interval(z_number(1))) :
                      (z_interval(z_number(1)) - x))) : *this;
	bound_t ll = a._lb / x._lb;
	bound_t lu = a._lb / x._ub;
	bound_t ul = a._ub / x._lb;
	bound_t uu = a._ub / x._ub;
	return interval_t(bound_t::min(ll, lu, ul, uu),
			  bound_t::max(ll, lu, ul, uu));
      }
    }
  }

  template <>
  inline interval< z_number > interval< z_number >::
  SRem(interval< z_number > x) const {
    // note that the sign of the divisor does not matter

    if (this->is_bottom() || x.is_bottom()) {
      return this->bottom();
    } else if (this->singleton() && x.singleton()) {
      z_number dividend = *this->singleton();
      z_number divisor = *x.singleton();

      if (divisor == 0) {
        return this->bottom();
      }

      return interval_t(dividend % divisor);
    } else if (x.ub().is_finite() && x.lb().is_finite()) {
      z_number max_divisor = max(abs(*x.lb().number()),
                                 abs(*x.ub().number()));

      if (max_divisor == 0) {
        return this->bottom();
      }

      if (this->lb() < 0) {
        if (this->ub() > 0) {
          return interval_t(-(max_divisor - 1), max_divisor - 1);
        } else {
          return interval_t(-(max_divisor - 1), 0);
        }
      } else {
        return interval_t(0, max_divisor - 1);
      }
    } else {
      return this->top();
    }
  }

  template <>
  inline interval< z_number > interval< z_number >::
  URem(interval< z_number > x) const {

    if (this->is_bottom() || x.is_bottom()) {
      return this->bottom();
    } else if (this->singleton() && x.singleton()) {
      z_number dividend = *this->singleton();
      z_number divisor = *x.singleton();

      if (divisor < 0) {
        return this->top();
      } else if (divisor == 0) {
        return this->bottom();
      } else if (dividend < 0) {
        // dividend is treated as an unsigned integer.
        // we would need the size to be more precise
        return interval_t(0, divisor - 1);
      } else {
        return interval_t(dividend % divisor);
      }
    } else if (x.ub().is_finite() && x.lb().is_finite()) {
      z_number max_divisor = *x.ub().number();

      if (x.lb() < 0 || x.ub() < 0) {
        return this->top();
      } else if (max_divisor == 0) {
        return this->bottom();
      }

      return interval_t(0, max_divisor - 1);
    } else {
      return this->top();
    }
  }

  template <>
  inline interval< z_number > interval< z_number >::
  And(interval< z_number > x) const {
    if (this->is_bottom() || x.is_bottom()) {
      return this->bottom();
    } else {
      boost::optional< z_number > left_op = this->singleton();
      boost::optional< z_number > right_op = x.singleton();

      if (left_op && right_op) {
        return interval_t((*left_op) & (*right_op));
      } else if (this->lb() >= 0 && x.lb() >= 0) {
        return interval_t(0, bound_t::min(this->ub(), x.ub()));
      } else {
        return this->top();
      }
    }
  }

  template <>
  inline interval< z_number > interval< z_number >::
  Or(interval< z_number > x) const {
    if (this->is_bottom() || x.is_bottom()) {
      return this->bottom();
    } else {
      boost::optional< z_number > left_op = this->singleton();
      boost::optional< z_number > right_op = x.singleton();

      if (left_op && right_op) {
        return interval_t((*left_op) | (*right_op));
      } else if (this->lb() >= 0 && x.lb() >= 0) {
        boost::optional< z_number > left_ub = this->ub().number();
        boost::optional< z_number > right_ub = x.ub().number();

        if (left_ub && right_ub) {
          z_number m = (*left_ub > *right_ub ? *left_ub : *right_ub);
          return interval_t(0, m.fill_ones());
        } else {
          return interval_t(0, bound_t::plus_infinity());
        }
      } else {
        return this->top();
      }
    }
  }

  template <>
  inline interval< z_number > interval< z_number >::
  Xor(interval< z_number > x)  const {
    if (this->is_bottom() || x.is_bottom()) {
      return this->bottom();
    } else {
      boost::optional< z_number > left_op = this->singleton();
      boost::optional< z_number > right_op = x.singleton();

      if (left_op && right_op) {
        return interval_t((*left_op) ^ (*right_op));
      } else {
        return this->Or(x);
      }
    }
  }

  template <>
  inline interval< z_number > interval< z_number >::
  Shl(interval< z_number > x) const {
    if (this->is_bottom() || x.is_bottom()) {
      return this->bottom();
    } else {
      if (boost::optional<z_number> shift = x.singleton()) {
	z_number k = *shift;
	if (k < 0) {
	  //CRAB_ERROR("lshr shift operand cannot be negative");
	  return this->top();
	}
	// Some crazy linux drivers generate shl instructions with
	// huge shifts.  We limit the number of times the loop is run
	// to avoid wasting too much time on it.
	if (k <= 128) {
	  z_number factor = 1;
	  for (int i = 0; k > i ; i++) {
	    factor *= 2;
	  }
	  return (*this) * factor;
	}
      }
      return this->top();
    }
  }

  template <>
  inline interval< z_number > interval< z_number >::
  AShr(interval< z_number > x) const {
    if (this->is_bottom() || x.is_bottom()) {
      return this->bottom();
    } else {
      if (boost::optional<z_number> shift = x.singleton()) {
	z_number k = *shift;
	if (k < 0) {
	  //CRAB_ERROR("ashr shift operand cannot be negative");
	  return this->top();
	}
	// Some crazy linux drivers generate ashr instructions with
	// huge shifts.  We limit the number of times the loop is run
	// to avoid wasting too much time on it.
	if (k <= 128) {
	  z_number factor = 1;
	  for (int i = 0; k > i; i++) {
	    factor *= 2;
	  }
	  return (*this) / factor;
	}
      }
      return this->top();
    }
  }

  template <>
  inline interval< z_number > interval< z_number >::
  LShr(interval< z_number > x) const {
    if (this->is_bottom() || x.is_bottom()) {
      return this->bottom();
    } else {
      if (boost::optional< z_number > shift = x.singleton()) {
	z_number k = *shift;
	if (k < 0) {
	  //CRAB_ERROR("lshr shift operand cannot be negative");
	  return this->top();
	}
	// Some crazy linux drivers generate lshr instructions with
	// huge shifts.  We limit the number of times the loop is run
	// to avoid wasting too much time on it.
	if (k <= 128) {
	  if (this->lb() >= 0 && this->ub().is_finite() && shift) {
	    z_number lb = *this->lb().number();
	    z_number ub = *this->ub().number();
	    return interval< z_number >(lb >> k, ub >> k);
	  }
	}
      }
      return this->top();
    }
  }

  template< typename Number >
  inline interval< Number > operator+(Number c, interval< Number > x) {
    return interval< Number >(c) + x;
  }

  template< typename Number >
  inline interval< Number > operator+(interval< Number > x, Number c) {
    return x + interval< Number >(c);
  }

  template< typename Number >
  inline interval< Number > operator*(Number c, interval< Number > x) {
    return interval< Number >(c) * x;
  }

  template< typename Number >
  inline interval< Number > operator*(interval< Number > x, Number c) {
    return x * interval< Number >(c);
  }

  template< typename Number >
  inline interval< Number > operator/(Number c, interval< Number > x) {
    return interval< Number >(c) / x;
  }

  template< typename Number >
  inline interval< Number > operator/(interval< Number > x, Number c) {
    return x / interval< Number >(c);
  }

  template< typename Number >
  inline interval< Number > operator-(Number c, interval< Number > x) {
    return interval< Number >(c) - x;
  }

  template< typename Number >
  inline interval< Number > operator-(interval< Number > x, Number c) {
    return x - interval< Number >(c);
  }

  template < typename Number >
  inline crab::crab_os& operator<<(crab::crab_os& o, interval< Number > i) {
    i.write(o);
    return o;
  }

  typedef interval< z_number > z_interval;
  typedef interval< q_number > q_interval;

  namespace linear_interval_solver_impl {

    template<>
    inline z_interval trim_interval(z_interval i, z_interval j) {
      if (boost::optional<z_number> c = j.singleton()) {
	if (i.lb() == *c) {
	  return z_interval(*c + 1, i.ub());
	} else if (i.ub() == *c) {
	  return z_interval(i.lb(), *c - 1);
	} else {
	}
      }
      return i;
    }

    template<>
    inline q_interval trim_interval(q_interval i, q_interval /* j */) {
      // No refinement possible for disequations over rational numbers
      return i;
    }

    template<>
    inline z_interval lower_half_line(z_interval i, bool /*is_signed*/) {
      return i.lower_half_line();
    }

    template<>
    inline q_interval lower_half_line(q_interval i, bool /*is_signed*/) {
      return i.lower_half_line();
    }

    template<>
    inline z_interval upper_half_line(z_interval i, bool /*is_signed*/) {
      return i.upper_half_line();
    }

    template<>
    inline q_interval upper_half_line(q_interval i, bool /*is_signed*/) {
      return i.upper_half_line();
    }
  } // namespace linear_interval_solver_impl

  template<typename Number, typename VariableName, std::size_t max_reduction_cycles = 10>
  class interval_domain:
    public crab::domains::
    abstract_domain<Number, VariableName,
		    interval_domain<Number,VariableName,max_reduction_cycles> >  {
  public:
    typedef interval_domain<Number, VariableName, max_reduction_cycles> interval_domain_t;
    typedef crab::domains::
    abstract_domain<Number,VariableName,interval_domain_t> abstract_domain_t;
    using typename abstract_domain_t::linear_expression_t;
    using typename abstract_domain_t::linear_constraint_t;
    using typename abstract_domain_t::linear_constraint_system_t;
    using typename abstract_domain_t::variable_t;
    using typename abstract_domain_t::number_t;
    using typename abstract_domain_t::varname_t;
    typedef interval<Number> interval_t;

  private:
    typedef separate_domain<variable_t, interval_t> separate_domain_t;
    typedef linear_interval_solver<Number, VariableName, separate_domain_t> solver_t;

  public:
    typedef typename separate_domain_t::iterator iterator;

  private:
    separate_domain_t _env;

    interval_domain(separate_domain_t env): _env(env) { }

  public:
    static interval_domain_t top() {
      return interval_domain(separate_domain_t::top());
    }

    static interval_domain_t bottom() {
      return interval_domain(separate_domain_t::bottom());
    }

  public:
    interval_domain(): _env(separate_domain_t::top()) { }

    interval_domain(const interval_domain_t& e):
      _env(e._env) {
      crab::CrabStats::count (getDomainName() + ".count.copy");
      crab::ScopedCrabStats __st__(getDomainName() + ".copy");
    }

    interval_domain_t& operator=(const interval_domain_t& o) {
      crab::CrabStats::count (getDomainName() + ".count.copy");
      crab::ScopedCrabStats __st__(getDomainName() + ".copy");
      if (this != &o)
        this->_env = o._env;
      return *this;
    }

    iterator begin() {
      return this->_env.begin();
    }

    iterator end() {
      return this->_env.end();
    }

    bool is_bottom() {
      return this->_env.is_bottom();
    }

    bool is_top() {
      return this->_env.is_top();
    }

    bool operator<=(interval_domain_t e) {
      crab::CrabStats::count (getDomainName() + ".count.leq");
      crab::ScopedCrabStats __st__(getDomainName() + ".leq");
      return (this->_env <= e._env);
    }

    void operator|=(interval_domain_t e) {
      crab::CrabStats::count (getDomainName() + ".count.join");
      crab::ScopedCrabStats __st__(getDomainName() + ".join");
      this->_env = this->_env | e._env;
    }

    interval_domain_t operator|(interval_domain_t e) {
      crab::CrabStats::count (getDomainName() + ".count.join");
      crab::ScopedCrabStats __st__(getDomainName() + ".join");
      return (this->_env | e._env);
    }

    interval_domain_t operator&(interval_domain_t e) {
      crab::CrabStats::count (getDomainName() + ".count.meet");
      crab::ScopedCrabStats __st__(getDomainName() + ".meet");
      return (this->_env & e._env);
    }

    interval_domain_t operator||(interval_domain_t e) {
      crab::CrabStats::count (getDomainName() + ".count.widening");
      crab::ScopedCrabStats __st__(getDomainName() + ".widening");
      return (this->_env || e._env);
    }

    template<typename Thresholds>
    interval_domain_t widening_thresholds (interval_domain_t e, const Thresholds &ts) {
      crab::CrabStats::count (getDomainName() + ".count.widening");
      crab::ScopedCrabStats __st__(getDomainName() + ".widening");
      return this->_env.widening_thresholds (e._env, ts);
    }

    interval_domain_t operator&&(interval_domain_t e) {
      crab::CrabStats::count (getDomainName() + ".count.narrowing");
      crab::ScopedCrabStats __st__(getDomainName() + ".narrowing");
      return (this->_env && e._env);
    }

    void set(variable_t v, interval_t i) {
      crab::CrabStats::count (getDomainName() + ".count.assign");
      crab::ScopedCrabStats __st__(getDomainName() + ".assign");
      this->_env.set(v, i);
    }

    void set(variable_t v, Number n) {
      crab::CrabStats::count (getDomainName() + ".count.assign");
      crab::ScopedCrabStats __st__(getDomainName() + ".assign");
      this->_env.set(v, interval_t(n));
    }

    void operator-=(variable_t v) {
      crab::CrabStats::count (getDomainName() + ".count.forget");
      crab::ScopedCrabStats __st__(getDomainName() + ".forget");
      this->_env -= v;
    }

    interval_t operator[](variable_t v) {
      return this->_env[v];
    }

    interval_t operator[](linear_expression_t expr) {
      interval_t r(expr.constant());
      for (typename linear_expression_t::iterator it = expr.begin();
           it != expr.end(); ++it) {
	interval_t c(it->first);
	r += c * this->_env[it->second];
      }
      return r;
    }

    void operator+=(linear_constraint_system_t csts) {
      crab::CrabStats::count (getDomainName() + ".count.add_constraints");
      crab::ScopedCrabStats __st__(getDomainName() + ".add_constraints");
      this->add(csts);
    }

    void add(linear_constraint_system_t csts,
             std::size_t threshold = max_reduction_cycles) {
      if (!this->is_bottom()) {
	// XXX: filter out unsigned linear inequalities
	linear_constraint_system_t signed_csts;
	for (auto const& c: csts) {
	  if (c.is_inequality() && c.is_unsigned()) {
	    CRAB_WARN("unsigned inequality skipped");
	    continue;
	  }
	  signed_csts += c;
	}
	solver_t solver(signed_csts, threshold);
	solver.run(this->_env);
      }
    }

    interval_domain_t operator+(linear_constraint_system_t csts) {
      interval_domain_t e(this->_env);
      e += csts;
      return e;
    }

    void assign(variable_t x, linear_expression_t e) {
      crab::CrabStats::count (getDomainName() + ".count.assign");
      crab::ScopedCrabStats __st__(getDomainName() + ".assign");

      if (boost::optional<variable_t> v = e.get_variable ()) {
        this->_env.set(x, this->_env [(*v)]);
      }
      else {
        interval_t r = e.constant();
        for (typename linear_expression_t::iterator it = e.begin();
             it != e.end(); ++it) {
	r += it->first * this->_env[it->second];
        }
        this->_env.set(x, r);
      }
    }

    void apply(operation_t op, variable_t x, variable_t y, variable_t z) {
      crab::CrabStats::count (getDomainName() + ".count.apply");
      crab::ScopedCrabStats __st__(getDomainName() + ".apply");

      interval_t yi = this->_env[y];
      interval_t zi = this->_env[z];
      interval_t xi = interval_t::bottom();

      switch (op) {
      case OP_ADDITION: {
	xi = yi + zi;
	break;
      }
      case OP_SUBTRACTION: {
	xi = yi - zi;
	break;
      }
      case OP_MULTIPLICATION: {
	xi = yi * zi;
	break;
      }
      case OP_DIVISION: {
	xi = yi / zi;
	break;
      }
      }
      this->_env.set(x, xi);
    }

    void apply(operation_t op, variable_t x, variable_t y, Number k) {
      crab::CrabStats::count (getDomainName() + ".count.apply");
      crab::ScopedCrabStats __st__(getDomainName() + ".apply");

      interval_t yi = this->_env[y];
      interval_t zi(k);
      interval_t xi = interval_t::bottom();

      switch (op) {
      case OP_ADDITION: {
	xi = yi + zi;
	break;
      }
      case OP_SUBTRACTION: {
	xi = yi - zi;
	break;
      }
      case OP_MULTIPLICATION: {
	xi = yi * zi;
	break;
      }
      case OP_DIVISION: {
	xi = yi / zi;
	break;
      }
      }
      this->_env.set(x, xi);
    }

    void backward_assign (variable_t x, linear_expression_t e,
			  interval_domain_t inv) {
      crab::domains::BackwardAssignOps<interval_domain_t>::
	assign (*this, x, e, inv);
    }

    void backward_apply (operation_t op,
			 variable_t x, variable_t y, Number z,
			 interval_domain_t inv) {
      crab::domains::BackwardAssignOps<interval_domain_t>::
	apply(*this, op, x, y, z, inv);
    }

    void backward_apply(operation_t op,
			variable_t x, variable_t y, variable_t z,
			interval_domain_t inv) {
      crab::domains::BackwardAssignOps<interval_domain_t>::
	apply(*this, op, x, y, z, inv);
    }

    // cast_operators_api

    void apply(crab::domains::int_conv_operation_t /*op*/,
	       variable_t dst, variable_t src){
      // ignore the widths
      assign(dst, src);
    }

    // bitwise_operators_api

    void apply(bitwise_operation_t op, variable_t x, variable_t y, variable_t z){
      crab::CrabStats::count (getDomainName() + ".count.apply");
      crab::ScopedCrabStats __st__(getDomainName() + ".apply");

      interval_t yi = this->_env[y];
      interval_t zi = this->_env[z];
      interval_t xi = interval_t::bottom();

      switch (op) {
        case OP_AND: {
	xi = yi.And(zi);
	break;
        }
        case OP_OR: {
	xi = yi.Or(zi);
	break;
        }
        case OP_XOR: {
	xi = yi.Xor(zi);
	break;
        }
        case OP_SHL: {
	xi = yi.Shl(zi);
	break;
        }
        case OP_LSHR: {
          xi = yi.LShr(zi);
          break;
        }
        case OP_ASHR: {
	xi = yi.AShr(zi);
	break;
        }
        default:
          CRAB_ERROR("unreachable");
      }
      this->_env.set(x, xi);
    }

    void apply(bitwise_operation_t op, variable_t x, variable_t y, Number k){
      crab::CrabStats::count (getDomainName() + ".count.apply");
      crab::ScopedCrabStats __st__(getDomainName() + ".apply");

      interval_t yi = this->_env[y];
      interval_t zi(k);
      interval_t xi = interval_t::bottom();
      switch (op) {
        case OP_AND: {
	xi = yi.And(zi);
	break;
        }
        case OP_OR: {
	xi = yi.Or(zi);
	break;
        }
        case OP_XOR: {
	xi = yi.Xor(zi);
	break;
        }
        case OP_SHL: {
	xi = yi.Shl(zi);
	break;
        }
        case OP_LSHR: {
          xi = yi.LShr(zi);
          break;
        }
        case OP_ASHR: {
	xi = yi.AShr(zi);
	break;
        }
        default:
          CRAB_ERROR("unreachable");
      }
      this->_env.set(x, xi);
    }

    // division_operators_api

    void apply(div_operation_t op, variable_t x, variable_t y, variable_t z){
      crab::CrabStats::count (getDomainName() + ".count.apply");
      crab::ScopedCrabStats __st__(getDomainName() + ".apply");

      interval_t yi = this->_env[y];
      interval_t zi = this->_env[z];
      interval_t xi = interval_t::bottom();

      switch (op) {
        case OP_SDIV: {
	xi = yi / zi;
	break;
        }
        case OP_UDIV: {
	xi = yi.UDiv(zi);
	break;
        }
        case OP_SREM: {
	xi = yi.SRem(zi);
	break;
        }
        case OP_UREM: {
	xi = yi.URem(zi);
	break;
        }
        default:
          CRAB_ERROR("unreachable");
      }
      this->_env.set(x, xi);

    }

    void apply(div_operation_t op, variable_t x, variable_t y, Number k){
      crab::CrabStats::count (getDomainName() + ".count.apply");
      crab::ScopedCrabStats __st__(getDomainName() + ".apply");

      interval_t yi = this->_env[y];
      interval_t zi(k);
      interval_t xi = interval_t::bottom();
      switch (op) {
        case OP_SDIV: {
	xi = yi / zi;
	break;
        }
        case OP_UDIV: {
	xi = yi.UDiv(zi);
	break;
        }
        case OP_SREM: {
	xi = yi.SRem(zi);
	break;
        }
        case OP_UREM: {
	xi = yi.URem(zi);
	break;
        }
        default:
          CRAB_ERROR("unreachable");
      }
      this->_env.set(x, xi);
    }

    void write(crab::crab_os& o) {
      this->_env.write(o);
    }

    linear_constraint_system_t to_linear_constraint_system ()
    {
      linear_constraint_system_t csts;

      if (this->is_bottom()) {
        csts += linear_constraint_t::get_false();
        return csts;
      }

      for (iterator it = this->_env.begin(); it != this->_env.end(); ++it)
      {
        variable_t v = it->first;
        interval_t   i = it->second;
        boost::optional<Number> lb = i.lb().number();
        boost::optional<Number> ub = i.ub().number();
        if (lb) csts += linear_constraint_t(v >= *lb);
        if (ub) csts += linear_constraint_t(v <= *ub);
      }
      return csts;
    }

    static std::string getDomainName () {
      return "Intervals";
    }

  }; // class interval_domain

} // namespace ikos


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

// Copyright (c) 2019 Tinko Bartels, Berlin, Germany.

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

#ifndef BOOST_GEOMETRY_EXTENSIONS_TRIANGULATION_STRATEGIES_CARTESIAN_ACCELERATED_SHULL_HPP
#define BOOST_GEOMETRY_EXTENSIONS_TRIANGULATION_STRATEGIES_CARTESIAN_ACCELERATED_SHULL_HPP

#include <boost/geometry/extensions/triangulation/strategies/delaunay_triangulation.hpp>
#include <boost/geometry/extensions/triangulation/strategies/cartesian/detail/accelerated_shull.hpp>
#include <boost/geometry/extensions/triangulation/strategies/delaunay_triangulation.hpp>
#include <boost/geometry/extensions/triangulation/strategies/cartesian/in_circle_robust.hpp>
#include <boost/geometry/strategies/cartesian/side_by_triangle.hpp>

#include <boost/geometry/core/coordinate_system.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>

namespace boost { namespace geometry { namespace strategy
{

namespace delaunay_triangulation
{

struct accelerated_shull
{
    template
    <
        typename PointContainer,
        typename Triangulation,
        typename SideStrategy = strategy::side::side_by_triangle<>,
        typename InCircleStrategy = strategy::in_circle::in_circle_robust<>
    >
    static inline void apply(PointContainer const & in,
                             Triangulation& out,
                             bool legalize = true)
    {
        detail::accelerated_shull::apply<
            PointContainer,
            Triangulation,
            SideStrategy,
            InCircleStrategy>(in, out, legalize);
    }
};

namespace services
{
template <>
struct default_strategy<point_tag, cartesian_tag, 2>
{
    typedef accelerated_shull type;
};
}

}}}} // namespace boost::geometry::strategy::delaunay:triangulation

#endif // BOOST_GEOMETRY_EXTENSIONS_TRIANGULATION_STRATEGIES_CARTESIAN_ACCELERATED_SHULL_HPP


/*
 * Copyright (C) 2015-2018 Philippe Proulx <eepp.ca>
 *
 * This software may be modified and distributed under the terms
 * of the MIT license. See the LICENSE file for details.
 */

#include <cassert>
#include <boost/optional.hpp>

#include <yactfr/metadata/clk-type.hpp>

namespace yactfr {

ClockValueInterval::ClockValueInterval(const Cycles lower, const Cycles upper) noexcept :
    _lower {lower},
    _upper {upper}
{
}

ClockOffset::ClockOffset(const long long secs, const Cycles cycles) noexcept :
    _secs {secs},
    _cycles {cycles}
{
}

ClockType::ClockType(const unsigned long long freq, boost::optional<std::string> name,
                     boost::optional<std::string> descr, boost::optional<boost::uuids::uuid> uuid,
                     const Cycles prec, const ClockOffset& offset, const bool originIsUnixEpoch,
                     MapItem::UP userAttrs) :
    _freq {freq},
    _name {std::move(name)},
    _descr {std::move(descr)},
    _uuid {std::move(uuid)},
    _prec {prec},
    _offset {offset},
    _originIsUnixEpoch {originIsUnixEpoch},
    _userAttrs {std::move(userAttrs)}
{
    assert(freq > 0);
    assert(offset.cycles() < freq);
}

ClockValueInterval ClockType::clockValueInterval(const Cycles cycles) const noexcept
{
    return ClockValueInterval {cycles - _prec, cycles + _prec};
}

} // namespace yactfr


/***************************************************************************
 * Copyright 1998-2020 by authors (see AUTHORS.txt)                        *
 *                                                                         *
 *   This file is part of LuxCoreRender.                                   *
 *                                                                         *
 * Licensed under the Apache License, Version 2.0 (the "License");         *
 * you may not use this file except in compliance with the License.        *
 * You may obtain a copy of the License at                                 *
 *                                                                         *
 *     http://www.apache.org/licenses/LICENSE-2.0                          *
 *                                                                         *
 * Unless required by applicable law or agreed to in writing, software     *
 * distributed under the License is distributed on an "AS IS" BASIS,       *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.*
 * See the License for the specific language governing permissions and     *
 * limitations under the License.                                          *
 ***************************************************************************/

#include <stdexcept>
#include <boost/foreach.hpp>
#include <boost/regex.hpp>

#include "luxrays/kernels/kernels.h"
#include "slg/kernels/kernels.h"
#include "slg/film/film.h"
#include "slg/film/imagepipeline/plugins/gaussianblur3x3.h"

using namespace std;
using namespace luxrays;
using namespace slg;

//------------------------------------------------------------------------------
// GaussianBlur filter plugin
//------------------------------------------------------------------------------

BOOST_CLASS_EXPORT_IMPLEMENT(slg::GaussianBlur3x3FilterPlugin)

GaussianBlur3x3FilterPlugin::GaussianBlur3x3FilterPlugin(const float w) : weight(w),
		tmpBuffer(nullptr), tmpBufferSize(0) {
	hardwareDevice = nullptr;
	hwTmpBuffer = nullptr;

	filterXKernel = nullptr;
	filterYKernel = nullptr;
}

GaussianBlur3x3FilterPlugin::GaussianBlur3x3FilterPlugin() : tmpBuffer(nullptr) {
	hardwareDevice = nullptr;
	hwTmpBuffer = nullptr;

	filterXKernel = nullptr;
	filterYKernel = nullptr;
}

GaussianBlur3x3FilterPlugin::~GaussianBlur3x3FilterPlugin() {
	delete[] tmpBuffer;

	delete filterXKernel;
	delete filterYKernel;

	if (hardwareDevice)
		hardwareDevice->FreeBuffer(&hwTmpBuffer);
}

ImagePipelinePlugin *GaussianBlur3x3FilterPlugin::Copy() const {
	return new GaussianBlur3x3FilterPlugin(weight);
}

//------------------------------------------------------------------------------
// CPU version
//------------------------------------------------------------------------------

template<class T> void GaussianBlur3x3FilterPlugin::ApplyBlurFilterXR1(
		const u_int filmWidth, const u_int filmHeight,
		const T *src,
		T *dst,
		const float aF,
		const float bF,
		const float cF) {
	// Do left edge
	T a;
	T b = src[0];
	T c = src[1];

	const float leftTotF = bF + cF;
	const T bLeftK = bF / leftTotF;
	const T cLeftK = cF / leftTotF;
	dst[0] = bLeftK  * b + cLeftK * c;

    // Main loop
	const float totF = aF + bF + cF;
	const T aK = aF / totF;
	const T bK = bF / totF;
	const T cK = cF / totF;

	for (u_int x = 1; x < filmWidth - 1; ++x) {
		a = b;
		b = c;
		c = src[x + 1];

		dst[x] = aK * a + bK  * b + cK * c;
    }

    // Do right edge
	const float rightTotF = aF + bF;
	const T aRightK = aF / rightTotF;
	const T bRightK = bF / rightTotF;
	a = b;
	b = c;
	dst[filmWidth - 1] = aRightK  * a + bRightK * b;
}

template<class T> void GaussianBlur3x3FilterPlugin::ApplyBlurFilterYR1(
		const u_int filmWidth, const u_int filmHeight,
		const T *src,
		T *dst,
		const float aF,
		const float bF,
		const float cF) {
	// Do left edge
	T a;
	T b = src[0];
	T c = src[filmWidth];

	const float leftTotF = bF + cF;
	const T bLeftK = bF / leftTotF;
	const T cLeftK = cF / leftTotF;
	dst[0] = bLeftK  * b + cLeftK * c;

    // Main loop
	const float totF = aF + bF + cF;
	const T aK = aF / totF;
	const T bK = bF / totF;
	const T cK = cF / totF;

    for (u_int y = 1; y < filmHeight - 1; ++y) {
		const unsigned index = y * filmWidth;

		a = b;
		b = c;
		c = src[index + filmWidth];

		dst[index] = aK * a + bK  * b + cK * c;
    }

    // Do right edge
	const float rightTotF = aF + bF;
	const T aRightK = aF / rightTotF;
	const T bRightK = bF / rightTotF;
	a = b;
	b = c;
	dst[(filmHeight - 1) * filmWidth] = aRightK  * a + bRightK * b;
}

template<class T> void GaussianBlur3x3FilterPlugin::ApplyBlurFilter(const u_int width, const u_int height,
		T *src, T *tmpBuffer,
		const float aF, const float bF, const float cF) {

	for (u_int i = 0; i < 3; ++i) {
		#pragma omp parallel for
		for (
			// Visual C++ 2013 supports only OpenMP 2.5
#if _OPENMP >= 200805
			unsigned
#endif
				int y = 0; y < height; ++y) {
			const u_int index = y * width;
			GaussianBlur3x3FilterPlugin::ApplyBlurFilterXR1<T>(width, height, &src[index], &tmpBuffer[index],
					aF, bF, cF);
		}

		#pragma omp parallel for
		for (
			// Visual C++ 2013 supports only OpenMP 2.5
#if _OPENMP >= 200805
			unsigned
#endif
				int x = 0; x < width; ++x)
			GaussianBlur3x3FilterPlugin::ApplyBlurFilterYR1<T>(width, height, &tmpBuffer[x], &src[x],
					aF, bF, cF);
	}
}

namespace slg {
// Explicit instantiations
template void GaussianBlur3x3FilterPlugin::ApplyBlurFilter(const u_int width, const u_int height,
		float *src, float *tmpBuffer,
		const float aF, const float bF, const float cF);
template void GaussianBlur3x3FilterPlugin::ApplyBlurFilter(const u_int width, const u_int height,
		Spectrum *src, Spectrum *tmpBuffer,
		const float aF, const float bF, const float cF);
}

void GaussianBlur3x3FilterPlugin::Apply(Film &film, const u_int index) {
	Spectrum *pixels = (Spectrum *)film.channel_IMAGEPIPELINEs[index]->GetPixels();
	const u_int width = film.GetWidth();
	const u_int height = film.GetHeight();

	// Allocate the temporary buffer if required
	if ((!tmpBuffer) || (width * height != tmpBufferSize)) {
		delete tmpBuffer;

		tmpBufferSize = width * height;
		tmpBuffer = new Spectrum[tmpBufferSize];
	}

	ApplyBlurFilter<Spectrum>(width, height, &pixels[index], &tmpBuffer[index], weight, 1.f, weight);
}

//------------------------------------------------------------------------------
// HardwareDevice version
//------------------------------------------------------------------------------

void GaussianBlur3x3FilterPlugin::AddHWChannelsUsed(unordered_set<Film::FilmChannelType, hash<int> > &hwChannelsUsed) const {
	hwChannelsUsed.insert(Film::IMAGEPIPELINE);
}

void GaussianBlur3x3FilterPlugin::ApplyHW(Film &film, const u_int index) {
	const u_int width = film.GetWidth();
	const u_int height = film.GetHeight();

	if (!filterXKernel) {
		film.ctx->SetVerbose(true);

		hardwareDevice = film.hardwareDevice;

		// Allocate OpenCL buffers
		hardwareDevice->AllocBufferRW(&hwTmpBuffer, nullptr, width * height * sizeof(Spectrum), "GaussianBlur3x3");

		// Compile sources
		const double tStart = WallClockTime();

		vector<string> opts;
		opts.push_back("-D LUXRAYS_OPENCL_KERNEL");
		opts.push_back("-D SLG_OPENCL_KERNEL");

		HardwareDeviceProgram *program = nullptr;
		hardwareDevice->CompileProgram(&program,
				opts,
				luxrays::ocl::KernelSource_luxrays_types +
				slg::ocl::KernelSource_plugin_gaussianblur3x3_funcs,
				"GaussianBlur3x3FilterPlugin");

		//----------------------------------------------------------------------
		// GaussianBlur3x3FilterPlugin_FilterX kernel
		//----------------------------------------------------------------------

		SLG_LOG("[GaussianBlur3x3FilterPlugin] Compiling GaussianBlur3x3FilterPlugin_FilterX Kernel");
		hardwareDevice->GetKernel(program, &filterXKernel, "GaussianBlur3x3FilterPlugin_FilterX");

		// Set kernel arguments
		u_int argIndex = 0;
		hardwareDevice->SetKernelArg(filterXKernel, argIndex++, film.GetWidth());
		hardwareDevice->SetKernelArg(filterXKernel, argIndex++, film.GetHeight());
		hardwareDevice->SetKernelArg(filterXKernel, argIndex++, film.hw_IMAGEPIPELINE);
		hardwareDevice->SetKernelArg(filterXKernel, argIndex++, hwTmpBuffer);
		hardwareDevice->SetKernelArg(filterXKernel, argIndex++, weight);

		//----------------------------------------------------------------------
		// GaussianBlur3x3FilterPlugin_FilterY kernel
		//----------------------------------------------------------------------

		SLG_LOG("[GaussianBlur3x3FilterPlugin] Compiling GaussianBlur3x3FilterPlugin_FilterY Kernel");
		hardwareDevice->GetKernel(program, &filterYKernel, "GaussianBlur3x3FilterPlugin_FilterY");

		// Set kernel arguments
		argIndex = 0;
		hardwareDevice->SetKernelArg(filterYKernel, argIndex++, film.GetWidth());
		hardwareDevice->SetKernelArg(filterYKernel, argIndex++, film.GetHeight());
		hardwareDevice->SetKernelArg(filterYKernel, argIndex++, hwTmpBuffer);
		hardwareDevice->SetKernelArg(filterYKernel, argIndex++, film.hw_IMAGEPIPELINE);
		hardwareDevice->SetKernelArg(filterYKernel, argIndex++, weight);

		//----------------------------------------------------------------------

		delete program;

		const double tEnd = WallClockTime();
		SLG_LOG("[GaussianBlur3x3FilterPlugin] Kernels compilation time: " << int((tEnd - tStart) * 1000.0) << "ms");

		film.ctx->SetVerbose(false);
	}

	for (u_int i = 0; i < 3; ++i) {
		hardwareDevice->EnqueueKernel(filterXKernel, HardwareDeviceRange(RoundUp(height, 256u)),
			HardwareDeviceRange(256));
		hardwareDevice->EnqueueKernel(filterYKernel, HardwareDeviceRange(RoundUp(width, 256u)),
			HardwareDeviceRange(256));
	}
}


//==============================================================================
//         Copyright 2003 - 2011 LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 - 2011 LRI    UMR 8623 CNRS/Univ Paris Sud XI
//         Copyright 2012 - 2014 MetaScale SAS
//
//          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 BOOST_SIMD_REDUCTION_FUNCTIONS_SIMD_COMMON_NBTRUE_HPP_INCLUDED
#define BOOST_SIMD_REDUCTION_FUNCTIONS_SIMD_COMMON_NBTRUE_HPP_INCLUDED

#include <boost/simd/reduction/functions/nbtrue.hpp>
#include <boost/simd/include/functions/simd/if_one_else_zero.hpp>
#include <boost/simd/include/functions/simd/sum.hpp>
#include <boost/simd/sdk/meta/scalar_of.hpp>
#include <boost/simd/sdk/meta/as_arithmetic.hpp>
#include <boost/dispatch/attributes.hpp>

namespace boost { namespace simd { namespace ext
{
  BOOST_DISPATCH_IMPLEMENT          ( nbtrue_, tag::cpu_
                                    , (A0)(X)
                                    , ((simd_<unspecified_<A0>,X>))
                                    )
  {
    typedef typename meta::as_arithmetic<A0>::type arith_t;
    typedef typename meta::scalar_of<arith_t>::type result_type;

    BOOST_FORCEINLINE BOOST_SIMD_FUNCTOR_CALL(1)
    {
      return sum(if_one_else_zero(a0));
    }
  };

  BOOST_DISPATCH_IMPLEMENT          ( nbtrue_, tag::cpu_
                                    , (A0)(A1)(X)
                                    , ((simd_<unspecified_<A0>,X>))
                                      (scalar_< integer_<A1> > )
                                    )
  {
    typedef typename meta::as_arithmetic<A0>::type arith_t;
    typedef typename meta::scalar_of<arith_t>::type result_type;

    BOOST_FORCEINLINE result_type operator()(A0 const & a0, A1 const &) const
    {
      return sum(if_one_else_zero(a0));
    }
  };
} } }

#endif


#pragma once
#include <Eigen/Core>
#include <ct/reflect.hpp>

namespace aq
{
template <class T>
struct Circle
{

    Circle(T x = 0.0, T y = 0.0, T rad = 0) : origin(x, y), radius(rad) {}

    Circle(Eigen::Matrix<T, 2, 1> og, T rad = 0.0) : origin(og), radius(rad) {}

    bool operator==(const aq::Circle<float>& other) { return origin == other.origin && radius == other.radius; }
    Eigen::Matrix<T, 2, 1> origin;
    T radius;
};
}

namespace ct
{
REFLECT_TEMPLATED_START(aq::Circle)
    PUBLIC_ACCESS(radius)
// PUBLIC_ACCESS(origin)
REFLECT_END;

}


#define BOOST_TEST_MODULE pcraster dal matrix_dimensions
#include <boost/test/unit_test.hpp>
#include "dal_MatrixDimensions.h"

BOOST_AUTO_TEST_CASE(test_)
{
  using namespace dal;

  // Default.
  {
    MatrixDimensions matrix;

    BOOST_CHECK_EQUAL(matrix.nrRows(), size_t(1));
    BOOST_CHECK_EQUAL(matrix.nrCols(), size_t(1));
    BOOST_CHECK_EQUAL(matrix.nrCells(), size_t(1));
  }

  // Non-default.
  {
    MatrixDimensions matrix(3, 4);

    BOOST_CHECK_EQUAL(matrix.nrRows(), size_t(3));
    BOOST_CHECK_EQUAL(matrix.nrCols(), size_t(4));
    BOOST_CHECK_EQUAL(matrix.nrCells(), size_t(12));
  }

  // Copy.
  {
    MatrixDimensions matrix1(3, 4);

    MatrixDimensions matrix2(matrix1);
    BOOST_CHECK_EQUAL(matrix2.nrRows(), size_t(3));
    BOOST_CHECK_EQUAL(matrix2.nrCols(), size_t(4));

    MatrixDimensions matrix3 = matrix1;
    BOOST_CHECK_EQUAL(matrix3.nrRows(), size_t(3));
    BOOST_CHECK_EQUAL(matrix3.nrCols(), size_t(4));
  }

  // Equality.
  {
    MatrixDimensions matrix1(3, 4), matrix2(4, 3), matrix3(3, 4);

    BOOST_CHECK(matrix1 == matrix1);
    BOOST_CHECK(matrix1 != matrix2);
    BOOST_CHECK(matrix1 == matrix3);
  }
}


//
// Created by peter on 19-5-20.
//

#ifndef MINESWEEPER_CHECKERBOARD_HPP
#define MINESWEEPER_CHECKERBOARD_HPP

#include <set>
#include <utility>
#include <boost/multi_array.hpp>
#include "ClickResult.hpp"

namespace minesweeper
{
	class Checkerboard
	{
		public:
			using coordinate_type = int;
			using mine_set_type = std::set<std::pair<coordinate_type, coordinate_type>>;
			using checker_board_type = boost::multi_array<int, 2>;
			using size_type = size_t;

			static constexpr const int INIT = -1;
			static constexpr const int MINE = -2;
			static constexpr const int FLAG = -3;

		private:
			coordinate_type height; ///< height of the checkerboard
			coordinate_type width; ///< width of the checkerboard
			mine_set_type mine_set; ///< set of the coordinate of the grids contain mine
			const size_type mine_num;
			checker_board_type checker_board;
			bool has_init = false;

		public:
			Checkerboard(coordinate_type height, coordinate_type width);
			Checkerboard(coordinate_type height, coordinate_type width, size_type mine_num);

			coordinate_type get_width() const
			{
				return width;
			}

			coordinate_type get_height() const
			{
				return height;
			}

			size_type get_mine_num() const
			{
				return mine_num;
			}

			checker_board_type get_uncovered_checkerboard_detail() const;

			const checker_board_type& get_covered_checkerboard_detail() const;

			ClickResult click_on(coordinate_type click_x, coordinate_type click_y);

			ClickResult set_flag(coordinate_type click_x, coordinate_type click_y);

			bool is_in_bound(coordinate_type x, coordinate_type y) const;

			size_type get_mine_count_nearby(int x, int y) const;

	};
}

#endif //MINESWEEPER_CHECKERBOARD_HPP


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

#include "open3d/pipelines/registration/Registration.h"

#include <benchmark/benchmark.h>

#include <Eigen/Eigen>

#include "open3d/data/Dataset.h"
#include "open3d/geometry/KDTreeFlann.h"
#include "open3d/geometry/PointCloud.h"
#include "open3d/io/PointCloudIO.h"
#include "open3d/pipelines/registration/TransformationEstimation.h"
#include "open3d/utility/Logging.h"

namespace open3d {
namespace pipelines {
namespace registration {

// Testing parameters:
// ICP ConvergenceCriteria.
static const double relative_fitness = 1e-6;
static const double relative_rmse = 1e-6;
static const int max_iterations = 30;

// NNS parameter.
static const double max_correspondence_distance = 0.05;

static std::tuple<geometry::PointCloud, geometry::PointCloud> LoadPointCloud(
        const std::string& source_filename,
        const std::string& target_filename,
        const double voxel_downsample_factor) {
    geometry::PointCloud source;
    geometry::PointCloud target;

    io::ReadPointCloud(source_filename, source, {"auto", false, false, true});
    io::ReadPointCloud(target_filename, target, {"auto", false, false, true});

    // Eliminates the case of impractical values (including negative).
    if (voxel_downsample_factor > 0.001) {
        source = *source.VoxelDownSample(voxel_downsample_factor);
        target = *target.VoxelDownSample(voxel_downsample_factor);
    } else {
        utility::LogWarning(
                " VoxelDownsample: Impractical voxel size [< 0.001], skiping "
                "downsampling.");
    }

    return std::make_tuple(source, target);
}

static void BenchmarkICPLegacy(benchmark::State& state,
                               const TransformationEstimationType& type) {
    data::DemoICPPointClouds demo_icp_pointclouds;
    geometry::PointCloud source, target;
    std::tie(source, target) = LoadPointCloud(
            demo_icp_pointclouds.GetPaths(0), demo_icp_pointclouds.GetPaths(1),
            /*voxel_downsampling_factor =*/0.02);

    std::shared_ptr<TransformationEstimation> estimation;
    if (type == TransformationEstimationType::PointToPlane) {
        estimation = std::make_shared<TransformationEstimationPointToPlane>();
    } else if (type == TransformationEstimationType::PointToPoint) {
        estimation = std::make_shared<TransformationEstimationPointToPoint>();
    }

    Eigen::Matrix4d init_trans;
    init_trans << 0.862, 0.011, -0.507, 0.5, -0.139, 0.967, -0.215, 0.7, 0.487,
            0.255, 0.835, -1.4, 0.0, 0.0, 0.0, 1.0;

    RegistrationResult reg_result(init_trans);
    // Warm up.
    reg_result = RegistrationICP(
            source, target, max_correspondence_distance, init_trans,
            *estimation,
            ICPConvergenceCriteria(relative_fitness, relative_rmse,
                                   max_iterations));
    for (auto _ : state) {
        reg_result = RegistrationICP(
                source, target, max_correspondence_distance, init_trans,
                *estimation,
                ICPConvergenceCriteria(relative_fitness, relative_rmse,
                                       max_iterations));
    }

    utility::LogDebug(" Max iterations: {}, Max_correspondence_distance : {}",
                      max_iterations, max_correspondence_distance);
    utility::LogDebug(" Fitness: {}  Inlier RMSE: {}", reg_result.fitness_,
                      reg_result.inlier_rmse_);
}

BENCHMARK_CAPTURE(BenchmarkICPLegacy,
                  PointToPlane / CPU,
                  TransformationEstimationType::PointToPlane)
        ->Unit(benchmark::kMillisecond);

BENCHMARK_CAPTURE(BenchmarkICPLegacy,
                  PointToPoint / CPU,
                  TransformationEstimationType::PointToPoint)
        ->Unit(benchmark::kMillisecond);

}  // namespace registration
}  // namespace pipelines
}  // namespace open3d


#include <iostream>
#include <armadillo>

using namespace std;
using namespace arma;

int main()
{

    int sx = 200;
    int nx= 400;
    int offset = 100;

    arma::Col<float> geo_line_all(nx,fill::zeros);
    arma::Col<float> geo_line(offset*2,fill::zeros);

    geo_line_all.load("./surface_all.dat",raw_binary);

for(int ix=0; ix<offset; ix++)
{
    geo_line(ix*2) = ix;
    geo_line(ix*2+1) = geo_line_all(sx-offset/2+ix);
}

    geo_line.save("./surface_singal_ASCII.dat",raw_ascii);

    return 0;
}


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

#ifndef BOOST_MATH_COMPLEX_DETAILS_INCLUDED
#define BOOST_MATH_COMPLEX_DETAILS_INCLUDED
//
// This header contains all the support code that is common to the
// inverse trig complex functions, it also contains all the includes
// that we need to implement all these functions.
//
#include <boost/detail/workaround.hpp>
#include <boost/config.hpp>
#include <boost/config/no_tr1/complex.hpp>
#include <boost/limits.hpp>
#include <math.h> // isnan where available
#include <cmath>

#ifdef BOOST_NO_STDC_NAMESPACE
namespace std{ using ::sqrt; }
#endif

namespace boost{ namespace math{ namespace detail{

template <class T>
inline bool test_is_nan(T t)
{
   // Comparisons with Nan's always fail:
   return std::numeric_limits<T>::has_infinity && (!(t <= std::numeric_limits<T>::infinity()) || !(t >= -std::numeric_limits<T>::infinity()));
}
#ifdef isnan
template<> inline bool test_is_nan<float>(float t) { return isnan(t); }
template<> inline bool test_is_nan<double>(double t) { return isnan(t); }
template<> inline bool test_is_nan<long double>(long double t) { return isnan(t); }
#endif

template <class T>
inline T mult_minus_one(const T& t)
{
   return test_is_nan(t) ? t : -t;
}

template <class T>
inline std::complex<T> mult_i(const std::complex<T>& t)
{
   return std::complex<T>(mult_minus_one(t.imag()), t.real());
}

template <class T>
inline std::complex<T> mult_minus_i(const std::complex<T>& t)
{
   return std::complex<T>(t.imag(), mult_minus_one(t.real()));
}

template <class T>
inline T safe_max(T t)
{
   return std::sqrt((std::numeric_limits<T>::max)()) / t;
}
inline long double safe_max(long double t)
{
   // long double sqrt often returns infinity due to
   // insufficient internal precision:
   return std::sqrt((std::numeric_limits<double>::max)()) / t;
}
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
// workaround for type deduction bug:
inline float safe_max(float t)
{
   return std::sqrt((std::numeric_limits<float>::max)()) / t;
}
inline double safe_max(double t)
{
   return std::sqrt((std::numeric_limits<double>::max)()) / t;
}
#endif
template <class T>
inline T safe_min(T t)
{
   return std::sqrt((std::numeric_limits<T>::min)()) * t;
}
inline long double safe_min(long double t)
{
   // long double sqrt often returns zero due to
   // insufficient internal precision:
   return std::sqrt((std::numeric_limits<double>::min)()) * t;
}
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
// type deduction workaround:
inline double safe_min(double t)
{
   return std::sqrt((std::numeric_limits<double>::min)()) * t;
}
inline float safe_min(float t)
{
   return std::sqrt((std::numeric_limits<float>::min)()) * t;
}
#endif

} } } // namespaces

#endif // BOOST_MATH_COMPLEX_DETAILS_INCLUDED


//
// Copyright (c) 2019 INRIA
//

#ifndef __pinocchio_multibody_joint_joint_common_operations_hpp__
#define __pinocchio_multibody_joint_joint_common_operations_hpp__

#include "pinocchio/macros.hpp"
#include "pinocchio/math/matrix.hpp"

#include <boost/type_traits.hpp>

namespace pinocchio
{
  namespace internal
  {
    ///
    /// \brief Operation called in JointModelBase<JointModel>::calc_aba
    ///
    template<typename Scalar, bool is_floating_point = boost::is_floating_point<Scalar>::value>
    struct PerformStYSInversion
    {
      template<typename M1, typename M2>
      static EIGEN_STRONG_INLINE
      void run(const Eigen::MatrixBase<M1> & StYS,
               const Eigen::MatrixBase<M2> & Dinv)
      {
        M2 & Dinv_ = PINOCCHIO_EIGEN_CONST_CAST(M2,Dinv);
        Dinv_.setIdentity();
        StYS.llt().solveInPlace(Dinv_);
      }
    };

    template<typename Scalar>
    struct PerformStYSInversion<Scalar, false>
    {
      template<typename M1, typename M2>
      static EIGEN_STRONG_INLINE
      void run(const Eigen::MatrixBase<M1> & StYS,
               const Eigen::MatrixBase<M2> & Dinv)
      {
        M2 & Dinv_ = PINOCCHIO_EIGEN_CONST_CAST(M2,Dinv);
        inverse(StYS,Dinv_);
      }
    };
  }

  ///
  /// \brief Linear affine transformation of the configuration vector.
  ///        Valide for most common joints which are evolving on a vectorial space.
  ///
  struct LinearAffineTransform
  {
    template<typename ConfigVectorIn, typename Scalar, typename ConfigVectorOut>
    static void run(const Eigen::MatrixBase<ConfigVectorIn> & q,
                    const Scalar & scaling,
                    const Scalar & offset,
                    const Eigen::MatrixBase<ConfigVectorOut> & dest)
    {
      assert(q.size() == dest.size());
      PINOCCHIO_EIGEN_CONST_CAST(ConfigVectorOut,dest).noalias() = scaling * q + ConfigVectorOut::Constant(dest.size(),offset);
    }
  };

  ///
  /// \brief Assign the correct configuration vector space affine transformation according to the joint type.
  ///
  template<typename Joint>
  struct ConfigVectorAffineTransform
  {
    typedef LinearAffineTransform Type;
  };

}

#endif // ifndef __pinocchio_multibody_joint_joint_common_operations_hpp__


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

// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2008-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.

// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.

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

#ifndef BOOST_GEOMETRY_ARITHMETIC_ARITHMETIC_HPP
#define BOOST_GEOMETRY_ARITHMETIC_ARITHMETIC_HPP

#include <functional>

#include <boost/call_traits.hpp>
#include <boost/concept/requires.hpp>

#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/geometries/concepts/point_concept.hpp>
#include <boost/geometry/util/for_each_coordinate.hpp>
#include <boost/geometry/util/select_most_precise.hpp>

namespace geofeatures_boost {} namespace boost = geofeatures_boost; namespace geofeatures_boost { namespace geometry
{

#ifndef DOXYGEN_NO_DETAIL
namespace detail
{

template <typename Point>
struct param
{
    typedef typename geofeatures_boost::call_traits
        <
            typename coordinate_type<Point>::type
        >::param_type type;
};

template <typename Value, template <typename> class Function>
struct value_operation
{
    Value m_value;

    inline value_operation(Value const &value)
        : m_value(value)
    {}

    template <typename PointDst, std::size_t Index>
    inline void apply(PointDst& point_dst) const
    {
        set<Index>(point_dst,
               Function
                <
                    typename geometry::select_most_precise
                        <
                            Value,
                            typename geometry::coordinate_type<PointDst>::type
                        >::type
                >()(get<Index>(point_dst), m_value));
    }
};

template <typename PointSrc, template <typename> class Function>
struct point_operation
{
    PointSrc const& m_point_src;

    inline point_operation(PointSrc const& point)
        : m_point_src(point)
    {}

    template <typename PointDst, std::size_t Index>
    inline void apply(PointDst& point_dst) const
    {
        set<Index>(point_dst,
               Function
                <
                    typename geometry::select_most_precise
                        <
                            typename geometry::coordinate_type<PointSrc>::type,
                            typename geometry::coordinate_type<PointDst>::type
                        >::type
                >()(get<Index>(point_dst), get<Index>(m_point_src)));
    }
};

template <typename Value>
struct value_assignment
{
    Value m_value;

    inline value_assignment(Value const &value)
        : m_value(value)
    {}

    template <typename PointDst, std::size_t Index>
    inline void apply(PointDst& point_dst) const
    {
        set<Index>(point_dst, m_value);
    }
};

template <typename PointSrc>
struct point_assignment
{
    PointSrc const& m_point_src;

    inline point_assignment(PointSrc const& point)
        : m_point_src(point)
    {}

    template <typename PointDst, std::size_t Index>
    inline void apply(PointDst& point_dst) const
    {
        set<Index>(point_dst, get<Index>(m_point_src));
    }
};

} // namespace detail
#endif // DOXYGEN_NO_DETAIL

/*!
    \brief Adds the same value to each coordinate of a point
    \ingroup arithmetic
    \details
    \tparam Point \tparam_point
    \param p point
    \param value value to add
 */
template <typename Point>
inline void add_value(Point& p, typename detail::param<Point>::type value)
{
    BOOST_CONCEPT_ASSERT( (concept::Point<Point>) );

    for_each_coordinate(p,
                        detail::value_operation
                            <
                                typename coordinate_type<Point>::type,
                                std::plus
                            >(value));
}

/*!
    \brief Adds a point to another
    \ingroup arithmetic
    \details The coordinates of the second point will be added to those of the first point.
             The second point is not modified.
    \tparam Point1 \tparam_point
    \tparam Point2 \tparam_point
    \param p1 first point
    \param p2 second point
 */
template <typename Point1, typename Point2>
inline void add_point(Point1& p1, Point2 const& p2)
{
    BOOST_CONCEPT_ASSERT( (concept::Point<Point1>) );
    BOOST_CONCEPT_ASSERT( (concept::ConstPoint<Point2>) );

    for_each_coordinate(p1, detail::point_operation<Point2, std::plus>(p2));
}

/*!
    \brief Subtracts the same value to each coordinate of a point
    \ingroup arithmetic
    \details
    \tparam Point \tparam_point
    \param p point
    \param value value to subtract
 */
template <typename Point>
inline void subtract_value(Point& p, typename detail::param<Point>::type value)
{
    BOOST_CONCEPT_ASSERT( (concept::Point<Point>) );

    for_each_coordinate(p,
                        detail::value_operation
                            <
                                typename coordinate_type<Point>::type,
                                std::minus
                            >(value));
}

/*!
    \brief Subtracts a point to another
    \ingroup arithmetic
    \details The coordinates of the second point will be subtracted to those of the first point.
             The second point is not modified.
    \tparam Point1 \tparam_point
    \tparam Point2 \tparam_point
    \param p1 first point
    \param p2 second point
 */
template <typename Point1, typename Point2>
inline void subtract_point(Point1& p1, Point2 const& p2)
{
    BOOST_CONCEPT_ASSERT( (concept::Point<Point1>) );
    BOOST_CONCEPT_ASSERT( (concept::ConstPoint<Point2>) );

    for_each_coordinate(p1, detail::point_operation<Point2, std::minus>(p2));
}

/*!
    \brief Multiplies each coordinate of a point by the same value
    \ingroup arithmetic
    \details
    \tparam Point \tparam_point
    \param p point
    \param value value to multiply by
 */
template <typename Point>
inline void multiply_value(Point& p, typename detail::param<Point>::type value)
{
    BOOST_CONCEPT_ASSERT( (concept::Point<Point>) );

    for_each_coordinate(p,
                        detail::value_operation
                            <
                                typename coordinate_type<Point>::type,
                                std::multiplies
                            >(value));
}

/*!
    \brief Multiplies a point by another
    \ingroup arithmetic
    \details The coordinates of the first point will be multiplied by those of the second point.
             The second point is not modified.
    \tparam Point1 \tparam_point
    \tparam Point2 \tparam_point
    \param p1 first point
    \param p2 second point
    \note This is *not* a dot, cross or wedge product. It is a mere field-by-field multiplication.
 */
template <typename Point1, typename Point2>
inline void multiply_point(Point1& p1, Point2 const& p2)
{
    BOOST_CONCEPT_ASSERT( (concept::Point<Point1>) );
    BOOST_CONCEPT_ASSERT( (concept::ConstPoint<Point2>) );

    for_each_coordinate(p1, detail::point_operation<Point2, std::multiplies>(p2));
}

/*!
    \brief Divides each coordinate of the same point by a value
    \ingroup arithmetic
    \details
    \tparam Point \tparam_point
    \param p point
    \param value value to divide by
 */
template <typename Point>
inline void divide_value(Point& p, typename detail::param<Point>::type value)
{
    BOOST_CONCEPT_ASSERT( (concept::Point<Point>) );

    for_each_coordinate(p,
                        detail::value_operation
                            <
                                typename coordinate_type<Point>::type,
                                std::divides
                            >(value));
}

/*!
    \brief Divides a point by another
    \ingroup arithmetic
    \details The coordinates of the first point will be divided by those of the second point.
             The second point is not modified.
    \tparam Point1 \tparam_point
    \tparam Point2 \tparam_point
    \param p1 first point
    \param p2 second point
 */
template <typename Point1, typename Point2>
inline void divide_point(Point1& p1, Point2 const& p2)
{
    BOOST_CONCEPT_ASSERT( (concept::Point<Point1>) );
    BOOST_CONCEPT_ASSERT( (concept::ConstPoint<Point2>) );

    for_each_coordinate(p1, detail::point_operation<Point2, std::divides>(p2));
}

/*!
    \brief Assign each coordinate of a point the same value
    \ingroup arithmetic
    \details
    \tparam Point \tparam_point
    \param p point
    \param value value to assign
 */
template <typename Point>
inline void assign_value(Point& p, typename detail::param<Point>::type value)
{
    BOOST_CONCEPT_ASSERT( (concept::Point<Point>) );

    for_each_coordinate(p,
                        detail::value_assignment
                            <
                                typename coordinate_type<Point>::type
                            >(value));
}

/*!
    \brief Assign a point with another
    \ingroup arithmetic
    \details The coordinates of the first point will be assigned those of the second point.
             The second point is not modified.
    \tparam Point1 \tparam_point
    \tparam Point2 \tparam_point
    \param p1 first point
    \param p2 second point
 */
template <typename Point1, typename Point2>
inline void assign_point(Point1& p1, Point2 const& p2)
{
    BOOST_CONCEPT_ASSERT( (concept::Point<Point1>) );
    BOOST_CONCEPT_ASSERT( (concept::ConstPoint<Point2>) );

    for_each_coordinate(p1, detail::point_assignment<Point2>(p2));
}

}} // namespace geofeatures_boost::geometry

#endif // BOOST_GEOMETRY_ARITHMETIC_ARITHMETIC_HPP


// Copyright Louis Dionne 2013-2016
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)

<% if input_size > 10 %>
    #define FUSION_MAX_VECTOR_SIZE <%= ((input_size + 9) / 10) * 10 %>
<% end %>

#include <boost/fusion/include/count_if.hpp>
#include <boost/fusion/include/make_vector.hpp>

#include <boost/hana/equal.hpp>
#include <boost/hana/integral_constant.hpp>
#include <boost/hana/mod.hpp>
namespace fusion = boost::fusion;
namespace hana = boost::hana;

struct is_even {
    template <typename N>
    constexpr auto operator()(N n) const {
        return n % hana::int_c<2> == hana::int_c<0>;
    }
};

int main() {
    auto ints = fusion::make_vector(
        <%= (1..input_size).map { |n| "hana::int_c<#{n}>" }.join(', ') %>
    );
    auto result = fusion::count_if(ints, is_even{});
    (void)result;
}


//==================================================================================================
/*!
  @file

  @copyright 2016 NumScale SAS
  @copyright 2016 J.T. Lapreste

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
//==================================================================================================
#ifndef BOOST_SIMD_ARCH_COMMON_SIMD_FUNCTION_SUBS_HPP_INCLUDED
#define BOOST_SIMD_ARCH_COMMON_SIMD_FUNCTION_SUBS_HPP_INCLUDED
#include <boost/simd/detail/overload.hpp>

#include <boost/simd/meta/hierarchy/simd.hpp>
#include <boost/simd/constant/valmax.hpp>
#include <boost/simd/constant/zero.hpp>
#include <boost/simd/function/simd/bitwise_and.hpp>
#include <boost/simd/function/simd/bitwise_cast.hpp>
#include <boost/simd/function/simd/bitwise_xor.hpp>
#include <boost/simd/function/simd/if_else.hpp>
#include <boost/simd/function/simd/if_else_zero.hpp>
#include <boost/simd/function/simd/is_less_equal.hpp>
#include <boost/simd/function/simd/minus.hpp>
#include <boost/simd/function/simd/plus.hpp>
#include <boost/simd/function/simd/shr.hpp>
#include <boost/simd/function/simd/splat.hpp>
#include <boost/dispatch/meta/scalar_of.hpp>

namespace boost { namespace simd { namespace ext
{
   namespace bd = boost::dispatch;
   namespace bs = boost::simd;
   BOOST_DISPATCH_OVERLOAD(subs_
                          , (typename A0, typename X)
                          , bd::cpu_
                          , bs::pack_<bd::floating_<A0>, X>
                          , bs::pack_<bd::floating_<A0>, X>
                          )
   {
      BOOST_FORCEINLINE A0 operator()( const A0& a0, const A0& a1) const BOOST_NOEXCEPT
      {
        return a0-a1;
      }
   };

   BOOST_DISPATCH_OVERLOAD(subs_
                          , (typename A0, typename X)
                          , bd::cpu_
                          , bs::pack_<bd::uint_<A0>, X>
                          , bs::pack_<bd::uint_<A0>, X>
                          )
   {
      BOOST_FORCEINLINE A0 operator()( const A0& a0, const A0& a1) const BOOST_NOEXCEPT
      {
        A0 a0ma1 = a0-a1;
        return if_else_zero(is_less_equal(a0ma1, a0), a0ma1);
      }
   };

   BOOST_DISPATCH_OVERLOAD(subs_
                          , (typename A0, typename X)
                          , bd::cpu_
                          , bs::pack_<bd::int_<A0>, X>
                          , bs::pack_<bd::int_<A0>, X>
                          )
   {
      BOOST_FORCEINLINE A0 operator()( const A0& a0, const A0& a1) const BOOST_NOEXCEPT
      {
        using utype = bd::as_unsigned_t<A0>;
        using stype = bd::scalar_of_t<A0>;
        utype ux = bitwise_cast<utype>(a0);
        utype uy = bitwise_cast<utype>(a1);
        utype res = ux - uy;
        ux = shr(ux, sizeof(stype)*CHAR_BIT-1) + splat<utype>(Valmax<stype>());
        return bitwise_cast<A0>(if_else(is_ltz(bitwise_cast<A0>(bitwise_and(bitwise_xor(ux,uy)
                                                                           , (bitwise_xor(ux,res))))
                                              )
                                       , ux
                                       , res)
                               );
      }
   };

} } }

#endif