<commit_before>#include <iostream>
#include <regex>
#include <string>
#include <vector>

using namespace std;

// Good diagram: https://engmrk.com/wp-content/uploads/2018/09/Image-Architecture-of-Convolutional-Neural-Network.png

class Layer {
 public:
  vector<vector<vector<double>>> h(vector<vector<vector<double>>> x);

  // Helper function
  static void rand_init(vector<vector<double>> matrix, int height, int width) {
    for (int i = 0; i < height; i++) {
      for (int j = 0; j < width; j++) {
        // use numbers between -100 and 100
        double n = (double)rand() / RAND_MAX;  // scales rand() to [0, 1].
        n = n * 200 - 100;
        matrix[i][j] = n;  // (possibly) change to use float to save memory
      }
    }
  }
};

class Conv : public Layer {
 public:
  int num_input_channels;
  int num_filters;
  vector<int> size_per_filter;
  vector<int> stride_per_filter;

  vector<vector<vector<double>>> filters;
  Conv(int num_input_channels, int num_filters, vector<int> size_per_filter, vector<int> stride_per_filter) {
    // TODO: Check if there is a better way to save these.
    num_input_channels = num_input_channels;
    num_filters = num_filters;
    size_per_filter = size_per_filter;
    stride_per_filter = stride_per_filter;

    for (int filter_num; filter_num < num_filters; filter_num++) {
      // Filters are square
      int height = size_per_filter[filter_num];
      int width = size_per_filter[filter_num];

      vector<vector<double>> filter;
      Layer().rand_init(filter, height, width);
      filters[filter_num] = filter;
    }
  }

  // vector<vector<vector<double>>> h(vector<vector<vector<double>>> a) {
  //   // Input and output is height x width x num_channels
  //   // First filter adds to the output of the first channel only, etc.

  //   // feature map (or activation map) is the output of one filter (or kernel or detector)
  //   vector<vector<vector<double>>> output_block;
  //   int num_filters = filters.size();
  //   for (int i = 0; i < num_filters; i++) {  // Should be embarrassingly parallel
  //     vector<vector<double>> feature_map = convolve(a, filters[i], stride_per_filter[i]);
  //   }
  // }

  // static because this is a self-contained method
  vector<vector<double>> static convolve(vector<vector<vector<double>>> a, vector<vector<double>> filter, int stride) {
    // a is height x width x num_channels
    // Let's say a is 10x10x3 and filter is 3x3
    // The first convolutional step will use a's top left corner block of size 3x3x3
    // For each (i, j, [1, 2, 3]) section of a, we use the same (i, j)th weight of filter to flatten it
    // In other words, we do a[i][j][1]*w + a[i][j][2]*w + a[i][j][3]*w.
    // This produces a 3x3x1 which we then element-wise multiply with filter which is also 3x3x1 to
    // produce 3x3x1 multiplications. These are then all added together to produce one output per
    // convolutional step.
    // Reference:
    //
    // https://stats.stackexchange.com/questions/335321/in-a-convolutional-neural-network-cnn-when-convolving-the-image-is-the-opera

    int height = a.size();
    int width = a[0].size();
    int depth = a[0][0].size();

    int depth_of_a = a.size();
    vector<vector<double>> feature_map = _convolve(a[0], filter, stride);
    for (int depth = 1; depth < depth_of_a; depth++) {
      vector<vector<double>> feature_map_for_depth = _convolve(a[depth], filter, stride);
      feature_map = add_matrices(feature_map, feature_map_for_depth);
    }

    return feature_map;
  }

  vector<vector<double>> static add_matrices(vector<vector<double>> a, vector<vector<double>> b) {
    vector<vector<double>> c;

    for (int i = 0; i < a.size(); i++) {
      vector<double> c_column;
      for (int j = 0; j < a[0].size(); j++) {
        c_column.push_back(a[i][j] + b[i][j]);
      }
      c.push_back(c_column);
    }

    return c;
  }

  vector<vector<double>> static _convolve(vector<vector<double>> a, vector<vector<double>> filter, int stride) {
    // Maybe switch the order of i and j
    int i = 0;
    int j = 0;

    vector<vector<double>> convolved;
    while (i <= a.size() - filter.size()) {
      vector<double> convolved_column;

      while (j <= a[0].size() - filter[0].size()) {
        double acc_sum{0.0};
        for (int x = 0; x < filter.size(); ++x) {
          for (int y = 0; y < filter[0].size(); ++y) {
            acc_sum = acc_sum + a[i + x][j + y] * filter[x][y];
          }
        }
        convolved_column.push_back(acc_sum);

        j = j + stride;
      }
      convolved.push_back(convolved_column);
      j = 0;

      i = i + stride;
    }
    return convolved;
  }

  void static _convolve_test() {
    vector<vector<double>> a = {{1.0, 1.0, 1.0, 0.0, 0.0},
                                {0.0, 1.0, 1.0, 1.0, 0.0},
                                {0.0, 0.0, 1.0, 1.0, 1.0},
                                {0.0, 0.0, 1.0, 1.0, 0.0},
                                {0.0, 1.0, 1.0, 0.0, 0.0}};
    vector<vector<double>> filter = {{1.0, 0.0, 1.0}, {0.0, 1.0, 0.0}, {1.0, 0.0, 1.0}};

    vector<vector<double>> actual_output = _convolve(a, filter, 2);
    vector<vector<double>> expected_output = {{4.0, 4.0}, {2.0, 4.0}};

    for (int i = 0; i < actual_output.size(); i++) {
      for (int j = 0; j < actual_output[i].size(); j++) {
        cout << actual_output[i][j] << ",";
        if (actual_output[i][j] != expected_output[i][j]) {
          throw;
        }
      }
      cout << endl;
    }

    vector<vector<double>> a2 = {{1.0, 1.0, 1.0, 0.0, 0.0},
                                 {0.0, 1.0, 1.0, 1.0, 0.0},
                                 {0.0, 0.0, 1.0, 1.0, 1.0},
                                 {0.0, 0.0, 1.0, 1.0, 0.0},
                                 {0.0, 1.0, 1.0, 0.0, 0.0}};
    vector<vector<double>> filter2 = {{1.0}};

    vector<vector<double>> actual_output2 = _convolve(a2, filter2, 1);
    vector<vector<double>> expected_output2 = {{1.0, 1.0, 1.0, 0.0, 0.0},
                                               {0.0, 1.0, 1.0, 1.0, 0.0},
                                               {0.0, 0.0, 1.0, 1.0, 1.0},
                                               {0.0, 0.0, 1.0, 1.0, 0.0},
                                               {0.0, 1.0, 1.0, 0.0, 0.0}};

    for (int i = 0; i < actual_output2.size(); i++) {
      for (int j = 0; j < actual_output2[i].size(); j++) {
        cout << actual_output2[i][j] << ",";
        if (actual_output2[i][j] != expected_output2[i][j]) {
          throw;
        }
      }
      cout << endl;
    }
  }

  void static convolve_test() {

    vector<vector<vector<double>>> a = {
                                {{1.0, 1.0, 1.0, 0.0, 0.0},
                                {0.0, 1.0, 1.0, 1.0, 0.0},
                                {0.0, 0.0, 1.0, 1.0, 1.0},
                                {0.0, 0.0, 1.0, 1.0, 0.0},
                                {0.0, 1.0, 1.0, 0.0, 0.0}},

                                {{0.0, 1.0, 0.0, 1.0, 0.0},
                                {0.0, 0.0, 1.0, 1.0, 1.0},
                                {0.0, 0.0, 1.0, 1.0, 0.0},
                                {0.0, 1.0, 1.0, 0.0, 1.0},
                                {0.0, 1.0, 1.0, 0.0, 0.0}},

                                {{1.0, 0.0, 0.0, 0.0, 0.0},
                                {0.0, 1.0, 0.0, 0.0, 0.0},
                                {0.0, 0.0, 1.0, 0.0, 0.0},
                                {0.0, 0.0, 0.0, 1.0, 0.0},
                                {0.0, 0.0, 0.0, 0.0, 1.0}}
                                };
    vector<vector<double>> filter = {{1, 0},{1, 1}};

    vector<vector<double>> actual_output = convolve(a, filter, 2);
    vector<vector<double>> expected_output = {{4.0, 5.0}, {1.0, 7.0}};

    for (int i = 0; i < actual_output.size(); i++) {
      for (int j = 0; j < actual_output[i].size(); j++) {
        cout << actual_output[i][j] << ",";
        //if (actual_output[i][j] != expected_output[i][j]) {
          //throw;
        //}
      }
      cout << endl;
    }

    vector<vector<vector<double>>> a2 = {{{9.0, 1.0, 9.0, 0.0, 9.0},
                                {0.0, 1.0, 9.0, 1.0, 0.0},
                                {9.0, 0.0, 9.0, 1.0, 9.0},
                                {0.0, 0.0, 9.0, 0.0, 0.0},
                                {9.0, 1.0, 9.0, 0.0, 9.0}},
                                // {{0.0, 1.0, 1.0, 1.0, 0.0},
                                // {0.0, 1.0, 0.0, 1.0, 0.0},
                                // {0.0, 0.0, 1.0, 1.0, 1.0},
                                // {0.0, 0.0, 1.0, 1.0, 0.0},
                                // {0.0, 1.0, 1.0, 0.0, 1.0}},
                                // {{1.0, 0.0, 0.0, 0.0, 0.0},
                                // {0.0, 1.0, 0.0, 0.0, 0.0},
                                // {0.0, 0.0, 1.0, 0.0, 0.0},
                                // {0.0, 0.0, 0.0, 1.0, 0.0},
                                // {0.0, 0.0, 0.0, 0.0, 1.0}}
                                };
    vector<vector<double>> filter2 = {{1.0}};

    vector<vector<double>> actual_output2 = convolve(a2, filter2, 2);
    vector<vector<double>> expected_output2 = {{9.0, 9.0, 9.0},{9.0, 9.0, 9.0}, {9.0, 9.0, 9.0}};

    for (int i = 0; i < actual_output2.size(); i++) {
      for (int j = 0; j < actual_output2[i].size(); j++) {
        cout << actual_output2[i][j] << ",";
        //if (actual_output[i][j] != expected_output[i][j]) {
          //throw;
        //}
      }
      cout << endl;
    }

  }
};

class Pool : public Layer {};

class Act : public Layer {};

class Dense : public Layer {};

class ConvNet {
 public:
  vector<Layer> layers;
  ConvNet(vector<Layer> layers) { layers = layers; }

  // int h(vector<vector<vector<double>>> x) {  // Returns an int, a classification
  //   vector<vector<vector<double>>> a = x;
  //   for (Layer layer : layers) {
  //     vector<vector<vector<double>>> a = layer.h(a);
  //   }
  //   // Convert the final output into a classification
  // }
};

