<commit_before>#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <iostream.h>
#include <fstream.h>

/**
 *  Requires GAlib from http://lancet.mit.edu/ga/ to run.
 */

#include <ga/ga.h>
#include <ga/GARealGenome.h>
#include <ga/GARealGenome.C>

extern "C" {
#include "tmp/scores.h"
#include "tmp/tests.h"
}

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

int threshold = 5;	// threshold of spam vs. non-spam

int nn, ny, yn, yy;	// simple number of y/n diagnoses

// These floats are the same as above, but incorrect scores are penalised
// by how wrong they are.
//
float nyscore, ynscore;

float nybias	= 5.0;
int sleepTime	= 0;		// time to sleep during runs

float float_num_spam;
float float_num_nonspam;

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

void printhits (FILE *fout, float convergence, int gens) {
  if (num_tests == 0) { num_tests = 1; }

  fprintf (fout, "# SUMMARY:            %6d / %6d\n#\n",
      	ny, yn);

  fprintf (fout,
"# Correctly non-spam: %6d  %3.2f%%  (%3.2f%% overall)\n",
        nn, (nn / (float) num_nonspam) * 100.0,
        (nn / (float) num_tests) * 100.0);

  fprintf (fout,
"# Correctly spam:     %6d  %3.2f%%  (%3.2f%% overall)\n",
        yy, (yy / (float) num_spam) * 100.0,
	(yy / (float) num_tests) * 100.0);

  fprintf (fout,
"# False positives:    %6d  %3.2f%%  (%3.2f%% overall, %6.0f adjusted)\n",
        ny, (ny / (float) num_nonspam) * 100.0,
	(ny / (float) num_tests) * 100.0, nyscore);

  fprintf (fout,
"# False negatives:    %6d  %3.2f%%  (%3.2f%% overall, %6.0f adjusted)\n",
        yn, (yn / (float) num_spam) * 100.0,
	(yn / (float) num_tests) * 100.0, ynscore);

  fprintf (fout, "# TOTAL:              %6d  %3.2f%%\n",
        num_tests, 100.0);

  fprintf (fout, "# convergence / generations: %3.4f %d\n#\n",
      	convergence, gens);
}

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

void writescores (FILE *fout) {
  int i;
  float score;

  for (i = 0; i < num_scores-1; i++) {
    score = scores[i];
    fprintf (fout, "score %-30s %2.1f\n", score_names[i], score);
  }
}

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

void fullcounthitsfromscores () {
  int file;
  float hits;
  int i;
  int overthresh;
  int nyint = 0;
  int ynint = 0;

  nn = ny = yn = yy = 0;
  for (file = 0; file < num_tests; file++) {
    hits = 0.0;
    for (i = num_tests_hit[file]-1; i >= 0; i--) {
      hits += scores[tests_hit[file][i]];
    }
    overthresh = (hits >= threshold);

    // we use the xxscore vars as a weighted "crapness" score; ie.
    // higher is worse.  incorrect diagnoses add (1 + incorrectness)
    // to them, where "incorrectness" is (num_points_over_threshold) / 5.0.
    //
    // This way, massively-incorrect scores are massively penalised.

    if (is_spam[file]) {
      if (overthresh) {
	yy++;
      } else {
	yn++; nyint += (int) (hits - threshold) + 5;
      }
    } else {
      if (overthresh) {
	ny++; ynint += (int) (threshold - hits) + 5;
      } else {
	nn++;
      }
    }
  }

  nyscore = ((float) nyint);		// / 5.0;
  ynscore = ((float) ynint);		// / 5.0;
}

void quickcounthitsfromscores () {
  int file;
  float hits;
  int i;
  int overthresh;
  int nyint = 0;
  int ynint = 0;

  for (file = 0; file < num_tests; file++) {
    hits = 0.0;

    for (i = num_tests_hit[file]-1; i >= 0; i--) {
      hits += scores[tests_hit[file][i]];
    }

    // Craig: good tips, this should be faster
    overthresh = (hits >= threshold);
    if (is_spam[file]) {
      if (!overthresh) {
	ynint += (int) (threshold - hits) + 5;
      }
    } else {
      if (overthresh) {
	nyint += (int) (hits - threshold) + 5;
      }
    }
  }

  nyscore = ((float) nyint);		// / 5.0;
  ynscore = ((float) ynint);		// / 5.0;
}

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

void copygenometoscores (GARealGenome &genome) {
  int i;

  for (i = 0; i < num_scores; i++) {
    if (is_mutatable[i]) {
      scores[i] = genome[i];
      if (scores[i] == 0.0) { scores[i] = 0.1; }
      else if (scores[i] < range_lo[i]) { scores[i] = range_lo[i]; }
      else if (scores[i] > range_hi[i]) { scores[i] = range_hi[i]; }

    } else {
      scores[i] = bestscores[i];	// use the standard one
    }
  }
}

void fullcounthitsfromgenome (GARealGenome &genome) {
  if (genome.length() != num_scores) {
    cerr << "len != numscores: "<<genome.length()<<"  "<<num_scores<<endl;
    exit(1);
  }
  copygenometoscores (genome);
  fullcounthitsfromscores ();
}

void quickcounthitsfromgenome (GARealGenome &genome) {
  copygenometoscores (genome);
  quickcounthitsfromscores ();
}

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

// add up all the incorrect diagnoses, and use that as the fitness
// score.  Since we're trying to minimise the objective, this should
// work OK -- we want it to be as low as possible.
//
float
objective(GAGenome & c)
{
  GARealGenome &genome = (GARealGenome &) c;
  quickcounthitsfromgenome(genome);

  if (sleepTime) { usleep(sleepTime); }

  // old old version; just use the # of messages
  // return ((float) yn + (ny * nybias));

  // old version: use the proportion of messages to messages in the
  // correct category.
  //return (float) ((yn / (float) num_spam)
    		//+ ((ny * nybias) / (float) num_nonspam));

  // new version: similar to above, but penalise scores that
  // are way off.
  return (float) ((ynscore / float_num_spam)
      		+ ((nyscore * nybias) / float_num_nonspam));
}

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

void
write_to_file (GARealGenome &genome, const char *fname) {
  FILE *fout;
  char namebuf[255];

  fullcounthitsfromgenome (genome);
  snprintf (namebuf, 255, "%s", fname);
  fout = fopen (namebuf, "w");
  printhits (fout, 0.0, 0);
  writescores (fout);
  fclose (fout);
}

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

void
fill_allele_set (GARealAlleleSetArray *setary)
{
  float hi, lo;
  int i;

  for (i = 0; i < num_scores; i++) {
    if (is_mutatable[i]) {
      hi = range_hi[i];
      lo = range_lo[i];
    } else {
      hi = bestscores[i];
      lo = bestscores[i];
    }
    setary->add (lo, hi);
  }
}

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

void usage () {
  cerr << "usage: evolve -s size [args]\n"
    << "\n"
    << "  -z sleeptime = time to sleep in msecs (0 default, 10 = 33% cpu usage)\n"
    << "  -s size = population size (300 recommended)\n"
    << "  -b nybias = bias towards false negatives (5.0 default)\n"
    << "\n"
    << "  -g ngens = generations to run (1500 default)\n"
    << "  -c conv = run until convergence (1.00 default)\n"
    << "  -m npops = migration with multi populations (5 default)\n"
    << "\n"
    << "  -g and -c are mutually exclusive.\n"
    << "  Steady-state mode is default, unless -m is used -- but currently\n"
    << "  -m is unimplemented; you need to edit code to do it. sorry.\n"
    <<endl;
  exit (30);
}

int
main (int argc, char **argv) {
  int arg;
  int demeMode	= 0;
  int convergeMode = 0;
  int justCount = 0;
  int npops	= 5;		// num pops (for deme mode)
  int popsize	= 0;		// population size
  int generations = 1500;	// generations to run
  float pconv	= 1.00;		// threshhold for when we have converged
  int nconv	= 300;		// how many gens back to check for convergence

  while ((arg = getopt (argc, argv, "b:c:s:m:g:Cz:")) != -1) {
    switch (arg) {
      case 'b':
	nybias = atof(optarg);
	break;

      case 's':
	popsize = atoi(optarg);
	break;

      case 'm':
	demeMode = 1;
	fprintf (stderr, "Deme mode not supported through cmdline args yet\n");
	usage();
	npops = atoi(optarg);
	break;

      case 'c':
	convergeMode = 1;
	pconv = atof(optarg);
	break;

      case 'C':
	justCount = 1;
	break;

      case 'g':
	demeMode = 0;
	generations = atoi(optarg);
	break;

      case 'z':
	sleepTime = atoi(optarg);
	break;

      case '?':
	usage();
	break;
    }
  }

  loadscores ();
  loadtests ();

  float_num_spam = (float) num_spam;
  float_num_nonspam = (float) num_nonspam;

  if (justCount) {
    cout << "Counts for current genome:" << endl;

    // copy the base scores to the "scores" array
    int i;
    for (i = 0; i < num_scores; i++) {
      scores[i] = bestscores[i];
    }

    fullcounthitsfromscores();
    printhits (stdout, 0.0, 0);
    exit (0);
  }

  if (popsize == 0) { usage(); }

  GARandomSeed();	// use time ^ $$

  // allow scores from -0.5 to 4.0 inclusive, in jumps of 0.1
  // each test has it's own range within this
  GARealAlleleSetArray allelesetarray;
  fill_allele_set (&allelesetarray);
  GARealGenome genome(allelesetarray, objective);

  // use our score-perturbing initialiser, the default
  // gaussian mutator, and crossover.

  // don't let the genome change its length
  genome.resizeBehaviour (num_scores, num_scores);

  // steady-state seems to give best results
  GASteadyStateGA ga(genome);

  // incremental, faster but not as good
  //GAIncrementalGA ga(genome);

  //GADemeGA ga(genome);
  //ga.nPopulations(npops);

  ga.populationSize(popsize);

  if (convergeMode) {
    ga.pConvergence(pconv);
    ga.nConvergence(nconv);
    ga.terminator(GAGeneticAlgorithm::TerminateUponConvergence);
  } else {
    ga.set(gaNnGenerations, generations);        // number of generations
  }

  ga.minimize();		// we want to minimize the objective
  ga.set(gaNpCrossover, 0.6);           // probability of crossover
  ga.set(gaNpMutation, 0.05);           // probability of mutation
  ga.set(gaNscoreFrequency, 1);         // how often to record scores
  ga.set(gaNflushFrequency, 20);        // how often to dump scores to file
  ga.set(gaNselectScores,               // which scores should we track?
         GAStatistics::AllScores);
  ga.set(gaNscoreFilename, "evolve.scores");
  ga.parameters(argc, argv);

  unlink ("evolve.scores");
  cout << "Run this to watch progress scores:" << endl
    	<< "\ttail -f evolve.scores" << endl;
  cout << "evolving...\n";

  int gens = 0;
  while(!ga.done()) {
    ga.step();
    gens++;

    if (gens % 5 == 0) {
      cout << "."; cout.flush();

      if (gens % (20000/popsize) == 0) {
	cout << "\nProgress: gen=" << gens << " convergence="
	      << ga.statistics().convergence()
	      << ":\n";
      }

      genome = ga.statistics().bestIndividual();
      fullcounthitsfromgenome (genome);
      printhits (stdout, ga.statistics().convergence(), gens);
      write_to_file (genome, "results.evolved");
    }
  }
  cout << endl;

  cout << "Best genome found:" << endl;
  genome = ga.statistics().bestIndividual();
  fullcounthitsfromgenome (genome);
  printhits (stdout, ga.statistics().convergence(), gens);
  write_to_file (genome, "results.evolved");

  cout << "Scores for this genome written to \"results.evolved\"." << endl;
  return 0;
}

<commit_msg>evolver was SIGFPEing if pop was bigger than 20000. nice bug to be able to afford ;)<commit_after>#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <iostream.h>
#include <fstream.h>

/**
 *  Requires GAlib from http://lancet.mit.edu/ga/ to run.
 */

#include <ga/ga.h>
#include <ga/GARealGenome.h>
#include <ga/GARealGenome.C>

extern "C" {
#include "tmp/scores.h"
#include "tmp/tests.h"
}

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

int threshold = 5;	// threshold of spam vs. non-spam

int nn, ny, yn, yy;	// simple number of y/n diagnoses

// These floats are the same as above, but incorrect scores are penalised
// by how wrong they are.
//
float nyscore, ynscore;

float nybias	= 5.0;
int sleepTime	= 0;		// time to sleep during runs

float float_num_spam;
float float_num_nonspam;

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

