<commit_before>/*****************************************************************************
 *
 * GARGOYLE_PSCAND: Gargoyle - Protection for Linux
 *
 * Program to test a given regex against a set of log data
 *
 * Copyright (c) 2017, Bayshore Networks, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that
 * the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
 * following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
 * following disclaimer in the documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
 * products derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *****************************************************************************/
#include <iostream>
#include <string>
#include <fstream>
#include <regex>
#include <vector>

#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#include "system_functions.h"

//std::vector<std::string> sshd_regexes;
size_t line_cnt = 0;
size_t regex_num_hits = 0;
size_t valid_ip_addr_cnt = 0;
std::vector<std::string> valid_ip_addr;

bool validate_ip_address(const std::string &);
bool valid_ip_addr_exists(const std::string &);
std::string hunt_for_ip_addr(std::string);
void do_regex_check(const std::string &, const std::regex &);
void add_valid_ip_addr(const std::string &);
void display_valid_ip_addr();

bool validate_ip_address(const std::string &ip_address) {
	struct sockaddr_in sa;
	int result = inet_pton(AF_INET, ip_address.c_str(), &(sa.sin_addr));
	return result != 0;
}

bool valid_ip_addr_exists(const std::string &ip_addr) {
	if(std::find(valid_ip_addr.begin(), valid_ip_addr.end(), ip_addr) != valid_ip_addr.end())
		return true;
	return false;
}

std::string hunt_for_ip_addr(const std::string &line, const char& c) {

	std::string resp = "";
	std::string buff{""};

	for(auto n:line)
	{
		if(n != c) {
			buff+=n;
		} else {
			if(n == c && buff != "") {
				if (validate_ip_address(buff))
					return buff;
				buff = "";
			}
		}
	}
	return resp;
}

void do_regex_check(const std::string &line, const std::regex &l_regex) {

	line_cnt++;
	std::smatch match;

	if (std::regex_search(line, match, l_regex)) {

		regex_num_hits++;
		/*
		std::cout << "MATCH SIZE: " << match.size() << std::endl;
		std::cout << "MATCH 0: " << match.str(0) << std::endl;
		std::cout << "MATCH 1: " << match.str(1) << std::endl;
		*/
		std::string ip_addr = match.str(1);
		//std::cout << "IP: " << ip_addr << std::endl;

		if (validate_ip_address(ip_addr)) {

			//std::cout << "VALID IP ADDR MATCH: " << ip_addr << std::endl;
			add_valid_ip_addr(ip_addr);
			valid_ip_addr_cnt++;

		} else {

			std::string hip = hunt_for_ip_addr(ip_addr, ' ');

			// the hack found an ip addr
			if (hip.size()) {

				//std::cout << "HIP IP ADDR MATCH: " << hip << std::endl;
				if (validate_ip_address(hip)) {

					//std::cout << "VALID IP ADDR MATCH [HIP]: " << hip << std::endl;
					add_valid_ip_addr(hip);
					valid_ip_addr_cnt++;

				}

			}

		}

	} else {

		//std::cout << "No regex hit" << std::endl;

	}

	//std::cout << std::endl;

}

void add_valid_ip_addr(const std::string &ip_addr) {

	if (!valid_ip_addr_exists(ip_addr))
		valid_ip_addr.push_back(ip_addr);

}

void display_valid_ip_addr() {

	std::cout << "Unique list of valid IP ADDRs discovered:" << std::endl << "-----------------" << std::endl;
	for (auto& it : valid_ip_addr) {
		std::cout << it << std::endl;
	}

}

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

	std::string log_entity = "";
	std::string regex_str = "";
	int c;
	bool using_file = false;

	while ((c = getopt(argc, argv, "r:l:")) != -1)
		switch (c) {
		case 'r':
			regex_str = optarg;
			break;
		case 'l':
			log_entity = optarg;
			break;
		case '?':
			std::cout << std::endl << "Problem with args dude ..." << std::endl << std::endl;
			break;
		}

	/*
	std::cout << std::endl;
	std::cout << log_entity << std::endl;
	std::cout << regex_str << std::endl;

	std::cout << std::endl;
	*/

	if (does_file_exist(log_entity.c_str())) {
		using_file = true;
	}

	// if file ....
	//std::ifstream ifs(log_entity.c_str(), std::ios::ate);
    // remember file position
    //std::ios::streampos gpos = ifs.tellg();

    std::string line;

	try {

		std::regex l_regex(regex_str);

		// working with one target string, not file
		if (!using_file) {

			do_regex_check(log_entity, l_regex);

		} else {

			// iterate on file line by line
			std::ifstream inf(log_entity);

			if(!inf) {
				std::cout << std::endl << "Cannot open input file: " << log_entity << std::endl << std::endl;
				return 1;
			}

			char str[512];

			while(inf) {
				inf.getline(str, 512);
				if(inf) {

					do_regex_check(str, l_regex);
					//std::cout << str << std::endl;

				}
			}

			inf.close();
		}

	} catch (std::regex_error& e) {

		std::cout << std::endl << "Regex exception: " << e.what() << std::endl;
		std::cout << "Regex exception code is: " << e.code() << std::endl;
		std::cout << "Cannot continue ..." << std::endl << std::endl;
		return 1;

	}

	std::cout << std::endl << "Results" << std::endl << "=======" << std::endl << std::endl;

	std::cout << "Entity scanned is a ";
	if (using_file)
		std::cout << "file named ";
	else
		std::cout << "string: ";
	std::cout << "\"" << log_entity << "\"" << std::endl;

	if (using_file) {
		std::cout << line_cnt << " lines were consumed and scanned" << std::endl;
	}

	std::cout << "Regex used: " << regex_str << std::endl;
	std::cout << "Number of hits for this regex: " << regex_num_hits << std::endl;
	std::cout << "Number of valid IP ADDRs from regex hits: " << valid_ip_addr_cnt << std::endl;

	std::cout << std::endl;
	if (valid_ip_addr.size()) {
		display_valid_ip_addr();
	}
	std::cout << std::endl << std::endl;

	return 0;
}

<commit_msg>regex tester - enlarging buffer size for each line consumed when scanning file data<commit_after>/*****************************************************************************
 *
 * GARGOYLE_PSCAND: Gargoyle - Protection for Linux
 *
 * Program to test a given regex against a set of log data
 *
 * Copyright (c) 2017, Bayshore Networks, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that
 * the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
 * following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
 * following disclaimer in the documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
 * products derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *****************************************************************************/
#include <iostream>
#include <string>
#include <fstream>
#include <regex>
#include <vector>

#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#include "system_functions.h"

//std::vector<std::string> sshd_regexes;
size_t line_sz = 2048;
size_t line_cnt = 0;
size_t regex_num_hits = 0;
size_t valid_ip_addr_cnt = 0;
std::vector<std::string> valid_ip_addr;

bool validate_ip_address(const std::string &);
bool valid_ip_addr_exists(const std::string &);
std::string hunt_for_ip_addr(std::string);
void do_regex_check(const std::string &, const std::regex &);
void add_valid_ip_addr(const std::string &);
void display_valid_ip_addr();

bool validate_ip_address(const std::string &ip_address) {
	struct sockaddr_in sa;
	int result = inet_pton(AF_INET, ip_address.c_str(), &(sa.sin_addr));
	return result != 0;
}

bool valid_ip_addr_exists(const std::string &ip_addr) {
	if(std::find(valid_ip_addr.begin(), valid_ip_addr.end(), ip_addr) != valid_ip_addr.end())
		return true;
	return false;
}

std::string hunt_for_ip_addr(const std::string &line, const char& c) {

	std::string resp = "";
	std::string buff{""};

	for(auto n:line)
	{
		if(n != c) {
			buff+=n;
		} else {
			if(n == c && buff != "") {
				if (validate_ip_address(buff))
					return buff;
				buff = "";
			}
		}
	}
	return resp;
}

void do_regex_check(const std::string &line, const std::regex &l_regex) {

	line_cnt++;
	std::smatch match;

	if (std::regex_search(line, match, l_regex)) {

		regex_num_hits++;
		/*
		std::cout << "MATCH SIZE: " << match.size() << std::endl;
		std::cout << "MATCH 0: " << match.str(0) << std::endl;
		std::cout << "MATCH 1: " << match.str(1) << std::endl;
		*/
		std::string ip_addr = match.str(1);
		//std::cout << "IP: " << ip_addr << std::endl;

		if (validate_ip_address(ip_addr)) {

			//std::cout << "VALID IP ADDR MATCH: " << ip_addr << std::endl;
			add_valid_ip_addr(ip_addr);
			valid_ip_addr_cnt++;

		} else {

			std::string hip = hunt_for_ip_addr(ip_addr, ' ');

			// the hack found an ip addr
			if (hip.size()) {

				//std::cout << "HIP IP ADDR MATCH: " << hip << std::endl;
				if (validate_ip_address(hip)) {

					//std::cout << "VALID IP ADDR MATCH [HIP]: " << hip << std::endl;
					add_valid_ip_addr(hip);
					valid_ip_addr_cnt++;

				}

			}

		}

	} else {

		//std::cout << "No regex hit" << std::endl;

	}

	//std::cout << std::endl;

}

void add_valid_ip_addr(const std::string &ip_addr) {

	if (!valid_ip_addr_exists(ip_addr))
		valid_ip_addr.push_back(ip_addr);

}