int main() {
  // TEST
  cout << "Starting test...\n";

  // int num_images = 100;
  // vector<vector<vector<vector<double>>>> X;  // num_images x height x width x num_channels
  // int Y[num_images];                         // labels for each example

  // // Randomly initialize X and Y
  // for (int i = 0; i < num_images; i++) {
  //   for (int j = 0; j < 28; j++) {
  //     for (int k = 0; k < 28; k++) {
  //       // use numbers from 0 to 255
  //       X[i][j][k][1] = rand() % 255; //TODO: Use push_back
  //     }
  //   }
  //   Y[i] = rand() % 10;  // TODO: Maybe decrease number of classes for the test?
  // }

  // // Look at first 2 "images"
  // for (int i = 0; i < 2; i++) {
  //   for (int j = 0; j < 28; j++) {
  //     for (int k = 0; k < 28; k++) {
  //       cout << X[j][k][i][1] << ",";
  //     }
  //     cout << endl;
  //   }
  //   cout << endl;
  // }

  //Conv::_convole_test();

  Conv::convolve_test();

  // Intialize model
  // Compound literal, (vector[]), helps initialize an array in function call
  // ConvNet model = ConvNet(vector<Layer>{Conv(1, 4, (vector<int>){3, 3, 5, 5}, (vector<int>){1, 1, 2, 2})});

  // Do a forward pass with the first "image"
  // model.h(X[1]);

  cout << "Test finished!\n";

  // Main

  return 0;
}
<commit_msg>Fixed test<commit_after>#include <iostream>
#include <regex>
#include <string>
#include <vector>

using namespace std;

// Good diagram: https://engmrk.com/wp-content/uploads/2018/09/Image-Architecture-of-Convolutional-Neural-Network.png

class Layer {
 public:
  vector<vector<vector<double>>> h(vector<vector<vector<double>>> x);

  // Helper function
  static void rand_init(vector<vector<double>> matrix, int height, int width) {
    for (int i = 0; i < height; i++) {
      for (int j = 0; j < width; j++) {
        // use numbers between -100 and 100
        double n = (double)rand() / RAND_MAX;  // scales rand() to [0, 1].
        n = n * 200 - 100;
        matrix[i][j] = n;  // (possibly) change to use float to save memory
      }
    }
  }
};

class Conv : public Layer {
 public:
  int num_input_channels;
  int num_filters;
  vector<int> size_per_filter;
  vector<int> stride_per_filter;

  vector<vector<vector<double>>> filters;
  Conv(int num_input_channels, int num_filters, vector<int> size_per_filter, vector<int> stride_per_filter) {
    // TODO: Check if there is a better way to save these.
    num_input_channels = num_input_channels;
    num_filters = num_filters;
    size_per_filter = size_per_filter;
    stride_per_filter = stride_per_filter;

    for (int filter_num; filter_num < num_filters; filter_num++) {
      // Filters are square
      int height = size_per_filter[filter_num];
      int width = size_per_filter[filter_num];

      vector<vector<double>> filter;
      Layer().rand_init(filter, height, width);
      filters[filter_num] = filter;
    }
  }

  // vector<vector<vector<double>>> h(vector<vector<vector<double>>> a) {
  //   // Input and output is height x width x num_channels
  //   // First filter adds to the output of the first channel only, etc.

  //   // feature map (or activation map) is the output of one filter (or kernel or detector)
  //   vector<vector<vector<double>>> output_block;
  //   int num_filters = filters.size();
  //   for (int i = 0; i < num_filters; i++) {  // Should be embarrassingly parallel
  //     vector<vector<double>> feature_map = convolve(a, filters[i], stride_per_filter[i]);
  //   }
  // }

  // static because this is a self-contained method
  vector<vector<double>> static convolve(vector<vector<vector<double>>> a, vector<vector<double>> filter, int stride) {
    // a is height x width x num_channels
    // Let's say a is 10x10x3 and filter is 3x3
    // The first convolutional step will use a's top left corner block of size 3x3x3
    // For each (i, j, [1, 2, 3]) section of a, we use the same (i, j)th weight of filter to flatten it
    // In other words, we do a[i][j][1]*w + a[i][j][2]*w + a[i][j][3]*w.
    // This produces a 3x3x1 which we then element-wise multiply with filter which is also 3x3x1 to
    // produce 3x3x1 multiplications. These are then all added together to produce one output per
    // convolutional step.
    // Reference:
    //
    // https://stats.stackexchange.com/questions/335321/in-a-convolutional-neural-network-cnn-when-convolving-the-image-is-the-opera

    int height = a.size();
    int width = a[0].size();
    int depth = a[0][0].size();

    int depth_of_a = a.size();
    vector<vector<double>> feature_map = _convolve(a[0], filter, stride);
    for (int depth = 1; depth < depth_of_a; depth++) {
      vector<vector<double>> feature_map_for_depth = _convolve(a[depth], filter, stride);
      feature_map = add_matrices(feature_map, feature_map_for_depth);
    }

    return feature_map;
  }

  vector<vector<double>> static add_matrices(vector<vector<double>> a, vector<vector<double>> b) {
    vector<vector<double>> c;

    for (int i = 0; i < a.size(); i++) {
      vector<double> c_column;
      for (int j = 0; j < a[0].size(); j++) {
        c_column.push_back(a[i][j] + b[i][j]);
      }
      c.push_back(c_column);
    }

    return c;
  }

  vector<vector<double>> static _convolve(vector<vector<double>> a, vector<vector<double>> filter, int stride) {
    // Maybe switch the order of i and j
    int i = 0;
    int j = 0;

    vector<vector<double>> convolved;
    while (i <= a.size() - filter.size()) {
      vector<double> convolved_column;

      while (j <= a[0].size() - filter[0].size()) {
        double acc_sum{0.0};
        for (int x = 0; x < filter.size(); ++x) {
          for (int y = 0; y < filter[0].size(); ++y) {
            acc_sum = acc_sum + a[i + x][j + y] * filter[x][y];
          }
        }
        convolved_column.push_back(acc_sum);

        j = j + stride;
      }
      convolved.push_back(convolved_column);
      j = 0;

      i = i + stride;
    }
    return convolved;
  }

  void static _convolve_test() {
    vector<vector<double>> a = {{1.0, 1.0, 1.0, 0.0, 0.0},
                                {0.0, 1.0, 1.0, 1.0, 0.0},
                                {0.0, 0.0, 1.0, 1.0, 1.0},
                                {0.0, 0.0, 1.0, 1.0, 0.0},
                                {0.0, 1.0, 1.0, 0.0, 0.0}};
    vector<vector<double>> filter = {{1.0, 0.0, 1.0}, {0.0, 1.0, 0.0}, {1.0, 0.0, 1.0}};

    vector<vector<double>> actual_output = _convolve(a, filter, 2);
    vector<vector<double>> expected_output = {{4.0, 4.0}, {2.0, 4.0}};

    for (int i = 0; i < actual_output.size(); i++) {
      for (int j = 0; j < actual_output[i].size(); j++) {
        cout << actual_output[i][j] << ",";
        if (actual_output[i][j] != expected_output[i][j]) {
          throw;
        }
      }
      cout << endl;
    }

    vector<vector<double>> a2 = {{1.0, 1.0, 1.0, 0.0, 0.0},
                                 {0.0, 1.0, 1.0, 1.0, 0.0},
                                 {0.0, 0.0, 1.0, 1.0, 1.0},
                                 {0.0, 0.0, 1.0, 1.0, 0.0},
                                 {0.0, 1.0, 1.0, 0.0, 0.0}};
    vector<vector<double>> filter2 = {{1.0}};

    vector<vector<double>> actual_output2 = _convolve(a2, filter2, 1);
    vector<vector<double>> expected_output2 = {{1.0, 1.0, 1.0, 0.0, 0.0},
                                               {0.0, 1.0, 1.0, 1.0, 0.0},
                                               {0.0, 0.0, 1.0, 1.0, 1.0},
                                               {0.0, 0.0, 1.0, 1.0, 0.0},
                                               {0.0, 1.0, 1.0, 0.0, 0.0}};

    for (int i = 0; i < actual_output2.size(); i++) {
      for (int j = 0; j < actual_output2[i].size(); j++) {
        cout << actual_output2[i][j] << ",";
        if (actual_output2[i][j] != expected_output2[i][j]) {
          throw;
        }
      }
      cout << endl;
    }
  }

  void static convolve_test() {
    vector<vector<vector<double>>> a = {{{1.0, 1.0, 1.0, 0.0, 0.0},
                                         {0.0, 1.0, 1.0, 1.0, 0.0},
                                         {0.0, 0.0, 1.0, 1.0, 1.0},
                                         {0.0, 0.0, 1.0, 1.0, 0.0},
                                         {0.0, 1.0, 1.0, 0.0, 0.0}},

                                        {{0.0, 1.0, 0.0, 1.0, 0.0},
                                         {0.0, 0.0, 1.0, 1.0, 1.0},
                                         {0.0, 0.0, 1.0, 1.0, 0.0},
                                         {0.0, 1.0, 1.0, 0.0, 1.0},
                                         {0.0, 1.0, 1.0, 0.0, 0.0}},

                                        {{1.0, 0.0, 0.0, 0.0, 0.0},
                                         {0.0, 1.0, 0.0, 0.0, 0.0},
                                         {0.0, 0.0, 1.0, 0.0, 0.0},
                                         {0.0, 0.0, 0.0, 1.0, 0.0},
                                         {0.0, 0.0, 0.0, 0.0, 1.0}}};
    vector<vector<double>> filter = {{1, 0}, {1, 1}};

    vector<vector<double>> actual_output = convolve(a, filter, 2);
    vector<vector<double>> expected_output = {{4.0, 5.0}, {1.0, 7.0}};

    for (int i = 0; i < actual_output.size(); i++) {
      for (int j = 0; j < actual_output[i].size(); j++) {
        cout << actual_output[i][j] << ",";
        if (actual_output[i][j] != expected_output[i][j]) {
          throw;
        }
      }
      cout << endl;
    }

    vector<vector<vector<double>>> a2 = {{{9.0, 1.0, 9.0, 0.0, 9.0},
                                          {0.0, 1.0, 9.0, 1.0, 0.0},
                                          {9.0, 0.0, 9.0, 1.0, 9.0},
                                          {0.0, 0.0, 9.0, 0.0, 0.0},
                                          {9.0, 1.0, 9.0, 0.0, 9.0}}};
    vector<vector<double>> filter2 = {{1.0}};

    vector<vector<double>> actual_output2 = convolve(a2, filter2, 2);
    vector<vector<double>> expected_output2 = {{9.0, 9.0, 9.0}, {9.0, 9.0, 9.0}, {9.0, 9.0, 9.0}};

    for (int i = 0; i < actual_output2.size(); i++) {
      for (int j = 0; j < actual_output2[0].size(); j++) {
        cout << actual_output2[i][j] << ",";
        if (actual_output2[i][j] != expected_output2[i][j]) {
          throw;
        }
      }
      cout << endl;
    }
  }
};

class Pool : public Layer {};

class Act : public Layer {};

class Dense : public Layer {};

class ConvNet {
 public:
  vector<Layer> layers;
  ConvNet(vector<Layer> layers) { layers = layers; }

  // int h(vector<vector<vector<double>>> x) {  // Returns an int, a classification
  //   vector<vector<vector<double>>> a = x;
  //   for (Layer layer : layers) {
  //     vector<vector<vector<double>>> a = layer.h(a);
  //   }
  //   // Convert the final output into a classification
  // }
};

