420KH2 Consignes pour la PFI

Ce qui suit détaille les règles pour la PFI du cours pour la session H2019. Notez qu'il s'agit d'une activité individuelle.

Contexte

Normalement, j'aurais intégré la PFI aux travaux de vos autres cours, mais ce serait compliqué cette année dû à l'agencement... atypique de vos cours de la session S4. Pour cette raison, notre PFI sera une activité individuelle propre à notre cours plutôt qu'une partie d'un travail commun à plusieurs cours.

Consignes

Considérant que vous n'avez que peu de temps pour faire ce travail, il sera bref. Soit la classe générique Mat2D<T> suivante :

#include <vector>
#include <iterator>

template <class T>
   class Mat2D {
      std::vector<T> vals;
   public:
      using size_type = int;
   private:
      size_type hau_,
                lar_;
   public:
      auto begin() {
         return std::begin(vals);
      }
      auto begin() const {
         return std::begin(vals);
      }
      auto end() {
         return std::end(vals);
      }
      auto end() const {
         return std::end(vals);
      }
      Mat2D(size_type hauteur, size_type largeur)
         : hau_{ hauteur }, lar_{ largeur }, vals(hauteur * largeur) {
      }
      auto operator[](size_type n) noexcept {
         return &vals[n * largeur()];
      }
      const auto operator[](size_type n) const noexcept {
         return &vals[n * largeur()];
      }
      size_type hauteur() const noexcept {
         return hau_;
      }
      size_type largeur() const noexcept {
         return lar_;
      }
      size_type size() const noexcept {
         return vals.size();
      }
   };
// ...

... et soit la fonction de fabrication suivante (prenez la version que vous préférez; elles sont équivalentes), qui crée une Mat2D<R> avec un nombre de lignes et de colonnes suppléés par l'appelant, en initialisant chaque case de cette matrice avec la valeur de retour d'une fonction génératrice gen() :

Version « manuelle » Version avec algorithme
template <class T, class G>
   Mat2D<T> fabriquer_matrice(int lignes, int colonnes, G gen) {
      Mat2D<T> mat{ lignes, colonnes };
      using size_type = typename Mat2D<T>::size_type;
      for (size_type i = 0; i != mat.hauteur(); ++i)
         for (size_type j = 0; j != mat.largeur(); ++j)
            mat[i][j] = gen();
      return mat;
   }
// ...
template <class T, class G>
   Mat2D<T> fabriquer_matrice(int lignes, int colonnes, G gen) {
      Mat2D<T> mat{ lignes, colonnes };
      std::generate(std::begin(mat), std::end(mat), gen);
      return mat;
   }
// ...

... enfin, soit le programme de test suivant, que vous pourrez adapter à vos besoins, sans toutefois changer la signature des fonctions compter_sequentiel(), compter_parallele() et compter_sequentiel_m() :

 
// ...
#include <utility>
#include <iterator>
#include <chrono>
#include <random>
#include <iostream>
using namespace std;
using namespace std::chrono;
template <class F, class ... Args>
   auto test(F f, Args &&... args) {
      auto pre = high_resolution_clock::now();
      auto res = f(std::forward<Args>(args)...);
      auto post = high_resolution_clock::now();
      return pair{ res, post - pre };
   }
int main() {
   // auto mat = fabriquer_matrice<int>(10, 20, [n = -5]() mutable { return n++; });
   auto mat = fabriquer_matrice<short>(10, 20, [prng = mt19937{ random_device{}() },
                                                d10 = uniform_int_distribution<short>{ 1,10 }]() mutable {
      return d10(prng);
   });
   cout << mat << endl;
   auto crit = [](auto n) {
      return n % 2 == 0;
   };
   auto [r0, dt0] = test([&] { return compter_sequentiel(mat, crit); });
   auto [r1, dt1] = test([&] { return compter_parallele(begin(mat), end(mat), crit); });
   cout << "Nombre de pairs (sequentiel) : " << r0
        << " obtenu en " << duration_cast<microseconds>(dt0).count() << " us.\n"<< endl;
   cout << "Nombre de pairs (parallele) : " << r1
        << " obtenu en " << duration_cast<microseconds>(dt1).count() << " us.\n" << endl;
   auto [r2, dt2] = test([&] {
      int n = 0;
      for (auto debut = begin(mat); debut != end(mat); ) {
         auto [cur, m] = compter_sequentiel_m(debut, end(mat), crit, [n = 20]() mutable {
            --n;
            return n != 0;
         });
         debut = cur;
         n += m;
         // cout << '.';
      }
      return n;
   });
   cout << "Nombre de pairs (sequentiel, morcelable) : " << r2
        << " obtenu en " << duration_cast<microseconds>(dt2).count() << " us.\n" << endl;
}

