/** * Choose an amount of bits (percentage of size of dataset) * of bits and turn them off or on with a probability, but, if * a bit has to be turned off, then it has to be ramdon bit on. * If a bit has to be turned on, then it has to be a random bit off. * @param 'S' : Solution */ void weightedRandomPlus::tweak(IS::Solution &S) { std::bitset<MAX> bits = S.getBits(); int size = S.getSize(); int n = (perc * size) / 100; double reduc = ((double) reduc_weight) / 100.0; for (int k = 0; k < n; k++) { double prob = ((double) rand() / (double) RAND_MAX); // Select a random bit on, and set it off if (bits.count() > 0 and reduc - prob > EPSILON) { int random_bit_on = (rand() % bits.count()) + 1; int i, j; for (j = 0, i = 0; j < size && i < random_bit_on; j++) if (bits.test(j)) i++; assert(bits.test(j-1)); bits[j-1] = 0; } else { // Select a random bit off, and set it on int random_bit_off = (rand() % (size - bits.count())) + 1; int i, j; for (j = 0, i = 0; j < size && i < random_bit_off; j++) if (! bits.test(j)) i++; assert(! bits.test(j-1)); bits[j-1] = 1; } } S.setBits(bits); }
/** * Apply n Random flips on random bits of solution * @param 'S' : Solution */ void nRandomFlips::tweak(IS::Solution &S) { std::bitset<MAX> bits = S.getBits(); int size = S.getSize(); for (int i = 0; i < n; ++i) { int j = (rand() % size); bits.flip(j); } S.setBits(bits); }
/** * Just turn off one random bit (but a bit that is on) * @param 'S' : Solution */ void oneRandomUnset::tweak(IS::Solution &S) { std::bitset<MAX> bits = S.getBits(); int size = S.getSize(); int n = (rand() % bits.count()) + 1; int i, j; for (j = 0, i = 0; j < size && i < n; j++) if (bits.test(j)) i++; assert(bits.test(j-1)); bits[j-1] = 0; S.setBits(bits); }
/** * Optimize of ILS * @param 'T' : Dataset * @param 'S' : Solution * * This function save in S the best found solution */ void ILS::optimize(const IS::Dataset &T, IS::Solution &S) const { std::cout << ">>>> Running ILS" << std::endl; std::cout << "quality = " << max_quality << std::endl; std::cout << "ite_limit = " << ite_limit << std::endl; std::cout << "no_change_best = " << no_change_best << std::endl; std::cout << ">>>>>>>>>>>>>>>>>>>>" << std::endl; IS::Solution best(S); double q_max, q_BEST = -1.0; int global_iter = 0; int max_out_iter = ite_limit; int no_change = 0; int max_local_iter = getLocalIter(); while(1) { global_iter++; // Local search int local_iter = 0; while(1) { local_iter++; IS::Solution R(S); tweaker->tweak(R); double q1 = quality(T, R, 0.5), q2 = quality(T, S, 0.5); if (q1 > q2) S.setBits(R.getBits()); q_max = std::max(q1, q2); bool stop = q_max > max_quality or local_iter == max_local_iter; if (stop) break; } // Compare and (maybe) perturb double qs = quality(T, S, 0.5); double qb = quality(T, best, 0.5); if (qs > qb) { best.setBits(S.getBits()); no_change = 0; } else { no_change++; } //weightedRandomPlus tweaker = weightedRandomPlus(perc, 50); int perc = S.getSize() / getPerturbPerc(); nRandomFlips tweaker = nRandomFlips(perc); tweaker.tweak(S); bool stop = q_max > max_quality or global_iter == max_out_iter; stop = stop or no_change == no_change_best; if (stop) break; } S.copy(best); }
/** * Choose an amount of bits (percentage of size of dataset) * of bits and turn them off or on with a probability * @param 'S' : Solution */ void weightedRandom::tweak(IS::Solution &S) { std::bitset<MAX> bits = S.getBits(); int size = S.getSize(); int n = (perc * size) / 100; double reduc = ((double) reduc_weight) / 100.0; for (int i = 0; i < n; ++i) { int j = (rand() % size); double prob = ((double) rand() / (double) RAND_MAX); bits[j] = (reduc - prob > EPSILON) ? 0 : 1; } S.setBits(bits); }
/** * Optimize of HillClimbing * @param 'T' : Dataset * @param 'S' : Solution * * This function save in S the best found solution */ void HillClimbing::optimize(const IS::Dataset &T, IS::Solution &S) const { std::cout << ">>>> Running Hill Climbing" << std::endl; std::cout << "quality = " << max_quality << std::endl; std::cout << "ite_limit = " << ite_limit << std::endl; std::cout << "no_change_best = " << no_change_best << std::endl; std::cout << ">>>>>>>>>>>>>>>>>>>>" << std::endl; double q_max, q_best = -1; int no_change = 0, iter = 0; while (1) { iter++; IS::Solution R(S); tweaker->tweak(R); // assert((S.getBits() ^ R.getBits()).count() == 1); // Using 0.5 because paper double q1 = quality(T, R, 0.5), q2 = quality(T, S, 0.5); if (q1 > q2) S.setBits(R.getBits()); q_max = std::max(q1, q2); if (q_best > q_max) { no_change++; } else { q_best = q_max; no_change = 0; } // TODO: Pass these values as parameters bool stop = q_max > max_quality or no_change == no_change_best; stop = stop || iter == ite_limit; if (stop) break; } }
/** * Optimize of ILS * @param 'T' : Dataset * @param 'S' : Solution * * This function save in S the best found solution */ void Tabu::optimize(const IS::Dataset &T, IS::Solution &best) const { std::cout << ">>>> Running Tabu" << std::endl; std::cout << "quality = " << max_quality << std::endl; std::cout << "ite_limit = " << ite_limit << std::endl; std::cout << "no_change_best = " << no_change_best << std::endl; std::cout << "Number of Tweaks = " << number_of_tweaks << std::endl; std::cout << "Length of the list = " << length << std::endl; std::cout << ">>>>>>>>>>>>>>>>>>>>" << std::endl; IS::Solution S(best); int max_length = (length * T.size() / 100); std::deque<IS::Solution> tl; // Tabu list tl.push_back(S); double q_max, q_BEST = -1; int no_change = 0, iter = 0; while (1) { iter++; while (tl.size() > max_length) tl.pop_front(); IS::Solution R(S); tweaker->tweak(R); for (int i = 0; i < number_of_tweaks - 1; i++) { IS::Solution W(S); tweaker->tweak(W); // if W is not int tabu list if (std::find(tl.begin(), tl.end(), W) == tl.end()) { double qw = quality(T, W, 0.5), qr = quality(T, R, 0.5); if (qw > qr || std::find(tl.begin(), tl.end(), R) != tl.end()) R.copy(W); } } // R is not in L and r is better bool R_is_better = quality(T, R, 0.5) > quality(T, S, 0.5); if (std::find(tl.begin(), tl.end(), R) == tl.end() and R_is_better) { S.copy(R); tl.push_back(R); } double qs = quality(T, S, 0.5), qb = quality(T, best, 0.5); q_max = std::max(qs, qb); if (qs > qb) best.copy(S); // TODO: Tune iter_total and no_change if (q_max > q_BEST) { q_BEST = q_max; no_change = 0; } else no_change++; bool stop = q_max > max_quality || no_change == no_change_best; stop = stop || iter == ite_limit; if (stop) break; } }
/** * Fitness function. * @param 'T' : Dataset * @param 'S' : Solution * @param 'alpha' : double * * This function calculates: * alpha * (instances_well_clasified) + (1 - alpha) * (percentage_of_reduction) * * @return Fitness of S. */ double Metaheuristic::quality(const IS::Dataset &T, const IS::Solution &S, double alpha) const { std::bitset<MAX> bits = S.getBits(); if (bits.count() == 0) return 0.5; IS::Dataset training, result; std::vector<double> category; int j = 0; for (int i = 0; i < T.size(); i++) { if (bits.test(i)) training.push_back(T[i]); else result.push_back(T[i]); } category.assign(result.size(), -1); oneNN(training, result, category); int count = 0; for (int i = 0; i < result.size(); i++) if (result[i].getCategory() == category[i]) count++; double clas_rate = (1.0 * count) / (1.0 * result.size()); double perc_redc = (1.0 * result.size()) / (1.0 * T.size()); double fitness = alpha * clas_rate + (1 - alpha) * perc_redc; // // XXX: Print cout << "Hubo un total de " << count << " aciertos" << endl; cout << "Result es de tamanio: " << result.size() << endl; cout << "La relación es: " << clas_rate << endl; cout << "El tamaño de T es: " << T.size() << endl; cout << "El tamaño de training es: " << training.size() << endl; cout << "El porcentaje de reducción es: " << perc_redc << endl; cout << "El fitness es : " << fitness << endl << endl; assert(fitness <= 1.0); return fitness; }