int main() {
  // TEST
  cout << "Starting test...\n";

  int num_images = 100;
  vector<vector<vector<vector<double>>>> X;  // num_images x height x width x num_channels
  int Y[num_images];                         // labels for each example

  // Randomly initialize X and Y
  for (int i = 0; i < num_images; i++) {
    vector<vector<vector<double>>> image;
    for (int j = 0; j < 28; j++) {
      vector<vector<double>> row;  // Row has depth (of 1 in this example)
      for (int k = 0; k < 28; k++) {
        double f = (double)rand() / RAND_MAX;
        vector<double> num = {255 * f};  // use numbers from 0 to 255
        row.push_back(num);
      }
      image.push_back(row);
    }
    X.push_back(image);
    Y[i] = rand() % 10;  // TODO: Maybe decrease number of classes for the test?
  }

  // Look at first 2 "images"
  for (int i = 0; i < 2; i++) {
    for (int j = 0; j < 28; j++) {
      for (int k = 0; k < 28; k++) {
        cout << X[i][j][k][0] << ",";
      }
      cout << endl;
    }
    cout << endl;
  }

  // Flat convolution test
  Conv::_convolve_test();

  // Depth convolution test
  Conv::convolve_test();

  // Intialize model
  // Compound literal, (vector[]), helps initialize an array in function call
  // ConvNet model = ConvNet(vector<Layer>{Conv(1, 4, (vector<int>){3, 3, 5, 5}, (vector<int>){1, 1, 2, 2})});

  // Do a forward pass with the first "image"
  // model.h(X[1]);

  cout << "Test finished!\n";

  // Main

  return 0;
}
<|endoftext|>


<commit_before>/*
 * v8cgi app file. Loosely based on V8's "shell" sample app.
 */

#define _STRING(x) #x
#define STRING(x) _STRING(x)

#include <sstream>
#include <stdlib.h>
#include <v8.h>
#include <map>

#ifdef FASTCGI
#  include <fcgi_stdio.h>
#endif

#include "js_app.h"
#include "js_system.h"
#include "js_io.h"
#include "js_socket.h"
#include "js_macros.h"
#include "js_cache.h"

#ifndef windows
#   include <dlfcn.h>
#	define DLSYM dlsym
#else
#   include <windows.h>
#	define DLSYM GetProcAddress
#   define dlsym(x,y) (void*)GetProcAddress((HMODULE)x,y)
#endif

// chdir()
#ifndef HAVE_CHDIR
#	include <direct.h>
#	define chdir(name) _chdir(name)
#endif

// getcwd()
#ifndef HAVE_GETCWD
#	include <direct.h>
#	define getcwd(name, bytes) _getcwd(name, bytes)
#endif

JS_METHOD(_include) {
	v8::HandleScope handle_scope;
	v8cgi_App * app = APP_PTR;
	v8::String::Utf8Value file(args[0]);
	int result = app->execfile(*file, true);
	return JS_BOOL(!result);
}

JS_METHOD(_library) {
	v8::HandleScope handle_scope;
	v8cgi_App * app = APP_PTR;
	v8::String::Utf8Value file(args[0]);
	int result = app->library(*file);
	return JS_BOOL(!result);
}

JS_METHOD(_onexit) {
	v8::HandleScope handle_scope;
	v8cgi_App * app = APP_PTR;
	app->addOnExit(args[0]);
	return v8::Undefined();
}

JS_METHOD(_exit) {
	v8::Context::GetCurrent()->Exit();
	return v8::Undefined();
}

int v8cgi_App::init(int argc, char ** argv) {
	v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
	this->cfgfile = STRING(CONFIG_PATH);

	int argptr = 0;
	for (int i = 1; i < argc; i++) {
		const char* str = argv[i];
		std::string sstr = str;
		argptr = i;
		if (sstr.find("-c") == 0 && i + 1 < argc) {
			this->cfgfile = argv[i+1];
			argptr = 0;
			i++;
		}
	}

	if (argptr) { this->mainfile = argv[argptr]; }
	FILE* file = fopen(this->cfgfile.c_str(), "rb");
	if (file == NULL) {
		this->error("Invalid configuration file.\n", __FILE__, __LINE__ );
		return 1;
	}
	fclose(file);
	return 0;
}

int v8cgi_App::execute(char ** envp) {
	int result;
	v8::HandleScope handle_scope;
	v8::Handle<v8::ObjectTemplate> globaltemplate = v8::ObjectTemplate::New();
	globaltemplate->SetInternalFieldCount(1);
	v8::Handle<v8::Context> context = v8::Context::New(NULL, globaltemplate);
	v8::Context::Scope context_scope(context);

	result = this->prepare(envp);
	if (result == 0) {
		result = this->go(envp);
	}
	this->finish();
	return result;
}

void v8cgi_App::addOnExit(v8::Handle<v8::Value> what) {
	this->onexit->Set(JS_INT(this->onexit->Length()), what);
}

void v8cgi_App::report_error(const char * message) {
	int cgi = 0;
	v8::Local<v8::Function> fun;
	v8::Local<v8::Value> context = JS_GLOBAL->Get(JS_STR("response"));
	if (context->IsObject()) {
		v8::Local<v8::Value> print = context->ToObject()->Get(JS_STR("write"));
		if (print->IsObject()) {
			fun = v8::Local<v8::Function>::Cast(print);
			cgi = 1;
		}
	}
	if (!cgi) {
		context = JS_GLOBAL->Get(JS_STR("System"));
		fun = v8::Local<v8::Function>::Cast(context->ToObject()->Get(JS_STR("stdout")));
	}

	v8::Handle<v8::Value> data[1];
	data[0] = JS_STR(message);
	fun->Call(context->ToObject(), 1, data);
}

void v8cgi_App::exception(v8::TryCatch* try_catch) {
	v8::HandleScope handle_scope;
	v8::String::Utf8Value exception(try_catch->Exception());
	v8::Handle<v8::Message> message = try_catch->Message();
	std::string msgstring = "";
	std::stringstream ss;

	if (message.IsEmpty()) {
		msgstring += *exception;
		msgstring += "\n";
	} else {
		v8::String::Utf8Value filename(message->GetScriptResourceName());
		int linenum = message->GetLineNumber();
		msgstring += *filename;
		msgstring += ":";
		ss << linenum;
		msgstring += ss.str();
		msgstring += ": ";
		msgstring += *exception;
		msgstring += "\n";
	}

	this->report_error(msgstring.c_str());
}

v8::Handle<v8::String> v8cgi_App::read(std::string name) {
	std::string source = this->cache.getJS(name);
	return JS_STR(source.c_str());
}

int v8cgi_App::execfile(std::string str, bool change) {
	v8::HandleScope handle_scope;
	v8::TryCatch try_catch;
	v8::Handle<v8::String> name = JS_STR(str.c_str());
	v8::Handle<v8::String> source = this->read(str);

	if (source->Length() == 0) {
		std::string s = "Error reading '";
		s += str;
		s += "'\n";
		this->report_error(s.c_str());
		return 1;
	}

	v8::Handle<v8::Script> script = v8::Script::Compile(source, name);
	if (script.IsEmpty()) {
		this->exception(&try_catch);
		return 1;
	} else {
		char * tmp = getcwd(NULL, 0);
		std::string oldcwd = tmp;
		free(tmp);

		std::string newcwd = str;
		size_t pos = newcwd.find_last_of('/');
		if (pos == std::string::npos) { pos = newcwd.find_last_of('\\'); }
		if (pos != std::string::npos && change) {
			newcwd.erase(pos, newcwd.length()-pos);
    		chdir(newcwd.c_str());
		}
		v8::Handle<v8::Value> result = script->Run();

		if (change) { chdir(oldcwd.c_str()); }
		if (result.IsEmpty()) {
			this->exception(&try_catch);
			return 1;
		}
	}
	return 0;
}

int v8cgi_App::library(char * name) {
	v8::HandleScope handle_scope;
	v8::Handle<v8::Value> config = JS_GLOBAL->Get(JS_STR("Config"));
	v8::Handle<v8::Value> prefix = config->ToObject()->Get(JS_STR("libraryPath"));
	v8::String::Utf8Value pfx(prefix);
	std::string path = "";
	std::string error;

	path += *pfx;
	path += "/";
	path += name;

	if (path.find(".so") != std::string::npos || path.find(".dll") != std::string::npos) {
		void * handle = this->cache.getHandle(path);
		if (handle == NULL) {
			error = "Cannot load shared library '";
			error += path;
			error += "'\n";
			this->report_error(error.c_str());
			return 1;
		}

		typedef void (*funcdef)(v8::Handle<v8::Object>);
		typedef funcdef (*dlsym_t)(void *, const char *);
		funcdef func;
		func = ((dlsym_t)(DLSYM))(handle, "init");

		if (!func) {
			error = "Cannot initialize shared library '";
			error += path;
			error += "'\n";
			this->report_error(error.c_str());
			return 1;
		}

		func(JS_GLOBAL);
		return 0;
	} else {
		return this->execfile(path, false);
	}
}

int v8cgi_App::autoload() {
	v8::HandleScope handle_scope;
	v8::Handle<v8::Value> config = JS_GLOBAL->Get(JS_STR("Config"));
	v8::Handle<v8::Array> list = v8::Handle<v8::Array>::Cast(config->ToObject()->Get(JS_STR("libraryAutoload")));
	int cnt = list->Length();
	for (int i=0;i<cnt;i++) {
		v8::Handle<v8::Value> item = list->Get(JS_INT(i));
		v8::String::Utf8Value name(item);
		if (this->library(*name)) { return 1; }
	}
	return 0;
}

void v8cgi_App::finish() {
	v8::HandleScope handle_scope;
	uint32_t max = this->onexit->Length();
	v8::Handle<v8::Function> fun;
	for (unsigned int i=0;i<max;i++) {
		fun = v8::Handle<v8::Function>::Cast(this->onexit->Get(JS_INT(i)));
		fun->Call(JS_GLOBAL, 0, NULL);
	}
}

void v8cgi_App::http() { /* prepare global request and response objects */
	v8::Handle<v8::Object> sys = JS_GLOBAL->Get(JS_STR("System"))->ToObject();
	v8::Handle<v8::Value> env = sys->ToObject()->Get(JS_STR("env"));
	v8::Handle<v8::Value> ss = env->ToObject()->Get(JS_STR("SERVER_SOFTWARE"));
	if (!ss->IsString()) { return; }

	v8::Handle<v8::Object> http = JS_GLOBAL->Get(JS_STR("HTTP"))->ToObject();
	v8::Handle<v8::Value> req = http->Get(JS_STR("ServerRequest"));
	v8::Handle<v8::Value> res = http->Get(JS_STR("ServerResponse"));
	v8::Handle<v8::Function> reqf = v8::Handle<v8::Function>::Cast(req);
	v8::Handle<v8::Function> resf = v8::Handle<v8::Function>::Cast(res);

	v8::Handle<v8::Value> reqargs[] = {
		sys->Get(JS_STR("stdin")),
		sys->Get(JS_STR("env"))
	};
	v8::Handle<v8::Value> resargs[] = {
		sys->Get(JS_STR("stdout")),
		sys->Get(JS_STR("header"))
	};

	JS_GLOBAL->Set(JS_STR("request"), reqf->NewInstance(2, reqargs));
	JS_GLOBAL->Set(JS_STR("response"), resf->NewInstance(2, resargs));
}