void printhits (FILE *fout, float convergence, int gens) {
  if (num_tests == 0) { num_tests = 1; }

  fprintf (fout, "# SUMMARY:            %6d / %6d\n#\n",
      	ny, yn);

  fprintf (fout,
"# Correctly non-spam: %6d  %3.2f%%  (%3.2f%% overall)\n",
        nn, (nn / (float) num_nonspam) * 100.0,
        (nn / (float) num_tests) * 100.0);

  fprintf (fout,
"# Correctly spam:     %6d  %3.2f%%  (%3.2f%% overall)\n",
        yy, (yy / (float) num_spam) * 100.0,
	(yy / (float) num_tests) * 100.0);

  fprintf (fout,
"# False positives:    %6d  %3.2f%%  (%3.2f%% overall, %6.0f adjusted)\n",
        ny, (ny / (float) num_nonspam) * 100.0,
	(ny / (float) num_tests) * 100.0, nyscore);

  fprintf (fout,
"# False negatives:    %6d  %3.2f%%  (%3.2f%% overall, %6.0f adjusted)\n",
        yn, (yn / (float) num_spam) * 100.0,
	(yn / (float) num_tests) * 100.0, ynscore);

  fprintf (fout, "# TOTAL:              %6d  %3.2f%%\n",
        num_tests, 100.0);

  fprintf (fout, "# convergence / generations: %3.4f %d\n#\n",
      	convergence, gens);
}

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

void writescores (FILE *fout) {
  int i;
  float score;

  for (i = 0; i < num_scores-1; i++) {
    score = scores[i];
    fprintf (fout, "score %-30s %2.1f\n", score_names[i], score);
  }
}

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

void fullcounthitsfromscores () {
  int file;
  float hits;
  int i;
  int overthresh;
  int nyint = 0;
  int ynint = 0;

  nn = ny = yn = yy = 0;
  for (file = 0; file < num_tests; file++) {
    hits = 0.0;
    for (i = num_tests_hit[file]-1; i >= 0; i--) {
      hits += scores[tests_hit[file][i]];
    }
    overthresh = (hits >= threshold);

    // we use the xxscore vars as a weighted "crapness" score; ie.
    // higher is worse.  incorrect diagnoses add (1 + incorrectness)
    // to them, where "incorrectness" is (num_points_over_threshold) / 5.0.
    //
    // This way, massively-incorrect scores are massively penalised.

    if (is_spam[file]) {
      if (overthresh) {
	yy++;
      } else {
	yn++; nyint += (int) (hits - threshold) + 5;
      }
    } else {
      if (overthresh) {
	ny++; ynint += (int) (threshold - hits) + 5;
      } else {
	nn++;
      }
    }
  }

  nyscore = ((float) nyint);		// / 5.0;
  ynscore = ((float) ynint);		// / 5.0;
}

void quickcounthitsfromscores () {
  int file;
  float hits;
  int i;
  int overthresh;
  int nyint = 0;
  int ynint = 0;

  for (file = 0; file < num_tests; file++) {
    hits = 0.0;

    for (i = num_tests_hit[file]-1; i >= 0; i--) {
      hits += scores[tests_hit[file][i]];
    }

    // Craig: good tips, this should be faster
    overthresh = (hits >= threshold);
    if (is_spam[file]) {
      if (!overthresh) {
	ynint += (int) (threshold - hits) + 5;
      }
    } else {
      if (overthresh) {
	nyint += (int) (hits - threshold) + 5;
      }
    }
  }

  nyscore = ((float) nyint);		// / 5.0;
  ynscore = ((float) ynint);		// / 5.0;
}

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

void copygenometoscores (GARealGenome &genome) {
  int i;

  for (i = 0; i < num_scores; i++) {
    if (is_mutatable[i]) {
      scores[i] = genome[i];
      if (scores[i] == 0.0) { scores[i] = 0.1; }
      else if (scores[i] < range_lo[i]) { scores[i] = range_lo[i]; }
      else if (scores[i] > range_hi[i]) { scores[i] = range_hi[i]; }

    } else {
      scores[i] = bestscores[i];	// use the standard one
    }
  }
}

void fullcounthitsfromgenome (GARealGenome &genome) {
  if (genome.length() != num_scores) {
    cerr << "len != numscores: "<<genome.length()<<"  "<<num_scores<<endl;
    exit(1);
  }
  copygenometoscores (genome);
  fullcounthitsfromscores ();
}

void quickcounthitsfromgenome (GARealGenome &genome) {
  copygenometoscores (genome);
  quickcounthitsfromscores ();
}

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

// add up all the incorrect diagnoses, and use that as the fitness
// score.  Since we're trying to minimise the objective, this should
// work OK -- we want it to be as low as possible.
//
float
objective(GAGenome & c)
{
  GARealGenome &genome = (GARealGenome &) c;
  quickcounthitsfromgenome(genome);

  if (sleepTime) { usleep(sleepTime); }

  // old old version; just use the # of messages
  // return ((float) yn + (ny * nybias));

  // old version: use the proportion of messages to messages in the
  // correct category.
  //return (float) ((yn / (float) num_spam)
    		//+ ((ny * nybias) / (float) num_nonspam));

  // new version: similar to above, but penalise scores that
  // are way off.
  return (float) ((ynscore / float_num_spam)
      		+ ((nyscore * nybias) / float_num_nonspam));
}

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

void
write_to_file (GARealGenome &genome, const char *fname) {
  FILE *fout;
  char namebuf[255];

  fullcounthitsfromgenome (genome);
  snprintf (namebuf, 255, "%s", fname);
  fout = fopen (namebuf, "w");
  printhits (fout, 0.0, 0);
  writescores (fout);
  fclose (fout);
}

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

void
fill_allele_set (GARealAlleleSetArray *setary)
{
  float hi, lo;
  int i;

  for (i = 0; i < num_scores; i++) {
    if (is_mutatable[i]) {
      hi = range_hi[i];
      lo = range_lo[i];
    } else {
      hi = bestscores[i];
      lo = bestscores[i];
    }
    setary->add (lo, hi);
  }
}

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

void usage () {
  cerr << "usage: evolve -s size [args]\n"
    << "\n"
    << "  -z sleeptime = time to sleep in msecs (0 default, 10 = 33% cpu usage)\n"
    << "  -s size = population size (300 recommended)\n"
    << "  -b nybias = bias towards false negatives (5.0 default)\n"
    << "\n"
    << "  -g ngens = generations to run (1500 default)\n"
    << "  -c conv = run until convergence (1.00 default)\n"
    << "  -m npops = migration with multi populations (5 default)\n"
    << "\n"
    << "  -g and -c are mutually exclusive.\n"
    << "  Steady-state mode is default, unless -m is used -- but currently\n"
    << "  -m is unimplemented; you need to edit code to do it. sorry.\n"
    <<endl;
  exit (30);
}

int
main (int argc, char **argv) {
  int arg;
  int demeMode	= 0;
  int convergeMode = 0;
  int justCount = 0;
  int npops	= 5;		// num pops (for deme mode)
  int popsize	= 0;		// population size
  int generations = 1500;	// generations to run
  float pconv	= 1.00;		// threshhold for when we have converged
  int nconv	= 300;		// how many gens back to check for convergence

  while ((arg = getopt (argc, argv, "b:c:s:m:g:Cz:")) != -1) {
    switch (arg) {
      case 'b':
	nybias = atof(optarg);
	break;

      case 's':
	popsize = atoi(optarg);
	break;

      case 'm':
	demeMode = 1;
	fprintf (stderr, "Deme mode not supported through cmdline args yet\n");
	usage();
	npops = atoi(optarg);
	break;

      case 'c':
	convergeMode = 1;
	pconv = atof(optarg);
	break;

      case 'C':
	justCount = 1;
	break;

      case 'g':
	demeMode = 0;
	generations = atoi(optarg);
	break;

      case 'z':
	sleepTime = atoi(optarg);
	break;

      case '?':
	usage();
	break;
    }
  }

  loadscores ();
  loadtests ();

  float_num_spam = (float) num_spam;
  float_num_nonspam = (float) num_nonspam;

  if (justCount) {
    cout << "Counts for current genome:" << endl;

    // copy the base scores to the "scores" array
    int i;
    for (i = 0; i < num_scores; i++) {
      scores[i] = bestscores[i];
    }

    fullcounthitsfromscores();
    printhits (stdout, 0.0, 0);
    exit (0);
  }

  if (popsize == 0) { usage(); }

  GARandomSeed();	// use time ^ $$

  // allow scores from -0.5 to 4.0 inclusive, in jumps of 0.1
  // each test has it's own range within this
  GARealAlleleSetArray allelesetarray;
  fill_allele_set (&allelesetarray);
  GARealGenome genome(allelesetarray, objective);

  // use our score-perturbing initialiser, the default
  // gaussian mutator, and crossover.

  // don't let the genome change its length
  genome.resizeBehaviour (num_scores, num_scores);

  // steady-state seems to give best results
  GASteadyStateGA ga(genome);

  // incremental, faster but not as good
  //GAIncrementalGA ga(genome);

  //GADemeGA ga(genome);
  //ga.nPopulations(npops);

  ga.populationSize(popsize);

  if (convergeMode) {
    ga.pConvergence(pconv);
    ga.nConvergence(nconv);
    ga.terminator(GAGeneticAlgorithm::TerminateUponConvergence);
  } else {
    ga.set(gaNnGenerations, generations);        // number of generations
  }

  ga.minimize();		// we want to minimize the objective
  ga.set(gaNpCrossover, 0.6);           // probability of crossover
  ga.set(gaNpMutation, 0.05);           // probability of mutation
  ga.set(gaNscoreFrequency, 1);         // how often to record scores
  ga.set(gaNflushFrequency, 20);        // how often to dump scores to file
  ga.set(gaNselectScores,               // which scores should we track?
         GAStatistics::AllScores);
  ga.set(gaNscoreFilename, "evolve.scores");
  ga.parameters(argc, argv);

  unlink ("evolve.scores");
  cout << "Run this to watch progress scores:" << endl
    	<< "\ttail -f evolve.scores" << endl;
  cout << "evolving...\n";

  int gens = 0;
  int progressinterval = (20000/popsize);
  if (progressinterval < 1) { progressinterval = 1; }

  while(!ga.done()) {
    ga.step();
    gens++;

    if (gens % 5 == 0) {
      cout << "."; cout.flush();

      if (gens % progressinterval == 0) {
	cout << "\nProgress: gen=" << gens << " convergence="
	      << ga.statistics().convergence()
	      << ":\n";
      }

      genome = ga.statistics().bestIndividual();
      fullcounthitsfromgenome (genome);
      printhits (stdout, ga.statistics().convergence(), gens);
      write_to_file (genome, "results.evolved");
    }
  }
  cout << endl;

  cout << "Best genome found:" << endl;
  genome = ga.statistics().bestIndividual();
  fullcounthitsfromgenome (genome);
  printhits (stdout, ga.statistics().convergence(), gens);
  write_to_file (genome, "results.evolved");

  cout << "Scores for this genome written to \"results.evolved\"." << endl;
  return 0;
}

<|endoftext|>


<commit_before>/**
 * This file is part of the CernVM File System.
 */

#include "kvstore.h"

#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <string.h>

#include <algorithm>

#include "util_concurrency.h"

using namespace std;  // NOLINT

