<commit_before>#include <string>
#include <fstream>
#include <iostream>
#include <Eigen/Dense>
#include "umintl/check_grad.hpp"
#include "umintl/backends/eigen.hpp"
#include "umintl/minimize.hpp"

typedef double ScalarType;
typedef Eigen::Matrix<ScalarType,Eigen::Dynamic,Eigen::Dynamic> MatrixType;
typedef Eigen::Matrix<ScalarType,Eigen::Dynamic,1> VectorType;
typedef Eigen::Matrix<int,Eigen::Dynamic,1> LabelType;

typedef umintl::backend::eigen_types<ScalarType> BackendType;

inline void sigmoid(MatrixType const & in, MatrixType & out)
{
    out = -in;
    out = 1/(1+out.array().exp());
}

inline void swap(int &val)
{
        val = (val<<24) | ((val<<8) & 0x00ff0000) | ((val>>8) & 0x0000ff00) | (val>>24);
}

MatrixType read_mnist_images(std::string filename)
{
  MatrixType X;
  std::ifstream fs(filename.c_str(), std::ios::binary);
  if(fs) {
    int magic_number, num_images, num_rows, num_columns;
    fs.read((char*)&magic_number, sizeof(magic_number));
    fs.read((char*)&num_images, sizeof(num_images));
    fs.read((char*)&num_rows, sizeof(num_rows));
    fs.read((char*)&num_columns, sizeof(num_columns));
    if (magic_number != 2051) {
      swap(magic_number);
      swap(num_images);
      swap(num_rows);
      swap(num_columns);
    }
    //num_images = 1000;
    X = MatrixType::Zero(num_rows*num_columns, num_images);

    for (int i=0; i<num_images; ++i) {
      for (int j=0; j<num_rows*num_columns; ++j) {
        unsigned char temp=0;
        fs.read((char*)&temp,sizeof(temp));
        X(j,i) = (double) temp;
      }
    }
    fs.close();
  } else {
    std::cerr << "error reading file: " << filename << std::endl;
    exit(1);
  }
  return X;
}

LabelType read_mnist_labels(std::string  filename)
{
  LabelType Y;
  std::ifstream fs(filename.c_str(), std::ios::binary);
  if(fs) {
    int magic_number, num_images;
    fs.read((char*)&magic_number, sizeof(magic_number));
    fs.read((char*)&num_images, sizeof(num_images));
    if (magic_number != 2049) {
      swap(magic_number);
      swap(num_images);
    }
    //num_images = 1000;

    Y = LabelType::Zero(num_images);

    for (int i=0; i<num_images; ++i) {
      unsigned char temp=0;
      fs.read((char*)&temp,sizeof(temp));
      Y(i) = (int) temp;
    }
    fs.close();
  } else {
    std::cerr << "error reading file: " << filename << std::endl;
    exit(1);
  }
  return Y;
}

struct temporaries_holder{

};

class neural_net{
private:

    template<class T>
    void feedforward(Eigen::MatrixBase<T> const & data) const{
        //Hidden
        Z1 = weights_1*data;
        Z1.colwise() += bias_1;
        sigmoid(Z1,A1);

        //Final output
        Z2 = weights_2*A1;
        Z2.colwise() += bias_2;
        A2 = Z2.array().exp();
        VectorType sum_exp = A2.colwise().sum();

        for(std::size_t i = 0 ; i < A2.rows() ; ++i)
            A2.row(i) = A2.row(i).array() / sum_exp.transpose().array();
    }

    template<class T, class U>
    void backpropagate(Eigen::MatrixBase<T> const & data, Eigen::MatrixBase<U> const & labels) const{
        D2 = A2;
        for(std::size_t j = 0 ; j < block_size_ ; ++j){
            D2(labels(j),j)-=1;
        }

        dbias_2 = D2.rowwise().sum();
        dweights_2 = D2*A1.transpose();

        D1 = weights_2.transpose()*D2;
        D1 = D1.array()*A1.array()*(1-A1.array());
        dweights_1 = D1*data.transpose();
        dbias_1 = D1.rowwise().sum();
    }

    template<class T>
    ScalarType get_cost(Eigen::MatrixBase<T> const & labels) const{
        ScalarType cross_entropy = 0;
        for(int j = 0 ; j < Z2.cols() ; ++j){
            cross_entropy-=log(A2(labels(j),j));
        }
        return cross_entropy;
    }

public:
    class early_stopper : public umintl::stopping_criterion<BackendType>{
    public:
        early_stopper(neural_net const & net, MatrixType const & validation_data, LabelType const & validation_labels) : net_(net), validation_data_(validation_data), validation_labels_(validation_labels), best_cost_(INFINITY){ }
        bool operator()(umintl::detail::optimization_context<BackendType> & c){
            if(c.iter()%10==0){
                net_.set_weights(c.x());
                net_.feedforward(validation_data_);
                ScalarType cross_entropy = net_.get_cost(validation_labels_);
                bool stop = (cross_entropy/best_cost_)>1.05;
                if(cross_entropy<best_cost_){
                    best_cost_ = cross_entropy;
                    best_x_=c.x();
                }
                best_cost_ = std::min(best_cost_, cross_entropy);
                std::cout << "Current validation error : " << cross_entropy << std::endl;
                return stop;
            }
            return false;
        }
        VectorType const & best_x(){ return best_x_; }

    private:
        neural_net const & net_;

        MatrixType const & validation_data_;
        LabelType const & validation_labels_;

        VectorType best_x_;
        ScalarType best_cost_;
    };

    early_stopper * create_early_stopping(MatrixType const & validation_data, LabelType const & validation_labels)
    {
        return new early_stopper(*this,validation_data,validation_labels);
    }

public:
    neural_net(MatrixType const & data, LabelType const & labels,
       std::size_t n_hidden, std::size_t block_size) :
        data_(data), labels_(labels),default_block_size_(std::min((std::size_t)data.cols()-1,block_size)), block_size_(default_block_size_), offset_(1)
      ,n_in_(data.rows()), n_hidden_(n_hidden), n_out_(labels.maxCoeff()+1)
    {
        weights_1.resize(n_hidden_,n_in_);
        bias_1.resize(n_hidden_);
        weights_2.resize(n_out_,n_hidden_);
        bias_2.resize(n_out_);
    }

    void set_weights(VectorType const & X) const{
        std::size_t offset = 0;
        //Layer1
        for(std::size_t i = 0 ; i < n_hidden_ ; ++i)
            for(std::size_t j = 0 ; j < n_in_ ; ++j)
                weights_1(i,j) = X[offset++];
        for(std::size_t i = 0 ; i < n_hidden_ ; ++i)
            bias_1(i) = X[offset++];

        //Layer2
        for(std::size_t i = 0 ; i < n_out_ ; ++i)
            for(std::size_t j = 0 ; j < n_hidden_ ; ++j)
                weights_2(i,j) = X[offset++];
        for(std::size_t i = 0 ; i < n_out_ ; ++i)
            bias_2(i) = X[offset++];

    }

    float misclassified_rate(MatrixType const & data, LabelType const & labels){
        feedforward(data);
        unsigned int n_misclassified = 0;
        for(std::size_t j = 0 ; j < labels.rows() ; ++j){
            unsigned int prediction;
            A2.col(j).maxCoeff(&prediction);
            n_misclassified+= static_cast<unsigned int>(labels(j)!=prediction);
        }
        return (float)n_misclassified/labels.rows()*100;
    }

    std::size_t n_params() const{
        return n_hidden_*n_in_+n_hidden_ + n_out_*n_hidden_+n_out_;
    }

    void set_current_minibatch(std::size_t id) const{
        offset_ = id*default_block_size_+1;
        block_size_ = std::min(default_block_size_, data_.cols()-offset_);
    }

    void operator()(VectorType const & X, ScalarType * val, VectorType * grad)const{
        //Unroll
        set_weights(X);
        //Hidden
        feedforward(data_.block(0,offset_,data_.rows(),block_size_));
        if(val){
            *val = get_cost(labels_.segment(offset_,block_size_));
        }
        if(grad){
            backpropagate(data_.block(0,offset_,data_.rows(),block_size_),labels_.segment(offset_,block_size_));

            //Reroll
            std::size_t offset = 0;
            //Layer1
            for(std::size_t i = 0 ; i < n_hidden_ ; ++i)
                for(std::size_t j = 0 ; j < n_in_ ; ++j)
                    (*grad)[offset++] = dweights_1(i,j);
            for(std::size_t i = 0 ; i < n_hidden_ ; ++i)
                (*grad)[offset++] = dbias_1(i);

            //Layer2
            for(std::size_t i = 0 ; i < n_out_ ; ++i)
                for(std::size_t j = 0 ; j < n_hidden_ ; ++j)
                    (*grad)[offset++] = dweights_2(i,j);
            for(std::size_t i = 0 ; i < n_out_ ; ++i)
                (*grad)[offset++] = dbias_2(i);
        }
    }

private:
    friend class early_stopper;

    mutable MatrixType weights_1;
    mutable VectorType bias_1;

    mutable  MatrixType weights_2;
    mutable VectorType bias_2;

    mutable MatrixType Z1;
    mutable MatrixType A1;
    mutable MatrixType Z2;
    mutable MatrixType A2;

    mutable MatrixType D2;
    mutable MatrixType D1;

    mutable MatrixType dweights_1;
    mutable MatrixType dbias_1;

    mutable MatrixType dweights_2;
    mutable MatrixType dbias_2;

    MatrixType const & data_;
    LabelType const & labels_;

    std::size_t default_block_size_;

    mutable std::size_t block_size_;
    mutable std::size_t offset_;

    std::size_t n_in_;
    std::size_t n_hidden_;
    std::size_t n_out_;
};

int main(int argc, char* argv[]){
    if (argc != 2) {
      std::cout << "please provide path to mnist data ..." << std::endl;
      std::cout << "you can download the dataset at http://yann.lecun.com/exdb/mnist/" << std::endl;
      std::cout << std::endl << "usage: " << argv[0] << " path_to_data" << std::endl << std::endl;
      return 1;
    }

    std::string path = argv[1];

    std::cout << "#Reading data..." << std::flush;
    MatrixType training_data = read_mnist_images(path + "/train-images.idx3-ubyte");
    LabelType training_label = read_mnist_labels(path + "/train-labels.idx1-ubyte");
    MatrixType testing_data = read_mnist_images(path + "/t10k-images.idx3-ubyte");
    LabelType testing_label = read_mnist_labels(path + "/t10k-labels.idx1-ubyte");

//    MatrixType training_data = MatrixType::Random(5,10);
//    LabelType training_label = LabelType::Zero(10);
//    for(std::size_t i = 0 ; i < 10 ; ++i)
//        training_label(i) = rand()%10;
//    MatrixType testing_data = MatrixType::Random(5,10);
//    LabelType testing_label = LabelType::Zero(10);
//    for(std::size_t i = 0 ; i < 10 ; ++i)
//        testing_label(i) = rand()%10;

    std::cout << "done!" << std::endl;

    std::cout << "#Initializing the network..." << std::flush;
    std::size_t block_size = training_data.cols();
    neural_net network(training_data,training_label,500,block_size);
    VectorType Res(network.n_params());
    for(std::size_t i = 0 ; i < Res.rows() ; ++i)
        Res(i) = (ScalarType)rand()/RAND_MAX - 0.5;

    std::cout << "done!" << std::endl;

    //std::cout << "#Checking gradient..." << std::flush;
    //std::cout << "Maximum relative error : " << umintl::check_grad<BackendType>(network,Res,Res.rows(),1e-6) << std::endl;

    umintl::minimizer<BackendType> optimization;
    //optimization.direction = new umintl::conjugate_gradient<BackendType>();
    //optimization.direction = new umintl::steepest_descent<BackendType>();
    optimization.direction = new umintl::quasi_newton<BackendType>(new umintl::lbfgs<BackendType>(8));
    neural_net::early_stopper * stop = network.create_early_stopping(testing_data,testing_label);
    optimization.stopping_criterion = stop;
    optimization.max_iter = 1000;
    optimization.verbosity_level=2;
    //optimization.minibatch_policy = new umintl::with_minibatch<neural_net>(training_data.cols()/block_size,network);
    optimization(Res,network,Res,Res.rows());
    network.set_weights(stop->best_x());
    std::cout << "Training complete!" << std::endl;
    std::cout << "Test error rate : " << network.misclassified_rate(testing_data, testing_label) << "%" << std::endl;

}
<commit_msg>Cleaned MNIST code - added deeper layer<commit_after>#include <string>
#include <fstream>
#include <iostream>
#include <Eigen/Dense>
#include "umintl/check_grad.hpp"
#include "umintl/backends/eigen.hpp"
#include "umintl/minimize.hpp"

typedef double ScalarType;
typedef Eigen::Matrix<ScalarType,Eigen::Dynamic,Eigen::Dynamic> MatrixType;
typedef Eigen::Matrix<ScalarType,Eigen::Dynamic,1> VectorType;
typedef Eigen::Matrix<int,Eigen::Dynamic,1> LabelType;

