text:
//
// Created by Anshuman Mishra on 11/25/19.
//

// These statements are saying to include source code that is stored somewhere else (these come with most compilers)
#include <iostream>		// For console i/o
#include <vector>		// For arrays that we don't use for linear algebra
#include <string>		// For strings used in file names
#include <fstream>		// For file i/o
#include <iomanip>		// For setprecision when printing numbers to the console or files

#include <boost/math/special_functions/beta.hpp>
#include <algorithm>
#include <Eigen/Dense>

#include "headers/MathUtils.h"
#include "headers/Policy.h"
#include "headers/Cartpole.h"
#include "headers/Gridworld.hpp"
#include "headers/Walk.h"
#include "headers/FourierBasis.h"
#include "headers/HelperFunctions.hh"

using namespace std;			// Some terms below are "inside" std. For example, cout, cin, and endl. Normally you have to write std::cout. This line makes it so that you don't have to write std:: before everything you are using from standard libraries.
using namespace Eigen;
using namespace boost::math;

void checkpoint(){
  cout << "Checkpoint"; getchar();
}

struct HistoryElement{
  vector<double> state;
  int action;
  double reward;

  HistoryElement (vector<double> s, int a, double r){
    state = s;
    action = a;
    reward = r;
  }
};

double PDIS(const vector<HistoryElement>& history, const Policy piE, const Policy piB, double gamma, const FourierBasis& fb){
//  cout << "Called PDIS for history" << endl;
  double value = 0;
  double gammaCoeff = 1.0;
  double piCoeff = 1.0;
  for (HistoryElement el : history){
//    cout << el.state[0] << el.action << el.reward << endl;
    vector<double> phi_vec = fb.basify(el.state);
    Map<VectorXd> phi = VectorXd::Map(&phi_vec[0], phi_vec.size());
    piCoeff *= (piE.getActionProbability(phi, el.action) / piB.getActionProbability(phi, el.action));
    value += gammaCoeff * piCoeff * el.reward;
//    cout << "Gamma: " << gammaCoeff << " Pi: " << piCoeff << " Value: " << value << endl;
//    getchar();
    gammaCoeff *= gamma;
    if (isnan(value)){
      cout << "PDIS is nan" << endl;
      cout << "piCoeff: " << piCoeff << " gammaCoeff: " << gammaCoeff << " Reward: " << el.reward << endl;
      getchar();
    }
  }
//  cout << "PDIS = " << value << endl;
  return value;
}

VectorXd PDIS(const vector<vector<HistoryElement> >& data, const Policy& piE, const Policy& piB, double gamma, const FourierBasis& fb){
//  cout << "Called PDIS for data" << endl;
  VectorXd pdis(data.size());
  for (int h=0; h<data.size(); h++)
    pdis[h] = PDIS(data[h], piE, piB, gamma, fb);
  return pdis;
}

void splitData(
    const vector<vector<HistoryElement> >& data,
    vector<vector<HistoryElement> >& Dc,
    vector<vector<HistoryElement> >& Ds,
    double ratio){
  int d = data.size();
  int i=0;
  while (i<d*ratio){
    Dc.push_back(data[i++]);
  }
  while (i<data.size()){
    Ds.push_back(data[i++]);
  }
  cout << "Split: " << data.size() << " => " << Dc.size() << "," << Ds.size() << endl;
}

bool candidatePassesTest(const vector<vector<HistoryElement>>& Ds, const Policy piE, const Policy piB, const FourierBasis& fb, const double delta, const double confBound){
  cout << "Testing Candidate" << endl;
  VectorXd j = PDIS(Ds, piE, piB, 1.0, fb); // Get the primary objective
  double ub = ttestLowerBound(j, delta);
  cout << "Target: " << confBound << " UB: " << ub << endl;
  return ub > confBound;
}

// The objective function maximized by getCandidateSolution.
double candidateObjective(
    const VectorXd& theta,                // The solution to evaluate
    const void * params[],                // Other terms that we need to compute the objective value, packed into one object - an array of const pointers to objects of unknown types (unknown to CMA-ES, but known to us here as we packed this object)
    mt19937_64& generator)                // The random number generator to use)
{
//  cout << "Evaluating Candidate" << endl;
  const vector<vector<HistoryElement>>* data = (vector<vector<HistoryElement>>*) params[0];
  Policy* piE = (Policy*) params[1];
  const Policy* piB = (Policy*) params[2];
  const FourierBasis* fb = (FourierBasis*) params[3];
  const int* safetyDataSize = (int*) params[4];
  const double* c = (double*) params[5];
  const double* delta = (double*) params[6];

  piE->setTheta(theta);
//  checkpoint();
  VectorXd j = PDIS(*data, *piE, *piB, 1.0, *fb); // Get the primary objective
  double ub = ttestLowerBound(j, *delta, *safetyDataSize);
  double result;
  cout << " Mean: " << j.mean() << " StdDev: " << stddev(j) << " ttest: " << ub << endl;
  if (ub < *c) {
    cout << "Failed Barrier Function" << endl;
    result = -100;
  }
  else
    result = j.mean();
//  cout << "Result : " << result << endl;
  return result;
}

// Use the provided data to get a solution expected to pass the safety test
VectorXd getCandidateSolution(
    const vector<vector<HistoryElement> >& data,
    const double delta,
    const int safetyDataSize,
    Policy& piE,
    const Policy& piB,
    const FourierBasis& fb,
    const double c,
    mt19937_64 & generator) {
  VectorXd initialSolution = piE.getTheta();
  double initialSigma = 2.0*(initialSolution.dot(initialSolution) + 1.0); // A heuristic to select the width of the search based on the weight magnitudes we expect to see.
  int numIterations = 100;                          // Number of iterations that CMA-ES should run. Larger is better, but takes longer.
  bool minimize = false;                            // We want to maximize the candidate objective.
  // Pack parameters of candidate objective into params. In candidateObjective we need to unpack in the same order.
  const void* params[7];

  params[0] = &data;
  params[1] = &piE;
  params[2] = &piB;
  params[3] = &fb;
  params[4] = &safetyDataSize;
  params[5] = &c;
  params[6] = δ

  cout << "Calling CMAES" << endl;
  // Use CMA-ES to get a solution that approximately maximizes candidateObjective
  return CMAES(initialSolution, initialSigma, numIterations, candidateObjective, params, minimize, generator);
}

double getTarget(const vector<vector<HistoryElement>>& data){
  double gamma = 1.0;
  int numEpisodes = data.size();
  VectorXd returns(data.size());
  for (int e = 0; e<data.size(); e++){
    double episodeReturn = 0.0;
    double gammaCoeff = 1.0;
    for (HistoryElement he : data[e]){
      episodeReturn += gammaCoeff*he.reward;
      gammaCoeff *= gamma;
    }
    returns[e] = episodeReturn;
//    if (data[e].size() > 10 || episodeReturn < -10)
//      checkpoint();
  }
  double avgReturn = returns.mean();
  return (avgReturn > 0 ? 1.1 : 0.9)*avgReturn;
}

template <typename Environment>
double getAverageReturn(Environment& e, Policy& pi, int numEpisodes, int maxEpisodeLength, const FourierBasis& fb){
//  Cartpole e;
  mt19937_64 gen(0);
  double gamma = 1.0;
  VectorXd returns(numEpisodes);

  for (int eps = 0; eps < numEpisodes; eps++){
    double curGamma = 1.0;					// We plot the discounted return - this stores gamma^t, which starts at 1.
    bool inTerminalState = false;			// We will use this flag to determine when we should terminate the loop below. If environment[trial].inTerminalState() is slow to call, this saves us from calling it a couple times. For our MDPs it really doesn't matter that we're doing this more efficiently.
    e.newEpisode(gen);	// Reset the environment, telling it to start a new episode.
    vector<double> state = e.getState(gen);	// Get the initial state.
    double episodeReturn = 0.0;
    for (int t = 0; (t < maxEpisodeLength) && (!inTerminalState); t++) { // Loop over time steps in the episode, stopping when we hit the max episode length or when we enter a terminal state.
      vector<double> phi_vec = fb.basify(state);
      VectorXd phi = VectorXd::Map(&phi_vec[0], phi_vec.size());
      int action = pi.getAction(phi);
      double reward = e.update(action, gen); // Apply the action by updating the environment with the chosen action, and get the resulting reward.

      vector<double> nextState = e.getState(gen); // Get the resulting state of the environment from this transition
      inTerminalState = e.inTerminalState(); // Store whether this is next-state is a terminal state.

      episodeReturn += curGamma*reward;
      state = nextState; // Prepare for the next iteration of the loop with this line and the next.
      curGamma *= gamma;
    }
    returns[eps] = episodeReturn;
  }
  cout << "AvgReturn: " << returns.mean() << endl;
  return returns.mean();
}

template <typename Environment>
void generateData(Environment& e, int numEpisodes, int maxEpisodeLength, int order){
  cout << "Generating Data" << endl;
  // Generate Histories for some policy
  // Write to file
  ofstream out("../../../output/data.csv");
//  Cartpole e;
  int stateDim = e.getStateDim();
//  int order = 3;
  int numActions = e.getNumActions();
  FourierBasis fb;
  fb.init(stateDim, 0, order);
  mt19937_64 gen(0);

  out << stateDim << endl;
//  cout << "StateDim in env " << stateDim << " " << e.getState(gen).size() << endl;
//  checkpoint();
  out << numActions << endl;
  out << order << endl;

  Policy p(numActions, fb.getNumOutputs(), 1234);
//  VectorXd params(numActions*fb.getNumOutputs());
//  params << 0.452687,-0.123691,-0.187805,-0.0419247,-0.3103,0.0169222,-0.440849,0.171773,0.122356,-0.0208773,-0.377911,0.24458,-0.345339,0.221081,0.181478,0.0931315,0.316947,-0.237248,-0.0783118,0.102174,0.197309,0.0129477,0.237053,-0.283958,0.0931003,-0.159108,-0.11468,-0.0336945,-0.312665,0.0494717,-0.437631,0.185128,0.13921,0.124541,0.269549,-0.0445983,-0.311025,0.186034,0.181678,0.065481,0.311506,-0.245937,0.320217,-0.266973,-0.10468,-0.0398326,0.24824,-0.237777,0.0789096,-0.109312,-0.131987,-0.0215236,-0.190011,0.263565,-0.391198,0.144332,0.109239,0.0786274,0.245533,-0.0450382,0.407343,-0.221437,-0.0711912,-0.023617,0.332143,-0.184834,0.315291,-0.193174,-0.122204,-0.08163,-0.262694,0.218761,0.136993,-0.0538062,-0.220642,0.0300469,-0.256064,0.217929,-0.118554,0.118296,0.102564,0.289925,-0.14454,0.0308677,-0.036806,-0.119257,-0.000854144,-0.27288,0.174216,-0.101032,0.0331704,-0.236314,0.194932,-0.219322,0.183163,-0.00102567,0.0264519,0.160525,-0.151711,-0.0274355,0.101995,0.0911902,-0.0420769,0.179202,-0.249171,0.0371926,-0.122774,-0.0147314,-0.0374526,-0.1332,0.0527589,-0.267015,0.200302,-0.0525608,0.117418,0.0845154,-0.0264594,-0.182052,0.195832,0.0153543,0.0274128,0.176015,-0.22169,0.192534,-0.244502,0.0506698,-0.0728419,0.158957,-0.293461,-0.0106893,-0.141654,-0.00546437,0.0100509,-0.113205,0.273374,-0.185785,0.167286,-0.0742353,0.0805248,0.0537695,-0.0490843,0.207685,-0.225989,0.101884,-0.0554201,0.15327,-0.205815,0.138937,-0.206245,0.060542,-0.052369,-0.0965512,0.20772,-0.0393728,-0.0666479,-0.00757391,0.10165,-0.104987,0.26088,0.0429262,0.137972,-0.0754444;
//  p.setTheta(params);
  VectorXd params = p.getTheta();
  for (int i=0; i<params.size(); i++){
    out << params[i] << ",";
  }
  out << endl;

  out << numEpisodes << endl;

  double gamma = 1.0;

  vector<HistoryElement> firstEps;
  for (int eps = 0; eps < numEpisodes; eps++){
    double curGamma = 1.0;					// We plot the discounted return - this stores gamma^t, which starts at 1.
    bool inTerminalState = false;			// We will use this flag to determine when we should terminate the loop below. If environment[trial].inTerminalState() is slow to call, this saves us from calling it a couple times. For our MDPs it really doesn't matter that we're doing this more efficiently.
    e.newEpisode(gen);	// Reset the environment, telling it to start a new episode.
    vector<double> state = e.getState(gen);	// Get the initial state.
    for (int t = 0; (t < maxEpisodeLength) && (!inTerminalState); t++) { // Loop over time steps in the episode, stopping when we hit the max episode length or when we enter a terminal state.
      vector<double> phi_vec = fb.basify(state);
      VectorXd phi = VectorXd::Map(&phi_vec[0], phi_vec.size());
      int action = p.getAction(phi);
      double reward = e.update(action, gen); // Apply the action by updating the environment with the chosen action, and get the resulting reward.

      for (double val : state)
        out << val << ",";
      out << action << ",";
      out << reward;

      if (eps == 0)
        firstEps.push_back(HistoryElement(state, action, reward));

      vector<double> nextState = e.getState(gen); // Get the resulting state of the environment from this transition
      inTerminalState = e.inTerminalState(); // Store whether this is next-state is a terminal state.

      if ((t < maxEpisodeLength-1) && (!inTerminalState))
        out << ",";

      state = nextState; // Prepare for the next iteration of the loop with this line and the next.
      curGamma *= gamma;
    }
    out<<endl;
  }

  for (int t=0; t<firstEps.size(); t++){
    HistoryElement ht = firstEps[t];
    vector<double> phi_vec = fb.basify(ht.state);
    VectorXd phi = VectorXd::Map(&phi_vec[0], phi_vec.size());
    out<< p.getActionProbability(phi, ht.action);
    out << ((t==firstEps.size()-1) ? '\n' : ',');
  }

  cout << "Data Generation Complete" << endl;
}