void display_valid_ip_addr() {

	std::cout << "Unique list of valid IP ADDRs discovered:" << std::endl << "-----------------" << std::endl;
	for (auto& it : valid_ip_addr) {
		std::cout << it << std::endl;
	}

}

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

	std::string log_entity = "";
	std::string regex_str = "";
	int c;
	bool using_file = false;

	while ((c = getopt(argc, argv, "r:l:")) != -1)
		switch (c) {
		case 'r':
			regex_str = optarg;
			break;
		case 'l':
			log_entity = optarg;
			break;
		case '?':
			std::cout << std::endl << "Problem with args dude ..." << std::endl << std::endl;
			break;
		}

	/*
	std::cout << std::endl;
	std::cout << log_entity << std::endl;
	std::cout << regex_str << std::endl;

	std::cout << std::endl;
	*/

	if (does_file_exist(log_entity.c_str())) {
		using_file = true;
	}

	// if file ....
	//std::ifstream ifs(log_entity.c_str(), std::ios::ate);
    // remember file position
    //std::ios::streampos gpos = ifs.tellg();

    std::string line;

	try {

		std::regex l_regex(regex_str);

		// working with one target string, not file
		if (!using_file) {

			do_regex_check(log_entity, l_regex);

		} else {

			// iterate on file line by line
			std::ifstream inf(log_entity);

			if(!inf) {
				std::cout << std::endl << "Cannot open input file: " << log_entity << std::endl << std::endl;
				return 1;
			}

			char str[line_sz];

			while(inf) {
				inf.getline(str, line_sz);
				if(inf) {

					do_regex_check(str, l_regex);
					//std::cout << str << std::endl;

				}
			}

			inf.close();
		}

	} catch (std::regex_error& e) {

		std::cout << std::endl << "Regex exception: " << e.what() << std::endl;
		std::cout << "Regex exception code is: " << e.code() << std::endl;
		std::cout << "Cannot continue ..." << std::endl << std::endl;
		return 1;

	}

	std::cout << std::endl << "Results" << std::endl << "=======" << std::endl << std::endl;

	std::cout << "Entity scanned is a ";
	if (using_file)
		std::cout << "file named ";
	else
		std::cout << "string: ";
	std::cout << "\"" << log_entity << "\"" << std::endl;

	if (using_file) {
		std::cout << line_cnt << " lines were consumed and scanned" << std::endl;
	}

	std::cout << "Regex used: " << regex_str << std::endl;
	std::cout << "Number of hits for this regex: " << regex_num_hits << std::endl;
	std::cout << "Number of valid IP ADDRs from regex hits: " << valid_ip_addr_cnt << std::endl;

	std::cout << std::endl;
	if (valid_ip_addr.size()) {
		display_valid_ip_addr();
	}
	std::cout << std::endl << std::endl;

	return 0;
}

<|endoftext|>


<commit_before>#ifndef ALEPH_GEOMETRY_TANGENT_SPACE_HH__
#define ALEPH_GEOMETRY_TANGENT_SPACE_HH__

#include <aleph/config/Eigen.hh>

#include <aleph/geometry/BruteForce.hh>
#include <aleph/geometry/FLANN.hh>

#include <aleph/geometry/distances/Euclidean.hh>

#include <aleph/math/AlgebraicSphere.hh>

#ifdef ALEPH_WITH_EIGEN
  #include <Eigen/Core>
  #include <Eigen/Cholesky>
  #include <Eigen/SVD>
#endif

#include <vector>

namespace aleph
{

namespace geometry
{

namespace detail
{

/**
  Model of a smooth decreasing weight function according to the
  original paper *Algebraic Point Set Surfaces* by Guennebaud &
  Gross.
*/

template <class T> T phi( T x )
{
  return x < 1 ? std::pow( 1 - x*x, T(4) ) : T();
}

} // namespace detail

#ifdef ALEPH_WITH_EIGEN

class TangentSpace
{
public:

  using T        = double;

  using Matrix = Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>;
  using Vector = Eigen::Matrix<T, 1, Eigen::Dynamic>;

  using Sphere = math::AlgebraicSphere<T>;

#if EIGEN_VERSION_AT_LEAST(3,3,0)
  using Index = Eigen::Index;
#else
  using Index = typename Matrix::Index;
#endif

  struct LocalTangentSpace
  {
    Matrix tangents;
    Vector normal;
    Vector position;

    std::vector<std::size_t> indices;
  };

  template <class Container> std::vector<T> operator()( const Container& container )
  {
    std::vector<double> curvature;
    curvature.reserve( container.size() );

    auto lts     = localTangentSpaces( container );
    auto spheres = fitSpheres( container, lts );

    std::transform( spheres.begin(), spheres.end(), std::back_inserter( curvature ),
      [] ( const Sphere& sphere )
      {
        return sphere.meanCurvature();
      }
    );

    return curvature;
  }

  template <class Container> std::vector<LocalTangentSpace> localTangentSpaces( const Container& container )
  {
    using ElementType = typename Container::ElementType;
    using Distance    = distances::Euclidean<ElementType>;

#ifdef ALEPH_WITH_FLANN
    using NearestNeighbours = FLANN<Container, Distance>;
#else
    using NearestNeighbours = BruteForce<Container, Distance>;
#endif

    NearestNeighbours nearestNeighbours( container );
    using IndexType = typename NearestNeighbours::IndexType;

    std::vector< std::vector<IndexType> > indices;
    std::vector< std::vector<ElementType> > distances;

    // FIXME: make configurable
    unsigned k = 10;

    nearestNeighbours.neighbourSearch( k,
                                       indices,
                                       distances );

    std::vector<LocalTangentSpace> localTangentSpaces;

    auto n = container.size();
    auto d = container.dimension();

    for( std::size_t i = 0; i < n; i++ )
    {
      // This coordinate matrix will contain the differences to the
      // centroid coordinate. The matrix will be transformed via an
      // SVD.
      Matrix M = Matrix::Zero( Index(k), Index(d) );

      // Centroid calculation ------------------------------------------

      Vector centroid  = Vector::Zero(1, Index(d) );

      for( std::size_t j = 0; j < indices[i].size(); j++ )
      {
        auto&& neighbourIndex = indices[i][j];
        auto p                = container[neighbourIndex];
        Vector v              = Vector::Zero(1, Index(d) );

        // copy (and transform!) the vector; there's an implicit type
        // conversion going on here
        for( std::size_t l = 0; l < d; l++ )
          v( Index(l) ) = p[l];

        centroid          += v;
        M.row( Index(j) )  = v;
      }

      centroid /= static_cast<T>( indices.size() );

      // Coordinate matrix setup ---------------------------------------

      M = M.rowwise() - centroid;

      Eigen::JacobiSVD<Matrix> svd( M, Eigen::ComputeThinV );

      LocalTangentSpace lts;
      lts.tangents = Matrix::Zero( Index(d), Index(d - 1) );

      // The singular vectors of all but the *smallest* singular value
      // form the tangential directions of the tangent space.

      auto&& V = svd.matrixV();

      for( Index j = 0; j < Index( d - 1 ); j++ )
        lts.tangents.col(j) = V.col(j);

      lts.normal   = Matrix::Zero( Index(1), Index(d) );
      lts.normal   = V.col( Index(d-1) );
      lts.position = getPosition( container, i );
      lts.indices  = indices[i];

      localTangentSpaces.push_back( lts );

      // TODO: calculate raw approximation (reconstruction) error by
      // assessing how well the space fits the original data set
    }

    return localTangentSpaces;
  }

  template <class Container>
    std::vector<Sphere> fitSpheres( const Container& container,
                                    const std::vector<LocalTangentSpace>& localTangentSpaces )
  {
    using namespace detail;

    std::vector<Sphere> spheres;
    spheres.reserve( container.size() );

    for( auto&& lts : localTangentSpaces )
    {
      auto d = Index( container.dimension() );
      auto w = 1.0;

      Matrix A = Matrix::Zero( d+2, d+2 );
      Vector b = Vector::Zero( 1,   d+2 );

      auto&& indices = lts.indices;

      for( auto&& index : indices )
      {
        auto neighbour           = getPosition( container, index );
        auto squaredNeigbourNorm = neighbour.squaredNorm();
        auto localFeatureSize    = 1.0; // FIXME: how to obtain estimates?
        auto _beta               = 1.0; // FIXME: how to obtain estimates?
        w                        = phi( ( lts.position - neighbour ).norm() / localFeatureSize );

        A(   0,   0) += w;
        A( d+1,   0) += w * squaredNeigbourNorm;
        A( d+1, d+1) += w * squaredNeigbourNorm * squaredNeigbourNorm;

        for( Index(i) = 1; i < d+1; i++ )
        {
          A(  i,   i) += w * ( neighbour(i-1)*neighbour(i-1) + 1 ) * _beta;
          A(  i,   0) += w * ( neighbour(i-1) );
          A(d+1,   i) += w * ( neighbour(i-1)*squaredNeigbourNorm + 2 * _beta * neighbour(i-1) );
          A(d+1, d+1) += w * ( 4*neighbour(i-1)*neighbour(i-1) ) * _beta;

          // re-establish symmetry
          A(  0,   i)  = A(i,0);
          A(  i, d+1)  = A(d+1, i);

          b(i  ) +=       _beta * w * lts.normal(i-1);
          b(d+1) += 2.0 * _beta * w * lts.normal(i-1) * neighbour(i-1);

          for( Index(j) = i+1; j < d+1; j++ )
          {
            A(j, i) += w * neighbour(i-1) * neighbour(j-1);
            A(i, j)  = A(j,i);
          }
        }
      }

      // Solve the linear system ---------------------------------------
      //
      // The solution of the system Ax = b is used to obtain the
      // coefficients of the algebraic sphere.

      using Solver = Eigen::LDLT<Matrix>;
      Solver solver(A);

      Vector u = solver.solve( b.transpose() );

      spheres.emplace_back( Sphere( u.data(), u.data() + u.size() ) );
    }

    return spheres;
  }

private:

  /**
    Auxiliary function for extracting and converting a position from
    a given container, storing it as a (mathematical) vector.
  */

  template <class Container> Vector getPosition( const Container& container, std::size_t i )
  {
    auto d   = container.dimension();
    auto p   = container[i];
    Vector v = Vector::Zero(1, Index(d) );

    // copy (and transform!) the vector; there's an implicit type
    // conversion going on here
    for( std::size_t l = 0; l < d; l++ )
      v( Index(l) ) = p[l];

    return v;
  }
};

#endif

} // namespace geometry

} // namespace aleph

#endif
<commit_msg>Improved configurability<commit_after>#ifndef ALEPH_GEOMETRY_TANGENT_SPACE_HH__
#define ALEPH_GEOMETRY_TANGENT_SPACE_HH__

#include <aleph/config/Eigen.hh>

#include <aleph/geometry/BruteForce.hh>
#include <aleph/geometry/FLANN.hh>

#include <aleph/geometry/distances/Euclidean.hh>

#include <aleph/math/AlgebraicSphere.hh>

#ifdef ALEPH_WITH_EIGEN
  #include <Eigen/Core>
  #include <Eigen/Cholesky>
  #include <Eigen/SVD>
#endif

#include <vector>

namespace aleph
{

namespace geometry
{

namespace detail
{

/**
  Model of a smooth decreasing weight function according to the
  original paper *Algebraic Point Set Surfaces* by Guennebaud &
  Gross.
*/

template <class T> T phi( T x )
{
  return x < 1 ? std::pow( 1 - x*x, T(4) ) : T();
}

} // namespace detail

#ifdef ALEPH_WITH_EIGEN

class TangentSpace
{
public:

  using T        = double;

  using Matrix = Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>;
  using Vector = Eigen::Matrix<T, 1, Eigen::Dynamic>;