typedef umintl::backend::eigen_types<ScalarType> BackendType;

inline void sigmoid(MatrixType const & in, MatrixType & out)
{
    out = -in;
    out = 1/(1+out.array().exp());
}

inline void softmax(MatrixType const & in, MatrixType & out)
{
    out = in.array().exp();
    VectorType sum_exp = out.colwise().sum();
    for(std::size_t i = 0 ; i < out.rows() ; ++i)
        out.row(i) = out.row(i).array() / sum_exp.transpose().array();
}

inline void swap(int &val)
{
        val = (val<<24) | ((val<<8) & 0x00ff0000) | ((val>>8) & 0x0000ff00) | (val>>24);
}

MatrixType read_mnist_images(std::string filename)
{
  MatrixType X;
  std::ifstream fs(filename.c_str(), std::ios::binary);
  if(fs) {
    int magic_number, num_images, num_rows, num_columns;
    fs.read((char*)&magic_number, sizeof(magic_number));
    fs.read((char*)&num_images, sizeof(num_images));
    fs.read((char*)&num_rows, sizeof(num_rows));
    fs.read((char*)&num_columns, sizeof(num_columns));
    if (magic_number != 2051) {
      swap(magic_number);
      swap(num_images);
      swap(num_rows);
      swap(num_columns);
    }
    //num_images = 1000;
    X = MatrixType::Zero(num_rows*num_columns, num_images);

    for (int i=0; i<num_images; ++i) {
      for (int j=0; j<num_rows*num_columns; ++j) {
        unsigned char temp=0;
        fs.read((char*)&temp,sizeof(temp));
        X(j,i) = (double) temp;
      }
    }
    fs.close();
  } else {
    std::cerr << "error reading file: " << filename << std::endl;
    exit(1);
  }
  return X;
}

LabelType read_mnist_labels(std::string  filename)
{
  LabelType Y;
  std::ifstream fs(filename.c_str(), std::ios::binary);
  if(fs) {
    int magic_number, num_images;
    fs.read((char*)&magic_number, sizeof(magic_number));
    fs.read((char*)&num_images, sizeof(num_images));
    if (magic_number != 2049) {
      swap(magic_number);
      swap(num_images);
    }
    //num_images = 1000;

    Y = LabelType::Zero(num_images);

    for (int i=0; i<num_images; ++i) {
      unsigned char temp=0;
      fs.read((char*)&temp,sizeof(temp));
      Y(i) = (int) temp;
    }
    fs.close();
  } else {
    std::cerr << "error reading file: " << filename << std::endl;
    exit(1);
  }
  return Y;
}

class neural_net{
private:

    template<class T>
    void feedforward(Eigen::MatrixBase<T> const & data) const{
        for(std::size_t L = 0 ; L < n_layers_; ++L){
            if(L==0)
                Z[L] = weights[L]*data;
            else
                Z[L] = weights[L]*A[L-1];
            Z[L].colwise() += bias[L];

            if(L==n_layers_-1)
                softmax(Z[L],A[L]);
            else
                sigmoid(Z[L],A[L]);
        }
    }

    template<class T, class U>
    void backpropagate(Eigen::MatrixBase<T> const & data, Eigen::MatrixBase<U> const & labels) const{
        for(int L = n_layers_-1 ; L>=0 ; --L){
            //Compute delta
            if(L==n_layers_-1){
                D[L] = A[L];
                for(std::size_t j = 0 ; j < block_size_ ; ++j){
                    D[L](labels(j),j)-=1;
                }
            }
            else{
                D[L] = weights[L+1].transpose()*D[L+1];
                D[L] = D[L].array()*A[L].array()*(1-A[L].array());
            }

            //Compute derivatives
            if(L==0)
                dweights[L] = D[L]*data.transpose();
            else
                dweights[L] = D[L]*A[L-1].transpose();

            dbias[L] = D[L].rowwise().sum();
        }
    }

    template<class T>
    ScalarType get_cost(Eigen::MatrixBase<T> const & labels) const{
        ScalarType cross_entropy = 0;
        for(int j = 0 ; j < A.back().cols() ; ++j){
            cross_entropy-=log(A.back()(labels(j),j));
        }
        return cross_entropy;
    }

public:
    class early_stopper : public umintl::stopping_criterion<BackendType>{
    public:
        early_stopper(neural_net const & net, MatrixType const & validation_data, LabelType const & validation_labels) : net_(net), validation_data_(validation_data), validation_labels_(validation_labels), best_cost_(INFINITY){ }
        bool operator()(umintl::detail::optimization_context<BackendType> & c){
            if(c.iter()%10==0){
                net_.set_weights(c.x());
                net_.feedforward(validation_data_);
                ScalarType cross_entropy = net_.get_cost(validation_labels_);
                bool stop = (cross_entropy/best_cost_)>1.05;
                if(cross_entropy<best_cost_){
                    best_cost_ = cross_entropy;
                    best_x_=c.x();
                }
                best_cost_ = std::min(best_cost_, cross_entropy);

                unsigned int n_misclassified = 0;
                for(std::size_t j = 0 ; j < validation_labels_.rows() ; ++j){
                    unsigned int prediction;
                    net_.A.back().col(j).maxCoeff(&prediction);
                    n_misclassified+= static_cast<unsigned int>(validation_labels_(j)!=prediction);
                }
                std::cout << "Misclassified on test set : " << (float)n_misclassified/validation_labels_.rows()*100 << "%" << std::endl;

                return stop;
            }
            return false;
        }
        VectorType const & best_x(){ return best_x_; }

    private:
        neural_net const & net_;

        MatrixType const & validation_data_;
        LabelType const & validation_labels_;

        VectorType best_x_;
        ScalarType best_cost_;
    };

    early_stopper * create_early_stopping(MatrixType const & validation_data, LabelType const & validation_labels)
    {
        return new early_stopper(*this,validation_data,validation_labels);
    }

public:
    neural_net(MatrixType const & data, LabelType const & labels,
       std::vector<std::size_t> const & hidden_sizes, std::size_t block_size) :
        data_(data), labels_(labels),default_block_size_(std::min((std::size_t)data.cols()-1,block_size)), block_size_(default_block_size_), offset_(1)
    {
        layer_sizes_.push_back(data.rows());
        for(std::size_t i = 0 ; i < hidden_sizes.size() ; ++i)
            layer_sizes_.push_back(hidden_sizes[i]);
        layer_sizes_.push_back(labels.maxCoeff()+1);
        n_layers_ = layer_sizes_.size() - 1;
        weights.resize(n_layers_);
        bias.resize(n_layers_);
        dweights.resize(n_layers_);
        dbias.resize(n_layers_);
        A.resize(n_layers_);
        Z.resize(n_layers_);
        D.resize(n_layers_);

        for(std::size_t L = 0 ; L < n_layers_; ++L){
            weights[L].resize(layer_sizes_[L+1], layer_sizes_[L]);
            bias[L].resize(layer_sizes_[L+1]);
        }
    }

    void set_weights(VectorType const & X) const{
        std::size_t offset = 0;
        for(std::size_t L = 0 ; L < n_layers_ ; ++L){
            for(std::size_t i = 0 ; i < weights[L].rows() ; ++i)
                for(std::size_t j = 0 ; j < weights[L].cols() ; ++j)
                    weights[L](i,j) = X[offset++];
            for(std::size_t i = 0 ; i < bias[L].rows() ; ++i)
                bias[L](i) = X[offset++];
        }

    }

    float misclassified_rate(MatrixType const & data, LabelType const & labels){
        feedforward(data);
        unsigned int n_misclassified = 0;
        for(std::size_t j = 0 ; j < labels.rows() ; ++j){
            unsigned int prediction;
            A.back().col(j).maxCoeff(&prediction);
            n_misclassified+= static_cast<unsigned int>(labels(j)!=prediction);
        }
        return (float)n_misclassified/labels.rows()*100;
    }

    std::size_t n_params() const{
        std::size_t res=0;
        for(std::size_t L = 0 ; L < n_layers_ ; ++L)
            res+=weights[L].rows()*weights[L].cols() + bias[L].rows();
        return res;
    }

    void set_current_minibatch(std::size_t id) const{
        offset_ = id*default_block_size_+1;
        block_size_ = std::min(default_block_size_, data_.cols()-offset_);
    }

    void operator()(VectorType const & X, ScalarType * val, VectorType * grad)const{
        set_weights(X);
        feedforward(data_.block(0,offset_,data_.rows(),block_size_));
        if(val)
            *val = get_cost(labels_.segment(offset_,block_size_));

//        unsigned int n_misclassified = 0;
//        for(std::size_t j = 0 ; j < labels_.rows() ; ++j){
//            unsigned int prediction;
//            A.back().col(j).maxCoeff(&prediction);
//            n_misclassified+= static_cast<unsigned int>(labels_(j)!=prediction);
//        }
//        std::cout << "Misclassified on training set : " << (float)n_misclassified/labels_.rows()*100 << "%" << std::endl;

        if(grad){
            backpropagate(data_.block(0,offset_,data_.rows(),block_size_),labels_.segment(offset_,block_size_));
            std::size_t offset = 0;
            for(std::size_t L = 0 ; L < n_layers_ ; ++L){
                for(std::size_t i = 0 ; i < dweights[L].rows() ; ++i)
                    for(std::size_t j = 0 ; j < dweights[L].cols() ; ++j)
                        (*grad)[offset++] = dweights[L](i,j);
                for(std::size_t i = 0 ; i < layer_sizes_[L+1] ; ++i)
                    (*grad)[offset++] = dbias[L](i);
            }
        }
    }

private:
    friend class early_stopper;

    mutable std::vector<MatrixType> weights;
    mutable std::vector<VectorType> bias;

    mutable std::vector<MatrixType> dweights;
    mutable std::vector<VectorType> dbias;

    mutable std::vector<MatrixType> Z;
    mutable std::vector<MatrixType> A;

    mutable std::vector<MatrixType> D;

    MatrixType const & data_;
    LabelType const & labels_;

    std::size_t default_block_size_;

    mutable std::size_t block_size_;
    mutable std::size_t offset_;

    mutable std::vector<std::size_t> layer_sizes_;
    std::size_t n_layers_;
};

int main(int argc, char* argv[]){
    if (argc != 2) {
      std::cout << "please provide path to mnist data ..." << std::endl;
      std::cout << "you can download the dataset at http://yann.lecun.com/exdb/mnist/" << std::endl;
      std::cout << std::endl << "usage: " << argv[0] << " path_to_data" << std::endl << std::endl;
      return 1;
    }

    std::string path = argv[1];

    std::cout << "#Reading data..." << std::flush;
    MatrixType training_data = read_mnist_images(path + "/train-images.idx3-ubyte");
    LabelType training_label = read_mnist_labels(path + "/train-labels.idx1-ubyte");
    MatrixType testing_data = read_mnist_images(path + "/t10k-images.idx3-ubyte");
    LabelType testing_label = read_mnist_labels(path + "/t10k-labels.idx1-ubyte");

//    MatrixType training_data = MatrixType::Random(5,100);
//    LabelType training_label = LabelType::Zero(100);
//    for(std::size_t i = 0 ; i < 10 ; ++i)
//        training_label(i) = rand()%10;
//    MatrixType testing_data = MatrixType::Random(5,100);
//    LabelType testing_label = LabelType::Zero(100);
//    for(std::size_t i = 0 ; i < 10 ; ++i)
//        testing_label(i) = rand()%10;

    std::cout << "done!" << std::endl;

    std::cout << "#Initializing the network..." << std::flush;
    std::size_t block_size = 5000;
    std::vector<std::size_t> hidden_sizes;
    hidden_sizes.push_back(300);
    hidden_sizes.push_back(500);
    neural_net network(training_data,training_label,hidden_sizes,block_size);
    VectorType Res(network.n_params());
    for(std::size_t i = 0 ; i < Res.rows() ; ++i)
        Res(i) = (ScalarType)rand()/RAND_MAX - 0.5;

    std::cout << "done!" << std::endl;

    //std::cout << "#Checking gradient..." << std::flush;
    //std::cout << "Maximum relative error : " << umintl::check_grad<BackendType>(network,Res,Res.rows(),1e-6) << std::endl;

    umintl::minimizer<BackendType> optimization;
    //optimization.direction = new umintl::conjugate_gradient<BackendType>();
    //optimization.direction = new umintl::steepest_descent<BackendType>();
    //optimization.direction = new umintl::quasi_newton<BackendType>(new umintl::lbfgs<BackendType>(8));
    neural_net::early_stopper * stop = network.create_early_stopping(testing_data,testing_label);
    optimization.stopping_criterion = stop;
    optimization.max_iter = 1000;
    optimization.verbosity_level=2;
    //optimization.minibatch_policy = new umintl::with_minibatch<neural_net>(training_data.cols()/block_size,network);
    optimization(Res,network,Res,Res.rows());
    network.set_weights(stop->best_x());
    std::cout << "Training complete!" << std::endl;
    std::cout << "Test error rate : " << network.misclassified_rate(testing_data, testing_label) << "%" << std::endl;
    std::cout << "Training error rate : " << network.misclassified_rate(training_data, training_label) << "%" << std::endl;
}
<|endoftext|>