int v8cgi_App::go(char ** envp) {
	v8::HandleScope handle_scope;

	this->http(); /* setup builtin request and response, if running as CGI */

	if (this->mainfile.length() == 0) { // try the PATH_TRANSLATED env var
		v8::Handle<v8::Value> sys = JS_GLOBAL->Get(JS_STR("System"));
		v8::Handle<v8::Value> env = sys->ToObject()->Get(JS_STR("env"));
		v8::Handle<v8::Value> pt = env->ToObject()->Get(JS_STR("PATH_TRANSLATED"));
		v8::Handle<v8::Value> sf = env->ToObject()->Get(JS_STR("SCRIPT_FILENAME"));
		if (pt->IsString()) {
			v8::String::Utf8Value jsname(pt);
			this->mainfile = *jsname;
		} else if (sf->IsString()) {
			v8::String::Utf8Value jsname(sf);
			this->mainfile = *jsname;
		}
	}

	if (this->mainfile.length() == 0) {
		error("Nothing to do.\n", __FILE__, __LINE__);
		return 1;
	} else {
		return this->execfile(this->mainfile, true);
	}
}

int v8cgi_App::prepare(char ** envp) {
	this->onexit = v8::Array::New();
	v8::Handle<v8::Object> g = JS_GLOBAL;

	GLOBAL_PROTO->SetInternalField(0, v8::External::New((void *)this));

	g->Set(JS_STR("library"), v8::FunctionTemplate::New(_library)->GetFunction());
	g->Set(JS_STR("include"), v8::FunctionTemplate::New(_include)->GetFunction());
	g->Set(JS_STR("onexit"), v8::FunctionTemplate::New(_onexit)->GetFunction());
//	g->Set(JS_STR("exit"), v8::FunctionTemplate::New(_exit)->GetFunction());
	g->Set(JS_STR("global"), g);
	g->Set(JS_STR("Config"), v8::Object::New());

	setup_system(g, envp);
	setup_io(g);
	setup_socket(g);

	if (this->execfile(cfgfile, false)) {
		error("Cannot load configuration, quitting...\n", __FILE__, __LINE__);
		return 1;
	}

	if (this->autoload()) {
		error("Cannot load default libraries, quitting...\n", __FILE__, __LINE__);
		return 1;
	}

	return 0;
}

size_t v8cgi_App::reader(char * destination, size_t amount) {
	return fread((void *) destination, sizeof(char), amount, stdin);
}

size_t v8cgi_App::writer(const char * data, size_t amount) {
	return fwrite((void *) data, sizeof(char), amount, stdout);
}

void v8cgi_App::error(const char * data, const char * file, int line) {
	fwrite((void *) data, sizeof(char), strlen(data), stderr);
}

void v8cgi_App::header(const char * name, const char * value) {
	printf("%s: %s\n", name, value);
}
<commit_msg>config error reporting<commit_after>/*
 * v8cgi app file. Loosely based on V8's "shell" sample app.
 */

#define _STRING(x) #x
#define STRING(x) _STRING(x)

#include <sstream>
#include <stdlib.h>
#include <v8.h>
#include <map>

#ifdef FASTCGI
#  include <fcgi_stdio.h>
#endif

#include "js_app.h"
#include "js_system.h"
#include "js_io.h"
#include "js_socket.h"
#include "js_macros.h"
#include "js_cache.h"

#ifndef windows
#   include <dlfcn.h>
#	define DLSYM dlsym
#else
#   include <windows.h>
#	define DLSYM GetProcAddress
#   define dlsym(x,y) (void*)GetProcAddress((HMODULE)x,y)
#endif

// chdir()
#ifndef HAVE_CHDIR
#	include <direct.h>
#	define chdir(name) _chdir(name)
#endif

// getcwd()
#ifndef HAVE_GETCWD
#	include <direct.h>
#	define getcwd(name, bytes) _getcwd(name, bytes)
#endif

JS_METHOD(_include) {
	v8::HandleScope handle_scope;
	v8cgi_App * app = APP_PTR;
	v8::String::Utf8Value file(args[0]);
	int result = app->execfile(*file, true);
	return JS_BOOL(!result);
}

JS_METHOD(_library) {
	v8::HandleScope handle_scope;
	v8cgi_App * app = APP_PTR;
	v8::String::Utf8Value file(args[0]);
	int result = app->library(*file);
	return JS_BOOL(!result);
}

JS_METHOD(_onexit) {
	v8::HandleScope handle_scope;
	v8cgi_App * app = APP_PTR;
	app->addOnExit(args[0]);
	return v8::Undefined();
}

JS_METHOD(_exit) {
	v8::Context::GetCurrent()->Exit();
	return v8::Undefined();
}

int v8cgi_App::init(int argc, char ** argv) {
	v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
	this->cfgfile = STRING(CONFIG_PATH);

	int argptr = 0;
	for (int i = 1; i < argc; i++) {
		const char* str = argv[i];
		std::string sstr = str;
		argptr = i;
		if (sstr.find("-c") == 0 && i + 1 < argc) {
			this->cfgfile = argv[i+1];
			argptr = 0;
			i++;
		}
	}

	if (argptr) { this->mainfile = argv[argptr]; }
	FILE* file = fopen(this->cfgfile.c_str(), "rb");
	if (file == NULL) {
		std::string err = "Invalid configuration file (";
		err += this->cfgfile;
		err += ").\n";
		this->error(err.c_str(), __FILE__, __LINE__ );
		return 1;
	}
	fclose(file);
	return 0;
}

int v8cgi_App::execute(char ** envp) {
	int result;
	v8::HandleScope handle_scope;
	v8::Handle<v8::ObjectTemplate> globaltemplate = v8::ObjectTemplate::New();
	globaltemplate->SetInternalFieldCount(1);
	v8::Handle<v8::Context> context = v8::Context::New(NULL, globaltemplate);
	v8::Context::Scope context_scope(context);

	result = this->prepare(envp);
	if (result == 0) {
		result = this->go(envp);
	}
	this->finish();
	return result;
}

void v8cgi_App::addOnExit(v8::Handle<v8::Value> what) {
	this->onexit->Set(JS_INT(this->onexit->Length()), what);
}

void v8cgi_App::report_error(const char * message) {
	int cgi = 0;
	v8::Local<v8::Function> fun;
	v8::Local<v8::Value> context = JS_GLOBAL->Get(JS_STR("response"));
	if (context->IsObject()) {
		v8::Local<v8::Value> print = context->ToObject()->Get(JS_STR("write"));
		if (print->IsObject()) {
			fun = v8::Local<v8::Function>::Cast(print);
			cgi = 1;
		}
	}
	if (!cgi) {
		context = JS_GLOBAL->Get(JS_STR("System"));
		fun = v8::Local<v8::Function>::Cast(context->ToObject()->Get(JS_STR("stdout")));
	}

	v8::Handle<v8::Value> data[1];
	data[0] = JS_STR(message);
	fun->Call(context->ToObject(), 1, data);
}

void v8cgi_App::exception(v8::TryCatch* try_catch) {
	v8::HandleScope handle_scope;
	v8::String::Utf8Value exception(try_catch->Exception());
	v8::Handle<v8::Message> message = try_catch->Message();
	std::string msgstring = "";
	std::stringstream ss;

	if (message.IsEmpty()) {
		msgstring += *exception;
		msgstring += "\n";
	} else {
		v8::String::Utf8Value filename(message->GetScriptResourceName());
		int linenum = message->GetLineNumber();
		msgstring += *filename;
		msgstring += ":";
		ss << linenum;
		msgstring += ss.str();
		msgstring += ": ";
		msgstring += *exception;
		msgstring += "\n";
	}

	this->report_error(msgstring.c_str());
}

v8::Handle<v8::String> v8cgi_App::read(std::string name) {
	std::string source = this->cache.getJS(name);
	return JS_STR(source.c_str());
}

int v8cgi_App::execfile(std::string str, bool change) {
	v8::HandleScope handle_scope;
	v8::TryCatch try_catch;
	v8::Handle<v8::String> name = JS_STR(str.c_str());
	v8::Handle<v8::String> source = this->read(str);

	if (source->Length() == 0) {
		std::string s = "Error reading '";
		s += str;
		s += "'\n";
		this->report_error(s.c_str());
		return 1;
	}

	v8::Handle<v8::Script> script = v8::Script::Compile(source, name);
	if (script.IsEmpty()) {
		this->exception(&try_catch);
		return 1;
	} else {
		char * tmp = getcwd(NULL, 0);
		std::string oldcwd = tmp;
		free(tmp);

		std::string newcwd = str;
		size_t pos = newcwd.find_last_of('/');
		if (pos == std::string::npos) { pos = newcwd.find_last_of('\\'); }
		if (pos != std::string::npos && change) {
			newcwd.erase(pos, newcwd.length()-pos);
    		chdir(newcwd.c_str());
		}
		v8::Handle<v8::Value> result = script->Run();

		if (change) { chdir(oldcwd.c_str()); }
		if (result.IsEmpty()) {
			this->exception(&try_catch);
			return 1;
		}
	}
	return 0;
}

int v8cgi_App::library(char * name) {
	v8::HandleScope handle_scope;
	v8::Handle<v8::Value> config = JS_GLOBAL->Get(JS_STR("Config"));
	v8::Handle<v8::Value> prefix = config->ToObject()->Get(JS_STR("libraryPath"));
	v8::String::Utf8Value pfx(prefix);
	std::string path = "";
	std::string error;

	path += *pfx;
	path += "/";
	path += name;

	if (path.find(".so") != std::string::npos || path.find(".dll") != std::string::npos) {
		void * handle = this->cache.getHandle(path);
		if (handle == NULL) {
			error = "Cannot load shared library '";
			error += path;
			error += "'\n";
			this->report_error(error.c_str());
			return 1;
		}

		typedef void (*funcdef)(v8::Handle<v8::Object>);
		typedef funcdef (*dlsym_t)(void *, const char *);
		funcdef func;
		func = ((dlsym_t)(DLSYM))(handle, "init");

		if (!func) {
			error = "Cannot initialize shared library '";
			error += path;
			error += "'\n";
			this->report_error(error.c_str());
			return 1;
		}

		func(JS_GLOBAL);
		return 0;
	} else {
		return this->execfile(path, false);
	}
}

int v8cgi_App::autoload() {
	v8::HandleScope handle_scope;
	v8::Handle<v8::Value> config = JS_GLOBAL->Get(JS_STR("Config"));
	v8::Handle<v8::Array> list = v8::Handle<v8::Array>::Cast(config->ToObject()->Get(JS_STR("libraryAutoload")));
	int cnt = list->Length();
	for (int i=0;i<cnt;i++) {
		v8::Handle<v8::Value> item = list->Get(JS_INT(i));
		v8::String::Utf8Value name(item);
		if (this->library(*name)) { return 1; }
	}
	return 0;
}