  using Sphere = math::AlgebraicSphere<T>;

#if EIGEN_VERSION_AT_LEAST(3,3,0)
  using Index = Eigen::Index;
#else
  using Index = typename Matrix::Index;
#endif

  struct LocalTangentSpace
  {
    Matrix tangents;
    Vector normal;
    Vector position;

    T localFeatureSize;
    std::vector<std::size_t> indices;
  };

  template <class Container> std::vector<T> operator()( const Container& container, unsigned k )
  {
    std::vector<double> curvature;
    curvature.reserve( container.size() );

    auto lts     = localTangentSpaces( container, k );
    auto spheres = fitSpheres( container, lts );

    std::transform( spheres.begin(), spheres.end(), std::back_inserter( curvature ),
      [] ( const Sphere& sphere )
      {
        return sphere.meanCurvature();
      }
    );

    return curvature;
  }

  template <class Container> std::vector<LocalTangentSpace> localTangentSpaces( const Container& container, unsigned k )
  {
    using ElementType = typename Container::ElementType;
    using Distance    = distances::Euclidean<ElementType>;

#ifdef ALEPH_WITH_FLANN
    using NearestNeighbours = FLANN<Container, Distance>;
#else
    using NearestNeighbours = BruteForce<Container, Distance>;
#endif

    NearestNeighbours nearestNeighbours( container );
    using IndexType = typename NearestNeighbours::IndexType;

    std::vector< std::vector<IndexType> > indices;
    std::vector< std::vector<ElementType> > distances;

    nearestNeighbours.neighbourSearch( k,
                                       indices,
                                       distances );

    std::vector<LocalTangentSpace> localTangentSpaces;

    auto n = container.size();
    auto d = container.dimension();

    for( std::size_t i = 0; i < n; i++ )
    {
      // This coordinate matrix will contain the differences to the
      // centroid coordinate. The matrix will be transformed via an
      // SVD.
      Matrix M = Matrix::Zero( Index(k), Index(d) );

      // Centroid calculation ------------------------------------------

      Vector centroid  = Vector::Zero(1, Index(d) );

      for( std::size_t j = 0; j < indices[i].size(); j++ )
      {
        auto&& neighbourIndex = indices[i][j];
        auto p                = container[neighbourIndex];
        Vector v              = Vector::Zero(1, Index(d) );

        // copy (and transform!) the vector; there's an implicit type
        // conversion going on here
        for( std::size_t l = 0; l < d; l++ )
          v( Index(l) ) = p[l];

        centroid          += v;
        M.row( Index(j) )  = v;
      }

      centroid /= static_cast<T>( indices.size() );

      // Coordinate matrix setup ---------------------------------------

      M = M.rowwise() - centroid;

      Eigen::JacobiSVD<Matrix> svd( M, Eigen::ComputeThinV );

      LocalTangentSpace lts;
      lts.tangents = Matrix::Zero( Index(d), Index(d - 1) );

      // The singular vectors of all but the *smallest* singular value
      // form the tangential directions of the tangent space.

      auto&& V = svd.matrixV();

      for( Index j = 0; j < Index( d - 1 ); j++ )
        lts.tangents.col(j) = V.col(j);

      lts.normal           = Matrix::Zero( Index(1), Index(d) );
      lts.normal           = V.col( Index(d-1) );
      lts.position         = getPosition( container, i );
      lts.indices          = indices[i];

      // Take the *maximum distance* in which we can find all of the
      // neighbours as a *rough*  approximation to the local feature
      // size.
      lts.localFeatureSize
        = distances[i].empty() == false ?
            *std::max_element( distances[i].begin(), distances[i].end() )
          : T();

      localTangentSpaces.push_back( lts );

      // TODO: calculate raw approximation (reconstruction) error by
      // assessing how well the space fits the original data set
    }

    return localTangentSpaces;
  }

  template <class Container>
    std::vector<Sphere> fitSpheres( const Container& container,
                                    const std::vector<LocalTangentSpace>& localTangentSpaces )
  {
    using namespace detail;

    std::vector<Sphere> spheres;
    spheres.reserve( container.size() );

    for( auto&& lts : localTangentSpaces )
    {
      auto d = Index( container.dimension() );
      auto w = 1.0;

      Matrix A = Matrix::Zero( d+2, d+2 );
      Vector b = Vector::Zero( 1,   d+2 );

      auto&& indices = lts.indices;

      for( auto&& index : indices )
      {
        auto neighbour           = getPosition( container, index );
        auto squaredNeigbourNorm = neighbour.squaredNorm();
        auto _beta               = 10e6; // FIXME: how to obtain estimates?
        w                        = phi( ( lts.position - neighbour ).norm() / lts.localFeatureSize );

        A(   0,   0) += w;
        A( d+1,   0) += w * squaredNeigbourNorm;
        A( d+1, d+1) += w * squaredNeigbourNorm * squaredNeigbourNorm;

        for( Index(i) = 1; i < d+1; i++ )
        {
          A(  i,   i) += w * ( neighbour(i-1)*neighbour(i-1) + 1 ) * _beta;
          A(  i,   0) += w * ( neighbour(i-1) );
          A(d+1,   i) += w * ( neighbour(i-1)*squaredNeigbourNorm + 2 * _beta * neighbour(i-1) );
          A(d+1, d+1) += w * ( 4*neighbour(i-1)*neighbour(i-1) ) * _beta;

          // re-establish symmetry
          A(  0,   i)  = A(i,0);
          A(  i, d+1)  = A(d+1, i);

          b(i  ) +=       _beta * w * lts.normal(i-1);
          b(d+1) += 2.0 * _beta * w * lts.normal(i-1) * neighbour(i-1);

          for( Index(j) = i+1; j < d+1; j++ )
          {
            A(j, i) += w * neighbour(i-1) * neighbour(j-1);
            A(i, j)  = A(j,i);
          }
        }
      }

      // Solve the linear system ---------------------------------------
      //
      // The solution of the system Ax = b is used to obtain the
      // coefficients of the algebraic sphere.

      using Solver = Eigen::LDLT<Matrix>;
      Solver solver(A);

      Vector u = solver.solve( b.transpose() );

      spheres.emplace_back( Sphere( u.data(), u.data() + u.size() ) );
    }

    return spheres;
  }

private:

  /**
    Auxiliary function for extracting and converting a position from
    a given container, storing it as a (mathematical) vector.
  */

  template <class Container> Vector getPosition( const Container& container, std::size_t i )
  {
    auto d   = container.dimension();
    auto p   = container[i];
    Vector v = Vector::Zero(1, Index(d) );

    // copy (and transform!) the vector; there's an implicit type
    // conversion going on here
    for( std::size_t l = 0; l < d; l++ )
      v( Index(l) ) = p[l];

    return v;
  }
};

#endif

} // namespace geometry

} // namespace aleph

#endif
<|endoftext|>


<commit_before>/**********************************************************************
 * $Id$
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.refractions.net
 *
 * Copyright (C) 2006 Refractions Research Inc.
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Licence as published
 * by the Free Software Foundation.
 * See the COPYING file for more information.
 *
 **********************************************************************
 *
 * Last port: noding/snapround/HotPixel.java rev. 1.3 (JTS-1.9)
 *
 **********************************************************************/

#include <geos/noding/snapround/HotPixel.h>
#include <geos/noding/NodedSegmentString.h>
#include <geos/algorithm/LineIntersector.h>
#include <geos/geom/Coordinate.h>

#ifndef GEOS_INLINE
# include "geos/noding/snapround/HotPixel.inl"
#endif

#include <algorithm> // for std::min and std::max
#include <cassert>
#include <memory>

using namespace std;
using namespace geos::algorithm;
using namespace geos::geom;

namespace geos {
namespace noding { // geos.noding
namespace snapround { // geos.noding.snapround

HotPixel::HotPixel(const Coordinate& newPt, double newScaleFactor,
		LineIntersector& newLi)
	:
	li(newLi),
	pt(newPt),
	originalPt(pt),
	scaleFactor(newScaleFactor)
{
	if (scaleFactor != 1.0) {
		pt.x=scale(pt.x);
		pt.y=scale(pt.y);
	}
	initCorners(pt);
}

const Envelope&
HotPixel::getSafeEnvelope() const
{
	if (safeEnv.get() == NULL) {
		double safeTolerance = .75 / scaleFactor;
		safeEnv = auto_ptr<Envelope>(new Envelope(originalPt.x - safeTolerance,
			originalPt.x + safeTolerance,
			originalPt.y - safeTolerance,
			originalPt.y + safeTolerance
			));
	}
	return *safeEnv;
}

/*private*/
void
HotPixel::initCorners(const Coordinate& pt)
{
	double tolerance = 0.5;
	minx = pt.x - tolerance;
	maxx = pt.x + tolerance;
	miny = pt.y - tolerance;
	maxy = pt.y + tolerance;

	corner.resize(4);
	corner[0] = Coordinate(maxx, maxy);
	corner[1] = Coordinate(minx, maxy);
	corner[2] = Coordinate(minx, miny);
	corner[4] = Coordinate(maxx, maxy);
}

bool
HotPixel::intersects(const Coordinate& p0,
		const Coordinate& p1) const
{
	if (scaleFactor == 1.0) return intersectsScaled(p0, p1);

	copyScaled(p0, p0Scaled);
	copyScaled(p1, p1Scaled);

	return intersectsScaled(p0Scaled, p1Scaled);
}

bool
HotPixel::intersectsScaled(const Coordinate& p0,
		const Coordinate& p1) const
{

	double segMinx = std::min(p0.x, p1.x);
	double segMaxx = std::max(p0.x, p1.x);
	double segMiny = std::min(p0.y, p1.y);
	double segMaxy = std::max(p0.y, p1.y);

	bool isOutsidePixelEnv =  maxx < segMinx
                         || minx > segMaxx
                         || maxy < segMiny
                         || miny > segMaxy;

	if (isOutsidePixelEnv) return false;

	bool intersects = intersectsToleranceSquare(p0, p1);

	// Found bad envelope test
	assert(!(isOutsidePixelEnv && intersects));

	return intersects;
}

/*private*/
bool
HotPixel::intersectsToleranceSquare(const Coordinate& p0,
		const Coordinate& p1) const
{
    bool intersectsLeft = false;
    bool intersectsBottom = false;

    li.computeIntersection(p0, p1, corner[0], corner[1]);
    if (li.isProper()) return true;

    li.computeIntersection(p0, p1, corner[1], corner[2]);
    if (li.isProper()) return true;
    if (li.hasIntersection()) intersectsLeft = true;

    li.computeIntersection(p0, p1, corner[2], corner[3]);
    if (li.isProper()) return true;
    if (li.hasIntersection()) intersectsBottom = true;

    li.computeIntersection(p0, p1, corner[3], corner[0]);
    if (li.isProper()) return true;

    if (intersectsLeft && intersectsBottom) return true;

    if (p0.equals2D(pt)) return true;
    if (p1.equals2D(pt)) return true;

    return false;
}

/*private*/
bool
HotPixel::intersectsPixelClosure(const Coordinate& p0,
		const Coordinate& p1)
{
    li.computeIntersection(p0, p1, corner[0], corner[1]);
    if (li.hasIntersection()) return true;
    li.computeIntersection(p0, p1, corner[1], corner[2]);
    if (li.hasIntersection()) return true;
    li.computeIntersection(p0, p1, corner[2], corner[3]);
    if (li.hasIntersection()) return true;
    li.computeIntersection(p0, p1, corner[3], corner[0]);
    if (li.hasIntersection()) return true;

    return false;
}

bool
HotPixel::addSnappedNode(NodedSegmentString& segStr, size_t segIndex)
{
	const Coordinate& p0 = segStr.getCoordinate(segIndex);
	const Coordinate& p1 = segStr.getCoordinate(segIndex + 1);

	if (intersects(p0, p1))
	{
		//cout << "snapped: " <<  snapPt << endl;
		segStr.addIntersection(getCoordinate(), segIndex);
		return true;
	}
	return false;
}

} // namespace geos.noding.snapround
} // namespace geos.noding
} // namespace geos