<commit_before>/***************************************************************************
* Copyright (c) Wolf Vollprecht, Johan Mabille and Sylvain Corlay          *
* Copyright (c) QuantStack                                                 *
*                                                                          *
* Distributed under the terms of the BSD 3-Clause License.                 *
*                                                                          *
* The full license is in the file LICENSE, distributed with this software. *
****************************************************************************/

#include "gtest/gtest.h"

#include "xtensor-python/pyarray_ref.hpp"

#include "xtensor/xarray.hpp"
#include "xtensor/xview.hpp"

#include "test_common.hpp"

namespace xt
{
    using container_type = std::vector<npy_intp>;

    template <class T>
    using ndarray = pyarray_ref<T, xt::layout_type::row_major>;

    void test1 (ndarray<int>const& x)
    {
        ndarray<int> y = x;
        ndarray<int> z = xt::zeros<int>({10});
    }

    double compute(ndarray<double> const& xs)
    {
        auto v = xt::view (xs, 0, xt::all());
        return v(0);
    }

    TEST(pyarray_ref, initializer_constructor)
    {
        pyarray_ref<int> t
          {{{ 0,  1,  2},
            { 3,  4,  5},
            { 6,  7,  8}},
           {{ 9, 10, 11},
            {12, 13, 14},
            {15, 16, 17}}};

        EXPECT_EQ(t.dimension(), 3);
        EXPECT_EQ(t(0, 0, 1), 1);
        EXPECT_EQ(t.shape()[0], 2);
    }

    TEST(pyarray_ref, shaped_constructor)
    {
        {
            SCOPED_TRACE("row_major constructor");
            row_major_result<> rm;
            pyarray_ref<int> ra(rm.m_shape);
            compare_shape(ra, rm);
            EXPECT_EQ(layout_type::row_major, ra.layout());
        }

        {
            SCOPED_TRACE("column_major constructor");
            column_major_result<> cm;
            pyarray_ref<int> ca(cm.m_shape, layout_type::column_major);
            compare_shape(ca, cm);
            EXPECT_EQ(layout_type::column_major, ca.layout());
        }
    }

    TEST(pyarray_ref, from_shape)
    {
        auto arr = pyarray_ref<double>::from_shape({5, 2, 6});
        auto exp_shape = std::vector<std::size_t>{5, 2, 6};
        EXPECT_TRUE(std::equal(arr.shape().begin(), arr.shape().end(), exp_shape.begin()));
        EXPECT_EQ(arr.shape().size(), 3);
        EXPECT_EQ(arr.size(), 5 * 2 * 6);
    }

    TEST(pyarray_ref, strided_constructor)
    {
        central_major_result<> cmr;
        pyarray_ref<int> cma(cmr.m_shape, cmr.m_strides);
        compare_shape(cma, cmr);
    }

    TEST(pyarray_ref, valued_constructor)
    {
        {
            SCOPED_TRACE("row_major valued constructor");
            row_major_result<> rm;
            int value = 2;
            pyarray_ref<int> ra(rm.m_shape, value);
            compare_shape(ra, rm);
            std::vector<int> vec(ra.size(), value);
            EXPECT_TRUE(std::equal(vec.cbegin(), vec.cend(), ra.storage().cbegin()));
        }

        {
            SCOPED_TRACE("column_major valued constructor");
            column_major_result<> cm;
            int value = 2;
            pyarray_ref<int> ca(cm.m_shape, value, layout_type::column_major);
            compare_shape(ca, cm);
            std::vector<int> vec(ca.size(), value);
            EXPECT_TRUE(std::equal(vec.cbegin(), vec.cend(), ca.storage().cbegin()));
        }
    }

    TEST(pyarray_ref, strided_valued_constructor)
    {
        central_major_result<> cmr;
        int value = 2;
        pyarray_ref<int> cma(cmr.m_shape, cmr.m_strides, value);
        compare_shape(cma, cmr);
        std::vector<int> vec(cma.size(), value);
        EXPECT_TRUE(std::equal(vec.cbegin(), vec.cend(), cma.storage().cbegin()));
    }

    TEST(pyarray_ref, copy_semantic)
    {
        central_major_result<> res;
        int value = 2;
        pyarray_ref<int> a(res.m_shape, res.m_strides, value);

        {
            SCOPED_TRACE("copy constructor");
            pyarray_ref<int> b(a);
            compare_shape(a, b);
            EXPECT_EQ(a.storage(), b.storage());
            a.data()[0] += 1;
            EXPECT_EQ(a.storage()[0], b.storage()[0]);
        }

        {
            SCOPED_TRACE("assignment operator");
            row_major_result<> r;
            pyarray_ref<int> c(r.m_shape, 0);
            EXPECT_NE(a.storage(), c.storage());
            c = a;
            compare_shape(a, c);
            EXPECT_EQ(a.storage(), c.storage());
            a.data()[0] += 1;
            EXPECT_EQ(a.storage()[0], c.storage()[0]);
        }
    }

    TEST(pyarray_ref, move_semantic)
    {
        central_major_result<> res;
        int value = 2;
        pyarray_ref<int> a(res.m_shape, res.m_strides, value);

        {
            SCOPED_TRACE("move constructor");
            pyarray_ref<int> tmp(a);
            pyarray_ref<int> b(std::move(tmp));
            compare_shape(a, b);
            EXPECT_EQ(a.storage(), b.storage());
        }

        {
            SCOPED_TRACE("move assignment");
            row_major_result<> r;
            pyarray_ref<int> c(r.m_shape, 0);
            EXPECT_NE(a.storage(), c.storage());
            pyarray_ref<int> tmp(a);
            c = std::move(tmp);
            compare_shape(a, c);
            EXPECT_EQ(a.storage(), c.storage());
        }
    }

    TEST(pyarray_ref, extended_constructor)
    {
        xt::xarray<int> a1 = { { 1, 2 },{ 3, 4 } };
        xt::xarray<int> a2 = { { 1, 2 },{ 3, 4 } };
        pyarray_ref<int> c = a1 + a2;
        EXPECT_EQ(c(0, 0), a1(0, 0) + a2(0, 0));
        EXPECT_EQ(c(0, 1), a1(0, 1) + a2(0, 1));
        EXPECT_EQ(c(1, 0), a1(1, 0) + a2(1, 0));
        EXPECT_EQ(c(1, 1), a1(1, 1) + a2(1, 1));
    }

    TEST(pyarray_ref, resize)
    {
        pyarray_ref<int> a;
        test_resize(a);

        pyarray_ref<int> b = { {1, 2}, {3, 4} };
        a.resize(b.shape());
        EXPECT_EQ(a.shape(), b.shape());
    }

    TEST(pyarray_ref, transpose)
    {
        pyarray_ref<int> a;
        test_transpose(a);
    }

    TEST(pyarray_ref, access)
    {
        pyarray_ref<int> a;
        test_access(a);
    }

    TEST(pyarray_ref, indexed_access)
    {
        pyarray_ref<int> a;
        test_indexed_access(a);
    }

    TEST(pyarray_ref, broadcast_shape)
    {
        pyarray_ref<int> a;
        test_broadcast(a);
        test_broadcast2(a);
    }

    TEST(pyarray_ref, iterator)
    {
        pyarray_ref<int> a;
        pyarray_ref<int> b;
        test_iterator(a, b);

        pyarray_ref<int, layout_type::row_major> c;
        bool truthy = std::is_same<decltype(c.begin()), int*>::value;
        EXPECT_TRUE(truthy);
    }

    TEST(pyarray_ref, initializer_list)
    {
        pyarray_ref<int> a0(1);
        pyarray_ref<int> a1({1, 2});
        pyarray_ref<int> a2({{1, 2}, {2, 4}, {5, 6}});
        EXPECT_EQ(1, a0());
        EXPECT_EQ(2, a1(1));
        EXPECT_EQ(4, a2(1, 1));
    }

    TEST(pyarray_ref, zerod)
    {
        pyarray_ref<int> a;
        EXPECT_EQ(0, a());
    }

    TEST(pyarray_ref, reshape)
    {
        pyarray_ref<int> a = {{1,2,3}, {4,5,6}};
        auto ptr = a.data();
        a.reshape({1, 6});
        std::vector<std::size_t> sc1({1, 6});
        EXPECT_TRUE(std::equal(sc1.begin(), sc1.end(), a.shape().begin()) && a.shape().size() == 2);
        EXPECT_EQ(ptr, a.data());
        a.reshape({6});
        std::vector<std::size_t> sc2 = {6};
        EXPECT_TRUE(std::equal(sc2.begin(), sc2.end(), a.shape().begin()) && a.shape().size() == 1);
        EXPECT_EQ(ptr, a.data());
    }

    TEST(pyarray_ref, view)
    {
        xt::pyarray_ref<int> arr = xt::zeros<int>({ 10 });
        auto v = xt::view(arr, xt::all());
        EXPECT_EQ(v(0), 0.);
    }

    TEST(pyarray_ref, zerod_copy)
    {
        xt::pyarray_ref<int> arr = 2;
        xt::pyarray_ref<int> arr2(arr);
        EXPECT_EQ(arr(), arr2());
    }
}
<commit_msg>Removed irrelevant test_pyarray_ref file<commit_after><|endoftext|>


<commit_before>/******************************************************************************\
* File:          extension.cpp
* Purpose:       Implementation of wxWidgets extension methods
* Author:        Anton van Wezenbeek
* RCS-ID:        $Id$
*
* Copyright (c) 1998-2008 Anton van Wezenbeek
* All rights are reserved. Reproduction in whole or part is prohibited
* without the written consent of the copyright owner.
\******************************************************************************/

#include <wx/clipbrd.h>
#include <wx/colordlg.h>
#include <wx/dir.h>
#include <wx/stdpaths.h>
#include <wx/tokenzr.h>
#include <wx/extension/extension.h>
#include <wx/extension/stc.h>

bool exApp::m_Logging = false;
wxString exApp::m_CatalogDir;
exConfig* exApp::m_Config = NULL;
exLexers* exApp::m_Lexers = NULL;
wxLocale exApp::m_Locale;
#if wxUSE_HTML & wxUSE_PRINTING_ARCHITECTURE
wxHtmlEasyPrinting* exApp::m_Printer = NULL;
#endif

int exApp::OnExit()
{
#if wxUSE_GUI
  exSTC::CleanUp();
#endif

  delete m_Lexers;
  delete m_Config;
#if wxUSE_HTML & wxUSE_PRINTING_ARCHITECTURE
  delete m_Printer;
#endif
  return wxApp::OnExit();
}

bool exApp::OnInit()
{
  // Init the localization, from now on things will be translated.
  // So do this before constructing config and exTool::Initialize, as these use localization.
  if (m_Locale.Init())
  {
    // If there are catalogs in the catalog_dir, then add them to the locale.
    wxArrayString files;

    // README: We use the canonical name, also for windows, not sure whether that is
    // the best.
    m_CatalogDir = wxStandardPaths::Get().GetLocalizedResourcesDir(
      m_Locale.GetCanonicalName(),
      // This seems to be necessarty for wxGTK. For wxMSW it isn't used.
      wxStandardPaths::ResourceCat_Messages);

    if (wxFileName::DirExists(m_CatalogDir))
    {
      wxDir::GetAllFiles(m_CatalogDir, &files);

      for (size_t i = 0 ; i < files.GetCount(); i++)
      {
        // Default the wxstd is already loaded by m_Locale.Init(),
        // so do not do it twice.
        const wxFileName fn(files.Item(i));

        if (!m_Locale.IsLoaded(fn.GetName()))
        {
          if (!m_Locale.AddCatalog(fn.GetName()))
          {
            wxLogError("Catalog could not be added: " + fn.GetName());
          }
        }
      }
    }
  }

  // Now construct the config, as most classes use it.
#ifdef EX_PORTABLE
  m_Config = new exConfig(
    wxFileName(
      wxFileName(wxStandardPaths::Get().GetExecutablePath()).GetPath(),
      wxTheApp->GetAppName() + wxString(".cfg")).GetFullPath());
#else
  m_Config = new exConfig();
#endif

  // And construct and read the lexers.
  m_Lexers = new exLexers();
  m_Lexers->Read();

#if wxUSE_HTML & wxUSE_PRINTING_ARCHITECTURE
  m_Printer = new wxHtmlEasyPrinting();
#endif

  // Finally call all available static initializers.
  exTool::Initialize();
  exSTC::PathListInit();

  return wxApp::OnInit();
}

#if wxUSE_GUI
void exBackgroundColourDialog(wxWindow* parent, wxWindow* win)
{
  wxColourData data;
  data.SetColour(win->GetBackgroundColour());
  wxColourDialog dlg(parent, &data);

  if (dlg.ShowModal())
  {
    win->SetBackgroundColour(dlg.GetColourData().GetColour());
    win->Refresh();
  }
}