void v8cgi_App::finish() {
	v8::HandleScope handle_scope;
	uint32_t max = this->onexit->Length();
	v8::Handle<v8::Function> fun;
	for (unsigned int i=0;i<max;i++) {
		fun = v8::Handle<v8::Function>::Cast(this->onexit->Get(JS_INT(i)));
		fun->Call(JS_GLOBAL, 0, NULL);
	}
}

void v8cgi_App::http() { /* prepare global request and response objects */
	v8::Handle<v8::Object> sys = JS_GLOBAL->Get(JS_STR("System"))->ToObject();
	v8::Handle<v8::Value> env = sys->ToObject()->Get(JS_STR("env"));
	v8::Handle<v8::Value> ss = env->ToObject()->Get(JS_STR("SERVER_SOFTWARE"));
	if (!ss->IsString()) { return; }

	v8::Handle<v8::Object> http = JS_GLOBAL->Get(JS_STR("HTTP"))->ToObject();
	v8::Handle<v8::Value> req = http->Get(JS_STR("ServerRequest"));
	v8::Handle<v8::Value> res = http->Get(JS_STR("ServerResponse"));
	v8::Handle<v8::Function> reqf = v8::Handle<v8::Function>::Cast(req);
	v8::Handle<v8::Function> resf = v8::Handle<v8::Function>::Cast(res);

	v8::Handle<v8::Value> reqargs[] = {
		sys->Get(JS_STR("stdin")),
		sys->Get(JS_STR("env"))
	};
	v8::Handle<v8::Value> resargs[] = {
		sys->Get(JS_STR("stdout")),
		sys->Get(JS_STR("header"))
	};

	JS_GLOBAL->Set(JS_STR("request"), reqf->NewInstance(2, reqargs));
	JS_GLOBAL->Set(JS_STR("response"), resf->NewInstance(2, resargs));
}

int v8cgi_App::go(char ** envp) {
	v8::HandleScope handle_scope;

	this->http(); /* setup builtin request and response, if running as CGI */

	if (this->mainfile.length() == 0) { // try the PATH_TRANSLATED env var
		v8::Handle<v8::Value> sys = JS_GLOBAL->Get(JS_STR("System"));
		v8::Handle<v8::Value> env = sys->ToObject()->Get(JS_STR("env"));
		v8::Handle<v8::Value> pt = env->ToObject()->Get(JS_STR("PATH_TRANSLATED"));
		v8::Handle<v8::Value> sf = env->ToObject()->Get(JS_STR("SCRIPT_FILENAME"));
		if (pt->IsString()) {
			v8::String::Utf8Value jsname(pt);
			this->mainfile = *jsname;
		} else if (sf->IsString()) {
			v8::String::Utf8Value jsname(sf);
			this->mainfile = *jsname;
		}
	}

	if (this->mainfile.length() == 0) {
		error("Nothing to do.\n", __FILE__, __LINE__);
		return 1;
	} else {
		return this->execfile(this->mainfile, true);
	}
}

int v8cgi_App::prepare(char ** envp) {
	this->onexit = v8::Array::New();
	v8::Handle<v8::Object> g = JS_GLOBAL;

	GLOBAL_PROTO->SetInternalField(0, v8::External::New((void *)this));

	g->Set(JS_STR("library"), v8::FunctionTemplate::New(_library)->GetFunction());
	g->Set(JS_STR("include"), v8::FunctionTemplate::New(_include)->GetFunction());
	g->Set(JS_STR("onexit"), v8::FunctionTemplate::New(_onexit)->GetFunction());
//	g->Set(JS_STR("exit"), v8::FunctionTemplate::New(_exit)->GetFunction());
	g->Set(JS_STR("global"), g);
	g->Set(JS_STR("Config"), v8::Object::New());

	setup_system(g, envp);
	setup_io(g);
	setup_socket(g);

	if (this->execfile(cfgfile, false)) {
		error("Cannot load configuration, quitting...\n", __FILE__, __LINE__);
		return 1;
	}

	if (this->autoload()) {
		error("Cannot load default libraries, quitting...\n", __FILE__, __LINE__);
		return 1;
	}

	return 0;
}

size_t v8cgi_App::reader(char * destination, size_t amount) {
	return fread((void *) destination, sizeof(char), amount, stdin);
}

size_t v8cgi_App::writer(const char * data, size_t amount) {
	return fwrite((void *) data, sizeof(char), amount, stdout);
}

void v8cgi_App::error(const char * data, const char * file, int line) {
	fwrite((void *) data, sizeof(char), strlen(data), stderr);
}

void v8cgi_App::header(const char * name, const char * value) {
	printf("%s: %s\n", name, value);
}
<|endoftext|>


<commit_before>// Copyright (C) 2010 - 2013 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and The University
// of Manchester.
// All rights reserved.

// Copyright (C) 2008 - 2009 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., EML Research, gGmbH, University of Heidelberg,
// and The University of Manchester.
// All rights reserved.

// Copyright (C) 2007 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc. and EML Research, gGmbH.
// All rights reserved.

/**
 * CTSSATask class.
 *
 * This class implements a time scale separation analysis task which is comprised of a
 * of a problem and a method. Additionally calls to the reporting
 * methods are done when initialized.
 *
 */

#include <string>

#include "copasi.h"

#include "CTSSATask.h"
#include "CTSSAProblem.h"
#include "CTSSAMethod.h"
#include "model/CModel.h"
#include "model/CState.h"
#include "report/CKeyFactory.h"
#include "report/CReport.h"
#include "utilities/CProcessReport.h"
#include "utilities/CCopasiException.h"
#include  "CopasiDataModel/CCopasiDataModel.h"

#define XXXX_Reporting

bool tfle(const C_FLOAT64 & d1, const C_FLOAT64 & d2)
{return (d1 <= d2);}

bool tfl(const C_FLOAT64 & d1, const C_FLOAT64 & d2)
{return (d1 < d2);}

bool tble(const C_FLOAT64 & d1, const C_FLOAT64 & d2)
{return (d1 >= d2);}

bool tbl(const C_FLOAT64 & d1, const C_FLOAT64 & d2)
{return (d1 > d2);}

const unsigned int CTSSATask::ValidMethods[] =
{
  CCopasiMethod::tssILDM,
  CCopasiMethod::tssILDMModified,
  CCopasiMethod::tssCSP,
  CCopasiMethod::unset
};

CTSSATask::CTSSATask(const CCopasiContainer * pParent):
  CCopasiTask(CCopasiTask::tssAnalysis, pParent),
  mTimeSeriesRequested(true),
  mTimeSeries(),
  mpTSSAProblem(NULL),
  mpTSSAMethod(NULL),
  mpCurrentState(NULL),
  mpCurrentTime(NULL)
{
  mpProblem = new CTSSAProblem(this);
  mpMethod = createMethod(CCopasiMethod::tssILDM);
  this->add(mpMethod, true);

  CCopasiParameter * pParameter = mpMethod->getParameter("Integrate Reduced Model");

  if (pParameter != NULL)
    mUpdateMoieties = *pParameter->getValue().pBOOL;
  else
    mUpdateMoieties = false;
}

CTSSATask::CTSSATask(const CTSSATask & src,
                     const CCopasiContainer * pParent):
  CCopasiTask(src, pParent),
  mTimeSeriesRequested(src.mTimeSeriesRequested),
  mTimeSeries(),
  mpTSSAProblem(NULL),
  mpTSSAMethod(NULL),
  mpCurrentState(NULL),
  mpCurrentTime(NULL)
{
  mpProblem =
    new CTSSAProblem(*static_cast< CTSSAProblem * >(src.mpProblem), this);

  mpMethod = createMethod(src.mpMethod->getSubType());
  * mpMethod = * src.mpMethod;
  mpMethod->elevateChildren();

  this->add(mpMethod, true);

  CCopasiParameter * pParameter = mpMethod->getParameter("Integrate Reduced Model");

  if (pParameter != NULL)
    mUpdateMoieties = *pParameter->getValue().pBOOL;
  else
    mUpdateMoieties = false;
}

CTSSATask::~CTSSATask()
{
  cleanup();
}

void CTSSATask::cleanup()
{
  pdelete(mpCurrentState);
}

bool CTSSATask::updateMatrices() //NEW
{
  assert(mpProblem != NULL && mpMethod != NULL);

  assert(dynamic_cast<CTSSAProblem *>(mpProblem) != NULL);

  if (!mpMethod->isValidProblem(mpProblem)) return false;

  CTSSAMethod * pMethod = dynamic_cast<CTSSAMethod*>(mpMethod);

  if (!pMethod) return false;

  pMethod->setModel(mpProblem->getModel());

  pMethod->predifineAnnotation();

  return true;
}

bool CTSSATask::initialize(const OutputFlag & of,
                           COutputHandler * pOutputHandler,
                           std::ostream * pOstream)
{
  assert(mpProblem && mpMethod);

  mpTSSAProblem = dynamic_cast<CTSSAProblem *>(mpProblem);
  assert(mpTSSAProblem);

  mpTSSAMethod = dynamic_cast<CTSSAMethod *>(mpMethod);
  assert(mpTSSAMethod);

  mpTSSAMethod->setProblem(mpTSSAProblem);

  bool success = mpMethod->isValidProblem(mpProblem);

  CCopasiParameter * pParameter = mpMethod->getParameter("Integrate Reduced Model");

  if (pParameter != NULL)
    mUpdateMoieties = *pParameter->getValue().pBOOL;
  else
    mUpdateMoieties = false;

  pdelete(mpCurrentState);
  mpCurrentState = new CState(mpTSSAProblem->getModel()->getState());
  mpCurrentTime = &mpCurrentState->getTime();

  // Handle the time series as a regular output.
  mTimeSeriesRequested = mpTSSAProblem->timeSeriesRequested();

  if (pOutputHandler != NULL)
    {
      if (mTimeSeriesRequested)
        {
          mTimeSeries.allocate(mpTSSAProblem->getStepNumber());
          pOutputHandler->addInterface(&mTimeSeries);
        }
      else
        {
          mTimeSeries.clear();
        }
    }

//NEW

  mpTSSAMethod->setModel(mpTSSAProblem->getModel());

  mpTSSAMethod->predifineAnnotation();

//

  if (!CCopasiTask::initialize(of, pOutputHandler, pOstream)) success = false;

  return success;
}