namespace kvstore {

bool MemoryKvStore::GetBuffer(const shash::Any &id, MemoryBuffer *buf) {
  return entries_.Lookup(id, buf);
}

bool MemoryKvStore::PopBuffer(const shash::Any &id, MemoryBuffer *buf) {
  WriteLockGuard guard(rwlock_);
  if (!entries_.Lookup(id, buf)) return false;
  used_bytes_ -= (*buf).size;
  entries_.Forget(id);
  return true;
}

int64_t MemoryKvStore::GetSize(const shash::Any &id) {
  MemoryBuffer mem;
  if (entries_.Lookup(id, &mem)) {
    return mem.size;
  } else {
    return -ENOENT;
  }
}

int64_t MemoryKvStore::GetRefcount(const shash::Any &id) {
  MemoryBuffer mem;
  if (entries_.Lookup(id, &mem)) {
    return mem.refcount;
  } else {
    return -ENOENT;
  }
}

bool MemoryKvStore::IncRef(const shash::Any &id) {
  WriteLockGuard guard(rwlock_);
  MemoryBuffer mem;
  if (entries_.Lookup(id, &mem)) {
    assert(mem.refcount < UINT_MAX);
    ++mem.refcount;
    entries_.Insert(id, mem);
    return true;
  } else {
    return false;
  }
}

bool MemoryKvStore::Unref(const shash::Any &id) {
  WriteLockGuard guard(rwlock_);
  MemoryBuffer mem;
  if (entries_.Lookup(id, &mem)) {
    assert(mem.refcount > 0);
    --mem.refcount;
    entries_.Insert(id, mem);
    return true;
  } else {
    return false;
  }
}

int64_t MemoryKvStore::Read(
  const shash::Any &id,
  void *buf,
  size_t size,
  size_t offset
) {
  MemoryBuffer mem;
  ReadLockGuard guard(rwlock_);
  if (entries_.Lookup(id, &mem)) {
    if (offset > mem.size) return 0;
    uint64_t copy_size = min(mem.size - offset, size);
    memcpy(buf, static_cast<char *>(mem.address) + offset, copy_size);
    return copy_size;
  } else {
    return -ENOENT;
  }
}

bool MemoryKvStore::Commit(
  const shash::Any &id,
  const kvstore::MemoryBuffer &buf
) {
  WriteLockGuard guard(rwlock_);
  MemoryBuffer mem;
  if (entries_.Lookup(id, &mem)) {
    if (!DoDelete(id)) return false;
  }
  entries_.Insert(id, buf);
  used_bytes_ += buf.size;
  return true;
}

bool MemoryKvStore::Delete(const shash::Any &id) {
  WriteLockGuard guard(rwlock_);
  return DoDelete(id);
}

bool MemoryKvStore::DoDelete(const shash::Any &id) {
  MemoryBuffer buf;
  if (entries_.Lookup(id, &buf)) {
    if (buf.refcount > 0) return false;
    used_bytes_ -= buf.size;
    free(buf.address);
    entries_.Forget(id);
  }
  return true;
}

bool MemoryKvStore::ShrinkTo(size_t size) {
  WriteLockGuard guard(rwlock_);
  shash::Any key;
  MemoryBuffer buf;

  if (used_bytes_ <= size) return true;

  entries_.FilterBegin();
  while (entries_.FilterNext()) {
    if (used_bytes_ <= size) break;
    entries_.FilterGet(&key, &buf);
    if (buf.refcount > 0) continue;
    entries_.FilterDelete();
    used_bytes_ -= buf.size;
    free(buf.address);
  }
  entries_.FilterEnd();
  return used_bytes_ <= size;
}

}  // namespace kvstore
<commit_msg>Allow commits to replace kvstore entries<commit_after>/**
 * This file is part of the CernVM File System.
 */

#include "kvstore.h"

#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <string.h>

#include <algorithm>

#include "util_concurrency.h"

using namespace std;  // NOLINT

namespace kvstore {

bool MemoryKvStore::GetBuffer(const shash::Any &id, MemoryBuffer *buf) {
  return entries_.Lookup(id, buf);
}

bool MemoryKvStore::PopBuffer(const shash::Any &id, MemoryBuffer *buf) {
  WriteLockGuard guard(rwlock_);
  if (!entries_.Lookup(id, buf)) return false;
  used_bytes_ -= (*buf).size;
  entries_.Forget(id);
  return true;
}

int64_t MemoryKvStore::GetSize(const shash::Any &id) {
  MemoryBuffer mem;
  if (entries_.Lookup(id, &mem)) {
    return mem.size;
  } else {
    return -ENOENT;
  }
}

int64_t MemoryKvStore::GetRefcount(const shash::Any &id) {
  MemoryBuffer mem;
  if (entries_.Lookup(id, &mem)) {
    return mem.refcount;
  } else {
    return -ENOENT;
  }
}

bool MemoryKvStore::IncRef(const shash::Any &id) {
  WriteLockGuard guard(rwlock_);
  MemoryBuffer mem;
  if (entries_.Lookup(id, &mem)) {
    assert(mem.refcount < UINT_MAX);
    ++mem.refcount;
    entries_.Insert(id, mem);
    return true;
  } else {
    return false;
  }
}

bool MemoryKvStore::Unref(const shash::Any &id) {
  WriteLockGuard guard(rwlock_);
  MemoryBuffer mem;
  if (entries_.Lookup(id, &mem)) {
    assert(mem.refcount > 0);
    --mem.refcount;
    entries_.Insert(id, mem);
    return true;
  } else {
    return false;
  }
}

int64_t MemoryKvStore::Read(
  const shash::Any &id,
  void *buf,
  size_t size,
  size_t offset
) {
  MemoryBuffer mem;
  ReadLockGuard guard(rwlock_);
  if (entries_.Lookup(id, &mem)) {
    if (offset > mem.size) return 0;
    uint64_t copy_size = min(mem.size - offset, size);
    memcpy(buf, static_cast<char *>(mem.address) + offset, copy_size);
    return copy_size;
  } else {
    return -ENOENT;
  }
}

bool MemoryKvStore::Commit(
  const shash::Any &id,
  const kvstore::MemoryBuffer &buf
) {
  bool overwrote = false;
  MemoryBuffer mem;
  WriteLockGuard guard(rwlock_);
  if (entries_.Lookup(id, &mem)) {
    used_bytes_ -= mem.size;
    overwrote = true;
  } else {
    mem.refcount = buf.refcount;
  }
  mem.address = buf.address;
  mem.size = buf.size;
  mem.object_type = buf.object_type;
  entries_.Insert(id, mem);
  used_bytes_ += mem.size;
  return overwrote;
}

bool MemoryKvStore::Delete(const shash::Any &id) {
  WriteLockGuard guard(rwlock_);
  return DoDelete(id);
}

bool MemoryKvStore::DoDelete(const shash::Any &id) {
  MemoryBuffer buf;
  if (entries_.Lookup(id, &buf)) {
    if (buf.refcount > 0) return false;
    used_bytes_ -= buf.size;
    free(buf.address);
    entries_.Forget(id);
  }
  return true;
}

bool MemoryKvStore::ShrinkTo(size_t size) {
  WriteLockGuard guard(rwlock_);
  shash::Any key;
  MemoryBuffer buf;

  if (used_bytes_ <= size) return true;

  entries_.FilterBegin();
  while (entries_.FilterNext()) {
    if (used_bytes_ <= size) break;
    entries_.FilterGet(&key, &buf);
    if (buf.refcount > 0) continue;
    entries_.FilterDelete();
    used_bytes_ -= buf.size;
    free(buf.address);
  }
  entries_.FilterEnd();
  return used_bytes_ <= size;
}

}  // namespace kvstore
<|endoftext|>


<commit_before><commit_msg>added visualflags margin<commit_after><|endoftext|>


<commit_before><commit_msg>make xDigitalWrite a bit shorter<commit_after><|endoftext|>


<commit_before><commit_msg>Добавлена проверка успешного создания манифеста.<commit_after><|endoftext|>


<commit_before><commit_msg>initial multiplier support in calibration<commit_after><|endoftext|>


<commit_before>#include "DisplayContact.h"
#include <QElapsedTimer>
#include <QDebug>
#include "VCardParser.h"

DisplayContact::DisplayContact(const Contact & a_Contact):
	m_Contact(a_Contact)
{
}

std::shared_ptr<DisplayContact> DisplayContact::fromContact(const Contact & a_Contact)
{
	QElapsedTimer timer;
	timer.start();

	std::shared_ptr<DisplayContact> res(new DisplayContact(a_Contact));

	for (const auto & s: a_Contact.sentences())
	{
		if (s.m_Key == "fn")
		{
			res->m_DisplayName = s.m_Value;
		}
		else if (s.m_Key == "n")
		{
			res->addNameItem(s);
		}
		else if (s.m_Key == "tel")
		{
			res->addTelItem(s);
		}
		else if (s.m_Key == "email")
		{
			res->addEmailItem(s);
		}
	}

	qDebug() << __FUNCTION__ << ": took " << timer.elapsed() << " msec.";

	return res;
}

void DisplayContact::addNameItem(const Contact::Sentence & a_NameSentence)
{
	auto components = VCardParser::breakValueIntoParts(a_NameSentence.m_Value);
	while (components.size() < 5)
	{
		components.push_back({});
	}
	const auto & lastNames = components[0];
	const auto & firstNames = components[1];
	const auto & middleNames = components[2];
	const auto & prefixes = components[3];
	const auto & suffixes = components[4];

	auto name = composeName(firstNames, middleNames, lastNames, prefixes, suffixes);
	addItem(nullptr, tr("Name"), {name});
}

void DisplayContact::addTelItem(const Contact::Sentence & a_TelSentence)
{
	// Decide the base type:
	QString type(tr("Other", "Phone"));
	if (isType(a_TelSentence.m_Params, "home"))
	{
		type = tr("Home", "Phone");
	}
	else if (isType(a_TelSentence.m_Params, "work"))
	{
		type = tr("Work", "Phone");
	}
	else if (
		isType(a_TelSentence.m_Params, "mobile") ||
		isType(a_TelSentence.m_Params, "cell")
	)
	{
		type = tr("Mobile", "Phone");
	}

	// If it is a fax number, add that info to the label:
	if (isType(a_TelSentence.m_Params, "fax"))
	{
		type = tr("%1 fax").arg(type);
	}

	addItem(icoTel(), type, {a_TelSentence.m_Value});
}

void DisplayContact::addEmailItem(const Contact::Sentence & a_EmailSentence)
{
	// Decide the base type:
	QString type(tr("Other", "Email"));
	if (isType(a_EmailSentence.m_Params, "home"))
	{
		type = tr("Home", "Email");
	}
	else if (isType(a_EmailSentence.m_Params, "work"))
	{
		type = tr("Work", "Email");
	}
	else if (
		isType(a_EmailSentence.m_Params, "mobile") ||
		isType(a_EmailSentence.m_Params, "cell")
	)
	{
		type = tr("Mobile", "Email");
	}

	addItem(icoEmail(), type, {a_EmailSentence.m_Value});
}

void DisplayContact::addItem(const QIcon * a_Icon, const QString & a_Label, const std::vector<QString> & a_Values)
{
	m_Items.emplace_back(new Item(a_Icon, a_Label, a_Values));
}

QString DisplayContact::composeName(
	const std::vector<QByteArray> & a_FirstNames,
	const std::vector<QByteArray> & a_MiddleNames,
	const std::vector<QByteArray> & a_LastNames,
	const std::vector<QByteArray> & a_Prefixes,
	const std::vector<QByteArray> & a_Suffixes
)
{
	QString res;
	for (const auto & s: a_Prefixes)
	{
		if ((res.length() > 0) && !res.at(res.length() - 1).isSpace())
		{
			res.append(" ");
		}
		res.append(QString::fromUtf8(s));
	}
	for (const auto & s: a_FirstNames)
	{
		if ((res.length() > 0) && !res.at(res.length() - 1).isSpace())
		{
			res.append(" ");
		}
		res.append(QString::fromUtf8(s));
	}
	for (const auto & s: a_MiddleNames)
	{
		if ((res.length() > 0) && !res.at(res.length() - 1).isSpace())
		{
			res.append(" ");
		}
		res.append(QString::fromUtf8(s));
	}
	for (const auto & s: a_LastNames)
	{
		if ((res.length() > 0) && !res.at(res.length() - 1).isSpace())
		{
			res.append(" ");
		}
		res.append(QString::fromUtf8(s));
	}

	if (!a_Suffixes.empty() && !a_Suffixes[0].isEmpty())
	{
		res.append(",");
	}
	for (const auto & s: a_Suffixes)
	{
		if ((res.length() > 0) && !res.at(res.length() - 1).isSpace())
		{
			res.append(" ");
		}
		res.append(QString::fromUtf8(s));
	}
	return res;
}

bool DisplayContact::isType(const Contact::SentenceParams & a_SentenceParams, const QByteArray & a_LcType)
{
	for (const auto & p: a_SentenceParams)
	{
		if ((p.m_Values.empty() || p.m_Values[0].isEmpty()) && (p.m_Name.toLower() == a_LcType))
		{
			// The sentence has a simple value-less parameter ("TEL;HOME:...")
			return true;
		}
		if (p.m_Name == "type")
		{
			for (const auto & v: p.m_Values)
			{
				if (v.toLower() == a_LcType)
				{
					return true;
				}
			}
		}
	}
	return false;
}

QIcon * DisplayContact::icoTel()
{
	static QIcon ico{":/res/Phone.png"};
	return &ico;
}

QIcon * DisplayContact::icoEmail()
{
	static QIcon ico(":/res/Email.png");
	return &ico;
}

<commit_msg>DisplayContact: Remove timing info.<commit_after>#include "DisplayContact.h"
#include "VCardParser.h"

DisplayContact::DisplayContact(const Contact & a_Contact):
	m_Contact(a_Contact)
{
}

std::shared_ptr<DisplayContact> DisplayContact::fromContact(const Contact & a_Contact)
{
	std::shared_ptr<DisplayContact> res(new DisplayContact(a_Contact));

	for (const auto & s: a_Contact.sentences())
	{
		if (s.m_Key == "fn")
		{
			res->m_DisplayName = s.m_Value;
		}
		else if (s.m_Key == "n")
		{
			res->addNameItem(s);
		}
		else if (s.m_Key == "tel")
		{
			res->addTelItem(s);
		}
		else if (s.m_Key == "email")
		{
			res->addEmailItem(s);
		}
	}
	return res;
}