/**********************************************************************
 * $Log$
 * Revision 1.8  2006/05/03 17:51:24  strk
 * system headers included after package headers
 *
 * Revision 1.7  2006/03/24 09:52:41  strk
 * USE_INLINE => GEOS_INLINE
 *
 * Revision 1.6  2006/03/14 12:55:56  strk
 * Headers split: geomgraphindex.h, nodingSnapround.h
 *
 * Revision 1.5  2006/03/03 10:46:21  strk
 * Removed 'using namespace' from headers, added missing headers in .cpp files, removed useless includes in headers (bug#46)
 *
 * Revision 1.4  2006/02/21 16:53:49  strk
 * MCIndexPointSnapper, MCIndexSnapRounder
 *
 * Revision 1.3  2006/02/19 19:46:49  strk
 * Packages <-> namespaces mapping for most GEOS internal code (uncomplete, but working). Dir-level libs for index/ subdirs.
 *
 * Revision 1.2  2006/02/18 21:08:09  strk
 * - new CoordinateSequence::applyCoordinateFilter method (slow but useful)
 * - SegmentString::getCoordinates() doesn't return a clone anymore.
 * - SegmentString::getCoordinatesRO() obsoleted.
 * - SegmentString constructor does not promises constness of passed
 *   CoordinateSequence anymore.
 * - NEW ScaledNoder class
 * - Stubs for MCIndexPointSnapper and  MCIndexSnapRounder
 * - Simplified internal interaces of OffsetCurveBuilder and OffsetCurveSetBuilder
 *
 * Revision 1.1  2006/02/14 13:28:26  strk
 * New SnapRounding code ported from JTS-1.7 (not complete yet).
 * Buffer op optimized by using new snaprounding code.
 * Leaks fixed in XMLTester.
 *
 **********************************************************************/
<commit_msg>Fix typo<commit_after>/**********************************************************************
 * $Id$
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.refractions.net
 *
 * Copyright (C) 2006 Refractions Research Inc.
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Licence as published
 * by the Free Software Foundation.
 * See the COPYING file for more information.
 *
 **********************************************************************
 *
 * Last port: noding/snapround/HotPixel.java rev. 1.3 (JTS-1.9)
 *
 **********************************************************************/

#include <geos/noding/snapround/HotPixel.h>
#include <geos/noding/NodedSegmentString.h>
#include <geos/algorithm/LineIntersector.h>
#include <geos/geom/Coordinate.h>

#ifndef GEOS_INLINE
# include "geos/noding/snapround/HotPixel.inl"
#endif

#include <algorithm> // for std::min and std::max
#include <cassert>
#include <memory>

using namespace std;
using namespace geos::algorithm;
using namespace geos::geom;

namespace geos {
namespace noding { // geos.noding
namespace snapround { // geos.noding.snapround

HotPixel::HotPixel(const Coordinate& newPt, double newScaleFactor,
		LineIntersector& newLi)
	:
	li(newLi),
	pt(newPt),
	originalPt(pt),
	scaleFactor(newScaleFactor)
{
	if (scaleFactor != 1.0) {
		pt.x=scale(pt.x);
		pt.y=scale(pt.y);
	}
	initCorners(pt);
}

const Envelope&
HotPixel::getSafeEnvelope() const
{
	if (safeEnv.get() == NULL) {
		double safeTolerance = .75 / scaleFactor;
		safeEnv = auto_ptr<Envelope>(new Envelope(originalPt.x - safeTolerance,
			originalPt.x + safeTolerance,
			originalPt.y - safeTolerance,
			originalPt.y + safeTolerance
			));
	}
	return *safeEnv;
}

/*private*/
void
HotPixel::initCorners(const Coordinate& pt)
{
	double tolerance = 0.5;
	minx = pt.x - tolerance;
	maxx = pt.x + tolerance;
	miny = pt.y - tolerance;
	maxy = pt.y + tolerance;

	corner.resize(4);
	corner[0] = Coordinate(maxx, maxy);
	corner[1] = Coordinate(minx, maxy);
	corner[2] = Coordinate(minx, miny);
	corner[3] = Coordinate(maxx, maxy);
}

bool
HotPixel::intersects(const Coordinate& p0,
		const Coordinate& p1) const
{
	if (scaleFactor == 1.0) return intersectsScaled(p0, p1);

	copyScaled(p0, p0Scaled);
	copyScaled(p1, p1Scaled);

	return intersectsScaled(p0Scaled, p1Scaled);
}

bool
HotPixel::intersectsScaled(const Coordinate& p0,
		const Coordinate& p1) const
{

	double segMinx = std::min(p0.x, p1.x);
	double segMaxx = std::max(p0.x, p1.x);
	double segMiny = std::min(p0.y, p1.y);
	double segMaxy = std::max(p0.y, p1.y);

	bool isOutsidePixelEnv =  maxx < segMinx
                         || minx > segMaxx
                         || maxy < segMiny
                         || miny > segMaxy;

	if (isOutsidePixelEnv) return false;

	bool intersects = intersectsToleranceSquare(p0, p1);

	// Found bad envelope test
	assert(!(isOutsidePixelEnv && intersects));

	return intersects;
}

/*private*/
bool
HotPixel::intersectsToleranceSquare(const Coordinate& p0,
		const Coordinate& p1) const
{
    bool intersectsLeft = false;
    bool intersectsBottom = false;

    li.computeIntersection(p0, p1, corner[0], corner[1]);
    if (li.isProper()) return true;

    li.computeIntersection(p0, p1, corner[1], corner[2]);
    if (li.isProper()) return true;
    if (li.hasIntersection()) intersectsLeft = true;

    li.computeIntersection(p0, p1, corner[2], corner[3]);
    if (li.isProper()) return true;
    if (li.hasIntersection()) intersectsBottom = true;

    li.computeIntersection(p0, p1, corner[3], corner[0]);
    if (li.isProper()) return true;

    if (intersectsLeft && intersectsBottom) return true;

    if (p0.equals2D(pt)) return true;
    if (p1.equals2D(pt)) return true;

    return false;
}

/*private*/
bool
HotPixel::intersectsPixelClosure(const Coordinate& p0,
		const Coordinate& p1)
{
    li.computeIntersection(p0, p1, corner[0], corner[1]);
    if (li.hasIntersection()) return true;
    li.computeIntersection(p0, p1, corner[1], corner[2]);
    if (li.hasIntersection()) return true;
    li.computeIntersection(p0, p1, corner[2], corner[3]);
    if (li.hasIntersection()) return true;
    li.computeIntersection(p0, p1, corner[3], corner[0]);
    if (li.hasIntersection()) return true;

    return false;
}

bool
HotPixel::addSnappedNode(NodedSegmentString& segStr, size_t segIndex)
{
	const Coordinate& p0 = segStr.getCoordinate(segIndex);
	const Coordinate& p1 = segStr.getCoordinate(segIndex + 1);

	if (intersects(p0, p1))
	{
		//cout << "snapped: " <<  snapPt << endl;
		segStr.addIntersection(getCoordinate(), segIndex);
		return true;
	}
	return false;
}

} // namespace geos.noding.snapround
} // namespace geos.noding
} // namespace geos

/**********************************************************************
 * $Log$
 * Revision 1.8  2006/05/03 17:51:24  strk
 * system headers included after package headers
 *
 * Revision 1.7  2006/03/24 09:52:41  strk
 * USE_INLINE => GEOS_INLINE
 *
 * Revision 1.6  2006/03/14 12:55:56  strk
 * Headers split: geomgraphindex.h, nodingSnapround.h
 *
 * Revision 1.5  2006/03/03 10:46:21  strk
 * Removed 'using namespace' from headers, added missing headers in .cpp files, removed useless includes in headers (bug#46)
 *
 * Revision 1.4  2006/02/21 16:53:49  strk
 * MCIndexPointSnapper, MCIndexSnapRounder
 *
 * Revision 1.3  2006/02/19 19:46:49  strk
 * Packages <-> namespaces mapping for most GEOS internal code (uncomplete, but working). Dir-level libs for index/ subdirs.
 *
 * Revision 1.2  2006/02/18 21:08:09  strk
 * - new CoordinateSequence::applyCoordinateFilter method (slow but useful)
 * - SegmentString::getCoordinates() doesn't return a clone anymore.
 * - SegmentString::getCoordinatesRO() obsoleted.
 * - SegmentString constructor does not promises constness of passed
 *   CoordinateSequence anymore.
 * - NEW ScaledNoder class
 * - Stubs for MCIndexPointSnapper and  MCIndexSnapRounder
 * - Simplified internal interaces of OffsetCurveBuilder and OffsetCurveSetBuilder
 *
 * Revision 1.1  2006/02/14 13:28:26  strk
 * New SnapRounding code ported from JTS-1.7 (not complete yet).
 * Buffer op optimized by using new snaprounding code.
 * Leaks fixed in XMLTester.
 *
 **********************************************************************/
<|endoftext|>


<commit_before>//  (C) Copyright Gennadiy Rozental 2011.
//  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)

