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.
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.
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 |
---|---|
|
|
... 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é :
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)
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.