vector<Policy> HCOPE(
    vector<vector<HistoryElement>>& data,
    const int numPolicies,
    const double delta,
    const double target,
    const Policy& piB,
    const FourierBasis& fb,
    const string outputDir){
  // Split Data into Ds and Dc
  vector<vector<HistoryElement> > Ds, Dc;
  double dataSplitRatio = 0.6;
  splitData(data, Dc, Ds, dataSplitRatio);

//  int numPolicies = 100;

  mt19937_64 generator(123);
  cout << "Target: " << target << endl;
//  Policy piE(numActions, fb.getNumOutputs(), 123);
//  Policy piE (piB, 123);

//  VectorXd theta(numActions*fb.getNumOutputs());
//  theta << 1, 1, 0.01, -0.01;
//  piE.setTheta(theta);
//  VectorXd pdis = PDIS(data, piE, piB, 1.0, fb);
//  cout << "PDIS " << pdis.mean() << endl;
//
//  pdis = PDIS(data, piB, piB, 1.0, fb);
//  cout << "PDIS " << pdis.mean() << endl;
//
//  cout << "Mean Return in Data " << target/1.1 << endl;
//  checkpoint();

  // Loop while more policies need to be found
//  ofstream policyOut("../../../output/result.csv");

  vector<Policy> policies(numPolicies, Policy(piB, 123));
  #pragma omp parallel for
  for (int p=0; p<numPolicies; p++){
//  while(policies.size() < numPolicies){
    bool passedTest = false;
    VectorXd candidate;
    while(!passedTest) {
      //   Select Candidate Policy
      policies[p].setTheta(piB.getTheta());
      candidate = getCandidateSolution(Dc, delta, Ds.size(), policies[p], piB,
                                       fb, target, generator);

      cout << "Generated Candidate" << endl;
      policies[p].setTheta(candidate);

      passedTest = candidatePassesTest(Ds, policies[p], piB, fb, delta, target);
      if (passedTest)
        cout << "****************** CANDIDATE PASSED TEST ******************" << endl;
      else
        cout << "****************** CANDIDATE FAILED TEST ******************" << endl;
    }
    //   Store Candidate Policy if Test Passed
    ofstream policyOut(outputDir + to_string(p) + ".csv");
    for (int i=0; i<candidate.size(); i++){
      policyOut << candidate[i];
      policyOut << (i == candidate.size()-1 ? "\n":",") << flush;
      cout << candidate[i];
      cout << (i == candidate.size()-1 ? "\n":",");
    }
    //checkpoint()
  }
  return policies;
}

void readData(
    string filename,
    int& stateDim,
    int& numActions,
    int& order,
    Policy& piB,
    int& numEpisodes,
    FourierBasis& fb,
    vector<vector<HistoryElement> >& data){
  cout << "Reading Data" << endl;
//  ifstream in("../../../output/data.csv");
//  ifstream in("../../../input/data.csv");
  ifstream in(filename);

  in >> stateDim;
  in >> numActions;
  in >> order;

  fb.init(stateDim, 0, order);

  VectorXd thetaB(numActions*fb.getNumOutputs());
//  cout << "ThetaB " << thetaB.size() << endl;

  cout << "Reading Policy" << endl;
  string s;
  for (int i=0; i<thetaB.size(); i++){
    char delim = (i == thetaB.size()-1 ? '\n': ',');
    getline(in, s, delim);
    thetaB[i] = stod(s);
//    cout << thetaB[i] << delim;
  }
  // Complete reading the line
//  getline(in, s);

  piB = Policy(thetaB, numActions, fb.getNumOutputs(), 123);

  in >> numEpisodes;

  for (int eps = 0; eps < numEpisodes; eps++){
    vector<HistoryElement> episode;
//    cout << "Reading Episode " << eps << endl;
    string ep;
    in >> ep;
//    cout << ep << endl;

    stringstream ss(ep);
    while(ss.good()){
      vector<double> state(stateDim, 0.0);
//      cout << "State: ";
      for (int st = 0; st < stateDim; st++) {
        getline(ss, s, ',');
        state[st] = stod(s);
//        cout << state[st] << ",";
      }
//      cout << " Action: ";

      getline(ss, s, ',');
      int action = stoi(s);
//      cout << action << ", Reward: ";
//      cout << action << ",";

      getline(ss, s, ',');
      double reward = stod(s);
//      cout << reward << ",";
//      cout << endl;
//      cin >> s;
      episode.push_back(HistoryElement(state, action, reward));
    }
//    cout << endl;
    data.push_back(episode);
  }

  cout << "Validating Policy Representation" << endl;
  string valPi;
  in >> valPi;
  stringstream ss(valPi);
  VectorXd expectedPi(data[0].size());
  VectorXd actualPi(data[0].size());
  bool match = true;
  for (int t=0; t<data[0].size(); t++){
    HistoryElement ht = data[0][t];
    vector<double> phi_vec = fb.basify(ht.state);
    VectorXd phi = VectorXd::Map(&phi_vec[0], phi_vec.size());
    actualPi[t] = piB.getActionProbability(phi, ht.action);

    string s;
    getline(ss, s, ',');
//    cout << s << ", ";
    expectedPi[t] = stod(s);

    if (abs(expectedPi[t] - actualPi[t]) > 1e-5)
      match = false;
  }

  if (!match){
    cout << "Policies Dont Match!"  << endl;
    cout << "Expected: " << expectedPi.transpose() << endl;
    cout << "Actual: " << actualPi.transpose() << endl;
    checkpoint();
    return;
  }

  cout << "Data Read Complete" << endl;
}

void run() {

  bool test = true;

  /****************************************************************/

  bool genData = false;
  int genEpisodes = 100000, genMaxEpisodeLength = 15, genOrder = 1;
//  Cartpole genEnv;
  Gridworld genEnv;
//  Walk genEnv;
  if (test && genData)
    generateData(genEnv, genEpisodes, genMaxEpisodeLength, genOrder);

  /*********************** End of Data Prep ***********************/

  int stateDim, numActions, order, numEpisodes;
  Policy piB(0,0,0);
  FourierBasis fb;
  vector<vector<HistoryElement> > data;
  if (test)
    readData("../../../output/data.csv", stateDim, numActions, order, piB, numEpisodes, fb, data);
  else
    readData("../../../input/data.csv", stateDim, numActions, order, piB, numEpisodes, fb, data);

  cout << "stateDim: " << stateDim << endl;
  cout << "numActions: " << numActions << endl;
  cout << "order: " << order << endl;
  cout << "Policy: " << piB.getTheta().transpose() << endl;
  cout << "numEpisodes: " << numEpisodes << endl;

  /*********************** End of Data Read ***********************/

//  VectorXd testTheta(piB.getTheta().size());
//  testTheta << 0.33304397, -1.3536084, -0.391217, -2.93140976, -4.07265164, -2.13137546, -1.94398795, 2.53769193;
//  Policy testPolicy (piB);
//  testPolicy.setTheta(testTheta);
//  double avgReturn = getAverageReturn(genEnv, testPolicy, genEpisodes, genMaxEpisodeLength, fb);
//  return;

  /********************* End of Testing Space *********************/

  int numPolicies = 50;
  double delta = 0.05;
  double target = getTarget(data);
  string outputDir;
  if (test)
    outputDir = "../../../result/" + to_string(delta) + "_";
  else
    outputDir = "../../../final_result/";
  vector<Policy> policies = HCOPE(data, numPolicies, delta, target, piB, fb, outputDir);

  /********************* End of Policy Search *********************/

  if (test) {
      // Validate policies found
      cout << "Validating Result Policies" << endl;
      int worked = 0;
      for (auto policy : policies){
        double avgReturn = getAverageReturn(genEnv, policy, genEpisodes, genMaxEpisodeLength, fb);
        if (avgReturn >= target/1.1)
          worked++;
      }

      cout << "Reality Check! #Policies that worked: " << worked << "/" << policies.size() << endl;
  }
}

int main(int argc, char* argv[])
{
  run();
//  VectorXd a(4);
//  a  << 1.0, 2.0, 3.0, 4.0;
//  cout << a << endl;
//  MatrixXd m = MatrixXd::Map(a.data(), 2,2);
//  cout << m << endl;
//
//  VectorXd b(4);
//  b << 2.0,3.0,4.0,5.0;
//  m = MatrixXd::Map(b.data(), m.rows(), m.cols());
//  cout << m << endl;
  cout << "Done." << endl;
}


text:
/*
 * cb.cpp
 *
 * Author: C. Rathgeb (crathgeb@cosy.sbg.ac.at), P. Wild (pwild@cosy.sbg.ac.at)
 *
 * Generates an iris code from iris texture using the context-based algorithm
 *
 */
#include "version.h"
#include <cstdio>
#include <map>
#include <vector>
#include <string>
#include <cstring>
#include <ctime>
#include <fstream>
#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <cstdlib>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/nonfree/features2d.hpp>
#include <opencv2/nonfree/nonfree.hpp>
#include <opencv2/legacy/legacy.hpp>
#include <boost/regex.hpp>
#include <boost/filesystem.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>

using namespace std;
using namespace cv;

/** no globbing in win32 mode **/
int _CRT_glob = 0;

/** Program modes **/
static const int MODE_MAIN = 1, MODE_HELP = 2;

/*
 * Print command line usage for this program
 */
void printUsage() {
    printVersion();
	printf("+-----------------------------------------------------------------------------+\n");
	printf("| SURF - feature extraction for enhanced iris textures                        |\n");
	printf("|                                                                             |\n");
	printf("|                                                                             |\n");
	printf("| MODES                                                                       |\n");
	printf("|                                                                             |\n");
    printf("| (# 1) SURF feature extraction from iris textures                            |\n");
    printf("| (# 2) usage                                                                 |\n");
    printf("|                                                                             |\n");
    printf("| ARGUMENTS                                                                   |\n");
    printf("|                                                                             |\n");
    printf("+------+------------+---+---+-------------------------------------------------+\n");
    printf("| Name | Parameters | # | ? | Description                                     |\n");
    printf("+------+------------+---+---+-------------------------------------------------+\n");
    printf("| -i   | infile     | 1 | N | input iris texture (use * as wildcard, all other|\n");
    printf("|      |            |   |   | file parameters may refer to n-th * with ?n)    |\n");
    printf("| -o   | outfile    | 1 | N | output iris features                            |\n");
    printf("| -q   |            | 1 | Y | quiet mode on (off)                             |\n");
    printf("| -t   |            | 1 | Y | time progress on (off)                          |\n");
    printf("| -h   |            | 2 | N | prints usage                                    |\n");
    printf("+------+------------+---+---+-------------------------------------------------+\n");
    printf("|                                                                             |\n");
    printf("| EXAMPLE USAGE                                                               |\n");
    printf("|                                                                             |\n");
    printf("| -i s1.tiff -o s1                                                            |\n");
    printf("| -i *.tiff -o ?1 -q -t                                                       |\n");
    printf("|                                                                             |\n");
    printf("| AUTHORS                                                                     |\n");
    printf("|                                                                             |\n");
    printf("| Johannes Wagner (johannes.wagner@cased.de)                                  |\n");
    printf("|                                                                             |\n");
    printf("| COPYRIGHT                                                                   |\n");
    printf("|                                                                             |\n");
    printf("| (C) 2015 All rights reserved. Do not distribute without written permission. |\n");
    printf("+-----------------------------------------------------------------------------+\n");
}

