Commit ece3483c authored by ehebrard's avatar ehebrard
Browse files

neurips

parent 7c0791b4
...@@ -85,13 +85,13 @@ int main(int argc, char *argv[]) { ...@@ -85,13 +85,13 @@ int main(int argc, char *argv[]) {
WeightedDataset<int> input; WeightedDataset<int> input;
////// READING ////// READING
try { // try {
read_binary(input, opt); // read_binary(input, opt);
} catch (const std::exception &e) { // } catch (const std::exception &e) {
if (opt.verbosity >= DTOptions::NORMAL) if (opt.verbosity >= DTOptions::NORMAL)
cout << "c binarizing...\n"; cout << "c binarizing...\n";
read_non_binary(input, opt); read_non_binary(input, opt);
} // }
if (opt.sample < 1) if (opt.sample < 1)
input.sample(opt.sample); input.sample(opt.sample);
......
...@@ -65,6 +65,9 @@ int run_algorithm(DTOptions &opt) { ...@@ -65,6 +65,9 @@ int run_algorithm(DTOptions &opt) {
cout << "d examples=" << A.numExample() << " features=" << A.numFeature() cout << "d examples=" << A.numExample() << " features=" << A.numFeature()
<< endl; << endl;
// A.perfectTree();
// A.minimize_error();
////// SOLVING ////// SOLVING
if (opt.mindepth) { if (opt.mindepth) {
if (opt.minsize) if (opt.minsize)
...@@ -72,10 +75,10 @@ int run_algorithm(DTOptions &opt) { ...@@ -72,10 +75,10 @@ int run_algorithm(DTOptions &opt) {
else else
A.minimize_error_depth(); A.minimize_error_depth();
} else { } else {
if (opt.minsize) if (opt.minsize)
A.set_size_objective(); A.set_size_objective();
A.minimize_error(); A.minimize_error();
} }
Tree<E_t> sol = A.getSolution(); Tree<E_t> sol = A.getSolution();
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
#include <iostream> #include <iostream>
#include <random> #include <random>
#include <vector> #include <vector>
#include <cmath> // #include <cmath>
#include "CmdLine.hpp" #include "CmdLine.hpp"
#include "Partition.hpp" #include "Partition.hpp"
...@@ -30,31 +30,31 @@ namespace blossom { ...@@ -30,31 +30,31 @@ namespace blossom {
/// this needs to be templated with "T" and should be 0 for integral types /// this needs to be templated with "T" and should be 0 for integral types
/// (e.g., static_cast<T>(1.e-9) should work) /// (e.g., static_cast<T>(1.e-9) should work)
// #define FLOAT_PRECISION std::numeric_limits<T>::epsilon() // #define FLOAT_PRECISION std::numeric_limits<T>::epsilon()
#define FLOAT_PRECISION static_cast<T>(1.e-6) // #define FLOAT_PRECISION static_cast<T>(1.e-6)
//
template <typename T> // template <typename T>
typename std::enable_if<std::is_integral<T>::value, bool>::type // typename std::enable_if<std::is_integral<T>::value, bool>::type
equal(const T &a, const T &b) { // equal(const T &a, const T &b) {
return a == b; // return a == b;
} // }
//
template <typename T> // template <typename T>
typename std::enable_if<std::is_integral<T>::value, bool>::type // typename std::enable_if<std::is_integral<T>::value, bool>::type
lt(const T &a, const T &b) { // lt(const T &a, const T &b) {
return a < b; // return a < b;
} // }
//
template <typename T> // template <typename T>
typename std::enable_if<std::is_floating_point<T>::value, bool>::type // typename std::enable_if<std::is_floating_point<T>::value, bool>::type
equal(const T &a, const T &b) { // equal(const T &a, const T &b) {
return std::fabs(a - b) < FLOAT_PRECISION; // return std::fabs(a - b) < FLOAT_PRECISION;
} // }
//
template <typename T> // template <typename T>
typename std::enable_if<std::is_floating_point<T>::value, bool>::type // typename std::enable_if<std::is_floating_point<T>::value, bool>::type
lt(const T &a, const T &b) { // lt(const T &a, const T &b) {
return a + FLOAT_PRECISION < b; // return a + FLOAT_PRECISION < b;
} // }
template <typename E_t> class CardinalityError; template <typename E_t> class CardinalityError;
...@@ -100,6 +100,8 @@ public: ...@@ -100,6 +100,8 @@ public:
E_t getUbError() const; E_t getUbError() const;
void perfectTree();
size_t getUbDepth() const; size_t getUbDepth() const;
size_t getUbSize() const; size_t getUbSize() const;
......
...@@ -47,6 +47,9 @@ public: ...@@ -47,6 +47,9 @@ public:
template <typename boolean_function> template <typename boolean_function>
void split(Part &l1, Part &l2, boolean_function condition); void split(Part &l1, Part &l2, boolean_function condition);
void addFalse(vector<int>::iterator elt_ptr);
void addTrue(vector<int>::iterator elt_ptr);
/*!@name Miscellaneous*/ /*!@name Miscellaneous*/
//@{ //@{
std::ostream &display(std::ostream &os) const; std::ostream &display(std::ostream &os) const;
...@@ -82,6 +85,8 @@ public: ...@@ -82,6 +85,8 @@ public:
template <typename boolean_function> template <typename boolean_function>
void branch(const int node, const int x, const int y, void branch(const int node, const int x, const int y,
boolean_function condition); boolean_function condition);
void branch(const int node, const int x, const int y);
/*!@name Miscellaneous*/ /*!@name Miscellaneous*/
//@{ //@{
......
...@@ -263,7 +263,7 @@ public: ...@@ -263,7 +263,7 @@ public:
// cout << ClassicEncoding<T>::value_set.size() << " " << (num_examples) ; // cout << ClassicEncoding<T>::value_set.size() << " " << (num_examples) ;
if (ClassicEncoding<T>::value_set.size() < sqrt(num_examples)) { if (ClassicEncoding<T>::value_set.size() < sqrt(num_examples) or ClassicEncoding<T>::value_set.size() < 10) {
// cout << " full\n"; // cout << " full\n";
full_encoding(); full_encoding();
......
...@@ -154,7 +154,9 @@ inline void WeightedDataset<E_t>::addExample(rIter beg_row, rIter end_row, ...@@ -154,7 +154,9 @@ inline void WeightedDataset<E_t>::addExample(rIter beg_row, rIter end_row,
int f{0}; int f{0};
for (auto x{beg_row}; x != end_row; ++x) { for (auto x{beg_row}; x != end_row; ++x) {
assert(*x == 0 or *x == 1); // assert(*x == 0 or *x == 1);
if (*x != 0 and *x != 1)
throw 0;
if (x - beg_row != column) { if (x - beg_row != column) {
if (*x) if (*x)
data[y].back().set(f); data[y].back().set(f);
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <iomanip> #include <iomanip>
#include <iostream> #include <iostream>
#include <math.h> #include <math.h>
#include <cmath>
// #define DEBUG_MODE // #define DEBUG_MODE
...@@ -29,6 +30,32 @@ floating_point fixedwidthfloat(const floating_point f, const int width) { ...@@ -29,6 +30,32 @@ floating_point fixedwidthfloat(const floating_point f, const int width) {
return (static_cast<floating_point>(i) / m); return (static_cast<floating_point>(i) / m);
} }
#define FLOAT_PRECISION static_cast<T>(1.e-6)
template <typename T>
typename std::enable_if<std::is_integral<T>::value, bool>::type
equal(const T &a, const T &b) {
return a == b;
}
template <typename T>
typename std::enable_if<std::is_integral<T>::value, bool>::type
lt(const T &a, const T &b) {
return a < b;
}
template <typename T>
typename std::enable_if<std::is_floating_point<T>::value, bool>::type
equal(const T &a, const T &b) {
return std::fabs(a - b) < FLOAT_PRECISION;
}
template <typename T>
typename std::enable_if<std::is_floating_point<T>::value, bool>::type
lt(const T &a, const T &b) {
return a + FLOAT_PRECISION < b;
}
} }
#endif // _BLOSSOM_UTILS_HPP #endif // _BLOSSOM_UTILS_HPP
...@@ -334,6 +334,7 @@ void BacktrackingAlgorithm<ErrorPolicy, E_t>::print_new_best() { ...@@ -334,6 +334,7 @@ void BacktrackingAlgorithm<ErrorPolicy, E_t>::print_new_best() {
<< search_size << " mem=" << setw(3) << wood.size() << search_size << " mem=" << setw(3) << wood.size()
<< " time=" << setprecision(max(4, static_cast<int>(log10(t)))) << " time=" << setprecision(max(4, static_cast<int>(log10(t))))
<< fixedwidthfloat(t, 3) << right << endl; << fixedwidthfloat(t, 3) << right << endl;
} }
template <template <typename> class ErrorPolicy, typename E_t> template <template <typename> class ErrorPolicy, typename E_t>
...@@ -601,7 +602,8 @@ void BacktrackingAlgorithm<ErrorPolicy, E_t>::sort_features(const int node) { ...@@ -601,7 +602,8 @@ void BacktrackingAlgorithm<ErrorPolicy, E_t>::sort_features(const int node) {
for (auto f{feature[node]}; f != end_feature[node]; ++f) for (auto f{feature[node]}; f != end_feature[node]; ++f)
f_error[*f] = get_feature_error(node, *f); f_error[*f] = get_feature_error(node, *f);
sort(feature[node], end_feature[node], sort(feature[node], end_feature[node],
[&](const int a, const int b) { return f_error[a] < f_error[b]; }); // [&](const int a, const int b) { return f_error[a] < f_error[b]; });
[&](const int a, const int b) { return (f_error[a] < f_error[b] or (f_error[a] == f_error[b] and a < b)); });
break; break;
case DTOptions::ENTROPY: case DTOptions::ENTROPY:
for (auto f{feature[node]}; f != end_feature[node]; ++f) for (auto f{feature[node]}; f != end_feature[node]; ++f)
...@@ -830,12 +832,12 @@ bool BacktrackingAlgorithm<ErrorPolicy, E_t>::update_upperbound(const int node) ...@@ -830,12 +832,12 @@ bool BacktrackingAlgorithm<ErrorPolicy, E_t>::update_upperbound(const int node)
max_error[node] = err; max_error[node] = err;
max_size[node] = sz; max_size[node] = sz;
#ifdef PRINTTRACE // #ifdef PRINTTRACE
if (PRINTTRACE) // if (PRINTTRACE)
cout << "new best for node " << node << ": feat=" << *feature[node] // cout << "new best for node " << node << ": feat=" << *feature[node]
<< ", error=" << max_error[node] << ", size=" << max_size[node] // << ", error=" << max_error[node] << ", size=" << max_size[node]
<< endl; // << endl;
#endif // #endif
if (node > 0) { if (node > 0) {
assert(parent[node] >= 0); assert(parent[node] >= 0);
...@@ -863,6 +865,7 @@ bool BacktrackingAlgorithm<ErrorPolicy, E_t>::backtrack() { ...@@ -863,6 +865,7 @@ bool BacktrackingAlgorithm<ErrorPolicy, E_t>::backtrack() {
#ifdef PRINTTRACE #ifdef PRINTTRACE
if (PRINTTRACE) { if (PRINTTRACE) {
cout << setw(3) << decision.size();
for (auto i{0}; i < decision.size(); ++i) for (auto i{0}; i < decision.size(); ++i)
cout << " "; cout << " ";
cout << "backtrack to " << backtrack_node << endl; cout << "backtrack to " << backtrack_node << endl;
...@@ -874,13 +877,13 @@ bool BacktrackingAlgorithm<ErrorPolicy, E_t>::backtrack() { ...@@ -874,13 +877,13 @@ bool BacktrackingAlgorithm<ErrorPolicy, E_t>::backtrack() {
(equal<E_t>(tree_error[backtrack_node],max_error[backtrack_node]) and (equal<E_t>(tree_error[backtrack_node],max_error[backtrack_node]) and
tree_size[backtrack_node] > max_size[backtrack_node])) { tree_size[backtrack_node] > max_size[backtrack_node])) {
#ifdef PRINTTRACE // #ifdef PRINTTRACE
if (PRINTTRACE) // and not updt) // if (PRINTTRACE) // and not updt)
cout << "new best for node " << backtrack_node // cout << "new best for node " << backtrack_node
<< ": feat=" << *feature[backtrack_node] // << ": feat=" << *feature[backtrack_node]
<< ", error=" << max_error[backtrack_node] // << ", error=" << max_error[backtrack_node]
<< ", size=" << max_size[backtrack_node] << endl; // << ", size=" << max_size[backtrack_node] << endl;
#endif // #endif
tree_error[backtrack_node] = max_error[backtrack_node]; tree_error[backtrack_node] = max_error[backtrack_node];
tree_size[backtrack_node] = max_size[backtrack_node]; tree_size[backtrack_node] = max_size[backtrack_node];
...@@ -888,12 +891,12 @@ bool BacktrackingAlgorithm<ErrorPolicy, E_t>::backtrack() { ...@@ -888,12 +891,12 @@ bool BacktrackingAlgorithm<ErrorPolicy, E_t>::backtrack() {
} else { } else {
#ifdef PRINTTRACE // #ifdef PRINTTRACE
if (PRINTTRACE) // if (PRINTTRACE)
cout << "no improvement for node " << backtrack_node // cout << "no improvement for node " << backtrack_node
<< ": feat=" << *feature[backtrack_node] << "(" // << ": feat=" << *feature[backtrack_node] << "("
<< ") -> free the best subtrees" << endl; // << ") -> free the best subtrees" << endl;
#endif // #endif
for (auto i{0}; i < 2; ++i) for (auto i{0}; i < 2; ++i)
if (child[i][backtrack_node] >= 0 and if (child[i][backtrack_node] >= 0 and
...@@ -914,12 +917,13 @@ bool BacktrackingAlgorithm<ErrorPolicy, E_t>::backtrack() { ...@@ -914,12 +917,13 @@ bool BacktrackingAlgorithm<ErrorPolicy, E_t>::backtrack() {
(not max_entropy(backtrack_node, *feature[backtrack_node]))); (not max_entropy(backtrack_node, *feature[backtrack_node])));
dead_end = ( dead_end = (
// (depth[backtrack_node] == ub_depth - 1 and
// (node_error(backtrack_node) >= ub_error)) or
// current_error >= ub_error or // current_error >= ub_error or
(lt<E_t>(0,ub_error) and equal<E_t>(max_error[backtrack_node], 0)) or (lt<E_t>(0, ub_error) and equal<E_t>(max_error[backtrack_node], 0)) or
no_feature(backtrack_node) or no_feature(backtrack_node) or
max_entropy(backtrack_node, *feature[backtrack_node]) max_entropy(backtrack_node, *feature[backtrack_node]) or
or ( options.bounding and fail(backtrack_node) ) (options.bounding and fail(backtrack_node)));
);
// backtrack again // backtrack again
if (dead_end) { if (dead_end) {
...@@ -1013,12 +1017,8 @@ void BacktrackingAlgorithm<ErrorPolicy, E_t>::branch(const int node, const int f ...@@ -1013,12 +1017,8 @@ void BacktrackingAlgorithm<ErrorPolicy, E_t>::branch(const int node, const int f
cout << setw(3) << decision.size(); cout << setw(3) << decision.size();
for (auto i{0}; i < decision.size(); ++i) for (auto i{0}; i < decision.size(); ++i)
cout << " "; cout << " ";
cout << "branch on " << node << " with " << f << " children: " << c[0] cout << "branch on " << node << " with " << f << " ("
// << " (" << P[0][c[0]].count() << "/" << P[1][c[0]].count() << ") and << (end_feature[node] - feature[node]) << ")";
// "
// << c[1] << "(" << P[0][c[1]].count() << "/" << P[1][c[1]].count()
// << ")"
<< endl;
} }
#endif #endif
...@@ -1065,6 +1065,36 @@ void BacktrackingAlgorithm<ErrorPolicy, E_t>::branch(const int node, const int f ...@@ -1065,6 +1065,36 @@ void BacktrackingAlgorithm<ErrorPolicy, E_t>::branch(const int node, const int f
++current_size; ++current_size;
} }
} }
#ifdef PRINTTRACE
if (PRINTTRACE) {
// cout << setw(3) << decision.size()-1;
// for (auto i{0}; i < decision.size()-1; ++i)
// cout << " ";
// cout << "branch on " << node << " (" << P[node].count() << "/"
// << (usize(node) - P[node].count()) << ") with " << f
// cout << " children: " << child[0][node] << " (" << P[0][c[0]].count() << "/" << P[1][c[0]].count() << ") and " << c[1] << " ("
// << P[0][c[1]].count() << "/" << P[1][c[1]].count()
// << ")" << endl;
cout << " children: " << c[0] << " (" << P[0][c[0]].count() << "/" << P[1][c[0]].count() << ") and " << c[1] << " ("
<< P[0][c[1]].count() << "/" << P[1][c[1]].count()
<< ")" << endl;
// cout << " children: " << c[0] << " ("
// << (child[0][node] >= 0 ? error_policy.get_total(0, child[0][node]) :
// (child[0][node] == -1 ? error_policy.get_total(0, node) : 0))
// << "/"
// << (child[0][node] >= 0 ? error_policy.get_total(1, child[0][node]) :
// (child[0][node] == -2 ? error_policy.get_total(1, node) : 0))
// << ") and "
// << c[1] << " ("
// << (child[1][node] >= 0 ? error_policy.get_total(0, child[1][node]) :
// (child[1][node] == -1 ? error_policy.get_total(0, node) : 0))
// << "/"
// << (child[1][node] >= 0 ? error_policy.get_total(1, child[1][node]) :
// (child[1][node] == -2 ? error_policy.get_total(1, node) : 0))
// << ")" << endl;
}
#endif
update_upperbound(node); update_upperbound(node);
} }
...@@ -1172,16 +1202,16 @@ void BacktrackingAlgorithm<ErrorPolicy, E_t>::expend() { ...@@ -1172,16 +1202,16 @@ void BacktrackingAlgorithm<ErrorPolicy, E_t>::expend() {
break; break;
} }
if (max_entropy(selected_node, *feature[selected_node])) { // if (max_entropy(selected_node, *feature[selected_node])) {
//
cout << selected_node << " " << *feature[selected_node] << " " // cout << selected_node << " " << *feature[selected_node] << " "
<< get_feature_frequency(0, selected_node, *feature[selected_node]) // << get_feature_frequency(0, selected_node, *feature[selected_node])
<< " / " << error_policy.get_total(0, selected_node) << " || " // << " / " << error_policy.get_total(0, selected_node) << " || "
<< get_feature_frequency(1, selected_node, *feature[selected_node]) // << get_feature_frequency(1, selected_node, *feature[selected_node])
<< " / " << error_policy.get_total(1, selected_node) << endl; // << " / " << error_policy.get_total(1, selected_node) << endl;
} // }
//
assert(not max_entropy(selected_node, *feature[selected_node])); // assert(not max_entropy(selected_node, *feature[selected_node]));
} }
if (options.width > 1) if (options.width > 1)
...@@ -1190,6 +1220,11 @@ void BacktrackingAlgorithm<ErrorPolicy, E_t>::expend() { ...@@ -1190,6 +1220,11 @@ void BacktrackingAlgorithm<ErrorPolicy, E_t>::expend() {
assert(feature[selected_node] >= ranked_feature[selected_node].begin() and assert(feature[selected_node] >= ranked_feature[selected_node].begin() and
feature[selected_node] < end_feature[selected_node]); feature[selected_node] < end_feature[selected_node]);
// cout << "(" << (end_feature[selected_node] - feature[selected_node]) << ")";
// for(auto f{feature[selected_node]}; f!=end_feature[selected_node]; ++f)
// cout << setw(3) << *f << " [" << get_feature_error(selected_node, *f) << "]";
// cout << endl;
branch(selected_node, *(feature[selected_node])); branch(selected_node, *(feature[selected_node]));
...@@ -1203,7 +1238,8 @@ void BacktrackingAlgorithm<ErrorPolicy, E_t>::initialise_search() { ...@@ -1203,7 +1238,8 @@ void BacktrackingAlgorithm<ErrorPolicy, E_t>::initialise_search() {
num_level_zero_feature = num_feature; num_level_zero_feature = num_feature;
setReverse(); setReverse();
start_time = cpu_time(); start_time = cpu_time();
// search_size = 0; // search_size = 0;
...@@ -1374,6 +1410,11 @@ void BacktrackingAlgorithm<ErrorPolicy, E_t>::minimize_error() { ...@@ -1374,6 +1410,11 @@ void BacktrackingAlgorithm<ErrorPolicy, E_t>::minimize_error() {
print_new_best(); print_new_best();
} }
template <template <typename> class ErrorPolicy, typename E_t>
void BacktrackingAlgorithm<ErrorPolicy, E_t>::perfectTree() {
ub_error = min_positive<E_t>();
}
template <template<typename> class ErrorPolicy, typename E_t> template <template<typename> class ErrorPolicy, typename E_t>
void BacktrackingAlgorithm<ErrorPolicy, E_t>::minimize_error_depth() { void BacktrackingAlgorithm<ErrorPolicy, E_t>::minimize_error_depth() {
...@@ -1520,10 +1561,10 @@ void BacktrackingAlgorithm<ErrorPolicy, E_t>::clearExamples() { ...@@ -1520,10 +1561,10 @@ void BacktrackingAlgorithm<ErrorPolicy, E_t>::clearExamples() {
template <template <typename> class ErrorPolicy, typename E_t> template <template <typename> class ErrorPolicy, typename E_t>
bool BacktrackingAlgorithm<ErrorPolicy, E_t>::fail(const int b) const { bool BacktrackingAlgorithm<ErrorPolicy, E_t>::fail(const int b) const {
#ifdef PRINTTRACE // #ifdef PRINTTRACE
if (PRINTTRACE) // if (PRINTTRACE)
cout << "bound from " << b << endl; // cout << "bound from " << b << endl;
#endif // #endif
E_t lbe{0}; E_t lbe{0};
auto lbs{0}; auto lbs{0};
...@@ -1544,15 +1585,15 @@ bool BacktrackingAlgorithm<ErrorPolicy, E_t>::fail(const int b) const { ...@@ -1544,15 +1585,15 @@ bool BacktrackingAlgorithm<ErrorPolicy, E_t>::fail(const int b) const {
lbs += min_size[child[i][p]]; lbs += min_size[child[i][p]];
++lbs; ++lbs;
} }
#ifdef PRINTTRACE // #ifdef PRINTTRACE
if (PRINTTRACE) // if (PRINTTRACE)
cout << "parent " << p << " (ub=" << ube << "/" << ubs << ", lb=" << lbe // cout << "parent " << p << " (ub=" << ube << "/" << ubs << ", lb=" << lbe
<< "/" << lbs << ") [" // << "/" << lbs << ") ["
<< (child[0][p] >= 0 ? min_error[child[0][p]] : 0) << "/" // << (child[0][p] >= 0 ? min_error[child[0][p]] : 0) << "/"
<< (child[1][p] >= 0 ? min_error[child[1][p]] : 0) << " | " // << (child[1][p] >= 0 ? min_error[child[1][p]] : 0) << " | "
<< (child[0][p] >= 0 ? min_size[child[0][p]] : 1) << "/" // << (child[0][p] >= 0 ? min_size[child[0][p]] : 1) << "/"
<< (child[1][p] >= 0 ? min_size[child[1][p]] : 1) << "]\n"; // << (child[1][p] >= 0 ? min_size[child[1][p]] : 1) << "]\n";
#endif // #endif
if (lt<E_t>(ube, lbe) or if (lt<E_t>(ube, lbe) or
(equal<E_t>(lbe, ube) and (lbs >= ubs or not size_matters))) { (equal<E_t>(lbe, ube) and (lbs >= ubs or not size_matters))) {
......
...@@ -31,6 +31,11 @@ size_t TreePartition::addNode() { ...@@ -31,6 +31,11 @@ size_t TreePartition::addNode() {
void TreePartition::remNode() { part.pop_back(); } void TreePartition::remNode() { part.pop_back(); }
void TreePartition::branch(const int node, const int x, const int y) {
part[x].begin_idx = part[x].end_idx = part[node].begin_idx;
part[y].begin_idx = part[y].end_idx = part[node].end_idx;
}
Part &TreePartition::operator[](const int i) { return part[i]; } Part &TreePartition::operator[](const int i) { return part[i]; }
const Part &TreePartition::operator[](const int i) const { return part[i]; } const Part &TreePartition::operator[](const int i) const { return part[i]; }
...@@ -93,6 +98,14 @@ vector<int>::const_iterator Part::end() const { ...@@ -93,6 +98,14 @@ vector<int>::const_iterator Part::end() const {
return element.begin() + end_idx; return element.begin() + end_idx;
} }
void Part::addTrue(vector<int>::iterator elt_ptr) {
std::swap(*elt_ptr, element[end_idx++]);
}
void Part::addFalse(vector<int>::iterator elt_ptr) {
std::swap(*elt_ptr, element[--begin_idx]);
}
std::ostream& Part::display(std::ostream& os) const { std::ostream& Part::display(std::ostream& os) const {