bool exCommitDialog(const wxString& caption)
{
  std::vector<exConfigItem> v;
  v.push_back(exConfigItem(_("Revision comment")));
  v.push_back(exConfigItem(_("Base folder"), CONFIG_COMBOBOXDIR, wxEmptyString, true));

  if (exConfigDialog(wxTheApp->GetTopWindow(),
    v,
    caption).ShowModal() == wxID_CANCEL)
  {
    return false;
  }

  const wxString cwd = wxGetCwd();
  wxSetWorkingDirectory(exApp::GetConfig(_("Base folder")));
  wxArrayString output;
  wxArrayString errors;
  wxExecute(
    "svn commit -m \'" + exApp::GetConfig(_("Revision comment")) + "\"",
    output,
    errors);
  wxSetWorkingDirectory(cwd);

  wxString msg;
  for (size_t i = 0; i < output.GetCount(); i++)
  {
    msg += output[i];
  }

  exFrame::StatusText(msg);

  return true;
}

bool exClipboardAdd(const wxString& text)
{
  wxClipboardLocker locker;
  if (!locker) return false;
  if (!wxTheClipboard->AddData(new wxTextDataObject(text))) return false;
  if (!wxTheClipboard->Flush()) return false; // take care that clipboard data remain after exiting
  return true;
}

const wxString exClipboardGet()
{
  wxBusyCursor wait;
  wxClipboardLocker locker;

  if (!locker)
  {
    wxLogError("Cannot open clipboard");
    return wxEmptyString;
  }

  if (!wxTheClipboard->IsSupported(wxDF_TEXT))
  {
    wxLogError("Clipboard format not supported");
    return wxEmptyString;
  }

  wxTextDataObject data;
  if (!wxTheClipboard->GetData(data))
  {
    wxLogError("Cannot get clipboard data");
    return wxEmptyString;
  }

  return data.GetText();
}

long exColourToLong(const wxColour& c)
{
  return c.Red() | (c.Green() << 8) | (c.Blue() << 16);
}

void exComboBoxFromString(
  wxComboBox* cb,
  const wxString& text,
  const wxChar field_separator)
{
  wxStringTokenizer tkz(text, field_separator);
  while (tkz.HasMoreTokens())
  {
    const wxString val = tkz.GetNextToken();
    if (cb->FindString(val) == wxNOT_FOUND)
    {
      cb->Append(val);
    }
  }

  if (cb->GetCount() > 0) cb->SetValue(cb->GetString(0));
}

bool exComboBoxToString(
  const wxComboBox* cb,
  wxString& text,
  const wxChar field_separator,
  size_t max_items)
{
  if (cb == NULL)
  {
    return false;
  }

  text = cb->GetValue();
  switch (cb->FindString(cb->GetValue()))
  {
    case wxNOT_FOUND:
    {
      // Add the string, as it is not in the combo box, to the text,
      // simply by appending all combobox items.
      for (size_t i = 0; i < max_items; i++)
        if (i < max_items - 1 && i < cb->GetCount())
          text += field_separator + cb->GetString(i);
    }
    break;
    // No change necessary, the string is already present as the first one.
    case 0: return false; break;
    default:
    {
      // Reorder. The new first element already present, just add all others.
      for (size_t i = 0; i < cb->GetCount(); i++)
      {
        const wxString cb_element = cb->GetString(i);
        if (cb_element != cb->GetValue())
          text += field_separator + cb_element;
      }
    }
  }

  return true;
}

const wxString exEllipsed(const wxString& text, const wxString& control)
{
  return text + "..." + (!control.empty() ? "\t" + control: wxString(wxEmptyString));
}

const wxString exGetEndOfWord(
  const wxString& text,
  size_t max_chars)
{
  wxString text_out(text);

  if (text_out.length() > max_chars)
  {
    text_out = "..." + text_out.substr(text_out.length() - max_chars);
  }

  return text_out;
}

int exGetNumberOfLines(const wxString& text)
{
  if (text.empty())
  {
    return 0;
  }
  else if (text.Find(wxChar('\r')) != wxNOT_FOUND)
  {
    return text.Freq(wxChar('\r')) + 1;
  }
  else if (text.Find(wxChar('\n')) != wxNOT_FOUND)
  {
    return text.Freq(wxChar('\n')) + 1;
  }
  else
  {
    return 1;
  }
}

const wxString exGetWord(
  wxString& text,
  bool use_other_field_separators,
  bool use_path_separator)
{
  wxString field_separators = " \t";
  if (use_other_field_separators) field_separators += ":";
  if (use_path_separator) field_separators = wxFILE_SEP_PATH;
  wxString token;
  wxStringTokenizer tkz(text, field_separators);
  if (tkz.HasMoreTokens()) token = tkz.GetNextToken();
  text = tkz.GetString();
  text.Trim(false);
  return token;
}

int exGetLineNumberFromText(const wxString& text)
{
  // Get text after :.
  const size_t pos_char = text.rfind(":");

  if (pos_char == wxString::npos)
  {
    return 0;
  }

  const wxString linenumber = text.substr(pos_char + 1);

  long line;

  if (linenumber.ToLong(&line))
  {
    return line;
  }
  else
  {
    return 0;
  }
}

bool exIsBrace(int ch)
{
  return ch == '[' || ch == ']' ||
         ch == '(' || ch == ')' ||
         ch == '{' || ch == '}' ||
         ch == '<' || ch == '>';
};

bool exIsCodewordSeparator(int c)
{
  return (isspace(c) || exIsBrace(c) || c == ',' || c == ';' || c == ':');
}

bool exIsWordCharacter(wxChar c)
{
  return isalnum(c) || c == '_';
}

void exLog(const wxString& text, const wxFileName& filename)
{
  wxFile(
    filename.GetFullPath(),
    wxFile::write_append).Write(
      wxDateTime::Now().Format() + " " + text + wxTextFile::GetEOL());
}

const wxFileName exLogfileName()
{
#ifdef EX_PORTABLE
  return wxFileName(
    wxPathOnly(wxStandardPaths::Get().GetExecutablePath()),
    wxTheApp->GetAppName().Lower() + ".log");
#else
  return wxFileName(
    wxStandardPaths::Get().GetUserDataDir(),
    wxTheApp->GetAppName().Lower() + ".log");
#endif
}

bool exMatchesOneOf(const wxFileName& filename, const wxString& pattern)
{
  if (pattern == "*") return true; // asterix matches always.

  const wxString fullname_uppercase = filename.GetFullName().Upper();

  wxStringTokenizer tokenizer(pattern.Upper(), ";");
  while (tokenizer.HasMoreTokens())
  {
    if (fullname_uppercase.Matches(tokenizer.GetNextToken())) return true;
  }

  return false;
}

void exOpenFile(const wxFileName& filename, long open_flags)
{
  wxWindow* window = wxTheApp->GetTopWindow();
  exFrame* frame = wxDynamicCast(window, exFrame);

  if (frame != NULL)
  {
    frame->OpenFile(filename.GetFullPath(), -1, wxEmptyString, open_flags);
  }
}

const wxString exSkipWhiteSpace(const wxString& text, const wxString& replace_with)
{
  wxString output = text;
  wxRegEx("[ \t\n]+").ReplaceAll(&output, replace_with);
  return output;
}

#if wxUSE_STATUSBAR
void exStatusText(const exFileName& filename, long flags)
{
  wxString text; // clear status bar for empty or not existing or not initialized file names

  if (filename.IsOk())
  {
    const wxString path = (flags & STAT_FULLPATH
      ? filename.GetFullPath(): filename.GetFullName());

    text += path;

    if (filename.GetStat().IsOk())
    {
      const wxString what = (flags & STAT_SYNC
        ? _("Synchronized"): _("Modified"));
      const wxString time = (flags & STAT_SYNC
        ? wxDateTime::Now().Format(): filename.GetStat().GetModificationTime());
      text += " " + what + " " + time;
    }
  }

  exFrame::StatusText(text);
}
#endif // wxUSE_STATUSBAR

const wxString exTranslate(const wxString& text, int pageNum, int numPages)
{
  wxString translation = text;
  wxString num;

  num.Printf("%i", pageNum);
  translation.Replace("@PAGENUM@", num);

  num.Printf("%i", numPages);
  translation.Replace("@PAGESCNT@", num);

  return translation;
}
#endif // wxUSE_GUI
<commit_msg>added space between outputs"<commit_after>/******************************************************************************\
* File:          extension.cpp
* Purpose:       Implementation of wxWidgets extension methods
* Author:        Anton van Wezenbeek
* RCS-ID:        $Id$
*
* Copyright (c) 1998-2008 Anton van Wezenbeek
* All rights are reserved. Reproduction in whole or part is prohibited
* without the written consent of the copyright owner.
\******************************************************************************/

#include <wx/clipbrd.h>
#include <wx/colordlg.h>
#include <wx/dir.h>
#include <wx/stdpaths.h>
#include <wx/tokenzr.h>
#include <wx/extension/extension.h>
#include <wx/extension/stc.h>

bool exApp::m_Logging = false;
wxString exApp::m_CatalogDir;
exConfig* exApp::m_Config = NULL;
exLexers* exApp::m_Lexers = NULL;
wxLocale exApp::m_Locale;
#if wxUSE_HTML & wxUSE_PRINTING_ARCHITECTURE
wxHtmlEasyPrinting* exApp::m_Printer = NULL;
#endif

int exApp::OnExit()
{
#if wxUSE_GUI
  exSTC::CleanUp();
#endif

  delete m_Lexers;
  delete m_Config;
#if wxUSE_HTML & wxUSE_PRINTING_ARCHITECTURE
  delete m_Printer;
#endif
  return wxApp::OnExit();
}

bool exApp::OnInit()
{
  // Init the localization, from now on things will be translated.
  // So do this before constructing config and exTool::Initialize, as these use localization.
  if (m_Locale.Init())
  {
    // If there are catalogs in the catalog_dir, then add them to the locale.
    wxArrayString files;

    // README: We use the canonical name, also for windows, not sure whether that is
    // the best.
    m_CatalogDir = wxStandardPaths::Get().GetLocalizedResourcesDir(
      m_Locale.GetCanonicalName(),
      // This seems to be necessarty for wxGTK. For wxMSW it isn't used.
      wxStandardPaths::ResourceCat_Messages);

    if (wxFileName::DirExists(m_CatalogDir))
    {
      wxDir::GetAllFiles(m_CatalogDir, &files);

      for (size_t i = 0 ; i < files.GetCount(); i++)
      {
        // Default the wxstd is already loaded by m_Locale.Init(),
        // so do not do it twice.
        const wxFileName fn(files.Item(i));

        if (!m_Locale.IsLoaded(fn.GetName()))
        {
          if (!m_Locale.AddCatalog(fn.GetName()))
          {
            wxLogError("Catalog could not be added: " + fn.GetName());
          }
        }
      }
    }
  }

  // Now construct the config, as most classes use it.
#ifdef EX_PORTABLE
  m_Config = new exConfig(
    wxFileName(
      wxFileName(wxStandardPaths::Get().GetExecutablePath()).GetPath(),
      wxTheApp->GetAppName() + wxString(".cfg")).GetFullPath());
#else
  m_Config = new exConfig();
#endif

  // And construct and read the lexers.
  m_Lexers = new exLexers();
  m_Lexers->Read();

#if wxUSE_HTML & wxUSE_PRINTING_ARCHITECTURE
  m_Printer = new wxHtmlEasyPrinting();
#endif

  // Finally call all available static initializers.
  exTool::Initialize();
  exSTC::PathListInit();

  return wxApp::OnInit();
}

#if wxUSE_GUI
void exBackgroundColourDialog(wxWindow* parent, wxWindow* win)
{
  wxColourData data;
  data.SetColour(win->GetBackgroundColour());
  wxColourDialog dlg(parent, &data);

  if (dlg.ShowModal())
  {
    win->SetBackgroundColour(dlg.GetColourData().GetColour());
    win->Refresh();
  }
}

bool exCommitDialog(const wxString& caption)
{
  std::vector<exConfigItem> v;
  v.push_back(exConfigItem(_("Revision comment")));
  v.push_back(exConfigItem(_("Base folder"), CONFIG_COMBOBOXDIR, wxEmptyString, true));

  if (exConfigDialog(wxTheApp->GetTopWindow(),
    v,
    caption).ShowModal() == wxID_CANCEL)
  {
    return false;
  }

  const wxString cwd = wxGetCwd();
  wxSetWorkingDirectory(exApp::GetConfig(_("Base folder")));
  wxArrayString output;
  wxArrayString errors;
  wxExecute(
    "svn commit -m \'" + exApp::GetConfig(_("Revision comment")) + "\"",
    output,
    errors);
  wxSetWorkingDirectory(cwd);

  wxString msg;
  for (size_t i = 0; i < output.GetCount(); i++)
  {
    msg += output[i] + " ";
  }

  exFrame::StatusText(msg);

  return true;
}

bool exClipboardAdd(const wxString& text)
{
  wxClipboardLocker locker;
  if (!locker) return false;
  if (!wxTheClipboard->AddData(new wxTextDataObject(text))) return false;
  if (!wxTheClipboard->Flush()) return false; // take care that clipboard data remain after exiting
  return true;
}