/** ------------------------------- image processing functions ------------------------------- **/

string featureExtract(string iris_image, string outputfilename) {
	initModule_nonfree(); //init nonfree modules

	//build Filename for output .surf
	string filename = iris_image;
	int lastindex = filename.find_last_of(".");
	string rawname = filename.substr(0, lastindex);

	string outputFilename = outputfilename;
	outputFilename.append(".surf");

	Mat image = imread(filename, 1);

        Ptr<FeatureDetector> featureDetector = FeatureDetector::create("SURF");
        //set params:
        //featureDetector->set("hessianThreshold", 0);    // Threshold for hessian keypoint detector used in SURF
        //featureDetector->set("hessianThreshold", 0.04); // Number of pyramid octaves the keypoint detector will use
        //featureDetector->set("nOctaveLayers", 10);      // Number of octave layers within each octave
        //featureDetector->set("extended", 3);            // Extended descriptor flag (true - use extended 128-element descriptors; false - use 64-element descriptors)
        //featureDetector->set("extended", 1.6);          // Up-right or rotated features flag (true - do not compute orientation of features; false - compute orientation)

	vector<KeyPoint> keypoints;

	// Detect the keypoints
	featureDetector->detect(image, keypoints);

	Ptr<DescriptorExtractor> featureExtractor = DescriptorExtractor::create("SURF");

	Mat descriptors;
	featureExtractor->compute(image, keypoints, descriptors);

	//save keypoints, descriptors to file
	FileStorage fs(outputFilename, FileStorage::WRITE);
	//write(fs, "image", image);
	write(fs, "keypoints", keypoints);
	write(fs, "descriptors", descriptors);
	fs.release();
	return outputFilename;
}

/** ------------------------------- commandline functions ------------------------------- **/

/**
 * Parses a command line
 * This routine should be called for parsing command lines for executables.
 * Note, that all options require '-' as prefix and may contain an arbitrary
 * number of optional arguments.
 *
 * cmd: commandline representation
 * argc: number of parameters
 * argv: string array of argument values
 */
void cmdRead(map<string ,vector<string> >& cmd, int argc, char *argv[]){
	for (int i=1; i< argc; i++){
		char * argument = argv[i];
		if (strlen(argument) > 1 && argument[0] == '-' && (argument[1] < '0' || argument[1] > '9')){
			cmd[argument]; // insert
			char * argument2;
			while (i + 1 < argc && (strlen(argument2 = argv[i+1]) <= 1 || argument2[0] != '-'  || (argument2[1] >= '0' && argument2[1] <= '9'))){
				cmd[argument].push_back(argument2);
				i++;
			}
		}
		else {
			CV_Error(CV_StsBadArg,"Invalid command line format");
		}
	}
}

/**
 * Checks, if each command line option is valid, i.e. exists in the options array
 *
 * cmd: commandline representation
 * validOptions: list of valid options separated by pipe (i.e. |) character
 */
void cmdCheckOpts(map<string ,vector<string> >& cmd, const string validOptions){
	vector<string> tokens;
	const string delimiters = "|";
	string::size_type lastPos = validOptions.find_first_not_of(delimiters,0); // skip delimiters at beginning
	string::size_type pos = validOptions.find_first_of(delimiters, lastPos); // find first non-delimiter
	while (string::npos != pos || string::npos != lastPos){
		tokens.push_back(validOptions.substr(lastPos,pos - lastPos)); // add found token to vector
		lastPos = validOptions.find_first_not_of(delimiters,pos); // skip delimiters
		pos = validOptions.find_first_of(delimiters,lastPos); // find next non-delimiter
	}
	sort(tokens.begin(), tokens.end());
	for (map<string, vector<string> >::iterator it = cmd.begin(); it != cmd.end(); it++){
		if (!binary_search(tokens.begin(),tokens.end(),it->first)){
			CV_Error(CV_StsBadArg,"Command line parameter '" + it->first + "' not allowed.");
			tokens.clear();
			return;
		}
	}
	tokens.clear();
}

/*
 * Checks, if a specific required option exists in the command line
 *
 * cmd: commandline representation
 * option: option name
 */
void cmdCheckOptExists(map<string ,vector<string> >& cmd, const string option){
	map<string, vector<string> >::iterator it = cmd.find(option);
	if (it == cmd.end()) CV_Error(CV_StsBadArg,"Command line parameter '" + option + "' is required, but does not exist.");
}

/*
 * Checks, if a specific option has the appropriate number of parameters
 *
 * cmd: commandline representation
 * option: option name
 * size: appropriate number of parameters for the option
 */
void cmdCheckOptSize(map<string ,vector<string> >& cmd, const string option, const unsigned int size = 1){
	map<string, vector<string> >::iterator it = cmd.find(option);
	if (it->second.size() != size) CV_Error(CV_StsBadArg,"Command line parameter '" + option + "' has unexpected size.");
}

/*
 * Checks, if a specific option has the appropriate number of parameters
 *
 * cmd: commandline representation
 * option: option name
 * min: minimum appropriate number of parameters for the option
 * max: maximum appropriate number of parameters for the option
 */
void cmdCheckOptRange(map<string ,vector<string> >& cmd, string option, unsigned int min = 0, unsigned int max = 1){
	map<string, vector<string> >::iterator it = cmd.find(option);
	unsigned int size = it->second.size();
	if (size < min || size > max) CV_Error(CV_StsBadArg,"Command line parameter '" + option + "' is out of range.");
}

/*
 * Returns the list of parameters for a given option
 *
 * cmd: commandline representation
 * option: name of the option
 */
vector<string> * cmdGetOpt(map<string ,vector<string> >& cmd, const string option){
	map<string, vector<string> >::iterator it = cmd.find(option);
	return (it != cmd.end()) ? &(it->second) : 0;
}

/*
 * Returns number of parameters in an option
 *
 * cmd: commandline representation
 * option: name of the option
 */
unsigned int cmdSizePars(map<string ,vector<string> >& cmd, const string option){
	map<string, vector<string> >::iterator it = cmd.find(option);
	return (it != cmd.end()) ? it->second.size() : 0;
}

/*
 * Returns a specific parameter type (int) given an option and parameter index
 *
 * cmd: commandline representation
 * option: name of option
 * param: name of parameter
 */
int cmdGetParInt(map<string ,vector<string> >& cmd, string option, unsigned int param = 0){
	map<string, vector<string> >::iterator it = cmd.find(option);
	if (it != cmd.end()) {
		if (param < it->second.size()) {
			return atoi(it->second[param].c_str());
		}
	}
	return 0;
}

/*
 * Returns a specific parameter type (float) given an option and parameter index
 *
 * cmd: commandline representation
 * option: name of option
 * param: name of parameter
 */
float cmdGetParFloat(map<string ,vector<string> >& cmd, const string option, const unsigned int param = 0){
	map<string, vector<string> >::iterator it = cmd.find(option);
	if (it != cmd.end()) {
		if (param < it->second.size()) {
			return atof(it->second[param].c_str());
		}
	}
	return 0;
}

/*
 * Returns a specific parameter type (string) given an option and parameter index
 *
 * cmd: commandline representation
 * option: name of option
 * param: name of parameter
 */
string cmdGetPar(map<string ,vector<string> >& cmd, const string option, const unsigned int param = 0){
	map<string, vector<string> >::iterator it = cmd.find(option);
	if (it != cmd.end()) {
		if (param < it->second.size()) {
			return it->second[param];
		}
	}
	return 0;
}

/** ------------------------------- timing functions ------------------------------- **/

/**
 * Class for handling timing progress information
 */
class Timing{
public:
	/** integer indicating progress with respect tot total **/
	int progress;
	/** total count for progress **/
	int total;

	/*
	 * Default constructor for timing initializing time.
	 * Automatically calls init()
	 *
	 * seconds: update interval in seconds
	 * eraseMode: if true, outputs sends erase characters at each print command
	 */
	Timing(long seconds, bool eraseMode){
		updateInterval = seconds;
		progress = 1;
		total = 100;
		eraseCount=0;
		erase = eraseMode;
		init();
	}

	/*
	 * Destructor
	 */
	~Timing(){}

	/*
	 * Initializes timing variables
	 */
	void init(void){
		start = boost::posix_time::microsec_clock::universal_time();
		lastPrint = start - boost::posix_time::seconds(updateInterval);
	}

	/*
	 * Clears printing (for erase option only)
	 */
	void clear(void){
		string erase(eraseCount,'\r');
		erase.append(eraseCount,' ');
		erase.append(eraseCount,'\r');
		printf("%s",erase.c_str());
		eraseCount = 0;
	}

	/*
	 * Updates current time and returns true, if output should be printed
	 */
	bool update(void){
		current = boost::posix_time::microsec_clock::universal_time();
		return ((current - lastPrint > boost::posix_time::seconds(updateInterval)) || (progress == total));
	}

	/*
	 * Prints timing object to STDOUT
	 */
	void print(void){
		lastPrint = current;
		float percent = 100.f * progress / total;
		boost::posix_time::time_duration passed = (current - start);
		boost::posix_time::time_duration togo = passed * (total - progress) / max(1,progress);
		if (erase) {
			string erase(eraseCount,'\r');
			printf("%s",erase.c_str());
			int newEraseCount = (progress != total) ? printf("Progress ... %3.2f%% (%i/%i Total %i:%02i:%02i.%03i Remaining ca. %i:%02i:%02i.%03i)",percent,progress,total,passed.hours(),passed.minutes(),passed.seconds(),(int)(passed.total_milliseconds()%1000),togo.hours(),togo.minutes(),togo.seconds(),(int)(togo.total_milliseconds() % 1000)) : printf("Progress ... %3.2f%% (%i/%i Total %i:%02i:%02i.%03d)",percent,progress,total,passed.hours(),passed.minutes(),passed.seconds(),(int)(passed.total_milliseconds()%1000));
			if (newEraseCount < eraseCount) {
				string erase(newEraseCount-eraseCount,' ');
				erase.append(newEraseCount-eraseCount,'\r');
				printf("%s",erase.c_str());
			}
			eraseCount = newEraseCount;
		}
		else {
			eraseCount = (progress != total) ? printf("Progress ... %3.2f%% (%i/%i Total %i:%02i:%02i.%03i Remaining ca. %i:%02i:%02i.%03i)\n",percent,progress,total,passed.hours(),passed.minutes(),passed.seconds(),(int)(passed.total_milliseconds()%1000),togo.hours(),togo.minutes(),togo.seconds(),(int)(togo.total_milliseconds() % 1000)) : printf("Progress ... %3.2f%% (%i/%i Total %i:%02i:%02i.%03d)\n",percent,progress,total,passed.hours(),passed.minutes(),passed.seconds(),(int)(passed.total_milliseconds()%1000));
		}
	}
private:
	long updateInterval;
	boost::posix_time::ptime start;
	boost::posix_time::ptime current;
	boost::posix_time::ptime lastPrint;
	int eraseCount;
	bool erase;
};

/** ------------------------------- file pattern matching functions ------------------------------- **/

/*
 * Formats a given string, such that it can be used as a regular expression
 * I.e. escapes special characters and uses * and ? as wildcards
 *
 * pattern: regular expression path pattern
 * pos: substring starting index
 * n: substring size
 *
 * returning: escaped substring
 */