void DisplayContact::addNameItem(const Contact::Sentence & a_NameSentence)
{
	auto components = VCardParser::breakValueIntoParts(a_NameSentence.m_Value);
	while (components.size() < 5)
	{
		components.push_back({});
	}
	const auto & lastNames = components[0];
	const auto & firstNames = components[1];
	const auto & middleNames = components[2];
	const auto & prefixes = components[3];
	const auto & suffixes = components[4];

	auto name = composeName(firstNames, middleNames, lastNames, prefixes, suffixes);
	addItem(nullptr, tr("Name"), {name});
}

void DisplayContact::addTelItem(const Contact::Sentence & a_TelSentence)
{
	// Decide the base type:
	QString type(tr("Other", "Phone"));
	if (isType(a_TelSentence.m_Params, "home"))
	{
		type = tr("Home", "Phone");
	}
	else if (isType(a_TelSentence.m_Params, "work"))
	{
		type = tr("Work", "Phone");
	}
	else if (
		isType(a_TelSentence.m_Params, "mobile") ||
		isType(a_TelSentence.m_Params, "cell")
	)
	{
		type = tr("Mobile", "Phone");
	}

	// If it is a fax number, add that info to the label:
	if (isType(a_TelSentence.m_Params, "fax"))
	{
		type = tr("%1 fax").arg(type);
	}

	addItem(icoTel(), type, {a_TelSentence.m_Value});
}

void DisplayContact::addEmailItem(const Contact::Sentence & a_EmailSentence)
{
	// Decide the base type:
	QString type(tr("Other", "Email"));
	if (isType(a_EmailSentence.m_Params, "home"))
	{
		type = tr("Home", "Email");
	}
	else if (isType(a_EmailSentence.m_Params, "work"))
	{
		type = tr("Work", "Email");
	}
	else if (
		isType(a_EmailSentence.m_Params, "mobile") ||
		isType(a_EmailSentence.m_Params, "cell")
	)
	{
		type = tr("Mobile", "Email");
	}

	addItem(icoEmail(), type, {a_EmailSentence.m_Value});
}

void DisplayContact::addItem(const QIcon * a_Icon, const QString & a_Label, const std::vector<QString> & a_Values)
{
	m_Items.emplace_back(new Item(a_Icon, a_Label, a_Values));
}

QString DisplayContact::composeName(
	const std::vector<QByteArray> & a_FirstNames,
	const std::vector<QByteArray> & a_MiddleNames,
	const std::vector<QByteArray> & a_LastNames,
	const std::vector<QByteArray> & a_Prefixes,
	const std::vector<QByteArray> & a_Suffixes
)
{
	QString res;
	for (const auto & s: a_Prefixes)
	{
		if ((res.length() > 0) && !res.at(res.length() - 1).isSpace())
		{
			res.append(" ");
		}
		res.append(QString::fromUtf8(s));
	}
	for (const auto & s: a_FirstNames)
	{
		if ((res.length() > 0) && !res.at(res.length() - 1).isSpace())
		{
			res.append(" ");
		}
		res.append(QString::fromUtf8(s));
	}
	for (const auto & s: a_MiddleNames)
	{
		if ((res.length() > 0) && !res.at(res.length() - 1).isSpace())
		{
			res.append(" ");
		}
		res.append(QString::fromUtf8(s));
	}
	for (const auto & s: a_LastNames)
	{
		if ((res.length() > 0) && !res.at(res.length() - 1).isSpace())
		{
			res.append(" ");
		}
		res.append(QString::fromUtf8(s));
	}

	if (!a_Suffixes.empty() && !a_Suffixes[0].isEmpty())
	{
		res.append(",");
	}
	for (const auto & s: a_Suffixes)
	{
		if ((res.length() > 0) && !res.at(res.length() - 1).isSpace())
		{
			res.append(" ");
		}
		res.append(QString::fromUtf8(s));
	}
	return res;
}

bool DisplayContact::isType(const Contact::SentenceParams & a_SentenceParams, const QByteArray & a_LcType)
{
	for (const auto & p: a_SentenceParams)
	{
		if ((p.m_Values.empty() || p.m_Values[0].isEmpty()) && (p.m_Name.toLower() == a_LcType))
		{
			// The sentence has a simple value-less parameter ("TEL;HOME:...")
			return true;
		}
		if (p.m_Name == "type")
		{
			for (const auto & v: p.m_Values)
			{
				if (v.toLower() == a_LcType)
				{
					return true;
				}
			}
		}
	}
	return false;
}

QIcon * DisplayContact::icoTel()
{
	static QIcon ico{":/res/Phone.png"};
	return &ico;
}

QIcon * DisplayContact::icoEmail()
{
	static QIcon ico(":/res/Email.png");
	return &ico;
}

<|endoftext|>


<commit_before>#include "proxy/DataCollector.h"
#include "object/object.h"

#include <map>

namespace aten {
	void DataCollector::collect(
		std::vector<aten::ShapeParameter>& shapeparams,
		std::vector<aten::PrimitiveParamter>& primparams,
		std::vector<aten::LightParameter>& lightparams,
		std::vector<aten::MaterialParameter>& mtrlparms,
		std::vector<aten::vertex>& vtxparams)
	{
		const auto& shapes = aten::transformable::getShapes();

		int order = 0;
		std::map<transformable*, int> orderMap;

		for (auto s : shapes) {
			auto type = s->getParam().type;

			switch (type) {
			case ShapeType::Polygon:
			{
				auto param = s->getParam();
				shapeparams.push_back(param);

				const int primcnt = primparams.size();

				if (primcnt <= param.primid) {
					primparams.resize(primparams.size() + param.primid + param.primnum);
				}

				s->getPrimitives(&primparams[param.primid]);

				orderMap.insert(std::pair<transformable*, int>(s, order++));
			}
				break;
			case ShapeType::Sphere:
			case ShapeType::Cube:
			{
				auto param = s->getParam();
				param.mtrl.idx = aten::material::findMaterialIdx((aten::material*)param.mtrl.ptr);
				shapeparams.push_back(param);

				orderMap.insert(std::pair<transformable*, int>(s, order++));
			}
				break;
			default:
				break;
			}
		}

		// Not gurantee order of the object which the instance has.
		for (auto s : shapes) {
			auto type = s->getParam().type;

			if (type == ShapeType::Instance) {
				auto param = s->getParam();
				auto obj = s->getHasObject();

				auto it = orderMap.find((transformable*)(obj));
				AT_ASSERT(it != orderMap.end());

				// Specify the index of the object which the instance has.
				param.shapeid = it->second;

				param.area = it->first->getParam().area;

				shapeparams.push_back(param);
			}
		}

		const auto& lights = aten::Light::getLights();

		for (auto l : lights) {
			auto param = l->param();
			lightparams.push_back(param);
		}

		const auto& mtrls = aten::material::getMaterials();

		for (auto m : mtrls) {
			mtrlparms.push_back(m->param());
		}

		const auto& faces = aten::face::faces();

		for (auto f : faces) {
			primparams.push_back(f->param);
		}

		const auto& vtxs = aten::VertexManager::getVertices();

		for (auto v : vtxs) {
			vtxparams.push_back(v);
		}
	}
}<commit_msg>Fix a bug about timing to register parameters.<commit_after>#include "proxy/DataCollector.h"
#include "object/object.h"

#include <map>

namespace aten {
	void DataCollector::collect(
		std::vector<aten::ShapeParameter>& shapeparams,
		std::vector<aten::PrimitiveParamter>& primparams,
		std::vector<aten::LightParameter>& lightparams,
		std::vector<aten::MaterialParameter>& mtrlparms,
		std::vector<aten::vertex>& vtxparams)
	{
		const auto& shapes = aten::transformable::getShapes();

		int order = 0;
		std::map<transformable*, int> orderMap;

		for (auto s : shapes) {
			auto type = s->getParam().type;

			switch (type) {
			case ShapeType::Polygon:
			{
				auto param = s->getParam();

				const int primcnt = primparams.size();

				if (primcnt <= param.primid) {
					primparams.resize(primparams.size() + param.primid + param.primnum);
				}

				s->getPrimitives(&primparams[param.primid]);

				orderMap.insert(std::pair<transformable*, int>(s, order++));
			}
				break;
			case ShapeType::Sphere:
			case ShapeType::Cube:
			{
				orderMap.insert(std::pair<transformable*, int>(s, order++));
			}
				break;
			default:
				break;
			}
		}

		// Not gurantee order of the object which the instance has.
		for (auto s : shapes) {
			auto type = s->getParam().type;

			if (type == ShapeType::Instance) {
				auto param = s->getParam();
				auto obj = s->getHasObject();

				auto it = orderMap.find((transformable*)(obj));
				AT_ASSERT(it != orderMap.end());

				// Specify the index of the object which the instance has.
				param.shapeid = it->second;

				param.area = it->first->getParam().area;

				shapeparams.push_back(param);
			}
			else if (type == ShapeType::Polygon) {
				auto param = s->getParam();
				shapeparams.push_back(param);
			}
			else if (type == ShapeType::Sphere
				|| type == ShapeType::Cube)
			{
				auto param = s->getParam();
				param.mtrl.idx = aten::material::findMaterialIdx((aten::material*)param.mtrl.ptr);
				shapeparams.push_back(param);
			}
		}

		const auto& lights = aten::Light::getLights();

		for (auto l : lights) {
			auto param = l->param();
			lightparams.push_back(param);
		}

		const auto& mtrls = aten::material::getMaterials();

		for (auto m : mtrls) {
			mtrlparms.push_back(m->param());
		}

		const auto& faces = aten::face::faces();

		for (auto f : faces) {
			primparams.push_back(f->param);
		}

		const auto& vtxs = aten::VertexManager::getVertices();

		for (auto v : vtxs) {
			vtxparams.push_back(v);
		}
	}
}<|endoftext|>


<commit_before>#include "FAST/Tests/catch.hpp"
#include "TubeSegmentationAndCenterlineExtraction.hpp"
#include "FAST/Importers/ImageFileImporter.hpp"
#include "FAST/Visualization/SliceRenderer/SliceRenderer.hpp"
#include "FAST/Visualization/LineRenderer/LineRenderer.hpp"
#include "FAST/Algorithms/SurfaceExtraction/SurfaceExtraction.hpp"
#include "FAST/Visualization/MeshRenderer/MeshRenderer.hpp"
#include "FAST/Visualization/SimpleWindow.hpp"
#include "FAST/Algorithms/ImageCropper/ImageCropper.hpp"