//  See http://www.boost.org/libs/test for the library home page.
//
//  File        : $RCSfile$
//
//  Version     : $Revision: 74663 $
//
//  Description : defines framework for automated assertion construction
// ***************************************************************************

#ifndef BOOST_TEST_TOOLS_ASSERTION_HPP_100911GER
#define BOOST_TEST_TOOLS_ASSERTION_HPP_100911GER

// Boost.Test

// Boost
#include <boost/mpl/assert.hpp>
#include <boost/utility/declval.hpp>

#include <boost/test/detail/suppress_warnings.hpp>

//____________________________________________________________________________//

namespace boost {
namespace test_tools {
namespace assertion {

// ************************************************************************** //
// **************             assertion::expression            ************** //
// ************************************************************************** //

class expression {
public:
    // expression interface
    virtual predicate_result    evaluate() const = 0;
};

// ************************************************************************** //
// **************             assertion::operators             ************** //
// ************************************************************************** //

namespace op {

enum id {
    // precedence 4: ->*, .*
    MEMP,
    // precedence 5: *, /, %
    MUL, DIV, MOD,
    // precedence 6: +, -
    ADD, SUB,
    // precedence 7: << , >>
    LSH, RSH,
    // precedence 8: <, <=, > and >=
    LT, LE, GT, GE,
    // precedence 9: == and !=
    EQ, NE,
    // precedence 10: bitwise AND
    BAND,
    // precedence 11: bitwise XOR
    XOR,
    // precedence 12: bitwise OR
    BOR,
    // precedence 13: logical AND
    //  disabled
    // precedence 14: logical OR
    //  disabled
    // precedence 15: ternary conditional
    //  disabled

    // precedence 16: = and OP= operators
    SET, IADD, ISUB, IMUL, IDIV, IMOD,
    ILSH, IRSH,
    IAND, IXOR, IOR
    // precedence 17: throw operator
    // not supported
    // precedence 18: comma
    // not supported
};

#define BOOST_TEST_FOR_EACH_OP( action )    \
    action(->*, MEMP )                      \
                                            \
    action( * , MUL  )                      \
    action( / , DIV  )                      \
    action( % , MOD  )                      \
                                            \
    action( + , ADD  )                      \
    action( - , SUB  )                      \
                                            \
    action( <<, LSH  )                      \
    action( >>, RSH  )                      \
                                            \
    action( < , LT   )                      \
    action( <=, LE   )                      \
    action( > , GT   )                      \
    action( >=, GE   )                      \
                                            \
    action( ==, EQ   )                      \
    action( !=, NE   )                      \
                                            \
    action( & , BAND )                      \
    action( ^ , XOR  )                      \
    action( | , BOR  )                      \
/**/

#define BOOST_TEST_FOR_EACH_MUT_OP( action )\
    action( = , SET  )                      \
    action( +=, IADD )                      \
    action( -=, ISUB )                      \
    action( *=, IMUL )                      \
    action( /=, IDIV )                      \
    action( %=, IMOD )                      \
    action(<<=, ILSH )                      \
    action(>>=, IRSH )                      \
    action( &=, IAND )                      \
    action( ^=, IXOR )                      \
    action( |=, IOR  )                      \
/**/

// ************************************************************************** //
// **************          assertion::operator traits          ************** //
// ************************************************************************** //

template<id ID>
struct traits {
    static char const* reverse( char const* direct ) { return direct; }
};

template<> struct traits<EQ> { static char const* reverse( char const* ) { return "!="; } };
template<> struct traits<NE> { static char const* reverse( char const* ) { return "=="; } };

template<> struct traits<LT> { static char const* reverse( char const* ) { return ">="; } };
template<> struct traits<LE> { static char const* reverse( char const* ) { return ">"; } };
template<> struct traits<GT> { static char const* reverse( char const* ) { return "<="; } };
template<> struct traits<GE> { static char const* reverse( char const* ) { return "<"; } };

} // anmespace op

// ************************************************************************** //
// **************         assertion::expression_result         ************** //
// ************************************************************************** //

namespace detail {

template<typename PrevExprType,typename Rhs,op::id OP>
class expression_result;

#ifndef BOOST_NO_DECLTYPE

#define DEFINE_OP_EXPRESSION_RESULT( OPER, ID )             \
template<typename PrevExprType,typename Rhs>                \
class expression_result<PrevExprType,Rhs,op::ID> {          \
    typedef typename PrevExprType::result_type Lhs;         \
public:                                                     \
                                                            \
    typedef decltype(boost::declval<Lhs>() OPER             \
                     boost::declval<Rhs>() ) type;          \
                                                            \
    static type                                             \
    produce( Lhs const& lhs, Rhs const& rhs)                \
    {                                                       \
        return lhs OPER rhs;                                \
    }                                                       \
                                                            \
    static void                                             \
    report( std::ostream& ostr,                             \
            PrevExprType const& lhs, Rhs const& rhs)        \
    {                                                       \
        lhs.report( ostr );                                 \
        ostr << op::traits<op::ID>::reverse( #OPER )        \
             << rhs;                                        \
    }                                                       \
};                                                          \
/**/

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

BOOST_TEST_FOR_EACH_OP( DEFINE_OP_EXPRESSION_RESULT );

#undef DEFINE_OP_EXPRESSION_RESULT

#endif

} // namespace detail

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

// ************************************************************************** //
// **************           assertion::expression_op           ************** //
// ************************************************************************** //
// Defines expression operators

template<typename Lhs,typename Rhs,op::id OP> class binary_expr;

template<typename ExprType>
class expression_op {
public:
#ifndef BOOST_NO_DECLTYPE

#define ADD_OP_SUPPORT( OPER, ID )                          \
    template<typename T>                                    \
    binary_expr<ExprType,T,op::ID>                          \
    operator OPER( T const& rhs ) const                     \
    {                                                       \
        return binary_expr<ExprType,T,op::ID>(              \
            *static_cast<ExprType const*>(this),            \
            rhs );                                          \
    }                                                       \
/**/

    BOOST_TEST_FOR_EACH_OP( ADD_OP_SUPPORT );
#undef ADD_OP_SUPPORT

#endif

    // Disabled operators
    template<typename T>
    ExprType&
    operator ||( T const& rhs )
    {
        BOOST_MPL_ASSERT_MSG(false, CANT_USE_LOGICAL_OPERATOR_OR_WITHIN_THIS_TESTING_TOOL, () );

        return *static_cast<ExprType*>(this);
    }

    template<typename T>
    ExprType&
    operator &&( T const& rhs )
    {
        BOOST_MPL_ASSERT_MSG(false, CANT_USE_LOGICAL_OPERATOR_AND_WITHIN_THIS_TESTING_TOOL, () );

        return *static_cast<ExprType*>(this);
    }

    operator bool()
    {
        BOOST_MPL_ASSERT_MSG(false, CANT_USE_TERNARY_OPERATOR_WITHIN_THIS_TESTING_TOOL, () );

        return false;
    }
};

// ************************************************************************** //
// **************            assertion::value_expr             ************** //
// ************************************************************************** //
// simple value expression

template<typename T>
class value_expr : public expression, public expression_op<value_expr<T> > {
public:
    // Public types
    typedef T                   result_type;

    // Constructor
    explicit                    value_expr( T&& val )
    : m_value( val )
    {}

    // Specific expresson interface
    T const&                    value() const
    {
        return m_value;
    }
    void                        report( std::ostream& ostr ) const
    {
        ostr << m_value;
    }

    // Mutating operators
#define ADD_OP_SUPPORT( OPER, ID )                          \
    template<typename U>                                    \
    value_expr<T>&                                          \
    operator OPER( U const& rhs )                           \
    {                                                       \
        m_value OPER rhs;                                   \
                                                            \
        return *this;                                       \
    }                                                       \
/**/

    BOOST_TEST_FOR_EACH_MUT_OP( ADD_OP_SUPPORT )
#undef ADD_OP_SUPPORT

private:
    // expression interface
    virtual predicate_result    evaluate() const
    {
        predicate_result res( value() );
        if( !res )
            res.message() << "(bool)" << value() << " is false";

        return res;
    }

    // Data members
    T                           m_value;
};

// ************************************************************************** //
// **************         assertion::binary_expr_expr          ************** //
// ************************************************************************** //
// binary expression

template<typename Lhs,typename Rhs,op::id OP>
class binary_expr : public expression, public expression_op<binary_expr<Lhs,Rhs,OP> > {
    typedef detail::expression_result<Lhs,Rhs,OP>   result;
public:
    // Public types
    typedef typename result::type result_type;

    // Constructor
    binary_expr( Lhs const& lhs, Rhs const& rhs )
    : m_lhs( lhs )
    , m_rhs( rhs )
    {}

    // Specifica expression interface
    result_type                 value() const
    {
        return result::produce( m_lhs.value(), m_rhs );
    }
    void                        report( std::ostream& ostr ) const
    {
        return result::report( ostr, m_lhs, m_rhs );
    }

private:
    // expression interface
    virtual predicate_result    evaluate() const
    {
        predicate_result res( value() );
        if( !res )
            report( res.message().stream() );

        return res;
    }

    // Data members
    Lhs                         m_lhs;
    Rhs                         m_rhs;
};

// ************************************************************************** //
// **************               assertion::seed                ************** //
// ************************************************************************** //
// seed added ot the input expression to form an assertion expression

class seed {
public:
    // ->* is highest precedence left to right operator
    template<typename T>
    value_expr<T>
    operator->*( T&& v )
    {
        return value_expr<T>( std::forward<T>( v ) );
    }
};

#undef BOOST_TEST_FOR_EACH_OP

} // namespace assertion
} // namespace test_tools
} // namespace boost

#include <boost/test/detail/enable_warnings.hpp>

#endif // BOOST_TEST_TOOLS_ASSERTION_HPP_100911GER

<commit_msg>some portability fixes<commit_after>//  (C) Copyright Gennadiy Rozental 2011.
//  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)

//  See http://www.boost.org/libs/test for the library home page.
//
//  File        : $RCSfile$
//
//  Version     : $Revision: 74663 $
//
//  Description : defines framework for automated assertion construction
// ***************************************************************************

#ifndef BOOST_TEST_TOOLS_ASSERTION_HPP_100911GER
#define BOOST_TEST_TOOLS_ASSERTION_HPP_100911GER

// Boost.Test

// Boost
#include <boost/mpl/assert.hpp>
#include <boost/utility/declval.hpp>

#include <boost/test/detail/suppress_warnings.hpp>

//____________________________________________________________________________//

namespace boost {
namespace test_tools {
namespace assertion {

// ************************************************************************** //
// **************             assertion::expression            ************** //
// ************************************************************************** //

class expression {
public:
    // expression interface
    virtual predicate_result    evaluate() const = 0;
};

// ************************************************************************** //
// **************             assertion::operators             ************** //
// ************************************************************************** //

namespace op {

enum id {
    // precedence 4: ->*, .*
    MEMP,
    // precedence 5: *, /, %
    MUL, DIV, MOD,
    // precedence 6: +, -
    ADD, SUB,
    // precedence 7: << , >>
    LSH, RSH,
    // precedence 8: <, <=, > and >=
    LT, LE, GT, GE,
    // precedence 9: == and !=
    EQ, NE,
    // precedence 10: bitwise AND
    BAND,
    // precedence 11: bitwise XOR
    XOR,
    // precedence 12: bitwise OR
    BOR,
    // precedence 13: logical AND
    //  disabled
    // precedence 14: logical OR
    //  disabled
    // precedence 15: ternary conditional
    //  disabled