string patternSubstrRegex(string& pattern, size_t pos, size_t n){
	string result;
	for (size_t i=pos, e=pos+n; i < e; i++ ) {
		char c = pattern[i];
		if ( c == '\\' || c == '.' || c == '+' || c == '[' || c == '{' || c == '|' || c == '(' || c == ')' || c == '^' || c == '$' || c == '}' || c == ']') {
			result.append(1,'\\');
			result.append(1,c);
		}
		else if (c == '*'){
			result.append("([^/\\\\]*)");
		}
		else if (c == '?'){
			result.append("([^/\\\\])");
		}
		else {
			result.append(1,c);
		}
	}
	return result;
}

/*
 * Converts a regular expression path pattern into a list of files matching with this pattern by replacing wildcards
 * starting in position pos assuming that all prior wildcards have been resolved yielding intermediate directory path.
 * I.e. this function appends the files in the specified path according to yet unresolved pattern by recursive calling.
 *
 * pattern: regular expression path pattern
 * files: the list to which new files can be applied
 * pos: an index such that positions 0...pos-1 of pattern are already considered/matched yielding path
 * path: the current directory (or empty)
 */
void patternToFiles(string& pattern, vector<string>& files, const size_t& pos, const string& path){
	size_t first_unknown = pattern.find_first_of("*?",pos); // find unknown * in pattern
	if (first_unknown != string::npos){
		size_t last_dirpath = pattern.find_last_of("/\\",first_unknown);
		size_t next_dirpath = pattern.find_first_of("/\\",first_unknown);
		if (next_dirpath != string::npos){
			boost::regex expr((last_dirpath != string::npos && last_dirpath > pos) ? patternSubstrRegex(pattern,last_dirpath+1,next_dirpath-last_dirpath-1) : patternSubstrRegex(pattern,pos,next_dirpath-pos));
			boost::filesystem::directory_iterator end_itr; // default construction yields past-the-end
			try {
				for ( boost::filesystem::directory_iterator itr( ((path.length() > 0) ? path + pattern[pos-1] : (last_dirpath != string::npos && last_dirpath > pos) ? "" : "./") + ((last_dirpath != string::npos && last_dirpath > pos) ? pattern.substr(pos,last_dirpath-pos) : "")); itr != end_itr; ++itr )
				{
					if (boost::filesystem::is_directory(itr->path())){
						boost::filesystem::path p = itr->path().filename();
						string s =  p.string();
						if (boost::regex_match(s.c_str(), expr)){
							patternToFiles(pattern,files,(int)(next_dirpath+1),((path.length() > 0) ? path + pattern[pos-1] : "") + ((last_dirpath != string::npos && last_dirpath > pos) ? pattern.substr(pos,last_dirpath-pos) + pattern[last_dirpath] : "") + s);
						}
					}
				}
			}
			catch (boost::filesystem::filesystem_error &e){}
		}
		else {
			boost::regex expr((last_dirpath != string::npos && last_dirpath > pos) ? patternSubstrRegex(pattern,last_dirpath+1,pattern.length()-last_dirpath-1) : patternSubstrRegex(pattern,pos,pattern.length()-pos));
			boost::filesystem::directory_iterator end_itr; // default construction yields past-the-end
			try {
				for ( boost::filesystem::directory_iterator itr(((path.length() > 0) ? path +  pattern[pos-1] : (last_dirpath != string::npos && last_dirpath > pos) ? "" : "./") + ((last_dirpath != string::npos && last_dirpath > pos) ? pattern.substr(pos,last_dirpath-pos) : "")); itr != end_itr; ++itr )
				{
					boost::filesystem::path p = itr->path().filename();
					string s =  p.string();
					if (boost::regex_match(s.c_str(), expr)){
						files.push_back(((path.length() > 0) ? path + pattern[pos-1] : "") + ((last_dirpath != string::npos && last_dirpath > pos) ? pattern.substr(pos,last_dirpath-pos) + pattern[last_dirpath] : "") + s);
					}
				}
			}
			catch (boost::filesystem::filesystem_error &e){}
		}
	}
	else { // no unknown symbols
		boost::filesystem::path file(((path.length() > 0) ? path + "/" : "") + pattern.substr(pos,pattern.length()-pos));
		if (boost::filesystem::exists(file)){
			files.push_back(file.string());
		}
	}
}

/**
 * Converts a regular expression path pattern into a list of files matching with this pattern
 *
 * pattern: regular expression path pattern
 * files: the list to which new files can be applied
 */
void patternToFiles(string& pattern, vector<string>& files){
	patternToFiles(pattern,files,0,"");
}

/*
 * Renames a given filename corresponding to the actual file pattern using a renaming pattern.
 * Wildcards can be referred to as ?1, ?2, ... in the order they appeared in the file pattern.
 *
 * pattern: regular expression path pattern
 * renamePattern: renaming pattern using ?1, ?2, ... as placeholders for wildcards
 * infile: path of the file (matching with pattern) to be renamed
 * outfile: path of the renamed file
 * par: used parameter (default: '?')
 */
void patternFileRename(string& pattern, const string& renamePattern, const string& infile, string& outfile, const char par = '?'){
	size_t first_unknown = renamePattern.find_first_of(par,0); // find unknown ? in renamePattern
	if (first_unknown != string::npos){
		string formatOut = "";
		for (size_t i=0, e=renamePattern.length(); i < e; i++ ) {
			char c = renamePattern[i];
			if ( c == par && i+1 < e) {
				c = renamePattern[i+1];
				if (c > '0' && c <= '9'){
					formatOut.append(1,'$');
					formatOut.append(1,c);
				}
				else {
					formatOut.append(1,par);
					formatOut.append(1,c);
				}
				i++;
			}
			else {
				formatOut.append(1,c);
			}
		}
		boost::regex patternOut(patternSubstrRegex(pattern,0,pattern.length()));
		outfile = boost::regex_replace(infile,patternOut,formatOut,boost::match_default | boost::format_perl);
	} else {
		outfile = renamePattern;
	}
}

/** ------------------------------- Program ------------------------------- **/

/*
 * Main program
 */
int main(int argc, char *argv[])
{
	int mode = MODE_HELP;
	map<string,vector<string> > cmd;
	try {
		cmdRead(cmd,argc,argv);
    	if (cmd.size() == 0 || cmdGetOpt(cmd,"-h") != 0) mode = MODE_HELP;
    	else mode = MODE_MAIN;
    	if (mode == MODE_MAIN){
			// validate command line
			cmdCheckOpts(cmd,"-i|-o|-q|-t");
			cmdCheckOptExists(cmd,"-i");
			cmdCheckOptSize(cmd,"-i",1);
			string inFiles = cmdGetPar(cmd,"-i");
			cmdCheckOptExists(cmd,"-o");
			cmdCheckOptSize(cmd,"-o",1);
			string outFiles = cmdGetPar(cmd,"-o");
			string imaskFiles, omaskFiles;
			bool quiet = false;
			if (cmdGetOpt(cmd,"-q") != 0){
				cmdCheckOptSize(cmd,"-q",0);
				quiet = true;
			}
			bool time = false;
			if (cmdGetOpt(cmd,"-t") != 0){
				cmdCheckOptSize(cmd,"-t",0);
				time = true;
			}
			// starting routine
			Timing timing(1,quiet);
			vector<string> files;
			string outfile;
			patternToFiles(inFiles,files);
			CV_Assert(files.size() > 0);
			timing.total = files.size();
			for (vector<string>::iterator inFile = files.begin(); inFile != files.end(); ++inFile, timing.progress++){
				if (!quiet) printf("Feature extract on texture '%s' ...\n", (*inFile).c_str());;
				patternFileRename(inFiles,outFiles,*inFile,outfile);
				featureExtract((*inFile).c_str(), outfile);
				patternFileRename(inFiles,outFiles,*inFile,outfile);

				if (!quiet) printf("Storing SURF Features to '%s' ...\n", outfile.append(".surf").c_str());
				if (time && timing.update()) timing.print();
			}
			if (time && quiet) timing.clear();
    	}
    	else if (mode == MODE_HELP){
			// validate command line
			cmdCheckOpts(cmd,"-h");
			if (cmdGetOpt(cmd,"-h") != 0) cmdCheckOptSize(cmd,"-h",0);
			// starting routine
			printUsage();
    	}
    }
	catch (...){
	   	printf("Exit with errors.\n");
	   	exit(EXIT_FAILURE);
	}
    return EXIT_SUCCESS;
}

ext: cpp


text:
// This file is part of snark, a generic and flexible library for robotics research
// Copyright (c) 2011 The University of Sydney
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
// 3. Neither the name of the University of Sydney nor the
//    names of its contributors may be used to endorse or promote products
//    derived from this software without specific prior written permission.
//
// NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
// GRANTED BY THIS LICENSE.  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
// HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <boost/date_time/posix_time/posix_time.hpp>
#include <comma/application/command_line_options.h>
#include <comma/csv/stream.h>
#include <comma/string/string.h>
#include <comma/csv/traits.h>
#include <comma/application/signal_flag.h>
#include "base.h"
#include "mode.h"

static const char* name() { return "ur-arm-status"; }

void usage( bool verbose )
{
    std::cerr << std::endl;
    std::cerr << "take arm status feed on stdin, output csv data to stdout" << std::endl;
    std::cerr << std::endl;
    std::cerr << "options:" << std::endl;
    std::cerr << "    --help,-h: show this message" << std::endl;
    std::cerr << "    --verbose,-v: show more info (mode names, etc)" << std::endl;
    std::cerr << "    --binary,-b: output binary equivalent of csv" << std::endl;
    std::cerr << "    --format: output binary format for given fields to stdout and exit" << std::endl;
    std::cerr << "    --output-fields: output field names and exit" << std::endl;
    std::cerr << "    --packet-size: output packet size and exit" << std::endl;
    std::cerr << "    --mode-from-name=<name>: output the integer corresponding to the given mode name and exit" << std::endl;
    std::cerr << "    --joint-mode-from-name=<name>: same as above for joint modes" << std::endl;
    std::cerr << "    --mode-to-name=<mode>: output the name of the given mode integer and exit" << std::endl;
    std::cerr << "    --joint-mode-to-name=<mode>: same as above for joint modes" << std::endl;
    std::cerr << std::endl;
    std::cerr << "example (assuming status daemon publishes arm status on port 14000): " << std::endl;
    std::cerr << "    nc localhost 14000 | " << name() << " --fields=t,mode,arm/modes" << std::endl;
    std::cerr << std::endl;
    if( verbose )
    {
        std::cerr << "modes: " << std::endl;
        for( snark::ur::modes_t::const_iterator it = snark::ur::modes.begin(); it != snark::ur::modes.end(); ++it ) { std::cerr << "    " << it->left << ": " << it->right << std::endl; }
        std::cerr << std::endl;
        std::cerr << "joint modes: " << std::endl;
        for( snark::ur::modes_t::const_iterator it = snark::ur::joint_modes.begin(); it != snark::ur::joint_modes.end(); ++it ) { std::cerr << "    " << it->left << ": " << it->right << std::endl; }
        std::cerr << std::endl;
    }
    exit ( -1 );
}

struct status_t
{
    boost::posix_time::ptime t;
    snark::ur::arm_t arm;
    snark::ur::tool_t tool;
    int mode;
    double time_since_boot;

    void set( const snark::ur::body_t& body )
    {
        t = boost::posix_time::microsec_clock::universal_time();
        body.export_to( arm );
        body.export_to( tool );
        mode = static_cast< int >( body.mode() );
        time_since_boot = body.time_since_boot();
    }
};

namespace comma { namespace visiting {

template <> struct traits< status_t >
{
    template< typename K, typename V > static void visit( const K& k, const status_t& t, V& v )
    {
        v.apply( "t", t.t );
        v.apply( "arm", t.arm );
        v.apply( "tool", t.tool );
        v.apply( "mode",  t.mode );
        v.apply( "time_since_boot", t.time_since_boot );
    }
};

} } // namespace comma { namespace visiting {