Rappel : un prédicat applicable à un T est une fonction de signature bool(T). Par exemple, la fonction bool est_pair(int) est un prédicat applicable à un int.

Votre mandat sera de coder les fonctions suivantes :

Dans la réalisation de cette tâche, vous avez un certain degré de liberté :

Possible code de test

Pour vous amuser, voici un  possible code de test (vous pouvez ajouter des cas à loisir) :

// ...
enum class afficher_matrice : unsigned char { oui, non };
template <class T, class Crit, class MkPred>
   auto tests(afficher_matrice aff, ostream &os, string_view nom, const Mat2D<T> &mat, Crit crit, MkPred mkpred) {
      if (aff == afficher_matrice::oui)
         os << mat << "\n\n";
      auto [r0, dt0] = test([&] { return compter_sequentiel(mat, crit); });
      auto [r1, dt1] = test([&] { return compter_parallele(begin(mat), end(mat), crit); });
      os << r0 << " en " << duration_cast<microseconds>(dt0).count() << " us. pour " << nom << " sequentiel\n";
      os << r1 << " en " << duration_cast<microseconds>(dt1).count() << " us. pour " << nom << " parallele\n";
      int nmcx = 0;
      auto [r2, dt2] = test([&] {
         int n = 0;
         for (auto debut = begin(mat); debut != end(mat); ) {
            auto [cur, m] = compter_sequentiel_m(debut, end(mat), crit, mkpred());
            debut = cur;
            n += m;
            ++nmcx;
            // cout << '.';
         }
         return n;
      });
      os << r2 << " en " << duration_cast<microseconds>(dt2).count() << " us. pour " << nom << " sequentiel morcelable (" << nmcx << " morceaux)\n\n";
   }


int main() {
   using namespace std;
   tests(
      afficher_matrice::oui, cout,
      "nb impairs"sv,
      fabriquer_matrice<int>(10, 20, [n = -5]() mutable { return n++; }),
      [](auto n) { return n % 2 != 0; },
      [] { return[n = 5]() mutable {
         --n;
         return n != 0;
      }; }
   );
   tests(
      afficher_matrice::oui, cout,
      "nb pairs"sv,
      fabriquer_matrice<short>(10, 20, [prng = mt19937{ random_device{}() },
         d10 = uniform_int_distribution<short>{ 1,10 }]() mutable {
         return d10(prng);
      }),
      [](auto n) { return n % 2 == 0; },
      [] { return[n = 20]() mutable {
         --n;
         return n != 0;
      }; }
   );
   tests(
      afficher_matrice::non, cout,
      "nb impairs (gros)"sv,
      fabriquer_matrice<int>(1'000, 2'000, [n = -5]() mutable { return n++; }),
      [](auto n) { return n % 2 != 0; },
      [] { return[deadline = high_resolution_clock::now() + 500us]() mutable {
         return high_resolution_clock::now() < deadline;
      }; }
   );
   tests(
      afficher_matrice::oui, cout,
      "nb gros mots"sv,
      fabriquer_matrice<string>(10, 2, [prng = mt19937{ random_device{}() },
                                        d2 = uniform_int_distribution<short>{ 0,1 }]() mutable {
         return d2(prng) ? "patate"s : "supercalifragilistique"s;
      }),
      [](auto && s) { return s.size() > 10; },
      [] { return[deadline = high_resolution_clock::now() + 500us]() mutable {
         return high_resolution_clock::now() < deadline;
      }; }
   );
   tests(
      afficher_matrice::non, cout,
      "nb gros mots (gros)"sv,
      fabriquer_matrice<string>(1'000, 500, [prng = mt19937{ random_device{}() },
                                        d2 = uniform_int_distribution<short>{ 0,1 }]() mutable {
         return d2(prng) ? "patate"s : "supercalifragilistique"s;
      }),
      [](auto&& s) { return s.size() > 10; },
      [] { return[deadline = high_resolution_clock::now() + 500us]() mutable {
         return high_resolution_clock::now() < deadline;
      }; }
   );
}