const wxString exClipboardGet()
{
  wxBusyCursor wait;
  wxClipboardLocker locker;

  if (!locker)
  {
    wxLogError("Cannot open clipboard");
    return wxEmptyString;
  }

  if (!wxTheClipboard->IsSupported(wxDF_TEXT))
  {
    wxLogError("Clipboard format not supported");
    return wxEmptyString;
  }

  wxTextDataObject data;
  if (!wxTheClipboard->GetData(data))
  {
    wxLogError("Cannot get clipboard data");
    return wxEmptyString;
  }

  return data.GetText();
}

long exColourToLong(const wxColour& c)
{
  return c.Red() | (c.Green() << 8) | (c.Blue() << 16);
}

void exComboBoxFromString(
  wxComboBox* cb,
  const wxString& text,
  const wxChar field_separator)
{
  wxStringTokenizer tkz(text, field_separator);
  while (tkz.HasMoreTokens())
  {
    const wxString val = tkz.GetNextToken();
    if (cb->FindString(val) == wxNOT_FOUND)
    {
      cb->Append(val);
    }
  }

  if (cb->GetCount() > 0) cb->SetValue(cb->GetString(0));
}

bool exComboBoxToString(
  const wxComboBox* cb,
  wxString& text,
  const wxChar field_separator,
  size_t max_items)
{
  if (cb == NULL)
  {
    return false;
  }

  text = cb->GetValue();
  switch (cb->FindString(cb->GetValue()))
  {
    case wxNOT_FOUND:
    {
      // Add the string, as it is not in the combo box, to the text,
      // simply by appending all combobox items.
      for (size_t i = 0; i < max_items; i++)
        if (i < max_items - 1 && i < cb->GetCount())
          text += field_separator + cb->GetString(i);
    }
    break;
    // No change necessary, the string is already present as the first one.
    case 0: return false; break;
    default:
    {
      // Reorder. The new first element already present, just add all others.
      for (size_t i = 0; i < cb->GetCount(); i++)
      {
        const wxString cb_element = cb->GetString(i);
        if (cb_element != cb->GetValue())
          text += field_separator + cb_element;
      }
    }
  }

  return true;
}

const wxString exEllipsed(const wxString& text, const wxString& control)
{
  return text + "..." + (!control.empty() ? "\t" + control: wxString(wxEmptyString));
}

const wxString exGetEndOfWord(
  const wxString& text,
  size_t max_chars)
{
  wxString text_out(text);

  if (text_out.length() > max_chars)
  {
    text_out = "..." + text_out.substr(text_out.length() - max_chars);
  }

  return text_out;
}

int exGetNumberOfLines(const wxString& text)
{
  if (text.empty())
  {
    return 0;
  }
  else if (text.Find(wxChar('\r')) != wxNOT_FOUND)
  {
    return text.Freq(wxChar('\r')) + 1;
  }
  else if (text.Find(wxChar('\n')) != wxNOT_FOUND)
  {
    return text.Freq(wxChar('\n')) + 1;
  }
  else
  {
    return 1;
  }
}

const wxString exGetWord(
  wxString& text,
  bool use_other_field_separators,
  bool use_path_separator)
{
  wxString field_separators = " \t";
  if (use_other_field_separators) field_separators += ":";
  if (use_path_separator) field_separators = wxFILE_SEP_PATH;
  wxString token;
  wxStringTokenizer tkz(text, field_separators);
  if (tkz.HasMoreTokens()) token = tkz.GetNextToken();
  text = tkz.GetString();
  text.Trim(false);
  return token;
}

int exGetLineNumberFromText(const wxString& text)
{
  // Get text after :.
  const size_t pos_char = text.rfind(":");

  if (pos_char == wxString::npos)
  {
    return 0;
  }

  const wxString linenumber = text.substr(pos_char + 1);

  long line;

  if (linenumber.ToLong(&line))
  {
    return line;
  }
  else
  {
    return 0;
  }
}

bool exIsBrace(int ch)
{
  return ch == '[' || ch == ']' ||
         ch == '(' || ch == ')' ||
         ch == '{' || ch == '}' ||
         ch == '<' || ch == '>';
};

bool exIsCodewordSeparator(int c)
{
  return (isspace(c) || exIsBrace(c) || c == ',' || c == ';' || c == ':');
}

bool exIsWordCharacter(wxChar c)
{
  return isalnum(c) || c == '_';
}

void exLog(const wxString& text, const wxFileName& filename)
{
  wxFile(
    filename.GetFullPath(),
    wxFile::write_append).Write(
      wxDateTime::Now().Format() + " " + text + wxTextFile::GetEOL());
}

const wxFileName exLogfileName()
{
#ifdef EX_PORTABLE
  return wxFileName(
    wxPathOnly(wxStandardPaths::Get().GetExecutablePath()),
    wxTheApp->GetAppName().Lower() + ".log");
#else
  return wxFileName(
    wxStandardPaths::Get().GetUserDataDir(),
    wxTheApp->GetAppName().Lower() + ".log");
#endif
}

bool exMatchesOneOf(const wxFileName& filename, const wxString& pattern)
{
  if (pattern == "*") return true; // asterix matches always.

  const wxString fullname_uppercase = filename.GetFullName().Upper();

  wxStringTokenizer tokenizer(pattern.Upper(), ";");
  while (tokenizer.HasMoreTokens())
  {
    if (fullname_uppercase.Matches(tokenizer.GetNextToken())) return true;
  }

  return false;
}

void exOpenFile(const wxFileName& filename, long open_flags)
{
  wxWindow* window = wxTheApp->GetTopWindow();
  exFrame* frame = wxDynamicCast(window, exFrame);

  if (frame != NULL)
  {
    frame->OpenFile(filename.GetFullPath(), -1, wxEmptyString, open_flags);
  }
}

const wxString exSkipWhiteSpace(const wxString& text, const wxString& replace_with)
{
  wxString output = text;
  wxRegEx("[ \t\n]+").ReplaceAll(&output, replace_with);
  return output;
}

#if wxUSE_STATUSBAR
void exStatusText(const exFileName& filename, long flags)
{
  wxString text; // clear status bar for empty or not existing or not initialized file names

  if (filename.IsOk())
  {
    const wxString path = (flags & STAT_FULLPATH
      ? filename.GetFullPath(): filename.GetFullName());

    text += path;

    if (filename.GetStat().IsOk())
    {
      const wxString what = (flags & STAT_SYNC
        ? _("Synchronized"): _("Modified"));
      const wxString time = (flags & STAT_SYNC
        ? wxDateTime::Now().Format(): filename.GetStat().GetModificationTime());
      text += " " + what + " " + time;
    }
  }

  exFrame::StatusText(text);
}
#endif // wxUSE_STATUSBAR

const wxString exTranslate(const wxString& text, int pageNum, int numPages)
{
  wxString translation = text;
  wxString num;

  num.Printf("%i", pageNum);
  translation.Replace("@PAGENUM@", num);

  num.Printf("%i", numPages);
  translation.Replace("@PAGESCNT@", num);

  return translation;
}
#endif // wxUSE_GUI
<|endoftext|>