int main( int ac, char** av )
{
    try
    {
        comma::command_line_options options( ac, av, usage );
        if( options.exists( "--output-fields" ) ) { std::cout << comma::join( comma::csv::names< status_t >(), ',' ) << std::endl; return 0; }
        comma::csv::options csv;
        csv.full_xpath = true;
        csv.fields = options.value< std::string >( "--fields", "" );
        if( options.exists( "--format" ) ) { std::cout << comma::csv::format::value< status_t >( csv.fields, true ) << std::endl; return 0; }
        if( options.exists( "--binary,-b" ) ) { csv.format( comma::csv::format::value< status_t >( csv.fields, true ) ); }
        const unsigned int expected_packet_size = snark::ur::header_t::size + snark::ur::body_t::size;
        if( options.exists( "--packet-size" ) ) { std::cout << expected_packet_size << std::endl; return 0; }
        if( options.exists( "--mode-from-name" ) ) { std::cout << snark::ur::mode_from_name( options.value< std::string >( "--mode-from-name" ) ) << std::endl; return 0; }
        if( options.exists( "--joint-mode-from-name" ) ) { std::cout << snark::ur::joint_mode_from_name( options.value< std::string >( "--joint-mode-from-name" ) ) << std::endl; return 0; }
        if( options.exists( "--mode-to-name" ) ) { std::cout << snark::ur::mode_to_name( options.value< int >( "--mode-to-name" ) ) << std::endl; return 0; }
        if( options.exists( "--joint-mode-to-name" ) ) { std::cout << snark::ur::joint_mode_to_name( options.value< int >( "--joint-mode-to-name" ) ) << std::endl; return 0; }
        static comma::csv::output_stream< status_t > ostream( std::cout, csv );
        snark::ur::header_t header;
        snark::ur::body_t body;
        status_t status;
        comma::signal_flag is_shutdown;
        char incomplete_body[expected_packet_size];
        while( !is_shutdown && std::cin.good() && !std::cin.eof() )
        {
            std::cin.read( header.data(), snark::ur::header_t::size );
            if( std::cin.gcount() == 0 ) { break; }
            if( std::cin.gcount() < snark::ur::header_t::size ) { std::cerr << name() << ": received corrupted header of size " << std::cin.gcount() << " (expected " << snark::ur::header_t::size << ")" <<std::endl; return 1; }
            unsigned int size = header.length();
            if( size > expected_packet_size ) { std::cerr << name() << ": cannot process a packet of size " << size << " (expected " << expected_packet_size << ")" << std::endl; return 1; }
            if( size < expected_packet_size )
            {
                std::cerr << name() << ": skipping an unknown packet of size " << size << " (expected " << expected_packet_size << ")" << std::endl;
                std::cin.read( incomplete_body, size );
                continue;
            }
            std::cin.read( body.data(), snark::ur::body_t::size );
            if( std::cin.gcount() == 0 ) { break; }
            if( std::cin.gcount() < snark::ur::body_t::size ) { std::cerr << name() << ": received body of size " << std::cin.gcount() << " (expected " << snark::ur::body_t::size << ")" << std::endl; return 1; }
            status.set( body );
            ostream.write( status );
        }
    }
    catch( std::exception& ex ) { std::cerr << name() << ": " << ex.what() << std::endl; return 1; }
    catch(...) { std::cerr << name() << ": unknown exception" << std::endl; return 1; }
}

max_stars_repo_name: mission-systems-pty-ltd/snark

max_issues_repo_name: NEU-LC/snark

max_forks_repo_name: NEU-LC/snark


text:
/*
 * Copyright 2009-2020 The VOTCA Development Team (http://www.votca.org)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 *
 *     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.
 *
 */
#define BOOST_TEST_MAIN

#define BOOST_TEST_MODULE adiis_test

// Standard includes
#include <iostream>

// Third party includes
#include <boost/test/unit_test.hpp>

// Local VOTCA includes
#include "votca/xtp/adiis.h"
#include <votca/tools/eigenio_matrixmarket.h>

using namespace votca::xtp;

BOOST_AUTO_TEST_SUITE(adiis_test)

BOOST_AUTO_TEST_CASE(coeffs_test) {
  std::vector<Eigen::MatrixXd> dmatHist_;
  std::vector<Eigen::MatrixXd> mathist_;

  ADIIS adiis;

  for (votca::Index i = 0; i < 3; i++) {
    dmatHist_.push_back(votca::tools::EigenIO_MatrixMarket::ReadMatrix(
        std::string(XTP_TEST_DATA_FOLDER) + "/adiis/dmatHist_" +
        std::to_string(i) + ".mm"));
    mathist_.push_back(votca::tools::EigenIO_MatrixMarket::ReadMatrix(
        std::string(XTP_TEST_DATA_FOLDER) + "/adiis/mathist_" +
        std::to_string(i) + ".mm"));
  }

  Eigen::VectorXd Coeffs = adiis.CalcCoeff(dmatHist_, mathist_);

  Eigen::VectorXd Ref = Eigen::VectorXd::Zero(3);
  Ref << 4.45639501e-17, 1.76102089e-18, 1;

  bool check_adiis = Coeffs.isApprox(Ref, 0.00001);
  if (!check_adiis) {
    std::cout << "Ref:" << Ref << std::endl;
    std::cout << "Coeffs:" << Coeffs << std::endl;
  }

  BOOST_CHECK_EQUAL(check_adiis, 1);
}

BOOST_AUTO_TEST_SUITE_END()

ext: cc

max_stars_repo_name: rubengerritsen/xtp

max_issues_repo_name: rubengerritsen/xtp

max_forks_repo_name: rubengerritsen/xtp


text:
//==================================================================================================
/*!
  @file

  @copyright 2016 NumScale SAS

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
//==================================================================================================
#ifndef BOOST_SIMD_FUNCTION_EXPONENTBITS_HPP_INCLUDED
#define BOOST_SIMD_FUNCTION_EXPONENTBITS_HPP_INCLUDED

#if defined(DOXYGEN_ONLY)
namespace boost { namespace simd
{

 /*!

    @ingroup group-ieee
    Function object implementing exponentbits capabilities

    Returns the exponent bits of the floating input as an integer value,
    the other bits (sign and mantissa) being just masked.

    This function is not defined on integral types.

    @par Semantic:

    @code
    as_integer_t<T> r = exponentbits(x);
    @endcode

  **/
  as_integer_t<Value> exponentbits(Value const & v0);
} }
#endif

#include <boost/simd/function/scalar/exponentbits.hpp>
#include <boost/simd/function/simd/exponentbits.hpp>

#endif

ext: hpp

max_stars_repo_name: xmar/pythran

max_issues_repo_name: xmar/pythran

max_forks_repo_name: xmar/pythran


text:
// Copyright (C) 2015 The Regents of the University of California (Regents).
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//
//     * Neither the name of The Regents or University of California nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Please contact the author of this library if you have any questions.
// Author: Chris Sweeney (cmsweeney@cs.ucsb.edu)

#include "theia/sfm/estimators/estimate_similarity_transformation_2d_3d.h"

#include <Eigen/Core>
#include <Eigen/Geometry>

#include <limits>
#include <memory>
#include <vector>

#include "theia/sfm/camera/camera.h"
#include "theia/sfm/create_and_initialize_ransac_variant.h"
#include "theia/sfm/feature.h"
#include "theia/sfm/similarity_transformation.h"
#include "theia/sfm/transformation/gdls_similarity_transform.h"
#include "theia/solvers/estimator.h"
#include "theia/solvers/sample_consensus_estimator.h"
#include "theia/util/util.h"

namespace theia {
namespace {

inline void TransformCamera(const SimilarityTransformation& sim_transform,
                            Camera* camera) {
  const Eigen::Vector3d old_position = camera->GetPosition();
  const Eigen::Vector3d new_position =
      sim_transform.scale * sim_transform.rotation *
      old_position + sim_transform.translation;
  camera->SetPosition(new_position);

  const Eigen::Matrix3d old_orientation =
      camera->GetOrientationAsRotationMatrix();
  const Eigen::Matrix3d new_orientation =
      old_orientation * sim_transform.rotation.transpose();
  camera->SetOrientationFromRotationMatrix(new_orientation);
}

// An estimator for computing the similarity transformation from 4 2D-3D
// correspondences using the gDLS algorithm to minimize reprojection error.
class GdlsSimilarityTransformationEstimator
    : public Estimator<CameraAndFeatureCorrespondence2D3D,
                       SimilarityTransformation> {
 public:
  GdlsSimilarityTransformationEstimator() {}

  // 3 correspondences are needed to determine the absolute pose.
  double SampleSize() const { return 4; }

  // Estimates candidate absolute poses from correspondences.
  bool EstimateModel(
      const std::vector<CameraAndFeatureCorrespondence2D3D>& correspondences,
      std::vector<SimilarityTransformation>* similarity_transformations) const {
    std::vector<Eigen::Vector3d> ray_origins(4), ray_directions(4),
        world_points(4);
    for (int i = 0; i < 4; i++) {
      ray_origins[i] = correspondences[i].camera.GetPosition();
      ray_directions[i] = correspondences[i].camera.PixelToUnitDepthRay(
          correspondences[i].observation).normalized();
      world_points[i] = correspondences[i].point3d.hnormalized();
    }

    // Compute the similarity transformation. Note that this function computes
    // R, t, and s such that:
    //
    //   s * c_i + alpha_i * x_i = R * X_i + t
    //
    // where c_i is the camera position, alpha_i is the depth of the feature,
    // x_i is the unit-norm feature observation, and X_i is the 3D point.
    std::vector<Eigen::Quaterniond> rotations;
    std::vector<Eigen::Vector3d> translations;
    std::vector<double> scales;
    GdlsSimilarityTransform(ray_origins,
                            ray_directions,
                            world_points,
                            &rotations,
                            &translations,
                            &scales);

    // Aggregate the solutions, modifying the output so that R, t, s are of the
    // more useful form of:
    //
    //   s * R * (c_i + alpha_i * x_i) + t = X_i
    //
    // which transforms only the camera coordinate system so that it is aligned
    // with the 3D points.
    for (int i = 0; i < rotations.size(); i++) {
      SimilarityTransformation similarity_transformation;
      similarity_transformation.rotation =
          rotations[i].toRotationMatrix().transpose();
      similarity_transformation.translation =
          similarity_transformation.rotation * -translations[i];
      similarity_transformation.scale = scales[i];
      similarity_transformations->emplace_back(similarity_transformation);
    }
    return similarity_transformations->size() > 0;
  }

  // The error for a correspondences given an absolute pose. This is the squared
  // reprojection error.
  double Error(
      const CameraAndFeatureCorrespondence2D3D& correspondence,
      const SimilarityTransformation& similarity_transformation) const {
    // Apply the similarity transformation to the camera.
    Camera transformed_camera = correspondence.camera;
    TransformCamera(similarity_transformation, &transformed_camera);

    Eigen::Vector2d reprojection;
    // If the point is reprojected behind the camera, return the maximum
    // possible error.
    if (transformed_camera.ProjectPoint(correspondence.point3d, &reprojection) <
        0) {
      return std::numeric_limits<double>::max();
    }

    // Return the squared reprojection error.
    return (correspondence.observation - reprojection).squaredNorm();
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(GdlsSimilarityTransformationEstimator);
};

}  // namespace

bool EstimateSimilarityTransformation2D3D(
    const RansacParameters& ransac_params,
    const RansacType& ransac_type,
    const std::vector<CameraAndFeatureCorrespondence2D3D>& correspondences,
    SimilarityTransformation* similarity_transformation,
    RansacSummary* ransac_summary) {
  GdlsSimilarityTransformationEstimator similarity_transformation_estimator;
  std::unique_ptr <
      SampleConsensusEstimator<GdlsSimilarityTransformationEstimator> > ransac =
      CreateAndInitializeRansacVariant(ransac_type,
                                       ransac_params,
                                       similarity_transformation_estimator);
  // Estimate the absolute pose.
  return ransac->Estimate(correspondences,
                          similarity_transformation,
                          ransac_summary);
}

}  // namespace theia


text:
/*!
	\file MemoryTraceAnalayzer.cpp

	\author Andrew Kerr <arkerr@gatech.edu>

	\brief Implementation of an analysis tool for memory traces
*/

#ifndef MEMORY_TRACE_ANALYZER_CPP_INCLUDED
#define MEMORY_TRACE_ANALYZER_CPP_INCLUDED

#include <ocelot/ir/interface/PTXInstruction.h>
#include <traces/interface/MemoryTraceAnalyzer.h>
#include <hydrazine/interface/ArgumentParser.h>
#include <hydrazine/interface/Exception.h>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/string.hpp>
#include <fstream>
#include <cfloat>
#include <unordered_map>

namespace trace {