    // precedence 16: = and OP= operators
    SET, IADD, ISUB, IMUL, IDIV, IMOD,
    ILSH, IRSH,
    IAND, IXOR, IOR
    // precedence 17: throw operator
    // not supported
    // precedence 18: comma
    // not supported
};

#ifndef BOOST_NO_DECLTYPE

#define BOOST_TEST_FOR_EACH_OP( action )    \
    action(->*, MEMP )                      \
                                            \
    action( * , MUL  )                      \
    action( / , DIV  )                      \
    action( % , MOD  )                      \
                                            \
    action( + , ADD  )                      \
    action( - , SUB  )                      \
                                            \
    action( <<, LSH  )                      \
    action( >>, RSH  )                      \
                                            \
    action( < , LT   )                      \
    action( <=, LE   )                      \
    action( > , GT   )                      \
    action( >=, GE   )                      \
                                            \
    action( ==, EQ   )                      \
    action( !=, NE   )                      \
                                            \
    action( & , BAND )                      \
    action( ^ , XOR  )                      \
    action( | , BOR  )                      \
/**/

#else

#define BOOST_TEST_FOR_EACH_OP( action )    \
    action( < , LT   )                      \
    action( <=, LE   )                      \
    action( > , GT   )                      \
    action( >=, GE   )                      \
                                            \
    action( ==, EQ   )                      \
    action( !=, NE   )                      \
/**/

#endif

#define BOOST_TEST_FOR_EACH_MUT_OP( action )\
    action( = , SET  )                      \
    action( +=, IADD )                      \
    action( -=, ISUB )                      \
    action( *=, IMUL )                      \
    action( /=, IDIV )                      \
    action( %=, IMOD )                      \
    action(<<=, ILSH )                      \
    action(>>=, IRSH )                      \
    action( &=, IAND )                      \
    action( ^=, IXOR )                      \
    action( |=, IOR  )                      \
/**/

// ************************************************************************** //
// **************          assertion::operator traits          ************** //
// ************************************************************************** //

template<id ID>
struct traits {
    static char const* reverse( char const* direct ) { return direct; }
};

template<> struct traits<EQ> { static char const* reverse( char const* ) { return "!="; } };
template<> struct traits<NE> { static char const* reverse( char const* ) { return "=="; } };

template<> struct traits<LT> { static char const* reverse( char const* ) { return ">="; } };
template<> struct traits<LE> { static char const* reverse( char const* ) { return ">"; } };
template<> struct traits<GT> { static char const* reverse( char const* ) { return "<="; } };
template<> struct traits<GE> { static char const* reverse( char const* ) { return "<"; } };

} // anmespace op

// ************************************************************************** //
// **************         assertion::expression_result         ************** //
// ************************************************************************** //

namespace detail {

template<typename PrevExprType,typename Rhs,op::id OP>
class expression_result;

#define DEFINE_OP_EXPRESSION_RESULT( OPER, ID )             \
template<typename PrevExprType,typename Rhs>                \
class expression_result<PrevExprType,Rhs,op::ID> {          \
    typedef typename PrevExprType::result_type Lhs;         \
public:                                                     \
                                                            \
    typedef DEDUCE_RESULT_TYPE( OPER ) type;                \
                                                            \
    static type                                             \
    produce( Lhs const& lhs, Rhs const& rhs)                \
    {                                                       \
        return lhs OPER rhs;                                \
    }                                                       \
                                                            \
    static void                                             \
    report( std::ostream& ostr,                             \
            PrevExprType const& lhs, Rhs const& rhs)        \
    {                                                       \
        lhs.report( ostr );                                 \
        ostr << op::traits<op::ID>::reverse( #OPER )        \
             << rhs;                                        \
    }                                                       \
};                                                          \
/**/

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

#ifndef BOOST_NO_DECLTYPE
#define DEDUCE_RESULT_TYPE( OPER ) decltype(boost::declval<Lhs>() OPER boost::declval<Rhs>() )
#else
#define DEDUCE_RESULT_TYPE( OPER ) predicate_result
#endif

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

BOOST_TEST_FOR_EACH_OP( DEFINE_OP_EXPRESSION_RESULT )

#undef DEDUCE_RESULT_TYPE
#undef DEFINE_OP_EXPRESSION_RESULT

} // namespace detail

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

// ************************************************************************** //
// **************           assertion::expression_op           ************** //
// ************************************************************************** //
// Defines expression operators

template<typename Lhs,typename Rhs,op::id OP> class binary_expr;

template<typename ExprType>
class expression_op {
public:

#define ADD_OP_SUPPORT( OPER, ID )                          \
    template<typename T>                                    \
    binary_expr<ExprType,T,op::ID>                          \
    operator OPER( T const& rhs ) const                     \
    {                                                       \
        return binary_expr<ExprType,T,op::ID>(              \
            *static_cast<ExprType const*>(this),            \
            rhs );                                          \
    }                                                       \
/**/

    BOOST_TEST_FOR_EACH_OP( ADD_OP_SUPPORT )
#undef ADD_OP_SUPPORT

    // Disabled operators
    template<typename T>
    ExprType&
    operator ||( T const& rhs )
    {
        BOOST_MPL_ASSERT_MSG(false, CANT_USE_LOGICAL_OPERATOR_OR_WITHIN_THIS_TESTING_TOOL, () );

        return *static_cast<ExprType*>(this);
    }

    template<typename T>
    ExprType&
    operator &&( T const& rhs )
    {
        BOOST_MPL_ASSERT_MSG(false, CANT_USE_LOGICAL_OPERATOR_AND_WITHIN_THIS_TESTING_TOOL, () );

        return *static_cast<ExprType*>(this);
    }

    operator bool()
    {
        BOOST_MPL_ASSERT_MSG(false, CANT_USE_TERNARY_OPERATOR_WITHIN_THIS_TESTING_TOOL, () );

        return false;
    }
};

// ************************************************************************** //
// **************            assertion::value_expr             ************** //
// ************************************************************************** //
// simple value expression

template<typename T>
class value_expr : public expression, public expression_op<value_expr<T> > {
public:
    // Public types
    typedef T                   result_type;

    // Constructor
#ifndef BOOST_NO_RVALUE_REFERENCES
    explicit                    value_expr( T&& val )
#else
    explicit                    value_expr( T const& val )
#endif
    : m_value( val )
    {}

    // Specific expresson interface
    T const&                    value() const
    {
        return m_value;
    }
    void                        report( std::ostream& ostr ) const
    {
        ostr << m_value;
    }

    // Mutating operators
#define ADD_OP_SUPPORT( OPER, ID )                          \
    template<typename U>                                    \
    value_expr<T>&                                          \
    operator OPER( U const& rhs )                           \
    {                                                       \
        m_value OPER rhs;                                   \
                                                            \
        return *this;                                       \
    }                                                       \
/**/

    BOOST_TEST_FOR_EACH_MUT_OP( ADD_OP_SUPPORT )
#undef ADD_OP_SUPPORT

private:
    // expression interface
    virtual predicate_result    evaluate() const
    {
        predicate_result res( value() );
        if( !res )
            res.message() << "(bool)" << value() << " is false";

        return res;
    }

    // Data members
    T                           m_value;
};

// ************************************************************************** //
// **************         assertion::binary_expr_expr          ************** //
// ************************************************************************** //
// binary expression

template<typename Lhs,typename Rhs,op::id OP>
class binary_expr : public expression, public expression_op<binary_expr<Lhs,Rhs,OP> > {
    typedef detail::expression_result<Lhs,Rhs,OP>   result;
public:
    // Public types
    typedef typename result::type result_type;

    // Constructor
    binary_expr( Lhs const& lhs, Rhs const& rhs )
    : m_lhs( lhs )
    , m_rhs( rhs )
    {}

    // Specifica expression interface
    result_type                 value() const
    {
        return result::produce( m_lhs.value(), m_rhs );
    }
    void                        report( std::ostream& ostr ) const
    {
        return result::report( ostr, m_lhs, m_rhs );
    }

private:
    // expression interface
    virtual predicate_result    evaluate() const
    {
        predicate_result res( value() );
        if( !res )
            report( res.message().stream() );

        return res;
    }

    // Data members
    Lhs                         m_lhs;
    Rhs                         m_rhs;
};

// ************************************************************************** //
// **************               assertion::seed                ************** //
// ************************************************************************** //
// seed added ot the input expression to form an assertion expression

class seed {
public:
    // ->* is highest precedence left to right operator
    template<typename T>
    value_expr<T>
#ifndef BOOST_NO_RVALUE_REFERENCES
    operator->*( T&& v )
    {
        return value_expr<T>( std::forward<T>( v ) );
    }
#else
    operator->*( T const& v )
    {
        return value_expr<T>( v );
    }
#endif

};

#undef BOOST_TEST_FOR_EACH_OP

} // namespace assertion
} // namespace test_tools
} // namespace boost

#include <boost/test/detail/enable_warnings.hpp>

#endif // BOOST_TEST_TOOLS_ASSERTION_HPP_100911GER

<|endoftext|>


<commit_before>// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com

#ifndef CHAISCRIPT_ANY_HPP_
#define CHAISCRIPT_ANY_HPP_

#include <utility>

namespace chaiscript {
  namespace detail {
    namespace exception
    {
      /// \brief Thrown in the event that an Any cannot be cast to the desired type
      ///
      /// It is used internally during function dispatch.
      ///
      /// \sa chaiscript::detail::Any
      class bad_any_cast : public std::bad_cast
      {
        public:
          bad_any_cast() CHAISCRIPT_NOEXCEPT
            : m_what("bad any cast")
          {
          }