<commit_before>/*******************************************************************************
  The MIT License (MIT)

  Copyright (c) 2015 Manuel Freiberger

  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 "catch.hpp"

#include "../src/statemachine.hpp"

using namespace fsm11;

namespace syncSM
{
using StateMachine_t = StateMachine<>;
using State_t = StateMachine_t::state_type;

struct TrackingStateMachine : public StateMachine<>
{
    virtual void onEntry(int) override
    {
        ++entered;
    }

    virtual void onExit(int) override
    {
        ++left;
    }

    std::atomic_int entered{0};
    std::atomic_int left{0};
};

} // namespace syncSM

namespace asyncSM
{
using StateMachine_t = StateMachine<AsynchronousEventDispatching,
                                    ConfigurationChangeCallbacksEnable<true>>;
using State_t = StateMachine_t::state_type;

struct TrackingStateMachine : public StateMachine_t
{
    virtual void onEntry(int) override
    {
        ++entered;
    }

    virtual void onExit(int) override
    {
        ++left;
    }

    std::atomic_int entered{0};
    std::atomic_int left{0};
};

} // namespace asyncSM

TEST_CASE("construct a synchronous statemachine", "[statemachine]")
{
    using namespace syncSM;
    StateMachine_t sm;
    REQUIRE(!sm.running());
    REQUIRE(sm.numConfigurationChanges() == 0);
}

TEST_CASE("construct an asynchronous statemachine", "[statemachine]")
{
    using namespace asyncSM;
    StateMachine_t sm;
    REQUIRE(!sm.running());
    REQUIRE(sm.numConfigurationChanges() == 0);
}

TEST_CASE("the eventloop of an asynchronous statemachine is left upon destruction",
          "[statemachine]")
{
    std::future<void> result;

    {
        using namespace asyncSM;
        StateMachine_t sm;
        REQUIRE(!sm.running());
        REQUIRE(sm.numConfigurationChanges() == 0);

        result = sm.startAsyncEventLoop();
    }
}

TEST_CASE("start an empty synchronous statemachine", "[statemachine]")
{
    using namespace syncSM;
    StateMachine_t sm;
    REQUIRE(!sm.running());
    REQUIRE(!sm.isActive());
    for (int cnt = 0; cnt < 2; ++cnt)
    {
        sm.start();
        REQUIRE(sm.running());
        REQUIRE(sm.isActive());
        REQUIRE(sm.numConfigurationChanges() == 2 * cnt + 1);
        sm.stop();
        REQUIRE(!sm.running());
        REQUIRE(!sm.isActive());
        REQUIRE(sm.numConfigurationChanges() == 2 * cnt + 2);
    }
}

TEST_CASE("start an empty asynchronous statemachine", "[statemachine]")
{
    using namespace asyncSM;

    std::mutex mutex;
    bool configurationChanged = false;
    std::condition_variable cv;

    auto waitForConfigurationChange = [&] {
        std::unique_lock<std::mutex> lock(mutex);
        cv.wait(lock, [&] { return configurationChanged; });
        configurationChanged = false;
    };

    StateMachine_t sm;
    sm.setConfigurationChangeCallback([&] {
        std::unique_lock<std::mutex> lock(mutex);
        configurationChanged = true;
        cv.notify_all();
    });

    REQUIRE(!sm.running());
    for (int cnt = 0; cnt < 2; ++cnt)
    {
        auto result = sm.startAsyncEventLoop();

        sm.start();
        waitForConfigurationChange();
        REQUIRE(sm.running());
        REQUIRE(sm.isActive());
        REQUIRE(sm.numConfigurationChanges() == 2 * cnt + 1);
        sm.stop();
        waitForConfigurationChange();
        REQUIRE(!sm.running());
        REQUIRE(!sm.isActive());
        REQUIRE(sm.numConfigurationChanges() == 2 * cnt + 2);
    }
}

TEST_CASE("an asynchronous statemachine is stopped upon destruction",
          "[statemachine]")
{
    using namespace asyncSM;
    std::future<void> result;

    std::mutex mutex;
    bool configurationChanged = false;
    std::condition_variable cv;

    auto waitForConfigurationChange = [&] {
        std::unique_lock<std::mutex> lock(mutex);
        cv.wait(lock, [&] { return configurationChanged; });
        configurationChanged = false;
    };

    SECTION("without starting")
    {
        StateMachine_t sm;
        result = sm.startAsyncEventLoop();
    }

    SECTION("with starting")
    {
        StateMachine_t sm;
        result = sm.startAsyncEventLoop();
        sm.start();
    }

    SECTION("with starting and waiting for a configuration change")
    {
        StateMachine_t sm;
        sm.setConfigurationChangeCallback([&] {
            std::unique_lock<std::mutex> lock(mutex);
            configurationChanged = true;
            cv.notify_all();
        });

        result = sm.startAsyncEventLoop();
        sm.start();
        waitForConfigurationChange();
    }
}

SCENARIO("state machine actions are executed", "[statemachine]")
{
    GIVEN ("a synchronous FSM")
    {
        using namespace syncSM;

        TrackingStateMachine sm;

        WHEN ("the state machine is not started")
        {
            REQUIRE(!sm.running());
            THEN ("neither onEntry() nor onExit() is called")
            {
                REQUIRE(sm.entered == 0);
                REQUIRE(sm.left == 0);
            }
        }

        WHEN ("the state machine is started")
        {
            sm.start();
            THEN ("the state machine executes its onEntry() method")
            {
                REQUIRE(sm.running());
                REQUIRE(sm.entered == 1);
                REQUIRE(sm.left == 0);
            }

            WHEN ("the state machine is stopped")
            {
                sm.stop();
                THEN ("the state machine executes its onExit() method")
                {
                    REQUIRE(!sm.running());
                    REQUIRE(sm.entered == 1);
                    REQUIRE(sm.left == 1);
                }
            }
        }
    }

    GIVEN ("an asynchronous FSM")
    {
        using namespace asyncSM;

        std::future<void> result;

        std::mutex mutex;
        bool configurationChanged = false;
        std::condition_variable cv;

        auto waitForConfigurationChange = [&] {
            std::unique_lock<std::mutex> lock(mutex);
            cv.wait(lock, [&] { return configurationChanged; });
            configurationChanged = false;
        };

        TrackingStateMachine sm;
        sm.setConfigurationChangeCallback([&] {
            std::unique_lock<std::mutex> lock(mutex);
            configurationChanged = true;
            cv.notify_all();
        });

        result = sm.startAsyncEventLoop();

        WHEN ("the state machine is not started")
        {
            REQUIRE(!sm.running());
            THEN ("neither onEntry() nor onExit() is called")
            {
                REQUIRE(sm.entered == 0);
                REQUIRE(sm.left == 0);
            }
        }

        WHEN ("the state machine is started")
        {
            sm.start();
            waitForConfigurationChange();
            THEN ("the state machine executes its onEntry() method")
            {
                REQUIRE(sm.running());
                REQUIRE(sm.entered == 1);
                REQUIRE(sm.left == 0);
            }

            WHEN ("the state machine is stopped")
            {
                sm.stop();
                waitForConfigurationChange();
                THEN ("the state machine executes its onExit() method")
                {
                    REQUIRE(!sm.running());
                    REQUIRE(sm.entered == 1);
                    REQUIRE(sm.left == 1);
                }
            }
        }
    }
}
<commit_msg>Added tests for finding a descendent in a state machine.<commit_after>/*******************************************************************************
  The MIT License (MIT)

  Copyright (c) 2015 Manuel Freiberger

  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 "catch.hpp"

#include "../src/statemachine.hpp"

using namespace fsm11;

namespace syncSM
{
using StateMachine_t = StateMachine<>;
using State_t = StateMachine_t::state_type;

struct TrackingStateMachine : public StateMachine<>
{
    virtual void onEntry(int) override
    {
        ++entered;
    }

    virtual void onExit(int) override
    {
        ++left;
    }

    std::atomic_int entered{0};
    std::atomic_int left{0};
};

} // namespace syncSM

namespace asyncSM
{
using StateMachine_t = StateMachine<AsynchronousEventDispatching,
                                    ConfigurationChangeCallbacksEnable<true>>;
using State_t = StateMachine_t::state_type;

struct TrackingStateMachine : public StateMachine_t
{
    virtual void onEntry(int) override
    {
        ++entered;
    }

    virtual void onExit(int) override
    {
        ++left;
    }

    std::atomic_int entered{0};
    std::atomic_int left{0};
};

} // namespace asyncSM

TEST_CASE("construct a synchronous statemachine", "[statemachine]")
{
    using namespace syncSM;
    StateMachine_t sm;
    REQUIRE(!sm.running());
    REQUIRE(sm.numConfigurationChanges() == 0);
}

TEST_CASE("construct an asynchronous statemachine", "[statemachine]")
{
    using namespace asyncSM;
    StateMachine_t sm;
    REQUIRE(!sm.running());
    REQUIRE(sm.numConfigurationChanges() == 0);
}

TEST_CASE("the eventloop of an asynchronous statemachine is left upon destruction",
          "[statemachine]")
{
    std::future<void> result;

    {
        using namespace asyncSM;
        StateMachine_t sm;
        REQUIRE(!sm.running());
        REQUIRE(sm.numConfigurationChanges() == 0);

        result = sm.startAsyncEventLoop();
    }
}

TEST_CASE("start an empty synchronous statemachine", "[statemachine]")
{
    using namespace syncSM;
    StateMachine_t sm;
    REQUIRE(!sm.running());
    REQUIRE(!sm.isActive());
    for (int cnt = 0; cnt < 2; ++cnt)
    {
        sm.start();
        REQUIRE(sm.running());
        REQUIRE(sm.isActive());
        REQUIRE(sm.numConfigurationChanges() == 2 * cnt + 1);
        sm.stop();
        REQUIRE(!sm.running());
        REQUIRE(!sm.isActive());
        REQUIRE(sm.numConfigurationChanges() == 2 * cnt + 2);
    }
}

TEST_CASE("start an empty asynchronous statemachine", "[statemachine]")
{
    using namespace asyncSM;

    std::mutex mutex;
    bool configurationChanged = false;
    std::condition_variable cv;

    auto waitForConfigurationChange = [&] {
        std::unique_lock<std::mutex> lock(mutex);
        cv.wait(lock, [&] { return configurationChanged; });
        configurationChanged = false;
    };

    StateMachine_t sm;
    sm.setConfigurationChangeCallback([&] {
        std::unique_lock<std::mutex> lock(mutex);
        configurationChanged = true;
        cv.notify_all();
    });

    REQUIRE(!sm.running());
    for (int cnt = 0; cnt < 2; ++cnt)
    {
        auto result = sm.startAsyncEventLoop();

        sm.start();
        waitForConfigurationChange();
        REQUIRE(sm.running());
        REQUIRE(sm.isActive());
        REQUIRE(sm.numConfigurationChanges() == 2 * cnt + 1);
        sm.stop();
        waitForConfigurationChange();
        REQUIRE(!sm.running());
        REQUIRE(!sm.isActive());
        REQUIRE(sm.numConfigurationChanges() == 2 * cnt + 2);
    }
}

TEST_CASE("an asynchronous statemachine is stopped upon destruction",
          "[statemachine]")
{
    using namespace asyncSM;
    std::future<void> result;

    std::mutex mutex;
    bool configurationChanged = false;
    std::condition_variable cv;

    auto waitForConfigurationChange = [&] {
        std::unique_lock<std::mutex> lock(mutex);
        cv.wait(lock, [&] { return configurationChanged; });
        configurationChanged = false;
    };

    SECTION("without starting")
    {
        StateMachine_t sm;
        result = sm.startAsyncEventLoop();
    }

    SECTION("with starting")
    {
        StateMachine_t sm;
        result = sm.startAsyncEventLoop();
        sm.start();
    }

    SECTION("with starting and waiting for a configuration change")
    {
        StateMachine_t sm;
        sm.setConfigurationChangeCallback([&] {
            std::unique_lock<std::mutex> lock(mutex);
            configurationChanged = true;
            cv.notify_all();
        });

        result = sm.startAsyncEventLoop();
        sm.start();
        waitForConfigurationChange();
    }
}

SCENARIO("state machine actions are executed", "[statemachine]")
{
    GIVEN ("a synchronous FSM")
    {
        using namespace syncSM;

        TrackingStateMachine sm;

        WHEN ("the state machine is not started")
        {
            REQUIRE(!sm.running());
            THEN ("neither onEntry() nor onExit() is called")
            {
                REQUIRE(sm.entered == 0);
                REQUIRE(sm.left == 0);
            }
        }

        WHEN ("the state machine is started")
        {
            sm.start();
            THEN ("the state machine executes its onEntry() method")
            {
                REQUIRE(sm.running());
                REQUIRE(sm.entered == 1);
                REQUIRE(sm.left == 0);
            }

            WHEN ("the state machine is stopped")
            {
                sm.stop();
                THEN ("the state machine executes its onExit() method")
                {
                    REQUIRE(!sm.running());
                    REQUIRE(sm.entered == 1);
                    REQUIRE(sm.left == 1);
                }
            }
        }
    }

    GIVEN ("an asynchronous FSM")
    {
        using namespace asyncSM;

        std::future<void> result;

        std::mutex mutex;
        bool configurationChanged = false;
        std::condition_variable cv;

        auto waitForConfigurationChange = [&] {
            std::unique_lock<std::mutex> lock(mutex);
            cv.wait(lock, [&] { return configurationChanged; });
            configurationChanged = false;
        };

        TrackingStateMachine sm;
        sm.setConfigurationChangeCallback([&] {
            std::unique_lock<std::mutex> lock(mutex);
            configurationChanged = true;
            cv.notify_all();
        });

        result = sm.startAsyncEventLoop();

        WHEN ("the state machine is not started")
        {
            REQUIRE(!sm.running());
            THEN ("neither onEntry() nor onExit() is called")
            {
                REQUIRE(sm.entered == 0);
                REQUIRE(sm.left == 0);
            }
        }

        WHEN ("the state machine is started")
        {
            sm.start();
            waitForConfigurationChange();
            THEN ("the state machine executes its onEntry() method")
            {
                REQUIRE(sm.running());
                REQUIRE(sm.entered == 1);
                REQUIRE(sm.left == 0);
            }

            WHEN ("the state machine is stopped")
            {
                sm.stop();
                waitForConfigurationChange();
                THEN ("the state machine executes its onExit() method")
                {
                    REQUIRE(!sm.running());
                    REQUIRE(sm.entered == 1);
                    REQUIRE(sm.left == 1);
                }
            }
        }
    }
}

TEST_CASE("find a descendant of a state machine", "[statemachine]")
{
    using namespace syncSM;

    StateMachine_t sm;
    State_t p("p", &sm);
    State_t c1("c1", &p);
    State_t c2("c2", &p);
    State_t c3("c3", &p);
    State_t c11("c11", &c1);
    State_t c12("c12", &c1);
    State_t c31("c31", &c3);
    State_t c32("c32", &c3);

    REQUIRE(sm.findDescendant({}) == &sm);
    REQUIRE(sm.findDescendant({"p", "c1"}) == &c1);
    REQUIRE(sm.findDescendant({"p", "c3", "c32"}) == &c32);
    REQUIRE(sm.findDescendant({"p", "x"}) == nullptr);
    REQUIRE(sm.findDescendant({"x"}) == nullptr);
}
<|endoftext|>


<commit_before>/*
 * Copyright 2006-2008 The FLWOR Foundation.
 *
 * 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 <vector>
#include <iostream>

#include <zorba/zorba.h>
#include <inmemorystore/inmemorystore.h>

using namespace zorba;

void* query_thread_1(void *param);
void* query_thread_2(void *param);

#define NR_THREADS  20
static  XQuery_t    lQuery;

#ifdef ZORBA_HAVE_PTHREAD_H

/*
Simple cloning test
*/
bool
multithread_example_1(Zorba* aZorba)
{
  unsigned int  i;
  pthread_t     pt[NR_THREADS];

  try {
    lQuery = aZorba->compileQuery("1+1");

    for(i=0; i<NR_THREADS; i++)
    {
      pthread_create(&pt[i], NULL, query_thread_1, (void*)i);
    }

    //wait for threads to finish
    for(i=0;i<NR_THREADS;i++)
    {
      void  *thread_result;
      pthread_join(pt[i], &thread_result);
    }

    lQuery = NULL;

    return true;
  }
  catch (ZorbaException &e) {
    std::cerr << "some exception " << e << std::endl;
    return false;
  }
}

/*
Create multiple threads that compile and execute a query
*/
bool
multithread_example_2(Zorba* aZorba)
{
  unsigned int  i;
  pthread_t     pt[NR_THREADS];

  try {
    for(i=0; i<NR_THREADS; i++)
    {
      pthread_create(&pt[i], NULL, query_thread_2, (void*)aZorba);
    }

    //wait for threads to finish
    for(i=0;i<NR_THREADS;i++)
    {
      void  *thread_result;
      pthread_join(pt[i], &thread_result);
    }

    return true;
  }
  catch (ZorbaException &e) {
    std::cerr << "some exception " << e << std::endl;
    return false;
  }
}

int
multithread(int argc, char* argv[])
{
  store::SimpleStore* lStore = inmemorystore::InMemoryStore::getInstance();
  Zorba*              lZorba = Zorba::getInstance(lStore);
  bool                res = false;

  std::cout << std::endl  << "executing multithread test 1" << std::endl;
  res = multithread_example_1(lZorba);
  if (!res) return 1;
  std::cout << std::endl;

  std::cout << std::endl  << "executing multithread test 2" << std::endl;
  res = multithread_example_2(lZorba);
  if (!res) return 1;
  std::cout << std::endl;

  lZorba->shutdown();
  inmemorystore::InMemoryStore::shutdown(lStore);
  return 0;
}

void* query_thread_1(void *param)
{
  XQuery_t        xquery_clone;

  xquery_clone = lQuery->clone();
  if(xquery_clone == NULL)
  {
    std::cout << "cannot clone xquery object" << std::endl;
    return (void*)1;
  }

  std::cout << xquery_clone << std::endl;

  xquery_clone->close();

  return (void*)0;
}

void* query_thread_2(void *param)
{
  XQuery_t    query;

  query = ((Zorba*)param)->compileQuery("2+2");

  std::cout << query << std::endl;

  query->close();

  return (void*)0;
}