	/*!
		Gets a list of all applications and their kernels in the order in which the kernels are called.

		If filter is true, only those applications in which some kernel is called more than once are
		returned.
	*/
	ApplicationMap GetApplications(MemoryTraceAnalyzer::KernelVector _kernels, bool filter) {
		using namespace std;

		ApplicationMap applications;

		for(MemoryTraceAnalyzer::KernelVector::const_iterator kernel = _kernels.begin();
			kernel != _kernels.end(); ++kernel)	{

			// open the kernel's archive and visit every ld/st instruction
			std::ifstream hstream( kernel->header.c_str() );
			boost::archive::text_iarchive harchive( hstream );

			MemoryTraceGenerator::Header header;

			harchive >> header;
			assert( header.format == TraceGenerator::MemoryTraceFormat );
			hstream.close();

			KernelData data;
			data.kernel = *kernel;
			data.header = header;

			applications[ kernel->program ].kernels.push_back( data );
			applications[ kernel->program ].name = kernel->program;
		}

		if (filter) {
			ApplicationMap applications_out;
			for (ApplicationMap::iterator fi = applications.begin();
				fi != applications.end(); ++fi) {
				bool print = false;
				map< string, int > kernelCalls;
				for (int j = 0; j < (int)fi->second.kernels.size(); j++) {
					string name = fi->second.kernels[j].kernel.name;
					if (kernelCalls.find(name) == kernelCalls.end()) {
						kernelCalls[name] = 1;
					}
					else {
						print = true;
						kernelCalls[name]++;
					}
				}
				if (print) {
					applications_out.insert( *fi );
				}
			}
			return applications_out;
		}

		return applications;
	}
}

namespace trace
{

	MemoryTraceAnalyzer::MemoryTraceAnalyzer(
		const std::string& database ) {
		std::ifstream stream(database.c_str());
		verbose = false;

		if (!stream.is_open()) {
			throw hydrazine::Exception("Could not open database file "
				+ database);
		}

		unsigned int count;

		boost::archive::text_iarchive archive(stream);
		archive >> count;

		for( unsigned int i = 0; i < count; ++i) {
			KernelEntry entry;
			archive >> entry;
			if(entry.format == TraceGenerator::MemoryTraceFormat) {
				_kernels.push_back(entry);
			}
		}
	}

	void MemoryTraceAnalyzer::list(bool machine) const {
		using namespace std;
		if (machine) {
			cout << "(\n";
			for(KernelVector::const_iterator kernel = _kernels.begin();
				kernel != _kernels.end(); ++kernel)	{

				cout << "\t  '" << kernel->name << "',\n";
			}
			cout << "\t),\n";
		}
		else {
			std::cout << "There are " << _kernels.size()
				<< " kernels referenced in the database\n";

			for( KernelVector::const_iterator kernel = _kernels.begin();
				kernel != _kernels.end(); ++kernel)	{

				std::cout << " " << kernel->path << "\n";
			}
			std::cout << "\n";
		}
	}

	/*!
		Produces a comma-separated value of a histogram with a given segment size
		for each selected address space aggregated across kernels.

		\param prefix value to prefix each file name - _<space> is affixed to filename
		\param bin_size_pow2 (1 << bin_size_pow2) specifies number of bytes in each bin

	*/
	void MemoryTraceAnalyzer::histogram(std::string prefix, int bin_size_pow2) {
		using namespace std;
		typedef std::map< ir::PTXU64, ir::PTXU64 > Histogram;

		map< ir::PTXInstruction::AddressSpace, ir::PTXU64 > addressMask;
		map< ir::PTXInstruction::AddressSpace, Histogram > histograms;
		for (unsigned int i = 0; i < (unsigned int)spaces.size(); i++) {
			// cglspt
			ir::PTXInstruction::AddressSpace
				space = ir::PTXInstruction::AddressSpace_Invalid;
			switch (spaces[i]) {
				case 'c': space = ir::PTXInstruction::Const; break;
				case 'g': space = ir::PTXInstruction::Global; break;
				case 'l': space = ir::PTXInstruction::Local; break;
				case 's': space = ir::PTXInstruction::Shared; break;
				case 'p': space = ir::PTXInstruction::Param; break;
				case 't': space = ir::PTXInstruction::Texture; break;
				default:
					break;
			}
			histograms[space] = Histogram();
		}

		// enables of masking address bits
		addressMask[ir::PTXInstruction::Const] = ~(0);
		addressMask[ir::PTXInstruction::Global] = ~(0);
		addressMask[ir::PTXInstruction::Local] = ~(0);
		addressMask[ir::PTXInstruction::Shared] = (16384-1);
		addressMask[ir::PTXInstruction::Param] = ~(0);
		addressMask[ir::PTXInstruction::Texture] = ~(0);

		// iterates over kernels in archive
		for( KernelVector::const_iterator kernel = _kernels.begin();
			kernel != _kernels.end(); ++kernel)	{

			// open the kernel's archive and visit every ld/st instruction
			std::ifstream hstream( kernel->header.c_str() );
			boost::archive::text_iarchive harchive( hstream );

			MemoryTraceGenerator::Header header;

			harchive >> header;
			assert( header.format == TraceGenerator::MemoryTraceFormat );
			hstream.close();

			if( header.headerOnly )
			{
				std::stringstream error;
				error << "Trace for Kernel " << kernel->name
					<< " was generated without support for recording "
					<< "individual accesses requried for histogram generation.";
				throw hydrazine::Exception( error.str() );
			}

			std::ifstream stream( kernel->path.c_str() );
			boost::archive::text_iarchive archive( stream );

			for(; true; ) {
				try {
					MemoryTraceGenerator::Event event;
					archive >> event;

					if (histograms.find(event.addressSpace) != histograms.end()) {
						Histogram &hist = histograms[event.addressSpace];

						for (MemoryTraceGenerator::AccessVector::iterator acc_it = event.accesses.begin();
							acc_it != event.accesses.end(); ++acc_it) {

							ir::PTXU64 address = (acc_it->address & addressMask[event.addressSpace]);

							ir::PTXU64 binNumber = ((address >> bin_size_pow2) << bin_size_pow2);
							if (hist.find(binNumber) == hist.end()) {
								hist[binNumber] = 1;
							}
							else {
								++hist[binNumber];
							}

						}	// end for(accesses)
					}
				}
				catch( const boost::archive::archive_exception& e ) {
					break;
				}
			}	// end for(events)

		}	// end for(kernels)

		// now emit the histogram
		for (map< ir::PTXInstruction::AddressSpace, Histogram >::iterator hist_it = histograms.begin();
			hist_it != histograms.end(); ++hist_it) {

			string filename = prefix + "_" + ir::PTXInstruction::toString(hist_it->first) + ".csv";
			std::ofstream file(filename.c_str());

			for (Histogram::iterator h_it = hist_it->second.begin(); h_it != hist_it->second.end(); ++h_it) {
				file << "0x" << hex << h_it->first << "," << dec << h_it->second << "\n";
			}
			hist_it->second.clear();
		}
	}

	void MemoryTraceAnalyzer::global_access_fraction(bool machine) {
		using namespace std;
		using namespace ir;

		PTXU64 agg_globalMemInstructions = 0;
		PTXU64 agg_globalMemWords = 0;
		PTXU64 agg_Instructions = 0;
		PTXU64 agg_Operations = 0;
		PTXU64 agg_Extent = 0;

		int kernelIndex = 0;

		if (machine) {
			cout << "memIntensity = (\n";
		}

		ApplicationMap applications = GetApplications(_kernels, false);

		for( ApplicationMap::const_iterator application = applications.begin();
			application != applications.end(); ++application ) {

			PTXU64 app_globalMemInstructions = 0;
			PTXU64 app_globalMemWords = 0;
			PTXU64 app_Instructions = 0;
			PTXU64 app_Operations = 0;
			PTXU64 app_Extent = 0;

			// iterates over kernels in archive
			for( KernelDataVector::const_iterator
				kernel = application->second.kernels.begin();
				kernel != application->second.kernels.end();
				++kernel, ++kernelIndex )	{

				MemoryTraceGenerator::Header header = kernel->header;

				PTXU64 kernel_globalMemInstructions
					= header.global_instructions + header.texture_instructions;
				PTXU64 kernel_globalMemWords = header.global_words
					+ header.texture_words;

				// accumulate statistics over the aggregate of kernels
				agg_globalMemInstructions += kernel_globalMemInstructions;
				agg_Instructions += header.dynamic_instructions;
				agg_Operations += header.dynamic_operations;
				agg_globalMemWords += kernel_globalMemWords;
				agg_Extent += header.global_extent;

				app_globalMemInstructions += kernel_globalMemInstructions;
				app_Instructions += header.dynamic_instructions;
				app_Operations += header.dynamic_operations;
				app_globalMemWords += kernel_globalMemWords;
				app_Extent += header.global_extent;

				if (machine) {
					// kernel->name , kernel index , mem instructions , instructions , mem words , operations
					cout << "  (" << kernelIndex << " , '" << dec <<  kernel->kernel.name << "' , "
						<< kernel_globalMemInstructions << " , "
						<< header.dynamic_instructions << " , "
						<< kernel_globalMemWords << " , " << header.dynamic_operations << "),\n";
				}
				else {
					cout << "Kernel " << kernel->kernel.name << dec << "\n";
					cout << "  texture ops " << header.texture_accesses << "\n";
					cout << "  module " << kernel->kernel.module << "\n";
					cout << "  path " << kernel->kernel.path << "\n";
					cout << "  mem instructions " << kernel_globalMemInstructions
						<< "\n";
					cout << "  instructions " << header.dynamic_instructions
						<< "\n";
					cout << "  extent " << header.global_extent << "\n";
					cout << "  memory instruction fraction "
						<< (double)kernel_globalMemInstructions
						/ (double)header.dynamic_instructions << "\n";
					cout << "  mem words " << kernel_globalMemWords << "\n";
					cout << "  operations " << header.dynamic_operations << "\n";
					cout << "  words / operations " << (double)kernel_globalMemWords
						/ (double)header.dynamic_operations << "\n";
				}

			}	// end for(kernels)

			if (machine) {
				cout << "  (0, '" << application->first << "' , "
					<< app_globalMemInstructions << " , " << app_Instructions << " , "
					<< app_globalMemWords << " , " << app_Operations << ")\n";
			}
			else {
				cout << "\nAggregate for '" << application->first << "'\n";
				cout << "    mem instructions: " << app_globalMemInstructions << "\n";
				cout << "  extent: "
					<< ( app_Extent / application->second.kernels.size() )
					<< "\n";
				cout << "  dynamic instructions: " << app_Instructions << "\n";
				cout << "    mem instr fraction: " << (double)app_globalMemInstructions / (double)agg_Instructions << "\n";
				cout << " glob mem words: " << app_globalMemWords << "\n";
				cout << "   operations: " << app_Operations << "\n";
				cout << "   words / operations: " << (double)app_globalMemWords / (double)agg_Operations << "\n";
			}

		}

		if (machine) {
			cout << "  (" << dec << kernelIndex << " , 'aggregate'"  << " , "
				<< agg_globalMemInstructions << " , " << agg_Instructions << " , "
				<< agg_globalMemWords << " , " << agg_Operations << ")\n";
			cout << ")\n\n";
		}
		else {
			cout << "\nAggregate\n";
			cout << "    mem instructions: " << agg_globalMemInstructions << "\n";
			cout << "  dynamic instructions: " << agg_Instructions << "\n";
			cout << "  extent: " << ( agg_Extent / kernelIndex ) << "\n";
			cout << "    mem instr fraction: " << (double)agg_globalMemInstructions / (double)agg_Instructions << "\n";
			cout << " glob mem words: " << agg_globalMemWords << "\n";
			cout << "   operations: " << agg_Operations << "\n";
			cout << "   words / operations: " << (double)agg_globalMemWords / (double)agg_Operations << "\n";
		}
	}

	ir::PTXU64 next_power_two(ir::PTXU64 n) {
		n |= (n >> 1);
		n |= (n >> 2);
		n |= (n >> 4);
		n |= (n >> 8);
		n |= (n >> 16);
		n |= (n >> 32);
		return (n + 1);
	}

