Initia commit.
authorFrancois Fleuret <francois@fleuret.org>
Sun, 22 Nov 2009 20:48:40 +0000 (21:48 +0100)
committerFrancois Fleuret <francois@fleuret.org>
Sun, 22 Nov 2009 20:48:40 +0000 (21:48 +0100)
69 files changed:
Makefile [new file with mode: 0644]
README.txt [new file with mode: 0644]
boosted_classifier.cc [new file with mode: 0644]
boosted_classifier.h [new file with mode: 0644]
classifier.cc [new file with mode: 0644]
classifier.h [new file with mode: 0644]
classifier_reader.cc [new file with mode: 0644]
classifier_reader.h [new file with mode: 0644]
discrete_density.cc [new file with mode: 0644]
discrete_density.h [new file with mode: 0644]
doit.sh [new file with mode: 0755]
error_rates.cc [new file with mode: 0644]
error_rates.h [new file with mode: 0644]
fusion_sort.cc [new file with mode: 0644]
fusion_sort.h [new file with mode: 0644]
global.cc [new file with mode: 0644]
global.h [new file with mode: 0644]
gpl-3.0.txt [new file with mode: 0644]
jpeg_misc.cc [new file with mode: 0644]
jpeg_misc.h [new file with mode: 0644]
misc.cc [new file with mode: 0644]
misc.h [new file with mode: 0644]
naive_bayesian_classifier.cc [new file with mode: 0644]
naive_bayesian_classifier.h [new file with mode: 0644]
param_parser.cc [new file with mode: 0644]
param_parser.h [new file with mode: 0644]
progress_bar.cc [new file with mode: 0644]
progress_bar.h [new file with mode: 0644]
rgb_image.cc [new file with mode: 0644]
rgb_image.h [new file with mode: 0644]
shape.cc [new file with mode: 0644]
shape.h [new file with mode: 0644]
stump.cc [new file with mode: 0644]
stump.h [new file with mode: 0644]
tools.cc [new file with mode: 0644]
tools.h [new file with mode: 0644]
vignette.cc [new file with mode: 0644]
vignette.h [new file with mode: 0644]
vignette_generator.cc [new file with mode: 0644]
vignette_generator.h [new file with mode: 0644]
vision_problem_1.cc [new file with mode: 0644]
vision_problem_1.h [new file with mode: 0644]
vision_problem_11.cc [new file with mode: 0644]
vision_problem_11.h [new file with mode: 0644]
vision_problem_12.cc [new file with mode: 0644]
vision_problem_12.h [new file with mode: 0644]
vision_problem_13.cc [new file with mode: 0644]
vision_problem_13.h [new file with mode: 0644]
vision_problem_17.cc [new file with mode: 0644]
vision_problem_17.h [new file with mode: 0644]
vision_problem_18.cc [new file with mode: 0644]
vision_problem_18.h [new file with mode: 0644]
vision_problem_2.cc [new file with mode: 0644]
vision_problem_2.h [new file with mode: 0644]
vision_problem_20.cc [new file with mode: 0644]
vision_problem_20.h [new file with mode: 0644]
vision_problem_21.cc [new file with mode: 0644]
vision_problem_21.h [new file with mode: 0644]
vision_problem_3.cc [new file with mode: 0644]
vision_problem_3.h [new file with mode: 0644]
vision_problem_5.cc [new file with mode: 0644]
vision_problem_5.h [new file with mode: 0644]
vision_problem_6.cc [new file with mode: 0644]
vision_problem_6.h [new file with mode: 0644]
vision_problem_8.cc [new file with mode: 0644]
vision_problem_8.h [new file with mode: 0644]
vision_problem_tools.cc [new file with mode: 0644]
vision_problem_tools.h [new file with mode: 0644]
vision_test.cc [new file with mode: 0644]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..2e37a79
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,75 @@
+
+#  svrt is the ``Synthetic Visual Reasoning Test'', an image generator
+#  for evaluating classification performance of machine learning
+#  systems, humans and primates.
+#
+#  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+#  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+#
+#  This file is part of svrt.
+#
+#  svrt is free software: you can redistribute it and/or modify it
+#  under the terms of the GNU General Public License version 3 as
+#  published by the Free Software Foundation.
+#
+#  svrt is distributed in the hope that it will be useful, but WITHOUT
+#  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+#  License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+
+LDFLAGS=-lm -ljpeg -lpng
+
+ifeq ($(DEBUG),yes)
+  OPTIMIZE_FLAG = -ggdb3 -DDEBUG -fno-omit-frame-pointer
+else
+  OPTIMIZE_FLAG = -ggdb3 -O3
+endif
+
+ifeq ($(PROFILE),yes)
+  PROFILE_FLAG = -pg
+endif
+
+CXXFLAGS = -Wall $(OPTIMIZE_FLAG) $(PROFILE_FLAG) $(CXXGLPK)
+
+all: vision_test TAGS
+
+TAGS: *.cc *.h
+       etags --members -l c++ *.cc *.h
+
+vision_test: misc.o rgb_image.o jpeg_misc.o fusion_sort.o global.o param_parser.o progress_bar.o \
+       discrete_density.o \
+       tools.o \
+       vignette.o \
+       shape.o \
+       vignette_generator.o \
+       vision_problem_tools.o \
+       vision_problem_1.o \
+       vision_problem_2.o \
+       vision_problem_3.o \
+       vision_problem_5.o \
+       vision_problem_6.o \
+       vision_problem_8.o \
+       vision_problem_11.o \
+       vision_problem_12.o \
+       vision_problem_13.o \
+       vision_problem_17.o \
+       vision_problem_18.o \
+       vision_problem_20.o \
+       vision_problem_21.o \
+       classifier_reader.o \
+        classifier.o naive_bayesian_classifier.o \
+       stump.o boosted_classifier.o \
+       error_rates.o \
+       vision_test.o
+       $(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
+
+Makefile.depend: *.h *.cc Makefile
+       $(CC) -M *.cc > Makefile.depend
+
+clean:
+       \rm -f vision_test *.o Makefile.depend TAGS
+
+-include Makefile.depend
diff --git a/README.txt b/README.txt
new file mode 100644 (file)
index 0000000..eab2d84
--- /dev/null
@@ -0,0 +1,14 @@
+This software should compile on any standard GNU/Linux machine, and
+UNIX machine in general. It only requires the jpeg and png library.
+
+To test it on a list of problems, just run the script doit.sh with the
+problem numbers as arguments. For instance:
+
+  ./doit.sh 1 2 3
+
+It will compile the source and run the executable on the specified
+problems to generate sample images and test a Boosted classifier. If
+no argument is given, it will run on all the problems by default.
+
+--
+Francois Fleuret, Nov 2009.
diff --git a/boosted_classifier.cc b/boosted_classifier.cc
new file mode 100644 (file)
index 0000000..70f09d1
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "boosted_classifier.h"
+#include "classifier_reader.h"
+#include "fusion_sort.h"
+#include "tools.h"
+
+inline scalar_t loss_derivative(int label, scalar_t response) {
+  return - scalar_t(label * 2 - 1) * exp( - scalar_t(label * 2 - 1) * response );
+}
+
+BoostedClassifier::BoostedClassifier() {
+  _nb_stumps = 0;
+  _stumps = 0;
+}
+
+BoostedClassifier::BoostedClassifier(int nb_weak_learners) {
+  _nb_stumps = nb_weak_learners;
+  _stumps = new Stump[_nb_stumps];
+}
+
+BoostedClassifier::~BoostedClassifier() {
+  delete[] _stumps;
+}
+
+const char *BoostedClassifier::name() {
+  return "ADABOOST";
+}
+
+void BoostedClassifier::chose_stump_from_sampling(int t, int **integral_images, scalar_t *derivatives, int nb_samples) {
+  int *indexes = new int[nb_samples];
+  int *sorted_indexes = new int[nb_samples];
+  scalar_t *stump_counts = new scalar_t[nb_samples];
+
+  scalar_t max_loss_derivative = 0;
+  Stump tmp;
+  tmp.weight0 = -1;
+  tmp.weight1 =  1;
+  tmp.threshold = 0;
+
+  for(int k = 0; k < global.nb_optimization_weak_learners; k++) {
+    tmp.randomize();
+    scalar_t s = 0;
+
+    for(int n = 0; n < nb_samples; n++) {
+      stump_counts[n] = tmp.count(integral_images[n]);
+      indexes[n] = n;
+      s += derivatives[n];
+    }
+
+    indexed_fusion_sort(nb_samples, indexes, sorted_indexes, stump_counts);
+
+    for(int n = 0; n < nb_samples - 1; n++) {
+      int i = sorted_indexes[n];
+      int j = sorted_indexes[n + 1];
+      s -= 2 * derivatives[i];
+      if(stump_counts[j] > stump_counts[i]) {
+        if(abs(s) > abs(max_loss_derivative)) {
+          max_loss_derivative = s;
+          _stumps[t] = tmp;
+          _stumps[t].threshold = (stump_counts[i] + stump_counts[j])/2;
+        }
+      }
+    }
+  }
+
+  delete[] stump_counts;
+  delete[] indexes;
+  delete[] sorted_indexes;
+}
+
+void BoostedClassifier::chose_stump(int t, int **integral_images, scalar_t *derivatives, int nb_samples) {
+  if(global.nb_sampled_samples <= 0) {
+    chose_stump_from_sampling(t, integral_images, derivatives, nb_samples);
+  } else {
+    int *sampled_indexes = new int[global.nb_sampled_samples];
+    scalar_t *weights = new scalar_t[nb_samples];
+    for(int s = 0; s < nb_samples; s++) {
+      weights[s] = abs(derivatives[s]);
+    }
+    robust_sampling(nb_samples, weights, global.nb_sampled_samples, sampled_indexes);
+    delete[] weights;
+
+    int **sampled_integral_images = new int *[global.nb_sampled_samples];
+    scalar_t *sampled_derivatives = new scalar_t[global.nb_sampled_samples];
+
+    for(int s = 0; s < global.nb_sampled_samples; s++) {
+      sampled_integral_images[s] = integral_images[sampled_indexes[s]];
+      if(derivatives[sampled_indexes[s]] > 0) {
+        sampled_derivatives[s] = 1.0;
+      } else {
+        sampled_derivatives[s] = -1.0;
+      }
+    }
+
+    chose_stump_from_sampling(t, sampled_integral_images, sampled_derivatives, global.nb_sampled_samples);
+
+    delete[] sampled_derivatives;
+    delete[] sampled_integral_images;
+    delete[] sampled_indexes;
+  }
+}
+
+void BoostedClassifier::train(int nb_vignettes, Vignette *vignettes, int *labels) {
+  int **integral_images = new int *[nb_vignettes];
+
+  for(int n = 0; n < nb_vignettes; n++) {
+    integral_images[n] = new int[(Vignette::width + 1) * (Vignette::height + 1)];
+    compute_integral_image(&vignettes[n], integral_images[n]);
+  }
+
+  scalar_t *responses = new scalar_t[nb_vignettes];
+  scalar_t *derivatives = new scalar_t[nb_vignettes];
+
+  for(int n = 0; n < nb_vignettes; n++) {
+    responses[n] = 0.0;
+  }
+
+  global.bar.init(&cout, _nb_stumps);
+  for(int t = 0; t < _nb_stumps; t++) {
+
+    for(int n = 0; n < nb_vignettes; n++) {
+      derivatives[n] = loss_derivative(labels[n], responses[n]);
+    }
+
+    chose_stump(t, integral_images, derivatives, nb_vignettes);
+
+    scalar_t num0 = 0, den0 = 0, num1 = 0, den1 = 0;
+
+    for(int n = 0; n < nb_vignettes; n++) {
+      if(_stumps[t].response(integral_images[n]) > 0) {
+        if(labels[n] == 1) {
+          num1 += exp( - responses[n] );
+        } else {
+          den1 += exp(   responses[n] );
+        }
+      } else {
+        if(labels[n] == 1) {
+          num0 += exp( - responses[n] );
+        } else {
+          den0 += exp(   responses[n] );
+        }
+      }
+    }
+
+    scalar_t weight_max = 5.0;
+
+    _stumps[t].weight0 = 0.5 * log(num0 / den0);
+
+    if(_stumps[t].weight0 < -weight_max)
+      _stumps[t].weight0 = -weight_max;
+    else if(_stumps[t].weight0 > weight_max)
+      _stumps[t].weight0 = weight_max;
+
+    _stumps[t].weight1 = 0.5 * log(num1 / den1);
+    if(_stumps[t].weight1 < -weight_max)
+      _stumps[t].weight1 = -weight_max;
+    else if(_stumps[t].weight1 > weight_max)
+      _stumps[t].weight1 = weight_max;
+
+    for(int n = 0; n < nb_vignettes; n++) {
+      responses[n] += _stumps[t].response(integral_images[n]);
+    }
+
+    // cout << "ADABOOST_STEP " << t + 1 << " " << loss << endl;
+    global.bar.refresh(&cout, t);
+  }
+  global.bar.finish(&cout);
+
+  scalar_t loss = 0;
+  for(int n = 0; n < nb_vignettes; n++) {
+    loss += exp( - scalar_t(labels[n] * 2 - 1) * responses[n]);
+  }
+
+  cout << "Final loss is " << loss << endl;
+
+  delete[] derivatives;
+  delete[] responses;
+
+  for(int n = 0; n < nb_vignettes; n++) {
+    delete[] integral_images[n];
+  }
+
+  delete[] integral_images;
+}
+
+scalar_t BoostedClassifier::classify(Vignette *vignette) {
+  int integral_image[(Vignette::width + 1) * (Vignette::height + 1)];
+  compute_integral_image(vignette, integral_image);
+  scalar_t result = 0;
+  for(int n = 0; n < _nb_stumps; n++) {
+    result += _stumps[n].response(integral_image);
+  }
+  return result;
+}
+
+void BoostedClassifier::read(istream *in) {
+  delete[] _stumps;
+  read_var(in, &_nb_stumps);
+  cout << "Reading " << _nb_stumps << " stumps." << endl;
+  _stumps = new Stump[_nb_stumps];
+  in->read((char *) _stumps, sizeof(Stump) * _nb_stumps);
+}
+
+void BoostedClassifier::write(ostream *out) {
+  int t;
+  t = CT_BOOSTED;
+  write_var(out, &t);
+  write_var(out, &_nb_stumps);
+  out->write((char *) _stumps, sizeof(Stump) * _nb_stumps);
+}
+
+scalar_t BoostedClassifier::partial_sum(int first, int nb, Vignette *vignette) {
+  int integral_image[(Vignette::width + 1) * (Vignette::height + 1)];
+  compute_integral_image(vignette, integral_image);
+  scalar_t result = 0;
+  for(int n = first; n < first + nb; n++) {
+    result += _stumps[n].response(integral_image);
+  }
+  return result;
+}
diff --git a/boosted_classifier.h b/boosted_classifier.h
new file mode 100644 (file)
index 0000000..23039e6
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef BOOSTED_CLASSIFIER_H
+#define BOOSTED_CLASSIFIER_H
+
+#include "classifier.h"
+#include "stump.h"
+
+class BoostedClassifier : public Classifier {
+  Stump *_stumps;
+  int _nb_stumps;
+  void chose_stump_from_sampling(int t, int **integral_images, scalar_t *derivatives, int nb_samples);
+  void chose_stump(int t, int **integral_images, scalar_t *derivatives, int nb_samples);
+public:
+  BoostedClassifier();
+  BoostedClassifier(int nb_weak_learners);
+  ~BoostedClassifier();
+  inline int nb_stumps() { return _nb_stumps; }
+  virtual const char *name();
+  virtual void train(int nb_vignettes, Vignette *vignettes, int *labels);
+  virtual scalar_t classify(Vignette *vignette);
+  virtual void read(istream *in);
+  virtual void write(ostream *out);
+  scalar_t partial_sum(int first, int nb, Vignette *vignette);
+};
+
+#endif
diff --git a/classifier.cc b/classifier.cc
new file mode 100644 (file)
index 0000000..491b194
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "classifier.h"
+
+Classifier::~Classifier() { }
diff --git a/classifier.h b/classifier.h
new file mode 100644 (file)
index 0000000..b38ba40
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef CLASSIFIER_H
+#define CLASSIFIER_H
+
+#include "misc.h"
+#include "vignette.h"
+
+class Classifier {
+public:
+
+  // We need a virtual destructor since there are virtual methods
+  virtual ~Classifier();
+
+  // This method returns an upper-caps string to identify the classifier
+  virtual const char *name() = 0;
+
+  // Train the classifier from a set of vignettes. The labels are in the
+  // vignettes.
+  virtual void train(int nb_vignettes, Vignette *vignettes, int *labels) = 0;
+
+  // Compute a scalar value which should be strictly positive on
+  // positive vignettes and strictly negative on negative ones.
+  virtual scalar_t classify(Vignette *vignette) = 0;
+
+  // Read or write the classifier from or to a stream
+  virtual void read(istream *in) = 0;
+  virtual void write(ostream *out) = 0;
+};
+
+#endif
diff --git a/classifier_reader.cc b/classifier_reader.cc
new file mode 100644 (file)
index 0000000..e118979
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "misc.h"
+#include "classifier_reader.h"
+#include "naive_bayesian_classifier.h"
+#include "boosted_classifier.h"
+
+Classifier *read_classifier(istream *in) {
+  Classifier *result = 0;
+
+  unsigned int t;
+  read_var(in, &t);
+
+  switch(t) {
+  case CT_NAIVE_BAYESIAN:
+    cout << "Reading a CT_NAIVE_BAYESIAN." << endl;
+    result = new NaiveBayesianClassifier();
+    result->read(in);
+    break;
+  case CT_BOOSTED:
+    cout << "Reading a CT_BOOSTED." << endl;
+    result = new BoostedClassifier();
+    result->read(in);
+    break;
+  default:
+    cerr << "Unknown classifier type for reading." << endl;
+    abort();
+  }
+
+  return result;
+}
diff --git a/classifier_reader.h b/classifier_reader.h
new file mode 100644 (file)
index 0000000..70fa73a
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef CLASSIFIER_READER_H
+#define CLASSIFIER_READER_H
+
+#include "classifier.h"
+
+enum {
+  CT_NAIVE_BAYESIAN,
+  CT_BOOSTED
+};
+
+Classifier *read_classifier(istream *in);
+
+#endif
diff --git a/discrete_density.cc b/discrete_density.cc
new file mode 100644 (file)
index 0000000..d14ec8d
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "discrete_density.h"
+
+DiscreteDensityTree::DiscreteDensityTree(scalar_t *proba, int first_value, int nb_values) {
+  if(nb_values > 1) {
+    _proba_tree0 = 0;
+    for(int n = 0; n < nb_values/2; n++) _proba_tree0 += proba[first_value + n];
+    scalar_t s = 0;
+    for(int n = 0; n < nb_values; n++) s += proba[first_value + n];
+    _proba_tree0 /= s;
+    _tree0 = new DiscreteDensityTree(proba, first_value, nb_values/2);
+    _tree1 = new DiscreteDensityTree(proba, first_value + nb_values/2, nb_values - (nb_values/2));
+  } else {
+    _tree0 = 0;
+    _tree1 = 0;
+    _value = first_value;
+  }
+}
+
+DiscreteDensityTree::~DiscreteDensityTree() {
+  if(_tree0) delete _tree0;
+  if(_tree1) delete _tree1;
+}
+
+int DiscreteDensityTree::sample() {
+  if(_tree0) {
+    if(drand48() < _proba_tree0)
+      return _tree0->sample();
+    else
+      return _tree1->sample();
+  } else return _value;
+}
+
+DiscreteDensity::DiscreteDensity(int nb_values) {
+  _nb_values = nb_values;
+  _probas = new scalar_t[_nb_values];
+  _log_probas = new scalar_t[_nb_values];
+  _sampling_tree = 0;
+}
+
+DiscreteDensity::~DiscreteDensity() {
+  delete[] _probas;
+  delete[] _log_probas;
+  delete _sampling_tree;
+}
+
+void DiscreteDensity::set_non_normalized_proba(int n, scalar_t p) {
+  _probas[n] = p;
+}
+
+void DiscreteDensity::normalize() {
+  scalar_t s = 0;
+  for(int k = 0; k < _nb_values; k++) {
+    s += _probas[k];
+  }
+  for(int k = 0; k < _nb_values; k++) {
+    _probas[k] /= s;
+    _log_probas[k] = log(_probas[k]);
+  }
+  delete _sampling_tree;
+  _sampling_tree = new DiscreteDensityTree(_probas, 0, _nb_values);
+}
+
+scalar_t DiscreteDensity::entropy() {
+  scalar_t h = 0;
+  for(int k = 0; k < _nb_values; k++) {
+    if(_probas[k] > 0) h += - _probas[k] * _log_probas[k]/log(2.0);
+  }
+  return h;
+}
+
+scalar_t DiscreteDensity::proba(int n) {
+  return _probas[n];
+}
+
+scalar_t DiscreteDensity::log_proba(int n) {
+  return _log_probas[n];
+}
+
+int DiscreteDensity::sample() {
+  return _sampling_tree->sample();
+}
diff --git a/discrete_density.h b/discrete_density.h
new file mode 100644 (file)
index 0000000..1c2b08d
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef DISCRETE_DENSITY_H
+#define DISCRETE_DENSITY_H
+
+#include "misc.h"
+
+class DiscreteDensityTree {
+  scalar_t _proba_tree0;
+  DiscreteDensityTree *_tree0, *_tree1;
+  int _value;
+public:
+  DiscreteDensityTree(scalar_t *proba, int first_value, int nb_values);
+  ~DiscreteDensityTree();
+  int sample();
+};
+
+class DiscreteDensity {
+  DiscreteDensityTree *_sampling_tree;
+  int _nb_values;
+  scalar_t *_probas, *_log_probas;
+public:
+  DiscreteDensity(int nb_values);
+  ~DiscreteDensity();
+
+  void set_non_normalized_proba(int n, scalar_t p);
+  void normalize();
+  scalar_t entropy();
+
+  scalar_t proba(int n);
+  scalar_t log_proba(int n);
+  int sample();
+};
+
+#endif
diff --git a/doit.sh b/doit.sh
new file mode 100755 (executable)
index 0000000..1315b59
--- /dev/null
+++ b/doit.sh
@@ -0,0 +1,53 @@
+#!/bin/bash
+
+#  svrt is the ``Synthetic Visual Reasoning Test'', an image generator
+#  for evaluating classification performance of machine learning
+#  systems, humans and primates.
+#
+#  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+#  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+#
+#  This file is part of svrt.
+#
+#  svrt is free software: you can redistribute it and/or modify it
+#  under the terms of the GNU General Public License version 3 as
+#  published by the Free Software Foundation.
+#
+#  svrt is distributed in the hope that it will be useful, but WITHOUT
+#  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+#  License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+
+nb_samples_to_save=100
+nb_samples_for_training=1000
+
+problem_list=$*
+
+[[ ${problem_list} ]] || problem_list="1 2 3 5 6 8 11 12 13 17 18 20 21"
+
+set -e
+
+make -j -k vision_test
+
+for problem_number in ${problem_list}; do
+
+    result_dir=./results_problem_${problem_number}/
+
+    mkdir -p ${result_dir}
+
+    ./vision_test \
+        --problem_number=${problem_number} \
+        --nb_train_samples=${nb_samples_to_save} \
+        --result_path=${result_dir} \
+        write-samples
+
+    ./vision_test \
+        --problem_number=${problem_number} \
+        --nb_train_samples=${nb_samples_for_training} \
+        --result_path=${result_dir} \
+        randomize-train adaboost compute-train-error compute-test-error
+
+done
diff --git a/error_rates.cc b/error_rates.cc
new file mode 100644 (file)
index 0000000..979edb4
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "error_rates.h"
+#include "rgb_image.h"
+
+scalar_t error_rate(Classifier *classifier, int nb_vignettes, Vignette *vignettes, int *labels) {
+  int e = 0;
+
+  for(int n = 0; n < nb_vignettes; n++) {
+    if(classifier->classify(&vignettes[n]) >= 0) {
+      if(labels[n] == 0) e++;
+    } else {
+      if(labels[n] == 1) e++;
+    }
+  }
+
+  return scalar_t(e)/scalar_t(nb_vignettes);
+}
+
+scalar_t test_error_rate(VignetteGenerator *generator, Classifier *classifier, long int nb_to_try) {
+  scalar_t e = 0;
+  Vignette vignette;
+  int label;
+
+  global.bar.init(&cout, nb_to_try);
+
+  for(long int k = 0; k < nb_to_try; k++) {
+    label = int(drand48() * 2);
+    generator->generate(label, &vignette);
+    if(classifier->classify(&vignette) >= 0) {
+      if(label == 0) e++;
+    } else {
+      if(label == 1) e++;
+    }
+    global.bar.refresh(&cout, k);
+  }
+  global.bar.finish(&cout);
+
+  return scalar_t(e)/scalar_t(nb_to_try);
+}
+
+
+void compute_response_mu_and_sigma(int nb_samples, Vignette *vignette, Classifier *classifier,
+                                   scalar_t *mu, scalar_t *sigma) {
+  scalar_t sum = 0, sum_sq = 0;
+  const int nb_pixels_to_switch = 1;
+  int changed_pixels[nb_pixels_to_switch];
+
+  for(int n = 0; n < nb_samples; n++) {
+    for(int p = 0; p < nb_pixels_to_switch; p++) {
+      changed_pixels[p] = int(drand48() * Vignette::width * Vignette::height);
+      vignette->content[changed_pixels[p]] = 255 - vignette->content[changed_pixels[p]];
+    }
+
+    scalar_t r = classifier->classify(vignette);
+    sum += r;
+    sum_sq += sq(r);
+
+    for(int p = 0; p < nb_pixels_to_switch; p++) {
+      vignette->content[changed_pixels[p]] = 255 - vignette->content[changed_pixels[p]];
+    }
+  }
+
+  *mu = sum_sq/scalar_t(nb_samples);
+  *sigma = *mu - sq(sum/scalar_t(nb_samples));
+}
diff --git a/error_rates.h b/error_rates.h
new file mode 100644 (file)
index 0000000..899cd4d
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef ERROR_RATES_H
+#define ERROR_RATES_H
+
+#include "classifier.h"
+#include "vignette_generator.h"
+
+scalar_t error_rate(Classifier *classifier, int nb_vignettes, Vignette *vignettes, int *labels);
+
+scalar_t test_error_rate(VignetteGenerator *generator, Classifier *classifier, long int nb_to_try);
+
+#endif
diff --git a/fusion_sort.cc b/fusion_sort.cc
new file mode 100644 (file)
index 0000000..96d056f
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "fusion_sort.h"
+#include <string.h>
+
+inline void indexed_fusion(int na, int *ia, int nb, int *ib, int *ic, scalar_t *values) {
+  int *ma = ia + na, *mb = ib + nb;
+  while(ia < ma && ib < mb)
+    if(values[*ia] <= values[*ib]) *(ic++) = *(ia++);
+    else                           *(ic++) = *(ib++);
+  while(ia < ma) *(ic++) = *(ia++);
+  while(ib < mb) *(ic++) = *(ib++);
+}
+
+void indexed_fusion_sort(int n, int *from, int *result, scalar_t *values) {
+  ASSERT(n > 0);
+  if(n == 1) result[0] = from[0];
+  else {
+    int k = n/2;
+    indexed_fusion_sort(k, from, result, values);
+    indexed_fusion_sort(n - k, from + k, result + k, values);
+    memcpy((void *) from, (void *) result, n * sizeof(int));
+    indexed_fusion(k, from, n - k, from + k, result, values);
+  }
+}
+
+// Sorting in decreasing order
+
+inline void indexed_fusion_dec(int na, int *ia,
+                           int nb, int *ib,
+                           int *ic, scalar_t *values) {
+  int *ma = ia + na, *mb = ib + nb;
+  while(ia < ma && ib < mb)
+    if(values[*ia] > values[*ib]) *(ic++) = *(ia++);
+    else                          *(ic++) = *(ib++);
+  while(ia < ma) *(ic++) = *(ia++);
+  while(ib < mb) *(ic++) = *(ib++);
+}
+
+void indexed_fusion_dec_sort(int n, int *from, int *result, scalar_t *values) {
+  ASSERT(n > 0);
+  if(n == 1) result[0] = from[0];
+  else {
+    int k = n/2;
+    indexed_fusion_dec_sort(k, from, result, values);
+    indexed_fusion_dec_sort(n - k, from + k, result + k, values);
+    memcpy((void *) from, (void *) result, n * sizeof(int));
+    indexed_fusion_dec(k, from, n - k, from + k, result, values);
+  }
+}
+
+void fusion_two_cells(int n1, scalar_t *cell1, int n2, scalar_t *cell2, scalar_t *result) {
+  scalar_t *max1 = cell1 + n1, *max2 = cell2 + n2;
+  while(cell1 < max1 && cell2 < max2) {
+    if(*(cell1) <= *(cell2)) *(result++) = *(cell1++);
+    else                     *(result++) = *(cell2++);
+  }
+  while(cell1 < max1) *(result++) = *(cell1++);
+  while(cell2 < max2) *(result++) = *(cell2++);
+}
+
+void fusion_sort(int n, scalar_t *from, scalar_t *result) {
+  if(n > 1) {
+    fusion_sort(n/2, from, result);
+    fusion_sort(n - n/2, from + n/2, result + n/2);
+    memcpy(from, result, sizeof(scalar_t) * n);
+    fusion_two_cells(n/2, from, n - n/2, from + n/2, result);
+  } else result[0] = from[0];
+}
diff --git a/fusion_sort.h b/fusion_sort.h
new file mode 100644 (file)
index 0000000..e1254b9
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef FUSION_SORT_H
+#define FUSION_SORT_H
+
+#include "misc.h"
+
+void indexed_fusion_sort(int n, int *from, int *result, scalar_t *values);
+void indexed_fusion_dec_sort(int n, int *from, int *result, scalar_t *values);
+void fusion_sort(int n, scalar_t *from, scalar_t *result);
+
+#endif
diff --git a/global.cc b/global.cc
new file mode 100644 (file)
index 0000000..8137f35
--- /dev/null
+++ b/global.cc
@@ -0,0 +1,79 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <string.h>
+
+#include "global.h"
+
+Global global;
+
+Global::Global() { }
+
+Global::~Global() { }
+
+void Global::init_parser(ParamParser *parser) {
+  // The nice level of the process
+  parser->add_association("niceness", "15", false);
+  // Seed to initialize the random generator
+  parser->add_association("random_seed", "0", false);
+
+  // Where to put the generated files
+  parser->add_association("result_path", "/tmp/", false);
+  // The classifier filename
+  parser->add_association("classifier_name", "default.clf", false);
+
+  // Should we display a progress bar for lengthy operations
+  parser->add_association("progress_bar", "yes", false);
+
+  // The problem number
+  parser->add_association("problem_number", "0", false);
+
+  // The number of samples for training and testing
+  parser->add_association("nb_train_samples", "1000", false);
+  parser->add_association("nb_test_samples", "1000", false);
+  parser->add_association("nb_weak_learners", "1000", false);
+  parser->add_association("nb_optimization_weak_learners", "100", false);
+  parser->add_association("nb_sampled_samples", "-1", false);
+}
+
+void Global::read_parser(ParamParser *parser) {
+  niceness = parser->get_association_int("niceness");
+  random_seed = parser->get_association_int("random_seed");
+
+  strncpy(result_path, parser->get_association("result_path"), buffer_size);
+  strncpy(classifier_name, parser->get_association("classifier_name"), buffer_size);
+  if(!classifier_name[0]) {
+    sprintf(classifier_name, "%s/default.clf", result_path);
+  }
+
+  bar.set_visible(parser->get_association_bool("progress_bar"));
+
+  problem_number = parser->get_association_int("problem_number");
+
+  nb_train_samples = parser->get_association_int("nb_train_samples");
+  nb_test_samples = parser->get_association_int("nb_test_samples");
+  nb_weak_learners = parser->get_association_int("nb_weak_learners");
+  nb_optimization_weak_learners = parser->get_association_int("nb_optimization_weak_learners");
+  nb_sampled_samples = parser->get_association_int("nb_sampled_samples");
+}
diff --git a/global.h b/global.h
new file mode 100644 (file)
index 0000000..1066ac6
--- /dev/null
+++ b/global.h
@@ -0,0 +1,61 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef GLOBAL_H
+#define GLOBAL_H
+
+#include <iostream>
+
+using namespace std;
+
+#include "misc.h"
+#include "param_parser.h"
+#include "progress_bar.h"
+
+class Global {
+public:
+  int niceness;
+  int random_seed;
+  char result_path[buffer_size];
+  char classifier_name[buffer_size];
+  ProgressBar bar;
+
+  int problem_number;
+
+  int nb_train_samples;
+  int nb_test_samples;
+  int nb_weak_learners;
+  int nb_optimization_weak_learners;
+  int nb_sampled_samples;
+
+  Global();
+  ~Global();
+
+  void init_parser(ParamParser *parser);
+  void read_parser(ParamParser *parser);
+};
+
+extern Global global;
+
+#endif
diff --git a/gpl-3.0.txt b/gpl-3.0.txt
new file mode 100644 (file)
index 0000000..94a9ed0
--- /dev/null
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/jpeg_misc.cc b/jpeg_misc.cc
new file mode 100644 (file)
index 0000000..574bf13
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "jpeg_misc.h"
+
+void my_error_exit (j_common_ptr cinfo) {
+  my_error_ptr myerr = (my_error_ptr) cinfo->err;
+  (*cinfo->err->output_message) (cinfo);
+  longjmp (myerr->setjmp_buffer, 1);
+}
diff --git a/jpeg_misc.h b/jpeg_misc.h
new file mode 100644 (file)
index 0000000..b34da02
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef JPEG_MISC_H
+#define JPEG_MISC_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <setjmp.h>
+#include <jpeglib.h>
+
+struct my_error_mgr {
+  struct jpeg_error_mgr pub;
+  jmp_buf setjmp_buffer;
+};
+
+typedef struct my_error_mgr *my_error_ptr;
+
+void my_error_exit (j_common_ptr cinfo);
+
+#endif
diff --git a/misc.cc b/misc.cc
new file mode 100644 (file)
index 0000000..2f766a6
--- /dev/null
+++ b/misc.cc
@@ -0,0 +1,103 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <fstream>
+
+using namespace std;
+
+#include "misc.h"
+
+char *basename(char *name) {
+  char *result = name;
+  while(*name) {
+    if(*name == '/') result = name + 1;
+    name++;
+  }
+  return result;
+}
+
+char *next_word(char *buffer, char *r, int buffer_size) {
+  char *s;
+  s = buffer;
+
+  if(r != 0) {
+    while((*r == ' ') || (*r == '\t') || (*r == ',')) r++;
+    if(*r == '"') {
+      r++;
+      while((*r != '"') && (*r != '\0') &&
+            (s<buffer+buffer_size-1))
+        *s++ = *r++;
+      if(*r == '"') r++;
+    } else {
+      while((*r != '\r') && (*r != '\n') && (*r != '\0') &&
+            (*r != '\t') && (*r != ' ') && (*r != ',')) {
+        if(s == buffer + buffer_size) {
+          cerr << "Buffer overflow in next_word." << endl;
+          exit(1);
+        }
+        *s++ = *r++;
+      }
+    }
+
+    while((*r == ' ') || (*r == '\t') || (*r == ',')) r++;
+    if((*r == '\0') || (*r=='\r') || (*r=='\n')) r = 0;
+  }
+  *s = '\0';
+
+  return r;
+}
+
+scalar_t discrete_entropy(int *n, int nb) {
+  scalar_t s = 0, t = 0;
+  for(int k = 0; k < nb; k++) if(n[k] > 0) {
+    s += n[k] * log(scalar_t(n[k]));
+    t += n[k];
+  }
+  return (log(t) - s/scalar_t(t))/log(2.0);
+}
+
+void random_permutation(int *val, int nb) {
+  for(int k = 0; k < nb; k++) val[k] = k;
+  int i, t;
+  for(int k = 0; k < nb - 1; k++) {
+    i = int(drand48() * (nb - k)) + k;
+    t = val[i];
+    val[i] = val[k];
+    val[k] = t;
+  }
+}
+
+void tag_subset(bool *val, int nb_total, int nb_to_tag) {
+  ASSERT(nb_to_tag <= nb_total);
+  int index[nb_total];
+  random_permutation(index, nb_total);
+  for(int n = 0; n < nb_total; n++) val[n] = false;
+  for(int n = 0; n < nb_to_tag; n++) val[index[n]] = true;
+}
+
+int compare_couple(const void *a, const void *b) {
+  if(((Couple *) a)->value < ((Couple *) b)->value) return -1;
+  else if(((Couple *) a)->value > ((Couple *) b)->value) return 1;
+  else return 0;
+}
diff --git a/misc.h b/misc.h
new file mode 100644 (file)
index 0000000..d5f956c
--- /dev/null
+++ b/misc.h
@@ -0,0 +1,124 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MISC_H
+#define MISC_H
+
+#include <iostream>
+#include <cmath>
+#include <fstream>
+#include <cfloat>
+#include <stdlib.h>
+#include <string.h>
+
+using namespace std;
+
+typedef double scalar_t;
+// typedef float scalar_t;
+
+const int buffer_size = 1024;
+
+using namespace std;
+
+#ifdef DEBUG
+#define ASSERT(x) if(!(x)) { \
+  std::cerr << "ASSERT FAILED IN " << __FILE__ << ":" << __LINE__ << endl; \
+  abort(); \
+}
+#else
+#define ASSERT(x)
+#endif
+
+template<class T>
+T **allocate_array(int a, int b) {
+  T *tmp = new T[a * b];
+  T **array = new T *[a];
+  for(int k = 0; k < a; k++) {
+    array[k] = tmp;
+    tmp += b;
+  }
+  return array;
+}
+
+template<class T>
+void deallocate_array(T **array) {
+  delete[] array[0];
+  delete[] array;
+}
+
+template<class T>
+T smooth_min(T x, T y) {
+  T z = exp(x - y);
+  return 0.5 * (x + y - (x - y)/(1 + 1/z) - (y - x)/(1 + z));
+}
+
+template <class T>
+void write_var(ostream *os, const T *x) { os->write((char *) x, sizeof(T)); }
+
+template <class T>
+void read_var(istream *is, T *x) { is->read((char *) x, sizeof(T)); }
+
+template <class T>
+void grow(int *nb_max, int nb, T** current, int factor) {
+  ASSERT(*nb_max > 0);
+  if(nb == *nb_max) {
+    T *tmp = new T[*nb_max * factor];
+    memcpy(tmp, *current, *nb_max * sizeof(T));
+    delete[] *current;
+    *current = tmp;
+    *nb_max *= factor;
+  }
+}
+
+template <class T>
+inline T sq(T x) {
+  return x * x;
+}
+
+inline scalar_t log2(scalar_t x) {
+  return log(x)/log(2.0);
+}
+
+inline scalar_t xi(scalar_t x) {
+  if(x <= 0.0) return 0.0;
+  else         return - x * log(x)/log(2.0);
+}
+
+scalar_t discrete_entropy(int *n, int nb);
+
+char *basename(char *name);
+
+char *next_word(char *buffer, char *r, int buffer_size);
+
+void random_permutation(int *val, int nb);
+void tag_subset(bool *val, int nb_total, int nb_to_tag);
+
+struct Couple {
+  int index;
+  scalar_t value;
+};
+
+int compare_couple(const void *a, const void *b);
+
+#endif
diff --git a/naive_bayesian_classifier.cc b/naive_bayesian_classifier.cc
new file mode 100644 (file)
index 0000000..f8799c1
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "naive_bayesian_classifier.h"
+#include "classifier_reader.h"
+
+NaiveBayesianClassifier::NaiveBayesianClassifier() { }
+
+NaiveBayesianClassifier::~NaiveBayesianClassifier() { }
+
+const char *NaiveBayesianClassifier::name() {
+  return "NAIVE_BAYESIAN";
+}
+
+void NaiveBayesianClassifier::train(int nb_vignettes, Vignette *vignettes, int *labels) {
+  for(int k = 0; k < Vignette::width * Vignette::height * Vignette::nb_grayscales; k++) {
+    proba_given_0[k] = 0;
+    proba_given_1[k] = 0;
+  }
+
+  int nb_0 = 0, nb_1 = 0;
+
+  global.bar.init(&cout, nb_vignettes);
+  for(int n = 0; n < nb_vignettes; n++) {
+    if(labels[n] == 1) {
+      nb_1++;
+      for(int k = 0; k < Vignette::width * Vignette::height; k++) {
+        proba_given_1[k * Vignette::nb_grayscales + vignettes[n].content[k]] += 1.0;
+      }
+    } else {
+      nb_0++;
+      for(int k = 0; k < Vignette::width * Vignette::height; k++) {
+        proba_given_0[k * Vignette::nb_grayscales + vignettes[n].content[k]] += 1.0;
+      }
+    }
+    global.bar.refresh(&cout, n);
+  }
+  global.bar.finish(&cout);
+
+  for(int k = 0; k < Vignette::width * Vignette::height * Vignette::nb_grayscales; k++) {
+    proba_given_0[k] /= scalar_t(nb_0);
+    proba_given_1[k] /= scalar_t(nb_1);
+  }
+}
+
+scalar_t NaiveBayesianClassifier::classify(Vignette *vignette) {
+  scalar_t result = 0.0;
+
+  for(int k = 0; k < Vignette::width * Vignette::height; k++) {
+    result += log(proba_given_1[k * Vignette::nb_grayscales + vignette->content[k]])
+      - log(proba_given_0[k * Vignette::nb_grayscales + vignette->content[k]]);
+  }
+
+  return result;
+}
+
+void NaiveBayesianClassifier::read(istream *in) {
+  in->read((char *) proba_given_0, sizeof(scalar_t) * Vignette::width * Vignette::height * Vignette::nb_grayscales);
+  in->read((char *) proba_given_1, sizeof(scalar_t) * Vignette::width * Vignette::height * Vignette::nb_grayscales);
+}
+
+void NaiveBayesianClassifier::write(ostream *out) {
+  int t;
+  t = CT_NAIVE_BAYESIAN;
+  write_var(out, &t);
+  out->write((char *) proba_given_0, sizeof(scalar_t) * Vignette::width * Vignette::height * Vignette::nb_grayscales);
+  out->write((char *) proba_given_1, sizeof(scalar_t) * Vignette::width * Vignette::height * Vignette::nb_grayscales);
+}
diff --git a/naive_bayesian_classifier.h b/naive_bayesian_classifier.h
new file mode 100644 (file)
index 0000000..de045ff
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef NAIVE_BAYESIAN_CLASSIFIER_H
+#define NAIVE_BAYESIAN_CLASSIFIER_H
+
+#include "classifier.h"
+#include "vignette.h"
+
+class NaiveBayesianClassifier : public Classifier {
+  scalar_t proba_given_0[Vignette::width * Vignette::height * Vignette::nb_grayscales];
+  scalar_t proba_given_1[Vignette::width * Vignette::height * Vignette::nb_grayscales];
+public:
+  NaiveBayesianClassifier();
+  ~NaiveBayesianClassifier();
+  virtual const char *name();
+  virtual void train(int nb_vignettes, Vignette *vignettes, int *labels);
+  virtual scalar_t classify(Vignette *vignette);
+  virtual void read(istream *in);
+  virtual void write(ostream *out);
+};
+
+#endif
diff --git a/param_parser.cc b/param_parser.cc
new file mode 100644 (file)
index 0000000..2d918bd
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+// All this is clearly non-optimal, loaded with news and deletes and
+// should be rewritten.
+
+#include <string.h>
+
+#include "param_parser.h"
+
+ParamParser::ParamParser() : _nb_max(10),
+                             _nb(0),
+                             _names(new char *[_nb_max]),
+                             _values(new char *[_nb_max]),
+                             _changed(new bool[_nb_max]) { }
+
+ParamParser::~ParamParser() {
+  for(int k = 0; k < _nb; k++) {
+    delete[] _names[k];
+    delete[] _values[k];
+  }
+  delete[] _names;
+  delete[] _values;
+  delete[] _changed;
+}
+
+void ParamParser::add_association(const char *variable_name, const char *variable_value, bool change) {
+  int n;
+
+  for(n = 0; n < _nb && strcmp(variable_name, _names[n]) != 0; n++);
+
+  if(n < _nb) {
+    delete[] _values[n];
+    _values[n] = new char[strlen(variable_value) + 1];
+    strcpy(_values[n], variable_value);
+    _changed[n] = change;
+  } else {
+    int nm;
+    nm = _nb_max; grow(&nm, _nb, &_names, 2);
+    nm = _nb_max; grow(&nm, _nb, &_values, 2);
+    grow(&_nb_max, _nb, &_changed, 2);
+
+    _names[_nb] = new char[strlen(variable_name) + 1];
+    strcpy(_names[_nb], variable_name);
+    _values[_nb] = new char[strlen(variable_value) + 1];
+    strcpy(_values[_nb], variable_value);
+    _changed[_nb] = change;
+    _nb++;
+  }
+}
+
+char *ParamParser::get_association(const char *variable_name) {
+  int n;
+  for(n = 0; n < _nb && strcmp(variable_name, _names[n]) != 0; n++);
+  if(n < _nb) return _values[n];
+  else        {
+    cerr << "Unknown parameter \"" << variable_name << "\", existing ones are" << endl;
+    for(int n = 0; n < _nb; n++)
+      cerr << "   \"" << _names[n] << "\"" << endl;
+    exit(1);
+  }
+}
+
+int ParamParser::get_association_int(const char *variable_name) {
+  char *u = get_association(variable_name);
+  char *s = u;
+  while(*s)
+    if((*s < '0' || *s > '9') && *s != '-') {
+      cerr << "Non-numerical value for " << variable_name << " (" << u << ")" << endl;
+      exit(1);
+    } else s++;
+  return atoi(u);
+}
+
+long int ParamParser::get_association_long_int(const char *variable_name) {
+  char *u = get_association(variable_name);
+  char *s = u;
+  while(*s)
+    if((*s < '0' || *s > '9') && *s != '-') {
+      cerr << "Non-numerical value for " << variable_name << " (" << u << ")" << endl;
+      exit(1);
+    } else s++;
+  return atol(u);
+}
+
+scalar_t ParamParser::get_association_scalar(const char *variable_name) {
+  char *u = get_association(variable_name);
+  char *s = u;
+  while(*s)
+    if((*s < '0' || *s > '9') && *s != '.' && *s != 'e' && *s != '-') {
+      cerr << "Non-numerical value for " << variable_name << " (" << u << ")" << endl;
+      exit(1);
+    } else s++;
+  return atof(u);
+}
+
+bool ParamParser::get_association_bool(const char *variable_name) {
+  char *value = get_association(variable_name);
+  if(strcasecmp(value, "") == 0 || strcasecmp(value, "y") == 0 || strcasecmp(value, "yes") == 0) return true;
+  if(strcasecmp(value, "n") == 0 || strcasecmp(value, "no") == 0) return false;
+  cerr << "Expects nothing (for yes), or y[es] or n[o] for a boolean argument and got '" << value << "'" << endl;
+  exit(1);
+}
+
+void ParamParser::parse_options(int argc, char **argv,
+                                bool allow_undefined,
+                                int *new_argc, char **new_argv) {
+
+  int i = 1;
+
+  if(new_argc && new_argv)
+    new_argv[(*new_argc)++] = argv[0];
+
+  while(i < argc) {
+    if(strncmp(argv[i], "--", 2) == 0) {
+      // This is so 70s! I luuuuv it!
+      char variable_name[buffer_size] = "", variable_value[buffer_size] = "";
+      char *o = argv[i] + 2, *s = variable_name, *u = variable_value;
+      while(*o && *o != '=') *s++ = *o++;
+      *s = '\0';
+      if(*o) { o++; while(*o) *u++ = *o++; }
+      *u = '\0';
+      if(!allow_undefined) get_association(variable_name);
+      add_association(variable_name, variable_value, true);
+    } else {
+      if(new_argc && new_argv)
+        new_argv[(*new_argc)++] = argv[i];
+      else {
+        cerr << "Can not parse " << argv[i] << endl;
+        exit(1);
+      }
+    }
+    i++;
+  }
+}
+
+void ParamParser::print_all(ostream *os) {
+  for(int n = 0; n < _nb; n++) {
+    (*os) << (_changed[n] ? " * " : "   ") << "\"" << _names[n] << "\" \"" << _values[n] << "\"" << endl;
+  }
+}
+
diff --git a/param_parser.h b/param_parser.h
new file mode 100644 (file)
index 0000000..3477c27
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/*
+
+  A class to parse the arguments from the command line.
+
+ */
+
+#ifndef PARAM_PARSER_H
+#define PARAM_PARSER_H
+
+#include <iostream>
+#include "misc.h"
+
+using namespace std;
+
+class ParamParser {
+  int _nb_max, _nb;
+  char **_names, **_values;
+  bool *_changed;
+public:
+  ParamParser();
+  ~ParamParser();
+  void add_association(const char *variable_name, const char *variable_value, bool change);
+  char *get_association(const char *variable_name);
+  int get_association_int(const char *variable_name);
+  long int get_association_long_int(const char *variable_name);
+  scalar_t get_association_scalar(const char *variable_name);
+  bool get_association_bool(const char *variable_name);
+
+  void parse_options(int argc, char **argv, bool allow_undefined, int *new_argc, char **new_argv);
+  void print_all(ostream *os);
+};
+
+#endif
diff --git a/progress_bar.cc b/progress_bar.cc
new file mode 100644 (file)
index 0000000..96dc313
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <time.h>
+#include "progress_bar.h"
+
+ProgressBar::ProgressBar()  : _visible(false), _value_max(-1) { }
+
+void ProgressBar::set_visible(bool visible) {
+  _visible = visible;
+}
+
+void ProgressBar::init(ostream *out, scalar_t value_max) {
+  _value_max = value_max;
+  _last_step = -1;
+  time(&_initial_time);
+  refresh(out, 0);
+}
+
+void ProgressBar::refresh(ostream *out, scalar_t value) {
+  if(_visible && _value_max > 0) {
+    int step = int((value * 40) / _value_max);
+
+    if(step > _last_step) {
+      char buffer[width + 1], date_buffer[buffer_size];
+      int i, j;
+      j = sprintf(buffer, "Timer: ");
+
+      for(i = 0; i < step; i++) buffer[j + i] = 'X';
+      for(; i < 40; i++) buffer[j + i] = (i%4 == 0) ? '+' : '-';
+      j += i;
+
+      time_t current_time; time(&current_time);
+      int rt = int(((current_time - _initial_time)/scalar_t(value)) * scalar_t(_value_max - value));
+
+      if(rt > 0) {
+        if(rt > 3600 * 24) {
+          time_t current;
+          time(&current);
+          current += rt;
+          strftime(date_buffer, buffer_size, "%a %b %e %H:%M", localtime(&current));
+          j += snprintf(buffer + j, width - j - 1, " (end ~ %s)", date_buffer);
+        } else {
+          int hours = rt/3600, min = (rt%3600)/60, sec = rt%60;
+          if(hours > 0)
+            j += snprintf(buffer + j, width - j - 1, " (~%dh%dmin left)", hours, min);
+          else if(min > 0)
+            j += snprintf(buffer + j, width - j - 1, " (~%dmin%ds left)", min, sec);
+          else
+            j += snprintf(buffer + j, width - j - 1, " (~%ds left)", sec);
+        }
+      }
+
+      for(; j < width; j++) buffer[j] = ' ';
+      buffer[j] = '\0';
+      (*out) << buffer << "\r";
+      out->flush();
+      _last_step = step;
+    }
+  }
+}
+
+void ProgressBar::finish(ostream *out) {
+  if(_visible) {
+    char buffer[width + 1];
+    int j;
+    time_t current_time; time(&current_time);
+    int rt = int(current_time - _initial_time);
+    int min = rt/60, sec = rt%60;
+    j = sprintf(buffer, "Timer: Total %dmin%ds", min, sec);
+    for(; j < width; j++) buffer[j] = ' ';
+    buffer[j] = '\0';
+    (*out) << buffer << endl;
+    out->flush();
+  }
+}
diff --git a/progress_bar.h b/progress_bar.h
new file mode 100644 (file)
index 0000000..ef0a88d
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/*
+
+  This class displays a progress bar in text mode and computes a rough
+  estimate of the remaining processing time.
+
+*/
+
+#ifndef PROGRESS_BAR_H
+#define PROGRESS_BAR_H
+
+#include <iostream>
+
+using namespace std;
+
+#include "misc.h"
+
+class ProgressBar {
+  const static int width = 80;
+  bool _visible;
+  scalar_t _value_max, _last_step;
+  time_t _initial_time;
+public:
+  ProgressBar();
+  void set_visible(bool visible);
+  void init(ostream *out, scalar_t value_max);
+  void refresh(ostream *out, scalar_t value);
+  void finish(ostream *out);
+};
+
+#endif
diff --git a/rgb_image.cc b/rgb_image.cc
new file mode 100644 (file)
index 0000000..f803363
--- /dev/null
@@ -0,0 +1,479 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <iostream>
+#include <stdio.h>
+
+#include <libpng/png.h>
+#include "jpeg_misc.h"
+
+#include "rgb_image.h"
+
+void RGBImage::allocate() {
+  _bit_plans = new unsigned char **[RGB_DEPTH];
+  _bit_lines = new unsigned char *[RGB_DEPTH * _height];
+  _bit_map = new unsigned char [_width * _height * RGB_DEPTH];
+  for(int k = 0; k < RGB_DEPTH; k++) _bit_plans[k] = _bit_lines + k * _height;
+  for(int k = 0; k < RGB_DEPTH * _height; k++) _bit_lines[k] = _bit_map + k * _width;
+}
+
+void RGBImage::deallocate() {
+  delete[] _bit_plans;
+  delete[] _bit_lines;
+  delete[] _bit_map;
+}
+
+RGBImage::RGBImage() : _bit_plans(0), _bit_lines(0), _bit_map(0) { }
+
+RGBImage::RGBImage(int width, int height) : _width(width), _height(height) {
+  allocate();
+  memset(_bit_map, 0, _width * _height * RGB_DEPTH * sizeof(unsigned char));
+}
+
+RGBImage::RGBImage(RGBImage *image, scalar_t scale) {
+  _width = int(scale * image->_width);
+  _height = int(scale * image->_height);
+
+  allocate();
+
+  for(int y = 0; y < _height; y++) {
+    for(int x = 0; x < _width; x++) {
+
+      const int delta = 10;
+      int sr = 0, sg = 0, sb = 0, t = 0;
+      int xo, yo;
+
+      for(int yy = y * delta; yy < (y + 1) * delta; yy++) {
+        for(int xx = x * delta; xx < (x + 1) * delta; xx++) {
+          xo = (image->_width * xx)/(_width * delta);
+          yo = (image->_height * yy)/(_height * delta);
+          if(xo >= 0 && xo < image->_width && yo >= 0 && yo < image->_height) {
+            sr += image->_bit_plans[RED][yo][xo];
+            sg += image->_bit_plans[GREEN][yo][xo];
+            sb += image->_bit_plans[BLUE][yo][xo];
+            t++;
+          }
+        }
+      }
+
+      if(t > 0) {
+        _bit_plans[RED][y][x] = sr / t;
+        _bit_plans[GREEN][y][x] = sg / t;
+        _bit_plans[BLUE][y][x] = sb / t;
+      } else {
+        _bit_plans[RED][y][x] = 0;
+        _bit_plans[GREEN][y][x] = 0;
+        _bit_plans[BLUE][y][x] = 0;
+      }
+
+    }
+  }
+}
+
+RGBImage::~RGBImage() {
+  deallocate();
+}
+
+void RGBImage::read_png(const char *name) {
+  // This is the number of bytes the read_png routine will read to
+  // decide if the file is a PNG or not. According to the png
+  // documentation, it can be 1 to 8 bytes, 8 being the max and the
+  // best.
+
+  const int header_size = 8;
+
+  png_byte header[header_size];
+  png_bytep *row_pointers;
+
+  deallocate();
+
+  // open file
+  FILE *fp = fopen(name, "rb");
+  if (!fp) {
+    cerr << "Unable to open file " << name << " for reading.\n";
+    exit(1);
+  }
+
+  // read header
+  fread(header, 1, header_size, fp);
+  if (png_sig_cmp(header, 0, header_size)) {
+    cerr << "File " << name << " does not look like PNG.\n";
+    fclose(fp);
+    exit(1);
+  }
+
+  // create png pointer
+  png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
+  if (!png_ptr) {
+    cerr << "png_create_read_struct failed\n";
+    fclose(fp);
+    exit(1);
+  }
+
+  // create png info struct
+  png_infop info_ptr = png_create_info_struct(png_ptr);
+  if (!info_ptr) {
+    png_destroy_read_struct(&png_ptr, (png_infopp) 0, (png_infopp) 0);
+    cerr << "png_create_info_struct failed\n";
+    fclose(fp);
+    exit(1);
+  }
+
+  // get image info
+  png_init_io(png_ptr, fp);
+  png_set_sig_bytes(png_ptr, header_size);
+  png_read_info(png_ptr, info_ptr);
+
+  _width = info_ptr->width;
+  _height = info_ptr->height;
+
+  png_byte bit_depth, color_type, channels;
+  color_type = info_ptr->color_type;
+  bit_depth = info_ptr->bit_depth;
+  channels = info_ptr->channels;
+
+  if(bit_depth != 8) {
+    cerr << "Can only read 8-bits PNG images." << endl;
+    exit(1);
+  }
+
+  // allocate image pointer
+  row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * _height);
+  for (int y = 0; y < _height; y++)
+    row_pointers[y] = (png_byte*) malloc(info_ptr->rowbytes);
+
+  allocate();
+
+  // read image
+  png_read_image(png_ptr, row_pointers);
+
+  // send image to red, green and blue buffers
+  switch (color_type) {
+  case PNG_COLOR_TYPE_GRAY:
+    {
+      unsigned char pixel = 0;
+      for (int y = 0; y < _height; y++) for (int x = 0; x < _width; x++) {
+        pixel = row_pointers[y][x];
+        _bit_plans[RED][y][x] = pixel;
+        _bit_plans[GREEN][y][x] = pixel;
+        _bit_plans[BLUE][y][x] = pixel;
+      }
+    }
+    break;
+
+  case PNG_COLOR_TYPE_GRAY_ALPHA:
+    cerr << "PNG type GRAY_ALPHA not supported.\n";
+    exit(1);
+    break;
+
+  case PNG_COLOR_TYPE_PALETTE:
+    cerr << "PNG type PALETTE not supported.\n";
+    exit(1);
+    break;
+
+  case PNG_COLOR_TYPE_RGB:
+    {
+      if(channels != RGB_DEPTH) {
+        cerr << "Unsupported number of channels for RGB type\n";
+        break;
+      }
+      int k;
+      for (int y = 0; y < _height; y++) {
+        k = 0;
+        for (int x = 0; x < _width; x++) {
+          _bit_plans[RED][y][x] = row_pointers[y][k++];
+          _bit_plans[GREEN][y][x] = row_pointers[y][k++];
+          _bit_plans[BLUE][y][x] = row_pointers[y][k++];
+        }
+      }
+    }
+    break;
+
+  case PNG_COLOR_TYPE_RGB_ALPHA:
+    cerr << "PNG type RGB_ALPHA not supported.\n";
+    exit(1);
+    break;
+
+  default:
+    cerr << "Unknown PNG type\n";
+    exit(1);
+  }
+
+  // release memory
+  png_destroy_read_struct(&png_ptr, &info_ptr, 0);
+
+  for (int y = 0; y < _height; y++) free(row_pointers[y]);
+  free(row_pointers);
+
+  fclose(fp);
+}
+
+void RGBImage::write_png(const char *name) {
+  png_bytep *row_pointers;
+
+  // create file
+  FILE *fp = fopen(name, "wb");
+
+  if (!fp) {
+    cerr << "Unable to create image '" << name << "'\n";
+    exit(1);
+  }
+
+  png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
+
+  if (!png_ptr) {
+    cerr << "png_create_write_struct failed\n";
+    fclose(fp);
+    exit(1);
+  }
+
+  png_infop info_ptr = png_create_info_struct(png_ptr);
+  if (!info_ptr) {
+    cerr << "png_create_info_struct failed\n";
+    fclose(fp);
+    exit(1);
+  }
+
+  png_init_io(png_ptr, fp);
+
+  png_set_IHDR(png_ptr, info_ptr, _width, _height,
+               8, 2, PNG_INTERLACE_NONE,
+               PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+
+  png_write_info(png_ptr, info_ptr);
+
+  // allocate memory
+  row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * _height);
+  for (int y = 0; y < _height; y++)
+    row_pointers[y] = (png_byte*) malloc(info_ptr->rowbytes);
+
+  int k;
+  for (int y = 0; y < _height; y++) {
+    k = 0;
+    for (int x = 0; x < _width; x++) {
+      row_pointers[y][k++] = _bit_map[x + _width * (y + _height * RED)];
+      row_pointers[y][k++] = _bit_map[x + _width * (y + _height * GREEN)];
+      row_pointers[y][k++] = _bit_map[x + _width * (y + _height * BLUE)];
+    }
+  }
+
+  png_write_image(png_ptr, row_pointers);
+  png_write_end(png_ptr, 0);
+
+  png_destroy_write_struct(&png_ptr, &info_ptr);
+
+  // cleanup heap allocation
+  for (int y = 0; y < _height; y++) free(row_pointers[y]);
+  free(row_pointers);
+
+  fclose(fp);
+}
+
+void RGBImage::write_jpg(const char *filename, int quality) {
+  struct jpeg_compress_struct cinfo;
+  struct my_error_mgr jerr;
+  FILE *outfile;                /* target file */
+  JSAMPARRAY buffer;            /* Output row buffer */
+
+  jpeg_create_compress (&cinfo);
+
+  if ((outfile = fopen (filename, "wb")) == 0) {
+    fprintf (stderr, "Can't open %s\n", filename);
+    exit(1);
+  }
+
+  cinfo.err = jpeg_std_error (&jerr.pub);
+  jerr.pub.error_exit = my_error_exit;
+
+  if (setjmp (jerr.setjmp_buffer)) {
+    jpeg_destroy_compress (&cinfo);
+    fclose (outfile);
+    exit(1);
+  }
+
+  jpeg_stdio_dest (&cinfo, outfile);
+
+  cinfo.image_width = _width;
+  cinfo.image_height = _height;
+  cinfo.input_components = RGB_DEPTH;
+
+  cinfo.in_color_space = JCS_RGB;
+
+  jpeg_set_defaults (&cinfo);
+  jpeg_set_quality (&cinfo, quality, TRUE);
+  jpeg_start_compress (&cinfo, TRUE);
+  int y = 0;
+  buffer =
+    (*cinfo.mem->alloc_sarray) ((j_common_ptr) & cinfo, JPOOL_IMAGE,
+                                _width * RGB_DEPTH, 1);
+  while (int(cinfo.next_scanline) < _height) {
+    for(int d = 0; d < RGB_DEPTH; d++)
+      for(int x = 0; x < _width; x++)
+        buffer[0][x * RGB_DEPTH + d] =
+          (JSAMPLE) ((_bit_map[x + _width * (y + _height * d)] * (MAXJSAMPLE + 1)) / 255);
+    jpeg_write_scanlines (&cinfo, buffer, 1);
+    y++;
+  }
+
+  jpeg_finish_compress (&cinfo);
+  fclose (outfile);
+
+  jpeg_destroy_compress (&cinfo);
+}
+
+void RGBImage::read_jpg(const char *filename) {
+  struct jpeg_decompress_struct cinfo;
+  struct my_error_mgr jerr;
+  FILE *infile;
+  JSAMPARRAY buffer;
+
+  deallocate();
+
+  if ((infile = fopen (filename, "rb")) == 0) {
+    fprintf (stderr, "can't open %s\n", filename);
+    return;
+  }
+
+  cinfo.err = jpeg_std_error (&jerr.pub);
+  jerr.pub.error_exit = my_error_exit;
+
+  if (setjmp (jerr.setjmp_buffer)) {
+    jpeg_destroy_decompress (&cinfo);
+    fclose (infile);
+    delete[] _bit_map;
+    _width = 0;
+    _height = 0;
+    _bit_map = 0;
+    return;
+  }
+
+  jpeg_create_decompress (&cinfo);
+  jpeg_stdio_src (&cinfo, infile);
+  jpeg_read_header (&cinfo, TRUE);
+  jpeg_start_decompress (&cinfo);
+
+  _width = cinfo.output_width;
+  _height = cinfo.output_height;
+  int depth = cinfo.output_components;
+
+  allocate();
+
+  buffer =
+    (*cinfo.mem->alloc_sarray) ((j_common_ptr) & cinfo, JPOOL_IMAGE,
+                                _width * depth, 1);
+
+  int y = 0;
+  while (cinfo.output_scanline < cinfo.output_height) {
+    jpeg_read_scanlines (&cinfo, buffer, 1);
+    if(depth == 1) {
+      for(int d = 0; d < RGB_DEPTH; d++)
+        for(int x = 0; x < _width; x++)
+          _bit_plans[d][y][x] =
+            (unsigned char) ((buffer[0][x * depth] * 255) / (MAXJSAMPLE + 1));
+    } else {
+      for(int d = 0; d < depth; d++)
+        for(int x = 0; x < _width; x++)
+          _bit_plans[d][y][x] =
+            (unsigned char) ((buffer[0][x * depth + d] * 255) / (MAXJSAMPLE + 1));
+    }
+    y++;
+  }
+
+  jpeg_finish_decompress (&cinfo);
+  jpeg_destroy_decompress (&cinfo);
+
+  fclose (infile);
+}
+
+void RGBImage::draw_line(int thickness,
+                         unsigned char r, unsigned char g, unsigned char b,
+                         scalar_t x0, scalar_t y0, scalar_t x1, scalar_t y1) {
+  int l = 0;
+  int dx, dy, h, v;
+  int ix0 = int(x0 + 0.5), iy0 = int(y0 + 0.5), ix1 = int(x1 + 0.5), iy1 = int(y1 + 0.5);
+
+  if(ix0 < ix1) { dx = 1; h = ix1 - ix0; } else { dx = -1; h = ix0 - ix1; }
+  if(iy0 < iy1) { dy = 1; v = iy1 - iy0; } else { dy = -1; v = iy0 - iy1; }
+
+  int x = ix0, y = iy0;
+
+  if(h > v) {
+    for(int i = 0; i < h + 1; i++) {
+      for(int ex = - thickness / 2 - 1; ex < (thickness + 1) / 2 + 1; ex++) {
+        for(int ey = - thickness / 2 - 1; ey < (thickness + 1) / 2 + 1; ey++) {
+          if(ex * ex + ey * ey <= thickness * thickness / 4) {
+            int xx = x + ex, yy = y + ey;
+            if(xx >= 0 && xx < _width && yy >= 0 && yy < _height)
+              set_pixel(xx, yy, r, g, b);
+          }
+        }
+      }
+
+      x += dx; l += v;
+      if(l > 0) { y += dy; l -= h; }
+    }
+
+  } else {
+
+    for(int i = 0; i < v + 1; i++) {
+      for(int ex = - thickness / 2 - 1; ex < (thickness + 1) / 2 + 1; ex++) {
+        for(int ey = - thickness / 2 - 1; ey < (thickness + 1) / 2 + 1; ey++) {
+          if(ex * ex + ey * ey <= thickness * thickness / 4) {
+            int xx = x + ex, yy = y + ey;
+            if(xx >= 0 && xx < _width && yy >= 0 && yy < _height)
+              set_pixel(xx, yy, r, g, b);
+          }
+        }
+      }
+
+      y += dy; l -= h;
+      if(l < 0) { x += dx; l += v; }
+    }
+
+  }
+
+}
+
+void RGBImage::draw_ellipse(int thickness,
+                            unsigned char r, unsigned char g, unsigned char b,
+                            scalar_t xc, scalar_t yc, scalar_t radius_1, scalar_t radius_2, scalar_t tilt) {
+  scalar_t ux1 =   cos(tilt) * radius_1, uy1 =   sin(tilt) * radius_1;
+  scalar_t ux2 = - sin(tilt) * radius_2, uy2 =   cos(tilt) * radius_2;
+
+  const int nb_points_to_draw = 80;
+  scalar_t x, y, px = 0, py = 0;
+
+  for(int i = 0; i <= nb_points_to_draw; i++) {
+    scalar_t alpha = (M_PI * 2 * scalar_t(i)) / scalar_t(nb_points_to_draw);
+
+    x = xc + cos(alpha) * ux1 + sin(alpha) * ux2;
+    y = yc + cos(alpha) * uy1 + sin(alpha) * uy2;
+
+    if(i > 0) {
+      draw_line(thickness, r, g, b, px, py, x, y);
+    }
+
+    px = x; py = y;
+  }
+}
diff --git a/rgb_image.h b/rgb_image.h
new file mode 100644 (file)
index 0000000..0f7bf66
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/*
+
+  A simple image class to either load color images, or produce
+  materials.
+
+ */
+
+#ifndef RGB_IMAGE_H
+#define RGB_IMAGE_H
+
+#include "misc.h"
+
+class RGBImage {
+protected:
+  int _width, _height;
+  unsigned char ***_bit_plans, **_bit_lines, *_bit_map;
+  static const int RED = 0;
+  static const int GREEN = 1;
+  static const int BLUE = 2;
+  static const int RGB_DEPTH = 3;
+
+  void allocate();
+  void deallocate();
+
+public:
+
+  RGBImage();
+  RGBImage(int width, int height);
+  RGBImage(RGBImage *image, scalar_t scale);
+  virtual ~RGBImage();
+
+  inline int width() const { return _width; }
+  inline int height() const { return _height; }
+
+  inline void set_pixel(int x, int y, unsigned char r, unsigned char g, unsigned char b) {
+    ASSERT(x >= 0 && x < _width && y >= 0 && y < _height);
+    _bit_plans[RED][y][x] = r;
+    _bit_plans[GREEN][y][x] = g;
+    _bit_plans[BLUE][y][x] = b;
+  }
+
+  inline unsigned char pixel(int x, int y, int d) {
+    ASSERT(x >= 0 && x < _width && y >= 0 && y < _height && d >= 0 && d < RGB_DEPTH);
+    return _bit_plans[d][y][x];
+  }
+
+  virtual void read_png(const char *filename);
+  virtual void write_png(const char *filename);
+
+  virtual void read_jpg(const char *filename);
+  virtual void write_jpg(const char *filename, int quality);
+
+  virtual void draw_line(int thickness,
+                         unsigned char r, unsigned char g, unsigned char b,
+                         scalar_t x0, scalar_t y0, scalar_t x1, scalar_t y1);
+
+  virtual void draw_ellipse(int thickness,
+                            unsigned char r, unsigned char g, unsigned char b,
+                            scalar_t xc, scalar_t yc, scalar_t radius_1, scalar_t radius_2, scalar_t tilt);
+};
+
+#endif
diff --git a/shape.cc b/shape.cc
new file mode 100644 (file)
index 0000000..a1932ae
--- /dev/null
+++ b/shape.cc
@@ -0,0 +1,257 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "shape.h"
+
+int Shape::generate_part_part(scalar_t *xp, scalar_t *yp, int *nb_pixels,
+                              scalar_t radius, scalar_t hole_radius,
+                              scalar_t x1, scalar_t y1, scalar_t x2, scalar_t y2) {
+  if(abs(x1 - x2) > gap_max || abs(y1 - y2) > gap_max) {
+
+    scalar_t d = sqrt(scalar_t(sq(x1 - x2) + sq(y1 - y2)))/5;
+    scalar_t x3, y3, dx, dy;
+
+    do {
+      // Isotropic jump
+      do {
+        dx = (2 * drand48() - 1) * d;
+        dy = (2 * drand48() - 1) * d;
+      } while(sq(dx) + sq(dy) > sq(d));
+      x3 = (x1 + x2) / 2 + dx;
+      y3 = (y1 + y2) / 2 + dy;
+    } while(sq(x3) + sq(y3) > sq(radius));
+
+    if(generate_part_part(xp, yp, nb_pixels,
+                          radius, hole_radius, x1, y1, x3, y3)) {
+      return 1;
+    }
+
+    if(generate_part_part(xp, yp, nb_pixels,
+                          radius, hole_radius, x3, y3, x2, y2)) {
+      return 1;
+    }
+
+  } else {
+
+    if(sq(x1) + sq(y1) >= sq(radius) || sq(x1) + sq(y1) < sq(hole_radius)) {
+      return 1;
+    }
+
+    xp[*nb_pixels] = x1;
+    yp[*nb_pixels] = y1;
+    (*nb_pixels)++;
+
+  }
+
+  return 0;
+}
+
+void Shape::generate_part(scalar_t *xp, scalar_t *yp, int *nb_pixels,
+                          scalar_t radius, scalar_t hole_radius) {
+  scalar_t x1, y1, x2, y2, x3, y3, x4, y4;
+  int err1, err2, err3, err4;
+
+  do {
+    *nb_pixels = 0;
+
+    do {
+      x1 = drand48() * radius;
+      y1 = drand48() * radius;
+    } while(sq(x1) + sq(y1) > sq(radius) || sq(x1) + sq(y1) < sq(hole_radius));
+
+    do {
+      x2 = -drand48() * radius;
+      y2 = drand48() * radius;
+    } while(sq(x2) + sq(y2) > sq(radius) || sq(x2) + sq(y2) < sq(hole_radius));
+
+    do {
+      x3 = -drand48() * radius;
+      y3 = -drand48() * radius;
+    } while(sq(x3) + sq(y3) > sq(radius) || sq(x3) + sq(y3) < sq(hole_radius));
+
+    do {
+      x4 = drand48() * radius;
+      y4 = -drand48() * radius;
+    } while(sq(x4) + sq(y4) > sq(radius) || sq(x4) + sq(y4) < sq(hole_radius));
+
+    n_pixels1 = *nb_pixels;
+    err1 = generate_part_part(xp, yp, nb_pixels, radius, hole_radius, x1, y1, x2, y2);
+    n_pixels2 = *nb_pixels;
+    err2 = generate_part_part(xp, yp, nb_pixels, radius, hole_radius, x2, y2, x3, y3);
+    n_pixels3 = *nb_pixels;
+    err3 = generate_part_part(xp, yp, nb_pixels, radius, hole_radius, x3, y3, x4, y4);
+    n_pixels4 = *nb_pixels;
+    err4 = generate_part_part(xp, yp, nb_pixels, radius, hole_radius, x4, y4, x1, y1);
+
+  } while(err1 || err2 || err3 || err4);
+}
+
+Shape::Shape() {
+  nb_pixels = 0;
+  x_pixels = 0;
+  y_pixels = 0;
+}
+
+Shape::~Shape() {
+  delete[] x_pixels;
+  delete[] y_pixels;
+}
+
+void Shape::randomize(scalar_t radius, scalar_t hole_radius) {
+  delete[] x_pixels;
+  delete[] y_pixels;
+  nb_pixels = 0;
+  scalar_t tmp_x_pixels[nb_max_pixels], tmp_y_pixels[nb_max_pixels];
+  generate_part(tmp_x_pixels, tmp_y_pixels, &nb_pixels, radius, hole_radius);
+  x_pixels = new scalar_t[nb_pixels];
+  y_pixels = new scalar_t[nb_pixels];
+  for(int p = 0; p < nb_pixels; p++) {
+    x_pixels[p] = tmp_x_pixels[p];
+    y_pixels[p] = tmp_y_pixels[p];
+  }
+
+  rotate(drand48() * M_PI * 2);
+
+  // { // ******************************* START ***************************
+// #warning Test code added on 2009 Sep 09 18:15:25
+    // for(int p = 0; p < nb_pixels; p++) {
+      // cout << x_pixels[p] << " " << y_pixels[p] << endl;
+    // }
+  // } // ******************************** END ****************************
+
+}
+
+void Shape::copy(Shape *shape) {
+  delete[] x_pixels;
+  delete[] y_pixels;
+  nb_pixels = shape->nb_pixels;
+  n_pixels1 = shape->n_pixels1;
+  n_pixels2 = shape->n_pixels2;
+  n_pixels3 = shape->n_pixels3;
+  n_pixels4 = shape->n_pixels4;
+  x_pixels = new scalar_t[nb_pixels];
+  y_pixels = new scalar_t[nb_pixels];
+  for(int p = 0; p < nb_pixels; p++) {
+    x_pixels[p] = shape->x_pixels[p];
+    y_pixels[p] = shape->y_pixels[p];
+  }
+}
+
+void Shape::scale(scalar_t s) {
+  for(int p = 0; p < nb_pixels; p++) {
+    x_pixels[p] *= s;
+    y_pixels[p] *= s;
+  }
+}
+
+void Shape::rotate(scalar_t alpha) {
+  scalar_t ux = cos(alpha), uy = -sin(alpha);
+  scalar_t vx = sin(alpha), vy = cos(alpha);
+  scalar_t x, y;
+  for(int p = 0; p < nb_pixels; p++) {
+    x = x_pixels[p] * ux + y_pixels[p] * uy;
+    y = x_pixels[p] * vx + y_pixels[p] * vy;
+    x_pixels[p] = x;
+    y_pixels[p] = y;
+  }
+}
+
+void Shape::symmetrize(scalar_t axis_x, scalar_t axis_y) {
+  scalar_t sql = sq(axis_x) + sq(axis_y);
+  scalar_t u, v;
+  for(int p = 0; p < nb_pixels; p++) {
+    u =   x_pixels[p] * axis_y - y_pixels[p] * axis_x;
+    v =   x_pixels[p] * axis_x + y_pixels[p] * axis_y;
+    u = - u;
+    x_pixels[p] = (  u * axis_y + v * axis_x) / sql;
+    y_pixels[p] = (- u * axis_x + v * axis_y) / sql;
+  }
+}
+
+
+int Shape::overwrites(Vignette *vignette, scalar_t xc, scalar_t yc, int n1, int n2) {
+  int x1 = int(x_pixels[n1 % nb_pixels] + xc);
+  int y1 = int(y_pixels[n1 % nb_pixels] + yc);
+  int x2 = int(x_pixels[n2 % nb_pixels] + xc);
+  int y2 = int(y_pixels[n2 % nb_pixels] + yc);
+  int n3 = (n1 + n2) / 2;
+
+  if(n1 + 1 < n2 && (abs(x1 - x2) > 1 || abs(y1 - y2) > 1)) {
+    return
+      overwrites(vignette, xc, yc, n1, n3) ||
+      overwrites(vignette, xc, yc, n3, n2);
+  } else {
+
+    if(x1 >= margin && x1 < Vignette::width - margin &&
+       y1 >= margin && y1 < Vignette::height - margin) {
+
+      if(margin > 0) {
+        for(int xx = x1 - margin; xx <= x1 + margin; xx++) {
+          for(int yy = y1 - margin; yy <= y1 + margin; yy++) {
+            if(vignette->content[xx + Vignette::width * yy] != 255) {
+              return 1;
+            }
+          }
+        }
+      }
+
+      return 0;
+    } else {
+      return 1;
+    }
+  }
+}
+
+int Shape::overwrites(Vignette *vignette, scalar_t xc, scalar_t yc) {
+  return
+    overwrites(vignette, xc, yc, n_pixels1, n_pixels2) ||
+    overwrites(vignette, xc, yc, n_pixels2, n_pixels3) ||
+    overwrites(vignette, xc, yc, n_pixels3, n_pixels4) ||
+    overwrites(vignette, xc, yc, n_pixels4, nb_pixels);
+}
+
+void Shape::draw(Vignette *vignette, scalar_t xc, scalar_t yc, int n1, int n2) {
+  int x1 = int(x_pixels[n1 % nb_pixels] + xc);
+  int y1 = int(y_pixels[n1 % nb_pixels] + yc);
+  int x2 = int(x_pixels[n2 % nb_pixels] + xc);
+  int y2 = int(y_pixels[n2 % nb_pixels] + yc);
+  int n3 = (n1 + n2) / 2;
+
+  if(n1 + 1 < n2 && (abs(x1 - x2) > 1 || abs(y1 - y2) > 1)) {
+    draw(vignette, xc, yc, n1, n3);
+    draw(vignette, xc, yc, n3, n2);
+  } else {
+    if(x1 >= margin && x1 < Vignette::width-margin &&
+       y1 >= margin && y1 < Vignette::height-margin) {
+      vignette->content[x1 + Vignette::width * y1] = 0;
+    }
+  }
+}
+
+void Shape::draw(Vignette *vignette, scalar_t xc, scalar_t yc) {
+  draw(vignette, xc, yc, n_pixels1, n_pixels2);
+  draw(vignette, xc, yc, n_pixels2, n_pixels3);
+  draw(vignette, xc, yc, n_pixels3, n_pixels4);
+  draw(vignette, xc, yc, n_pixels4, nb_pixels);
+}
diff --git a/shape.h b/shape.h
new file mode 100644 (file)
index 0000000..5440197
--- /dev/null
+++ b/shape.h
@@ -0,0 +1,61 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef SHAPE_H
+#define SHAPE_H
+
+#include "misc.h"
+#include "vignette.h"
+
+class Shape {
+  static const int margin = 1;
+  static const int nb_max_pixels = Vignette::width * Vignette::height;
+  static const scalar_t gap_max = 0.25;
+  int n_pixels1, n_pixels2, n_pixels3, n_pixels4;
+  int nb_pixels;
+  scalar_t xc, yc;
+  scalar_t *x_pixels;
+  scalar_t *y_pixels;
+
+  int generate_part_part(scalar_t *xp, scalar_t *yp, int *nb_pixels, scalar_t radius, scalar_t hole_radius,
+                         scalar_t x1, scalar_t y1, scalar_t x2, scalar_t y2);
+  void generate_part(scalar_t *xp, scalar_t *yp, int *nb_pixels, scalar_t radius, scalar_t hole_radius);
+  int overwrites(Vignette *vignette, scalar_t xc, scalar_t yc, int first, int nb);
+  void draw(Vignette *vignette, scalar_t xc, scalar_t yc, int first, int nb);
+
+public:
+  Shape();
+  ~Shape();
+
+  void randomize(scalar_t radius, scalar_t hole_radius);
+  void copy(Shape *shape);
+  void scale(scalar_t s);
+  void rotate(scalar_t alpha);
+  void symmetrize(scalar_t axis_x, scalar_t axis_y);
+
+  int overwrites(Vignette *vignette, scalar_t xc, scalar_t yc);
+  void draw(Vignette *vignette, scalar_t xc, scalar_t yc);
+};
+
+#endif
diff --git a/stump.cc b/stump.cc
new file mode 100644 (file)
index 0000000..c2835a5
--- /dev/null
+++ b/stump.cc
@@ -0,0 +1,61 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "stump.h"
+
+void compute_integral_image(Vignette *vignette, int *integral_image) {
+  int k = 0;
+  for(int y = 0; y <= Vignette::height; y++) {
+    for(int x = 0; x <= Vignette::width; x++) {
+      if(x == 0 || y == 0) {
+        integral_image[k] = 0;
+      } else {
+        ASSERT(k >= (Vignette::width + 1) + 1);
+        integral_image[k] =  vignette->content[x - 1 + Vignette::width * (y - 1)]
+          + integral_image[k - (Vignette::width + 1)]
+          + integral_image[k - 1]
+          - integral_image[k - (Vignette::width + 1) - 1];
+      }
+      k++;
+    }
+  }
+}
+
+
+void Stump::randomize() {
+  do {
+    roi_x = int(drand48() * Vignette::width);
+    roi_y = int(drand48() * Vignette::height);
+    roi_w = int(drand48() * Vignette::width);
+    roi_h = int(drand48() * Vignette::height);
+    // #warning *!*!*!*!*!*!*!*!*!*!*!*!*!*
+    // roi_w = int(drand48() * Vignette::width/2);
+    // roi_h = int(drand48() * Vignette::height/2);
+  } while(roi_x + roi_w > Vignette::width || roi_y + roi_h > Vignette::height);
+
+  k1 = (roi_x +     0) + (roi_y +     0) * (Vignette::width + 1);
+  k2 = (roi_x + roi_w) + (roi_y +     0) * (Vignette::width + 1);
+  k3 = (roi_x +     0) + (roi_y + roi_h) * (Vignette::width + 1);
+  k4 = (roi_x + roi_w) + (roi_y + roi_h) * (Vignette::width + 1);
+}
diff --git a/stump.h b/stump.h
new file mode 100644 (file)
index 0000000..7c3606e
--- /dev/null
+++ b/stump.h
@@ -0,0 +1,55 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef STUMP_H
+#define STUMP_H
+
+#include "misc.h"
+#include "vignette.h"
+
+void compute_integral_image(Vignette *vignette, int *integral_mage);
+
+class Stump {
+public:
+  int roi_x, roi_y, roi_w, roi_h;
+  int k1, k2, k3, k4;
+  scalar_t threshold;
+  scalar_t weight0, weight1;
+
+  inline scalar_t count(int *iimage) {
+    return scalar_t(iimage[k1] + iimage[k4] - iimage[k2] - iimage[k3]);
+  }
+
+  inline scalar_t response(int *iimage) {
+    if(count(iimage) >= threshold) {
+      return weight1;
+    } else {
+      return weight0;
+    }
+  }
+
+  void randomize();
+};
+
+#endif
diff --git a/tools.cc b/tools.cc
new file mode 100644 (file)
index 0000000..1492e72
--- /dev/null
+++ b/tools.cc
@@ -0,0 +1,55 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "misc.h"
+#include "tools.h"
+#include "fusion_sort.h"
+
+scalar_t robust_sampling(int nb, scalar_t *weights, int nb_to_sample, int *sampled) {
+  ASSERT(nb > 0);
+  if(nb == 1) {
+    for(int k = 0; k < nb_to_sample; k++) sampled[k] = 0;
+    return weights[0];
+  } else {
+    scalar_t *pair_weights = new scalar_t[(nb+1)/2];
+    for(int k = 0; k < nb/2; k++)
+      pair_weights[k] = weights[2 * k] + weights[2 * k + 1];
+    if(nb%2)
+      pair_weights[(nb+1)/2 - 1] = weights[nb-1];
+    scalar_t result = robust_sampling((nb+1)/2, pair_weights, nb_to_sample, sampled);
+    for(int k = 0; k < nb_to_sample; k++) {
+      int s = sampled[k];
+      // There is a bit of a trick for the isolated sample in the odd
+      // case. Since the corresponding pair weight is the same as the
+      // one sample alone, the test is always true and the isolated
+      // sample will be taken for sure.
+      if(drand48() * pair_weights[s] <= weights[2 * s])
+        sampled[k] = 2 * s;
+      else
+        sampled[k] = 2 * s + 1;
+    }
+    delete[] pair_weights;
+    return result;
+  }
+}
diff --git a/tools.h b/tools.h
new file mode 100644 (file)
index 0000000..3e498af
--- /dev/null
+++ b/tools.h
@@ -0,0 +1,36 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef TOOLS_H
+#define TOOLS_H
+
+#include <iostream>
+#include "misc.h"
+
+// This function is not trivial because it has to handle numerical
+// pitfalls due to the very large number of samples.
+
+scalar_t robust_sampling(int nb, scalar_t *weights, int nb_to_sample, int *sampled);
+
+#endif
diff --git a/vignette.cc b/vignette.cc
new file mode 100644 (file)
index 0000000..8402af0
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "vignette.h"
+#include "rgb_image.h"
+
+void Vignette::clear() {
+  for(int k = 0; k < width * height; k++) {
+    content[k] = 255;
+  }
+}
+
+void Vignette::write_png(const char *name, int delta) {
+  RGBImage result(width * delta - (delta > 1 ? 1 : 0), height * delta - (delta > 1 ? 1 : 0));
+  for(int y = 0; y < result.height(); y++) {
+    for(int x = 0; x < result.width(); x++) {
+      int c;
+      if(delta > 4 && (x%delta == 0 || y%delta == 0)) {
+        c = 255;
+      } else {
+        c = content[(x / delta) + width * (y / delta)];
+      }
+      result.set_pixel(x, y, c, c, c);
+    }
+  }
+
+  result.write_png(name);
+}
+
+void Vignette::fill(int x, int y, int v) {
+  if(x >= 0 && x < Vignette::width && y >= 0 && y < Vignette::height &&
+     content[x + Vignette::width * y] == 255) {
+    content[x + Vignette::width * y] = v;
+    fill(x + 1, y    , v);
+    fill(x - 1, y    , v);
+    fill(x    , y + 1, v);
+    fill(x    , y - 1, v);
+  }
+}
+
+void Vignette::switch_values(int v1, int v2) {
+  for(int k = 0; k < Vignette::height * Vignette::width; k++) {
+    if(content[k] == v1) {
+      content[k] = v2;
+    } else if(content[k] == v2) {
+      content[k] = v1;
+    }
+  }
+}
+
+void Vignette::replace_value(int from, int to) {
+  for(int k = 0; k < Vignette::height * Vignette::width; k++) {
+    if(content[k] == from) {
+      content[k] = to;
+    }
+  }
+}
+
+void Vignette::superpose(Vignette *infront, Vignette *inback) {
+  for(int k = 0; k < Vignette::height * Vignette::width; k++) {
+    if(infront->content[k] < 255) {
+      content[k] = infront->content[k];
+    } else {
+      content[k] = inback->content[k];
+    }
+  }
+}
+
+int Vignette::surface() {
+  int n = 0;
+  for(int k = 0; k < Vignette::height * Vignette::width; k++) {
+    if(content[k] < 255) {
+      n++;
+    }
+  }
+  return n;
+}
+
+int Vignette::intersection(Vignette *v) {
+  int n = 0;
+  for(int k = 0; k < Vignette::height * Vignette::width; k++) {
+    if(content[k] < 255 && v->content[k] < 255) {
+      n++;
+    }
+  }
+  return n;
+}
+
+void Vignette::grow() {
+  int tmp[Vignette::width * Vignette::height];
+  for(int k = 0; k < Vignette::height * Vignette::width; k++) {
+    tmp[k] = content[k];
+  }
+  int k;
+  for(int y = 1; y < Vignette::height - 1; y++) {
+    for(int x = 1; x < Vignette::width - 1; x++) {
+      k = x + Vignette::width * y;
+      content[k] = min(tmp[k],
+                       min(min(tmp[k - Vignette::width], tmp[k - 1]),
+                           min(tmp[k + 1], tmp[k + Vignette::width])));
+    }
+  }
+}
diff --git a/vignette.h b/vignette.h
new file mode 100644 (file)
index 0000000..5966ac6
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef VIGNETTE_H
+#define VIGNETTE_H
+
+#include "misc.h"
+#include "global.h"
+
+class Vignette {
+public:
+  static const int width = 128;
+  static const int height = width;
+  static const int nb_grayscales = 256;
+
+  // static const int small_part_size = 24;
+  // static const int small_part_hole_size = 2;
+  // static const int big_part_size = 64;
+  // static const int big_part_hole_size = 32;
+
+  int content[width * height];
+
+  void clear();
+
+  void write_png(const char *name, int delta);
+
+  void fill(int x, int y, int v);
+  void switch_values(int c1, int c2);
+  void replace_value(int from, int to);
+  void superpose(Vignette *infront, Vignette *inback);
+  int surface();
+  int intersection(Vignette *v);
+  void grow();
+
+};
+
+#endif
diff --git a/vignette_generator.cc b/vignette_generator.cc
new file mode 100644 (file)
index 0000000..417fb22
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "vignette_generator.h"
+
+VignetteGenerator::~VignetteGenerator() { }
+
+void VignetteGenerator::precompute() { }
diff --git a/vignette_generator.h b/vignette_generator.h
new file mode 100644 (file)
index 0000000..2390fbf
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef VIGNETTE_GENERATOR_H
+#define VIGNETTE_GENERATOR_H
+
+#include "misc.h"
+#include "global.h"
+#include "vignette.h"
+#include "rgb_image.h"
+
+class VignetteGenerator {
+public:
+  // We need a virtual destructor since we have virtual methods
+  virtual ~VignetteGenerator();
+
+  // Some generators need to do pre-computations that can not be put
+  // in the constructor
+  virtual void precompute();
+
+  // Generate a vignette
+  virtual void generate(int label, Vignette *vignette) = 0;
+};
+
+#endif
diff --git a/vision_problem_1.cc b/vision_problem_1.cc
new file mode 100644 (file)
index 0000000..aa766e9
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "vision_problem_1.h"
+#include "shape.h"
+
+VisionProblem_1::VisionProblem_1() { }
+
+void VisionProblem_1::generate(int label, Vignette *vignette) {
+  int nb_shapes = 2;
+  int xs[nb_shapes], ys[nb_shapes];
+  scalar_t scales[nb_shapes], angles[nb_shapes];
+  Shape shapes[nb_shapes];
+
+  int error;
+  do {
+
+    scalar_t max_scale = -1;
+
+    for(int n = 0; n < nb_shapes; n++) {
+      xs[n] = int(drand48() * Vignette::width);
+      ys[n] = int(drand48() * Vignette::height);
+
+        scales[n] = 2.5;
+
+      if(n == 0 || scales[n] > max_scale) max_scale = scales[n];
+
+      angles[n] = 0;
+    }
+
+    for(int n = 0; n < nb_shapes; n++) {
+      if(n == 0 || label == 0) {
+        shapes[n].randomize(max_scale * part_size / 2, max_scale * hole_size/2);
+      } else {
+        shapes[n].copy(&shapes[0]);
+      }
+    }
+
+    for(int n = 0; n < nb_shapes; n++) {
+      shapes[n].scale(scales[n] / max_scale);
+      shapes[n].rotate(angles[n]);
+    }
+
+    vignette->clear();
+
+    error = 0;
+    for(int n = 0; n < nb_shapes; n++) {
+      error |= shapes[n].overwrites(vignette, xs[n], ys[n]);
+      shapes[n].draw(vignette, xs[n], ys[n]);
+    }
+  } while(error);
+}
diff --git a/vision_problem_1.h b/vision_problem_1.h
new file mode 100644 (file)
index 0000000..afdf97a
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef VISION_PROBLEM_1_H
+#define VISION_PROBLEM_1_H
+
+#include "vignette_generator.h"
+#include "vision_problem_tools.h"
+
+class VisionProblem_1 : public VignetteGenerator {
+  static const int part_size = Vignette::width / 6;
+  static const int hole_size = Vignette::width / 64;
+public:
+  VisionProblem_1();
+  virtual void generate(int label, Vignette *vignette);
+};
+
+#endif
diff --git a/vision_problem_11.cc b/vision_problem_11.cc
new file mode 100644 (file)
index 0000000..4cd1cff
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "vision_problem_11.h"
+#include "shape.h"
+
+VisionProblem_11::VisionProblem_11() { }
+
+void VisionProblem_11::generate(int label, Vignette *vignette) {
+  int nb_shapes;
+  int xs, ys, i, pxs, pys;
+  const int dist_min = Vignette::width/12;
+  int nb_attempts, max_nb_attempts = 100;
+
+  Vignette mask, tmp;
+
+  nb_shapes = 2;
+
+  do {
+    nb_attempts = 0;
+
+    mask.clear();
+    vignette->clear();
+
+    pxs = 0; pys = 0;
+
+    for(int s = 0; nb_attempts < max_nb_attempts && s < nb_shapes; s++) {
+      Shape shape;
+
+      do {
+        tmp.clear();
+
+        do {
+
+          if(s == 0) {
+            shape.randomize(big_part_size / 2, big_part_hole_size / 2);
+          } else {
+            shape.randomize(small_part_size / 2, small_part_hole_size / 2);
+          }
+
+          if(nb_shapes == 2 || s == 0 || label == 0) {
+            xs = int(drand48() * Vignette::width);
+            ys = int(drand48() * Vignette::height);
+          } else {
+            xs = pxs + int(4 * (drand48() - 0.5) * small_part_hole_size);
+            ys = pys + int(4 * (drand48() - 0.5) * small_part_hole_size);
+          }
+          nb_attempts++;
+
+        } while(nb_attempts < max_nb_attempts &&
+                shape.overwrites(&tmp, xs, ys));
+
+        shape.draw(&tmp, xs, ys);
+        tmp.fill(xs, ys, 128);
+        i = tmp.intersection(&mask);
+
+        nb_attempts++;
+      } while(nb_attempts < max_nb_attempts &&
+              s > 0 &&
+              ((label == 0 && i > 0) || (label == 1 && (i < 1 || i > 4))));
+
+      shape.draw(vignette, xs, ys);
+      pxs = xs; pys = ys;
+
+      if(label == 0) {
+        for(int k = 0; k < dist_min; k++) tmp.grow();
+      }
+
+      mask.superpose(&mask, &tmp);
+    }
+  } while(nb_attempts >= max_nb_attempts);
+}
diff --git a/vision_problem_11.h b/vision_problem_11.h
new file mode 100644 (file)
index 0000000..a8cf1ef
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef VISION_PROBLEM_11_H
+#define VISION_PROBLEM_11_H
+
+#include "vignette_generator.h"
+#include "vision_problem_tools.h"
+
+class VisionProblem_11 : public VignetteGenerator {
+  static const int small_part_size = Vignette::width / 3;
+  static const int small_part_hole_size = Vignette::width / 9;
+  static const int big_part_size = (Vignette::width * 3)/4;
+  static const int big_part_hole_size = Vignette::width / 4;
+public:
+  VisionProblem_11();
+  virtual void generate(int label, Vignette *vignette);
+};
+
+#endif
diff --git a/vision_problem_12.cc b/vision_problem_12.cc
new file mode 100644 (file)
index 0000000..ea75acb
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "vision_problem_12.h"
+#include "shape.h"
+
+VisionProblem_12::VisionProblem_12() { }
+
+void VisionProblem_12::generate(int label, Vignette *vignette) {
+  int nb_shapes = 3;
+  scalar_t alpha, beta, gamma;
+  int xs, ys;
+  Shape shape;
+
+  int error;
+
+  do {
+    scalar_t xc, yc, radius;
+    xc = (drand48() * 0.5 + 0.25) * Vignette::width;
+    yc = (drand48() * 0.5 + 0.25) * Vignette::height;
+    radius = (drand48() * 0.5 + 0.1) * Vignette::width;
+    alpha = drand48() * 2 * M_PI;
+    beta = (drand48() * 0.4 + 0.1) * M_PI;
+
+    vignette->clear();
+    error = 0;
+
+    for(int n = 0; n < nb_shapes; n++) {
+      if(label) {
+        if(n == 0)
+          gamma = alpha + M_PI - beta/2;
+        else if(n == 1)
+          gamma = alpha + M_PI + beta/2;
+        else
+          gamma = alpha;
+      } else {
+        if(n == 0)
+          gamma = alpha + M_PI - beta/2;
+        else if(n == 1)
+          gamma = alpha;
+        else
+          gamma = alpha + M_PI + beta/2;
+      }
+
+      if(n < 2) {
+        shape.randomize(small_part_size, small_part_hole_size);
+      } else {
+        shape.randomize(big_part_size, big_part_hole_size);
+      }
+
+      xs = int(xc + radius * cos(gamma));
+      ys = int(yc + radius * sin(gamma));
+
+      error |= shape.overwrites(vignette, xs, ys);
+      shape.draw(vignette, xs, ys);
+    }
+  } while(error);
+}
diff --git a/vision_problem_12.h b/vision_problem_12.h
new file mode 100644 (file)
index 0000000..3d17d83
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef VISION_PROBLEM_12_H
+#define VISION_PROBLEM_12_H
+
+#include "vignette_generator.h"
+#include "vision_problem_tools.h"
+
+class VisionProblem_12 : public VignetteGenerator {
+  static const int small_part_size = Vignette::width / 12;
+  static const int small_part_hole_size = Vignette::width / 24;
+  static const int big_part_size = Vignette::width / 6;
+  static const int big_part_hole_size = Vignette::width / 12;
+public:
+  VisionProblem_12();
+  virtual void generate(int label, Vignette *vignette);
+};
+
+#endif
diff --git a/vision_problem_13.cc b/vision_problem_13.cc
new file mode 100644 (file)
index 0000000..30e96f4
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "vision_problem_13.h"
+#include "shape.h"
+
+VisionProblem_13::VisionProblem_13() { }
+
+void VisionProblem_13::generate(int label, Vignette *vignette) {
+  Shape big_shape, small_shape;
+  int big_xs1, big_ys1, small_xs1, small_ys1;
+  int big_xs2, big_ys2, small_xs2, small_ys2;
+  int translated_small_xs, translated_small_ys;
+  Vignette tmp;
+  const int dist_min = Vignette::width/4;
+  int nb_attempts;
+  const int max_nb_attempts = 100;
+
+  do {
+    nb_attempts = 0;
+    do {
+
+      vignette->clear();
+
+      big_shape.randomize(big_part_size / 2, big_part_hole_size / 2);
+
+      tmp.clear();
+      do {
+        big_xs1 = int(drand48() * Vignette::width);
+        big_ys1 = int(drand48() * Vignette::height);
+        nb_attempts++;
+      } while(nb_attempts < max_nb_attempts &&
+              big_shape.overwrites(vignette, big_xs1, big_ys1));
+
+      big_shape.draw(vignette, big_xs1, big_ys1);
+      big_shape.draw(&tmp, big_xs1, big_ys1);
+      for(int k = 0; k < dist_min; k++) tmp.grow();
+
+      do {
+        small_shape.randomize(small_part_size / 2, small_part_hole_size / 2);
+        small_xs1 = int(drand48() * Vignette::width);
+        small_ys1 = int(drand48() * Vignette::height);
+        nb_attempts++;
+      } while(nb_attempts < max_nb_attempts &&
+              (!small_shape.overwrites(&tmp, small_xs1, small_ys1) ||
+               small_shape.overwrites(vignette, small_xs1, small_ys1)));
+
+      small_shape.draw(vignette, small_xs1, small_ys1);
+
+      tmp.clear();
+      do {
+        big_xs2 = int(drand48() * Vignette::width);
+        big_ys2 = int(drand48() * Vignette::height);
+        nb_attempts++;
+      } while(nb_attempts < max_nb_attempts &&
+              big_shape.overwrites(vignette, big_xs2, big_ys2));
+      big_shape.draw(vignette, big_xs2, big_ys2);
+      big_shape.draw(&tmp, big_xs2, big_ys2);
+      for(int k = 0; k < dist_min; k++) tmp.grow();
+
+      translated_small_xs = small_xs1 + (big_xs2 - big_xs1);
+      translated_small_ys = small_ys1 + (big_ys2 - big_ys1);
+
+    } while(nb_attempts < max_nb_attempts &&
+            small_shape.overwrites(vignette,
+                                   translated_small_xs,
+                                   translated_small_ys));
+
+    if(label) {
+      small_xs2 = translated_small_xs;
+      small_ys2 = translated_small_ys;
+    } else {
+      do {
+        small_xs2 = int(drand48() * Vignette::width);
+        small_ys2 = int(drand48() * Vignette::height);
+        nb_attempts++;
+      } while(nb_attempts < max_nb_attempts &&
+              (sq(small_xs2 - translated_small_xs) + sq(small_ys2 - translated_small_ys) < sq(dist_min) ||
+               !small_shape.overwrites(&tmp, small_xs2, small_ys2) ||
+               small_shape.overwrites(vignette, small_xs2, small_ys2)));
+    }
+  } while(nb_attempts >= max_nb_attempts);
+  small_shape.draw(vignette, small_xs2, small_ys2);
+}
diff --git a/vision_problem_13.h b/vision_problem_13.h
new file mode 100644 (file)
index 0000000..98c49f8
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef VISION_PROBLEM_13_H
+#define VISION_PROBLEM_13_H
+
+#include "vignette_generator.h"
+#include "vision_problem_tools.h"
+
+class VisionProblem_13 : public VignetteGenerator {
+  static const int small_part_size = Vignette::width / 6;
+  static const int small_part_hole_size = Vignette::width / 12;
+  static const int big_part_size = Vignette::width / 2;
+  static const int big_part_hole_size = Vignette::width / 4;
+public:
+  VisionProblem_13();
+  virtual void generate(int label, Vignette *vignette);
+};
+
+#endif
diff --git a/vision_problem_17.cc b/vision_problem_17.cc
new file mode 100644 (file)
index 0000000..8d3d9e6
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "vision_problem_17.h"
+#include "shape.h"
+
+VisionProblem_17::VisionProblem_17() { }
+
+void VisionProblem_17::generate(int label, Vignette *vignette) {
+  const int nb_shapes = 4;
+  int xs[nb_shapes], ys[nb_shapes];
+  int shape_number[nb_shapes];
+
+  ASSERT(nb_shapes == 4);
+
+  int too_ambiguous;
+
+  int error;
+
+  do {
+    Shape shape1, shape2;
+    shape1.randomize(part_size/2, hole_size/2);
+    shape2.randomize(part_size/2, hole_size/2);
+
+    //////////////////////////////////////////////////////////////////////
+
+    do {
+      for(int n = 0; n < nb_shapes; n++) {
+        if(n < nb_shapes - 1) {
+          shape_number[n] = 0;
+        } else {
+          shape_number[n] = 1;
+        }
+        xs[n] = int(drand48() * (Vignette::width - part_size)) + part_size/2;
+        ys[n] = int(drand48() * (Vignette::width - part_size)) + part_size/2;
+      }
+
+      scalar_t a = scalar_t(xs[1] - xs[0]), b = scalar_t(ys[1] - ys[0]);
+      scalar_t c = scalar_t(xs[2] - xs[1]), d = scalar_t(ys[2] - ys[1]);
+      scalar_t det = a * d - b * c;
+      scalar_t u = scalar_t(xs[1] * xs[1] - xs[0] * xs[0] + ys[1] * ys[1] - ys[0] * ys[0]);
+      scalar_t v = scalar_t(xs[2] * xs[2] - xs[1] * xs[1] + ys[2] * ys[2] - ys[1] * ys[1]);
+      scalar_t xc = 1/(2 * det) *(  d * u - b * v);
+      scalar_t yc = 1/(2 * det) *(- c * u + a * v);
+
+      if(label == 1) {
+        xs[nb_shapes - 1] = int(xc);
+        ys[nb_shapes - 1] = int(yc);
+        too_ambiguous = 0;
+      } else {
+        too_ambiguous = sqrt(sq(scalar_t(xs[nb_shapes - 1]) - xc) +
+                             sq(scalar_t(ys[nb_shapes - 1]) - yc)) < scalar_t(part_size);
+      }
+    } while(too_ambiguous ||
+            cluttered_shapes(part_size, nb_shapes, xs, ys));
+
+    //////////////////////////////////////////////////////////////////////
+
+    vignette->clear();
+
+    error = 0;
+    for(int n = 0; n < nb_shapes; n++) {
+      if(shape_number[n] == 0) {
+        error |= shape1.overwrites(vignette, xs[n], ys[n]);
+        shape1.draw(vignette, xs[n], ys[n]);
+      } else {
+        error |= shape2.overwrites(vignette, xs[n], ys[n]);
+        shape2.draw(vignette, xs[n], ys[n]);
+      }
+    }
+  } while(error);
+}
diff --git a/vision_problem_17.h b/vision_problem_17.h
new file mode 100644 (file)
index 0000000..f614126
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef VISION_PROBLEM_17_H
+#define VISION_PROBLEM_17_H
+
+#include "vignette_generator.h"
+#include "vision_problem_tools.h"
+
+class VisionProblem_17 : public VignetteGenerator {
+  static const int part_size = Vignette::width / 6;
+  static const int hole_size = Vignette::width / 64;
+public:
+  VisionProblem_17();
+  virtual void generate(int label, Vignette *vignette);
+};
+
+#endif
diff --git a/vision_problem_18.cc b/vision_problem_18.cc
new file mode 100644 (file)
index 0000000..7064657
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "vision_problem_18.h"
+#include "shape.h"
+
+VisionProblem_18::VisionProblem_18() { }
+
+void VisionProblem_18::generate(int label, Vignette *vignette) {
+  int error;
+
+  int nb_shapes = 6;
+  int xs[nb_shapes], ys[nb_shapes];
+  Shape shape1, shape2;
+  shape1.randomize(part_size / 2, hole_size / 2);
+  shape2.copy(&shape1);
+
+  do {
+    vignette->clear();
+    error = 0;
+
+    // First half of the shapes are random
+    for(int n = 0; n < nb_shapes/2; n++) {
+      xs[n] = int(drand48() * (Vignette::width - part_size + 1)) + part_size/2;
+      ys[n] = int(drand48() * (Vignette::height - part_size + 1)) + part_size/2;
+      error |= shape1.overwrites(vignette, xs[n], ys[n]);
+      shape1.draw(vignette, xs[n], ys[n]);
+    }
+
+    for(int n = nb_shapes/2; n < nb_shapes; n++) {
+      if(label == 1) {
+        xs[n] = Vignette::width - xs[n - nb_shapes/2];
+        ys[n] = ys[n - nb_shapes/2];
+      } else {
+        xs[n] = int(drand48() * (Vignette::width - part_size + 1)) + part_size/2;
+        ys[n] = ys[n - nb_shapes/2];
+      }
+      error |= shape2.overwrites(vignette, xs[n], ys[n]);
+      shape2.draw(vignette, xs[n], ys[n]);
+    }
+  } while(error);
+}
diff --git a/vision_problem_18.h b/vision_problem_18.h
new file mode 100644 (file)
index 0000000..b8c4dca
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef VISION_PROBLEM_18_H
+#define VISION_PROBLEM_18_H
+
+#include "vignette_generator.h"
+#include "vision_problem_tools.h"
+
+class VisionProblem_18 : public VignetteGenerator {
+  static const int part_size = Vignette::width / 6;
+  static const int hole_size = Vignette::width / 64;
+public:
+  VisionProblem_18();
+  virtual void generate(int label, Vignette *vignette);
+};
+
+#endif
diff --git a/vision_problem_2.cc b/vision_problem_2.cc
new file mode 100644 (file)
index 0000000..75bcbc9
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "vision_problem_2.h"
+#include "shape.h"
+
+VisionProblem_2::VisionProblem_2() { }
+
+void VisionProblem_2::generate(int label, Vignette *vignette) {
+  int x_big, y_big, x_small, y_small;
+  Shape big_shape, small_shape;
+  Vignette mask;
+  int nb_attempts, max_nb_attempts = 10;
+  int dist_min = Vignette::width/8;
+
+  do {
+    vignette->clear();
+    mask.clear();
+
+    big_shape.randomize(big_part_size / 2, big_part_hole_size / 2);
+
+    do {
+      x_big = int(drand48() * Vignette::width);
+      y_big = int(drand48() * Vignette::height);
+    } while(big_shape.overwrites(vignette, x_big, y_big));
+
+    // The mask will encode either a thin area the small shape should
+    // intersect with (class 1) or a thick one it should not (class 0)
+
+    big_shape.draw(&mask, x_big, y_big);
+
+    if(label) {
+      mask.grow();
+    } else {
+      for(int k = 0; k < dist_min; k++) {
+        mask.grow();
+      }
+    }
+
+    big_shape.draw(vignette, x_big, y_big);
+    vignette->fill(x_big, y_big, 128);
+    vignette->switch_values(128, 255);
+
+    nb_attempts = 0;
+    do {
+      do {
+        small_shape.randomize(small_part_size / 2, small_part_hole_size / 2);
+        x_small = x_big + int((drand48() - 0.5) * big_part_size);
+        y_small = y_big + int((drand48() - 0.5) * big_part_size);
+      } while(small_shape.overwrites(vignette, x_small, y_small)); // ||
+      nb_attempts++;
+    } while(nb_attempts < max_nb_attempts &&
+            ((label && !small_shape.overwrites(&mask, x_small, y_small)) ||
+             (!label && small_shape.overwrites(&mask, x_small, y_small))));
+
+    vignette->replace_value(128, 255);
+    small_shape.draw(vignette, x_small, y_small);
+  } while(nb_attempts >= max_nb_attempts);
+}
diff --git a/vision_problem_2.h b/vision_problem_2.h
new file mode 100644 (file)
index 0000000..a1239f0
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef VISION_PROBLEM_2_H
+#define VISION_PROBLEM_2_H
+
+#include "vignette_generator.h"
+#include "vision_problem_tools.h"
+
+class VisionProblem_2 : public VignetteGenerator {
+  static const int small_part_size = Vignette::width/6;
+  static const int small_part_hole_size = Vignette::width/64;
+  static const int big_part_size = (Vignette::width * 3)/4;
+  static const int big_part_hole_size = Vignette::width / 3;
+
+public:
+  VisionProblem_2();
+  virtual void generate(int label, Vignette *vignette);
+};
+
+#endif
diff --git a/vision_problem_20.cc b/vision_problem_20.cc
new file mode 100644 (file)
index 0000000..e4af48f
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "vision_problem_20.h"
+#include "shape.h"
+
+VisionProblem_20::VisionProblem_20() { }
+
+
+void VisionProblem_20::generate(int label, Vignette *vignette) {
+  int nb_shapes = 2;
+  int xs[nb_shapes], ys[nb_shapes];
+  Shape shapes[nb_shapes];
+
+  int error;
+  do{
+    vignette->clear();
+    error = 0;
+    for(int n = 0; !error && n < nb_shapes; n++) {
+      xs[n] = int(drand48() * Vignette::width);
+      ys[n] = int(drand48() * Vignette::height);
+      if(!label || n == 0) {
+        shapes[n].randomize(part_size / 2, part_hole_size / 2);
+      } else {
+        shapes[n].copy(&shapes[0]);
+        shapes[n].symmetrize(ys[n] - ys[0], - xs[n] + xs[0]);
+      }
+      error |= shapes[n].overwrites(vignette, xs[n], ys[n]);
+      shapes[n].draw(vignette, xs[n], ys[n]);
+    }
+  }  while(error);
+}
diff --git a/vision_problem_20.h b/vision_problem_20.h
new file mode 100644 (file)
index 0000000..a1f1b7a
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef VISION_PROBLEM_20_H
+#define VISION_PROBLEM_20_H
+
+#include "vignette_generator.h"
+#include "vision_problem_tools.h"
+
+class VisionProblem_20 : public VignetteGenerator {
+  static const int part_size = Vignette::width / 4;
+  static const int part_hole_size = Vignette::width / 32;
+public:
+  VisionProblem_20();
+  virtual void generate(int label, Vignette *vignette);
+};
+
+#endif
diff --git a/vision_problem_21.cc b/vision_problem_21.cc
new file mode 100644 (file)
index 0000000..2c58a4d
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "vision_problem_21.h"
+#include "shape.h"
+
+VisionProblem_21::VisionProblem_21() { }
+
+void VisionProblem_21::generate(int label, Vignette *vignette) {
+  int nb_shapes = 2;
+  int xs[nb_shapes], ys[nb_shapes];
+  scalar_t scales[nb_shapes], angles[nb_shapes];
+  Shape shapes[nb_shapes];
+
+  int error;
+  do {
+
+    scalar_t max_scale = -1;
+
+    for(int n = 0; n < nb_shapes; n++) {
+      xs[n] = int(drand48() * Vignette::width);
+      ys[n] = int(drand48() * Vignette::height);
+
+      scales[n] = 1.0 + 3.0 * drand48();
+
+      if(n == 0 || scales[n] > max_scale) max_scale = scales[n];
+
+      angles[n] = drand48() * 2 * M_PI;
+    }
+
+    for(int n = 0; n < nb_shapes; n++) {
+      if(n == 0 || label == 0) {
+        shapes[n].randomize(max_scale * part_size / 2, max_scale * hole_size/2);
+      } else {
+        shapes[n].copy(&shapes[0]);
+      }
+    }
+
+    for(int n = 0; n < nb_shapes; n++) {
+      shapes[n].scale(scales[n] / max_scale);
+      shapes[n].rotate(angles[n]);
+    }
+
+    vignette->clear();
+
+    error = 0;
+    for(int n = 0; n < nb_shapes; n++) {
+      error |= shapes[n].overwrites(vignette, xs[n], ys[n]);
+      shapes[n].draw(vignette, xs[n], ys[n]);
+    }
+  } while(error);
+}
diff --git a/vision_problem_21.h b/vision_problem_21.h
new file mode 100644 (file)
index 0000000..3fa825a
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef VISION_PROBLEM_21_H
+#define VISION_PROBLEM_21_H
+
+#include "vignette_generator.h"
+#include "vision_problem_tools.h"
+
+class VisionProblem_21 : public VignetteGenerator {
+  static const int part_size = Vignette::width / 6;
+  static const int hole_size = Vignette::width / 64;
+public:
+  VisionProblem_21();
+  virtual void generate(int label, Vignette *vignette);
+};
+
+#endif
diff --git a/vision_problem_3.cc b/vision_problem_3.cc
new file mode 100644 (file)
index 0000000..49a917b
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "vision_problem_3.h"
+#include "shape.h"
+
+VisionProblem_3::VisionProblem_3() { }
+
+void VisionProblem_3::generate(int label, Vignette *vignette) {
+  int nb_shapes = 4;
+  Vignette avoid, tmp;
+  const int dist_min = Vignette::width / 8;
+
+  int nb_attempts;
+  const int max_nb_attempts = 100;
+
+  do {
+    avoid.clear();
+    vignette->clear();
+
+    nb_attempts = 0;
+
+    for(int s = 0; nb_attempts < max_nb_attempts && s < nb_shapes; s++) {
+      Shape shape;
+
+      int xs, ys, i, right_margin, right_connection;
+
+      do {
+        tmp.clear();
+        do {
+          do {
+            xs = int(drand48() * Vignette::width);
+            ys = int(drand48() * Vignette::height);
+            shape.randomize(part_size, hole_size);
+          }  while(shape.overwrites(&tmp, xs, ys)); // check not out-of-vignette
+
+          // omg this is ugly
+          if(label && s == 1) {
+            right_margin = 1;
+          } else {
+            right_margin = !shape.overwrites(&avoid, xs, ys);
+          }
+
+          if((label && (s == 1 || s == 3)) || (!label && (s >= 2))) {
+            right_connection = shape.overwrites(vignette, xs, ys);
+          } else {
+            right_connection = 1;
+          }
+
+          nb_attempts++;
+
+        } while(nb_attempts < max_nb_attempts && !right_margin);
+
+        shape.draw(&tmp, xs, ys);
+        tmp.fill(xs, ys, 0);
+
+        if(right_margin && right_connection) {
+          if((label && (s == 1 || s == 3)) || (!label && (s >= 2))) {
+            i = vignette->intersection(&tmp);
+            right_connection = (i > 0) && (i < 4);
+          } else {
+            right_connection = 1;
+          }
+        } else right_connection = 0; // To avoid compilation warning
+      } while(nb_attempts < max_nb_attempts && (!right_margin || !right_connection));
+
+      if(nb_attempts < max_nb_attempts) {
+        shape.draw(vignette, xs, ys);
+        vignette->fill(xs, ys, 128);
+        if((label && s < 2) || (!label && s < 1)) {
+          for(int k = 0; k < dist_min; k++) tmp.grow();
+          avoid.superpose(&avoid, &tmp);
+        }
+      }
+    }
+  } while(nb_attempts >= max_nb_attempts);
+
+  vignette->replace_value(128, 255);
+}
diff --git a/vision_problem_3.h b/vision_problem_3.h
new file mode 100644 (file)
index 0000000..2df8286
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef VISION_PROBLEM_3_H
+#define VISION_PROBLEM_3_H
+
+#include "vignette_generator.h"
+#include "vision_problem_tools.h"
+
+class VisionProblem_3 : public VignetteGenerator {
+  static const int part_size = Vignette::width / 6;
+  static const int hole_size = Vignette::width / 64;
+public:
+  VisionProblem_3();
+  virtual void generate(int label, Vignette *vignette);
+};
+
+#endif
diff --git a/vision_problem_5.cc b/vision_problem_5.cc
new file mode 100644 (file)
index 0000000..84b058b
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "vision_problem_5.h"
+#include "shape.h"
+
+VisionProblem_5::VisionProblem_5() { }
+
+void VisionProblem_5::generate(int label, Vignette *vignette) {
+  int nb_shapes;
+
+  nb_shapes = 4;
+
+  vignette->clear();
+  Shape shape;
+
+  for(int s = 0; s < nb_shapes; s++) {
+    if(label == 0 || s == 0 || s == nb_shapes/2) {
+      shape.randomize(part_size, part_hole_size);
+    }
+
+    int xs, ys;
+    do {
+      xs = int(drand48() * Vignette::width);
+      ys = int(drand48() * Vignette::height);
+    } while(shape.overwrites(vignette, xs, ys));
+    shape.draw(vignette, xs, ys);
+  }
+}
diff --git a/vision_problem_5.h b/vision_problem_5.h
new file mode 100644 (file)
index 0000000..8c23f0d
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef VISION_PROBLEM_5_H
+#define VISION_PROBLEM_5_H
+
+#include "vignette_generator.h"
+#include "vision_problem_tools.h"
+
+class VisionProblem_5 : public VignetteGenerator {
+  static const int part_size = Vignette::width/6;
+  static const int part_hole_size = Vignette::width/64;
+public:
+  VisionProblem_5();
+  virtual void generate(int label, Vignette *vignette);
+};
+
+#endif
diff --git a/vision_problem_6.cc b/vision_problem_6.cc
new file mode 100644 (file)
index 0000000..b3b0dfb
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "vision_problem_6.h"
+#include "shape.h"
+
+VisionProblem_6::VisionProblem_6() { }
+
+void VisionProblem_6::generate(int label, Vignette *vignette) {
+  const int nb_shapes = 4;
+  int xs[nb_shapes], ys[nb_shapes];
+  int shape_number[nb_shapes];
+
+  ASSERT(nb_shapes == 4);
+
+  int too_ambiguous;
+
+  int error;
+
+  do {
+    Shape shape1, shape2;
+    shape1.randomize(part_size/2, hole_size/2);
+    shape2.randomize(part_size/2, hole_size/2);
+
+    scalar_t xc1, yc1, alpha1;
+    scalar_t xc2, yc2, alpha2;
+    scalar_t r;
+    shape_number[0] = 0;
+    shape_number[1] = 0;
+    shape_number[2] = 1;
+    shape_number[3] = 1;
+    do {
+      if(label == 1) {
+        xc1 = drand48() * (Vignette::width - part_size) ;
+        yc1 = drand48() * (Vignette::width - part_size) ;
+        alpha1 = drand48() * M_PI * 2;
+        r = drand48() * (Vignette::width + Vignette::height)/2;
+
+        xc2 = drand48() * (Vignette::width - part_size) ;
+        yc2 = drand48() * (Vignette::width - part_size) ;
+        alpha2 = drand48() * M_PI * 2;
+
+        xs[0] = int(xc1 + r * cos(alpha1));
+        ys[0] = int(yc1 + r * sin(alpha1));
+        xs[1] = int(xc1 - r * cos(alpha1));
+        ys[1] = int(yc1 - r * sin(alpha1));
+        xs[2] = int(xc2 + r * cos(alpha2));
+        ys[2] = int(yc2 + r * sin(alpha2));
+        xs[3] = int(xc2 - r * cos(alpha2));
+        ys[3] = int(yc2 - r * sin(alpha2));
+        too_ambiguous = 0;
+      } else {
+        for(int n = 0; n < nb_shapes; n++) {
+          xs[n] = int(drand48() * (Vignette::width - part_size));
+          ys[n] = int(drand48() * (Vignette::width - part_size));
+        }
+        scalar_t d1 = sqrt(sq(xs[0] - xs[1]) + sq(ys[0] - ys[1]));
+        scalar_t d2 = sqrt(sq(xs[2] - xs[3]) + sq(ys[2] - ys[3]));
+        too_ambiguous = abs(d1 - d2) < scalar_t(part_size);
+      }
+    } while(too_ambiguous ||
+            cluttered_shapes(part_size, nb_shapes, xs, ys));
+
+    vignette->clear();
+
+    error = 0;
+    for(int n = 0; n < nb_shapes; n++) {
+      if(shape_number[n] == 0) {
+        error |= shape1.overwrites(vignette, xs[n], ys[n]);
+        shape1.draw(vignette, xs[n], ys[n]);
+      } else {
+        error |= shape2.overwrites(vignette, xs[n], ys[n]);
+        shape2.draw(vignette, xs[n], ys[n]);
+      }
+    }
+  } while(error);
+}
diff --git a/vision_problem_6.h b/vision_problem_6.h
new file mode 100644 (file)
index 0000000..1cbc3fb
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef VISION_PROBLEM_6_H
+#define VISION_PROBLEM_6_H
+
+#include "vignette_generator.h"
+#include "vision_problem_tools.h"
+
+class VisionProblem_6 : public VignetteGenerator {
+  static const int part_size = Vignette::width / 6;
+  static const int hole_size = Vignette::width / 64;
+public:
+  VisionProblem_6();
+  virtual void generate(int label, Vignette *vignette);
+};
+
+#endif
diff --git a/vision_problem_8.cc b/vision_problem_8.cc
new file mode 100644 (file)
index 0000000..0d7a28e
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "vision_problem_8.h"
+#include "shape.h"
+
+VisionProblem_8::VisionProblem_8() { }
+
+void VisionProblem_8::generate(int label, Vignette *vignette) {
+  int x_big, y_big, x_small, y_small;
+  Shape big_shape, small_shape;
+
+  int error;
+  do {
+
+    vignette->clear();
+
+    error = 0;
+
+    big_shape.randomize(big_part_size / 2, big_part_hole_size / 2);
+    small_shape.copy(&big_shape);
+    small_shape.scale(0.5);
+
+    do {
+      x_big = int(drand48() * Vignette::width);
+      y_big = int(drand48() * Vignette::height);
+    } while(big_shape.overwrites(vignette, x_big, y_big));
+
+    if(!error) {
+      big_shape.draw(vignette, x_big, y_big);
+
+      vignette->fill(x_big, y_big, 128);
+
+      if(label) {
+        vignette->switch_values(128, 255);
+      } else {
+        if(drand48() < 0.5) {
+          vignette->switch_values(128, 255);
+          Shape tmp;
+          tmp.randomize(big_part_size / 2, big_part_hole_size / 2);
+          small_shape.copy(&tmp);
+          small_shape.scale(0.5);
+        }
+      }
+
+      int nb_attempts = 0;
+      do {
+        x_small = int(drand48() * Vignette::width);
+        y_small = int(drand48() * Vignette::height);
+        error = small_shape.overwrites(vignette, x_small, y_small);
+        nb_attempts++;
+      } while(error && nb_attempts < 10);
+
+      if(!error) {
+        vignette->replace_value(128, 255);
+        small_shape.draw(vignette, x_small, y_small);
+      }
+    }
+
+  } while(error);
+}
diff --git a/vision_problem_8.h b/vision_problem_8.h
new file mode 100644 (file)
index 0000000..b194452
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef VISION_PROBLEM_8_H
+#define VISION_PROBLEM_8_H
+
+#include "vignette_generator.h"
+#include "vision_problem_tools.h"
+
+class VisionProblem_8 : public VignetteGenerator {
+  static const int small_part_size = Vignette::width/6;
+  static const int small_part_hole_size = Vignette::width/64;
+  static const int big_part_size = (Vignette::width * 3)/4;
+  static const int big_part_hole_size = Vignette::width / 3;
+public:
+  VisionProblem_8();
+  virtual void generate(int label, Vignette *vignette);
+};
+
+#endif
diff --git a/vision_problem_tools.cc b/vision_problem_tools.cc
new file mode 100644 (file)
index 0000000..0100e90
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "vision_problem_tools.h"
+
+int cluttered_shapes(int part_size, int nb_shapes, int *xs, int *ys) {
+  for(int n = 0; n < nb_shapes; n++) {
+    for(int m = 0; m < n; m++) {
+      if(abs(xs[n] - xs[m]) < part_size && abs(ys[n] - ys[m]) < part_size)
+        return 1;
+    }
+  }
+  return 0;
+}
+
+scalar_t dist_point_to_segment(scalar_t xp, scalar_t yp,
+                               scalar_t x1, scalar_t y1, scalar_t x2, scalar_t y2) {
+  scalar_t s;
+  s = (xp - x1) * (x2 - x1) + (yp - y1) * (y2 - y1);
+  if(s < 0) {
+    return sqrt(sq(xp - x1) + sq(yp - y1));
+  } else if(s > sq(x2 - x1) + sq(y2 - y1)) {
+    return sqrt(sq(xp - x2) + sq(yp - y2));
+  } else {
+    return abs((xp - x1) * (y2 - y1) - (yp - y1) * (x2 - x1))/sqrt(sq(x2 - x1) + sq(y2 - y1));
+  }
+}
+
+int point_in_band(scalar_t xp, scalar_t yp,
+                  scalar_t x1, scalar_t y1, scalar_t x2, scalar_t y2,
+                  scalar_t width) {
+  scalar_t s;
+  s = (xp - x1) * (x2 - x1) + (yp - y1) * (y2 - y1);
+  if(s < 0) {
+    return 0;
+  } else if(s > sq(x2 - x1) + sq(y2 - y1)) {
+    return 0;
+  } else {
+    return abs((xp - x1) * (y2 - y1) - (yp - y1) * (x2 - x1))/sqrt(sq(x2 - x1) + sq(y2 - y1)) <= width;
+  }
+}
diff --git a/vision_problem_tools.h b/vision_problem_tools.h
new file mode 100644 (file)
index 0000000..c2082ae
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef VISION_PROBLEM_TOOLS_H
+#define VISION_PROBLEM_TOOLS_H
+
+#include "misc.h"
+#include "vignette.h"
+
+int cluttered_shapes(int part_size, int nb_shapes, int *xs, int *ys);
+
+scalar_t dist_point_to_segment(scalar_t xp, scalar_t yp,
+                               scalar_t x1, scalar_t y1, scalar_t x2, scalar_t y2);
+
+int point_in_band(scalar_t xp, scalar_t yp,
+                  scalar_t x1, scalar_t y1, scalar_t x2, scalar_t y2,
+                  scalar_t width);
+
+#endif
diff --git a/vision_test.cc b/vision_test.cc
new file mode 100644 (file)
index 0000000..94591f1
--- /dev/null
@@ -0,0 +1,304 @@
+c/*
+ *  svrt is the ``Synthetic Visual Reasoning Test'', an image
+ *  generator for evaluating classification performance of machine
+ *  learning systems, humans and primates.
+ *
+ *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
+ *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
+ *
+ *  This file is part of svrt.
+ *
+ *  svrt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation.
+ *
+ *  svrt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <iostream>
+#include <fstream>
+#include <cmath>
+#include <stdio.h>
+#include <stdlib.h>
+
+using namespace std;
+
+#include "rgb_image.h"
+#include "param_parser.h"
+#include "global.h"
+
+#include "vignette.h"
+#include "shape.h"
+#include "classifier.h"
+#include "classifier_reader.h"
+#include "naive_bayesian_classifier.h"
+#include "boosted_classifier.h"
+#include "error_rates.h"
+
+#include "vision_problem_1.h"
+#include "vision_problem_2.h"
+#include "vision_problem_3.h"
+#include "vision_problem_5.h"
+#include "vision_problem_6.h"
+#include "vision_problem_8.h"
+#include "vision_problem_11.h"
+#include "vision_problem_12.h"
+#include "vision_problem_13.h"
+#include "vision_problem_17.h"
+#include "vision_problem_18.h"
+#include "vision_problem_20.h"
+#include "vision_problem_21.h"
+
+//////////////////////////////////////////////////////////////////////
+
+void check(bool condition, const char *message) {
+  if(!condition) {
+    cerr << message << endl;
+    exit(1);
+  }
+}
+
+int main(int argc, char **argv) {
+
+  char buffer[buffer_size];
+  char *new_argv[argc];
+  int new_argc = 0;
+
+  cout << "-- ARGUMENTS ---------------------------------------------------------" << endl;
+
+  for(int i = 0; i < argc; i++)
+    cout << (i > 0 ? "  " : "") << argv[i] << (i < argc - 1 ? " \\" : "")
+         << endl;
+
+  cout << "-- PARAMETERS --------------------------------------------------------" << endl;
+
+  {
+    ParamParser parser;
+    global.init_parser(&parser);
+    parser.parse_options(argc, argv, false, &new_argc, new_argv);
+    global.read_parser(&parser);
+    parser.print_all(&cout);
+  }
+
+  nice(global.niceness);
+  srand48(global.random_seed);
+
+  VignetteGenerator *generator;
+
+  switch(global.problem_number) {
+  case 1:
+    generator = new VisionProblem_1();
+    break;
+  case 2:
+    generator = new VisionProblem_2();
+    break;
+  case 3:
+    generator = new VisionProblem_3();
+    break;
+  // case 4:
+    // generator = new VisionProblem_4();
+    // break;
+  case 5:
+    generator = new VisionProblem_5();
+    break;
+  case 6:
+    generator = new VisionProblem_6();
+    break;
+  // case 7:
+    // generator = new VisionProblem_7();
+    // break;
+  case 8:
+    generator = new VisionProblem_8();
+    break;
+  // case 9:
+    // generator = new VisionProblem_9();
+    // break;
+  // case 10:
+    // generator = new VisionProblem_10();
+    // break;
+  case 11:
+    generator = new VisionProblem_11();
+    break;
+  case 12:
+    generator = new VisionProblem_12();
+    break;
+  case 13:
+    generator = new VisionProblem_13();
+    break;
+  // case 14:
+    // generator = new VisionProblem_14();
+    // break;
+  // case 15:
+    // generator = new VisionProblem_15();
+    // break;
+  // case 16:
+    // generator = new VisionProblem_16();
+    // break;
+  case 17:
+    generator = new VisionProblem_17();
+    break;
+  case 18:
+    generator = new VisionProblem_18();
+    break;
+  // case 19:
+    // generator = new VisionProblem_19();
+    // break;
+  case 20:
+    generator = new VisionProblem_20();
+    break;
+  case 21:
+    generator = new VisionProblem_21();
+    break;
+  // case 22:
+    // generator = new VisionProblem_22();
+    // break;
+  // case 23:
+    // generator = new VisionProblem_23();
+    // break;
+  default:
+    cerr << "Can not find problem "
+         << global.problem_number
+         << endl;
+    exit(1);
+  }
+
+  generator->precompute();
+
+  //////////////////////////////////////////////////////////////////////
+
+  Vignette *train_samples;
+  int *train_labels;
+
+  train_samples = new Vignette[global.nb_train_samples];
+  train_labels = new int[global.nb_train_samples];
+
+  //////////////////////////////////////////////////////////////////////
+
+  Classifier *classifier = 0;
+
+  cout << "-- COMPUTATIONS ------------------------------------------------------" << endl;
+
+  for(int c = 1; c < new_argc; c++) {
+
+    if(strcmp(new_argv[c], "randomize-train") == 0) {
+      for(int n = 0; n < global.nb_train_samples; n++) {
+        if(n > 0 && n%100 == 0) cout << "*"; cout.flush();
+        // cout << "n = " << n << endl;
+        train_labels[n] = int(drand48() * 2);
+        generator->generate(train_labels[n], &train_samples[n]);
+      }
+      cout << endl;
+    }
+
+    else if(strcmp(new_argv[c], "adaboost") == 0) {
+      delete classifier;
+      cout << "Building and training adaboost classifier." << endl;
+      classifier = new BoostedClassifier(global.nb_weak_learners);
+      classifier->train(global.nb_train_samples, train_samples, train_labels);
+    }
+
+    else if(strcmp(new_argv[c], "naive-bayesian") == 0) {
+      delete classifier;
+      cout << "Building and training naive bayesian classifier." << endl;
+      classifier = new NaiveBayesianClassifier();
+      classifier->train(global.nb_train_samples, train_samples, train_labels);
+    }
+
+    else if(strcmp(new_argv[c], "read-classifier") == 0) {
+      delete classifier;
+      sprintf(buffer, "%s", global.classifier_name);
+      cout << "Reading classifier from " << buffer << "." << endl;
+      ifstream in(buffer);
+      if(in.fail()) {
+        cerr << "Can not open " << buffer << " for reading." << endl;
+        exit(1);
+      }
+      classifier = read_classifier(&in);
+    }
+
+    else if(strcmp(new_argv[c], "write-classifier") == 0) {
+      check(classifier, "No classifier.");
+      sprintf(buffer, "%s/%s", global.result_path, global.classifier_name);
+      cout << "Writing classifier to " << buffer << "." << endl;
+      ofstream out(buffer);
+      if(out.fail()) {
+        cerr << "Can not open " << buffer << " for writing." << endl;
+        exit(1);
+      }
+      classifier->write(&out);
+    }
+
+    else if(strcmp(new_argv[c], "compute-errors-vs-nb-samples") == 0) {
+      for(int t = global.nb_train_samples; t >= 100; t /= 10) {
+        for(int n = 0; n < t; n++) {
+          train_labels[n] = int(drand48() * 2);
+          generator->generate(train_labels[n], &train_samples[n]);
+        }
+        Classifier *classifier = 0;
+        cout << "Building and training adaboost classifier with " << t << " samples." << endl;
+        classifier = new BoostedClassifier(global.nb_weak_learners);
+        classifier->train(t, train_samples, train_labels);
+        cout << "ERROR_RATES_VS_NB_SAMPLES "
+             << t
+             << " TRAIN_ERROR "
+             << error_rate(classifier, t, train_samples, train_labels)
+             << " TEST_ERROR "
+             << test_error_rate(generator, classifier, global.nb_test_samples) << endl;
+        delete classifier;
+      }
+    }
+
+    else if(strcmp(new_argv[c], "compute-train-error") == 0) {
+      check(classifier, "No classifier.");
+      cout << "TRAIN_ERROR_RATE "
+           << classifier->name()
+           << " "
+           << error_rate(classifier, global.nb_train_samples, train_samples, train_labels)
+           << endl;
+    }
+
+    else if(strcmp(new_argv[c], "compute-test-error") == 0) {
+      check(classifier, "No classifier.");
+      cout << "TEST_ERROR_RATE "
+           << classifier->name()
+           << " "
+           << test_error_rate(generator, classifier, global.nb_test_samples) << endl;
+    }
+
+    else if(strcmp(new_argv[c], "write-samples") == 0) {
+      Vignette vignette;
+      for(int k = 0; k < global.nb_train_samples; k++) {
+        for(int l = 0; l < 2; l++) {
+          generator->generate(l, &vignette);
+          sprintf(buffer, "%s/sample_%01d_%04d.png", global.result_path, l, k);
+          vignette.write_png(buffer, 1);
+          cout << "Wrote " << buffer << endl;
+        }
+      }
+    }
+
+    //////////////////////////////////////////////////////////////////////
+
+    //////////////////////////////////////////////////////////////////////
+
+    else {
+      cerr << "Unknown action " << new_argv[c] << endl;
+      exit(1);
+    }
+
+  }
+
+  cout << "-- FINISHED ----------------------------------------------------------" << endl;
+
+  delete classifier;
+  delete[] train_labels;
+  delete[] train_samples;
+  delete generator;
+}