bool CTSSATask::process(const bool & useInitialValues)
{
  //*****

  processStart(useInitialValues);

  //*****

  C_FLOAT64 StepSize = mpTSSAProblem->getStepSize();
  C_FLOAT64 NextTimeToReport;

  const C_FLOAT64 EndTime = *mpCurrentTime + mpTSSAProblem->getDuration();
  const C_FLOAT64 StartTime = *mpCurrentTime;

  C_FLOAT64 StepNumber = (mpTSSAProblem->getDuration()) / StepSize;

  bool (*LE)(const C_FLOAT64 &, const C_FLOAT64 &);
  bool (*L)(const C_FLOAT64 &, const C_FLOAT64 &);

  if (StepSize < 0.0)
    {
      LE = &tble;
      L = &tbl;
    }
  else
    {
      LE = &tfle;
      L = &tfl;
    }

  size_t StepCounter = 1;

  C_FLOAT64 outputStartTime = mpTSSAProblem->getOutputStartTime();

  if (StepSize == 0.0 && mpTSSAProblem->getDuration() != 0.0)
    {
      CCopasiMessage(CCopasiMessage::ERROR, MCTSSAProblem + 1, StepSize);
      return false;
    }

  output(COutputInterface::BEFORE);

  bool flagProceed = true;
  C_FLOAT64 handlerFactor = 100.0 / mpTSSAProblem->getDuration();

  C_FLOAT64 Percentage = 0;
  size_t hProcess;

  if (mpCallBack)
    {
      mpCallBack->setName("performing simulation...");
      C_FLOAT64 hundred = 100;
      hProcess = mpCallBack->addItem("Completion",
                                     Percentage,
                                     &hundred);
    }

  //if ((*LE)(outputStartTime, *mpCurrentTime)) output(COutputInterface::DURING);

  try
    {
      do
        {
          // This is numerically more stable then adding
          // mpTSSAProblem->getStepSize().
          NextTimeToReport =
            StartTime + (EndTime - StartTime) * StepCounter++ / StepNumber;

          flagProceed &= processStep(NextTimeToReport);

          if (mpCallBack)
            {
              Percentage = (*mpCurrentTime - StartTime) * handlerFactor;
              flagProceed &= mpCallBack->progressItem(hProcess);
            }

          if ((*LE)(outputStartTime, *mpCurrentTime))
            {
              output(COutputInterface::DURING);
            }
        }
      while ((*L)(*mpCurrentTime, EndTime) && flagProceed);
    }

  catch (int)
    {
      mpTSSAProblem->getModel()->setState(*mpCurrentState);
      mpTSSAProblem->getModel()->updateSimulatedValues(mUpdateMoieties);

      if ((*LE)(outputStartTime, *mpCurrentTime))
        {
          output(COutputInterface::DURING);
        }

      if (mpCallBack) mpCallBack->finishItem(hProcess);

      output(COutputInterface::AFTER);

      CCopasiMessage(CCopasiMessage::EXCEPTION, MCTSSAMethod + 4);
    }

  catch (CCopasiException Exception)
    {
      mpTSSAProblem->getModel()->setState(*mpCurrentState);
      mpTSSAProblem->getModel()->updateSimulatedValues(mUpdateMoieties);

      if ((*LE)(outputStartTime, *mpCurrentTime))
        {
          output(COutputInterface::DURING);
        }

      if (mpCallBack) mpCallBack->finishItem(hProcess);

      output(COutputInterface::AFTER);

      throw CCopasiException(Exception.getMessage());
    }

  if (mpCallBack) mpCallBack->finishItem(hProcess);

  output(COutputInterface::AFTER);

  return true;
}

void CTSSATask::processStart(const bool & useInitialValues)
{
  if (useInitialValues)
    mpTSSAProblem->getModel()->applyInitialValues();

  *mpCurrentState = mpTSSAProblem->getModel()->getState();

  mpTSSAMethod->setCurrentState(mpCurrentState);
  mpTSSAMethod->start(mpCurrentState);

  return;
}

bool CTSSATask::processStep(const C_FLOAT64 & nextTime)
{
  C_FLOAT64 CompareTime = nextTime - 100.0 * fabs(nextTime) * std::numeric_limits< C_FLOAT64 >::epsilon();

  if (*mpCurrentTime <= CompareTime)
    {
      do
        {
          mpTSSAMethod->step(nextTime - *mpCurrentTime);

          if (*mpCurrentTime > CompareTime) break;

          /* Here we will do conditional event processing */

          /* Currently this is correct since no events are processed. */
          CCopasiMessage(CCopasiMessage::EXCEPTION, MCTSSAMethod + 3);
        }
      while (true);

      mpTSSAProblem->getModel()->setState(*mpCurrentState);
      mpTSSAProblem->getModel()->updateSimulatedValues(mUpdateMoieties);

      return true;
    }

  CompareTime = nextTime + 100.0 * fabs(nextTime) * std::numeric_limits< C_FLOAT64 >::epsilon();

  if (*mpCurrentTime >= CompareTime)
    {
      do
        {
          mpTSSAMethod->step(nextTime - *mpCurrentTime);

          if (*mpCurrentTime < CompareTime) break;

          /* Here we will do conditional event processing */

          /* Currently this is correct since no events are processed. */
          CCopasiMessage(CCopasiMessage::EXCEPTION, MCTSSAMethod + 3);
        }
      while (true);

      mpTSSAProblem->getModel()->setState(*mpCurrentState);
      mpTSSAProblem->getModel()->updateSimulatedValues(mUpdateMoieties);

      return true;
    }

  // Current time is approximately nextTime;
  return false;
}

bool CTSSATask::restore()
{
  bool success = CCopasiTask::restore();

  if (mUpdateModel)
    {
      CModel * pModel = mpProblem->getModel();

      pModel->setState(*mpCurrentState);
      pModel->updateSimulatedValues(mUpdateMoieties);
      pModel->setInitialState(pModel->getState());
      pModel->updateInitialValues();
    }

  return success;
}

bool CTSSATask::setMethodType(const int & type)
{
  CCopasiMethod::SubType Type = (CCopasiMethod::SubType) type;

  if (!isValidMethod(Type, ValidMethods)) return false;

  if (mpMethod->getSubType() == Type) return true;

  pdelete(mpMethod);
  mpMethod = createMethod(Type);
  this->add(mpMethod, true);
  //mpMethod->setObjectParent(this);

  return true;
}

// virtual
CCopasiMethod * CTSSATask::createMethod(const int & type) const
{
  CCopasiMethod::SubType Type = (CCopasiMethod::SubType) type;

  return CTSSAMethod::createMethod(Type);
}

CState * CTSSATask::getState()
{return mpCurrentState;}

const CTimeSeries & CTSSATask::getTimeSeries() const
{return mTimeSeries;}
<commit_msg>Fixed compiler warning.<commit_after>// Copyright (C) 2010 - 2013 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and The University
// of Manchester.
// All rights reserved.

// Copyright (C) 2008 - 2009 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., EML Research, gGmbH, University of Heidelberg,
// and The University of Manchester.
// All rights reserved.

// Copyright (C) 2007 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc. and EML Research, gGmbH.
// All rights reserved.

/**
 * CTSSATask class.
 *
 * This class implements a time scale separation analysis task which is comprised of a
 * of a problem and a method. Additionally calls to the reporting
 * methods are done when initialized.
 *
 */

#include <string>

#include "copasi.h"

#include "CTSSATask.h"
#include "CTSSAProblem.h"
#include "CTSSAMethod.h"
#include "model/CModel.h"
#include "model/CState.h"
#include "report/CKeyFactory.h"
#include "report/CReport.h"
#include "utilities/CProcessReport.h"
#include "utilities/CCopasiException.h"
#include  "CopasiDataModel/CCopasiDataModel.h"

#define XXXX_Reporting

bool tfle(const C_FLOAT64 & d1, const C_FLOAT64 & d2)
{return (d1 <= d2);}

bool tfl(const C_FLOAT64 & d1, const C_FLOAT64 & d2)
{return (d1 < d2);}

bool tble(const C_FLOAT64 & d1, const C_FLOAT64 & d2)
{return (d1 >= d2);}

bool tbl(const C_FLOAT64 & d1, const C_FLOAT64 & d2)
{return (d1 > d2);}

const unsigned int CTSSATask::ValidMethods[] =
{
  CCopasiMethod::tssILDM,
  CCopasiMethod::tssILDMModified,
  CCopasiMethod::tssCSP,
  CCopasiMethod::unset
};

CTSSATask::CTSSATask(const CCopasiContainer * pParent):
  CCopasiTask(CCopasiTask::tssAnalysis, pParent),
  mTimeSeriesRequested(true),
  mTimeSeries(),
  mpTSSAProblem(NULL),
  mpTSSAMethod(NULL),
  mpCurrentState(NULL),
  mpCurrentTime(NULL)
{
  mpProblem = new CTSSAProblem(this);
  mpMethod = createMethod(CCopasiMethod::tssILDM);
  this->add(mpMethod, true);

  CCopasiParameter * pParameter = mpMethod->getParameter("Integrate Reduced Model");

  if (pParameter != NULL)
    mUpdateMoieties = *pParameter->getValue().pBOOL;
  else
    mUpdateMoieties = false;
}

CTSSATask::CTSSATask(const CTSSATask & src,
                     const CCopasiContainer * pParent):
  CCopasiTask(src, pParent),
  mTimeSeriesRequested(src.mTimeSeriesRequested),
  mTimeSeries(),
  mpTSSAProblem(NULL),
  mpTSSAMethod(NULL),
  mpCurrentState(NULL),
  mpCurrentTime(NULL)
{
  mpProblem =
    new CTSSAProblem(*static_cast< CTSSAProblem * >(src.mpProblem), this);

  mpMethod = createMethod(src.mpMethod->getSubType());
  * mpMethod = * src.mpMethod;
  mpMethod->elevateChildren();

  this->add(mpMethod, true);

  CCopasiParameter * pParameter = mpMethod->getParameter("Integrate Reduced Model");

  if (pParameter != NULL)
    mUpdateMoieties = *pParameter->getValue().pBOOL;
  else
    mUpdateMoieties = false;
}

CTSSATask::~CTSSATask()
{
  cleanup();
}

void CTSSATask::cleanup()
{
  pdelete(mpCurrentState);
}

bool CTSSATask::updateMatrices() //NEW
{
  assert(mpProblem != NULL && mpMethod != NULL);

  assert(dynamic_cast<CTSSAProblem *>(mpProblem) != NULL);

  if (!mpMethod->isValidProblem(mpProblem)) return false;

  CTSSAMethod * pMethod = dynamic_cast<CTSSAMethod*>(mpMethod);

  if (!pMethod) return false;

  pMethod->setModel(mpProblem->getModel());

  pMethod->predifineAnnotation();

  return true;
}

bool CTSSATask::initialize(const OutputFlag & of,
                           COutputHandler * pOutputHandler,
                           std::ostream * pOstream)
{
  assert(mpProblem && mpMethod);

  mpTSSAProblem = dynamic_cast<CTSSAProblem *>(mpProblem);
  assert(mpTSSAProblem);

  mpTSSAMethod = dynamic_cast<CTSSAMethod *>(mpMethod);
  assert(mpTSSAMethod);

  mpTSSAMethod->setProblem(mpTSSAProblem);

  bool success = mpMethod->isValidProblem(mpProblem);

  CCopasiParameter * pParameter = mpMethod->getParameter("Integrate Reduced Model");

  if (pParameter != NULL)
    mUpdateMoieties = *pParameter->getValue().pBOOL;
  else
    mUpdateMoieties = false;

  pdelete(mpCurrentState);
  mpCurrentState = new CState(mpTSSAProblem->getModel()->getState());
  mpCurrentTime = &mpCurrentState->getTime();

  // Handle the time series as a regular output.
  mTimeSeriesRequested = mpTSSAProblem->timeSeriesRequested();

  if (pOutputHandler != NULL)
    {
      if (mTimeSeriesRequested)
        {
          mTimeSeries.allocate(mpTSSAProblem->getStepNumber());
          pOutputHandler->addInterface(&mTimeSeries);
        }
      else
        {
          mTimeSeries.clear();
        }
    }

//NEW

  mpTSSAMethod->setModel(mpTSSAProblem->getModel());

  mpTSSAMethod->predifineAnnotation();

//

  if (!CCopasiTask::initialize(of, pOutputHandler, pOstream)) success = false;

  return success;
}