	/*!
		Over all kernels, determines the number of global memory transactions needed to
		satisfy all ld and st instructions if the warp_size is given. Uses CUDA compute capability
		1.2 memory coalescing protocol.
	*/
	void MemoryTraceAnalyzer::global_transactions(int warp_size, bool machine) {
		using namespace ir;

		std::ostream &out = std::cout;

		ir::PTXU64 global_instructions = 0;
		ir::PTXU64 global_halfwarps = 0;
		ir::PTXU64 global_transactions = 0;

		if (machine) {
			out << "memEfficiency = (\n";
		}

		ApplicationMap applications = GetApplications(_kernels, false);

		for( ApplicationMap::const_iterator application = applications.begin();
			application != applications.end(); ++application ) {

			ir::PTXU64 app_instructions = 0;
			ir::PTXU64 app_halfwarps = 0;
			ir::PTXU64 app_transactions = 0;

			for( KernelDataVector::const_iterator
				kernel = application->second.kernels.begin();
				kernel != application->second.kernels.end(); ++kernel)	{

				MemoryTraceGenerator::Header header = kernel->header;

				ir::PTXU64 kernel_instructions
					= header.global_instructions + header.texture_instructions;
				ir::PTXU64 kernel_halfwarps = header.halfwarps;
				ir::PTXU64 kernel_transactions = header.global_segments;
				ir::PTXU64 kernel_size = header.global_bytes + header.shared_bytes;
				ir::PTXU64 kernel_access_counter
					= header.global_accesses + header.texture_accesses;

				global_instructions += kernel_instructions;
				global_halfwarps += kernel_halfwarps;
				global_transactions += kernel_transactions;

				app_instructions += kernel_instructions;
				app_halfwarps += kernel_halfwarps;
				app_transactions += kernel_transactions;

				if (machine) {
					// (kernelName, threadCount, instructions, halfwarps, transactions) = result
					out << "  ('" << kernel->kernel.name << "', "
						<< header.thread_count << " , "
						<< kernel_instructions << " , "
						<< kernel_halfwarps << " , "
						<< kernel_transactions << "),\n";
				}
				else {
					// finish kernel
					out << "\nKernel " << kernel->kernel.name << "\n";
					out << "         thread count: " << header.thread_count << "\n";
					out << "  memory instructions: " << kernel_instructions << "\n"
							<< "            halfwarps: " << kernel_halfwarps << "\n"
							<< "         transactions: " << kernel_transactions << "\n";
					if (kernel_halfwarps) {
						out << "  average access size: "
							<< (double)kernel_size / (double)kernel_access_counter
							<< " bytes\n";
						out	<< "                  t/h: "
							<< (double)kernel_transactions
							/ (double)kernel_halfwarps << "\n";
					}
				}
			}
			// finished all kernels
			if (machine) {
				// (kernelName, threadCount, instructions, halfwarps, transactions) = result
				out << "  ('" << application->first << "', " << 0 << " , "
					<< app_instructions << " , "
					<< app_halfwarps << " , " << app_transactions << "),\n";
			}
			else {
				out << "\nAggregate '" << application->first << "'results:\n";
				out << "            warp size: " << warp_size << "\n";
				out << "  memory instructions: " << app_instructions << "\n"
						<< "            halfwarps: " << app_halfwarps << "\n"
						<< "         transactions: " << app_transactions << "\n";
				if (app_halfwarps) {
					out << "                  t/h: "
						<< (double)app_transactions
						/ (double)app_halfwarps << "\n";
				}
			}
		}

		// finished all kernels
		if (machine) {
			// (kernelName, threadCount, instructions, halfwarps, transactions) = result
			out << "  ('SDK Average', " << 0 << " , " << global_instructions << " , "
				<< global_halfwarps << " , " << global_transactions << "),\n";
			out << ")\n\n";
		}
		else {
			out << "\nAggregate results:\n";
			out << "            warp size: " << warp_size << "\n";
			out << "  memory instructions: " << global_instructions << "\n"
					<< "            halfwarps: " << global_halfwarps << "\n"
					<< "         transactions: " << global_transactions << "\n";
			if (global_halfwarps) {
				out << "                  t/h: "
					<< (double)global_transactions
					/ (double)global_halfwarps << "\n";
			}
		}
	}
}

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

/*!
	For each kernel, examines how each CTA references the same memory segments
*/
void trace::MemoryTraceAnalyzer::kernel_level_overlapped_global_memory(int segmentSize_pow2) {
	using namespace ir;
	using namespace std;

	for( KernelVector::const_iterator kernel = _kernels.begin();
		kernel != _kernels.end(); ++kernel)	{

		// open the kernel's archive and visit every ld/st instruction
		std::ifstream hstream( kernel->header.c_str() );
		boost::archive::text_iarchive harchive( hstream );

		MemoryTraceGenerator::Header header;

		harchive >> header;
		assert( header.format == TraceGenerator::MemoryTraceFormat );
		hstream.close();

		if( header.headerOnly )
		{
			std::stringstream error;
			error << "Trace for Kernel " << kernel->name
				<< " was generated without support for recording "
				<< "individual accesses requried for computing "
				<< "kernel global memory overlaps.";
			throw hydrazine::Exception( error.str() );
		}

		std::ifstream stream( kernel->path.c_str() );
		boost::archive::text_iarchive archive( stream );

		if (!stream.is_open()) {
			throw hydrazine::Exception(
				"Failed to open MemoryTrace kernel trace file "
				+ kernel->path );
		}

		PTXU64 globalWorkingSetSize = (header.global_max_address - header.global_min_address);
		PTXU64 globalSegmentCount = (globalWorkingSetSize >> segmentSize_pow2) +
			((globalWorkingSetSize & ((1<<segmentSize_pow2)-1)) ? 1 : 0);
		PTXS32 *globalSegmentOwners = new PTXS32[globalSegmentCount];

		for (PTXU64 n = 0; n < globalSegmentCount; n++) {
			globalSegmentOwners[n] = -1;
		}

		PTXU64 global_Lds = 0,
			global_crossCta_Lds = 0,
			global_Sts = 0,
			global_OOB = 0;

		PTXU64 observed_min_address = 0,
			observed_max_address = 0;

		while (true) {
			try {
				MemoryTraceGenerator::Event event;
				archive >> event;

				if (event.addressSpace == PTXInstruction::Global) {
					PTXS32 ctaID = event.ctaX + event.ctaY * header.blockDimX +
						event.ctaZ * (header.blockDimX * header.blockDimY);

					for (MemoryTraceGenerator::AccessVector::const_iterator acc_it = event.accesses.begin();
						acc_it != event.accesses.end(); ++acc_it) {

						PTXU64 segmentNumber = ((acc_it->address - header.global_min_address) >> segmentSize_pow2);

						if (!observed_min_address || acc_it->address < observed_min_address) {
							observed_min_address = acc_it->address;
						}
						if (!observed_max_address || acc_it->address > observed_max_address) {
							observed_max_address = acc_it->address;
						}

						if (segmentNumber < globalSegmentCount) {
							if (event.opcode == PTXInstruction::St) {
								for (PTXU64 n = 0; n < (PTXU64)acc_it->size; n++) {
									PTXU64 seg = (((acc_it->address + n) - header.global_min_address) >> segmentSize_pow2);
									globalSegmentOwners[seg] = ctaID;
								}
								++global_Sts;
							}
							else if (event.opcode == PTXInstruction::Ld) {
								if (globalSegmentOwners[segmentNumber] >= 0 && globalSegmentOwners[segmentNumber] != ctaID) {
									// event of interest
									//
									// record statistics
									++global_crossCta_Lds;
								}
								++global_Lds;
							}
						}
						else {
							// bad news
							++ global_OOB;
						}
					}
				}
			}
			catch( const boost::archive::archive_exception& e ) {
				break;
			}
		}

		delete [] globalSegmentOwners;

		cout << "\nKernel " << kernel->name << "\n";
		cout << " path: " << kernel->path << "\n";
		cout << " module: " << kernel->module << "\n";
		cout << "     global addr range: 0x" << hex << header.global_min_address << " - 0x" << header.global_max_address << dec << "\n";
		cout << "      working set size: " << (header.global_max_address - header.global_min_address) << " bytes\n";
		cout << " segments of " << (1<<segmentSize_pow2) << " bytes: " << globalSegmentCount << "\n";
		cout << "       global OOB refs: " << global_OOB << "\n";
		cout << "   global stored words: " << global_Sts << "\n";
		cout << "     global load words: " << global_Lds << "\n";
		cout << "      x-cta load words: " << global_crossCta_Lds << "\n";
	}
}

/*!
	Print a list of applications and their kernels. If filter is true, only display applications
	that call at least one kernel more than once
*/
void trace::MemoryTraceAnalyzer::application_list(bool filter) {
	using namespace ir;
	using namespace std;

	ApplicationMap applications = GetApplications(_kernels, filter);

	cout << "--\nKernels grouped by application:\n";

	// list kernels by application
	for (ApplicationMap::iterator fi = applications.begin();
		fi != applications.end(); ++fi) {
		cout << "\nApplication: '" << fi->second.name << "' with "
			<< fi->second.kernels.size() << " kernels\n";
		for (int j = 0; j < (int)fi->second.kernels.size(); j++) {
			cout << "  kernel " << fi->second.kernels[j].kernel.name << hex
				<< " - 0x" << fi->second.kernels[j].header.global_min_address
				<< " : 0x" << fi->second.kernels[j].header.global_max_address
				<< dec << "\n";
		}
	}
	cout << "\n";
}

/*!

	class KernelData {
	public:
		KernelEntry kernel;
		MemoryTraceGenerator::Header header;
	};

	class ApplicationData {
	public:
		std::string name;

		std::vector< KernelData > kernels;
	};
*/

class CTAData {
public:
	CTAData() {
		count_Stores = 0;
		count_Loads = 0;
		count_crossCtaLoads = 0;
	}
	~CTAData()
	{

	}

	void clear() {
		globalOwners.clear();
	}

	void initialize(ir::PTXU64 addressSpaceSize, ir::PTXU64 addressBase, int segmentSize_pow2) {
		this->addressBase = addressBase;
		this->segmentSize_pow2 = segmentSize_pow2;
		clear();
	}

	void store(ir::PTXU64 base, int size, int ctaID) {
		++count_Stores;

		for (int n = 0; n < size; n++) {
			ir::PTXU64 offset = (base + (ir::PTXU64)n) - addressBase;
			ir::PTXU64 segmentNumber = (offset >> segmentSize_pow2);
			globalOwners[segmentNumber] = ctaID;
		}
	}