Un affichage convenable serait :

  -5   -4   -3   -2   -1    0    1    2    3    4    5    6    7    8    9   10   11   12   13   14
  15   16   17   18   19   20   21   22   23   24   25   26   27   28   29   30   31   32   33   34
  35   36   37   38   39   40   41   42   43   44   45   46   47   48   49   50   51   52   53   54
  55   56   57   58   59   60   61   62   63   64   65   66   67   68   69   70   71   72   73   74
  75   76   77   78   79   80   81   82   83   84   85   86   87   88   89   90   91   92   93   94
  95   96   97   98   99  100  101  102  103  104  105  106  107  108  109  110  111  112  113  114
 115  116  117  118  119  120  121  122  123  124  125  126  127  128  129  130  131  132  133  134
 135  136  137  138  139  140  141  142  143  144  145  146  147  148  149  150  151  152  153  154
 155  156  157  158  159  160  161  162  163  164  165  166  167  168  169  170  171  172  173  174
 175  176  177  178  179  180  181  182  183  184  185  186  187  188  189  190  191  192  193  194


100 en 1 us. pour nb impairs sequentiel
100 en 1 us. pour nb impairs parallele
100 en 1 us. pour nb impairs sequentiel morcelable (50 morceaux)

  7   3   8   8   3   6   2   5   5   5   9   8   3   4   6   4   4   1   2   4
  6   5  10   2   3   8   8   4   4   1   9   5   5  10   7   3  10   5   7   2
  9   1   2   8   4   2   6   1   7   3   1   6   3   8   3  10  10   4   9   2
  6   5   9   9   8   1   8   8   6   5  10   4   1   4   2   9  10   3   6   9
 10  10   6   6   1   7   7   2   3   9  10   9   6   1   5   4   4  10   8   7
 10   3   1   5  10   8   4   8   2   3   8   5   9   3   3   4   4   5   8   1
  2   3   9  10   8   2   5   3   2   9   5   7   7   3   8   9   9   3   1   5
  2   8   3   2  10   8   9   4   1  10   6   9   4   1   4   2   3   4   6   1
  1   4   9   4   1   9  10   7   4   5   3   9   9   5   3   2   3   3   4   3
 10   4   3   7   9   2  10   6   7  10   9   9   3   8   1   3   3  10   3   2


98 en 44 us. pour nb pairs sequentiel
98 en 1 us. pour nb pairs parallele
98 en 4 us. pour nb pairs sequentiel morcelable (11 morceaux)

1000000 en 10942 us. pour nb impairs (gros) sequentiel
1000000 en 17802 us. pour nb impairs (gros) parallele
1000000 en 488783 us. pour nb impairs (gros) sequentiel morcelable (968 morceaux)

supercalifragilistique                 patate
supercalifragilistique supercalifragilistique
supercalifragilistique                 patate
                patate                 patate
supercalifragilistique                 patate
supercalifragilistique                 patate
                patate                 patate
supercalifragilistique supercalifragilistique
                patate                 patate
supercalifragilistique supercalifragilistique


10 en 0 us. pour nb gros mots sequentiel
10 en 0 us. pour nb gros mots parallele
10 en 3 us. pour nb gros mots sequentiel morcelable (1 morceaux)

249577 en 5031 us. pour nb gros mots (gros) sequentiel
249577 en 2228 us. pour nb gros mots (gros) parallele
249577 en 150091 us. pour nb gros mots (gros) sequentiel morcelable (297 morceaux)

Paramètres de remise

Ce que vous devrez remettre sera :

La remise imprimée devra être faite à la dernière séance de la session (séance T14).

Vous avez suffisamment de temps pour faire cette tâche, et pour bien la faire. Assurez-vous de produire du code de qualité, et de profiter des acquis accumulés tout au cours de la session.


Valid XHTML 1.0 Transitional

CSS Valide !