namespace fast {

/*
TEST_CASE("TSF", "[tsf]") {
    ImageFileImporter::pointer importer = ImageFileImporter::New();
    importer->setFilename("/home/smistad/Dropbox/Programmering/Tube-Segmentation-Framework/tests/data/synthetic/dataset_1/noisy.mhd");

    TubeSegmentationAndCenterlineExtraction::pointer tubeExtraction = TubeSegmentationAndCenterlineExtraction::New();
    tubeExtraction->setInputConnection(importer->getOutputPort());
    tubeExtraction->extractBrightTubes();
    tubeExtraction->setMinimumRadius(0.5);
    tubeExtraction->setMaximumRadius(8);
    tubeExtraction->setSensitivity(0.99);

    SliceRenderer::pointer renderer = SliceRenderer::New();
    renderer->setInputConnection(tubeExtraction->getTDFOutputPort());

    LineRenderer::pointer lineRenderer = LineRenderer::New();
    lineRenderer->addInputConnection(tubeExtraction->getCenterlineOutputPort());
    lineRenderer->setDefaultDrawOnTop(true);

    SurfaceExtraction::pointer surfaceExtraction = SurfaceExtraction::New();
    surfaceExtraction->setInputConnection(tubeExtraction->getSegmentationOutputPort());

    MeshRenderer::pointer meshRenderer = MeshRenderer::New();
    meshRenderer->addInputConnection(surfaceExtraction->getOutputPort());

    SimpleWindow::pointer window = SimpleWindow::New();
    window->addRenderer(renderer);
    window->addRenderer(meshRenderer);
    window->addRenderer(lineRenderer);
    window->start();
}
*/

TEST_CASE("TSF Airway", "[tsf][airway][visual]") {
    //Report::setReportMethod(Report::COUT);
    ImageFileImporter::pointer importer = ImageFileImporter::New();
    importer->setFilename(std::string(FAST_TEST_DATA_DIR) + "CT-Thorax.mhd");

    ImageCropper::pointer cropper = ImageCropper::New();
    cropper->setOffset(Vector3ui(56, 119, 155));
    cropper->setSize(Vector3ui(400, 232, 509));
    cropper->setInputConnection(importer->getOutputPort());

    TubeSegmentationAndCenterlineExtraction::pointer tubeExtraction = TubeSegmentationAndCenterlineExtraction::New();
    tubeExtraction->setInputConnection(cropper->getOutputPort());
    tubeExtraction->extractDarkTubes();
    tubeExtraction->setMinimumIntensity(-1024);
    tubeExtraction->setMaximumIntensity(100);
    tubeExtraction->setMinimumRadius(0.5);
    tubeExtraction->setMaximumRadius(50);
    tubeExtraction->setSensitivity(0.8);

    SliceRenderer::pointer renderer = SliceRenderer::New();
    renderer->setInputConnection(importer->getOutputPort());

    LineRenderer::pointer lineRenderer = LineRenderer::New();
    lineRenderer->addInputConnection(tubeExtraction->getCenterlineOutputPort());
    lineRenderer->setDefaultDrawOnTop(true);

    SurfaceExtraction::pointer surfaceExtraction = SurfaceExtraction::New();
    surfaceExtraction->setInputConnection(tubeExtraction->getSegmentationOutputPort());

    MeshRenderer::pointer meshRenderer = MeshRenderer::New();
    meshRenderer->addInputConnection(surfaceExtraction->getOutputPort());

    SimpleWindow::pointer window = SimpleWindow::New();
    window->addRenderer(renderer);
    window->addRenderer(meshRenderer);
    window->addRenderer(lineRenderer);
    window->setTimeout(3*1000);
    window->start();
}

}
<commit_msg>added broken on mac tag to test<commit_after>#include "FAST/Tests/catch.hpp"
#include "TubeSegmentationAndCenterlineExtraction.hpp"
#include "FAST/Importers/ImageFileImporter.hpp"
#include "FAST/Visualization/SliceRenderer/SliceRenderer.hpp"
#include "FAST/Visualization/LineRenderer/LineRenderer.hpp"
#include "FAST/Algorithms/SurfaceExtraction/SurfaceExtraction.hpp"
#include "FAST/Visualization/MeshRenderer/MeshRenderer.hpp"
#include "FAST/Visualization/SimpleWindow.hpp"
#include "FAST/Algorithms/ImageCropper/ImageCropper.hpp"

namespace fast {

/*
TEST_CASE("TSF", "[tsf]") {
    ImageFileImporter::pointer importer = ImageFileImporter::New();
    importer->setFilename("/home/smistad/Dropbox/Programmering/Tube-Segmentation-Framework/tests/data/synthetic/dataset_1/noisy.mhd");

    TubeSegmentationAndCenterlineExtraction::pointer tubeExtraction = TubeSegmentationAndCenterlineExtraction::New();
    tubeExtraction->setInputConnection(importer->getOutputPort());
    tubeExtraction->extractBrightTubes();
    tubeExtraction->setMinimumRadius(0.5);
    tubeExtraction->setMaximumRadius(8);
    tubeExtraction->setSensitivity(0.99);

    SliceRenderer::pointer renderer = SliceRenderer::New();
    renderer->setInputConnection(tubeExtraction->getTDFOutputPort());

    LineRenderer::pointer lineRenderer = LineRenderer::New();
    lineRenderer->addInputConnection(tubeExtraction->getCenterlineOutputPort());
    lineRenderer->setDefaultDrawOnTop(true);

    SurfaceExtraction::pointer surfaceExtraction = SurfaceExtraction::New();
    surfaceExtraction->setInputConnection(tubeExtraction->getSegmentationOutputPort());

    MeshRenderer::pointer meshRenderer = MeshRenderer::New();
    meshRenderer->addInputConnection(surfaceExtraction->getOutputPort());

    SimpleWindow::pointer window = SimpleWindow::New();
    window->addRenderer(renderer);
    window->addRenderer(meshRenderer);
    window->addRenderer(lineRenderer);
    window->start();
}
*/

TEST_CASE("TSF Airway", "[tsf][airway][visual][broken_on_mac]") {
    //Report::setReportMethod(Report::COUT);
    ImageFileImporter::pointer importer = ImageFileImporter::New();
    importer->setFilename(std::string(FAST_TEST_DATA_DIR) + "CT-Thorax.mhd");

    ImageCropper::pointer cropper = ImageCropper::New();
    cropper->setOffset(Vector3ui(56, 119, 155));
    cropper->setSize(Vector3ui(400, 232, 509));
    cropper->setInputConnection(importer->getOutputPort());

    TubeSegmentationAndCenterlineExtraction::pointer tubeExtraction = TubeSegmentationAndCenterlineExtraction::New();
    tubeExtraction->setInputConnection(cropper->getOutputPort());
    tubeExtraction->extractDarkTubes();
    tubeExtraction->setMinimumIntensity(-1024);
    tubeExtraction->setMaximumIntensity(100);
    tubeExtraction->setMinimumRadius(0.5);
    tubeExtraction->setMaximumRadius(50);
    tubeExtraction->setSensitivity(0.8);

    SliceRenderer::pointer renderer = SliceRenderer::New();
    renderer->setInputConnection(importer->getOutputPort());

    LineRenderer::pointer lineRenderer = LineRenderer::New();
    lineRenderer->addInputConnection(tubeExtraction->getCenterlineOutputPort());
    lineRenderer->setDefaultDrawOnTop(true);

    SurfaceExtraction::pointer surfaceExtraction = SurfaceExtraction::New();
    surfaceExtraction->setInputConnection(tubeExtraction->getSegmentationOutputPort());

    MeshRenderer::pointer meshRenderer = MeshRenderer::New();
    meshRenderer->addInputConnection(surfaceExtraction->getOutputPort());

    SimpleWindow::pointer window = SimpleWindow::New();
    window->addRenderer(renderer);
    window->addRenderer(meshRenderer);
    window->addRenderer(lineRenderer);
    window->setTimeout(3*1000);
    window->start();
}

}
<|endoftext|>


<commit_before>/**
 *  Copyright (c) 2014-present, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed in accordance with the terms specified in
 *  the LICENSE file found in the root directory of this source tree.
 */

#include <osquery/core.h>
#include <osquery/filesystem/filesystem.h>
#include <osquery/system.h>

#include <thrift/lib/cpp/async/TAsyncSocket.h>
#include <thrift/lib/cpp2/async/HeaderClientChannel.h>
#include <thrift/lib/cpp2/server/ThriftServer.h>

// Include intermediate Thrift-generated interface definitions.
#include "osquery/gen-cpp2/Extension.h"
#include "osquery/gen-cpp2/ExtensionManager.h"

#include "osquery/extensions/interface.h"

namespace osquery {

using namespace extensions;

class ExtensionHandler : virtual public extensions::ExtensionSvIf,
                         public ExtensionInterface {
 public:
  ExtensionHandler() : ExtensionInterface(0) {}
  explicit ExtensionHandler(RouteUUID uuid) : ExtensionInterface(uuid) {}

 public:
  using ExtensionInterface::ping;
  void ping(ExtensionStatus& _return) override;

  using ExtensionInterface::call;
  void call(ExtensionResponse& _return,
            const std::string& registry,
            const std::string& item,
            const ExtensionPluginRequest& request) override;

  using ExtensionInterface::shutdown;
  void shutdown() override;

 protected:
  /// UUID accessor.
  RouteUUID getUUID() const;
};

class ExtensionManagerHandler : virtual public extensions::ExtensionManagerSvIf,
                                public ExtensionManagerInterface,
                                public ExtensionHandler {
 public:
  ExtensionManagerHandler() = default;

 public:
  using ExtensionManagerInterface::extensions;
  void extensions(InternalExtensionList& _return) override;

  using ExtensionManagerInterface::options;
  void options(InternalOptionList& _return) override;

  using ExtensionManagerInterface::registerExtension;
  void registerExtension(ExtensionStatus& _return,
                         const InternalExtensionInfo& info,
                         const ExtensionRegistry& registry) override;

  using ExtensionManagerInterface::deregisterExtension;
  void deregisterExtension(ExtensionStatus& _return,
                           const ExtensionRouteUUID uuid) override;

  using ExtensionManagerInterface::query;
  void query(ExtensionResponse& _return, const std::string& sql) override;

  using ExtensionManagerInterface::getQueryColumns;
  void getQueryColumns(ExtensionResponse& _return,
                       const std::string& sql) override;
};

struct ImplExtensionRunner {
  std::unique_ptr<apache::thrift::ThriftServer> server;
  std::shared_ptr<ExtensionHandler> handler;

  /// Raw socket descriptor.
  int sd;
};

struct ImplExtensionClient {
  folly::EventBase base;

  std::unique_ptr<extensions::ExtensionAsyncClient> e;
  std::unique_ptr<extensions::ExtensionManagerAsyncClient> em;