#endif
<commit_msg>Made a change so that shutdown of zorba and store is called even if a test fails.<commit_after>/*
 * Copyright 2006-2008 The FLWOR Foundation.
 *
 * 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 <vector>
#include <iostream>
#include <sstream>

#include <zorba/zorba.h>
#include <inmemorystore/inmemorystore.h>

using namespace zorba;

void* query_thread_1(void *param);
void* query_thread_2(void *param);

#define NR_THREADS  20
static  XQuery_t    lQuery;

#ifdef ZORBA_HAVE_PTHREAD_H

/*
Simple cloning test
*/
bool
multithread_example_1(Zorba* aZorba)
{
  unsigned int  i;
  pthread_t     pt[NR_THREADS];

  try {
    lQuery = aZorba->compileQuery("1+1");

    for(i=0; i<NR_THREADS; i++)
    {
      pthread_create(&pt[i], NULL, query_thread_1, (void*)i);
    }

    //wait for threads to finish
    for(i=0;i<NR_THREADS;i++)
    {
      void  *thread_result;
      pthread_join(pt[i], &thread_result);
    }

    lQuery = NULL;

    return true;
  }
  catch (ZorbaException &e) {
    std::cerr << "some exception " << e << std::endl;
    return false;
  }
}

/*
Create multiple threads that compile and execute a query
*/
bool
multithread_example_2(Zorba* aZorba)
{
  unsigned int  i;
  pthread_t     pt[NR_THREADS];

  try {
    for(i=0; i<NR_THREADS; i++)
    {
      pthread_create(&pt[i], NULL, query_thread_2, (void*)aZorba);
    }

    //wait for threads to finish
    for(i=0;i<NR_THREADS;i++)
    {
      void  *thread_result;
      pthread_join(pt[i], &thread_result);
    }

    return true;
  }
  catch (ZorbaException &e) {
    std::cerr << "some exception " << e << std::endl;
    return false;
  }
}

/*
Create 2 separate threads that are working with the same document.
*/
bool
multithread_example_3(Zorba* zZorba)
{
  return false;
}

int
multithread(int argc, char* argv[])
{
  store::SimpleStore* lStore = inmemorystore::InMemoryStore::getInstance();
  Zorba*              lZorba = Zorba::getInstance(lStore);
  bool                res = false;

  std::cout << std::endl  << "executing multithread test 1 : ";
  res = multithread_example_1(lZorba);
  if (!res) {
    std::cout << "Failed" << std::endl;
    lZorba->shutdown();
    inmemorystore::InMemoryStore::shutdown(lStore);
    return 1;
  }
  else std::cout << "Passed" << std::endl;

  std::cout << std::endl  << "executing multithread test 2 : ";
  res = multithread_example_2(lZorba);
  if (!res) {
    std::cout << "Failed" << std::endl;
    lZorba->shutdown();
    inmemorystore::InMemoryStore::shutdown(lStore);
    return 1;
  }
  else std::cout << "Passed" << std::endl;

//   std::cout << std::endl  << "executing multithread test 3 : ";
//   res = multithread_example_3(lZorba);
//   if (!res) {
//     std::cout << "Failed" << std::endl;
//     lZorba->shutdown();
//     inmemorystore::InMemoryStore::shutdown(lStore);
//     return 1;
//   }
//   else std::cout << "Passed" << std::endl;

  lZorba->shutdown();
  inmemorystore::InMemoryStore::shutdown(lStore);
  return 0;
}

void* query_thread_1(void *param)
{
  XQuery_t        xquery_clone;

  xquery_clone = lQuery->clone();
  if(xquery_clone == NULL)
  {
    std::cout << "cannot clone xquery object" << std::endl;
    return (void*)1;
  }

  std::ostringstream os;
  os << xquery_clone << std::endl;

  xquery_clone->close();

  return (void*)0;
}

void* query_thread_2(void *param)
{
  XQuery_t    query;

  query = ((Zorba*)param)->compileQuery("2+2");

  std::ostringstream os;
  os << query << std::endl;

  query->close();

  return (void*)0;
}

#endif
<|endoftext|>


<commit_before>#include "Halide.h"

// This is a test of using the old buffer_t struct and having it
// auto-upgrade to the new one. We need some generator for which
// bounds inference does something, and with an extern definition.
class OldBufferT : public Halide::Generator<OldBufferT> {
public:
    Input<Buffer<int32_t>> in1{"in1", 2};
    Input<Buffer<int32_t>> in2{"in2", 2};
    Input<int>             scalar_param{"scalar_param", 1, 0, 64};

    Output<Buffer<int32_t>>  output{"output", 2};

    void generate() {
        Func f, g;
        Var x, y;
        f(x, y) = in1(x-1, y-1) + in1(x+1, y+3) + in2(x, y) + scalar_param;
        f.compute_root();

        if (get_target().has_gpu_feature()) {
            Var xi, yi;
            f.gpu_tile(x, y, xi, yi, 16, 16);
        }

        g.define_extern("extern_stage", {in2, f}, Int(32), 2,
                        NameMangling::Default,
                        true /* uses old buffer_t */);

        // Schedule the extern stage per tile to give the buffers a non-trivial min
        output(x, y) = g(x, y);
        Var xi, yi;
        output.tile(x, y, xi, yi, 8, 8);
        g.compute_at(output, x);
    }
};

HALIDE_REGISTER_GENERATOR(OldBufferT, old_buffer_t)
<commit_msg>Comment tweak<commit_after>#include "Halide.h"

// This is a test of using the old buffer_t struct and having it
// auto-upgrade to the new one. We need some generator for which
// bounds inference does something, and with an extern definition.
class OldBufferT : public Halide::Generator<OldBufferT> {
public:
    Input<Buffer<int32_t>> in1{"in1", 2};
    Input<Buffer<int32_t>> in2{"in2", 2};
    Input<int>             scalar_param{"scalar_param", 1, 0, 64};

    Output<Buffer<int32_t>>  output{"output", 2};

    void generate() {
        Func f, g;
        Var x, y;
        f(x, y) = in1(x-1, y-1) + in1(x+1, y+3) + in2(x, y) + scalar_param;
        f.compute_root();

        if (get_target().has_gpu_feature()) {
            Var xi, yi;
            f.gpu_tile(x, y, xi, yi, 16, 16);
        }

        g.define_extern("extern_stage", {in2, f}, Int(32), 2,
                        NameMangling::Default,
                        true /* uses old buffer_t */);

        // Schedule the extern stage per tile of the output to give
        // the buffers a non-trivial min
        output(x, y) = g(x, y);
        Var xi, yi;
        output.tile(x, y, xi, yi, 8, 8);
        g.compute_at(output, x);
    }
};

HALIDE_REGISTER_GENERATOR(OldBufferT, old_buffer_t)
<|endoftext|>


<commit_before>// division.cpp: functional tests for arbitrary configuration fixed-point division
//
// Copyright (C) 2017-2020 Stillwater Supercomputing, Inc.
//
// This file is part of the universal numbers project, which is released under an MIT Open Source license.

// Configure the fixpnt template environment
// first: enable general or specialized fixed-point configurations
#define FIXPNT_FAST_SPECIALIZATION
// second: enable/disable fixpnt arithmetic exceptions
#define FIXPNT_THROW_ARITHMETIC_EXCEPTION 1

// minimum set of include files to reflect source code dependencies
#include <universal/fixpnt/fixed_point.hpp>
// fixed-point type manipulators such as pretty printers
#include <universal/fixpnt/fixpnt_manipulators.hpp>
#include <universal/fixpnt/fixpnt_functions.hpp>
#include "../utils/fixpnt_test_suite.hpp"

// generate specific test case that you can trace with the trace conditions in fixed_point.hpp
// for most bugs they are traceable with _trace_conversion and _trace_add
template<size_t nbits, size_t rbits, typename Ty>
void GenerateTestCase(Ty _a, Ty _b) {
	Ty ref;
	sw::unum::fixpnt<nbits, rbits> a, b, cref, result;
	a = _a;
	b = _b;
	result = a / b;
	ref = _a / _b;
	cref = ref;
	std::streamsize oldPrecision = std::cout.precision();
	std::cout << std::setprecision(nbits - 2);
	std::cout << std::setw(nbits) << _a << " / " << std::setw(nbits) << _b << " = " << std::setw(nbits) << ref << std::endl;
	std::cout << a << " / " << b << " = " << result << " (reference: " << cref << ")   " ;
	std::cout << (cref == result ? "PASS" : "FAIL") << std::endl << std::endl;
	std::cout << std::dec << std::setprecision(oldPrecision);
}

// conditional compile flags
#define MANUAL_TESTING 1
#define STRESS_TESTING 0

int main(int argc, char** argv)
try {
	using namespace std;
	using namespace sw::unum;

	int nrOfFailedTestCases = 0;

	std::string tag = "modular division: ";

#if MANUAL_TESTING

	constexpr size_t nbits = 8;
	constexpr size_t rbits = 4;

	/*
	fixpnt<nbits, rbits> a, b, c;
	a = 6.0f;
	b = 3*0.0625f;
	for (int i = 0; i < nbits; ++i) {
		blockbinary<16> raw = urdiv(a.getbb(), b.getbb(), i);
		cout << to_binary(a) << " / " << to_binary(b) << " = " << to_binary(raw) << " msb of result is: " << raw.msb() << endl;
	}
	c = a / b;
	*/

	fixpnt<8, 4> a,b, c;
	a.set_raw_bits(0xCC);
	cout << float(a) << endl;
	b.set_raw_bits(0x55);
	cout << float(b) << endl;
	c = b * a;

	GenerateTestCase<8, 4>(float(a), float(b)); // -52 / 85 in 8bit 2's complement

	/*
	// generate individual testcases to hand trace/debug
	GenerateTestCase<4, 1>(1.0f, 1.0f);
	GenerateTestCase<4, 1>(1.0f, 2.0f);
	GenerateTestCase<4, 1>(2.0f, 3.0f);

	GenerateTestCase<8, 4>(1.0f, 1.0f);
	GenerateTestCase<8, 4>(1.0f, 2.0f);
	GenerateTestCase<8, 4>(1.0f, 0.5f);
	GenerateTestCase<8, 4>(1.0f, 4.0f);
	GenerateTestCase<8, 4>(1.0f, 0.25f);

	GenerateTestCase<4, 1>(0.5f, -4.0f);
	GenerateTestCase<4, 1>(0.5f,  3.5f);
	GenerateTestCase<4, 1>(0.5f, -3.5f);
	GenerateTestCase<4, 1>(0.5f, -3.0f);
	GenerateTestCase<4, 1>(0.5f, -2.5f);
	GenerateTestCase<4, 1>(0.5f, -2.0f);
	GenerateTestCase<4, 1>(0.5f, -1.5f);
	GenerateTestCase<4, 1>(0.5f, -1.0f);
	GenerateTestCase<4, 1>(0.5f, -0.5f);
	*/

	return 0;

	nrOfFailedTestCases += ReportTestResult(VerifyDivision<4, 0, Modular, uint8_t>("Manual Testing", true), "fixpnt<4,0,Modular,uint8_t>", "division");
	nrOfFailedTestCases += ReportTestResult(VerifyDivision<4, 1, Modular, uint8_t>("Manual Testing", true), "fixpnt<4,1,Modular,uint8_t>", "division");
	//	nrOfFailedTestCases += ReportTestResult(VerifyDivision<8, 4, Modular, uint8_t>("Manual Testing", true), "fixpnt<8,4,Modular,uint8_t>", "division");

#if STRESS_TESTING

	// manual exhaustive test
	nrOfFailedTestCases += ReportTestResult(VerifyDivision<4, 0, Modular, uint8_t>("Manual Testing", true), "fixpnt<4,0,Modular,uint8_t>", "division");
	nrOfFailedTestCases += ReportTestResult(VerifyDivision<4, 1, Modular, uint8_t>("Manual Testing", true), "fixpnt<4,1,Modular,uint8_t>", "division");
	nrOfFailedTestCases += ReportTestResult(VerifyDivision<4, 2, Modular, uint8_t>("Manual Testing", true), "fixpnt<4,2,Modular,uint8_t>", "division");
	nrOfFailedTestCases += ReportTestResult(VerifyDivision<4, 3, Modular, uint8_t>("Manual Testing", true), "fixpnt<4,3,Modular,uint8_t>", "division");
	nrOfFailedTestCases += ReportTestResult(VerifyDivision<4, 4, Modular, uint8_t>("Manual Testing", true), "fixpnt<4,4,Modular,uint8_t>", "division");

#endif

	nrOfFailedTestCases = 0; // ignore any failures in MANUAL mode
#else
	bool bReportIndividualTestCases = false;

	cout << "Fixed-point modular division validation" << endl;

	nrOfFailedTestCases += ReportTestResult(VerifyDivision<8, 0, Modular, uint8_t>(tag, bReportIndividualTestCases), "fixpnt<8,0,Modular,uint8_t>", "division");
	nrOfFailedTestCases += ReportTestResult(VerifyDivision<8, 1, Modular, uint8_t>(tag, bReportIndividualTestCases), "fixpnt<8,1,Modular,uint8_t>", "division");
	nrOfFailedTestCases += ReportTestResult(VerifyDivision<8, 2, Modular, uint8_t>(tag, bReportIndividualTestCases), "fixpnt<8,2,Modular,uint8_t>", "division");
	nrOfFailedTestCases += ReportTestResult(VerifyDivision<8, 3, Modular, uint8_t>(tag, bReportIndividualTestCases), "fixpnt<8,3,Modular,uint8_t>", "division");
	nrOfFailedTestCases += ReportTestResult(VerifyDivision<8, 4, Modular, uint8_t>(tag, bReportIndividualTestCases), "fixpnt<8,4,Modular,uint8_t>", "division");
	nrOfFailedTestCases += ReportTestResult(VerifyDivision<8, 5, Modular, uint8_t>(tag, bReportIndividualTestCases), "fixpnt<8,5,Modular,uint8_t>", "division");
	nrOfFailedTestCases += ReportTestResult(VerifyDivision<8, 6, Modular, uint8_t>(tag, bReportIndividualTestCases), "fixpnt<8,6,Modular,uint8_t>", "division");
	nrOfFailedTestCases += ReportTestResult(VerifyDivision<8, 7, Modular, uint8_t>(tag, bReportIndividualTestCases), "fixpnt<8,7,Modular,uint8_t>", "division");
	nrOfFailedTestCases += ReportTestResult(VerifyDivision<8, 8, Modular, uint8_t>(tag, bReportIndividualTestCases), "fixpnt<8,8,Modular,uint8_t>", "division");

#if STRESS_TESTING

#endif  // STRESS_TESTING

#endif  // MANUAL_TESTING

	return (nrOfFailedTestCases > 0 ? EXIT_FAILURE : EXIT_SUCCESS);
}
catch (char const* msg) {
	std::cerr << msg << std::endl;
	return EXIT_FAILURE;
}
catch (const sw::unum::fixpnt_arithmetic_exception& err) {
	std::cerr << "Uncaught fixpnt arithmetic exception: " << err.what() << std::endl;
	return EXIT_FAILURE;
}
catch (const sw::unum::fixpnt_internal_exception& err) {
	std::cerr << "Uncaught fixpnt internal exception: " << err.what() << std::endl;
	return EXIT_FAILURE;
}
catch (const std::runtime_error& err) {
	std::cerr << "Uncaught runtime exception: " << err.what() << std::endl;
	return EXIT_FAILURE;
}
catch (...) {
	std::cerr << "Caught unknown exception" << std::endl;
	return EXIT_FAILURE;
}
<commit_msg>WIP: checkpointing new debug environment for fixed-point divide algorithm<commit_after>// division.cpp: functional tests for arbitrary configuration fixed-point division
//
// Copyright (C) 2017-2020 Stillwater Supercomputing, Inc.
//
// This file is part of the universal numbers project, which is released under an MIT Open Source license.