	ir::PTXS32 load(ir::PTXU64 address) {
		++count_Loads;
		ir::PTXU64 segmentNumber = ((address - addressBase) >> segmentSize_pow2);
		GlobalMap::iterator segment = globalOwners.find( segmentNumber );
		if( segment == globalOwners.end() )
		{
			return -1;
		}
		else
		{
			return segment->second;
		}
	}

public:
	typedef std::unordered_map< ir::PTXU64, ir::PTXS32 > GlobalMap;
	ir::PTXU64 addressBase;
	GlobalMap globalOwners;
	int segmentSize_pow2;

public:
	ir::PTXU64 count_Stores;
	ir::PTXU64 count_Loads;
	ir::PTXU64 count_crossCtaLoads;
};

void trace::MemoryTraceAnalyzer::application_overlapped(
	ApplicationData application,
	int segmentSize_pow2) {

	using namespace ir;
	using namespace std;

	map< string, CTAData > kernelsCtaData;

	cout << "Application: " << application.name << "\n" << flush;

	for( vector< KernelData >::const_iterator kernel = application.kernels.begin();
		kernel != application.kernels.end(); ++kernel)	{

		std::ifstream stream( kernel->kernel.path.c_str() );
		boost::archive::text_iarchive archive( stream );

		if (!stream.is_open()) {
			throw hydrazine::Exception(
				"Failed to open MemoryTrace kernel trace file "
				+ kernel->kernel.path );
		}

		if( kernel->header.headerOnly )
		{
			std::stringstream error;
			error << "Trace for Kernel " << kernel->kernel.name
				<< " was generated without support for recording "
				<< "individual accesses requried for computing "
				<< "application global memory overlaps.";
			throw hydrazine::Exception( error.str() );
		}

		cout << "\nKernel " << kernel->kernel.name << "\n" << flush;

		cout << " new base address: 0x" << hex << kernel->header.global_min_address << dec << "\n";
		cout << "      max address: 0x" << hex << kernel->header.global_max_address << dec << "\n";

		if (kernelsCtaData.find(kernel->kernel.name) == kernelsCtaData.end()) {
			CTAData ctaGlobalOwners;
			ctaGlobalOwners.initialize( kernel->header.global_max_address - kernel->header.global_min_address,
				kernel->header.global_min_address, segmentSize_pow2);
			kernelsCtaData[kernel->kernel.name] = ctaGlobalOwners;
		}
		else {
			cout << "Former base address: 0x" << hex << kernelsCtaData[kernel->kernel.name].addressBase << dec << "\n";
		}

		CTAData &ctaGlobalOwners = kernelsCtaData[kernel->kernel.name];

		while (true) {
			try {
				MemoryTraceGenerator::Event event;
				archive >> event;

				PTXS32 ctaID = event.ctaX + event.ctaY * kernel->header.blockDimX +
					event.ctaZ * (kernel->header.blockDimX * kernel->header.blockDimY);

				if (event.addressSpace == PTXInstruction::Global ||
					event.opcode == PTXInstruction::Ld || event.opcode == PTXInstruction::St) {

					//cout << " global operation encountered\n" << flush;

					for (MemoryTraceGenerator::AccessVector::const_iterator acc_it = event.accesses.begin();
						acc_it != event.accesses.end(); ++acc_it) {
						if (event.opcode == PTXInstruction::St) {
							//cout << "  store to 0x" << hex << acc_it->address << dec << " " << flush;
							ctaGlobalOwners.store(acc_it->address, acc_it->size, ctaID);
							//cout << "done\n" << flush;
						}
						else {
							//cout << "  load from 0x" << hex << acc_it->address << dec << " " <<  flush;
							PTXS32 owningCtaID = ctaGlobalOwners.load(acc_it->address);
							//cout << "done\n" << flush;

							if (owningCtaID >= 0 && owningCtaID != ctaID) {
								// loading from a segment written to by another CTA
								++ ctaGlobalOwners.count_crossCtaLoads;
							}
						}
					}
				}
			}
			catch( const boost::archive::archive_exception& e ) {
				break;
			}
		}
	}

	cout << "Application " << application.name << "\n";

	// free ownership information for kernels
	for (map<string,CTAData>::iterator it = kernelsCtaData.begin();
		it != kernelsCtaData.end(); ++it) {
		it->second.clear();

		cout << "  kernel " << it->first << "\n";
		cout << "         stores: " << it->second.count_Stores << "\n";
		cout << "          loads: " << it->second.count_Loads << "\n";
		cout << "    x-cta loads: " << it->second.count_crossCtaLoads << "\n";
	}
	kernelsCtaData.clear();
}

/*!
	For each application, examines how many times kernels refer to the same memory segments
*/
void trace::MemoryTraceAnalyzer::application_level_overlapped_global_memory(int segmentSize_pow2) {
	CTAData data;
	using namespace std;

	ApplicationMap applications = GetApplications(_kernels, false);

	for( ApplicationMap::iterator app = applications.begin();
		app != applications.end(); ++app )
	{
		ir::PTXU64 minAddress = -1;
		ir::PTXU64 maxAddress = 0;

		for( vector< KernelData >::const_iterator
			kernel = app->second.kernels.begin();
			kernel != app->second.kernels.end(); ++kernel)	{
			minAddress = std::min( minAddress,
				kernel->header.global_min_address );
			maxAddress = std::max( maxAddress,
				kernel->header.global_min_address );
		}

		data.initialize( maxAddress - minAddress, minAddress, segmentSize_pow2 );
		application_overlapped(app->second, segmentSize_pow2);
	}

}

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

int main( int argc, char** argv) {
	hydrazine::ArgumentParser parser( argc, argv );

	parser.description("Provides the ability to inspect and analyze a database created by"
		+ std::string( "a MemoryTraceGenerator" ) );

	bool list = false;
	bool histogram = false;
	bool global = false;
	bool kernel_overlapped = false;
	bool app_overlapped = false;
	bool list_apps = false;
	bool filter_apps_list = false;
	bool mem_intensity = false;
	bool verbose = false;
	bool machine_readable = false;

	std::string database;
	std::string spaces;
	std::string prepend;

	int binsize;
	int warpsize;
	int segment_size_pow2;

	parser.parse( "-l", "--list", list, false,
		"List all traces in the database." );

	parser.parse( "-z", "--machine", machine_readable, false,
		"Indicates output is intended to be machine-readable");
	parser.parse( "-i", "--input", database, "traces/database.trace",
		"Path to database file." );
	parser.parse( "-v", "--verbose", verbose, false,
		"Prints an unmanagable amount of information.");
	parser.parse("-s", "--spaces", spaces, "cglspt",
		"Selects address spaces of interest [cglspt]");

	parser.parse( "", "--histogram", histogram, false,
		"Constructs a histogram document for each selected address space over all kernels");
	parser.parse( "", "--prepend", prepend, "memory",
		"String prepended to generated filenames for histogram and other analysis");
	parser.parse( "", "--binsize", binsize, 6,
		"Exponent to which 2 must be raised to specify bin size in bytes for histogram.");

	parser.parse( "-g", "--Global", global, false,
		"Print global load/store statistics to stdout");
	parser.parse( "", "--warpsize", warpsize, 32,
		"Number of threads per warp");

	parser.parse( "", "--Koverlapped", kernel_overlapped, false,
		"Analyzes overlapped working sets across CTAs within each kernel");

	parser.parse( "", "--Apps", list_apps, false,
		"Lists kernels grouped by application");
	parser.parse( "-f", "--filter", filter_apps_list, false,
		"Only print apps that call the same kernel more than once");

	parser.parse( "", "--Aoverlapped", app_overlapped, false,
		"[DOESN'T WORK] Analyzes overlapped working sets across kernels within each application");
	parser.parse( "", "--segsize", segment_size_pow2, 7,
		"Exponent to which 2 must be raised to specify segment size in Koverlapped and Aoverlapped metrics");

	parser.parse( "-m", "--MemIntensity", mem_intensity, false,
		"Computes [ld+st]/dynamic instructions for each kernel and aggregates, weighting by dynamic instructions");
	parser.parse();

	trace::MemoryTraceAnalyzer analyzer( database );
	analyzer.spaces = spaces;
	analyzer.verbose = verbose;
	if (list) {
		analyzer.list(machine_readable);
	}

	if (histogram) {
		analyzer.histogram(prepend, binsize);
	}

	if (global) {
		analyzer.global_transactions(warpsize, machine_readable);
	}

	if (kernel_overlapped) {
		analyzer.kernel_level_overlapped_global_memory(segment_size_pow2);
	}
	if (list_apps) {
		analyzer.application_list(filter_apps_list);
	}
	if (app_overlapped) {
		analyzer.application_level_overlapped_global_memory(segment_size_pow2);
	}
	if (mem_intensity) {
		analyzer.global_access_fraction(machine_readable);
	}

	return 0;
}

#endif

max_stars_repo_name: florianjacob/gpuocelot

max_issues_repo_name: mprevot/gpuocelot

max_forks_repo_name: mprevot/gpuocelot


text:
//  Copyright (c) 2006, Giovanni P. Deretta
//
//  This code may be used under either of the following two licences:
//
//  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. OF SUCH DAMAGE.
//
//  Or:
//
//  Distributed under the Boost Software License, Version 1.0.
//  (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)

#ifndef BOOST_COROUTINE_ARGUMENT_UNPACKER_HPP_20060601
#define BOOST_COROUTINE_ARGUMENT_UNPACKER_HPP_20060601
#include <boost/preprocessor/control/if.hpp>
#include <boost/preprocessor/repetition.hpp>
#include <boost/utility/result_of.hpp>
#include <boost/coroutine/detail/index.hpp>
#include <boost/coroutine/detail/arg_max.hpp>

namespace boost { namespace coroutines { namespace detail {
  template<typename Traits, int Len>
  struct unpacker_n;

  template<typename Traits, int Len>
  struct unpacker_ex_n;

#define BOOST_COROUTINE_ARGUMENT_UNPACKER(z, len, unused)              \
    template<typename Traits>                                          \
    struct unpacker_n<Traits, len> {                                   \
        template<typename Functor, typename Tuple>                     \
      struct result {/*for result_of compatibility*/                   \
	  typedef typename  boost::result_of                           \
             <Functor(BOOST_PP_ENUM_BINARY_PARAMS                      \
		      (len, typename Traits::template at<index_ , >    \
		       ::type BOOST_PP_INTERCEPT))>::type type;        \
      };                                                               \
      template<typename Functor, typename Tuple>                       \
      typename result<Functor, Tuple>::type operator()                 \
       (Functor& f, Tuple& parms){                                     \
           using boost::get; /*tuples::get cannot be found via ADL*/   \
           return f(BOOST_PP_ENUM_BINARY_PARAMS                        \
		    (len,                                              \
		     get<index_, >                                     \
		     (parms) BOOST_PP_INTERCEPT));                     \
      }                                                                \
    };                                                                 \
/**/

#define BOOST_COROUTINE_ARGUMENT_UNPACKER_EX(z, len, unused)           \
    template<typename Traits>                                          \
    struct unpacker_ex_n<Traits, len >           {                     \
    template<typename Functor,                                         \
             typename First,                                           \
	     typename Tuple>                                           \
      struct result {                                                  \
	  typedef typename  boost::result_of                           \
             <Functor(First BOOST_PP_COMMA_IF(len)                     \
		      BOOST_PP_ENUM_BINARY_PARAMS                      \
		      (len, typename Traits                            \
		       ::template at<index_ , >::type BOOST_PP_INTERCEPT))>     \
          ::type type;                                                 \
	};                                                             \
                                                                       \
      template<typename Functor,                                       \
               typename First,                                         \
	       typename Tuple>                                         \
      typename result<Functor, First, Tuple>::type                     \
      operator()(Functor& f, First& arg0, Tuple& parms){                \
           using boost::get; /*tuples::get cannot be found via ADL*/  \
           return f(arg0                                               \
		    BOOST_PP_COMMA_IF(len)                             \
		    BOOST_PP_ENUM_BINARY_PARAMS                        \
		    (len,                                              \
		     get<index_, >                                     \
		     (parms) BOOST_PP_INTERCEPT) );                    \
      }                                                                \
    };                                                                 \
/**/

  BOOST_PP_REPEAT(BOOST_COROUTINE_ARG_MAX,
		  BOOST_COROUTINE_ARGUMENT_UNPACKER, ~);
  BOOST_PP_REPEAT(BOOST_COROUTINE_ARG_MAX,
		  BOOST_COROUTINE_ARGUMENT_UNPACKER_EX, ~);

  // Somehow VCPP 8.0 chockes if the Trait for unpack[_ex]
  // is explicitly specified. We use an empty dispatch
  // tag to let the compiler deduce it.
  template<typename Trait>
  struct trait_tag {};

  /**
   * Inovoke function object @p f passing  all
   * elements in tuple @p parms as distinct parameters.
   */
  template<typename Traits, typename Functor, typename Tuple>
  inline
  typename unpacker_n<Traits, Traits::length>
  ::template result<Functor, Tuple>::type
  unpack(Functor f, Tuple& parms, trait_tag<Traits>) {
    return unpacker_n<Traits, Traits::length>()(f, parms);
  }

  /**
   * Inovke function object @p f passing argument @p arg0 and all
   * elements in tuple @p parms as distinct parameters.
   */
  template<typename Traits, typename Functor, typename First, typename Tuple>
  inline
  typename unpacker_ex_n<Traits, Traits::length>::
  template result<Functor, First, Tuple>::type
  unpack_ex(Functor f, First& arg0, Tuple& parms, trait_tag<Traits>) {
    return unpacker_ex_n<Traits, Traits::length>()
      (f, arg0, parms);
  }
} } }
#endif

max_stars_repo_name: erikfrey/coroutine

max_issues_repo_name: erikfrey/coroutine

max_forks_repo_name: erikfrey/coroutine