          virtual ~bad_any_cast() CHAISCRIPT_NOEXCEPT {}

          /// \brief Description of what error occured
          virtual const char * what() const CHAISCRIPT_NOEXCEPT CHAISCRIPT_OVERRIDE
          {
            return m_what.c_str();
          }

        private:
          std::string m_what;
      };
    }

    class Any {
      private:
        struct Data
        {
          virtual ~Data() {}
          virtual void *data() = 0;
          virtual const std::type_info &type() const = 0;
          virtual std::shared_ptr<Data> clone() const = 0;
        };

        template<typename T>
          struct Data_Impl : Data
          {
            Data_Impl(T t_type)
              : m_type(typeid(T)),
                m_data(std::move(t_type))
            {
            }

            virtual ~Data_Impl() {}

            virtual void *data() CHAISCRIPT_OVERRIDE
            {
              return &m_data;
            }

            const std::type_info &type() const CHAISCRIPT_OVERRIDE
            {
              return m_type;
            }

            std::shared_ptr<Data> clone() const CHAISCRIPT_OVERRIDE
            {
              return std::shared_ptr<Data>(new Data_Impl<T>(m_data));
            }

            Data_Impl &operator=(const Data_Impl&) = delete;

            const std::type_info &m_type;
            T m_data;
          };

        std::shared_ptr<Data> m_data;

      public:
        // construct/copy/destruct
        Any() = default;

        Any(const Any &t_any)
        {
          if (!t_any.empty())
          {
            m_data = t_any.m_data->clone();
          } else {
            m_data.reset();
          }
        }

        template<typename ValueType>
        Any(const ValueType &t_value)
          : m_data(std::shared_ptr<Data>(new Data_Impl<ValueType>(t_value)))
        {
        }

        Any & operator=(const Any &t_any)
        {
          Any copy(t_any);
          swap(copy);
          return *this;
        }

        template<typename ValueType>
          Any & operator=(const ValueType &t_value)
        {
          m_data = std::shared_ptr<Data>(new Data_Impl<ValueType>(t_value));
          return *this;
        }

        template<typename ToType>
          ToType &cast() const
          {
            if (m_data && typeid(ToType) == m_data->type())
            {
              return *static_cast<ToType *>(m_data->data());
            } else {
              throw chaiscript::detail::exception::bad_any_cast();
            }

          }

        ~Any()
        {
        }

        // modifiers
        Any & swap(Any &t_other)
        {
          std::shared_ptr<Data> data = t_other.m_data;
          t_other.m_data = m_data;
          m_data = data;
          return *this;
        }

        // queries
        bool empty() const
        {
          return !bool(m_data);
        }

        const std::type_info & type() const
        {
          if (m_data)
          {
            return m_data->type();
          } else {
            return typeid(void);
          }
        }
    };

  }
}

#endif

<commit_msg>Move to unique_ptr for Any implemenation<commit_after>// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com

#ifndef CHAISCRIPT_ANY_HPP_
#define CHAISCRIPT_ANY_HPP_

#include <utility>

namespace chaiscript {
  namespace detail {
    namespace exception
    {
      /// \brief Thrown in the event that an Any cannot be cast to the desired type
      ///
      /// It is used internally during function dispatch.
      ///
      /// \sa chaiscript::detail::Any
      class bad_any_cast : public std::bad_cast
      {
        public:
          bad_any_cast() CHAISCRIPT_NOEXCEPT
            : m_what("bad any cast")
          {
          }

          virtual ~bad_any_cast() CHAISCRIPT_NOEXCEPT {}

          /// \brief Description of what error occured
          virtual const char * what() const CHAISCRIPT_NOEXCEPT CHAISCRIPT_OVERRIDE
          {
            return m_what.c_str();
          }

        private:
          std::string m_what;
      };
    }

    class Any {
      private:
        struct Data
        {
          virtual ~Data() {}
          virtual void *data() = 0;
          virtual const std::type_info &type() const = 0;
          virtual std::unique_ptr<Data> clone() const = 0;
        };

        template<typename T>
          struct Data_Impl : Data
          {
            Data_Impl(T t_type)
              : m_type(typeid(T)),
                m_data(std::move(t_type))
            {
            }

            virtual ~Data_Impl() {}

            virtual void *data() CHAISCRIPT_OVERRIDE
            {
              return &m_data;
            }

            const std::type_info &type() const CHAISCRIPT_OVERRIDE
            {
              return m_type;
            }

            std::unique_ptr<Data> clone() const CHAISCRIPT_OVERRIDE
            {
              return std::unique_ptr<Data>(new Data_Impl<T>(m_data));
            }

            Data_Impl &operator=(const Data_Impl&) = delete;

            const std::type_info &m_type;
            T m_data;
          };

        std::unique_ptr<Data> m_data;

      public:
        // construct/copy/destruct
        Any() = default;

        Any(const Any &t_any)
        {
          if (!t_any.empty())
          {
            m_data = t_any.m_data->clone();
          } else {
            m_data.reset();
          }
        }

        template<typename ValueType>
        Any(const ValueType &t_value)
          : m_data(std::unique_ptr<Data>(new Data_Impl<ValueType>(t_value)))
        {
        }

        Any & operator=(const Any &t_any)
        {
          Any copy(t_any);
          swap(copy);
          return *this;
        }

        template<typename ValueType>
          Any & operator=(const ValueType &t_value)
        {
          m_data = std::unique_ptr<Data>(new Data_Impl<ValueType>(t_value));
          return *this;
        }

        template<typename ToType>
          ToType &cast() const
          {
            if (m_data && typeid(ToType) == m_data->type())
            {
              return *static_cast<ToType *>(m_data->data());
            } else {
              throw chaiscript::detail::exception::bad_any_cast();
            }

          }

        ~Any()
        {
        }

        // modifiers
        Any & swap(Any &t_other)
        {
          std::swap(t_other.m_data, m_data);
          return *this;
        }

        // queries
        bool empty() const
        {
          return !bool(m_data);
        }

        const std::type_info & type() const
        {
          if (m_data)
          {
            return m_data->type();
          } else {
            return typeid(void);
          }
        }
    };

  }
}

#endif

<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014-2017 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#pragma once

#include "dll/base_traits.hpp"
#include "dll/neural_layer.hpp"

namespace dll {

/*!
 * \brief Standard dense layer of neural network.
 */
template <typename Desc>
struct dyn_dense_layer final : neural_layer<dyn_dense_layer<Desc>, Desc> {
    using desc      = Desc;
    using weight    = typename desc::weight;
    using this_type = dyn_dense_layer<desc>;
    using base_type = neural_layer<this_type, desc>;

    static constexpr auto activation_function = desc::activation_function;
    static constexpr auto w_initializer       = desc::w_initializer;
    static constexpr auto b_initializer       = desc::b_initializer;

    using input_one_t  = etl::dyn_matrix<weight, 1>;
    using output_one_t = etl::dyn_matrix<weight, 1>;
    using input_t      = std::vector<input_one_t>;
    using output_t     = std::vector<output_one_t>;

    using w_type = etl::dyn_matrix<weight, 2>;
    using b_type = etl::dyn_matrix<weight, 1>;

    //Weights and biases
    w_type w; //!< Weights
    b_type b; //!< Hidden biases

    //Backup Weights and biases
    std::unique_ptr<w_type> bak_w; //!< Backup Weights
    std::unique_ptr<b_type> bak_b; //!< Backup Hidden biases

    std::size_t num_visible;
    std::size_t num_hidden;

    dyn_dense_layer() : base_type() {}

    void init_layer(size_t nv, size_t nh) {
        num_visible = nv;
        num_hidden  = nh;

        w = etl::dyn_matrix<weight, 2>(num_visible, num_hidden);
        b = etl::dyn_matrix<weight, 1>(num_hidden);

        initializer_function<w_initializer>::initialize(w, input_size(), output_size());
        initializer_function<b_initializer>::initialize(b, input_size(), output_size());
    }

    /*!
     * \brief Returns the input size of this layer
     */
    std::size_t input_size() const noexcept {
        return num_visible;
    }

    /*!
     * \brief Returns the output size of this layer
     */
    std::size_t output_size() const noexcept {
        return num_hidden;
    }

    /*!
     * \brief Returns the number of parameters of this layer
     */
    std::size_t parameters() const noexcept {
        return num_visible * num_hidden;
    }

    std::string to_short_string() const {
        char buffer[1024];
        snprintf(buffer, 1024, "Dense: %lu -> %s -> %lu", num_visible, to_string(activation_function).c_str(), num_hidden);
        return {buffer};
    }

    template <typename V, cpp_enable_if(etl::decay_traits<V>::dimensions() == 1)>
    void activate_hidden(output_one_t& output, const V& v) const {
        output = f_activate<activation_function>(b + v * w);
    }

    template <typename V, cpp_enable_if(etl::decay_traits<V>::dimensions() != 1)>
    void activate_hidden(output_one_t& output, const V& v) const {
        output = f_activate<activation_function>(b + etl::reshape(v, num_visible) * w);
    }

    template <typename H, typename V, cpp_enable_if(etl::decay_traits<V>::dimensions() == 2)>
    void batch_activate_hidden(H&& output, const V& v) const {
        const auto Batch = etl::dim<0>(v);

        cpp_assert(etl::dim<0>(output) == Batch, "The number of samples must be consistent");

        if (activation_function == function::SOFTMAX) {
            auto expr = etl::force_temporary(etl::rep_l(b, Batch) + v * w);

            for (std::size_t i = 0; i < Batch; ++i) {
                output(i) = f_activate<activation_function>(expr(i));
            }
        } else {
            output = f_activate<activation_function>(etl::rep_l(b, Batch) + v * w);
        }
    }

    template <typename H, typename V, cpp_enable_if(etl::decay_traits<V>::dimensions() != 2)>
    void batch_activate_hidden(H&& output, const V& input) const {
        auto Batch = etl::dim<0>(input);

        cpp_assert(etl::dim<0>(output) == Batch, "The number of samples must be consistent");

        if (activation_function == function::SOFTMAX) {
            auto expr = etl::force_temporary(etl::rep_l(b, Batch) + etl::reshape(input, Batch, num_visible) * w);

            for (std::size_t i = 0; i < Batch; ++i) {
                output(i) = f_activate<activation_function>(expr(i));
            }
        } else {
            output = f_activate<activation_function>(etl::rep_l(b, Batch) + etl::reshape(input, Batch, num_visible) * w);
        }
    }

    template <typename DBN>
    void init_sgd_context() {
        this->sgd_context_ptr = std::make_shared<sgd_context<DBN, this_type>>(num_visible, num_hidden);
    }