// Configure the fixpnt template environment
// first: enable general or specialized fixed-point configurations
#define FIXPNT_FAST_SPECIALIZATION
// second: enable/disable fixpnt arithmetic exceptions
#define FIXPNT_THROW_ARITHMETIC_EXCEPTION 1

// minimum set of include files to reflect source code dependencies
#include <universal/fixpnt/fixed_point.hpp>
// fixed-point type manipulators such as pretty printers
#include <universal/fixpnt/fixpnt_manipulators.hpp>
#include <universal/fixpnt/fixpnt_functions.hpp>
#include "../utils/fixpnt_test_suite.hpp"

// unrounded division, returns a blockbinary that is of size 2*nbits
template<size_t nbits, size_t roundingBits, typename BlockType>
inline sw::unum::blockbinary<2 * nbits + roundingBits, BlockType> unrounded_div(const sw::unum::blockbinary<nbits, BlockType>& a, const sw::unum::blockbinary<nbits, BlockType>& b, sw::unum::blockbinary<roundingBits, BlockType>& r) {
	using namespace sw::unum;

	if (b.iszero()) {
		// division by zero
		throw "urdiv divide by zero";
	}
	// generate the absolute values to do long division
	// 2's complement special case -max requires an signed int that is 1 bit bigger to represent abs()
	bool a_sign = a.sign();
	bool b_sign = b.sign();
	bool result_negative = (a_sign ^ b_sign);

	// normalize both arguments to positive in new size
	blockbinary<nbits + 1, BlockType> a_new(a); // TODO optimize: now create a, create _a.bb, copy, destroy _a.bb_copy
	blockbinary<nbits + 1, BlockType> b_new(b);
	if (a_sign) a_new.twoscomplement();
	if (b_sign) b_new.twoscomplement();

	// initialize the long division
	blockbinary<2 * nbits + roundingBits, BlockType> decimator(a);
	decimator <<= nbits + roundingBits - 1; // scale the decimator to the largest possible positive value
	blockbinary<2 * nbits + roundingBits, BlockType> subtractand(b); // prepare the subtractand
	blockbinary<2 * nbits + roundingBits, BlockType> result;

	std::cout << to_binary(subtractand) << ' ' << to_binary(decimator) << std::endl;

	int msb_b = subtractand.msb();
	int msb_a = decimator.msb();
	int shift = msb_a - msb_b;
	subtractand <<= shift;

	std::cout << to_binary(subtractand) << ' ' << to_binary(decimator) << ' ' << to_binary(result) << " shift: " << shift << std::endl;

	// long division
	for (int i = shift; i >= 0; --i) {

		std::cout << to_binary(subtractand) << ' ' << to_binary(decimator) << std::endl;

		if (subtractand <= decimator) {
			decimator -= subtractand;
			result.set(i);
		}
		else {
			result.reset(i);
		}
		subtractand >>= 1;

		std::cout << to_binary(subtractand) << ' ' << to_binary(decimator) << ' ' << to_binary(result) << std::endl;

	}
	r.assign(result); // copy the lowest bits which represent the bits on which we need to apply the rounding test
	return result;
}

// generate specific test case that you can trace with the trace conditions in fixed_point.hpp
// for most bugs they are traceable with _trace_conversion and _trace_add
template<size_t nbits, size_t rbits, typename Ty>
void GenerateTestCase(Ty _a, Ty _b) {
	Ty ref;
	sw::unum::fixpnt<nbits, rbits> a, b, cref, result;
	a = _a;
	b = _b;
	result = a / b;
	ref = _a / _b;
	cref = ref;
	std::streamsize oldPrecision = std::cout.precision();
	std::cout << std::setprecision(nbits - 2);
	std::cout << std::setw(nbits) << _a << " / " << std::setw(nbits) << _b << " = " << std::setw(nbits) << ref << std::endl;
	std::cout << a << " / " << b << " = " << result << " (reference: " << cref << ")   " ;
	std::cout << (cref == result ? "PASS" : "FAIL") << std::endl << std::endl;
	std::cout << std::dec << std::setprecision(oldPrecision);
}

// conditional compile flags
#define MANUAL_TESTING 1
#define STRESS_TESTING 0

int main(int argc, char** argv)
try {
	using namespace std;
	using namespace sw::unum;

	int nrOfFailedTestCases = 0;

	std::string tag = "modular division: ";

#if MANUAL_TESTING

	constexpr size_t nbits = 8;
	constexpr size_t rbits = 4;

	{
		constexpr size_t nbits = 8;
		constexpr size_t rbits = 4;

		fixpnt<nbits,rbits> a, b;
		a.set_raw_bits(0xCC);
		b.set_raw_bits(0x55);
		constexpr size_t roundingDecisionBits = 4; // guard, round, and 2 sticky bits
		blockbinary<roundingDecisionBits> roundingBits;
		blockbinary<2 * nbits> c = unrounded_div(a.getbb(), b.getbb(), roundingBits);
		std::cout << a << " / " << b << std::endl;
		std::cout << a.getbb() << " / " << b.getbb() << " = " << to_binary(c) << " rounding bits " << to_binary(roundingBits);
		bool roundUp = c.roundingMode(rbits + 4);
		c >>= nbits + roundingDecisionBits - 1;
		if (roundUp) ++c;
		std::cout << " rounded " << to_binary(c) << std::endl;
		//this->bb = c; // select the lower nbits of the result
	}

	return 0;

	// generate individual testcases to hand trace/debug
//	fixpnt<4, 1> a, b, c;
	fixpnt<6, 2> a, b, c;
	a.set_raw_bits(0xCC);
	cout << a << ' ' << to_binary(a) << ' ' << float(a) << endl;
	b.set_raw_bits(0x55);
	cout << b << ' ' << to_binary(b) << ' ' << float(b) << endl;
	c = a * b;
	c = b * a;

	GenerateTestCase<4, 1>(float(a), float(b)); // -52 / 85 in 8bit 2's complement

	nrOfFailedTestCases += ReportTestResult(VerifyDivision<4, 0, Modular, uint8_t>("Manual Testing", true), "fixpnt<4,0,Modular,uint8_t>", "division");
	nrOfFailedTestCases += ReportTestResult(VerifyDivision<4, 1, Modular, uint8_t>("Manual Testing", true), "fixpnt<4,1,Modular,uint8_t>", "division");
	//	nrOfFailedTestCases += ReportTestResult(VerifyDivision<8, 4, Modular, uint8_t>("Manual Testing", true), "fixpnt<8,4,Modular,uint8_t>", "division");

#if STRESS_TESTING

	// manual exhaustive test
	nrOfFailedTestCases += ReportTestResult(VerifyDivision<4, 0, Modular, uint8_t>("Manual Testing", true), "fixpnt<4,0,Modular,uint8_t>", "division");
	nrOfFailedTestCases += ReportTestResult(VerifyDivision<4, 1, Modular, uint8_t>("Manual Testing", true), "fixpnt<4,1,Modular,uint8_t>", "division");
	nrOfFailedTestCases += ReportTestResult(VerifyDivision<4, 2, Modular, uint8_t>("Manual Testing", true), "fixpnt<4,2,Modular,uint8_t>", "division");
	nrOfFailedTestCases += ReportTestResult(VerifyDivision<4, 3, Modular, uint8_t>("Manual Testing", true), "fixpnt<4,3,Modular,uint8_t>", "division");
	nrOfFailedTestCases += ReportTestResult(VerifyDivision<4, 4, Modular, uint8_t>("Manual Testing", true), "fixpnt<4,4,Modular,uint8_t>", "division");

#endif

	nrOfFailedTestCases = 0; // ignore any failures in MANUAL mode
#else
	bool bReportIndividualTestCases = false;

	cout << "Fixed-point modular division validation" << endl;

	nrOfFailedTestCases += ReportTestResult(VerifyDivision<8, 0, Modular, uint8_t>(tag, bReportIndividualTestCases), "fixpnt<8,0,Modular,uint8_t>", "division");
	nrOfFailedTestCases += ReportTestResult(VerifyDivision<8, 1, Modular, uint8_t>(tag, bReportIndividualTestCases), "fixpnt<8,1,Modular,uint8_t>", "division");
	nrOfFailedTestCases += ReportTestResult(VerifyDivision<8, 2, Modular, uint8_t>(tag, bReportIndividualTestCases), "fixpnt<8,2,Modular,uint8_t>", "division");
	nrOfFailedTestCases += ReportTestResult(VerifyDivision<8, 3, Modular, uint8_t>(tag, bReportIndividualTestCases), "fixpnt<8,3,Modular,uint8_t>", "division");
	nrOfFailedTestCases += ReportTestResult(VerifyDivision<8, 4, Modular, uint8_t>(tag, bReportIndividualTestCases), "fixpnt<8,4,Modular,uint8_t>", "division");
	nrOfFailedTestCases += ReportTestResult(VerifyDivision<8, 5, Modular, uint8_t>(tag, bReportIndividualTestCases), "fixpnt<8,5,Modular,uint8_t>", "division");
	nrOfFailedTestCases += ReportTestResult(VerifyDivision<8, 6, Modular, uint8_t>(tag, bReportIndividualTestCases), "fixpnt<8,6,Modular,uint8_t>", "division");
	nrOfFailedTestCases += ReportTestResult(VerifyDivision<8, 7, Modular, uint8_t>(tag, bReportIndividualTestCases), "fixpnt<8,7,Modular,uint8_t>", "division");
	nrOfFailedTestCases += ReportTestResult(VerifyDivision<8, 8, Modular, uint8_t>(tag, bReportIndividualTestCases), "fixpnt<8,8,Modular,uint8_t>", "division");

#if STRESS_TESTING

#endif  // STRESS_TESTING

#endif  // MANUAL_TESTING

	return (nrOfFailedTestCases > 0 ? EXIT_FAILURE : EXIT_SUCCESS);
}
catch (char const* msg) {
	std::cerr << msg << std::endl;
	return EXIT_FAILURE;
}
catch (const sw::unum::fixpnt_arithmetic_exception& err) {
	std::cerr << "Uncaught fixpnt arithmetic exception: " << err.what() << std::endl;
	return EXIT_FAILURE;
}
catch (const sw::unum::fixpnt_internal_exception& err) {
	std::cerr << "Uncaught fixpnt internal exception: " << err.what() << std::endl;
	return EXIT_FAILURE;
}
catch (const std::runtime_error& err) {
	std::cerr << "Uncaught runtime exception: " << err.what() << std::endl;
	return EXIT_FAILURE;
}
catch (...) {
	std::cerr << "Caught unknown exception" << std::endl;
	return EXIT_FAILURE;
}
<|endoftext|>


<commit_before><commit_msg>Typo: reqired->required<commit_after><|endoftext|>