bool CTSSATask::process(const bool & useInitialValues)
{
  //*****

  processStart(useInitialValues);

  //*****

  C_FLOAT64 StepSize = mpTSSAProblem->getStepSize();
  C_FLOAT64 NextTimeToReport;

  const C_FLOAT64 EndTime = *mpCurrentTime + mpTSSAProblem->getDuration();
  const C_FLOAT64 StartTime = *mpCurrentTime;

  C_FLOAT64 StepNumber = (mpTSSAProblem->getDuration()) / StepSize;

  bool (*LE)(const C_FLOAT64 &, const C_FLOAT64 &);
  bool (*L)(const C_FLOAT64 &, const C_FLOAT64 &);

  if (StepSize < 0.0)
    {
      LE = &tble;
      L = &tbl;
    }
  else
    {
      LE = &tfle;
      L = &tfl;
    }

  size_t StepCounter = 1;

  C_FLOAT64 outputStartTime = mpTSSAProblem->getOutputStartTime();

  if (StepSize == 0.0 && mpTSSAProblem->getDuration() != 0.0)
    {
      CCopasiMessage(CCopasiMessage::ERROR, MCTSSAProblem + 1, StepSize);
      return false;
    }

  output(COutputInterface::BEFORE);

  bool flagProceed = true;
  C_FLOAT64 handlerFactor = 100.0 / mpTSSAProblem->getDuration();

  C_FLOAT64 Percentage = 0;
  size_t hProcess;

  if (mpCallBack)
    {
      mpCallBack->setName("performing simulation...");
      C_FLOAT64 hundred = 100;
      hProcess = mpCallBack->addItem("Completion",
                                     Percentage,
                                     &hundred);
    }

  //if ((*LE)(outputStartTime, *mpCurrentTime)) output(COutputInterface::DURING);

  try
    {
      do
        {
          // This is numerically more stable then adding
          // mpTSSAProblem->getStepSize().
          NextTimeToReport =
            StartTime + (EndTime - StartTime) * StepCounter++ / StepNumber;

          flagProceed &= processStep(NextTimeToReport);

          if (mpCallBack)
            {
              Percentage = (*mpCurrentTime - StartTime) * handlerFactor;
              flagProceed &= mpCallBack->progressItem(hProcess);
            }

          if ((*LE)(outputStartTime, *mpCurrentTime))
            {
              output(COutputInterface::DURING);
            }
        }
      while ((*L)(*mpCurrentTime, EndTime) && flagProceed);
    }

  catch (int)
    {
      mpTSSAProblem->getModel()->setState(*mpCurrentState);
      mpTSSAProblem->getModel()->updateSimulatedValues(mUpdateMoieties);

      if ((*LE)(outputStartTime, *mpCurrentTime))
        {
          output(COutputInterface::DURING);
        }

      if (mpCallBack) mpCallBack->finishItem(hProcess);

      output(COutputInterface::AFTER);

      CCopasiMessage(CCopasiMessage::EXCEPTION, MCTSSAMethod + 4);
    }

  catch (CCopasiException & Exception)
    {
      mpTSSAProblem->getModel()->setState(*mpCurrentState);
      mpTSSAProblem->getModel()->updateSimulatedValues(mUpdateMoieties);

      if ((*LE)(outputStartTime, *mpCurrentTime))
        {
          output(COutputInterface::DURING);
        }

      if (mpCallBack) mpCallBack->finishItem(hProcess);

      output(COutputInterface::AFTER);

      throw CCopasiException(Exception.getMessage());
    }

  if (mpCallBack) mpCallBack->finishItem(hProcess);

  output(COutputInterface::AFTER);

  return true;
}

void CTSSATask::processStart(const bool & useInitialValues)
{
  if (useInitialValues)
    mpTSSAProblem->getModel()->applyInitialValues();

  *mpCurrentState = mpTSSAProblem->getModel()->getState();

  mpTSSAMethod->setCurrentState(mpCurrentState);
  mpTSSAMethod->start(mpCurrentState);

  return;
}

bool CTSSATask::processStep(const C_FLOAT64 & nextTime)
{
  C_FLOAT64 CompareTime = nextTime - 100.0 * fabs(nextTime) * std::numeric_limits< C_FLOAT64 >::epsilon();

  if (*mpCurrentTime <= CompareTime)
    {
      do
        {
          mpTSSAMethod->step(nextTime - *mpCurrentTime);

          if (*mpCurrentTime > CompareTime) break;

          /* Here we will do conditional event processing */

          /* Currently this is correct since no events are processed. */
          CCopasiMessage(CCopasiMessage::EXCEPTION, MCTSSAMethod + 3);
        }
      while (true);

      mpTSSAProblem->getModel()->setState(*mpCurrentState);
      mpTSSAProblem->getModel()->updateSimulatedValues(mUpdateMoieties);

      return true;
    }

  CompareTime = nextTime + 100.0 * fabs(nextTime) * std::numeric_limits< C_FLOAT64 >::epsilon();

  if (*mpCurrentTime >= CompareTime)
    {
      do
        {
          mpTSSAMethod->step(nextTime - *mpCurrentTime);

          if (*mpCurrentTime < CompareTime) break;

          /* Here we will do conditional event processing */

          /* Currently this is correct since no events are processed. */
          CCopasiMessage(CCopasiMessage::EXCEPTION, MCTSSAMethod + 3);
        }
      while (true);

      mpTSSAProblem->getModel()->setState(*mpCurrentState);
      mpTSSAProblem->getModel()->updateSimulatedValues(mUpdateMoieties);

      return true;
    }

  // Current time is approximately nextTime;
  return false;
}

bool CTSSATask::restore()
{
  bool success = CCopasiTask::restore();

  if (mUpdateModel)
    {
      CModel * pModel = mpProblem->getModel();

      pModel->setState(*mpCurrentState);
      pModel->updateSimulatedValues(mUpdateMoieties);
      pModel->setInitialState(pModel->getState());
      pModel->updateInitialValues();
    }

  return success;
}

bool CTSSATask::setMethodType(const int & type)
{
  CCopasiMethod::SubType Type = (CCopasiMethod::SubType) type;

  if (!isValidMethod(Type, ValidMethods)) return false;

  if (mpMethod->getSubType() == Type) return true;

  pdelete(mpMethod);
  mpMethod = createMethod(Type);
  this->add(mpMethod, true);
  //mpMethod->setObjectParent(this);

  return true;
}

// virtual
CCopasiMethod * CTSSATask::createMethod(const int & type) const
{
  CCopasiMethod::SubType Type = (CCopasiMethod::SubType) type;

  return CTSSAMethod::createMethod(Type);
}

CState * CTSSATask::getState()
{return mpCurrentState;}

const CTimeSeries & CTSSATask::getTimeSeries() const
{return mTimeSeries;}
<|endoftext|>


<commit_before>/* ===========================
 *
 * Copyright (c) 2013 Philippe Tillet - National Chiao Tung University
 *
 * FMinCL - Unconstrained Function Minimization on OpenCL
 *
 * License : MIT X11 - See the LICENSE file in the root folder
 * ===========================*/

#ifndef FMINCL_DIRECTIONS_QUASI_NEWTON_UPDATE_HPP_
#define FMINCL_DIRECTIONS_QUASI_NEWTON_UPDATE_HPP_

#include "fmincl/mapping.hpp"
#include "fmincl/utils.hpp"

namespace fmincl{

struct qn_update{
    template<class BackendType>
    struct implementation : public implementation_base<BackendType>{
        implementation(detail::optimization_context<BackendType> & context) : implementation_base<BackendType>(context){ }
        virtual void operator()(void) = 0;
    };

    virtual ~qn_update(){ }
};

struct lbfgs : public qn_update{
    lbfgs(unsigned int _m = 4) : m(_m) { }
    unsigned int m;

    template<class BackendType>
    class implementation : public qn_update::implementation<BackendType>{
        using implementation_base<BackendType>::context_;
        using typename implementation_base<BackendType>::ScalarType;
        using typename implementation_base<BackendType>::VectorType;
        using typename implementation_base<BackendType>::MatrixType;

        struct storage_pair{
            VectorType s;
            VectorType y;
        };

        VectorType & s(std::size_t i) { return vecs_[i].s; }
        VectorType & y(std::size_t i) { return vecs_[i].y; }

    public:
        implementation(lbfgs const & tag, detail::optimization_context<BackendType> & context) : qn_update::implementation<BackendType>(context), tag_(tag), vecs_(tag.m){
            N_ = context_.dim();

            q_ = BackendType::create_vector(N_);
            r_ = BackendType::create_vector(N_);

            for(unsigned int i = 0 ; i < tag_.m ; ++i){
                vecs_[i].s = BackendType::create_vector(N_);
                vecs_[i].y = BackendType::create_vector(N_);
            }
        }

        void operator()(){
            //Initizalization of aliases
            VectorType const & x=context_.x();
            VectorType const & xm1=context_.xm1();
            VectorType const & g=context_.g();
            VectorType const & gm1=context_.gm1();
            VectorType & p=context_.p();

            unsigned int const & iter = context_.iter();
            unsigned int const & m = tag_.m;

            std::vector<ScalarType> rhos(m);
            std::vector<ScalarType> alphas(m);

            //Algorithm

            //Updates storage
            for(unsigned int i = std::min(iter,m)-1 ; i > 0  ; --i){
                BackendType::copy(N_,s(i-1), s(i));
                BackendType::copy(N_,y(i-1), y(i));
            }

            //s(0) = x - xm1;
            BackendType::copy(N_,x,s(0));
            BackendType::axpy(N_,-1,xm1,s(0));

            //y(0) = g - gm1;
            BackendType::copy(N_,g,y(0));
            BackendType::axpy(N_,-1,gm1,y(0));

            BackendType::copy(N_,g,q_);
            int i = 0;
            for(; i < (int)std::min(iter,m) ; ++i){
                rhos[i] = static_cast<ScalarType>(1)/BackendType::dot(N_,y(i),s(i));
                alphas[i] = rhos[i]*BackendType::dot(N_,s(i),q_);
                //q_ = q - alphas[i]*y(i);
                BackendType::axpy(N_,-alphas[i],y(i),q_);
            }
            ScalarType scale = BackendType::dot(N_,s(0),y(0))/BackendType::dot(N_,y(0),y(0));

            //r_ = scale*q_;
            BackendType::copy(N_,q_,r_);
            BackendType::scale(N_,scale,r_);

            --i;
            for(; i >=0 ; --i){
                ScalarType beta = rhos[i]*BackendType::dot(N_,y(i),r_);
                //r_ = r_ + (alphas[i]-beta)*s(i)
                BackendType::axpy(N_,alphas[i]-beta,s(i),r_);
            }

            //p = -r_;
            BackendType::copy(N_,r_,p);
            BackendType::scale(N_,-1,p);
        }