    template <typename Input>
    output_one_t prepare_one_output() const {
        return output_one_t(num_hidden);
    }

    template <typename Input>
    output_t prepare_output(std::size_t samples) const {
        output_t output;
        output.reserve(samples);
        for(std::size_t i = 0; i < samples; ++i){
            output.emplace_back(num_hidden);
        }
        return output;
    }

    void prepare_input(input_one_t& input) const {
        input = input_one_t(num_visible);
    }

    template<typename DRBM>
    static void dyn_init(DRBM&){
        //Nothing to change
    }

    /*!
     * \brief Adapt the errors, called before backpropagation of the errors.
     *
     * This must be used by layers that have both an activation fnction and a non-linearity.
     *
     * \param context the training context
     */
    template<typename C>
    void adapt_errors(C& context) const {
        context.errors = f_derivative<activation_function>(context.output) >> context.errors;
    }

    /*!
     * \brief Backpropagate the errors to the previous layers
     * \param output The ETL expression into which write the output
     * \param context The training context
     */
    template<typename H, typename C>
    void backward_batch(H&& output, C& context) const {
        // The reshape has no overhead, so better than SFINAE for nothing
        auto batch_size = etl::dim<0>(output);
        etl::reshape(output, batch_size, num_visible) = context.errors * etl::transpose(w);
    }

    /*!
     * \brief Compute the gradients for this layer, if any
     * \param context The trainng context
     */
    template<typename C>
    void compute_gradients(C& context) const {
        context.w_grad = batch_outer(context.input, context.errors);
        context.b_grad = etl::sum_l(context.errors);
    }
};

// Declare the traits for the Layer

template<typename Desc>
struct layer_base_traits<dyn_dense_layer<Desc>> {
    static constexpr bool is_neural     = true;  ///< Indicates if the layer is a neural layer
    static constexpr bool is_dense      = true;  ///< Indicates if the layer is dense
    static constexpr bool is_conv       = false; ///< Indicates if the layer is convolutional
    static constexpr bool is_deconv     = false; ///< Indicates if the layer is deconvolutional
    static constexpr bool is_standard   = true;  ///< Indicates if the layer is standard
    static constexpr bool is_rbm        = false; ///< Indicates if the layer is RBM
    static constexpr bool is_pooling    = false; ///< Indicates if the layer is a pooling layer
    static constexpr bool is_unpooling  = false; ///< Indicates if the layer is an unpooling laye
    static constexpr bool is_transform  = false; ///< Indicates if the layer is a transform layer
    static constexpr bool is_patches    = false; ///< Indicates if the layer is a patches layer
    static constexpr bool is_augment    = false; ///< Indicates if the layer is an augment layer
    static constexpr bool is_dynamic    = true;  ///< Indicates if the layer is dynamic
    static constexpr bool pretrain_last = false; ///< Indicates if the layer is dynamic
    static constexpr bool sgd_supported = true;  ///< Indicates if the layer is supported by SGD
};

} //end of dll namespace
<commit_msg>Relax activate_hidden<commit_after>//=======================================================================
// Copyright (c) 2014-2017 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#pragma once

#include "dll/base_traits.hpp"
#include "dll/neural_layer.hpp"

namespace dll {

/*!
 * \brief Standard dense layer of neural network.
 */
template <typename Desc>
struct dyn_dense_layer final : neural_layer<dyn_dense_layer<Desc>, Desc> {
    using desc      = Desc;
    using weight    = typename desc::weight;
    using this_type = dyn_dense_layer<desc>;
    using base_type = neural_layer<this_type, desc>;

    static constexpr auto activation_function = desc::activation_function;
    static constexpr auto w_initializer       = desc::w_initializer;
    static constexpr auto b_initializer       = desc::b_initializer;

    using input_one_t  = etl::dyn_matrix<weight, 1>;
    using output_one_t = etl::dyn_matrix<weight, 1>;
    using input_t      = std::vector<input_one_t>;
    using output_t     = std::vector<output_one_t>;

    using w_type = etl::dyn_matrix<weight, 2>;
    using b_type = etl::dyn_matrix<weight, 1>;

    //Weights and biases
    w_type w; //!< Weights
    b_type b; //!< Hidden biases

    //Backup Weights and biases
    std::unique_ptr<w_type> bak_w; //!< Backup Weights
    std::unique_ptr<b_type> bak_b; //!< Backup Hidden biases

    std::size_t num_visible;
    std::size_t num_hidden;

    dyn_dense_layer() : base_type() {}

    void init_layer(size_t nv, size_t nh) {
        num_visible = nv;
        num_hidden  = nh;

        w = etl::dyn_matrix<weight, 2>(num_visible, num_hidden);
        b = etl::dyn_matrix<weight, 1>(num_hidden);

        initializer_function<w_initializer>::initialize(w, input_size(), output_size());
        initializer_function<b_initializer>::initialize(b, input_size(), output_size());
    }

    /*!
     * \brief Returns the input size of this layer
     */
    std::size_t input_size() const noexcept {
        return num_visible;
    }

    /*!
     * \brief Returns the output size of this layer
     */
    std::size_t output_size() const noexcept {
        return num_hidden;
    }

    /*!
     * \brief Returns the number of parameters of this layer
     */
    std::size_t parameters() const noexcept {
        return num_visible * num_hidden;
    }

    std::string to_short_string() const {
        char buffer[1024];
        snprintf(buffer, 1024, "Dense: %lu -> %s -> %lu", num_visible, to_string(activation_function).c_str(), num_hidden);
        return {buffer};
    }

    template <typename H, typename V, cpp_enable_if(etl::decay_traits<V>::dimensions() == 1)>
    void activate_hidden(H&& output, const V& v) const {
        output = f_activate<activation_function>(b + v * w);
    }

    template <typename H, typename V, cpp_enable_if(etl::decay_traits<V>::dimensions() != 1)>
    void activate_hidden(H&& output, const V& v) const {
        output = f_activate<activation_function>(b + etl::reshape(v, num_visible) * w);
    }

    template <typename H, typename V, cpp_enable_if(etl::decay_traits<V>::dimensions() == 2)>
    void batch_activate_hidden(H&& output, const V& v) const {
        const auto Batch = etl::dim<0>(v);

        cpp_assert(etl::dim<0>(output) == Batch, "The number of samples must be consistent");

        if (activation_function == function::SOFTMAX) {
            auto expr = etl::force_temporary(etl::rep_l(b, Batch) + v * w);

            for (std::size_t i = 0; i < Batch; ++i) {
                output(i) = f_activate<activation_function>(expr(i));
            }
        } else {
            output = f_activate<activation_function>(etl::rep_l(b, Batch) + v * w);
        }
    }

    template <typename H, typename V, cpp_enable_if(etl::decay_traits<V>::dimensions() != 2)>
    void batch_activate_hidden(H&& output, const V& input) const {
        auto Batch = etl::dim<0>(input);

        cpp_assert(etl::dim<0>(output) == Batch, "The number of samples must be consistent");

        if (activation_function == function::SOFTMAX) {
            auto expr = etl::force_temporary(etl::rep_l(b, Batch) + etl::reshape(input, Batch, num_visible) * w);

            for (std::size_t i = 0; i < Batch; ++i) {
                output(i) = f_activate<activation_function>(expr(i));
            }
        } else {
            output = f_activate<activation_function>(etl::rep_l(b, Batch) + etl::reshape(input, Batch, num_visible) * w);
        }
    }

    template <typename DBN>
    void init_sgd_context() {
        this->sgd_context_ptr = std::make_shared<sgd_context<DBN, this_type>>(num_visible, num_hidden);
    }

    template <typename Input>
    output_one_t prepare_one_output() const {
        return output_one_t(num_hidden);
    }

    template <typename Input>
    output_t prepare_output(std::size_t samples) const {
        output_t output;
        output.reserve(samples);
        for(std::size_t i = 0; i < samples; ++i){
            output.emplace_back(num_hidden);
        }
        return output;
    }

    void prepare_input(input_one_t& input) const {
        input = input_one_t(num_visible);
    }

    template<typename DRBM>
    static void dyn_init(DRBM&){
        //Nothing to change
    }

    /*!
     * \brief Adapt the errors, called before backpropagation of the errors.
     *
     * This must be used by layers that have both an activation fnction and a non-linearity.
     *
     * \param context the training context
     */
    template<typename C>
    void adapt_errors(C& context) const {
        context.errors = f_derivative<activation_function>(context.output) >> context.errors;
    }

    /*!
     * \brief Backpropagate the errors to the previous layers
     * \param output The ETL expression into which write the output
     * \param context The training context
     */
    template<typename H, typename C>
    void backward_batch(H&& output, C& context) const {
        // The reshape has no overhead, so better than SFINAE for nothing
        auto batch_size = etl::dim<0>(output);
        etl::reshape(output, batch_size, num_visible) = context.errors * etl::transpose(w);
    }

    /*!
     * \brief Compute the gradients for this layer, if any
     * \param context The trainng context
     */
    template<typename C>
    void compute_gradients(C& context) const {
        context.w_grad = batch_outer(context.input, context.errors);
        context.b_grad = etl::sum_l(context.errors);
    }
};

// Declare the traits for the Layer

template<typename Desc>
struct layer_base_traits<dyn_dense_layer<Desc>> {
    static constexpr bool is_neural     = true;  ///< Indicates if the layer is a neural layer
    static constexpr bool is_dense      = true;  ///< Indicates if the layer is dense
    static constexpr bool is_conv       = false; ///< Indicates if the layer is convolutional
    static constexpr bool is_deconv     = false; ///< Indicates if the layer is deconvolutional
    static constexpr bool is_standard   = true;  ///< Indicates if the layer is standard
    static constexpr bool is_rbm        = false; ///< Indicates if the layer is RBM
    static constexpr bool is_pooling    = false; ///< Indicates if the layer is a pooling layer
    static constexpr bool is_unpooling  = false; ///< Indicates if the layer is an unpooling laye
    static constexpr bool is_transform  = false; ///< Indicates if the layer is a transform layer
    static constexpr bool is_patches    = false; ///< Indicates if the layer is a patches layer
    static constexpr bool is_augment    = false; ///< Indicates if the layer is an augment layer
    static constexpr bool is_dynamic    = true;  ///< Indicates if the layer is dynamic
    static constexpr bool pretrain_last = false; ///< Indicates if the layer is dynamic
    static constexpr bool sgd_supported = true;  ///< Indicates if the layer is supported by SGD
};

} //end of dll namespace
<|endoftext|>