  /// Raw socket descriptor.
  int sd;
};

void ExtensionHandler::ping(ExtensionStatus& _return) {
  auto s = ExtensionInterface::ping();
  _return.code = (int)extensions::ExtensionCode::EXT_SUCCESS;
  _return.uuid = s.getCode();
  _return.message = s.getMessage();
}

void ExtensionHandler::call(ExtensionResponse& _return,
                            const std::string& registry,
                            const std::string& item,
                            const ExtensionPluginRequest& request) {
  PluginRequest plugin_request;
  for (const auto& request_item : request) {
    // Create a PluginRequest from an ExtensionPluginRequest.
    plugin_request[request_item.first] = request_item.second;
  }

  PluginResponse response;
  auto s = ExtensionInterface::call(registry, item, plugin_request, response);
  _return.status.code = s.getCode();
  _return.status.message = s.getMessage();
  _return.status.uuid = getUUID();

  if (s.ok()) {
    for (const auto& response_item : response) {
      // Translate a PluginResponse to an ExtensionPluginResponse.
      _return.response.push_back(response_item);
    }
  }
}

void ExtensionHandler::shutdown() {}

RouteUUID ExtensionHandler::getUUID() const {
  return uuid_;
}

void ExtensionManagerHandler::extensions(InternalExtensionList& _return) {
  //_return = ExtensionManagerInterface::extensions();
  auto extensions = ExtensionManagerInterface::extensions();
  for (const auto& extension : extensions) {
    auto& ext = _return[extension.first];
    ext.min_sdk_version = extension.second.min_sdk_version;
    ext.version = extension.second.version;
    ext.sdk_version = extension.second.sdk_version;
    ext.name = extension.second.name;
  }
}

void ExtensionManagerHandler::options(InternalOptionList& _return) {
  auto options = ExtensionManagerInterface::options();
  for (const auto& option : options) {
    _return[option.first].value = option.second.value;
    _return[option.first].default_value = option.second.default_value;
    _return[option.first].type = option.second.type;
  }
}

void ExtensionManagerHandler::registerExtension(
    ExtensionStatus& _return,
    const InternalExtensionInfo& info,
    const ExtensionRegistry& registry) {
  ExtensionRegistry er;
  for (const auto& rt : registry) {
    er[rt.first] = rt.second;
  }

  RouteUUID uuid;
  auto s = ExtensionManagerInterface::registerExtension(
      {info.name, info.version, info.sdk_version, info.min_sdk_version},
      er,
      uuid);
  _return.message = s.getMessage();
  if (s.ok()) {
    _return.code = (int)extensions::ExtensionCode::EXT_SUCCESS;
    _return.uuid = uuid;
  } else {
    _return.code = (int)extensions::ExtensionCode::EXT_FAILED;
  }
}

void ExtensionManagerHandler::deregisterExtension(
    ExtensionStatus& _return, const ExtensionRouteUUID uuid) {
  auto s = ExtensionManagerInterface::deregisterExtension(uuid);
  _return.message = s.getMessage();
  if (s.ok()) {
    _return.code = (int)extensions::ExtensionCode::EXT_SUCCESS;
    _return.uuid = getUUID();
  } else {
    _return.code = (int)extensions::ExtensionCode::EXT_FAILED;
  }
}

void ExtensionManagerHandler::query(ExtensionResponse& _return,
                                    const std::string& sql) {
  QueryData qd;
  auto s = ExtensionManagerInterface::query(sql, qd);
  for (auto& row : qd) {
    _return.response.emplace_back(std::move(row));
  }
  _return.status.message = s.getMessage();
  if (s.ok()) {
    _return.status.code = (int)extensions::ExtensionCode::EXT_SUCCESS;
    _return.status.uuid = getUUID();
  } else {
    _return.status.code = (int)extensions::ExtensionCode::EXT_FAILED;
  }
}

void ExtensionManagerHandler::getQueryColumns(ExtensionResponse& _return,
                                              const std::string& sql) {
  QueryData qd;
  auto s = ExtensionManagerInterface::getQueryColumns(sql, qd);
  for (auto& row : qd) {
    _return.response.emplace_back(std::move(row));
  }
  _return.status.message = s.getMessage();
  if (s.ok()) {
    _return.status.code = (int)extensions::ExtensionCode::EXT_SUCCESS;
    _return.status.uuid = getUUID();
  } else {
    _return.status.code = (int)extensions::ExtensionCode::EXT_FAILED;
  }
}

ExtensionRunnerInterface::~ExtensionRunnerInterface() {
  removePath(path_);

  if (server_->sd > 0) {
    close(server_->sd);
    server_->sd = 0;
  }
};

ExtensionRunnerInterface::ExtensionRunnerInterface()
    : server_{std::make_unique<ImplExtensionRunner>()} {}

void ExtensionRunnerInterface::serve() {
  // Start the Thrift server's run loop.
  server_->server->serve();
}

void ExtensionRunnerInterface::connect() {
  server_->server = std::make_unique<apache::thrift::ThriftServer>();
  server_->server->setInterface(server_->handler);

  server_->sd = socket(AF_UNIX, SOCK_STREAM, 0);
  struct sockaddr_un addr;
  memset(&addr, 0, sizeof(addr));
  addr.sun_family = AF_UNIX;
  strncpy(addr.sun_path, path_.c_str(), sizeof(addr.sun_path) - 1);
  if (::bind(server_->sd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
    throw std::runtime_error("Cannot bind to socket");
  }
  server_->server->useExistingSocket(server_->sd);
}

void ExtensionRunnerInterface::init(RouteUUID uuid, bool manager) {
  manager_ = manager;

  // Create the thrift instances.
  if (!manager_) {
    server_->handler = std::make_shared<ExtensionHandler>(uuid);
  } else {
    server_->handler = std::make_shared<ExtensionManagerHandler>();
  }
}

void ExtensionRunnerInterface::stopServer() {
  // In most cases the service thread has started before the stop request.
  if (server_->server != nullptr) {
    server_->server->stop();
  }
}

void ExtensionRunnerInterface::stopServerManager() {
  if (server_->server != nullptr) {
    removeStalePaths(path_);
  }
}

void ExtensionClientCore::init(const std::string& path, bool manager) {
  path_ = path;
  manager_ = manager;

  client_ = std::make_unique<ImplExtensionClient>();
  client_->sd = socket(AF_UNIX, SOCK_STREAM, 0);

  struct sockaddr_un addr;
  memset(&addr, 0, sizeof(addr));
  addr.sun_family = AF_UNIX;
  strncpy(addr.sun_path, path_.c_str(), sizeof(addr.sun_path) - 1);
  if (::connect(client_->sd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
    throw std::runtime_error("Cannot connect to socket");
  }

  auto tsock(apache::thrift::async::TAsyncSocket::newSocket(&client_->base,
                                                            client_->sd));
  auto channel(apache::thrift::HeaderClientChannel::newChannel(tsock));
  channel->setProtocolId(apache::thrift::protocol::T_BINARY_PROTOCOL);
  channel->setClientType(THRIFT_UNFRAMED_DEPRECATED);

  if (!manager_) {
    client_->e = std::make_unique<ExtensionAsyncClient>(std::move(channel));
  } else {
    client_->em =
        std::make_unique<ExtensionManagerAsyncClient>(std::move(channel));
  }
}

ExtensionClientCore::~ExtensionClientCore() = default;

void ExtensionClientCore::setTimeouts(size_t /* timeouts */) {}

bool ExtensionClientCore::manager() {
  return manager_;
}

ExtensionClient::ExtensionClient(const std::string& path, size_t timeout) {
  init(path, false);
  setTimeouts(timeout);
}

ExtensionManagerClient::ExtensionManagerClient(const std::string& path,
                                               size_t timeout) {
  init(path, true);
  setTimeouts(timeout);
}

Status ExtensionClient::ping() {
  ExtensionStatus status;
  auto client = manager() ? client_->em.get() : client_->e.get();
  client->sync_ping(status);
  if (status.code != (int)extensions::ExtensionCode::EXT_FAILED) {
    return Status(0, status.message);
  }
  return Status(1);
}

Status ExtensionClient::call(const std::string& registry,
                             const std::string& item,
                             const PluginRequest& request,
                             PluginResponse& response) {
  ExtensionResponse er;
  auto client = manager() ? client_->em.get() : client_->e.get();
  client->sync_call(er, registry, item, request);
  for (const auto& r : er.response) {
    response.push_back(r);
  }

  return Status(er.status.code, er.status.message);
}

void ExtensionClient::shutdown() {
  auto client = manager() ? client_->em.get() : client_->e.get();
  client->sync_shutdown();
}

ExtensionList ExtensionManagerClient::extensions() {
  ExtensionList el;
  InternalExtensionList iel;
  client_->em->sync_extensions(iel);
  for (const auto& extension : iel) {
    auto& ext = el[extension.first];
    ext.min_sdk_version = extension.second.min_sdk_version;
    ext.version = extension.second.version;
    ext.sdk_version = extension.second.sdk_version;
    ext.name = extension.second.name;
  }
  return el;
}

OptionList ExtensionManagerClient::options() {
  OptionList ol;
  InternalOptionList iol;
  client_->em->sync_options(iol);
  for (const auto& option : iol) {
    auto& opt = option.second;
    ol[option.first] = {opt.value, opt.default_value, opt.type};
  }
  return ol;
}

Status ExtensionManagerClient::registerExtension(
    const ExtensionInfo& info,
    const ExtensionRegistry& registry,
    RouteUUID& uuid) {
  InternalExtensionInfo iei;
  iei.name = info.name;
  iei.version = info.version;
  iei.sdk_version = info.sdk_version;
  iei.min_sdk_version = info.min_sdk_version;
  ExtensionStatus status;
  client_->em->sync_registerExtension(status, iei, registry);
  uuid = status.uuid;
  return Status(status.code, status.message);
}

Status ExtensionManagerClient::query(const std::string& sql, QueryData& qd) {
  ExtensionResponse er;
  client_->em->sync_query(er, sql);
  for (const auto& row : er.response) {
    qd.push_back(row);
  }

  return Status();
}

Status ExtensionManagerClient::getQueryColumns(const std::string& sql,
                                               QueryData& qd) {
  ExtensionResponse er;
  client_->em->sync_getQueryColumns(er, sql);
  for (const auto& row : er.response) {
    qd.push_back(row);
  }

  return Status(er.status.code, er.status.message);
}

Status ExtensionManagerClient::deregisterExtension(RouteUUID uuid) {
  ExtensionStatus status;
  client_->em->sync_deregisterExtension(status, uuid);
  return Status(status.code, status.message);
}

ExtensionClient::~ExtensionClient() {}

ExtensionManagerClient::~ExtensionManagerClient() {}
} // namespace osquery
<commit_msg>osquery/extensions/impl_fbthrift.cpp are moved to fbcode/osquery/sdk<commit_after><|endoftext|>


<commit_before>#include "eval.h"
#include "catch.hpp"
#include "defs.h"

TEST_CASE("Evaluation functions work properly") {
  Board board;

  SECTION("Eval returns 0 for black and white from the start pos") {
    board.setToStartPos();

    REQUIRE(Eval::evaluate(board, WHITE) == 0);
    REQUIRE(Eval::evaluate(board, BLACK) == 0);
  }

  SECTION("White's eval is the negative of black's eval") {
    board.setToFen("rnbqkb2/pp3ppp/4pn2/3p2B1/3PP3/2N5/PPP2PPP/R2QKB1R b KQkq -");

    REQUIRE(Eval::evaluate(board, WHITE) == -Eval::evaluate(board, BLACK));
  }
}
<commit_msg>Add a full suite of tests for Eval<commit_after>#include "eval.h"
#include "catch.hpp"
#include "defs.h"

TEST_CASE("Evaluation functions work properly") {
  Eval::init();
  Board board;

  SECTION("Eval returns 0 for black and white from the start pos") {
    board.setToStartPos();

    REQUIRE(Eval::evaluate(board, WHITE) == 0);
    REQUIRE(Eval::evaluate(board, BLACK) == 0);
  }

  SECTION("White's eval is the negative of black's eval") {
    board.setToFen("rnbqkb2/pp3ppp/4pn2/3p2B1/3PP3/2N5/PPP2PPP/R2QKB1R b KQkq -");

    REQUIRE(Eval::evaluate(board, WHITE) == -Eval::evaluate(board, BLACK));
  }

  SECTION("Doubled pawn calculations are correct") {
    board.setToStartPos();
    REQUIRE(Eval::doubledPawns(board, WHITE) == 0);
    REQUIRE(Eval::doubledPawns(board, BLACK) == 0);

    // One doubled pawn for white
    board.setToFen("rnbqkbnr/pppp1ppp/8/4p3/2B1P3/4P3/PPPP2PP/RNBQK1NR b KQkq -");
    REQUIRE(Eval::doubledPawns(board, WHITE) == 1);
    REQUIRE(Eval::doubledPawns(board, BLACK) == 0);

    // Two doubled pawns for black
    board.setToFen("rnbqkbnr/1ppp2pp/1p2p3/4p3/2B1P3/8/PPPP1PPP/RNBQK1NR b KQkq -");
    REQUIRE(Eval::doubledPawns(board, WHITE) == 0);
    REQUIRE(Eval::doubledPawns(board, BLACK) == 2);

    // Three pawns on one file for white (counts as two doubled pawns)
    board.setToFen("rnbqkbnr/pppp1ppp/8/4p3/2B1P3/4P3/PPP1P1PP/RNBQK1NR b KQkq -");
    REQUIRE(Eval::doubledPawns(board, WHITE) == 2);
    REQUIRE(Eval::doubledPawns(board, BLACK) == 0);
  }

  SECTION("Isolated pawn calculations are correct") {
    board.setToStartPos();
    REQUIRE(Eval::isolatedPawns(board, WHITE) == 0);
    REQUIRE(Eval::isolatedPawns(board, BLACK) == 0);

    // One isolated pawn for white
    board.setToFen("rnbqkbnr/pppp1ppp/8/8/3pP3/2P5/PP4PP/RNBQKBNR b KQkq -");
    REQUIRE(Eval::isolatedPawns(board, WHITE) == 1);
    REQUIRE(Eval::isolatedPawns(board, BLACK) == 0);

    // Two isolated pawns for black
    board.setToFen("rnbqkbnr/pp4p1/8/8/3pP3/2P5/PP3PPP/RNBQKBNR b KQkq -");
    REQUIRE(Eval::isolatedPawns(board, WHITE) == 0);
    REQUIRE(Eval::isolatedPawns(board, BLACK) == 2);
  }

  SECTION("Backward pawn calculations are correct") {
    board.setToStartPos();
    REQUIRE(Eval::isolatedPawns(board, WHITE) == 0);
    REQUIRE(Eval::isolatedPawns(board, BLACK) == 0);

    // One backward pawn for white
    board.setToFen("rnbqkbnr/pppp1ppp/8/4p3/4P3/3P4/PPP2PPP/RNBQKBNR b KQkq -");
    REQUIRE(Eval::backwardPawns(board, WHITE) == 1);
    REQUIRE(Eval::backwardPawns(board, BLACK) == 0);

    // Two backward pawns for black
    board.setToFen("rnbqkbnr/pp4pp/3p1p2/2p1p3/4P3/8/PPPP1PPP/RNBQKBNR b KQkq -");
    REQUIRE(Eval::backwardPawns(board, WHITE) == 0);
    REQUIRE(Eval::backwardPawns(board, BLACK) == 2);
  }

  SECTION("Mobility calculations are correct") {
    board.setToStartPos();
    REQUIRE(Eval::mobility(board, WHITE) == 20);
    REQUIRE(Eval::mobility(board, BLACK) == 20);

    board.setToFen("7k/8/4b3/8/3N4/8/4P3/K7 w - -");
    REQUIRE(Eval::mobility(board, WHITE) == 12);
    REQUIRE(Eval::mobility(board, BLACK) == 14);

    board.setToFen("7k/8/8/8/4q3/8/8/K7 w - -");
    REQUIRE(Eval::mobility(board, WHITE) == 3);
    REQUIRE(Eval::mobility(board, BLACK) == 30);

    board.setToFen("7k/8/8/3Rr3/8/8/8/K7 w - -");
    REQUIRE(Eval::mobility(board, WHITE) == 14);
    REQUIRE(Eval::mobility(board, BLACK) == 14);
  }

  SECTION("Bishop pair calculations are correct") {
    board.setToStartPos();
    REQUIRE(Eval::hasBishopPair(board, WHITE));
    REQUIRE(Eval::hasBishopPair(board, BLACK));

    // White and black have one bishop on black
    board.setToFen("7k/4b3/8/8/8/2B5/8/K7 w - -");
    REQUIRE(!Eval::hasBishopPair(board, WHITE));
    REQUIRE(!Eval::hasBishopPair(board, BLACK));

    // White and black have two bishops, each on the same color
    board.setToFen("3b3k/4b3/8/8/8/2B5/3B4/K7 w - -");
    REQUIRE(!Eval::hasBishopPair(board, WHITE));
    REQUIRE(!Eval::hasBishopPair(board, BLACK));

    // White has one bishop, black has two on different colors
    board.setToFen("3bb2k/8/8/8/8/2B5/8/K7 w - -");
    REQUIRE(!Eval::hasBishopPair(board, WHITE));
    REQUIRE(Eval::hasBishopPair(board, BLACK));
  }

  SECTION("Rook on open file calculations are correct") {
    board.setToStartPos();
    REQUIRE(Eval::rooksOnOpenFiles(board, WHITE) == 0);
    REQUIRE(Eval::rooksOnOpenFiles(board, BLACK) == 0);

    // White has one rook on an open file
    board.setToFen("7k/8/8/8/8/2R5/8/K7 w - -");
    REQUIRE(Eval::rooksOnOpenFiles(board, WHITE) == 1);
    REQUIRE(Eval::rooksOnOpenFiles(board, BLACK) == 0);

    // White has one rook on a non open file, black has two on open files
    board.setToFen("1r5k/6r1/2N5/2p5/8/2R5/8/K7 w - -");
    REQUIRE(Eval::rooksOnOpenFiles(board, WHITE) == 0);
    REQUIRE(Eval::rooksOnOpenFiles(board, BLACK) == 2);
  }

  SECTION("Pawn shield calculations are correct") {
    board.setToStartPos();
    REQUIRE(Eval::pawnsShieldingKing(board, WHITE) == 3);
    REQUIRE(Eval::pawnsShieldingKing(board, BLACK) == 3);

    // Kings on A and H files
    board.setToFen("7k/5ppp/8/8/8/8/PPP5/K7 w - -");
    REQUIRE(Eval::pawnsShieldingKing(board, WHITE) == 2);
    REQUIRE(Eval::pawnsShieldingKing(board, BLACK) == 2);

    // 2 pawns each
    board.setToFen("6k1/5pp1/8/8/8/8/3PP3/3K4 w - -");
    REQUIRE(Eval::pawnsShieldingKing(board, WHITE) == 2);
    REQUIRE(Eval::pawnsShieldingKing(board, BLACK) == 2);

    // 1 pawn shielding white, 2 shielding black
    board.setToFen("2k5/2pp4/8/8/8/8/2P5/2K5 w - -");
    REQUIRE(Eval::pawnsShieldingKing(board, WHITE) == 1);
    REQUIRE(Eval::pawnsShieldingKing(board, BLACK) == 2);
  }
}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
// fex_rate.cpp
// ------------
//
// Optimal combined control of the exchange rate, as formulated in [1].
//
// [1] Mundaca, Gabriela, and Bernt Øksendal. "Optimal stochastic intervention
// control with application to the exchange rate." Journal of Mathematical
// Economics 29.2 (1998): 225-243.
//
////////////////////////////////////////////////////////////////////////////////

#include <QuantPDE/Core>

#include <cstdlib>  // abs
#include <fstream>  // ofstream
#include <iomanip>  // setw
#include <iostream> // cout, cerr
#include <limits>   // numeric_limits
#include <string>   // to_string

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

using namespace QuantPDE;
using namespace std;

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

// The problem is solved on [-boundary, boundary]
Real boundary = 3.; // log(1000) ~= 7

// Interest rate differential in [-betaMax, +betaMax]
Real betaMax = 0.5;

// Number of points in space (initial discretization)
int gridPoints = 32;

// Number of points for interest rate control (initial discretization)
int controlPoints = 16;

// Constants
Real c_1 = 1.;
Real c_2 = 1.;
Real c_3 = QuantPDE::epsilon;
Real c_4 = 1.;
Real c_5 = 1.;
Real c_6 = 1.;

// Effect of an intervention
//Real a = 1.;

// Discount
Real rho = 0.04;

// Volatility
Real v = 0.2;

// Central parity
Real m = 0.;

// Initial (log of the) exchange rate
Real x_0 = 0.;

int maxRefinement = 10;

constexpr int td = 20;

////////////////////////////////////////////////////////////////////////////////
// Functions
////////////////////////////////////////////////////////////////////////////////

// gamma(zeta) = c_1 * zeta
// L(zeta)     = c_2 * |zeta| + c_3
// F(y)        = c_4 * y
// M(y)        = c_5 * y^2
// N(y)        = c_6 * y^2

/**
* Cost of an impulse.
*/
inline Real interventionCost(Real t, Real x, Real x_j) {
	const Real zeta = (x_j - x) / c_1;
	return -(c_2 * abs(zeta) + c_3);
}

/**
* State of the exchange rate after an impulse.
*/
inline Real xplus(Real t, Real x, Real x_j) {
	return x_j;
}

/**
 * Effect of the interest rate differential on the exchange rate.
 *
 */
inline Real F(Real y) {
	return c_4 * y;
}

/**
* Cost of exchange rate differential.
*/
inline Real M(Real y) {
	return c_5 * y * y;
}

/**
* Cost of interest rate differential.
*/
inline Real N(Real y) {
	return c_6 * y * y;
}

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

class Discretizee final : public RawControlledLinearSystem1_1 {

	const RectilinearGrid1 &grid;

	const Function1 F, M, N;
	const Real rho, v, m;

	// TODO: Nonconstant coefficients

public:

	template <typename G, typename F1, typename F2, typename F3>
	Discretizee(
		G &grid,
		F1 &&interestDifferentialEffect,
		F2 &&exchangeRateCost,
		F3 &&interestDifferentialCost,
		Real discount,
		Real volatility,
		Real centralParity = 0.
	) noexcept :
		grid(grid),
		F( std::forward<F1>(interestDifferentialEffect) ),
		M( std::forward<F3>(exchangeRateCost) ),
		N( std::forward<F2>(interestDifferentialCost) ),
		rho( discount ),
		v( volatility ),
		m( centralParity )
	{
	}

	virtual Matrix A(Real time) {
		Matrix A = grid.matrix();
		A.reserve( IntegerVector::Constant(grid.size(), 3) );

		// x axis
		const Axis &x = grid[0];
		const int n = x.size();

		// Control as a vector
		const Vector &raw = control(0);

		// Left boundary (derivatives disappear)
		A.insert(0, 0) = rho;

		// Interior point
		for(Index i = 1; i < n - 1; ++i) {
			const Real
				dxb = x[i]     - x[i - 1],
				dxc = x[i + 1] - x[i - 1],
				dxf = x[i + 1] - x[i]
			;

			const Real tmp1 = v * v;
			const Real tmp2 = -F( raw(i) );

			const Real alpha_common = tmp1 / dxb / dxc;
			const Real  beta_common = tmp1 / dxf / dxc;

			// Central
			Real alpha_i = alpha_common - tmp2 / dxc;
			Real beta_i  =  beta_common + tmp2 / dxc;
			if(alpha_i < 0.) {
				// Forward
				alpha_i = alpha_common;
				beta_i  =  beta_common + tmp2 / dxf;
			} else if(beta_i < 0.) {
				// Backward
				alpha_i = alpha_common - tmp2 / dxb;
				beta_i  =  beta_common;
			}

			assert(alpha_i >= 0.);
			assert( beta_i >= 0.);

			A.insert(i, i - 1) = -alpha_i;
			A.insert(i, i    ) =  alpha_i + beta_i + rho;
			A.insert(i, i + 1) = -beta_i;
		}

		{
			const Real dx = x[n - 1] - x[n - 2];

			const Real tmp1 = v * v;
			const Real tmp2 = -F( raw(n - 1) );

			const Real alpha_common = tmp1 / dx / (2 * dx);
			const Real  beta_common = tmp1 / dx / (2 * dx);

			// Central
			Real alpha_i = alpha_common - tmp2 / (2 * dx);
			Real beta_i  =  beta_common + tmp2 / (2 * dx);
			if(alpha_i < 0.) {
				// Forward
				alpha_i = alpha_common;
				beta_i  =  beta_common + tmp2 / dx;
			} else if(beta_i < 0.) {
				// Backward
				alpha_i = alpha_common - tmp2 / dx;
				beta_i  =  beta_common;
			}

			assert(alpha_i >= 0.);
			assert( beta_i >= 0.);

			A.insert(n - 1, n - 2) = -(alpha_i + beta_i);
			A.insert(n - 1, n - 1) =   alpha_i + beta_i + rho;
		}

		A.makeCompressed();
		return A;
	}

	virtual Vector b(Real time) {
		Vector b = grid.vector();

		const Axis &x = grid[0];

		// Control as a vector
		const Vector &raw = control(0);

		// Interior and boundary points
		for(Index i = 0; i < x.size(); ++i) {
			b(i) = -( M( x[i] - m ) + N( raw(i) ) );
		}

		return b;
	}

	virtual bool isATheSame() const {
		// TODO: Check the coefficients
		return true;
	}

};

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

int main() {

	Real previousValue = nan(""), previousChange = nan("");

	RectilinearGrid1 initialGrid(
		// Uniform grid
		Axis::uniform(
			-boundary,
			m,
			gridPoints
		)

		// Clustered grid
		/*Axis::cluster(
			-boundary,  // Left-hand boundary
			0.,         // Feature to cluster around
			0.,         // Right-hand boundary
			gridPoints, // Number of points
			10.         // Clustering intensity
		)*/
	);

	// Table headers
	cout
		<< setw(td) << "Nodes"         << "\t"
		<< setw(td) << "Control Nodes" << "\t"
		<< setw(td) << "Value at x=0"  << "\t"
		<< setw(td) << "Iterations"    << "\t"
		<< setw(td) << "Change"        << "\t"
		<< setw(td) << "Ratio"
		<< endl
	;

	for(int ref = 0; ref <= maxRefinement; ++ref, controlPoints *= 2) {

		// Refine the grid ref times
		auto grid = initialGrid.refined( ref );

		RectilinearGrid1 stochasticControls(
			Axis::uniform(
				-betaMax,
				+betaMax,
				controlPoints
			)
		);

		ToleranceIteration toleranceIteration;

		////////////////////////////////////////////////////////////////
		// Linear system tree
		////////////////////////////////////////////////////////////////

		Discretizee discretizee(
			grid, // Domain
			F,    // Effect of interest rate differential on the
			      // exchange rate
			M,    // Cost of interest rate differential
			N,    // Cost of exchange rate differential
			rho,  // Discount factor
			v,    // Volatility
			m     // Central parity
		);

		// Policy iteration for stochastic control
		MinPolicyIteration1_1 stochasticPolicy(
			grid,               // Domain
			stochasticControls, // Control grid
			discretizee         // Lu - rho*u + f
		);
		stochasticPolicy.setIteration(toleranceIteration);

		// Policy iteration for impulse control
			Impulse1_1 impulseWithdrawal(
			grid,             // Spatial grid
			interventionCost, // Cost of an intervention
			xplus             // State of exchange rate after
			                  // intervention
		);
		MinPolicyIteration1_1 impulsePolicy(
			grid,             // Domain
			grid,             // Control grid
			impulseWithdrawal // Impulse
		);
		impulsePolicy.setIteration(toleranceIteration);

		// Penalty method
		PenaltyMethod penalty(
			grid,             // Domain
			stochasticPolicy, // Stochastic control component
			impulsePolicy     // Impulse control component
		);
		penalty.setIteration(toleranceIteration);

		IterationNode *root;
		//root = &stochasticPolicy;
		root = &penalty;

		////////////////////////////////////////////////////////////////
		// Run
		////////////////////////////////////////////////////////////////

		BiCGSTABSolver solver;
		auto u = toleranceIteration.solve(
			grid,                        // Domain
			[=] (Real x) { return 0.; }, // Initial guess (zero
			                             // everywhere)
			*root,                       // Root of linear system
			                             // tree
			solver                       // Linear system solver
		);

		////////////////////////////////////////////////////////////////
		// Print solution at x_0
		////////////////////////////////////////////////////////////////

		// If x_0 > m, use the fact that u(.) is symmetric about x=m
		Real adjusted;
		if(x_0 > m) {
			adjusted = m - (x_0 - m);
		} else {
			adjusted = x_0;
		}

		Real value = -u( adjusted );
		Real
			change = value - previousValue,
			ratio = previousChange / change
		;
		previousValue = value;
		previousChange = change;

		cout.precision(12);

		const int its = toleranceIteration.iterations().back();

		// Print row of table
		cout
			<< setw(td) << grid.size()               << "\t"
			<< setw(td) << stochasticControls.size() << "\t"
			<< setw(td) << value                     << "\t"
			<< setw(td) << its                       << "\t"
			<< setw(td) << change                    << "\t"
			<< setw(td) << ratio                     << "\t"
			<< endl
		;

		////////////////////////////////////////////////////////////////
		// Write to file
		////////////////////////////////////////////////////////////////

		/*
		// Controls
		Vector beta = discretizee.control(0);
		auto mask = penalty.constraintMask();
		for(int i = 0; i < grid.size(); i++) {
			if(mask[i]) {
				beta(i) = numeric_limits<Real>::infinity();
			}
		}

		// Write to file
		RectilinearGrid1 printGrid(
			Axis::uniform(
				-boundary,
				0.,
				100
			)
		);
		ofstream file;
		file.open("/tmp/fex_rate_ref_" + to_string(ref) + ".txt");
		file << accessor( printGrid, u );
		file.close();
		*/
	}

	return 0;

}
<commit_msg>Uneven FEX penalty.<commit_after>////////////////////////////////////////////////////////////////////////////////
// fex_rate.cpp
// ------------
//
// Optimal combined control of the exchange rate, as formulated in [1].
//
// [1] Mundaca, Gabriela, and Bernt Øksendal. "Optimal stochastic intervention
// control with application to the exchange rate." Journal of Mathematical
// Economics 29.2 (1998): 225-243.
//
////////////////////////////////////////////////////////////////////////////////

//#define QUANT_PDE_FEX_RATE_EVEN
#define QUANT_PDE_FEX_RATE_WRITE

#include <QuantPDE/Core>

#include <cmath>  // fabs
#include <fstream>  // ofstream
#include <iomanip>  // setw
#include <iostream> // cout, cerr
#include <limits>   // numeric_limits
#include <string>   // to_string

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

using namespace QuantPDE;
using namespace std;

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

// The problem is solved on [-boundary, boundary]
Real boundary = 3.; // log(1000) ~= 7

// Interest rate differential in [-betaMax, +betaMax]
Real betaMax = 0.5;

// Number of points in space (initial discretization)
int gridPoints = 32;

// Number of points for interest rate control (initial discretization)
int controlPoints = 16;

// Constants
Real c_1 = 1.;
Real c_2 = 1.;
Real c_3 = QuantPDE::epsilon;
Real c_4 = 1.;
Real c_5 = 1.;
Real c_6 = 1.;

// Effect of an intervention
//Real a = 1.;

// Discount
Real rho = 0.04;

// Volatility
Real v = 0.2;

// Central parity
Real m = 0.;

// Initial (log of the) exchange rate
Real x_0 = 0.;

int maxRefinement = 10;

constexpr int td = 20;

////////////////////////////////////////////////////////////////////////////////
// Functions
////////////////////////////////////////////////////////////////////////////////

// gamma(zeta) = c_1 * zeta
// L(zeta)     = c_2 * |zeta| + c_3
// F(y)        = c_4 * y
// M(y)        = c_5 * y^2
// N(y)        = c_6 * y^2

/**
* Cost of an impulse.
*/
inline Real interventionCost(Real t, Real x, Real x_j) {
	const Real zeta = (x_j - x) / c_1;
	return -(c_2 * fabs(zeta) + c_3);
}

/**
* State of the exchange rate after an impulse.
*/
inline Real xplus(Real t, Real x, Real x_j) {
	return x_j;
}

/**
 * Effect of the interest rate differential on the exchange rate.
 *
 */
inline Real F(Real y) {
	return c_4 * y;
}

/**
* Cost of exchange rate differential.
*/
inline Real M(Real y) {
	#ifdef QUANT_PDE_FEX_RATE_EVEN
	return c_5 * y * y;
	#else
	return (y < 0.) ? (c_5 * y * y) : 0.;
	#endif
}

/**
* Cost of interest rate differential.
*/
inline Real N(Real y) {
	return c_6 * y * y;
}

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

class Discretizee final : public RawControlledLinearSystem1_1 {

	const RectilinearGrid1 &grid;

	const Function1 F, M, N;
	const Real rho, v, m;

	// TODO: Nonconstant coefficients

public:

	template <typename G, typename F1, typename F2, typename F3>
	Discretizee(
		G &grid,
		F1 &&interestDifferentialEffect,
		F2 &&exchangeRateCost,
		F3 &&interestDifferentialCost,
		Real discount,
		Real volatility,
		Real centralParity = 0.
	) noexcept :
		grid(grid),
		F( std::forward<F1>(interestDifferentialEffect) ),
		M( std::forward<F3>(exchangeRateCost) ),
		N( std::forward<F2>(interestDifferentialCost) ),
		rho( discount ),
		v( volatility ),
		m( centralParity )
	{
	}

	virtual Matrix A(Real time) {
		Matrix A = grid.matrix();
		A.reserve( IntegerVector::Constant(grid.size(), 3) );

		// x axis
		const Axis &x = grid[0];
		const int n = x.size();

		// Control as a vector
		const Vector &raw = control(0);

		// Left boundary (derivatives disappear)
		A.insert(0, 0) = rho;

		// Interior point
		for(Index i = 1; i < n - 1; ++i) {
			const Real
				dxb = x[i]     - x[i - 1],
				dxc = x[i + 1] - x[i - 1],
				dxf = x[i + 1] - x[i]
			;

			const Real tmp1 = v * v;
			const Real tmp2 = -F( raw(i) );

			const Real alpha_common = tmp1 / dxb / dxc;
			const Real  beta_common = tmp1 / dxf / dxc;

			// Central
			Real alpha_i = alpha_common - tmp2 / dxc;
			Real beta_i  =  beta_common + tmp2 / dxc;
			if(alpha_i < 0.) {
				// Forward
				alpha_i = alpha_common;
				beta_i  =  beta_common + tmp2 / dxf;
			} else if(beta_i < 0.) {
				// Backward
				alpha_i = alpha_common - tmp2 / dxb;
				beta_i  =  beta_common;
			}

			assert(alpha_i >= 0.);
			assert( beta_i >= 0.);

			A.insert(i, i - 1) = -alpha_i;
			A.insert(i, i    ) =  alpha_i + beta_i + rho;
			A.insert(i, i + 1) = -beta_i;
		}

		#ifdef QUANT_PDE_FEX_RATE_EVEN
		{
			const Real dx = x[n - 1] - x[n - 2];

			const Real tmp1 = v * v;
			const Real tmp2 = -F( raw(n - 1) );

			const Real alpha_common = tmp1 / dx / (2 * dx);
			const Real  beta_common = tmp1 / dx / (2 * dx);

			// Central
			Real alpha_i = alpha_common - tmp2 / (2 * dx);
			Real beta_i  =  beta_common + tmp2 / (2 * dx);
			if(alpha_i < 0.) {
				// Forward
				alpha_i = alpha_common;
				beta_i  =  beta_common + tmp2 / dx;
			} else if(beta_i < 0.) {
				// Backward
				alpha_i = alpha_common - tmp2 / dx;
				beta_i  =  beta_common;
			}

			assert(alpha_i >= 0.);
			assert( beta_i >= 0.);

			A.insert(n - 1, n - 2) = -(alpha_i + beta_i);
			A.insert(n - 1, n - 1) =   alpha_i + beta_i + rho;
		}
		#else
		A.insert(n - 1, n - 1) = rho;
		#endif

		A.makeCompressed();
		return A;
	}

	virtual Vector b(Real time) {
		Vector b = grid.vector();

		const Axis &x = grid[0];

		// Control as a vector
		const Vector &raw = control(0);

		// Interior and boundary points
		for(Index i = 0; i < x.size(); ++i) {
			b(i) = -( M( x[i] - m ) + N( raw(i) ) );
		}

		return b;
	}

	virtual bool isATheSame() const {
		// TODO: Check the coefficients
		return true;
	}

};

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

int main() {

	Real previousValue = nan(""), previousChange = nan("");

	RectilinearGrid1 initialGrid(
		// Uniform grid
		Axis::uniform(
			-boundary,
			#ifdef QUANT_PDE_FEX_RATE_EVEN
			m,
			#else
			+boundary,
			#endif
			gridPoints
		)

		// Clustered grid
		/*Axis::cluster(
			-boundary,  // Left-hand boundary
			0.,         // Feature to cluster around
			0.,         // Right-hand boundary
			gridPoints, // Number of points
			10.         // Clustering intensity
		)*/
	);

	// Table headers
	cout
		<< setw(td) << "Nodes"         << "\t"
		<< setw(td) << "Control Nodes" << "\t"
		<< setw(td) << "Value at x=0"  << "\t"
		<< setw(td) << "Iterations"    << "\t"
		<< setw(td) << "Change"        << "\t"
		<< setw(td) << "Ratio"
		<< endl
	;

	for(int ref = 0; ref <= maxRefinement; ++ref, controlPoints *= 2) {

		// Refine the grid ref times
		auto grid = initialGrid.refined( ref );

		RectilinearGrid1 stochasticControls(
			Axis::uniform(
				-betaMax,
				+betaMax,
				controlPoints
			)
		);

		ToleranceIteration toleranceIteration;

		////////////////////////////////////////////////////////////////
		// Linear system tree
		////////////////////////////////////////////////////////////////

		Discretizee discretizee(
			grid, // Domain
			F,    // Effect of interest rate differential on the
			      // exchange rate
			M,    // Cost of interest rate differential
			N,    // Cost of exchange rate differential
			rho,  // Discount factor
			v,    // Volatility
			m     // Central parity
		);

		// Policy iteration for stochastic control
		MinPolicyIteration1_1 stochasticPolicy(
			grid,               // Domain
			stochasticControls, // Control grid
			discretizee         // Lu - rho*u + f
		);
		stochasticPolicy.setIteration(toleranceIteration);

		// Policy iteration for impulse control
			Impulse1_1 impulseWithdrawal(
			grid,             // Spatial grid
			interventionCost, // Cost of an intervention
			xplus             // State of exchange rate after
			                  // intervention
		);
		MinPolicyIteration1_1 impulsePolicy(
			grid,             // Domain
			grid,             // Control grid
			impulseWithdrawal // Impulse
		);
		impulsePolicy.setIteration(toleranceIteration);

		// Penalty method
		PenaltyMethod penalty(
			grid,             // Domain
			stochasticPolicy, // Stochastic control component
			impulsePolicy     // Impulse control component
		);
		penalty.setIteration(toleranceIteration);

		IterationNode *root;
		//root = &stochasticPolicy;
		root = &penalty;

		////////////////////////////////////////////////////////////////
		// Run
		////////////////////////////////////////////////////////////////

		BiCGSTABSolver solver;
		auto u = toleranceIteration.solve(
			grid,                        // Domain
			[=] (Real x) { return 0.; }, // Initial guess (zero
			                             // everywhere)
			*root,                       // Root of linear system
			                             // tree
			solver                       // Linear system solver
		);

		////////////////////////////////////////////////////////////////
		// Print solution at x_0
		////////////////////////////////////////////////////////////////

		Real adjusted = x_0;
		#ifdef QUANT_PDE_FEX_RATE_EVEN
		// If x_0 > m, use the fact that u(.) is symmetric about x=m
		if(x_0 > m) {
			adjusted = m - (x_0 - m);
		}
		#endif

		Real value = -u( adjusted );
		Real
			change = value - previousValue,
			ratio = previousChange / change
		;
		previousValue = value;
		previousChange = change;

		cout.precision(12);

		const int its = toleranceIteration.iterations().back();

		// Print row of table
		cout
			<< setw(td) << grid.size()               << "\t"
			<< setw(td) << stochasticControls.size() << "\t"
			<< setw(td) << value                     << "\t"
			<< setw(td) << its                       << "\t"
			<< setw(td) << change                    << "\t"
			<< setw(td) << ratio                     << "\t"
			<< endl
		;

		////////////////////////////////////////////////////////////////
		// Write to file
		////////////////////////////////////////////////////////////////

		#ifdef QUANT_PDE_FEX_RATE_WRITE
		// Controls
		Vector beta = discretizee.control(0);
		auto mask = penalty.constraintMask();
		for(int i = 0; i < grid.size(); i++) {
			if(mask[i]) {
				beta(i) = numeric_limits<Real>::infinity();
			}
		}

		// Write to file
		RectilinearGrid1 printGrid(
			Axis::uniform(
				-boundary,
				#ifdef QUANT_PDE_FEX_RATE_EVEN
				m,
				#else
				+boundary,
				#endif
				100
			)
		);
		ofstream file;
		file.open("/tmp/fex_rate_ref_" + to_string(ref) + ".txt");
		file << accessor( printGrid, u );
		file.close();
		#endif
	}

	return 0;

}
<|endoftext|>