        ~implementation(){
            BackendType::delete_if_dynamically_allocated(q_);
            BackendType::delete_if_dynamically_allocated(r_);

            for(unsigned int i = 0 ; i < tag_.m ; ++i){
                BackendType::delete_if_dynamically_allocated(s(i));
                BackendType::delete_if_dynamically_allocated(y(i));
            }
        }

    private:
        lbfgs const & tag_;
        std::size_t N_;
        VectorType q_;
        VectorType r_;
        std::vector<storage_pair> vecs_;
    };
};

struct bfgs : public qn_update{
    template<class BackendType>
    class implementation : public qn_update::implementation<BackendType>{
        using implementation_base<BackendType>::context_;
        using typename implementation_base<BackendType>::ScalarType;
        using typename implementation_base<BackendType>::VectorType;
        using typename implementation_base<BackendType>::MatrixType;
    public:
        implementation(bfgs const &, detail::optimization_context<BackendType> & context) : qn_update::implementation<BackendType>(context), is_first_update_(true){
            N_ = context_.dim();
            Hy_ = BackendType::create_vector(N_);
            s_ = BackendType::create_vector(N_);
            y_ = BackendType::create_vector(N_);
            H_ = BackendType::create_matrix(N_, N_);

            BackendType::set_to_value(Hy_,0,N_);
            BackendType::set_to_value(s_,0,N_);
            BackendType::set_to_value(y_,0,N_);

        }

        void operator()(){
          //s = x - xm1;
          BackendType::copy(N_,context_.x(),s_);
          BackendType::axpy(N_,-1,context_.xm1(),s_);

          //y = g - gm1;
          BackendType::copy(N_,context_.g(),y_);
          BackendType::axpy(N_,-1,context_.gm1(),y_);

          ScalarType ys = BackendType::dot(N_,s_,y_);

          if(is_first_update_)
            BackendType::set_to_diagonal(N_,H_,1);

          ScalarType gamma = 1;

          //Update Scaling
          if(is_first_update_){
              BackendType::symv(N_,1,H_,y_,0,Hy_);
              ScalarType yHy = BackendType::dot(N_,y_,Hy_);
              gamma = ys/yHy;
          }

          BackendType::scale(N_,N_,gamma,H_);
          BackendType::symv(N_,1,H_,y_,0,Hy_);
          ScalarType yHy = BackendType::dot(N_,y_,Hy_);

          //BFGS UPDATE
          //H_ += alpha*(s_*Hy' + Hy*s_') + beta*s_*s_';
          ScalarType alpha = -1/ys;
          ScalarType beta = 1/ys + yHy/pow(ys,2);
          BackendType::syr2(N_,alpha,s_,Hy_,H_);
          BackendType::syr1(N_,beta,s_,H_);

          //p = -H_*g
          BackendType::symv(N_,-1,H_,context_.g(),0,context_.p());

          if(is_first_update_) is_first_update_=false;
        }

        ~implementation(){
            BackendType::delete_if_dynamically_allocated(Hy_);
            BackendType::delete_if_dynamically_allocated(s_);
            BackendType::delete_if_dynamically_allocated(y_);

            BackendType::delete_if_dynamically_allocated(H_);
        }

    private:
        std::size_t N_;

        VectorType Hy_;
        VectorType s_;
        VectorType y_;

        MatrixType H_;

        bool is_first_update_;
    };
};

}

#endif
<commit_msg>Algorithm : BFGS : Implemented scaling based on Oren's switch rule<commit_after>/* ===========================
 *
 * Copyright (c) 2013 Philippe Tillet - National Chiao Tung University
 *
 * FMinCL - Unconstrained Function Minimization on OpenCL
 *
 * License : MIT X11 - See the LICENSE file in the root folder
 * ===========================*/

#ifndef FMINCL_DIRECTIONS_QUASI_NEWTON_UPDATE_HPP_
#define FMINCL_DIRECTIONS_QUASI_NEWTON_UPDATE_HPP_

#include "fmincl/mapping.hpp"
#include "fmincl/utils.hpp"

namespace fmincl{

struct qn_update{
    template<class BackendType>
    struct implementation : public implementation_base<BackendType>{
        implementation(detail::optimization_context<BackendType> & context) : implementation_base<BackendType>(context){ }
        virtual void operator()(void) = 0;
    };

    virtual ~qn_update(){ }
};

struct lbfgs : public qn_update{
    lbfgs(unsigned int _m = 4) : m(_m) { }
    unsigned int m;

    template<class BackendType>
    class implementation : public qn_update::implementation<BackendType>{
        using implementation_base<BackendType>::context_;
        using typename implementation_base<BackendType>::ScalarType;
        using typename implementation_base<BackendType>::VectorType;
        using typename implementation_base<BackendType>::MatrixType;

        struct storage_pair{
            VectorType s;
            VectorType y;
        };

        VectorType & s(std::size_t i) { return vecs_[i].s; }
        VectorType & y(std::size_t i) { return vecs_[i].y; }

    public:
        implementation(lbfgs const & tag, detail::optimization_context<BackendType> & context) : qn_update::implementation<BackendType>(context), tag_(tag), vecs_(tag.m){
            N_ = context_.dim();

            q_ = BackendType::create_vector(N_);
            r_ = BackendType::create_vector(N_);

            for(unsigned int i = 0 ; i < tag_.m ; ++i){
                vecs_[i].s = BackendType::create_vector(N_);
                vecs_[i].y = BackendType::create_vector(N_);
            }
        }

        void operator()(){
            //Initizalization of aliases
            VectorType const & x=context_.x();
            VectorType const & xm1=context_.xm1();
            VectorType const & g=context_.g();
            VectorType const & gm1=context_.gm1();
            VectorType & p=context_.p();

            unsigned int const & iter = context_.iter();
            unsigned int const & m = tag_.m;

            std::vector<ScalarType> rhos(m);
            std::vector<ScalarType> alphas(m);

            //Algorithm

            //Updates storage
            for(unsigned int i = std::min(iter,m)-1 ; i > 0  ; --i){
                BackendType::copy(N_,s(i-1), s(i));
                BackendType::copy(N_,y(i-1), y(i));
            }

            //s(0) = x - xm1;
            BackendType::copy(N_,x,s(0));
            BackendType::axpy(N_,-1,xm1,s(0));

            //y(0) = g - gm1;
            BackendType::copy(N_,g,y(0));
            BackendType::axpy(N_,-1,gm1,y(0));

            BackendType::copy(N_,g,q_);
            int i = 0;
            for(; i < (int)std::min(iter,m) ; ++i){
                rhos[i] = static_cast<ScalarType>(1)/BackendType::dot(N_,y(i),s(i));
                alphas[i] = rhos[i]*BackendType::dot(N_,s(i),q_);
                //q_ = q - alphas[i]*y(i);
                BackendType::axpy(N_,-alphas[i],y(i),q_);
            }
            ScalarType scale = BackendType::dot(N_,s(0),y(0))/BackendType::dot(N_,y(0),y(0));

            //r_ = scale*q_;
            BackendType::copy(N_,q_,r_);
            BackendType::scale(N_,scale,r_);

            --i;
            for(; i >=0 ; --i){
                ScalarType beta = rhos[i]*BackendType::dot(N_,y(i),r_);
                //r_ = r_ + (alphas[i]-beta)*s(i)
                BackendType::axpy(N_,alphas[i]-beta,s(i),r_);
            }

            //p = -r_;
            BackendType::copy(N_,r_,p);
            BackendType::scale(N_,-1,p);
        }

        ~implementation(){
            BackendType::delete_if_dynamically_allocated(q_);
            BackendType::delete_if_dynamically_allocated(r_);

            for(unsigned int i = 0 ; i < tag_.m ; ++i){
                BackendType::delete_if_dynamically_allocated(s(i));
                BackendType::delete_if_dynamically_allocated(y(i));
            }
        }

    private:
        lbfgs const & tag_;
        std::size_t N_;
        VectorType q_;
        VectorType r_;
        std::vector<storage_pair> vecs_;
    };
};

struct bfgs : public qn_update{
    template<class BackendType>
    class implementation : public qn_update::implementation<BackendType>{
        using implementation_base<BackendType>::context_;
        using typename implementation_base<BackendType>::ScalarType;
        using typename implementation_base<BackendType>::VectorType;
        using typename implementation_base<BackendType>::MatrixType;
    public:
        implementation(bfgs const &, detail::optimization_context<BackendType> & context) : qn_update::implementation<BackendType>(context), is_first_update_(true){
            N_ = context_.dim();
            Hy_ = BackendType::create_vector(N_);
            s_ = BackendType::create_vector(N_);
            y_ = BackendType::create_vector(N_);
            H_ = BackendType::create_matrix(N_, N_);

            BackendType::set_to_value(Hy_,0,N_);
            BackendType::set_to_value(s_,0,N_);
            BackendType::set_to_value(y_,0,N_);

        }

        void operator()(){
          //s = x - xm1;
          BackendType::copy(N_,context_.x(),s_);
          BackendType::axpy(N_,-1,context_.xm1(),s_);

          //y = g - gm1;
          BackendType::copy(N_,context_.g(),y_);
          BackendType::axpy(N_,-1,context_.gm1(),y_);

          ScalarType ys = BackendType::dot(N_,s_,y_);

          if(is_first_update_)
            BackendType::set_to_diagonal(N_,H_,1);

          ScalarType gamma = 1;

          //Update Scaling
//          if(is_first_update_){
//              BackendType::symv(N_,1,H_,y_,0,Hy_);
//              ScalarType yHy = BackendType::dot(N_,y_,Hy_);
//              gamma = ys/yHy;
//          }
          {
              BackendType::symv(N_,1,H_,y_,0,Hy_);
              ScalarType yHy = BackendType::dot(N_,y_,Hy_);
              ScalarType sg = BackendType::dot(N_,s_,context_.gm1());
              ScalarType gHy = BackendType::dot(N_,context_.gm1(),Hy_);
              if(ys/yHy>1)
                  gamma = ys/yHy;
              else if(sg/gHy<1)
                  gamma = sg/gHy;
              else
                  gamma = 1;
          }

          BackendType::scale(N_,N_,gamma,H_);
          BackendType::symv(N_,1,H_,y_,0,Hy_);
          ScalarType yHy = BackendType::dot(N_,y_,Hy_);

          //BFGS UPDATE
          //H_ += alpha*(s_*Hy' + Hy*s_') + beta*s_*s_';
          ScalarType alpha = -1/ys;
          ScalarType beta = 1/ys + yHy/pow(ys,2);
          BackendType::syr2(N_,alpha,s_,Hy_,H_);
          BackendType::syr1(N_,beta,s_,H_);

          //p = -H_*g
          BackendType::symv(N_,-1,H_,context_.g(),0,context_.p());

          if(is_first_update_) is_first_update_=false;
        }

        ~implementation(){
            BackendType::delete_if_dynamically_allocated(Hy_);
            BackendType::delete_if_dynamically_allocated(s_);
            BackendType::delete_if_dynamically_allocated(y_);

            BackendType::delete_if_dynamically_allocated(H_);
        }

    private:
        std::size_t N_;

        VectorType Hy_;
        VectorType s_;
        VectorType y_;

        MatrixType H_;

        bool is_first_update_;
    };
};

}

#endif
<|endoftext|>