diff --git a/HRT/8_YESBIN_3STA_NOMERGED/AgentIterator.cpp b/HRT/8_YESBIN_3STA_NOMERGED/AgentIterator.cpp new file mode 100644 index 0000000..934d411 --- /dev/null +++ b/HRT/8_YESBIN_3STA_NOMERGED/AgentIterator.cpp @@ -0,0 +1,850 @@ +#include "AgentIterator.h" +#include "Allocation.h" + +template +AgentIteratorBase::AgentIteratorBase(const t_these& agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group, int posn) : + _agent(agent), + _these(these), _other(other), + _positions(positions), _candidates(candidates) { + if (_agent.preferences.size() == 0) { + _group = -1; + } else { + _group = group; + } + _position = posn; +} + +template +AgentIteratorBase::~AgentIteratorBase() { } + +template +int AgentIteratorBase::get_group() const { + return _group; +} + +template +int AgentIteratorBase::get_position() const { + return _position; +} + +template +const t_these & AgentIteratorBase::get_agent() const { + return _agent; +} + +template +const std::vector & AgentIteratorBase::get_these() const { + return _these; +} + +template +const std::vector & AgentIteratorBase::get_other() const { + return _other; +} + +template +const std::set & AgentIteratorBase::get_positions() const { + return _positions; +} + +template +const std::set & AgentIteratorBase::get_candidates() const { + return _candidates; +} + +template <> +void AgentIteratorBase::regularIncrement() { + _group++; + if ((int)_agent.preferences.size() == _group) { + _group = -1; + } +} + +template +void AgentIteratorBase::regularIncrement() { + _position++; + if ((int)_agent.preferences[_group].size() == _position) { + _position = 0; + _group++; + if ((int)_agent.preferences.size() == _group) { + _group = -1; + } + } +} + +template +bool AgentIterator::operator==(const AgentIterator & other) { + return get_group() == other.get_group() && get_position() == other.get_position(); +} + +template +bool AgentIterator::operator!=(const AgentIterator & other) { + return ! (*this == other); +} + +template +const std::pair AgentIterator::operator*() { + return std::pair(get_group(), get_position()); +} + +template +AgentIterator AgentIterator::begin() { + AgentIterator starter(this, 0, 0); + starter.base->begin(); + return starter; +} + +template +AgentIterator AgentIterator::end() { + return AgentIterator(this, -1, 0); +} + +template +AgentIterator::AgentIterator(const t_these & agent, const std::set & candidates, const std::set & positions, + const std::vector & these, const std::vector & other, int mode) : + _mode(mode) { + switch (_mode) { + default: + case 0: + base = new DescendingIterator(agent, candidates, positions, these, other, 0, 0); + break; + case 1: + base = new SkipBigIterator(agent, candidates, positions, these, other, 5, 0, 0); + break; + case 2: + base = new BestIterator(agent, candidates, positions, these, other, 0, 0); + break; + case 3: + base = new SkipBigIterator(agent, candidates, positions, these, other, 15, 0, 0); + break; + case 4: + base = new SkipBigIterator(agent, candidates, positions, these, other, 50, 0, 0); + break; + case 5: + base = new BestGroupIterator(agent, candidates, positions, these, other, 0, 0); + break; + } + } + +template +AgentIterator::AgentIterator(AgentIterator *other) : + _mode(other->get_mode()) { + switch (_mode) { + default: + case 0: + base = new DescendingIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), other->get_group(), other->get_position()); + break; + case 1: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 5, other->get_group(), other->get_position()); + break; + case 2: + base = new BestIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), other->get_group(), other->get_position()); + break; + case 3: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 15, other->get_group(), other->get_position()); + break; + case 4: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 50, other->get_group(), other->get_position()); + break; + case 5: + base = new BestGroupIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), other->get_group(), other->get_position()); + break; + } + } + +template +AgentIterator::AgentIterator(AgentIterator *other, int group, int posn) : + _mode(other->get_mode()) { + switch (_mode) { + case 0: + base = new DescendingIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), group, posn); + break; + case 1: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 5, group, posn); + break; + case 2: + base = new BestIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), group, posn); + break; + case 3: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 15, group, posn); + break; + case 4: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 50, group, posn); + break; + case 5: + base = new BestGroupIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), group, posn); + break; + } + } + +template +AgentIterator::~AgentIterator() { + delete base; +} + +template +int AgentIterator::get_group() const { + return base->get_group(); +} + +template +int AgentIterator::get_position() const { + return base->get_position(); +} + +template +int AgentIterator::get_mode() const { + return _mode; +} + +template +DescendingIterator::DescendingIterator(const t_these & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group, int posn) : + AgentIteratorBase(agent, candidates, positions, these, other, group, posn) { + } + +template +void DescendingIterator::begin() { +} + +template +void DescendingIterator::increment() { + this->regularIncrement(); +} + +template +SkipBigIterator::SkipBigIterator(const t_these& agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int skip, int group, int posn) : + AgentIteratorBase(agent, candidates, positions, these, other, group, posn) , _skip(skip) { + } + +template <> +void SkipBigIterator::begin() { + int num_added = 0; + while (true) { + if (this->get_group() == -1) { + break; + } + num_added = 0; + int other_id = this->_agent.preferences[this->_group]; + bool break_yet = false; + for(auto & group: this->_other[other_id-1].preferences) { + for(auto pref: group) { + if (this->_candidates.count(pref) == 0) { + num_added++; + } + if (pref == this->_agent.id) { + break_yet = true; + } + } + if (break_yet) { + break; + } + } + if (num_added > _skip) { + this->regularIncrement(); + } else { + break; + } + } +} + +template <> +void SkipBigIterator::begin() { + int num_added = 0; + while (true) { + if (this->get_group() == -1) { + break; + } + num_added = 0; + int other_id = this->_agent.preferences[this->_group][this->_position]; + for(auto pref: this->_other[other_id-1].preferences) { + if (this->_candidates.count(pref) == 0) { + num_added++; + } + if (pref == this->_agent.id) { + break; + } + } + if (num_added > _skip) { + this->regularIncrement(); + } else { + break; + } + } +} + +template +void SkipBigIterator::begin() { + int num_added = 0; + while (true) { + if (this->get_group() == -1) { + break; + } + num_added = 0; + int other_id = this->_agent.preferences[this->_group][this->_position]; + int other_rank = this->_agent.ranks[this->_group][this->_position]; + bool break_yet = false; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto pref: this->_other[other_id-1].preferences[group_ind]) { + if (this->_candidates.count(pref) == 0) { + num_added++; + } + if (pref == this->_agent.id) { + break_yet = true; + } + } + if (break_yet) { + break; + } + } + if (num_added > _skip) { + this->regularIncrement(); + } else { + break; + } + } +} + +template <> +void SkipBigIterator::increment() { + int num_added = 0; + do { + this->regularIncrement(); + if (this->get_group() == -1) { + break; + } + num_added = 0; + int other_id = this->_agent.preferences[this->_group][this->_position]; + for(auto pref: _other[other_id-1].preferences) { + if (this->_candidates.count(pref) == 0) { + num_added++; + } + if (pref == this->_agent.id) { + break; + } + } + } while (num_added > _skip); +} + +template<> +void SkipBigIterator::increment() { + int num_added = 0; + do { + this->regularIncrement(); + if (this->get_group() == -1) { + break; + } + num_added = 0; + int other_id = this->_agent.preferences[this->_group]; + bool break_yet = false; + for(auto & group: _other[other_id-1].preferences) { + for(auto pref: group) { + if (this->_candidates.count(pref) == 0) { + num_added++; + } + if (pref == _agent.id) { + break_yet = true; + } + } + if (break_yet) { + break; + } + } + } while (num_added > _skip); +} + +template +void SkipBigIterator::increment() { + int num_added = 0; + do { + this->regularIncrement(); + if (this->get_group() == -1) { + break; + } + num_added = 0; + int other_id = this->_agent.preferences[this->_group][this->_position]; + int other_rank = this->_agent.ranks[this->_group][this->_position]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto pref: this->_other[other_id-1].preferences[group_ind]) { + if (this->_candidates.count(pref) == 0) { + num_added++; + } + } + } + } while (num_added > _skip); +} + +template +BestIterator::BestIterator(const t_these & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group, int posn) : + AgentIteratorBase(agent, candidates, positions, these, other, group, posn) { + } + +template <> +void BestIterator::increment() { + int lowest_added = -1; + int best_group = -1; + int best_posn = -1; + for(size_t group_no = 0; group_no < this->_agent.preferences.size(); ++group_no) { + auto & group = this->_agent.preferences[group_no]; + for(size_t posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (this->_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + for(auto other_pref: this->_other[other_id-1].preferences) { + if (this->_candidates.count(other_pref) == 0) { + num_added++; + } + if (other_pref == this->_agent.id) { + break; + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_group = group_no; + best_posn = posn; + } + } + } + if (lowest_added != -1) { + this->_group = best_group; + this->_position = best_posn; + } else { + this->_group = -1; + this->_position = 0; + } +} + +template <> +void BestIterator::increment() { + int lowest_added = -1; + int best_group = -1; + int best_posn = -1; + for(size_t posn = 0; posn < this->_agent.preferences.size(); ++posn) { + int other_id = this->_agent.preferences[posn]; + if (this->_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + bool break_yet = false; + for(auto & group: this->_other[other_id-1].preferences) { + for(auto other_pref: group) { + if (this->_candidates.count(other_pref) == 0) { + num_added++; + } + if (other_pref == this->_agent.id) { + break_yet = true; + } + if (break_yet) { + break; + } + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_group = posn; + best_posn = 0; + } + } + if (lowest_added != -1) { + this->_group = best_group; + this->_position = best_posn; + } else { + this->_group = -1; + this->_position = 0; + } +} + +template +void BestIterator::increment() { + int lowest_added = -1; + int best_group = -1; + int best_posn = -1; + for(int group_no = 0; group_no < this->_agent.preferences.size(); ++group_no) { + auto & group = this->_agent.preferences[group_no]; + for(int posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (this->_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + int other_rank = this->_agent.ranks[group_no][posn]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto other_pref: this->_other[other_id-1].preferences[group_ind]) { + if (this->_candidates.count(other_pref) == 0) { + num_added++; + } + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_group = group_no; + best_posn = posn; + } + } + } + if (lowest_added != -1) { + this->_group = best_group; + this->_position = best_posn; + } else { + this->_group = -1; + this->_position = 0; + } +} + +template <> +void BestIterator::begin() { + int lowest_added = -1; + int best_group = -1; + int best_posn = -1; + for(size_t group_no = 0; group_no < this->_agent.preferences.size(); ++group_no) { + auto & group = this->_agent.preferences; + for(size_t posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (this->_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + bool break_yet = false; + for(size_t group_ind = 0; group_ind < this->_other[other_id-1].preferences.size(); group_ind++) { + for(auto other_pref: this->_other[other_id-1].preferences[group_ind]) { + if (this->_candidates.count(other_pref) == 0) { + num_added++; + } + if (other_pref == this->_agent.id) { + break_yet = true; + } + } + if (break_yet) { + break; + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_group = group_no; + best_posn = posn; + } + } + } + if (lowest_added != -1) { + this->_group = best_group; + this->_position = best_posn; + } else { + this->_group = -1; + this->_position = 0; + } +} + +template <> +void BestIterator::begin() { + int lowest_added = -1; + int best_group = -1; + int best_posn = -1; + for(size_t group_no = 0; group_no < this->_agent.preferences.size(); ++group_no) { + auto & group = this->_agent.preferences[group_no]; + for(size_t posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (this->_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + for(auto other_pref: this->_other[other_id-1].preferences) { + if (this->_candidates.count(other_pref) == 0) { + num_added++; + } + if (other_pref == other_id) { + break; + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_group = group_no; + best_posn = posn; + } + } + } + if (lowest_added != -1) { + this->_group = best_group; + this->_position = best_posn; + } else { + this->_group = -1; + this->_position = 0; + } +} + +template +void BestIterator::begin() { + int lowest_added = -1; + int best_group = -1; + int best_posn = -1; + for(size_t group_no = 0; group_no < this->_agent.preferences.size(); ++group_no) { + auto & group = this->_agent.preferences[group_no]; + for(size_t posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (this->_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + int other_rank = this->_agent.ranks[group_no][posn]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto other_pref: this->_other[other_id-1].preferences[group_ind]) { + if (this->_candidates.count(other_pref) == 0) { + num_added++; + } + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_group = group_no; + best_posn = posn; + } + } + } + if (lowest_added != -1) { + this->_group = best_group; + this->_position = best_posn; + } else { + this->_group = -1; + this->_position = 0; + } +} + +template +BestGroupIterator::BestGroupIterator(const t_these & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group, int posn) : + AgentIteratorBase(agent, candidates, positions, these, other, group, posn) { + } + +template <> +void BestGroupIterator::increment() { + this->_position = 0; + this->_group++; + if (this->_group == (int)this->_agent.preferences.size()) { + this->_position = 0; + this->_group = -1; + } +} + +template<> +void BestGroupIterator::increment() { + int lowest_added = -1; + int best_posn = -1; + const std::vector & group = this->_agent.preferences[this->_group]; + for(size_t posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (this->_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + for(auto other_pref: this->_other[other_id-1].preferences) { + if (this->_candidates.count(other_pref) == 0) { + num_added++; + } + if (other_pref == this->_agent.id) { + break; + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_posn = posn; + } + } + if (lowest_added != -1) { + this->_position = best_posn; + } else { + this->_group++; + if (this->_group == (int)this->_agent.preferences.size()) { + this->_position = 0; + this->_group = -1; + } else { + increment(); + } + } +} + +template +void BestGroupIterator::increment() { + int lowest_added = -1; + int best_posn = -1; + auto & group = this->_agent.preferences[this->_group]; + for(int posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (this->_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + int other_rank = this->_agent.ranks[this->_group][posn]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto other_pref: this->_other[other_id-1].preferences[group_ind]) { + if (this->_candidates.count(other_pref) == 0) { + num_added++; + } + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_posn = posn; + } + } + if (lowest_added != -1) { + this->_position = best_posn; + } else { + this->_group++; + if (this->_group == this->_agent.preferences.size()) { + this->_position = 0; + this->_group = -1; + } else { + increment(); + } + } +} + +template <> +void BestGroupIterator::begin() { + int lowest_added = -1; + int best_posn = -1; + if (this->_group == -1) { + return; + } + auto & group = this->_agent.preferences[this->_group]; + for(size_t posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (this->_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + for(auto other_pref: this->_other[other_id-1].preferences) { + if (this->_candidates.count(other_pref) == 0) { + num_added++; + } + if (other_pref == this->_agent.id) { + break; + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_posn = posn; + } + } + if (lowest_added != -1) { + this->_position = best_posn; + } else { + this->_group++; + if (this->_group == (int)this->_agent.preferences.size()) { + this->_position = 0; + this->_group = -1; + } else { + increment(); + } + } +} + +template <> +void BestGroupIterator::begin() { + int lowest_added = -1; + int best_posn = -1; + if (this->_group == -1) { + return; + } + for(size_t posn = 0; posn < this->_agent.preferences.size(); ++posn) { + int other_id = this->_agent.preferences[posn]; + if (this->_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + bool break_yet = false; + for(size_t group_ind = 0; group_ind < this->_other[other_id-1].preferences.size(); group_ind++) { + for(auto other_pref: this->_other[other_id-1].preferences[group_ind]) { + if (this->_candidates.count(other_pref) == 0) { + num_added++; + } + if (other_pref == this->_agent.id) { + break_yet = true; + } + } + if (break_yet) { + break; + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_posn = posn; + } + } + if (lowest_added != -1) { + this->_position = best_posn; + } else { + this->_group++; + if (this->_group == (int)this->_agent.preferences.size()) { + this->_position = 0; + this->_group = -1; + } else { + increment(); + } + } +} + +template +void BestGroupIterator::begin() { + int lowest_added = -1; + int best_posn = -1; + if (this->_group == -1) { + return; + } + auto & group = this->_agent.preferences[this->_group]; + for(size_t posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (this->_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + int other_rank = this->_agent.ranks[this->_group][posn]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto other_pref: this->_other[other_id-1].preferences[group_ind]) { + if (this->_candidates.count(other_pref) == 0) { + num_added++; + } + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_posn = posn; + } + } + if (lowest_added != -1) { + this->_position = best_posn; + } else { + this->_group++; + if (this->_group == this->_agent.preferences.size()) { + this->_position = 0; + this->_group = -1; + } else { + increment(); + } + } +} + +template class AgentIterator; +template class AgentIterator; + diff --git a/HRT/8_YESBIN_3STA_NOMERGED/AgentIterator.h b/HRT/8_YESBIN_3STA_NOMERGED/AgentIterator.h new file mode 100644 index 0000000..85c4a16 --- /dev/null +++ b/HRT/8_YESBIN_3STA_NOMERGED/AgentIterator.h @@ -0,0 +1,116 @@ +#ifndef AGENTITERATOR_H +#define AGENTITERATOR_H + +#include + +#include "Allocation.h" + +template +class AgentIteratorBase { +public: + AgentIteratorBase(const t_these & agent, const std::set & candidates, const std::set & positions, + const std::vector & these, const std::vector & other, int group=0, int posn=0); + virtual ~AgentIteratorBase() = 0; + virtual void increment() = 0; + virtual void begin() = 0; + + int get_position() const; + int get_group() const; + const t_these & get_agent() const; + const std::vector & get_these() const; + const std::vector & get_other() const; + const std::set & get_positions() const; + const std::set & get_candidates() const; +protected: + void regularIncrement(); + + const t_these & _agent; + int _group; + int _position; + const std::vector & _these; + const std::vector & _other; + const std::set & _positions; + const std::set & _candidates; +}; + + +template +class AgentIterator : public std::iterator, ptrdiff_t> { +public: + AgentIterator(const t_these & agent, const std::set & candidates, const std::set & positions, + const std::vector & these, const std::vector & other, int mode); + AgentIterator(AgentIterator *other, int group, int posn); + AgentIterator(AgentIterator *other); + ~AgentIterator(); + bool operator==(const AgentIterator& other); + bool operator!=(const AgentIterator& other); + const std::pair operator*(); + AgentIterator& operator++() {base->increment(); return *this; } + AgentIterator operator++(int) {AgentIterator res(this); base->increment(); return res; } + + AgentIterator begin(); + AgentIterator end(); + + int get_position() const; + int get_group() const; + int get_mode() const; + + const t_these & get_agent() const { return base->get_agent(); } + const std::vector & get_these() const {return base->get_these(); } + const std::vector & get_other() const {return base->get_other(); } + const std::set & get_positions() const {return base->get_positions(); } + const std::set & get_candidates() const {return base->get_candidates(); } +private: + AgentIteratorBase * base; + int _mode; +}; + + +template +class DescendingIterator : public AgentIteratorBase { + public: + DescendingIterator(const t_these & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group=0, int posn=0); + ~DescendingIterator() {} + void increment(); + void begin(); +}; + + +template +class SkipBigIterator : public AgentIteratorBase { + public: + SkipBigIterator(const t_these & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int skip, int group, int posn); + ~SkipBigIterator() {} + void increment(); + void begin(); + private: + int _skip; +}; + +template +class BestIterator : public AgentIteratorBase { + public: + BestIterator(const t_these & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group=0, int posn=0); + ~BestIterator() {} + void increment(); + void begin(); +}; + +template +class BestGroupIterator : public AgentIteratorBase { + public: + BestGroupIterator(const t_these & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group=0, int posn=0); + ~BestGroupIterator() {} + void increment(); + void begin(); +}; + +#endif /* AGENTITERATOR_H */ diff --git a/HRT/8_YESBIN_3STA_NOMERGED/Allocation.cpp b/HRT/8_YESBIN_3STA_NOMERGED/Allocation.cpp index 1705993..4901d58 100644 --- a/HRT/8_YESBIN_3STA_NOMERGED/Allocation.cpp +++ b/HRT/8_YESBIN_3STA_NOMERGED/Allocation.cpp @@ -1,4 +1,9 @@ +#include + #include "Allocation.h" +#include "AgentIterator.h" +#include "Graph.h" +#include "time.h" /* ************************************************************************************* *********************************** DOCTOR ***************************************** @@ -18,7 +23,7 @@ void Hospital::print(){ cout << "Hospital " << id << "\t Capacity " << cap << "\t Preferences (" << nbPref << " groups, " << nbTotPref << " in total)\t"; for(int i=0; i 0) cout << " "; cout << preferences[i][j]; } @@ -169,11 +174,11 @@ int Allocation::reductionHosOff(){ hbm = false; for(int j=0; j candidates; + set positions; + int worst_rank = 0; + unsigned int count = 0; + AgentIterator iter(doctors[i], candidates, positions, doctors, hospitals, mode); + for(std::pair p: iter) { + int j = p.first; + if (j > worst_rank) { + worst_rank = j; + } + int idxHos = doctors[i].preferences[j] - 1; + positions.insert(idxHos+1); + count += hospitals[idxHos].cap; + for (auto & group: hospitals[idxHos].preferences) { + bool break_yet = false; + for(int pref: group) { + candidates.insert(pref); + if (pref == doctors[i].id) { + break_yet = true; + } + } + if (break_yet) { + break; + } + } + if (count >= candidates.size()) { +#ifdef DEBUG + std::cout << "doctor worst rank of " << doctors[i].id << " is " << worst_rank << std::endl; + int remHere = 0; +#endif /* DEBUG */ + for (int k = worst_rank + 1; k < doctors[i].nbPref; k++) { + nbTotRem += 1; +#ifdef DEBUG + remHere += 1; +#endif /* DEBUG */ + int idxHos = doctors[i].preferences[k] - 1; + for(size_t rank = 0; rank < hospitals[idxHos].preferences.size(); ++rank) { + auto posDoc = std::find(hospitals[idxHos].preferences[rank].begin(), hospitals[idxHos].preferences[rank].end(), i+1); + if (posDoc != hospitals[idxHos].preferences[rank].end()) { + hospitals[idxHos].preferences[rank].erase(posDoc); + hospitals[idxHos].nbTotPref--; + } + } + } +#ifdef DEBUG + std::cout << "removed " << remHere << std::endl; +#endif /* DEBUG */ + doctors[i].nbPref = worst_rank + 1; + doctors[i].preferences.resize(doctors[i].nbPref); + break; + } + } + } + if (nbTotRem > 0) { + polish(); + } + return nbTotRem; +} + +int Allocation::reductionMineHospitals(int mode) { + int nbTotRem = 0; + + for (int i = 0; i < nbHospitals; i++) { + set candidates; + set positions; + unsigned int candidate_cap = 0; + int worst_rank = 0; + unsigned int count = 0; +#ifdef DEBUG + std::cout << "Preprocessing hospital " << i << std::endl; +#endif /* DEBUG */ + AgentIterator iter(hospitals[i], candidates, positions, hospitals, doctors, mode); + for(std::pair p: iter) { + int j = p.first; + int k = p.second; + if (j > worst_rank) { + worst_rank = j; + } + int idxDoc = hospitals[i].preferences[j][k] - 1; + positions.insert(idxDoc+1); + count += 1; + for (int pref: doctors[idxDoc].preferences) { + if (candidates.count(pref) == 0) { + candidates.insert(pref); + candidate_cap += hospitals[pref-1].cap; + } + if (pref == hospitals[i].id) { + break; + } + } + if (count >= candidate_cap) { +#ifdef DEBUG + std::cout << "hospital worst rank of " << i << " is " << worst_rank << std::endl; + int remHere = 0; +#endif /* DEBUG */ + for (int k = worst_rank + 1; k < hospitals[i].nbPref; k++) { + nbTotRem += hospitals[i].preferences[k].size(); +#ifdef DEBUG + remHere += hospitals[i].preferences[k].size(); +#endif /* DEBUG */ + hospitals[i].nbTotPref -= hospitals[i].preferences[k].size(); + for (unsigned int l = 0; l < hospitals[i].preferences[k].size(); l++) { + int idxDoc = hospitals[i].preferences[k][l] - 1; + for (size_t m = 0 ; m < doctors[idxDoc].preferences.size(); ++m) { + if (doctors[idxDoc].preferences[m] == i + 1) { + doctors[idxDoc].preferences.erase(doctors[idxDoc].preferences.begin() + m); + doctors[idxDoc].ranks.erase(doctors[idxDoc].ranks.begin() + m); + doctors[idxDoc].nbPref--; + break; + } + } + } + } + hospitals[i].nbPref = worst_rank + 1; + hospitals[i].preferences.resize(hospitals[i].nbPref); +#ifdef DEBUG + std::cout << "removed " << remHere << std::endl; +#endif /* DEBUG */ + break; + } + } + } + if (nbTotRem > 0) { + polish(); + } + return nbTotRem; +} + + int Allocation::reductionResApp(){ int nbTotRem = 0; @@ -234,13 +372,13 @@ int Allocation::reductionResApp(){ count += currentAssignmentByHospital[idxHos][k].size(); if(count >= hospitals[idxHos].cap){ for(int l = k+1; l MAXTIME) { + cout << "Time elapsed, breaking"; + return 0; + } + int position = doctors[i].preferences[rank] - 1; + auto pos_vert = std::make_pair(1, position); + g.addVertex(pos_vert, hospitals[position].cap); + bool break_yet = false; + for(size_t k = 0; k < hospitals[position].preferences.size(); ++k) { + for(size_t l = 0; l < hospitals[position].preferences[k].size(); ++l) { + int doctor_cand = hospitals[position].preferences[k][l] - 1; + if (doctor_cand == i) { // Don't add the current candidate to the graph + // Don't add doctors after this rank. + break_yet = true; + continue; + } + std::pair doctor_cand_vert = std::make_pair(0, doctor_cand); + if (! g.containsVertex(doctor_cand_vert)) { + g.addVertex(doctor_cand_vert, 1); + } + g.addEdge(pos_vert, doctor_cand_vert); + } + if (break_yet) { + break; + } + } + // max_flow is <= min(g.cap_left(), g.cap_right()), so we can do simple + // checks which might mean we can not bother trying to augment + bool can_def_preprocess = 1 + 2*g.cap_left() <= g.cap_total(); + if (1 + g.cap_left() + g.cap_right() <= g.cap_total()) { + can_def_preprocess = true; + } + if (!can_def_preprocess) { + while (g.augment()) { + // Empty loop on purpose, we keep augmenting while we can keep + // augmenting. + } + } + if (can_def_preprocess || g.can_preprocess()) { + // preprocess on rank! + // Firstly, they must be allocated, so mark as such (if we're in that + // mode) + if (supp && !doctors[i].mustBeAllocated) { + doctorsMustBeAllocated.push_back(i); + doctors[i].mustBeAllocated = true; + newMustBeAllocated = true; + } +#ifdef DEBUG + if (i == 6) { + //std::cout << "g.size() = " << g.size() << ", g.matchingSize() = " << g.matchingSize(); + //std::cout << ", n_1 = " << n_1 << std::endl; + //g.printGraph(); + //g.printMatching(); + } + std::cout << "doctor worst rank of " << i << " is " << rank << " "; + int remHere = 0; +#endif /* DEBUG */ + for (int k = rank + 1; k < doctors[i].nbPref; k++) { + nbTotRem += 1; +#ifdef DEBUG + remHere += 1; +#endif /* DEBUG */ + int idxHos = doctors[i].preferences[k] - 1; + // remove from idxHos any reference to i. + for(size_t rank = 0 ; rank < hospitals[idxHos].preferences.size(); ++rank) { + auto posDoc = std::find(hospitals[idxHos].preferences[rank].begin(), hospitals[idxHos].preferences[rank].end(), i + 1); + if (posDoc != hospitals[idxHos].preferences[rank].end()) { + hospitals[idxHos].preferences[rank].erase(posDoc); + } + } + } + doctors[i].nbPref = rank + 1; + doctors[i].preferences.resize(doctors[i].nbPref); +#ifdef DEBUG + std::cout << "removed " << remHere << std::endl; +#endif /* DEBUG */ + break; + } + } + } + if (nbTotRem > 0) { + polish(); + } + if ((nbTotRem == 0) && (newMustBeAllocated == true)) { + return -1; + } + return nbTotRem; +} + +/** + * Reduce on the hospital's preference lists, removing doctors. + */ +int Allocation::reductionExactHospital(bool supp) { + bool newMustBeAllocated = false; + int nbTotRem = 0; + for (size_t i = 0; i < (size_t)nbHospitals; i++) { + Graph g(hospitals[i].cap); + // First add all positions that must be filled. + for(int position: doctorsMustBeAllocated) { + // If position is acceptable to i, then skip it. + bool isAcceptable = false; + for(size_t ind = 0; ind < doctors[position].preferences.size(); ++ind) { + if ((doctors[position].preferences[ind] - 1) == (int)i) { + isAcceptable = true; + break; + } + } + if (isAcceptable) { + continue; + } + auto pos_vert = std::make_pair(1, position); + g.addVertex(pos_vert, 1); + for(size_t ind = 0; ind < doctors[position].preferences.size(); ++ind) { + int candidate = doctors[position].preferences[ind] - 1; + auto cand_vert = std::make_pair(0, candidate); + if (!g.containsVertex(cand_vert)) { + g.addVertex(cand_vert, hospitals[candidate].cap); + } + g.addEdge(pos_vert, cand_vert); + } + while (g.augment()) { } // Empty loop to keep augmenting while we can + } + for(size_t rank = 0; rank < hospitals[i].preferences.size(); rank++) { + // No point in checking the last rank if we already know this agent must + // be allocated, or if we don't care + if ((rank == hospitals[i].preferences.size()- 1) && (hospitals[i].mustBeAllocated || !supp)) { + continue; + } + if ((getCPUTime() - initTimePP) > MAXTIME) { + cout << "Time elapsed, breaking"; + return 0; + } + for(size_t ind = 0; ind < hospitals[i].preferences[rank].size(); ind++) { + int position = hospitals[i].preferences[rank][ind] - 1; + auto pos_vert = std::make_pair(1, position); + g.addVertex(pos_vert, 1); + for(size_t k = 0; k < doctors[position].preferences.size(); k++) { + int hosp_cand = doctors[position].preferences[k] - 1; + if (hosp_cand == (int)i) { // Don't add the current candidate to the graph + break; + } + std::pair hosp_cand_vert = std::make_pair(0, hosp_cand); + if (! g.containsVertex(hosp_cand_vert)) { + g.addVertex(hosp_cand_vert, hospitals[hosp_cand].cap); + } + g.addEdge(pos_vert, hosp_cand_vert); + } + } + // max_flow is <= min(g.cap_left(), g.cap_right()), so we can do simple + // checks which might mean we can not bother trying to augment + bool can_def_preprocess = hospitals[i].cap + 2*g.cap_left() <= g.cap_total(); + if (hospitals[i].cap + g.cap_left() + g.cap_right() <= g.cap_total()) { + can_def_preprocess = true; + } + if (!can_def_preprocess) { + while (g.augment()) { + // Empty loop on purpose, we keep augmenting while we can keep + // augmenting. + } + } + if (can_def_preprocess || g.can_preprocess()) { + // preprocess on rank! + // Firstly, they must be allocated, so mark as such (if we're in that + // mode) + if (supp && !hospitals[i].mustBeAllocated) { + hospitalsMustBeAllocated.push_back(i); + hospitals[i].mustBeAllocated = true; + newMustBeAllocated = true; + } +#ifdef DEBUG + if (i == 0) { + //std::cout << "g.cap_original() = " << hospitals[i].cap << ", g.cap_left() = " << g.cap_left(); + //std::cout << ", cap_total = " << g.cap_total() << ", g.maxFlow() = " << g.maxFlow() << std::endl; + //g.printGraph(); + //g.printMatching(); + } + std::cout << "hospital worst rank of " << i << " is " << rank << " "; + int remHere = 0; +#endif /* DEBUG */ + for (int k = rank + 1; k < hospitals[i].nbPref; k++) { + nbTotRem += hospitals[i].preferences[k].size(); +#ifdef DEBUG + remHere += hospitals[i].preferences[k].size(); +#endif /* DEBUG */ + hospitals[i].nbTotPref -= hospitals[i].preferences[k].size(); + for (unsigned int l = 0; l < hospitals[i].preferences[k].size(); l++) { + int idxDoc = hospitals[i].preferences[k][l] - 1; + for(size_t n=0; n < doctors[idxDoc].preferences.size();n++){ + if(doctors[idxDoc].preferences[n]-1 == (int)i){ + doctors[idxDoc].preferences.erase(doctors[idxDoc].preferences.begin() + n); + doctors[idxDoc].ranks.erase(doctors[idxDoc].ranks.begin() + n); + doctors[idxDoc].nbPref--; + } + } + } + } + hospitals[i].nbPref = rank + 1; + hospitals[i].preferences.resize(hospitals[i].nbPref); +#ifdef DEBUG + std::cout << "removed " << remHere << std::endl; +#endif /* DEBUG */ + break; + } + } + } + if (nbTotRem > 0) { + polish(); + } + if ((nbTotRem == 0) && (newMustBeAllocated == true)) { + return -1; + } + return nbTotRem; +} + void Allocation::polish(){ // Remove unused groups for(int j=0; j MAXTIME) { + cout << "Time elapsed, breaking"; + break; + } + }while(keep_going || this_time != 0); + } polish(); } @@ -307,7 +794,7 @@ void Allocation::printSol(){ cout << "Allocation by hospitals" << endl; for(int i=0; i 1){ cout << "Allocation error: doctor " << assignmentByHospital[i][j] << " is allocated " << doctorAllocated[assignmentByHospital[i][j] - 1] << " times " << endl; diff --git a/HRT/8_YESBIN_3STA_NOMERGED/Allocation.h b/HRT/8_YESBIN_3STA_NOMERGED/Allocation.h index 581cf1c..34cdf44 100644 --- a/HRT/8_YESBIN_3STA_NOMERGED/Allocation.h +++ b/HRT/8_YESBIN_3STA_NOMERGED/Allocation.h @@ -4,6 +4,7 @@ using namespace std; #include #include +#include #include #include #include @@ -24,8 +25,11 @@ int nbPref; vector preferences; vector ranks; + bool mustBeAllocated; void print(); + + Doctor() : mustBeAllocated(false) { } }; /* ************************************************************************************* @@ -38,9 +42,12 @@ int cap; int nbPref; int nbTotPref; + bool mustBeAllocated; vector > preferences; - + void print(); + + Hospital() : mustBeAllocated(false) { } }; /* ************************************************************************************* @@ -74,9 +81,17 @@ int nbDoctors; int nbHospitals; + + int total_removed; + int pp_mode; + double initTimePP; + vector doctors; vector hospitals; + std::list doctorsMustBeAllocated; + std::list hospitalsMustBeAllocated; + // Given by the ILP model vector assignmentByDoctor; vector > assignmentByHospital; @@ -87,11 +102,16 @@ int reductionHosOff(); int reductionResApp(); void polish(); - void reduction(); + void reduction(int mode); + int reductionMineDoctors(int mode); + int reductionMineHospitals(int mode); + int reductionExactHospital(bool supp); + int reductionExactDoctor(bool supp); void printSol(); void printInfo(const string& pathAndFileout); void checkSolution(); }; -#endif \ No newline at end of file +#endif + diff --git a/HRT/8_YESBIN_3STA_NOMERGED/Graph.cpp b/HRT/8_YESBIN_3STA_NOMERGED/Graph.cpp new file mode 100644 index 0000000..bb95fe5 --- /dev/null +++ b/HRT/8_YESBIN_3STA_NOMERGED/Graph.cpp @@ -0,0 +1,223 @@ +#include +#include +#include "Graph.h" + + +Graph::Graph(int cap_original) : _cap_original(cap_original), _cap_total(0), + _left_total(0), max_flow(0) { +#ifdef DEBUG_GRAPH + std::cout << "New graph" << std::endl; +#endif /* DEBUG_GRAPH */ + this->addVertex(std::make_pair(2, 0), 1); // SOURCE + this->addVertex(std::make_pair(2, 1), 1); // SINK +} + +void Graph::addVertex(Vertex name, int capacity) { + int index = size(); + this->_names[name] = index; + this->_indices[index] = name; +#ifdef DEBUG_GRAPH + std::cout << "Add vertex " << name << " with cap " << capacity << std::endl; +#endif /* DEBUG_GRAPH */ + this->_adjacents[index] = std::map(); + if (name.first != 2) { + Edge e1, e2; + _cap_total += capacity; + if (name.first == 0) { // left side + e1.id = index; + e1.flow = 0; + e1.cap = capacity; + e1.reverse = false; + e2.id = Graph::SOURCE; + e2.flow = 0; + e2.cap = capacity; + e2.reverse = false; + _left_total += capacity; + } else if (name.first == 1) { // right side + e1.id = index; + e1.flow = 0; + e1.cap = capacity; + e1.reverse = false; + e2.id = Graph::SINK; + e2.flow = 0; + e2.cap = capacity; + e2.reverse = false; + } + this->_adjacents[e1.id][e2.id] = e2; + this->_adjacents[e2.id][e1.id] = e1; + } +} + +Vertex Graph::name(int vert_index) { + return this->_indices[vert_index]; +} + +bool Graph::containsVertex(Vertex name) const { + return _names.find(name) != _names.end(); +} + +/** + * Adds an edge to the graph. Note that this edge must always be added in the + * form (right, left) for things to work. + */ +void Graph::addEdge(Vertex v1, Vertex v2) { + int i1 = this->_names[v1]; + int i2 = this->_names[v2]; + Edge e1, e2; + e1.id = i1; + e1.cap = std::numeric_limits::max(); + e1.flow = 0; + e1.reverse = false; + e2.id = i2; + e2.cap = std::numeric_limits::max(); + e2.flow = 0; + e2.reverse = true; + _adjacents[i1][i2] = e2; + _adjacents[i2][i1] = e1; +} + +int Graph::size() const { + return _names.size(); +} + +int Graph::maxFlow() const { + return max_flow; +} + +bool Graph::can_preprocess() { + return _cap_original + cap_left() <= _cap_total - max_flow; +} + +int Graph::cap_left() const { + return _left_total; +} + +int Graph::cap_right() const { + return _cap_total - _left_total; +} + +int Graph::cap_total() const { + return _cap_total; +} + +/** + * Augment the flow. + */ +bool Graph::augment() { +#ifdef DEBUG_GRAPH + std::cout << "Augmenting" << std::endl; + this->printGraph(); +#endif /* DEBUG_GRAPH */ + std::list path; + std::vector visited(size(), false); + visited[Graph::SOURCE] = true; + path.push_back(Graph::SOURCE); + return internal_augment(Graph::SOURCE, visited, path); +} + +#ifdef DEBUG_GRAPH +void Graph::printGraph() { + for(auto & tuple : _adjacents) { + int ind = tuple.first; + std::cout << _indices[ind] << ":"; + for(auto & inner_tuple: tuple.second) { + const Edge & adj = inner_tuple.second; + std::cout << " " << _indices[adj.id] << "{" << adj.flow << "/" << adj.cap << "}"; + } + std::cout << std::endl; + } +} + +#endif /* DEBUG_GRAPH */ + +/** + * Continues an augmentation, on vertex now, which is on the right. + */ +bool Graph::internal_augment(int now, std::vector & visited, + std::list & path) { + for(auto & tuple: _adjacents[now]) { + Edge & next_edge = tuple.second; + if (visited[next_edge.id]) { + continue; + } + // Can't add any more flow to this edge. + if (next_edge.flow >= next_edge.cap) { + continue; + } + // If we're going "backwards" we need to use up (subtract) flow, so check we + // have some. Note that since we are checking backwards, the flow will also + // be negative + if (next_edge.reverse) { + if (next_edge.flow >= 0) { + continue; + } + } + //std::cout << "Considering " << _indices[next_edge.id] << " which has " << next_edge.flow << "/" << next_edge.cap << std::endl; + if (next_edge.id == Graph::SINK) { + // Found an augmenting flow. Modify flows used. +#ifdef DEBUG_GRAPH + std::cout << "New flow found." << std::endl; +#endif /* DEBUG_GRAPH */ + path.push_back(next_edge.id); + int start = Graph::SOURCE; + int total_flow = std::numeric_limits::max(); +#ifdef DEBUG_GRAPH + std::cout << "Path is "; +#endif /* DEBUG_GRAPH */ + for(auto p: path) { + if (p != Graph::SOURCE) { + int new_flow; + if (next_edge.reverse) { + new_flow = _adjacents[start][p].flow; + } else { + new_flow = _adjacents[start][p].cap - _adjacents[start][p].flow; + } + if (_adjacents[start][p].flow < 0 && _adjacents[start][p].cap == std::numeric_limits::max()) { + new_flow = std::numeric_limits::max(); + } + total_flow = std::min(total_flow, new_flow); + } +#ifdef DEBUG_GRAPH + if (p != Graph::SOURCE) { + int new_flow; + if (next_edge.reverse) { + new_flow = _adjacents[start][p].flow; + } else { + new_flow = _adjacents[start][p].cap - _adjacents[start][p].flow; + } + if (_adjacents[start][p].flow < 0 && _adjacents[start][p].cap == std::numeric_limits::max()) { + new_flow = std::numeric_limits::max(); + } + std::cout << "f" << new_flow; + } + std::cout << " " << _indices.at(p); +#endif /* DEBUG_GRAPH */ + start = p; + } +#ifdef DEBUG_GRAPH + std::cout << " with flow " << total_flow << std::endl; +#endif /* DEBUG_GRAPH */ + start = Graph::SOURCE; + while(!path.empty()) { + int next = path.front(); + path.pop_front(); + if (next == Graph::SOURCE) { + continue; + } + _adjacents[start][next].flow += total_flow; + _adjacents[next][start].flow -= total_flow; + start = next; + } + max_flow += total_flow; + return true; + } + path.push_back(next_edge.id); + visited[next_edge.id] = true; + if (internal_augment(next_edge.id, visited, path)) { + return true; + } + path.pop_back(); + } + return false; +} + diff --git a/HRT/8_YESBIN_3STA_NOMERGED/Graph.h b/HRT/8_YESBIN_3STA_NOMERGED/Graph.h new file mode 100644 index 0000000..cbba3cb --- /dev/null +++ b/HRT/8_YESBIN_3STA_NOMERGED/Graph.h @@ -0,0 +1,83 @@ +#ifndef GRAPH_H +#define GRAPH_H + +#include +#include +#include +#include +#include +#include +#include + + +static_assert(std::numeric_limits::max() >= ((long unsigned)1 << 63), "size_t is too small"); + +struct pairhash { + public: + std::size_t operator()(const std::pair &x) const { + return (long)x.first * ((long)1 << 32) + x.second; + } +}; + +#if defined(DEBUG_GRAPH) || defined(DEBUG) +#include +inline std::ostream& operator<<(std::ostream& o, const std::pair &x) { + o << "(" << x.first << ", " << x.second << ")"; + return o; +} +#endif /* DEBUG_GRAPH */ + +struct Edge { + int id; + int cap; + int flow; + bool reverse; +}; + +typedef std::pair Vertex; + +class Graph { + public: + Graph(int cap_right); + void addVertex(Vertex name, int capacity); + bool containsVertex(Vertex name) const; + void addEdge(Vertex v1, Vertex v2); + const std::list adjacent(Vertex vertex) const; + int matched(Vertex vertex) const; + bool augment(); + + bool can_preprocess(); + + int size() const; + int maxFlow() const; + + int cap_total() const; + int cap_left() const; + int cap_right() const; + + Vertex name(int vert_index); + + constexpr static int SOURCE = 0; + constexpr static int SINK = 1; + +#ifdef DEBUG_GRAPH + void printGraph(); +#endif /* DEBUG_GRAPH */ + + private: + int _cap_original; + int _cap_total; + int _left_total; + int max_flow; + std::unordered_map _names; + std::unordered_map _indices; + // Each adjacent is a triple containing (other_vertex, capacity, + // current_flow) + std::map> _adjacents; + + Edge & getEdge(int a, int b) { return _adjacents[a][b]; } + + bool internal_augment(int now, std::vector & visited, std::list & path); +}; + +#endif /* GRAPH_H */ diff --git a/HRT/8_YESBIN_3STA_NOMERGED/main.cpp b/HRT/8_YESBIN_3STA_NOMERGED/main.cpp index b5014fa..94041a5 100644 --- a/HRT/8_YESBIN_3STA_NOMERGED/main.cpp +++ b/HRT/8_YESBIN_3STA_NOMERGED/main.cpp @@ -8,28 +8,43 @@ int main(int argc, char **argv){ // local variables Allocation allo ; + allo.total_removed = 0; string filein = argv[2]; string path = argv[1]; string pathAndFileout = argv[3]; + int mode = atoi(argv[4]); // functions allo.load(path,filein); - allo.printProb(); - - manlove(allo); - - allo.printSol(); - allo.checkSolution(); - allo.printInfo(pathAndFileout); + //allo.printProb(); + allo.pp_mode = mode; + + if (manlove(allo, mode) >= 0) { + allo.printSol(); + allo.checkSolution(); + } + allo.printInfo(pathAndFileout); } -int manlove(Allocation& allo){ +int manlove(Allocation& allo, int mode){ double initTimeModelCPU = getCPUTime(); GRBEnv env = GRBEnv(); - allo.reduction(); - allo.printProb(); - allo.infos.timeCPUPP = getCPUTime() - initTimeModelCPU; + if (mode != 12) { + allo.reduction(mode); + } + allo.infos.timeCPUPP = getCPUTime() - initTimeModelCPU; + if (allo.infos.timeCPUPP > MAXTIME) { + cout << "Preprocessing took over " << MAXTIME << " seconds" << endl; + allo.infos.LB = 0; + allo.infos.timeCPU = MAXTIME; + allo.assignmentByDoctor.resize(allo.nbDoctors, -1); + allo.assignmentByHospital.resize(allo.nbHospitals); + for(int i = 0; i < allo.nbHospitals; ++i) { + allo.assignmentByHospital[i].resize(allo.hospitals[i].cap, -1); + } + return -1; + } // Model try{ @@ -141,7 +156,7 @@ int manlove(Allocation& allo){ } // Setting of Gurobi - model.getEnv().set(GRB_DoubleParam_TimeLimit, 3600 - (getCPUTime() - initTimeModelCPU)); + model.getEnv().set(GRB_DoubleParam_TimeLimit, MAXTIME - (getCPUTime() - initTimeModelCPU)); model.getEnv().set(GRB_IntParam_Threads, 1); model.getEnv().set(GRB_DoubleParam_MIPGap, 0); @@ -207,9 +222,9 @@ int manlove(Allocation& allo){ cout << "Error code = " << e.getErrorCode() << endl; cout << e.getMessage() << endl; } - catch (...) { - cout << "Exception during optimization" << endl; - } +// catch (...) { +// cout << "Exception during optimization" << endl; +// } // End diff --git a/HRT/8_YESBIN_3STA_NOMERGED/main.h b/HRT/8_YESBIN_3STA_NOMERGED/main.h index 56e7b5d..01d0055 100644 --- a/HRT/8_YESBIN_3STA_NOMERGED/main.h +++ b/HRT/8_YESBIN_3STA_NOMERGED/main.h @@ -11,6 +11,6 @@ float EPSILON = 0.001; - int manlove(Allocation& allo); + int manlove(Allocation& allo, int reduction_mode); #endif diff --git a/HRT/8_YESBIN_3STA_NOMERGED/makefile b/HRT/8_YESBIN_3STA_NOMERGED/makefile index 8540bcd..12ac583 100644 --- a/HRT/8_YESBIN_3STA_NOMERGED/makefile +++ b/HRT/8_YESBIN_3STA_NOMERGED/makefile @@ -8,15 +8,15 @@ CPPLIB = -L$(GUROBI_DIR)/lib/ -lgurobi_c++ $(CLIB) GUROBI_OPTS = -I$(INC) $(CPPLIB) -lpthread -lm -m64 CC = g++ -CFLAGS = -O2 -Wall -ansi -pedantic -DIL_STD +CFLAGS = -O2 -Wall -ansi -pedantic -DIL_STD -std=c++17 DEBUG = -pg -g -Wall -ansi -pedantic -DIL_STD -OBJECTS = main.o Allocation.o time.o +OBJECTS = main.o Allocation.o time.o Graph.o AgentIterator.o exec : $(OBJECTS) $(CC) $(CFLAGS) -o YESBIN_3STA_NOMERGED $(OBJECTS) $(GUROBI_OPTS) -.cpp.o : - $(CC) $(CFLAGS) $(GUROBI_OPTS) -c $< -o $@ +.cpp.o : $< Allocation.h Graph.h + $(CC) $(CFLAGS) $(GUROBI_OPTS) -c $< -o $@ clean : rm -f $(OBJECTS) YESBIN_3STA_NOMERGED \ No newline at end of file diff --git a/HRT/8_YESBIN_3STA_NOMERGED/time.h b/HRT/8_YESBIN_3STA_NOMERGED/time.h index 6f1cb4f..bbac2cd 100644 --- a/HRT/8_YESBIN_3STA_NOMERGED/time.h +++ b/HRT/8_YESBIN_3STA_NOMERGED/time.h @@ -12,4 +12,7 @@ double getWallTime(); double getCPUTime(); +static const int MAXTIME = 3600; + + #endif diff --git a/SMTI-GRP/1_NOBIN_1STA_NOMERGED/AgentIterator.cpp b/SMTI-GRP/1_NOBIN_1STA_NOMERGED/AgentIterator.cpp new file mode 100644 index 0000000..88ceb8e --- /dev/null +++ b/SMTI-GRP/1_NOBIN_1STA_NOMERGED/AgentIterator.cpp @@ -0,0 +1,404 @@ +#include "AgentIterator.h" + +AgentIteratorBase::AgentIteratorBase(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group, int posn) : + _agent(agent), + _these(these), _other(other), + _positions(positions), _candidates(candidates) { + if (_agent.preferences.size() == 0) { + _group = -1; + } else { + _group = group; + } + _position = posn; +} + +AgentIteratorBase::~AgentIteratorBase() { } + +int AgentIteratorBase::get_group() const { + return _group; +} + +int AgentIteratorBase::get_position() const { + return _position; +} + +const Child & AgentIteratorBase::get_agent() const { + return _agent; +} + +const std::vector & AgentIteratorBase::get_these() const { + return _these; +} + +const std::vector & AgentIteratorBase::get_other() const { + return _other; +} +const std::set & AgentIteratorBase::get_positions() const { + return _positions; +} +const std::set & AgentIteratorBase::get_candidates() const { + return _candidates; +} + +void AgentIteratorBase::regularIncrement() { + _position++; + if (_agent.preferences[_group].size() == _position) { + _position = 0; + _group++; + if (_agent.preferences.size() == _group) { + _group = -1; + } + } +} + +bool AgentIterator::operator==(const AgentIterator & other) { + return get_group() == other.get_group() && get_position() == other.get_position(); +} + +bool AgentIterator::operator!=(const AgentIterator & other) { + return ! (*this == other); +} + +const std::pair AgentIterator::operator*() { + return std::pair(get_group(), get_position()); +} + +AgentIterator AgentIterator::begin() { + AgentIterator starter(this, 0, 0); + starter.base->begin(); + return starter; +} + +AgentIterator AgentIterator::end() { + return AgentIterator(this, -1, 0); +} + +AgentIterator::AgentIterator(const Child & agent, const std::set & candidates, const std::set & positions, + const std::vector & these, const std::vector & other, int mode) : + _mode(mode) { + switch (_mode) { + default: + case 0: + base = new DescendingIterator(agent, candidates, positions, these, other, 0, 0); + break; + case 1: + base = new SkipBigIterator(agent, candidates, positions, these, other, 5, 0, 0); + break; + case 2: + base = new BestIterator(agent, candidates, positions, these, other, 0, 0); + break; + case 3: + base = new SkipBigIterator(agent, candidates, positions, these, other, 15, 0, 0); + break; + case 4: + base = new SkipBigIterator(agent, candidates, positions, these, other, 50, 0, 0); + break; + case 5: + base = new BestGroupIterator(agent, candidates, positions, these, other, 0, 0); + break; + } + } + +AgentIterator::AgentIterator(AgentIterator *other) : + _mode(other->get_mode()) { + switch (_mode) { + default: + case 0: + base = new DescendingIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), other->get_group(), other->get_position()); + break; + case 1: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 5, other->get_group(), other->get_position()); + break; + case 2: + base = new BestIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), other->get_group(), other->get_position()); + break; + case 3: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 15, other->get_group(), other->get_position()); + break; + case 4: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 50, other->get_group(), other->get_position()); + break; + case 5: + base = new BestGroupIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), other->get_group(), other->get_position()); + break; + } + } + +AgentIterator::AgentIterator(AgentIterator *other, int group, int posn) : + _mode(other->get_mode()) { + switch (_mode) { + case 0: + base = new DescendingIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), group, posn); + break; + case 1: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 5, group, posn); + break; + case 2: + base = new BestIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), group, posn); + break; + case 3: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 15, group, posn); + break; + case 4: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 50, group, posn); + break; + case 5: + base = new BestGroupIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), group, posn); + break; + } + } + +AgentIterator::~AgentIterator() { + delete base; +} + +int AgentIterator::get_group() const { + return base->get_group(); +} + +int AgentIterator::get_position() const { + return base->get_position(); +} + +int AgentIterator::get_mode() const { + return _mode; +} + +DescendingIterator::DescendingIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group, int posn) : + AgentIteratorBase(agent, candidates, positions, these, other, group, posn) { + } + +void DescendingIterator::begin() { +} + +void DescendingIterator::increment() { + regularIncrement(); +} + +SkipBigIterator::SkipBigIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int skip, int group, int posn) : + AgentIteratorBase(agent, candidates, positions, these, other, group, posn) , _skip(skip) { + } + + +void SkipBigIterator::begin() { + int num_added = 0; + while (true) { + if (get_group() == -1) { + break; + } + num_added = 0; + int other_id = _agent.preferences[_group][_position]; + int other_rank = _agent.ranks[_group][_position]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(pref) == 0) { + num_added++; + } + } + } + if (num_added > _skip) { + regularIncrement(); + } else { + break; + } + } +} + +void SkipBigIterator::increment() { + int num_added = 0; + do { + regularIncrement(); + if (get_group() == -1) { + break; + } + num_added = 0; + int other_id = _agent.preferences[_group][_position]; + int other_rank = _agent.ranks[_group][_position]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(pref) == 0) { + num_added++; + } + } + } + } while (num_added > _skip); +} + +BestIterator::BestIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group, int posn) : + AgentIteratorBase(agent, candidates, positions, these, other, group, posn) { + } + +void BestIterator::increment() { + int lowest_added = -1; + int best_group = -1; + int best_posn = -1; + for(int group_no = 0; group_no < _agent.preferences.size(); ++group_no) { + auto & group = _agent.preferences[group_no]; + for(int posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + int other_rank = _agent.ranks[group_no][posn]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto other_pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(other_pref) == 0) { + num_added++; + } + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_group = group_no; + best_posn = posn; + } + } + } + if (lowest_added != -1) { + _group = best_group; + _position = best_posn; + std::cout << "Using " << _group << ", " << _position << std::endl; + } else { + _group = -1; + _position = 0; + } +} + +void BestIterator::begin() { + int lowest_added = -1; + int best_group = -1; + int best_posn = -1; + for(int group_no = 0; group_no < _agent.preferences.size(); ++group_no) { + auto & group = _agent.preferences[group_no]; + for(int posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + int other_rank = _agent.ranks[group_no][posn]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto other_pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(other_pref) == 0) { + num_added++; + } + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_group = group_no; + best_posn = posn; + } + } + } + if (lowest_added != -1) { + _group = best_group; + _position = best_posn; + std::cout << "Using " << _group << ", " << _position << std::endl; + } else { + _group = -1; + _position = 0; + } +} + +BestGroupIterator::BestGroupIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group, int posn) : + AgentIteratorBase(agent, candidates, positions, these, other, group, posn) { + } + +void BestGroupIterator::increment() { + int lowest_added = -1; + int best_posn = -1; + auto & group = _agent.preferences[_group]; + for(int posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + int other_rank = _agent.ranks[_group][posn]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto other_pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(other_pref) == 0) { + num_added++; + } + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_posn = posn; + } + } + if (lowest_added != -1) { + _position = best_posn; + } else { + _group++; + if (_group == _agent.preferences.size()) { + _position = 0; + _group = -1; + } else { + increment(); + } + } +} + +void BestGroupIterator::begin() { + int lowest_added = -1; + int best_posn = -1; + if (_group == -1) { + return; + } + auto & group = _agent.preferences[_group]; + for(int posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + int other_rank = _agent.ranks[_group][posn]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto other_pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(other_pref) == 0) { + num_added++; + } + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_posn = posn; + } + } + if (lowest_added != -1) { + _position = best_posn; + } else { + _group++; + if (_group == _agent.preferences.size()) { + _position = 0; + _group = -1; + } else { + increment(); + } + } +} diff --git a/SMTI-GRP/1_NOBIN_1STA_NOMERGED/AgentIterator.h b/SMTI-GRP/1_NOBIN_1STA_NOMERGED/AgentIterator.h new file mode 100644 index 0000000..48b96c6 --- /dev/null +++ b/SMTI-GRP/1_NOBIN_1STA_NOMERGED/AgentIterator.h @@ -0,0 +1,110 @@ +#ifndef AGENTITERATOR_H +#define AGENTITERATOR_H + +#include + +#include "Allocation.h" + +class AgentIteratorBase { +public: + AgentIteratorBase(const Child & agent, const std::set & candidates, const std::set & positions, + const std::vector & these, const std::vector & other, int group=0, int posn=0); + virtual ~AgentIteratorBase() = 0; + virtual void increment() = 0; + virtual void begin() = 0; + + int get_position() const; + int get_group() const; + const Child & get_agent() const; + const std::vector & get_these() const; + const std::vector & get_other() const; + const std::set & get_positions() const; + const std::set & get_candidates() const; +protected: + void regularIncrement(); + + const Child & _agent; + int _group; + int _position; + const std::vector & _these; + const std::vector & _other; + const std::set & _positions; + const std::set & _candidates; +}; + + +class AgentIterator : public std::iterator, ptrdiff_t> { +public: + AgentIterator(const Child & agent, const std::set & candidates, const std::set & positions, + const std::vector & these, const std::vector & other, int mode); + AgentIterator(AgentIterator *other, int group, int posn); + AgentIterator(AgentIterator *other); + ~AgentIterator(); + bool operator==(const AgentIterator& other); + bool operator!=(const AgentIterator& other); + const std::pair operator*(); + AgentIterator& operator++() {base->increment(); return *this; } + AgentIterator operator++(int) {AgentIterator res(this); base->increment(); return res; } + + AgentIterator begin(); + AgentIterator end(); + + int get_position() const; + int get_group() const; + int get_mode() const; + + const Child & get_agent() const { return base->get_agent(); } + const std::vector & get_these() const {return base->get_these(); } + const std::vector & get_other() const {return base->get_other(); } + const std::set & get_positions() const {return base->get_positions(); } + const std::set & get_candidates() const {return base->get_candidates(); } +private: + AgentIteratorBase * base; + int _mode; +}; + + +class DescendingIterator : public AgentIteratorBase { + public: + DescendingIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group=0, int posn=0); + ~DescendingIterator() {} + void increment(); + void begin(); +}; + + +class SkipBigIterator : public AgentIteratorBase { + public: + SkipBigIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int skip, int group, int posn); + ~SkipBigIterator() {} + void increment(); + void begin(); + private: + int _skip; +}; + +class BestIterator : public AgentIteratorBase { + public: + BestIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group=0, int posn=0); + ~BestIterator() {} + void increment(); + void begin(); +}; + +class BestGroupIterator : public AgentIteratorBase { + public: + BestGroupIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group=0, int posn=0); + ~BestGroupIterator() {} + void increment(); + void begin(); +}; + +#endif /* AGENTITERATOR_H */ diff --git a/SMTI-GRP/1_NOBIN_1STA_NOMERGED/Allocation.cpp b/SMTI-GRP/1_NOBIN_1STA_NOMERGED/Allocation.cpp index 9d5dec4..b77e5e2 100644 --- a/SMTI-GRP/1_NOBIN_1STA_NOMERGED/Allocation.cpp +++ b/SMTI-GRP/1_NOBIN_1STA_NOMERGED/Allocation.cpp @@ -1,29 +1,16 @@ #include "Allocation.h" +#include "AgentIterator.h" /* ************************************************************************************* *********************************** DOCTOR ***************************************** ************************************************************************************* */ -void Child::print(){ - cout << "Child " << id << "\t Preferences (" << nbPref << " groups, " << nbTotPref << " in total)\t"; - for(int i=0; i 0) cout << " "; - cout << preferences[i][j]; - cout << "[" << ranks[i][j] << "_" << positions[i][j] << "]"; - } - cout << ") "; - } - cout << endl; -} - -/* ************************************************************************************* - *********************************** HOSPITAL **************************************** - ************************************************************************************* */ - -void Family::print(){ - cout << "Family " << id << "\t Preferences (" << nbPref << " groups, " << nbTotPref << " in total)\t"; +void Child::print(bool family){ + if (family) + cout << "Family "; + else + cout << "Child "; + cout << id << "\t Preferences (" << nbPref << " groups, " << nbTotPref << " in total)\t"; for(int i=0; i, vector >::iterator it; - map, vector > mapFirstChoice; - for(int j=0; j temp(nbChildren,0); - if(families[j].nbPref > 0){ - for(int k=0;k, vector > add; - add.first = temp; - add.second.push_back(j); - mapFirstChoice.insert(add); - } - else{ - (*it).second.push_back(j); - } - } - else count++; - } - -/* for(it = mapFirstChoice.begin(); it!= mapFirstChoice.end(); ++it){ - cout << (*it).second.size() << " x (" << families[(*it).second[0]].preferences[0].size() << ") ["; - for(int i=0;i<(*it).second.size();i++){ - cout << (*it).second[i] << " "; - } - cout << "] == ["; - for(int i=0;i<(*it).first.size();i++){ - cout << (*it).first[i] << " "; - } - cout << "]" << endl; - } - - cout << "Count = " << count << endl;*/ - - // Step 2 -- See worst rank - - vector worstRank(nbChildren); - for(int i=0;i= families[(*it).second[0]].preferences[0].size() ){ - // cout << "Updates from " << co << endl;; co++; - for(int i=0; i < families[(*it).second[0]].preferences[0].size();i++){ - multiset orderedRanks; - multiset::iterator it2; - for(int j=0; j<(*it).second.size();j++){ - orderedRanks.insert(families[(*it).second[j]].ranks[0][i]); - } - // cout << "worstRank of " << families[(*it).second[0]].preferences[0][i] << " updated from " << worstRank[families[(*it).second[0]].preferences[0][i]]; - it2 = orderedRanks.begin(); - advance(it2, families[(*it).second[0]].preferences[0].size() - 1); - worstRank[families[(*it).second[0]].preferences[0][i]]=min(worstRank[families[(*it).second[0]].preferences[0][i]], *(it2)); - // cout << " to " << worstRank[families[(*it).second[0]].preferences[0][i]] << endl; - } - } - } - - // Step 3 -- Remove families after worst rank from child's preferences - - int nbTotRem = 0; - - for(int i=0; i, vector >::iterator it; - map, vector > mapFirstChoice; - for(int j=0; j temp(nbFamilies,0); - if(children[j].nbPref > 0){ - for(int k=0;k, vector > add; - add.first = temp; - add.second.push_back(j); - mapFirstChoice.insert(add); - } - else{ - (*it).second.push_back(j); - } - } - else count++; - } - -/* for(it = mapFirstChoice.begin(); it!= mapFirstChoice.end(); ++it){ - cout << (*it).second.size() << " x (" << children[(*it).second[0]].preferences[0].size() << ") ["; - for(int i=0;i<(*it).second.size();i++){ - cout << (*it).second[i] << " "; - } - cout << "] == ["; - for(int i=0;i<(*it).first.size();i++){ - cout << (*it).first[i] << " "; - } - cout << "]" << endl; - } - - cout << "Count = " << count << endl;*/ - - // Step 2 -- See worst rank - - vector worstRank(nbFamilies); - for(int i=0;i= children[(*it).second[0]].preferences[0].size() ){ - // cout << "Updates from " << co << endl;; co++; - for(int i=0; i < children[(*it).second[0]].preferences[0].size();i++){ - multiset orderedRanks; - multiset::iterator it2; - for(int j=0; j<(*it).second.size();j++){ - orderedRanks.insert(children[(*it).second[j]].ranks[0][i]); - } - // cout << "worstRank of " << children[(*it).second[0]].preferences[0][i] << " updated from " << worstRank[children[(*it).second[0]].preferences[0][i]]; - it2 = orderedRanks.begin(); - advance(it2, children[(*it).second[0]].preferences[0].size() - 1); - worstRank[children[(*it).second[0]].preferences[0][i]]=min(worstRank[children[(*it).second[0]].preferences[0][i]], *(it2)); - // cout << " to " << worstRank[children[(*it).second[0]].preferences[0][i]] << endl; - } - } + families[i].print(true); } - - // Step 3 -- Remove families after worst rank from child's preferences - - int nbTotRem = 0; - - for(int i=0; i worstRank(nbChildren); - for(int i=0;i allChildren; - int count = 0; - for(int j=0; j * thesep; + std::vector * otherp; + if (children_side) { + thesep = &children; + otherp = &families; + } else { + thesep = &families; + otherp = &children; + } + std::vector & these = (*thesep); + std::vector & other = (*otherp); + + for (int i = 0; i < number_here; i++) { + set candidates; + set positions; + int worst_rank = 0; + unsigned int count = 0; + AgentIterator iter(these[i], candidates, positions, these, other, mode); + for(std::pair p: iter) { + int j = p.first; + int k = p.second; + if (j > worst_rank) { + worst_rank = j; } - if(count >= allChildren.size()){ - worstRank[i] = j; - // cout << "worst rank of " << i << " is " << j << endl; - break; - } - } - } - - for(int i=0; i worstRank(nbFamilies); - for(int i=0;i allFamilies; - int count = 0; - for(int j=0; j= candidates.size()) { + for (int k = worst_rank + 1; k < these[i].nbPref; k++) { + nbTotRem += these[i].preferences[k].size(); + std::cout << "Removing from " << i << " : ["; + for(auto pref: these[i].preferences[k]) { + std::cout << pref << ", "; + } + std::cout << "]" << std::endl; + these[i].nbTotPref -= these[i].preferences[k].size(); + for (unsigned int l = 0; l < these[i].preferences[k].size(); l++) { + int idxFam = these[i].preferences[k][l]; + int idxPos = these[i].positions[k][l]; + int idxRank = these[i].ranks[k][l]; + for (unsigned int m = idxPos + 1; + m < other[idxFam].preferences[idxRank].size(); m++) { + these[other[idxFam].preferences[idxRank][m]] + .positions[other[idxFam].ranks[idxRank][m]] + [other[idxFam].positions[idxRank][m]]--; + } + other[idxFam].nbTotPref--; + other[idxFam].positions[idxRank].erase( + other[idxFam].positions[idxRank].begin() + idxPos); + other[idxFam].ranks[idxRank].erase( + other[idxFam].ranks[idxRank].begin() + idxPos); + other[idxFam].preferences[idxRank].erase( + other[idxFam].preferences[idxRank].begin() + idxPos); + } } - } - if(count >= allFamilies.size()){ - worstRank[i] = j; - // cout << "worst rank of " << i << " is " << j << endl; + these[i].nbPref = worst_rank + 1; + these[i].preferences.resize(these[i].nbPref); + these[i].ranks.resize(these[i].nbPref); + these[i].positions.resize(these[i].nbPref); break; } } } - - for(int i=0; i class Child; - class Family; + typedef Child Family; class Assignment; class Allocation; @@ -28,22 +28,7 @@ vector > preferences; vector > ranks; vector > positions; - void print(); - }; - -/* ************************************************************************************* - *********************************** HOSPITAL **************************************** - ************************************************************************************* */ - - class Family{ - public: - int id; - int nbPref; - int nbTotPref; - vector > preferences; - vector > ranks; - vector > positions; - void print(); + void print(bool); }; /* ************************************************************************************* @@ -77,6 +62,7 @@ string name; int nbChildren; int nbFamilies; + int total_reduced; vector > grades; vector children; @@ -90,16 +76,13 @@ void load(const string& path, const string& filein, const int& threshold); void printProb(); - int reductionFam1(); - int reductionChi1(); - int reductionFam2(); - int reductionChi2(); + int reductionMine(bool children_side=true, int mode=0); void polish(); - void reduction(); + void reduction(int mode); void printSol(); void printInfo(const string& pathAndFileout); void checkSolution(); }; -#endif \ No newline at end of file +#endif diff --git a/SMTI-GRP/1_NOBIN_1STA_NOMERGED/main.cpp b/SMTI-GRP/1_NOBIN_1STA_NOMERGED/main.cpp index 3411d94..fafedef 100644 --- a/SMTI-GRP/1_NOBIN_1STA_NOMERGED/main.cpp +++ b/SMTI-GRP/1_NOBIN_1STA_NOMERGED/main.cpp @@ -1,5 +1,7 @@ #include "main.h" +#define MAXTIME 3600 + /* ************************************************************************************* ************************************* MAIN ***************************************** ************************************************************************************* */ @@ -12,26 +14,35 @@ int main(int argc, char **argv){ string path = argv[1]; string pathAndFileout = argv[3]; int minGrade = atoi(argv[4]); + int mode = atoi(argv[5]); // functions allo.load(path,filein,minGrade); - allo.printProb(); + //allo.printProb(); - manlove(allo); - - allo.printSol(); - allo.checkSolution(); + int res = manlove(allo, mode); + if (res != -1) { + allo.printSol(); + allo.checkSolution(); + } allo.printInfo(pathAndFileout); } -int manlove(Allocation& allo){ +int manlove(Allocation& allo, int reduction_mode){ double initTimeModelCPU = getCPUTime(); GRBEnv env = GRBEnv(); - allo.reduction(); + allo.reduction(reduction_mode); allo.printProb(); allo.infos.timeCPUPP = getCPUTime() - initTimeModelCPU; + if (allo.infos.timeCPUPP > MAXTIME) { + cout << "Preprocessing took over " << MAXTIME << " seconds" << endl; + allo.infos.LB = 0; + allo.assignmentByChild.resize(allo.nbChildren, -1); + allo.assignmentByFamily.resize(allo.nbFamilies,-1); + return -1; + } // Model try{ @@ -111,7 +122,7 @@ int manlove(Allocation& allo){ } // Setting of Gurobi - model.getEnv().set(GRB_DoubleParam_TimeLimit, 3600 - (getCPUTime() - initTimeModelCPU)); + model.getEnv().set(GRB_DoubleParam_TimeLimit, MAXTIME - (getCPUTime() - initTimeModelCPU)); model.getEnv().set(GRB_IntParam_Threads, 1); model.getEnv().set(GRB_DoubleParam_MIPGap, 0); model.optimize(); diff --git a/SMTI-GRP/1_NOBIN_1STA_NOMERGED/main.h b/SMTI-GRP/1_NOBIN_1STA_NOMERGED/main.h index c441859..3bf5282 100644 --- a/SMTI-GRP/1_NOBIN_1STA_NOMERGED/main.h +++ b/SMTI-GRP/1_NOBIN_1STA_NOMERGED/main.h @@ -11,6 +11,6 @@ float EPSILON = 0.001; - int manlove(Allocation& allo); + int manlove(Allocation& allo, int reduction_mode); #endif diff --git a/SMTI-GRP/1_NOBIN_1STA_NOMERGED/makefile b/SMTI-GRP/1_NOBIN_1STA_NOMERGED/makefile index f555425..92551af 100644 --- a/SMTI-GRP/1_NOBIN_1STA_NOMERGED/makefile +++ b/SMTI-GRP/1_NOBIN_1STA_NOMERGED/makefile @@ -8,14 +8,14 @@ CPPLIB = -L$(GUROBI_DIR)/lib/ -lgurobi_c++ $(CLIB) GUROBI_OPTS = -I$(INC) $(CPPLIB) -lpthread -lm -m64 CC = g++ -CFLAGS = -O2 -Wall -ansi -pedantic -DIL_STD +CFLAGS = -O2 -Wall -ansi -pedantic -DIL_STD -std=c++11 DEBUG = -pg -g -Wall -ansi -pedantic -DIL_STD -OBJECTS = main.o Allocation.o time.o +OBJECTS = main.o Allocation.o time.o AgentIterator.o exec : $(OBJECTS) $(CC) $(CFLAGS) -o NOBIN_1STA_NOMERGED $(OBJECTS) $(GUROBI_OPTS) -.cpp.o : +%.o : %.cpp $(CC) $(CFLAGS) $(GUROBI_OPTS) -c $< -o $@ clean : diff --git a/SMTI-GRP/4_YESBIN_1STA_YESMERGED/AgentIterator.cpp b/SMTI-GRP/4_YESBIN_1STA_YESMERGED/AgentIterator.cpp new file mode 100644 index 0000000..6210288 --- /dev/null +++ b/SMTI-GRP/4_YESBIN_1STA_YESMERGED/AgentIterator.cpp @@ -0,0 +1,402 @@ +#include "AgentIterator.h" + +AgentIteratorBase::AgentIteratorBase(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group, int posn) : + _agent(agent), + _these(these), _other(other), + _positions(positions), _candidates(candidates) { + if (_agent.preferences.size() == 0) { + _group = -1; + } else { + _group = group; + } + _position = posn; +} + +AgentIteratorBase::~AgentIteratorBase() { } + +int AgentIteratorBase::get_group() const { + return _group; +} + +int AgentIteratorBase::get_position() const { + return _position; +} + +const Child & AgentIteratorBase::get_agent() const { + return _agent; +} + +const std::vector & AgentIteratorBase::get_these() const { + return _these; +} + +const std::vector & AgentIteratorBase::get_other() const { + return _other; +} +const std::set & AgentIteratorBase::get_positions() const { + return _positions; +} +const std::set & AgentIteratorBase::get_candidates() const { + return _candidates; +} + +void AgentIteratorBase::regularIncrement() { + _position++; + if (_agent.preferences[_group].size() == _position) { + _position = 0; + _group++; + if (_agent.preferences.size() == _group) { + _group = -1; + } + } +} + +bool AgentIterator::operator==(const AgentIterator & other) { + return get_group() == other.get_group() && get_position() == other.get_position(); +} + +bool AgentIterator::operator!=(const AgentIterator & other) { + return ! (*this == other); +} + +const std::pair AgentIterator::operator*() { + return std::pair(get_group(), get_position()); +} + +AgentIterator AgentIterator::begin() { + AgentIterator starter(this, 0, 0); + starter.base->begin(); + return starter; +} + +AgentIterator AgentIterator::end() { + return AgentIterator(this, -1, 0); +} + +AgentIterator::AgentIterator(const Child & agent, const std::set & candidates, const std::set & positions, + const std::vector & these, const std::vector & other, int mode) : + _mode(mode) { + switch (_mode) { + default: + case 0: + base = new DescendingIterator(agent, candidates, positions, these, other, 0, 0); + break; + case 1: + base = new SkipBigIterator(agent, candidates, positions, these, other, 5, 0, 0); + break; + case 2: + base = new BestIterator(agent, candidates, positions, these, other, 0, 0); + break; + case 3: + base = new SkipBigIterator(agent, candidates, positions, these, other, 15, 0, 0); + break; + case 4: + base = new SkipBigIterator(agent, candidates, positions, these, other, 50, 0, 0); + break; + case 5: + base = new BestGroupIterator(agent, candidates, positions, these, other, 0, 0); + break; + } + } + +AgentIterator::AgentIterator(AgentIterator *other) : + _mode(other->get_mode()) { + switch (_mode) { + default: + case 0: + base = new DescendingIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), other->get_group(), other->get_position()); + break; + case 1: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 5, other->get_group(), other->get_position()); + break; + case 2: + base = new BestIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), other->get_group(), other->get_position()); + break; + case 3: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 15, other->get_group(), other->get_position()); + break; + case 4: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 50, other->get_group(), other->get_position()); + break; + case 5: + base = new BestGroupIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), other->get_group(), other->get_position()); + break; + } + } + +AgentIterator::AgentIterator(AgentIterator *other, int group, int posn) : + _mode(other->get_mode()) { + switch (_mode) { + case 0: + base = new DescendingIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), group, posn); + break; + case 1: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 5, group, posn); + break; + case 2: + base = new BestIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), group, posn); + break; + case 3: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 15, group, posn); + break; + case 4: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 50, group, posn); + break; + case 5: + base = new BestGroupIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), group, posn); + break; + } + } + +AgentIterator::~AgentIterator() { + delete base; +} + +int AgentIterator::get_group() const { + return base->get_group(); +} + +int AgentIterator::get_position() const { + return base->get_position(); +} + +int AgentIterator::get_mode() const { + return _mode; +} + +DescendingIterator::DescendingIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group, int posn) : + AgentIteratorBase(agent, candidates, positions, these, other, group, posn) { + } + +void DescendingIterator::begin() { +} + +void DescendingIterator::increment() { + regularIncrement(); +} + +SkipBigIterator::SkipBigIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int skip, int group, int posn) : + AgentIteratorBase(agent, candidates, positions, these, other, group, posn) , _skip(skip) { + } + + +void SkipBigIterator::begin() { + int num_added = 0; + while (true) { + if (get_group() == -1) { + break; + } + num_added = 0; + int other_id = _agent.preferences[_group][_position]; + int other_rank = _agent.ranks[_group][_position]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(pref) == 0) { + num_added++; + } + } + } + if (num_added > _skip) { + regularIncrement(); + } else { + break; + } + } +} + +void SkipBigIterator::increment() { + int num_added = 0; + do { + regularIncrement(); + if (get_group() == -1) { + break; + } + num_added = 0; + int other_id = _agent.preferences[_group][_position]; + int other_rank = _agent.ranks[_group][_position]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(pref) == 0) { + num_added++; + } + } + } + } while (num_added > _skip); +} + +BestIterator::BestIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group, int posn) : + AgentIteratorBase(agent, candidates, positions, these, other, group, posn) { + } + +void BestIterator::increment() { + int lowest_added = -1; + int best_group = -1; + int best_posn = -1; + for(int group_no = 0; group_no < _agent.preferences.size(); ++group_no) { + auto & group = _agent.preferences[group_no]; + for(int posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + int other_rank = _agent.ranks[group_no][posn]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto other_pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(other_pref) == 0) { + num_added++; + } + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_group = group_no; + best_posn = posn; + } + } + } + if (lowest_added != -1) { + _group = best_group; + _position = best_posn; + } else { + _group = -1; + _position = 0; + } +} + +void BestIterator::begin() { + int lowest_added = -1; + int best_group = -1; + int best_posn = -1; + for(int group_no = 0; group_no < _agent.preferences.size(); ++group_no) { + auto & group = _agent.preferences[group_no]; + for(int posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + int other_rank = _agent.ranks[group_no][posn]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto other_pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(other_pref) == 0) { + num_added++; + } + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_group = group_no; + best_posn = posn; + } + } + } + if (lowest_added != -1) { + _group = best_group; + _position = best_posn; + } else { + _group = -1; + _position = 0; + } +} + +BestGroupIterator::BestGroupIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group, int posn) : + AgentIteratorBase(agent, candidates, positions, these, other, group, posn) { + } + +void BestGroupIterator::increment() { + int lowest_added = -1; + int best_posn = -1; + auto & group = _agent.preferences[_group]; + for(int posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + int other_rank = _agent.ranks[_group][posn]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto other_pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(other_pref) == 0) { + num_added++; + } + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_posn = posn; + } + } + if (lowest_added != -1) { + _position = best_posn; + } else { + _group++; + if (_group == _agent.preferences.size()) { + _position = 0; + _group = -1; + } else { + increment(); + } + } +} + +void BestGroupIterator::begin() { + int lowest_added = -1; + int best_posn = -1; + if (_group == -1) { + return; + } + auto & group = _agent.preferences[_group]; + for(int posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + int other_rank = _agent.ranks[_group][posn]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto other_pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(other_pref) == 0) { + num_added++; + } + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_posn = posn; + } + } + if (lowest_added != -1) { + _position = best_posn; + } else { + _group++; + if (_group == _agent.preferences.size()) { + _position = 0; + _group = -1; + } else { + increment(); + } + } +} diff --git a/SMTI-GRP/4_YESBIN_1STA_YESMERGED/AgentIterator.h b/SMTI-GRP/4_YESBIN_1STA_YESMERGED/AgentIterator.h new file mode 100644 index 0000000..48b96c6 --- /dev/null +++ b/SMTI-GRP/4_YESBIN_1STA_YESMERGED/AgentIterator.h @@ -0,0 +1,110 @@ +#ifndef AGENTITERATOR_H +#define AGENTITERATOR_H + +#include + +#include "Allocation.h" + +class AgentIteratorBase { +public: + AgentIteratorBase(const Child & agent, const std::set & candidates, const std::set & positions, + const std::vector & these, const std::vector & other, int group=0, int posn=0); + virtual ~AgentIteratorBase() = 0; + virtual void increment() = 0; + virtual void begin() = 0; + + int get_position() const; + int get_group() const; + const Child & get_agent() const; + const std::vector & get_these() const; + const std::vector & get_other() const; + const std::set & get_positions() const; + const std::set & get_candidates() const; +protected: + void regularIncrement(); + + const Child & _agent; + int _group; + int _position; + const std::vector & _these; + const std::vector & _other; + const std::set & _positions; + const std::set & _candidates; +}; + + +class AgentIterator : public std::iterator, ptrdiff_t> { +public: + AgentIterator(const Child & agent, const std::set & candidates, const std::set & positions, + const std::vector & these, const std::vector & other, int mode); + AgentIterator(AgentIterator *other, int group, int posn); + AgentIterator(AgentIterator *other); + ~AgentIterator(); + bool operator==(const AgentIterator& other); + bool operator!=(const AgentIterator& other); + const std::pair operator*(); + AgentIterator& operator++() {base->increment(); return *this; } + AgentIterator operator++(int) {AgentIterator res(this); base->increment(); return res; } + + AgentIterator begin(); + AgentIterator end(); + + int get_position() const; + int get_group() const; + int get_mode() const; + + const Child & get_agent() const { return base->get_agent(); } + const std::vector & get_these() const {return base->get_these(); } + const std::vector & get_other() const {return base->get_other(); } + const std::set & get_positions() const {return base->get_positions(); } + const std::set & get_candidates() const {return base->get_candidates(); } +private: + AgentIteratorBase * base; + int _mode; +}; + + +class DescendingIterator : public AgentIteratorBase { + public: + DescendingIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group=0, int posn=0); + ~DescendingIterator() {} + void increment(); + void begin(); +}; + + +class SkipBigIterator : public AgentIteratorBase { + public: + SkipBigIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int skip, int group, int posn); + ~SkipBigIterator() {} + void increment(); + void begin(); + private: + int _skip; +}; + +class BestIterator : public AgentIteratorBase { + public: + BestIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group=0, int posn=0); + ~BestIterator() {} + void increment(); + void begin(); +}; + +class BestGroupIterator : public AgentIteratorBase { + public: + BestGroupIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group=0, int posn=0); + ~BestGroupIterator() {} + void increment(); + void begin(); +}; + +#endif /* AGENTITERATOR_H */ diff --git a/SMTI-GRP/4_YESBIN_1STA_YESMERGED/Allocation.cpp b/SMTI-GRP/4_YESBIN_1STA_YESMERGED/Allocation.cpp index 9d5dec4..7a50885 100644 --- a/SMTI-GRP/4_YESBIN_1STA_YESMERGED/Allocation.cpp +++ b/SMTI-GRP/4_YESBIN_1STA_YESMERGED/Allocation.cpp @@ -1,29 +1,17 @@ #include "Allocation.h" +#include "AgentIterator.h" +#include "Graph.h" /* ************************************************************************************* *********************************** DOCTOR ***************************************** ************************************************************************************* */ -void Child::print(){ - cout << "Child " << id << "\t Preferences (" << nbPref << " groups, " << nbTotPref << " in total)\t"; - for(int i=0; i 0) cout << " "; - cout << preferences[i][j]; - cout << "[" << ranks[i][j] << "_" << positions[i][j] << "]"; - } - cout << ") "; - } - cout << endl; -} - -/* ************************************************************************************* - *********************************** HOSPITAL **************************************** - ************************************************************************************* */ - -void Family::print(){ - cout << "Family " << id << "\t Preferences (" << nbPref << " groups, " << nbTotPref << " in total)\t"; +void Child::print(bool family){ + if (family) + cout << "Family "; + else + cout << "Child "; + cout << id << "\t Preferences (" << nbPref << " groups, " << nbTotPref << " in total)\t"; for(int i=0; i= threshold) grade.insert(grades[i][j]); } - Family f; f.id = i; f.nbPref = grade.size(); f.nbTotPref = 0; f.preferences.resize(f.nbPref); f.ranks.resize(f.nbPref); f.positions.resize(f.nbPref); + Family f; f.id = i; f.nbPref = grade.size(); f.nbTotPref = 0; f.preferences.resize(f.nbPref); f.ranks.resize(f.nbPref); f.positions.resize(f.nbPref); + f.mustBeAllocated = false; vector gradeVector(grade.begin(), grade.end()); reverse(gradeVector.begin(),gradeVector.end()); for (int j = 0; j < nbChildren; j++){ @@ -111,7 +100,8 @@ void Allocation::load(const string& path, const string& filein, const int& thres for (int j = 0; j < nbFamilies; j++){ if(grades[j][i] >= threshold) grade.insert(grades[j][i]); } - Child c; c.id = i; c.nbPref = grade.size(); c.nbTotPref = 0; c.preferences.resize(c.nbPref); c.ranks.resize(c.nbPref); c.positions.resize(c.nbPref); + Child c; c.id = i; c.nbPref = grade.size(); c.nbTotPref = 0; c.preferences.resize(c.nbPref); c.ranks.resize(c.nbPref); c.positions.resize(c.nbPref); + c.mustBeAllocated = false; vector gradeVector(grade.begin(), grade.end()); reverse(gradeVector.begin(),gradeVector.end()); for (int j = 0; j < nbFamilies; j++){ @@ -156,320 +146,278 @@ void Allocation::load(const string& path, const string& filein, const int& thres void Allocation::printProb(){ cout << "Instance " << name << endl; for(int i=0; i, vector >::iterator it; - map, vector > mapFirstChoice; - for(int j=0; j temp(nbChildren,0); - if(families[j].nbPref > 0){ - for(int k=0;k, vector > add; - add.first = temp; - add.second.push_back(j); - mapFirstChoice.insert(add); - } - else{ - (*it).second.push_back(j); - } - } - else count++; - } - -/* for(it = mapFirstChoice.begin(); it!= mapFirstChoice.end(); ++it){ - cout << (*it).second.size() << " x (" << families[(*it).second[0]].preferences[0].size() << ") ["; - for(int i=0;i<(*it).second.size();i++){ - cout << (*it).second[i] << " "; - } - cout << "] == ["; - for(int i=0;i<(*it).first.size();i++){ - cout << (*it).first[i] << " "; - } - cout << "]" << endl; - } - - cout << "Count = " << count << endl;*/ - - // Step 2 -- See worst rank - - vector worstRank(nbChildren); - for(int i=0;i= families[(*it).second[0]].preferences[0].size() ){ - // cout << "Updates from " << co << endl;; co++; - for(int i=0; i < families[(*it).second[0]].preferences[0].size();i++){ - multiset orderedRanks; - multiset::iterator it2; - for(int j=0; j<(*it).second.size();j++){ - orderedRanks.insert(families[(*it).second[j]].ranks[0][i]); - } - // cout << "worstRank of " << families[(*it).second[0]].preferences[0][i] << " updated from " << worstRank[families[(*it).second[0]].preferences[0][i]]; - it2 = orderedRanks.begin(); - advance(it2, families[(*it).second[0]].preferences[0].size() - 1); - worstRank[families[(*it).second[0]].preferences[0][i]]=min(worstRank[families[(*it).second[0]].preferences[0][i]], *(it2)); - // cout << " to " << worstRank[families[(*it).second[0]].preferences[0][i]] << endl; - } - } - } - - // Step 3 -- Remove families after worst rank from child's preferences - +int Allocation::reductionExact(bool children_side, bool supp, bool early_exit) { int nbTotRem = 0; - - for(int i=0; i * thesep; + std::vector * otherp; + std::list *theseMustBeAllocatedp; + std::list *otherMustBeAllocatedp; + if (children_side) { + // Processing the lists of the children, removing families + thesep = &children; + otherp = &families; + theseMustBeAllocatedp = &childrenMustBeAllocated; + otherMustBeAllocatedp = &familiesMustBeAllocated; + number_here = nbChildren; + } else { + thesep = &families; + otherp = &children; + theseMustBeAllocatedp = &familiesMustBeAllocated; + otherMustBeAllocatedp = &childrenMustBeAllocated; + number_here = nbFamilies; + } + std::vector & these = (*thesep); + std::vector & other = (*otherp); + std::list & theseMustBeAllocated = (*theseMustBeAllocatedp); + std::list & otherMustBeAllocated = (*otherMustBeAllocatedp); + for (int i = 0; i < number_here; i++) { + // Early exit! + const float ratio = 0.1; + if (early_exit && (i >= ratio * number_here) && (nbTotRem == 0)) { + return 0; } - children[i].nbPref = worstRank[i] + 1; - children[i].preferences.resize(children[i].nbPref); - children[i].ranks.resize(children[i].nbPref); - children[i].positions.resize(children[i].nbPref); - } - - polish(); - return nbTotRem; -} - -int Allocation::reductionChi1(){ - - // Step 1 -- Create map - - int count = 0; - map, vector >::iterator it; - map, vector > mapFirstChoice; - for(int j=0; j temp(nbFamilies,0); - if(children[j].nbPref > 0){ - for(int k=0;k, vector > add; - add.first = temp; - add.second.push_back(j); - mapFirstChoice.insert(add); - } - else{ - (*it).second.push_back(j); + // A graph is "named" with two integers. The first is a 0 for a candidate + // (aka these) or a 1 for a position (aka other) + Graph g; + int n_1 = 0; + for(int rank = 0; rank < these[i].nbPref; rank++) { + // No point in checking the last rank if we already know this agent must + // be allocated, or if we don't care + if ((rank == these[i].nbPref - 1) && (these[i].mustBeAllocated || !supp)) { + continue; } - } - else count++; - } - -/* for(it = mapFirstChoice.begin(); it!= mapFirstChoice.end(); ++it){ - cout << (*it).second.size() << " x (" << children[(*it).second[0]].preferences[0].size() << ") ["; - for(int i=0;i<(*it).second.size();i++){ - cout << (*it).second[i] << " "; - } - cout << "] == ["; - for(int i=0;i<(*it).first.size();i++){ - cout << (*it).first[i] << " "; - } - cout << "]" << endl; - } - - cout << "Count = " << count << endl;*/ - - // Step 2 -- See worst rank - - vector worstRank(nbFamilies); - for(int i=0;i= children[(*it).second[0]].preferences[0].size() ){ - // cout << "Updates from " << co << endl;; co++; - for(int i=0; i < children[(*it).second[0]].preferences[0].size();i++){ - multiset orderedRanks; - multiset::iterator it2; - for(int j=0; j<(*it).second.size();j++){ - orderedRanks.insert(children[(*it).second[j]].ranks[0][i]); + for(size_t ind = 0; ind < these[i].preferences[rank].size(); ind++) { + int position = these[i].preferences[rank][ind]; + g.addVertex(1, position); + int idxRank = these[i].ranks[rank][ind]; + for(int l = 0; l <= idxRank; l++) { + for(size_t k = 0; k < other[position].preferences[l].size(); k++) { + int other_cand = other[position].preferences[l][k]; + if (other_cand == i) { // Don't add the current candidate to the graph + continue; + } + if (! g.containsVertex(0, other_cand)) { + g.addVertex(0, other_cand); + n_1 += 1; + } + g.addEdge(position, other_cand); + } } - // cout << "worstRank of " << children[(*it).second[0]].preferences[0][i] << " updated from " << worstRank[children[(*it).second[0]].preferences[0][i]]; - it2 = orderedRanks.begin(); - advance(it2, children[(*it).second[0]].preferences[0].size() - 1); - worstRank[children[(*it).second[0]].preferences[0][i]]=min(worstRank[children[(*it).second[0]].preferences[0][i]], *(it2)); - // cout << " to " << worstRank[children[(*it).second[0]].preferences[0][i]] << endl; } - } - } - - // Step 3 -- Remove families after worst rank from child's preferences - - int nbTotRem = 0; - - for(int i=0; i worstRank(nbChildren); - for(int i=0;i allChildren; - int count = 0; - for(int j=0; j= n_1 + 1)) { + break; } - } - if(count >= allChildren.size()){ - worstRank[i] = j; - // cout << "worst rank of " << i << " is " << j << endl; + // First add all positions that must be filled. + for(int position: otherMustBeAllocated) { + // If position is acceptable to i, then skip it. + bool isAcceptable = false; + for(int otherRank = 0; (!isAcceptable) && otherRank < other[position].nbPref; otherRank++) { + for(size_t ind = 0; ind < other[position].preferences[otherRank].size(); ++ind) { + if (other[position].preferences[otherRank][ind] == i) { + isAcceptable = true; + break; + } + } + } + if (isAcceptable) { + continue; + } + g.addVertex(1, position); + for(int otherRank = 0; otherRank < other[position].nbPref; otherRank++) { + for(size_t ind = 0; ind < other[position].preferences[otherRank].size(); ++ind) { + int candidate = other[position].preferences[otherRank][ind]; + if (!g.containsVertex(0, candidate)) { + g.addVertex(0, candidate); + n_1 += 1; + } + g.addEdge(position, candidate); + } + } + g.augment(position); + } + // I'm using a while loop as an if statement, so I need to break out. break; } - } - } - - for(int i=0; i= n_1 + 1)) { + // preprocess on rank! + // Firstly, they must be allocated, so mark as such (if we're in that + // mode) + if (supp && !these[i].mustBeAllocated) { + theseMustBeAllocated.push_back(i); + these[i].mustBeAllocated = true; + newMustAlways = true; + } +#ifdef DEBUG + if ((!children_side) and (i == 6)) { + std::cout << "g.size() = " << g.size() << ", g.matchingSize() = " << g.matchingSize(); + std::cout << ", n_1 = " << n_1 << std::endl; + g.printGraph(); + g.printMatching(); + } + if (children_side) { + std::cout << "child "; + } else { + std::cout << "family "; } - families[idxFam].nbTotPref--; - families[idxFam].positions[idxRank].erase(families[idxFam].positions[idxRank].begin() + idxPos); - families[idxFam].ranks[idxRank].erase(families[idxFam].ranks[idxRank].begin() + idxPos); - families[idxFam].preferences[idxRank].erase(families[idxFam].preferences[idxRank].begin() + idxPos); + std::cout << "worst rank of " << i << " is " << rank << " "; + int remHere = 0; +#endif /* DEBUG */ + for (int k = rank + 1; k < these[i].nbPref; k++) { + nbTotRem += these[i].preferences[k].size(); +#ifdef DEBUG + remHere += these[i].preferences[k].size(); +#endif /* DEBUG */ + these[i].nbTotPref -= these[i].preferences[k].size(); + for (unsigned int l = 0; l < these[i].preferences[k].size(); l++) { + int idxFam = these[i].preferences[k][l]; + int idxPos = these[i].positions[k][l]; + int idxRank = these[i].ranks[k][l]; + for (unsigned int m = idxPos + 1; + m < other[idxFam].preferences[idxRank].size(); m++) { + these[other[idxFam].preferences[idxRank][m]] + .positions[other[idxFam].ranks[idxRank][m]] + [other[idxFam].positions[idxRank][m]]--; + } + other[idxFam].nbTotPref--; + other[idxFam].positions[idxRank].erase( + other[idxFam].positions[idxRank].begin() + idxPos); + other[idxFam].ranks[idxRank].erase( + other[idxFam].ranks[idxRank].begin() + idxPos); + other[idxFam].preferences[idxRank].erase( + other[idxFam].preferences[idxRank].begin() + idxPos); + } + } + these[i].nbPref = rank + 1; + these[i].preferences.resize(these[i].nbPref); + these[i].ranks.resize(these[i].nbPref); + these[i].positions.resize(these[i].nbPref); +#ifdef DEBUG + std::cout << "removed " << remHere << std::endl; +#endif /* DEBUG */ + break; } } - children[i].nbPref = worstRank[i] + 1; - children[i].preferences.resize(children[i].nbPref); - children[i].ranks.resize(children[i].nbPref); - children[i].positions.resize(children[i].nbPref); } - - polish(); + if (nbTotRem > 0) { + polish(); + } + if ((nbTotRem == 0) && (newMustAlways)) { + return -1; + } return nbTotRem; } -int Allocation::reductionChi2(){ - +int Allocation::reductionMine(bool children_side, int mode, bool alt_store) { int nbTotRem = 0; - vector worstRank(nbFamilies); - for(int i=0;i allFamilies; + int number_here; + std::vector * thesep; + std::vector * otherp; + if (children_side) { + thesep = &children; + otherp = &families; + number_here = nbChildren; + } else { + thesep = &families; + otherp = &children; + number_here = nbFamilies; + } + std::vector & these = (*thesep); + std::vector & other = (*otherp); + + for (int i = 0; i < number_here; i++) { + set candidates; + set positions; + vector cand_in(number_here, false); + int cand_size = 0; + int worst_rank = 0; int count = 0; - for(int j=0; j p: iter) { + int j = p.first; + int k = p.second; + if (j > worst_rank) { + worst_rank = j; + } + int idxFam = these[i].preferences[j][k]; + int idxRank = these[i].ranks[j][k]; + positions.insert(idxFam); + count++; + for (int l = 0; l <= idxRank; l++) { + for (unsigned int m = 0; m < other[idxFam].preferences[l].size(); + m++) { + if ((alt_store && cand_in[other[idxFam].preferences[l][m]] == false) || + (!alt_store && candidates.count(other[idxFam].preferences[l][m]) == 0)) { + candidates.insert(other[idxFam].preferences[l][m]); + cand_in[other[idxFam].preferences[l][m]] = true; + cand_size++; + } } } - if(count >= allFamilies.size()){ - worstRank[i] = j; - // cout << "worst rank of " << i << " is " << j << endl; + if (count >= cand_size) { +#ifdef DEBUG + if (children_side) { + std::cout << "child "; + } else { + std::cout << "family "; + } + std::cout << "worst rank of " << i << " is " << worst_rank << std::endl; +#endif /* DEBUG */ + for (int k = worst_rank + 1; k < these[i].nbPref; k++) { + nbTotRem += these[i].preferences[k].size(); + these[i].nbTotPref -= these[i].preferences[k].size(); + for (unsigned int l = 0; l < these[i].preferences[k].size(); l++) { + int idxFam = these[i].preferences[k][l]; + int idxPos = these[i].positions[k][l]; + int idxRank = these[i].ranks[k][l]; + for (unsigned int m = idxPos + 1; + m < other[idxFam].preferences[idxRank].size(); m++) { + these[other[idxFam].preferences[idxRank][m]] + .positions[other[idxFam].ranks[idxRank][m]] + [other[idxFam].positions[idxRank][m]]--; + } + other[idxFam].nbTotPref--; + other[idxFam].positions[idxRank].erase( + other[idxFam].positions[idxRank].begin() + idxPos); + other[idxFam].ranks[idxRank].erase( + other[idxFam].ranks[idxRank].begin() + idxPos); + other[idxFam].preferences[idxRank].erase( + other[idxFam].preferences[idxRank].begin() + idxPos); + } + } + these[i].nbPref = worst_rank + 1; + these[i].preferences.resize(these[i].nbPref); + these[i].ranks.resize(these[i].nbPref); + these[i].positions.resize(these[i].nbPref); break; } } } - - for(int i=0; i 0) { + polish(); } - - polish(); return nbTotRem; } @@ -531,20 +479,94 @@ void Allocation::polish(){ } } -void Allocation::reduction(){ - int nbRed1 = 0; - int nbRed2 = 0; - int nbRed3 = 0; - int nbRed4 = 0; +void Allocation::reduction(int mode){ + total_reduced = 0; int i = 0; - do{ - nbRed1 = reductionFam1(); - nbRed2 = reductionChi1(); - nbRed3 = reductionFam2(); - nbRed4 = reductionChi2(); - cout << "Reduction iteration " << i << " reductionFam1 " << nbRed1 << " reductionChi1 " << nbRed2 << " reductionFam2 " << nbRed3 << " reductionChi2 " << nbRed4 << endl; - i++; - }while(nbRed1 + nbRed2 + nbRed3 + nbRed4 != 0); + int num = 0; + bool keepGoing; + if (mode == 7) { + do { + num = reductionMine(false, 1); + num += reductionMine(true, 1); + cout << "Iteration " << i << " in heuristic removed " << num << std::endl; + i++; + total_reduced += num; + } while (num != 0); + do { + num = reductionExact(false); + num += reductionExact(true); + cout << "Iteration " << i << " in exact mode removed " << num << std::endl; + i++; + total_reduced += num; + } while (num != 0); + } else if (mode == 11) { + do { + num = reductionMine(true, 1); + num += reductionMine(false, 1); + cout << "Iteration " << i << " in heuristic removed " << num << std::endl; + i++; + total_reduced += num; + } while (num != 0); + do { + num = reductionExact(true); + num += reductionExact(false); + cout << "Iteration " << i << " in exact mode removed " << num << std::endl; + i++; + total_reduced += num; + } while (num != 0); + } else { + do{ + keepGoing = false; + if (mode == 6) { + // True means preprocess childrens' lists, removing families. + // False means preprocess families' lists, removing children. + num = reductionExact(false); + num += reductionExact(true); + } else if (mode == 8) { + num = reductionExact(true); + num += reductionExact(false); + } else if (mode == 9) { + num = reductionExact(false, true); + if (num == -1) { + num = 0; + keepGoing = true; + } + int nextNum = reductionExact(true, true); + if (nextNum == -1) { + nextNum = 0; + keepGoing = true; + } + num += nextNum; + } else if (mode == 10) { + num = reductionExact(true, true); + if (num == -1) { + num = 0; + keepGoing = true; + } + int nextNum = reductionExact(false, true); + if (nextNum == -1) { + nextNum = 0; + keepGoing = true; + } + num += nextNum; + } else if (mode == 13) { + num = reductionMine(false, 0, true); + num += reductionMine(true, 0, true); + } else if (mode == 14) { + num = reductionExact(false, false, true); + num += reductionExact(true, false, true); + } else if (mode == 15) { + num = reductionExact(true, false, true); + num += reductionExact(false, false, true); + } else { + num = reductionMine(false, mode); + num += reductionMine(true, mode); + } + cout << "Iteration " << i << " in mode " << mode << " removed " << num << std::endl; + i++; + total_reduced += num; + }while(keepGoing || (num != 0)); + } } void Allocation::printSol(){ @@ -557,7 +579,7 @@ void Allocation::printSol(){ void Allocation::printInfo(const string& pathAndFileout){ string nameFile = pathAndFileout; std::ofstream file(nameFile.c_str(), std::ios::out | std::ios::app); - file << name << "\t" << infos.opt << "\t" << infos.timeCPU << "\t" << infos.timeCPUPP << "\t"<< infos.LB << "\t" << infos.UB << "\t" << infos.altInfo << "\t" << infos.contUB << "\t" << infos.nbVar << "\t" << infos.nbCons << "\t" << infos.nbNZ + file << name << "\t" << infos.opt << "\t" << infos.timeCPU << "\t" << infos.timeCPUPP << "\t" << total_reduced << "\t" << infos.LB << "\t" << infos.UB << "\t" << infos.altInfo << "\t" << infos.contUB << "\t" << infos.nbVar << "\t" << infos.nbCons << "\t" << infos.nbNZ << "\t" << infos.contUB2 << "\t" << infos.nbVar2 << "\t" << infos.nbCons2 << "\t" << infos.nbNZ2 << endl; file.close(); } diff --git a/SMTI-GRP/4_YESBIN_1STA_YESMERGED/Allocation.h b/SMTI-GRP/4_YESBIN_1STA_YESMERGED/Allocation.h index 0077780..a1c1da0 100644 --- a/SMTI-GRP/4_YESBIN_1STA_YESMERGED/Allocation.h +++ b/SMTI-GRP/4_YESBIN_1STA_YESMERGED/Allocation.h @@ -4,6 +4,7 @@ using namespace std; #include #include +#include #include #include #include @@ -12,7 +13,7 @@ #include class Child; - class Family; + typedef Child Family; class Assignment; class Allocation; @@ -21,29 +22,15 @@ ************************************************************************************* */ class Child{ - public: - int id; - int nbPref; - int nbTotPref; - vector > preferences; - vector > ranks; - vector > positions; - void print(); - }; - -/* ************************************************************************************* - *********************************** HOSPITAL **************************************** - ************************************************************************************* */ - - class Family{ public: int id; int nbPref; int nbTotPref; + bool mustBeAllocated; vector > preferences; vector > ranks; vector > positions; - void print(); + void print(bool); }; /* ************************************************************************************* @@ -77,6 +64,7 @@ string name; int nbChildren; int nbFamilies; + int total_reduced; vector > grades; vector children; @@ -86,20 +74,21 @@ vector assignmentByChild; vector assignmentByFamily; + std::list childrenMustBeAllocated; + std::list familiesMustBeAllocated; + Info infos; void load(const string& path, const string& filein, const int& threshold); void printProb(); - int reductionFam1(); - int reductionChi1(); - int reductionFam2(); - int reductionChi2(); + int reductionMine(bool children_side=true, int mode=0, bool alt_store=false); + int reductionExact(bool children_side, bool supp=false, bool early_exit=false); void polish(); - void reduction(); + void reduction(int mode); void printSol(); void printInfo(const string& pathAndFileout); void checkSolution(); }; -#endif \ No newline at end of file +#endif diff --git a/SMTI-GRP/4_YESBIN_1STA_YESMERGED/Graph.cpp b/SMTI-GRP/4_YESBIN_1STA_YESMERGED/Graph.cpp new file mode 100644 index 0000000..028c15d --- /dev/null +++ b/SMTI-GRP/4_YESBIN_1STA_YESMERGED/Graph.cpp @@ -0,0 +1,107 @@ +#include +#include "Graph.h" + + +// Expected biggest graph, to save on allocations +const size_t expected_size = 4096; + +Graph::Graph() : _exists(2), _adjacents(2), _matching(2), _size(0), _matching_size(0) { + _exists[0] = std::vector(expected_size, false); + _exists[1] = std::vector(expected_size, false); + _adjacents[0] = std::vector>(expected_size); + _adjacents[1] = std::vector>(expected_size); + _matching[0] = std::vector(expected_size, -1); + _matching[1] = std::vector(expected_size, -1); +#ifdef DEBUG + std::cout << "New graph" << std::endl; +#endif /* DEBUG */ +} + +void Graph::addVertex(int side, int name) { + _exists[side][name] = true; + _size += 1; +} + +bool Graph::containsVertex(int side, int name) const { + return _exists[side][name]; +} + +/** + * Adds an edge to the graph. Note that this edge must always be added in the + * form (right, left) for things to work. + */ +void Graph::addEdge(int v1, int v2) { + _adjacents[1][v1].push_back(v2); + _adjacents[0][v2].push_back(v1); +} + +int Graph::size() const { + return _size; +} + +int Graph::matchingSize() const { + return _matching_size; +} + +/** + * Augment the matching, starting at vertex name which is on the right. + */ +void Graph::augment(int name) { +#ifdef DEBUG + std::cout << "Augmenting on " << _indices.at(start) << std::endl; + this->printGraph(); +#endif /* DEBUG */ + std::list path; + std::vector visited(expected_size, false); + path.push_back(name); + internal_augment(name, visited, path); +} + +/** + * Continues an augmentation, on vertex now, which is on the right. + */ +bool Graph::internal_augment(int now, std::vector & visited, + std::list & path) { + for(int next: _adjacents[1][now]) { + // next is on the left + if (visited[next]) { + continue; + } + if (_matching[0][next] == -1) { + // Found an augmenting path. Switch edges and return true. +#ifdef DEBUG + std::cout << "New matching found." << std::endl; +#endif /* DEBUG */ + path.push_back(next); +#ifdef DEBUG + std::cout << "Path is "; + for(auto p: path) { + std::cout << " " << _indices.at(p); + } + std::cout << std::endl; + +#endif /* DEBUG */ + while(!path.empty()) { + int right = path.front(); + path.pop_front(); + int left = path.front(); + path.pop_front(); + _matching[1][right] = left; + _matching[0][left] = right; + } + _matching_size += 1; + return true; + } + int next2 = _matching[0][next]; + path.push_back(next); + path.push_back(next2); + visited[next] = true; + if (internal_augment(next2, visited, path)) { + return true; + } + path.pop_back(); + path.pop_back(); + } + return false; +} + diff --git a/SMTI-GRP/4_YESBIN_1STA_YESMERGED/Graph.h b/SMTI-GRP/4_YESBIN_1STA_YESMERGED/Graph.h new file mode 100644 index 0000000..5d07f00 --- /dev/null +++ b/SMTI-GRP/4_YESBIN_1STA_YESMERGED/Graph.h @@ -0,0 +1,60 @@ +#ifndef GRAPH_H +#define GRAPH_H + +#include +#include +#include +#include +#include +#include + + +static_assert(std::numeric_limits::max() >= ((long unsigned)1 << 63), "size_t is too small"); + +struct pairhash { + public: + std::size_t operator()(const std::pair &x) const { + return (long)x.first * ((long)1 << 32) + x.second; + } +}; + +#ifdef DEBUG +#include +inline std::ostream& operator<<(std::ostream& o, const std::pair &x) { + o << "(" << x.first << ", " << x.second << ")"; + return o; +} +#endif /* DEBUG */ + + +class Graph { + public: + Graph(); + void addVertex(int side, int name); + bool containsVertex(int side, int name) const; + void addEdge(int v1, int v2); + int matched(int vertex) const; + void augment(int vertex); + + int size() const; + int matchingSize() const; + + int name(int vert_index); + +#ifdef DEBUG + void printGraph(); + void printMatching() const; +#endif /* DEBUG */ + + private: + std::vector> _exists; + std::vector>> _adjacents; + std::vector> _matching; + + int _size; + int _matching_size; + + bool internal_augment(int now, std::vector & visited, std::list & path); +}; + +#endif /* GRAPH_H */ diff --git a/SMTI-GRP/4_YESBIN_1STA_YESMERGED/main.cpp b/SMTI-GRP/4_YESBIN_1STA_YESMERGED/main.cpp index b211b18..b344036 100644 --- a/SMTI-GRP/4_YESBIN_1STA_YESMERGED/main.cpp +++ b/SMTI-GRP/4_YESBIN_1STA_YESMERGED/main.cpp @@ -1,5 +1,7 @@ #include "main.h" +#define MAXTIME 3600 + /* ************************************************************************************* ************************************* MAIN ***************************************** ************************************************************************************* */ @@ -8,31 +10,43 @@ int main(int argc, char **argv){ // local variables Allocation allo ; + allo.total_reduced = 0; string filein = argv[2]; string path = argv[1]; string pathAndFileout = argv[3]; int minGrade = atoi(argv[4]); + int mode = atoi(argv[5]); // functions allo.load(path,filein,minGrade); - allo.printProb(); + //allo.printProb(); - manlove(allo); - - allo.printSol(); - allo.checkSolution(); + int res = manlove(allo, mode); + if (res != -1) { + allo.printSol(); + allo.checkSolution(); + } allo.printInfo(pathAndFileout); } -int manlove(Allocation& allo){ +int manlove(Allocation& allo, int mode){ double initTimeModelCPU = getCPUTime(); GRBEnv env = GRBEnv(); double initTimeModelCPUPP = getCPUTime(); - allo.reduction(); - allo.printProb(); + if (mode != 12) { + allo.reduction(mode); + } + //allo.printProb(); allo.infos.timeCPUPP = getCPUTime() - initTimeModelCPUPP; + if (allo.infos.timeCPUPP > MAXTIME) { + cout << "Preprocessing took over " << MAXTIME << " seconds" << endl; + allo.infos.LB = 0; + allo.assignmentByChild.resize(allo.nbChildren, -1); + allo.assignmentByFamily.resize(allo.nbFamilies,-1); + return -1; + } // Model try{ @@ -127,7 +141,7 @@ int manlove(Allocation& allo){ } // Setting of Gurobi - model.getEnv().set(GRB_DoubleParam_TimeLimit, 3600 - (getCPUTime() - initTimeModelCPU)); + model.getEnv().set(GRB_DoubleParam_TimeLimit, MAXTIME - (getCPUTime() - initTimeModelCPU)); model.getEnv().set(GRB_IntParam_Threads, 1); model.getEnv().set(GRB_DoubleParam_MIPGap, 0); model.optimize(); diff --git a/SMTI-GRP/4_YESBIN_1STA_YESMERGED/main.h b/SMTI-GRP/4_YESBIN_1STA_YESMERGED/main.h index c441859..3bf5282 100644 --- a/SMTI-GRP/4_YESBIN_1STA_YESMERGED/main.h +++ b/SMTI-GRP/4_YESBIN_1STA_YESMERGED/main.h @@ -11,6 +11,6 @@ float EPSILON = 0.001; - int manlove(Allocation& allo); + int manlove(Allocation& allo, int reduction_mode); #endif diff --git a/SMTI-GRP/4_YESBIN_1STA_YESMERGED/makefile b/SMTI-GRP/4_YESBIN_1STA_YESMERGED/makefile index d362afe..0e198a3 100644 --- a/SMTI-GRP/4_YESBIN_1STA_YESMERGED/makefile +++ b/SMTI-GRP/4_YESBIN_1STA_YESMERGED/makefile @@ -8,14 +8,14 @@ CPPLIB = -L$(GUROBI_DIR)/lib/ -lgurobi_c++ $(CLIB) GUROBI_OPTS = -I$(INC) $(CPPLIB) -lpthread -lm -m64 CC = g++ -CFLAGS = -O2 -Wall -ansi -pedantic -DIL_STD +CFLAGS = -O2 -Wall -ansi -pedantic -DIL_STD -std=c++11 DEBUG = -pg -g -Wall -ansi -pedantic -DIL_STD -OBJECTS = main.o Allocation.o time.o +OBJECTS = main.o Allocation.o time.o AgentIterator.o Graph.o exec : $(OBJECTS) $(CC) $(CFLAGS) -o YESBIN_1STA_NOMERGED $(OBJECTS) $(GUROBI_OPTS) -.cpp.o : +.cpp.o : $< $(CC) $(CFLAGS) $(GUROBI_OPTS) -c $< -o $@ clean : diff --git a/SMTI-GRP/8_YESBIN_2STA_YESMERGED/AgentIterator.cpp b/SMTI-GRP/8_YESBIN_2STA_YESMERGED/AgentIterator.cpp new file mode 100644 index 0000000..6210288 --- /dev/null +++ b/SMTI-GRP/8_YESBIN_2STA_YESMERGED/AgentIterator.cpp @@ -0,0 +1,402 @@ +#include "AgentIterator.h" + +AgentIteratorBase::AgentIteratorBase(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group, int posn) : + _agent(agent), + _these(these), _other(other), + _positions(positions), _candidates(candidates) { + if (_agent.preferences.size() == 0) { + _group = -1; + } else { + _group = group; + } + _position = posn; +} + +AgentIteratorBase::~AgentIteratorBase() { } + +int AgentIteratorBase::get_group() const { + return _group; +} + +int AgentIteratorBase::get_position() const { + return _position; +} + +const Child & AgentIteratorBase::get_agent() const { + return _agent; +} + +const std::vector & AgentIteratorBase::get_these() const { + return _these; +} + +const std::vector & AgentIteratorBase::get_other() const { + return _other; +} +const std::set & AgentIteratorBase::get_positions() const { + return _positions; +} +const std::set & AgentIteratorBase::get_candidates() const { + return _candidates; +} + +void AgentIteratorBase::regularIncrement() { + _position++; + if (_agent.preferences[_group].size() == _position) { + _position = 0; + _group++; + if (_agent.preferences.size() == _group) { + _group = -1; + } + } +} + +bool AgentIterator::operator==(const AgentIterator & other) { + return get_group() == other.get_group() && get_position() == other.get_position(); +} + +bool AgentIterator::operator!=(const AgentIterator & other) { + return ! (*this == other); +} + +const std::pair AgentIterator::operator*() { + return std::pair(get_group(), get_position()); +} + +AgentIterator AgentIterator::begin() { + AgentIterator starter(this, 0, 0); + starter.base->begin(); + return starter; +} + +AgentIterator AgentIterator::end() { + return AgentIterator(this, -1, 0); +} + +AgentIterator::AgentIterator(const Child & agent, const std::set & candidates, const std::set & positions, + const std::vector & these, const std::vector & other, int mode) : + _mode(mode) { + switch (_mode) { + default: + case 0: + base = new DescendingIterator(agent, candidates, positions, these, other, 0, 0); + break; + case 1: + base = new SkipBigIterator(agent, candidates, positions, these, other, 5, 0, 0); + break; + case 2: + base = new BestIterator(agent, candidates, positions, these, other, 0, 0); + break; + case 3: + base = new SkipBigIterator(agent, candidates, positions, these, other, 15, 0, 0); + break; + case 4: + base = new SkipBigIterator(agent, candidates, positions, these, other, 50, 0, 0); + break; + case 5: + base = new BestGroupIterator(agent, candidates, positions, these, other, 0, 0); + break; + } + } + +AgentIterator::AgentIterator(AgentIterator *other) : + _mode(other->get_mode()) { + switch (_mode) { + default: + case 0: + base = new DescendingIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), other->get_group(), other->get_position()); + break; + case 1: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 5, other->get_group(), other->get_position()); + break; + case 2: + base = new BestIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), other->get_group(), other->get_position()); + break; + case 3: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 15, other->get_group(), other->get_position()); + break; + case 4: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 50, other->get_group(), other->get_position()); + break; + case 5: + base = new BestGroupIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), other->get_group(), other->get_position()); + break; + } + } + +AgentIterator::AgentIterator(AgentIterator *other, int group, int posn) : + _mode(other->get_mode()) { + switch (_mode) { + case 0: + base = new DescendingIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), group, posn); + break; + case 1: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 5, group, posn); + break; + case 2: + base = new BestIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), group, posn); + break; + case 3: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 15, group, posn); + break; + case 4: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 50, group, posn); + break; + case 5: + base = new BestGroupIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), group, posn); + break; + } + } + +AgentIterator::~AgentIterator() { + delete base; +} + +int AgentIterator::get_group() const { + return base->get_group(); +} + +int AgentIterator::get_position() const { + return base->get_position(); +} + +int AgentIterator::get_mode() const { + return _mode; +} + +DescendingIterator::DescendingIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group, int posn) : + AgentIteratorBase(agent, candidates, positions, these, other, group, posn) { + } + +void DescendingIterator::begin() { +} + +void DescendingIterator::increment() { + regularIncrement(); +} + +SkipBigIterator::SkipBigIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int skip, int group, int posn) : + AgentIteratorBase(agent, candidates, positions, these, other, group, posn) , _skip(skip) { + } + + +void SkipBigIterator::begin() { + int num_added = 0; + while (true) { + if (get_group() == -1) { + break; + } + num_added = 0; + int other_id = _agent.preferences[_group][_position]; + int other_rank = _agent.ranks[_group][_position]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(pref) == 0) { + num_added++; + } + } + } + if (num_added > _skip) { + regularIncrement(); + } else { + break; + } + } +} + +void SkipBigIterator::increment() { + int num_added = 0; + do { + regularIncrement(); + if (get_group() == -1) { + break; + } + num_added = 0; + int other_id = _agent.preferences[_group][_position]; + int other_rank = _agent.ranks[_group][_position]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(pref) == 0) { + num_added++; + } + } + } + } while (num_added > _skip); +} + +BestIterator::BestIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group, int posn) : + AgentIteratorBase(agent, candidates, positions, these, other, group, posn) { + } + +void BestIterator::increment() { + int lowest_added = -1; + int best_group = -1; + int best_posn = -1; + for(int group_no = 0; group_no < _agent.preferences.size(); ++group_no) { + auto & group = _agent.preferences[group_no]; + for(int posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + int other_rank = _agent.ranks[group_no][posn]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto other_pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(other_pref) == 0) { + num_added++; + } + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_group = group_no; + best_posn = posn; + } + } + } + if (lowest_added != -1) { + _group = best_group; + _position = best_posn; + } else { + _group = -1; + _position = 0; + } +} + +void BestIterator::begin() { + int lowest_added = -1; + int best_group = -1; + int best_posn = -1; + for(int group_no = 0; group_no < _agent.preferences.size(); ++group_no) { + auto & group = _agent.preferences[group_no]; + for(int posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + int other_rank = _agent.ranks[group_no][posn]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto other_pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(other_pref) == 0) { + num_added++; + } + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_group = group_no; + best_posn = posn; + } + } + } + if (lowest_added != -1) { + _group = best_group; + _position = best_posn; + } else { + _group = -1; + _position = 0; + } +} + +BestGroupIterator::BestGroupIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group, int posn) : + AgentIteratorBase(agent, candidates, positions, these, other, group, posn) { + } + +void BestGroupIterator::increment() { + int lowest_added = -1; + int best_posn = -1; + auto & group = _agent.preferences[_group]; + for(int posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + int other_rank = _agent.ranks[_group][posn]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto other_pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(other_pref) == 0) { + num_added++; + } + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_posn = posn; + } + } + if (lowest_added != -1) { + _position = best_posn; + } else { + _group++; + if (_group == _agent.preferences.size()) { + _position = 0; + _group = -1; + } else { + increment(); + } + } +} + +void BestGroupIterator::begin() { + int lowest_added = -1; + int best_posn = -1; + if (_group == -1) { + return; + } + auto & group = _agent.preferences[_group]; + for(int posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + int other_rank = _agent.ranks[_group][posn]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto other_pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(other_pref) == 0) { + num_added++; + } + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_posn = posn; + } + } + if (lowest_added != -1) { + _position = best_posn; + } else { + _group++; + if (_group == _agent.preferences.size()) { + _position = 0; + _group = -1; + } else { + increment(); + } + } +} diff --git a/SMTI-GRP/8_YESBIN_2STA_YESMERGED/AgentIterator.h b/SMTI-GRP/8_YESBIN_2STA_YESMERGED/AgentIterator.h new file mode 100644 index 0000000..48b96c6 --- /dev/null +++ b/SMTI-GRP/8_YESBIN_2STA_YESMERGED/AgentIterator.h @@ -0,0 +1,110 @@ +#ifndef AGENTITERATOR_H +#define AGENTITERATOR_H + +#include + +#include "Allocation.h" + +class AgentIteratorBase { +public: + AgentIteratorBase(const Child & agent, const std::set & candidates, const std::set & positions, + const std::vector & these, const std::vector & other, int group=0, int posn=0); + virtual ~AgentIteratorBase() = 0; + virtual void increment() = 0; + virtual void begin() = 0; + + int get_position() const; + int get_group() const; + const Child & get_agent() const; + const std::vector & get_these() const; + const std::vector & get_other() const; + const std::set & get_positions() const; + const std::set & get_candidates() const; +protected: + void regularIncrement(); + + const Child & _agent; + int _group; + int _position; + const std::vector & _these; + const std::vector & _other; + const std::set & _positions; + const std::set & _candidates; +}; + + +class AgentIterator : public std::iterator, ptrdiff_t> { +public: + AgentIterator(const Child & agent, const std::set & candidates, const std::set & positions, + const std::vector & these, const std::vector & other, int mode); + AgentIterator(AgentIterator *other, int group, int posn); + AgentIterator(AgentIterator *other); + ~AgentIterator(); + bool operator==(const AgentIterator& other); + bool operator!=(const AgentIterator& other); + const std::pair operator*(); + AgentIterator& operator++() {base->increment(); return *this; } + AgentIterator operator++(int) {AgentIterator res(this); base->increment(); return res; } + + AgentIterator begin(); + AgentIterator end(); + + int get_position() const; + int get_group() const; + int get_mode() const; + + const Child & get_agent() const { return base->get_agent(); } + const std::vector & get_these() const {return base->get_these(); } + const std::vector & get_other() const {return base->get_other(); } + const std::set & get_positions() const {return base->get_positions(); } + const std::set & get_candidates() const {return base->get_candidates(); } +private: + AgentIteratorBase * base; + int _mode; +}; + + +class DescendingIterator : public AgentIteratorBase { + public: + DescendingIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group=0, int posn=0); + ~DescendingIterator() {} + void increment(); + void begin(); +}; + + +class SkipBigIterator : public AgentIteratorBase { + public: + SkipBigIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int skip, int group, int posn); + ~SkipBigIterator() {} + void increment(); + void begin(); + private: + int _skip; +}; + +class BestIterator : public AgentIteratorBase { + public: + BestIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group=0, int posn=0); + ~BestIterator() {} + void increment(); + void begin(); +}; + +class BestGroupIterator : public AgentIteratorBase { + public: + BestGroupIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group=0, int posn=0); + ~BestGroupIterator() {} + void increment(); + void begin(); +}; + +#endif /* AGENTITERATOR_H */ diff --git a/SMTI-GRP/8_YESBIN_2STA_YESMERGED/Allocation.cpp b/SMTI-GRP/8_YESBIN_2STA_YESMERGED/Allocation.cpp index 9d5dec4..7a50885 100644 --- a/SMTI-GRP/8_YESBIN_2STA_YESMERGED/Allocation.cpp +++ b/SMTI-GRP/8_YESBIN_2STA_YESMERGED/Allocation.cpp @@ -1,29 +1,17 @@ #include "Allocation.h" +#include "AgentIterator.h" +#include "Graph.h" /* ************************************************************************************* *********************************** DOCTOR ***************************************** ************************************************************************************* */ -void Child::print(){ - cout << "Child " << id << "\t Preferences (" << nbPref << " groups, " << nbTotPref << " in total)\t"; - for(int i=0; i 0) cout << " "; - cout << preferences[i][j]; - cout << "[" << ranks[i][j] << "_" << positions[i][j] << "]"; - } - cout << ") "; - } - cout << endl; -} - -/* ************************************************************************************* - *********************************** HOSPITAL **************************************** - ************************************************************************************* */ - -void Family::print(){ - cout << "Family " << id << "\t Preferences (" << nbPref << " groups, " << nbTotPref << " in total)\t"; +void Child::print(bool family){ + if (family) + cout << "Family "; + else + cout << "Child "; + cout << id << "\t Preferences (" << nbPref << " groups, " << nbTotPref << " in total)\t"; for(int i=0; i= threshold) grade.insert(grades[i][j]); } - Family f; f.id = i; f.nbPref = grade.size(); f.nbTotPref = 0; f.preferences.resize(f.nbPref); f.ranks.resize(f.nbPref); f.positions.resize(f.nbPref); + Family f; f.id = i; f.nbPref = grade.size(); f.nbTotPref = 0; f.preferences.resize(f.nbPref); f.ranks.resize(f.nbPref); f.positions.resize(f.nbPref); + f.mustBeAllocated = false; vector gradeVector(grade.begin(), grade.end()); reverse(gradeVector.begin(),gradeVector.end()); for (int j = 0; j < nbChildren; j++){ @@ -111,7 +100,8 @@ void Allocation::load(const string& path, const string& filein, const int& thres for (int j = 0; j < nbFamilies; j++){ if(grades[j][i] >= threshold) grade.insert(grades[j][i]); } - Child c; c.id = i; c.nbPref = grade.size(); c.nbTotPref = 0; c.preferences.resize(c.nbPref); c.ranks.resize(c.nbPref); c.positions.resize(c.nbPref); + Child c; c.id = i; c.nbPref = grade.size(); c.nbTotPref = 0; c.preferences.resize(c.nbPref); c.ranks.resize(c.nbPref); c.positions.resize(c.nbPref); + c.mustBeAllocated = false; vector gradeVector(grade.begin(), grade.end()); reverse(gradeVector.begin(),gradeVector.end()); for (int j = 0; j < nbFamilies; j++){ @@ -156,320 +146,278 @@ void Allocation::load(const string& path, const string& filein, const int& thres void Allocation::printProb(){ cout << "Instance " << name << endl; for(int i=0; i, vector >::iterator it; - map, vector > mapFirstChoice; - for(int j=0; j temp(nbChildren,0); - if(families[j].nbPref > 0){ - for(int k=0;k, vector > add; - add.first = temp; - add.second.push_back(j); - mapFirstChoice.insert(add); - } - else{ - (*it).second.push_back(j); - } - } - else count++; - } - -/* for(it = mapFirstChoice.begin(); it!= mapFirstChoice.end(); ++it){ - cout << (*it).second.size() << " x (" << families[(*it).second[0]].preferences[0].size() << ") ["; - for(int i=0;i<(*it).second.size();i++){ - cout << (*it).second[i] << " "; - } - cout << "] == ["; - for(int i=0;i<(*it).first.size();i++){ - cout << (*it).first[i] << " "; - } - cout << "]" << endl; - } - - cout << "Count = " << count << endl;*/ - - // Step 2 -- See worst rank - - vector worstRank(nbChildren); - for(int i=0;i= families[(*it).second[0]].preferences[0].size() ){ - // cout << "Updates from " << co << endl;; co++; - for(int i=0; i < families[(*it).second[0]].preferences[0].size();i++){ - multiset orderedRanks; - multiset::iterator it2; - for(int j=0; j<(*it).second.size();j++){ - orderedRanks.insert(families[(*it).second[j]].ranks[0][i]); - } - // cout << "worstRank of " << families[(*it).second[0]].preferences[0][i] << " updated from " << worstRank[families[(*it).second[0]].preferences[0][i]]; - it2 = orderedRanks.begin(); - advance(it2, families[(*it).second[0]].preferences[0].size() - 1); - worstRank[families[(*it).second[0]].preferences[0][i]]=min(worstRank[families[(*it).second[0]].preferences[0][i]], *(it2)); - // cout << " to " << worstRank[families[(*it).second[0]].preferences[0][i]] << endl; - } - } - } - - // Step 3 -- Remove families after worst rank from child's preferences - +int Allocation::reductionExact(bool children_side, bool supp, bool early_exit) { int nbTotRem = 0; - - for(int i=0; i * thesep; + std::vector * otherp; + std::list *theseMustBeAllocatedp; + std::list *otherMustBeAllocatedp; + if (children_side) { + // Processing the lists of the children, removing families + thesep = &children; + otherp = &families; + theseMustBeAllocatedp = &childrenMustBeAllocated; + otherMustBeAllocatedp = &familiesMustBeAllocated; + number_here = nbChildren; + } else { + thesep = &families; + otherp = &children; + theseMustBeAllocatedp = &familiesMustBeAllocated; + otherMustBeAllocatedp = &childrenMustBeAllocated; + number_here = nbFamilies; + } + std::vector & these = (*thesep); + std::vector & other = (*otherp); + std::list & theseMustBeAllocated = (*theseMustBeAllocatedp); + std::list & otherMustBeAllocated = (*otherMustBeAllocatedp); + for (int i = 0; i < number_here; i++) { + // Early exit! + const float ratio = 0.1; + if (early_exit && (i >= ratio * number_here) && (nbTotRem == 0)) { + return 0; } - children[i].nbPref = worstRank[i] + 1; - children[i].preferences.resize(children[i].nbPref); - children[i].ranks.resize(children[i].nbPref); - children[i].positions.resize(children[i].nbPref); - } - - polish(); - return nbTotRem; -} - -int Allocation::reductionChi1(){ - - // Step 1 -- Create map - - int count = 0; - map, vector >::iterator it; - map, vector > mapFirstChoice; - for(int j=0; j temp(nbFamilies,0); - if(children[j].nbPref > 0){ - for(int k=0;k, vector > add; - add.first = temp; - add.second.push_back(j); - mapFirstChoice.insert(add); - } - else{ - (*it).second.push_back(j); + // A graph is "named" with two integers. The first is a 0 for a candidate + // (aka these) or a 1 for a position (aka other) + Graph g; + int n_1 = 0; + for(int rank = 0; rank < these[i].nbPref; rank++) { + // No point in checking the last rank if we already know this agent must + // be allocated, or if we don't care + if ((rank == these[i].nbPref - 1) && (these[i].mustBeAllocated || !supp)) { + continue; } - } - else count++; - } - -/* for(it = mapFirstChoice.begin(); it!= mapFirstChoice.end(); ++it){ - cout << (*it).second.size() << " x (" << children[(*it).second[0]].preferences[0].size() << ") ["; - for(int i=0;i<(*it).second.size();i++){ - cout << (*it).second[i] << " "; - } - cout << "] == ["; - for(int i=0;i<(*it).first.size();i++){ - cout << (*it).first[i] << " "; - } - cout << "]" << endl; - } - - cout << "Count = " << count << endl;*/ - - // Step 2 -- See worst rank - - vector worstRank(nbFamilies); - for(int i=0;i= children[(*it).second[0]].preferences[0].size() ){ - // cout << "Updates from " << co << endl;; co++; - for(int i=0; i < children[(*it).second[0]].preferences[0].size();i++){ - multiset orderedRanks; - multiset::iterator it2; - for(int j=0; j<(*it).second.size();j++){ - orderedRanks.insert(children[(*it).second[j]].ranks[0][i]); + for(size_t ind = 0; ind < these[i].preferences[rank].size(); ind++) { + int position = these[i].preferences[rank][ind]; + g.addVertex(1, position); + int idxRank = these[i].ranks[rank][ind]; + for(int l = 0; l <= idxRank; l++) { + for(size_t k = 0; k < other[position].preferences[l].size(); k++) { + int other_cand = other[position].preferences[l][k]; + if (other_cand == i) { // Don't add the current candidate to the graph + continue; + } + if (! g.containsVertex(0, other_cand)) { + g.addVertex(0, other_cand); + n_1 += 1; + } + g.addEdge(position, other_cand); + } } - // cout << "worstRank of " << children[(*it).second[0]].preferences[0][i] << " updated from " << worstRank[children[(*it).second[0]].preferences[0][i]]; - it2 = orderedRanks.begin(); - advance(it2, children[(*it).second[0]].preferences[0].size() - 1); - worstRank[children[(*it).second[0]].preferences[0][i]]=min(worstRank[children[(*it).second[0]].preferences[0][i]], *(it2)); - // cout << " to " << worstRank[children[(*it).second[0]].preferences[0][i]] << endl; } - } - } - - // Step 3 -- Remove families after worst rank from child's preferences - - int nbTotRem = 0; - - for(int i=0; i worstRank(nbChildren); - for(int i=0;i allChildren; - int count = 0; - for(int j=0; j= n_1 + 1)) { + break; } - } - if(count >= allChildren.size()){ - worstRank[i] = j; - // cout << "worst rank of " << i << " is " << j << endl; + // First add all positions that must be filled. + for(int position: otherMustBeAllocated) { + // If position is acceptable to i, then skip it. + bool isAcceptable = false; + for(int otherRank = 0; (!isAcceptable) && otherRank < other[position].nbPref; otherRank++) { + for(size_t ind = 0; ind < other[position].preferences[otherRank].size(); ++ind) { + if (other[position].preferences[otherRank][ind] == i) { + isAcceptable = true; + break; + } + } + } + if (isAcceptable) { + continue; + } + g.addVertex(1, position); + for(int otherRank = 0; otherRank < other[position].nbPref; otherRank++) { + for(size_t ind = 0; ind < other[position].preferences[otherRank].size(); ++ind) { + int candidate = other[position].preferences[otherRank][ind]; + if (!g.containsVertex(0, candidate)) { + g.addVertex(0, candidate); + n_1 += 1; + } + g.addEdge(position, candidate); + } + } + g.augment(position); + } + // I'm using a while loop as an if statement, so I need to break out. break; } - } - } - - for(int i=0; i= n_1 + 1)) { + // preprocess on rank! + // Firstly, they must be allocated, so mark as such (if we're in that + // mode) + if (supp && !these[i].mustBeAllocated) { + theseMustBeAllocated.push_back(i); + these[i].mustBeAllocated = true; + newMustAlways = true; + } +#ifdef DEBUG + if ((!children_side) and (i == 6)) { + std::cout << "g.size() = " << g.size() << ", g.matchingSize() = " << g.matchingSize(); + std::cout << ", n_1 = " << n_1 << std::endl; + g.printGraph(); + g.printMatching(); + } + if (children_side) { + std::cout << "child "; + } else { + std::cout << "family "; } - families[idxFam].nbTotPref--; - families[idxFam].positions[idxRank].erase(families[idxFam].positions[idxRank].begin() + idxPos); - families[idxFam].ranks[idxRank].erase(families[idxFam].ranks[idxRank].begin() + idxPos); - families[idxFam].preferences[idxRank].erase(families[idxFam].preferences[idxRank].begin() + idxPos); + std::cout << "worst rank of " << i << " is " << rank << " "; + int remHere = 0; +#endif /* DEBUG */ + for (int k = rank + 1; k < these[i].nbPref; k++) { + nbTotRem += these[i].preferences[k].size(); +#ifdef DEBUG + remHere += these[i].preferences[k].size(); +#endif /* DEBUG */ + these[i].nbTotPref -= these[i].preferences[k].size(); + for (unsigned int l = 0; l < these[i].preferences[k].size(); l++) { + int idxFam = these[i].preferences[k][l]; + int idxPos = these[i].positions[k][l]; + int idxRank = these[i].ranks[k][l]; + for (unsigned int m = idxPos + 1; + m < other[idxFam].preferences[idxRank].size(); m++) { + these[other[idxFam].preferences[idxRank][m]] + .positions[other[idxFam].ranks[idxRank][m]] + [other[idxFam].positions[idxRank][m]]--; + } + other[idxFam].nbTotPref--; + other[idxFam].positions[idxRank].erase( + other[idxFam].positions[idxRank].begin() + idxPos); + other[idxFam].ranks[idxRank].erase( + other[idxFam].ranks[idxRank].begin() + idxPos); + other[idxFam].preferences[idxRank].erase( + other[idxFam].preferences[idxRank].begin() + idxPos); + } + } + these[i].nbPref = rank + 1; + these[i].preferences.resize(these[i].nbPref); + these[i].ranks.resize(these[i].nbPref); + these[i].positions.resize(these[i].nbPref); +#ifdef DEBUG + std::cout << "removed " << remHere << std::endl; +#endif /* DEBUG */ + break; } } - children[i].nbPref = worstRank[i] + 1; - children[i].preferences.resize(children[i].nbPref); - children[i].ranks.resize(children[i].nbPref); - children[i].positions.resize(children[i].nbPref); } - - polish(); + if (nbTotRem > 0) { + polish(); + } + if ((nbTotRem == 0) && (newMustAlways)) { + return -1; + } return nbTotRem; } -int Allocation::reductionChi2(){ - +int Allocation::reductionMine(bool children_side, int mode, bool alt_store) { int nbTotRem = 0; - vector worstRank(nbFamilies); - for(int i=0;i allFamilies; + int number_here; + std::vector * thesep; + std::vector * otherp; + if (children_side) { + thesep = &children; + otherp = &families; + number_here = nbChildren; + } else { + thesep = &families; + otherp = &children; + number_here = nbFamilies; + } + std::vector & these = (*thesep); + std::vector & other = (*otherp); + + for (int i = 0; i < number_here; i++) { + set candidates; + set positions; + vector cand_in(number_here, false); + int cand_size = 0; + int worst_rank = 0; int count = 0; - for(int j=0; j p: iter) { + int j = p.first; + int k = p.second; + if (j > worst_rank) { + worst_rank = j; + } + int idxFam = these[i].preferences[j][k]; + int idxRank = these[i].ranks[j][k]; + positions.insert(idxFam); + count++; + for (int l = 0; l <= idxRank; l++) { + for (unsigned int m = 0; m < other[idxFam].preferences[l].size(); + m++) { + if ((alt_store && cand_in[other[idxFam].preferences[l][m]] == false) || + (!alt_store && candidates.count(other[idxFam].preferences[l][m]) == 0)) { + candidates.insert(other[idxFam].preferences[l][m]); + cand_in[other[idxFam].preferences[l][m]] = true; + cand_size++; + } } } - if(count >= allFamilies.size()){ - worstRank[i] = j; - // cout << "worst rank of " << i << " is " << j << endl; + if (count >= cand_size) { +#ifdef DEBUG + if (children_side) { + std::cout << "child "; + } else { + std::cout << "family "; + } + std::cout << "worst rank of " << i << " is " << worst_rank << std::endl; +#endif /* DEBUG */ + for (int k = worst_rank + 1; k < these[i].nbPref; k++) { + nbTotRem += these[i].preferences[k].size(); + these[i].nbTotPref -= these[i].preferences[k].size(); + for (unsigned int l = 0; l < these[i].preferences[k].size(); l++) { + int idxFam = these[i].preferences[k][l]; + int idxPos = these[i].positions[k][l]; + int idxRank = these[i].ranks[k][l]; + for (unsigned int m = idxPos + 1; + m < other[idxFam].preferences[idxRank].size(); m++) { + these[other[idxFam].preferences[idxRank][m]] + .positions[other[idxFam].ranks[idxRank][m]] + [other[idxFam].positions[idxRank][m]]--; + } + other[idxFam].nbTotPref--; + other[idxFam].positions[idxRank].erase( + other[idxFam].positions[idxRank].begin() + idxPos); + other[idxFam].ranks[idxRank].erase( + other[idxFam].ranks[idxRank].begin() + idxPos); + other[idxFam].preferences[idxRank].erase( + other[idxFam].preferences[idxRank].begin() + idxPos); + } + } + these[i].nbPref = worst_rank + 1; + these[i].preferences.resize(these[i].nbPref); + these[i].ranks.resize(these[i].nbPref); + these[i].positions.resize(these[i].nbPref); break; } } } - - for(int i=0; i 0) { + polish(); } - - polish(); return nbTotRem; } @@ -531,20 +479,94 @@ void Allocation::polish(){ } } -void Allocation::reduction(){ - int nbRed1 = 0; - int nbRed2 = 0; - int nbRed3 = 0; - int nbRed4 = 0; +void Allocation::reduction(int mode){ + total_reduced = 0; int i = 0; - do{ - nbRed1 = reductionFam1(); - nbRed2 = reductionChi1(); - nbRed3 = reductionFam2(); - nbRed4 = reductionChi2(); - cout << "Reduction iteration " << i << " reductionFam1 " << nbRed1 << " reductionChi1 " << nbRed2 << " reductionFam2 " << nbRed3 << " reductionChi2 " << nbRed4 << endl; - i++; - }while(nbRed1 + nbRed2 + nbRed3 + nbRed4 != 0); + int num = 0; + bool keepGoing; + if (mode == 7) { + do { + num = reductionMine(false, 1); + num += reductionMine(true, 1); + cout << "Iteration " << i << " in heuristic removed " << num << std::endl; + i++; + total_reduced += num; + } while (num != 0); + do { + num = reductionExact(false); + num += reductionExact(true); + cout << "Iteration " << i << " in exact mode removed " << num << std::endl; + i++; + total_reduced += num; + } while (num != 0); + } else if (mode == 11) { + do { + num = reductionMine(true, 1); + num += reductionMine(false, 1); + cout << "Iteration " << i << " in heuristic removed " << num << std::endl; + i++; + total_reduced += num; + } while (num != 0); + do { + num = reductionExact(true); + num += reductionExact(false); + cout << "Iteration " << i << " in exact mode removed " << num << std::endl; + i++; + total_reduced += num; + } while (num != 0); + } else { + do{ + keepGoing = false; + if (mode == 6) { + // True means preprocess childrens' lists, removing families. + // False means preprocess families' lists, removing children. + num = reductionExact(false); + num += reductionExact(true); + } else if (mode == 8) { + num = reductionExact(true); + num += reductionExact(false); + } else if (mode == 9) { + num = reductionExact(false, true); + if (num == -1) { + num = 0; + keepGoing = true; + } + int nextNum = reductionExact(true, true); + if (nextNum == -1) { + nextNum = 0; + keepGoing = true; + } + num += nextNum; + } else if (mode == 10) { + num = reductionExact(true, true); + if (num == -1) { + num = 0; + keepGoing = true; + } + int nextNum = reductionExact(false, true); + if (nextNum == -1) { + nextNum = 0; + keepGoing = true; + } + num += nextNum; + } else if (mode == 13) { + num = reductionMine(false, 0, true); + num += reductionMine(true, 0, true); + } else if (mode == 14) { + num = reductionExact(false, false, true); + num += reductionExact(true, false, true); + } else if (mode == 15) { + num = reductionExact(true, false, true); + num += reductionExact(false, false, true); + } else { + num = reductionMine(false, mode); + num += reductionMine(true, mode); + } + cout << "Iteration " << i << " in mode " << mode << " removed " << num << std::endl; + i++; + total_reduced += num; + }while(keepGoing || (num != 0)); + } } void Allocation::printSol(){ @@ -557,7 +579,7 @@ void Allocation::printSol(){ void Allocation::printInfo(const string& pathAndFileout){ string nameFile = pathAndFileout; std::ofstream file(nameFile.c_str(), std::ios::out | std::ios::app); - file << name << "\t" << infos.opt << "\t" << infos.timeCPU << "\t" << infos.timeCPUPP << "\t"<< infos.LB << "\t" << infos.UB << "\t" << infos.altInfo << "\t" << infos.contUB << "\t" << infos.nbVar << "\t" << infos.nbCons << "\t" << infos.nbNZ + file << name << "\t" << infos.opt << "\t" << infos.timeCPU << "\t" << infos.timeCPUPP << "\t" << total_reduced << "\t" << infos.LB << "\t" << infos.UB << "\t" << infos.altInfo << "\t" << infos.contUB << "\t" << infos.nbVar << "\t" << infos.nbCons << "\t" << infos.nbNZ << "\t" << infos.contUB2 << "\t" << infos.nbVar2 << "\t" << infos.nbCons2 << "\t" << infos.nbNZ2 << endl; file.close(); } diff --git a/SMTI-GRP/8_YESBIN_2STA_YESMERGED/Allocation.h b/SMTI-GRP/8_YESBIN_2STA_YESMERGED/Allocation.h index 0077780..a1c1da0 100644 --- a/SMTI-GRP/8_YESBIN_2STA_YESMERGED/Allocation.h +++ b/SMTI-GRP/8_YESBIN_2STA_YESMERGED/Allocation.h @@ -4,6 +4,7 @@ using namespace std; #include #include +#include #include #include #include @@ -12,7 +13,7 @@ #include class Child; - class Family; + typedef Child Family; class Assignment; class Allocation; @@ -21,29 +22,15 @@ ************************************************************************************* */ class Child{ - public: - int id; - int nbPref; - int nbTotPref; - vector > preferences; - vector > ranks; - vector > positions; - void print(); - }; - -/* ************************************************************************************* - *********************************** HOSPITAL **************************************** - ************************************************************************************* */ - - class Family{ public: int id; int nbPref; int nbTotPref; + bool mustBeAllocated; vector > preferences; vector > ranks; vector > positions; - void print(); + void print(bool); }; /* ************************************************************************************* @@ -77,6 +64,7 @@ string name; int nbChildren; int nbFamilies; + int total_reduced; vector > grades; vector children; @@ -86,20 +74,21 @@ vector assignmentByChild; vector assignmentByFamily; + std::list childrenMustBeAllocated; + std::list familiesMustBeAllocated; + Info infos; void load(const string& path, const string& filein, const int& threshold); void printProb(); - int reductionFam1(); - int reductionChi1(); - int reductionFam2(); - int reductionChi2(); + int reductionMine(bool children_side=true, int mode=0, bool alt_store=false); + int reductionExact(bool children_side, bool supp=false, bool early_exit=false); void polish(); - void reduction(); + void reduction(int mode); void printSol(); void printInfo(const string& pathAndFileout); void checkSolution(); }; -#endif \ No newline at end of file +#endif diff --git a/SMTI-GRP/8_YESBIN_2STA_YESMERGED/Graph.cpp b/SMTI-GRP/8_YESBIN_2STA_YESMERGED/Graph.cpp new file mode 100644 index 0000000..028c15d --- /dev/null +++ b/SMTI-GRP/8_YESBIN_2STA_YESMERGED/Graph.cpp @@ -0,0 +1,107 @@ +#include +#include "Graph.h" + + +// Expected biggest graph, to save on allocations +const size_t expected_size = 4096; + +Graph::Graph() : _exists(2), _adjacents(2), _matching(2), _size(0), _matching_size(0) { + _exists[0] = std::vector(expected_size, false); + _exists[1] = std::vector(expected_size, false); + _adjacents[0] = std::vector>(expected_size); + _adjacents[1] = std::vector>(expected_size); + _matching[0] = std::vector(expected_size, -1); + _matching[1] = std::vector(expected_size, -1); +#ifdef DEBUG + std::cout << "New graph" << std::endl; +#endif /* DEBUG */ +} + +void Graph::addVertex(int side, int name) { + _exists[side][name] = true; + _size += 1; +} + +bool Graph::containsVertex(int side, int name) const { + return _exists[side][name]; +} + +/** + * Adds an edge to the graph. Note that this edge must always be added in the + * form (right, left) for things to work. + */ +void Graph::addEdge(int v1, int v2) { + _adjacents[1][v1].push_back(v2); + _adjacents[0][v2].push_back(v1); +} + +int Graph::size() const { + return _size; +} + +int Graph::matchingSize() const { + return _matching_size; +} + +/** + * Augment the matching, starting at vertex name which is on the right. + */ +void Graph::augment(int name) { +#ifdef DEBUG + std::cout << "Augmenting on " << _indices.at(start) << std::endl; + this->printGraph(); +#endif /* DEBUG */ + std::list path; + std::vector visited(expected_size, false); + path.push_back(name); + internal_augment(name, visited, path); +} + +/** + * Continues an augmentation, on vertex now, which is on the right. + */ +bool Graph::internal_augment(int now, std::vector & visited, + std::list & path) { + for(int next: _adjacents[1][now]) { + // next is on the left + if (visited[next]) { + continue; + } + if (_matching[0][next] == -1) { + // Found an augmenting path. Switch edges and return true. +#ifdef DEBUG + std::cout << "New matching found." << std::endl; +#endif /* DEBUG */ + path.push_back(next); +#ifdef DEBUG + std::cout << "Path is "; + for(auto p: path) { + std::cout << " " << _indices.at(p); + } + std::cout << std::endl; + +#endif /* DEBUG */ + while(!path.empty()) { + int right = path.front(); + path.pop_front(); + int left = path.front(); + path.pop_front(); + _matching[1][right] = left; + _matching[0][left] = right; + } + _matching_size += 1; + return true; + } + int next2 = _matching[0][next]; + path.push_back(next); + path.push_back(next2); + visited[next] = true; + if (internal_augment(next2, visited, path)) { + return true; + } + path.pop_back(); + path.pop_back(); + } + return false; +} + diff --git a/SMTI-GRP/8_YESBIN_2STA_YESMERGED/Graph.h b/SMTI-GRP/8_YESBIN_2STA_YESMERGED/Graph.h new file mode 100644 index 0000000..5d07f00 --- /dev/null +++ b/SMTI-GRP/8_YESBIN_2STA_YESMERGED/Graph.h @@ -0,0 +1,60 @@ +#ifndef GRAPH_H +#define GRAPH_H + +#include +#include +#include +#include +#include +#include + + +static_assert(std::numeric_limits::max() >= ((long unsigned)1 << 63), "size_t is too small"); + +struct pairhash { + public: + std::size_t operator()(const std::pair &x) const { + return (long)x.first * ((long)1 << 32) + x.second; + } +}; + +#ifdef DEBUG +#include +inline std::ostream& operator<<(std::ostream& o, const std::pair &x) { + o << "(" << x.first << ", " << x.second << ")"; + return o; +} +#endif /* DEBUG */ + + +class Graph { + public: + Graph(); + void addVertex(int side, int name); + bool containsVertex(int side, int name) const; + void addEdge(int v1, int v2); + int matched(int vertex) const; + void augment(int vertex); + + int size() const; + int matchingSize() const; + + int name(int vert_index); + +#ifdef DEBUG + void printGraph(); + void printMatching() const; +#endif /* DEBUG */ + + private: + std::vector> _exists; + std::vector>> _adjacents; + std::vector> _matching; + + int _size; + int _matching_size; + + bool internal_augment(int now, std::vector & visited, std::list & path); +}; + +#endif /* GRAPH_H */ diff --git a/SMTI-GRP/8_YESBIN_2STA_YESMERGED/main.cpp b/SMTI-GRP/8_YESBIN_2STA_YESMERGED/main.cpp index 839cefc..2198669 100644 --- a/SMTI-GRP/8_YESBIN_2STA_YESMERGED/main.cpp +++ b/SMTI-GRP/8_YESBIN_2STA_YESMERGED/main.cpp @@ -1,5 +1,7 @@ #include "main.h" +#define MAXTIME 3600 + /* ************************************************************************************* ************************************* MAIN ***************************************** ************************************************************************************* */ @@ -12,27 +14,38 @@ int main(int argc, char **argv){ string path = argv[1]; string pathAndFileout = argv[3]; int minGrade = atoi(argv[4]); + int mode = atoi(argv[5]); // functions allo.load(path,filein,minGrade); - allo.printProb(); + //allo.printProb(); - manlove(allo); - - allo.printSol(); - allo.checkSolution(); + int res = manlove(allo, mode); + if (res != -1) { + allo.printSol(); + allo.checkSolution(); + } allo.printInfo(pathAndFileout); } -int manlove(Allocation& allo){ +int manlove(Allocation& allo, int mode){ double initTimeModelCPU = getCPUTime(); GRBEnv env = GRBEnv(); double initTimeModelCPUPP = getCPUTime(); - allo.reduction(); - allo.printProb(); + if (mode != 12) { + allo.reduction(mode); + } + //allo.printProb(); allo.infos.timeCPUPP = getCPUTime() - initTimeModelCPUPP; + if (allo.infos.timeCPUPP > MAXTIME) { + cout << "Preprocessing took over " << MAXTIME << " seconds" << endl; + allo.infos.LB = 0; + allo.assignmentByChild.resize(allo.nbChildren, -1); + allo.assignmentByFamily.resize(allo.nbFamilies,-1); + return -1; + } // Model try{ @@ -140,7 +153,7 @@ int manlove(Allocation& allo){ } // Setting of Gurobi - model.getEnv().set(GRB_DoubleParam_TimeLimit, 3600 - (getCPUTime() - initTimeModelCPU)); + model.getEnv().set(GRB_DoubleParam_TimeLimit, MAXTIME - (getCPUTime() - initTimeModelCPU)); model.getEnv().set(GRB_IntParam_Threads, 1); model.getEnv().set(GRB_DoubleParam_MIPGap, 0); model.optimize(); diff --git a/SMTI-GRP/8_YESBIN_2STA_YESMERGED/main.h b/SMTI-GRP/8_YESBIN_2STA_YESMERGED/main.h index c441859..3bf5282 100644 --- a/SMTI-GRP/8_YESBIN_2STA_YESMERGED/main.h +++ b/SMTI-GRP/8_YESBIN_2STA_YESMERGED/main.h @@ -11,6 +11,6 @@ float EPSILON = 0.001; - int manlove(Allocation& allo); + int manlove(Allocation& allo, int reduction_mode); #endif diff --git a/SMTI-GRP/8_YESBIN_2STA_YESMERGED/makefile b/SMTI-GRP/8_YESBIN_2STA_YESMERGED/makefile index 9b4aeb1..82b1239 100644 --- a/SMTI-GRP/8_YESBIN_2STA_YESMERGED/makefile +++ b/SMTI-GRP/8_YESBIN_2STA_YESMERGED/makefile @@ -8,14 +8,14 @@ CPPLIB = -L$(GUROBI_DIR)/lib/ -lgurobi_c++ $(CLIB) GUROBI_OPTS = -I$(INC) $(CPPLIB) -lpthread -lm -m64 CC = g++ -CFLAGS = -O2 -Wall -ansi -pedantic -DIL_STD +CFLAGS = -O2 -Wall -ansi -pedantic -DIL_STD -std=c++11 DEBUG = -pg -g -Wall -ansi -pedantic -DIL_STD -OBJECTS = main.o Allocation.o time.o +OBJECTS = main.o Allocation.o time.o AgentIterator.o Graph.o exec : $(OBJECTS) $(CC) $(CFLAGS) -o YESBIN_2STA_YESMERGED $(OBJECTS) $(GUROBI_OPTS) -.cpp.o : +.cpp.o : $< $(CC) $(CFLAGS) $(GUROBI_OPTS) -c $< -o $@ clean : diff --git a/SMTI/3_NOBIN_1STA_YESMERGED/AgentIterator.cpp b/SMTI/3_NOBIN_1STA_YESMERGED/AgentIterator.cpp new file mode 100644 index 0000000..6210288 --- /dev/null +++ b/SMTI/3_NOBIN_1STA_YESMERGED/AgentIterator.cpp @@ -0,0 +1,402 @@ +#include "AgentIterator.h" + +AgentIteratorBase::AgentIteratorBase(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group, int posn) : + _agent(agent), + _these(these), _other(other), + _positions(positions), _candidates(candidates) { + if (_agent.preferences.size() == 0) { + _group = -1; + } else { + _group = group; + } + _position = posn; +} + +AgentIteratorBase::~AgentIteratorBase() { } + +int AgentIteratorBase::get_group() const { + return _group; +} + +int AgentIteratorBase::get_position() const { + return _position; +} + +const Child & AgentIteratorBase::get_agent() const { + return _agent; +} + +const std::vector & AgentIteratorBase::get_these() const { + return _these; +} + +const std::vector & AgentIteratorBase::get_other() const { + return _other; +} +const std::set & AgentIteratorBase::get_positions() const { + return _positions; +} +const std::set & AgentIteratorBase::get_candidates() const { + return _candidates; +} + +void AgentIteratorBase::regularIncrement() { + _position++; + if (_agent.preferences[_group].size() == _position) { + _position = 0; + _group++; + if (_agent.preferences.size() == _group) { + _group = -1; + } + } +} + +bool AgentIterator::operator==(const AgentIterator & other) { + return get_group() == other.get_group() && get_position() == other.get_position(); +} + +bool AgentIterator::operator!=(const AgentIterator & other) { + return ! (*this == other); +} + +const std::pair AgentIterator::operator*() { + return std::pair(get_group(), get_position()); +} + +AgentIterator AgentIterator::begin() { + AgentIterator starter(this, 0, 0); + starter.base->begin(); + return starter; +} + +AgentIterator AgentIterator::end() { + return AgentIterator(this, -1, 0); +} + +AgentIterator::AgentIterator(const Child & agent, const std::set & candidates, const std::set & positions, + const std::vector & these, const std::vector & other, int mode) : + _mode(mode) { + switch (_mode) { + default: + case 0: + base = new DescendingIterator(agent, candidates, positions, these, other, 0, 0); + break; + case 1: + base = new SkipBigIterator(agent, candidates, positions, these, other, 5, 0, 0); + break; + case 2: + base = new BestIterator(agent, candidates, positions, these, other, 0, 0); + break; + case 3: + base = new SkipBigIterator(agent, candidates, positions, these, other, 15, 0, 0); + break; + case 4: + base = new SkipBigIterator(agent, candidates, positions, these, other, 50, 0, 0); + break; + case 5: + base = new BestGroupIterator(agent, candidates, positions, these, other, 0, 0); + break; + } + } + +AgentIterator::AgentIterator(AgentIterator *other) : + _mode(other->get_mode()) { + switch (_mode) { + default: + case 0: + base = new DescendingIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), other->get_group(), other->get_position()); + break; + case 1: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 5, other->get_group(), other->get_position()); + break; + case 2: + base = new BestIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), other->get_group(), other->get_position()); + break; + case 3: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 15, other->get_group(), other->get_position()); + break; + case 4: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 50, other->get_group(), other->get_position()); + break; + case 5: + base = new BestGroupIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), other->get_group(), other->get_position()); + break; + } + } + +AgentIterator::AgentIterator(AgentIterator *other, int group, int posn) : + _mode(other->get_mode()) { + switch (_mode) { + case 0: + base = new DescendingIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), group, posn); + break; + case 1: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 5, group, posn); + break; + case 2: + base = new BestIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), group, posn); + break; + case 3: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 15, group, posn); + break; + case 4: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 50, group, posn); + break; + case 5: + base = new BestGroupIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), group, posn); + break; + } + } + +AgentIterator::~AgentIterator() { + delete base; +} + +int AgentIterator::get_group() const { + return base->get_group(); +} + +int AgentIterator::get_position() const { + return base->get_position(); +} + +int AgentIterator::get_mode() const { + return _mode; +} + +DescendingIterator::DescendingIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group, int posn) : + AgentIteratorBase(agent, candidates, positions, these, other, group, posn) { + } + +void DescendingIterator::begin() { +} + +void DescendingIterator::increment() { + regularIncrement(); +} + +SkipBigIterator::SkipBigIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int skip, int group, int posn) : + AgentIteratorBase(agent, candidates, positions, these, other, group, posn) , _skip(skip) { + } + + +void SkipBigIterator::begin() { + int num_added = 0; + while (true) { + if (get_group() == -1) { + break; + } + num_added = 0; + int other_id = _agent.preferences[_group][_position]; + int other_rank = _agent.ranks[_group][_position]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(pref) == 0) { + num_added++; + } + } + } + if (num_added > _skip) { + regularIncrement(); + } else { + break; + } + } +} + +void SkipBigIterator::increment() { + int num_added = 0; + do { + regularIncrement(); + if (get_group() == -1) { + break; + } + num_added = 0; + int other_id = _agent.preferences[_group][_position]; + int other_rank = _agent.ranks[_group][_position]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(pref) == 0) { + num_added++; + } + } + } + } while (num_added > _skip); +} + +BestIterator::BestIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group, int posn) : + AgentIteratorBase(agent, candidates, positions, these, other, group, posn) { + } + +void BestIterator::increment() { + int lowest_added = -1; + int best_group = -1; + int best_posn = -1; + for(int group_no = 0; group_no < _agent.preferences.size(); ++group_no) { + auto & group = _agent.preferences[group_no]; + for(int posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + int other_rank = _agent.ranks[group_no][posn]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto other_pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(other_pref) == 0) { + num_added++; + } + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_group = group_no; + best_posn = posn; + } + } + } + if (lowest_added != -1) { + _group = best_group; + _position = best_posn; + } else { + _group = -1; + _position = 0; + } +} + +void BestIterator::begin() { + int lowest_added = -1; + int best_group = -1; + int best_posn = -1; + for(int group_no = 0; group_no < _agent.preferences.size(); ++group_no) { + auto & group = _agent.preferences[group_no]; + for(int posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + int other_rank = _agent.ranks[group_no][posn]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto other_pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(other_pref) == 0) { + num_added++; + } + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_group = group_no; + best_posn = posn; + } + } + } + if (lowest_added != -1) { + _group = best_group; + _position = best_posn; + } else { + _group = -1; + _position = 0; + } +} + +BestGroupIterator::BestGroupIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group, int posn) : + AgentIteratorBase(agent, candidates, positions, these, other, group, posn) { + } + +void BestGroupIterator::increment() { + int lowest_added = -1; + int best_posn = -1; + auto & group = _agent.preferences[_group]; + for(int posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + int other_rank = _agent.ranks[_group][posn]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto other_pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(other_pref) == 0) { + num_added++; + } + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_posn = posn; + } + } + if (lowest_added != -1) { + _position = best_posn; + } else { + _group++; + if (_group == _agent.preferences.size()) { + _position = 0; + _group = -1; + } else { + increment(); + } + } +} + +void BestGroupIterator::begin() { + int lowest_added = -1; + int best_posn = -1; + if (_group == -1) { + return; + } + auto & group = _agent.preferences[_group]; + for(int posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + int other_rank = _agent.ranks[_group][posn]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto other_pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(other_pref) == 0) { + num_added++; + } + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_posn = posn; + } + } + if (lowest_added != -1) { + _position = best_posn; + } else { + _group++; + if (_group == _agent.preferences.size()) { + _position = 0; + _group = -1; + } else { + increment(); + } + } +} diff --git a/SMTI/3_NOBIN_1STA_YESMERGED/AgentIterator.h b/SMTI/3_NOBIN_1STA_YESMERGED/AgentIterator.h new file mode 100644 index 0000000..48b96c6 --- /dev/null +++ b/SMTI/3_NOBIN_1STA_YESMERGED/AgentIterator.h @@ -0,0 +1,110 @@ +#ifndef AGENTITERATOR_H +#define AGENTITERATOR_H + +#include + +#include "Allocation.h" + +class AgentIteratorBase { +public: + AgentIteratorBase(const Child & agent, const std::set & candidates, const std::set & positions, + const std::vector & these, const std::vector & other, int group=0, int posn=0); + virtual ~AgentIteratorBase() = 0; + virtual void increment() = 0; + virtual void begin() = 0; + + int get_position() const; + int get_group() const; + const Child & get_agent() const; + const std::vector & get_these() const; + const std::vector & get_other() const; + const std::set & get_positions() const; + const std::set & get_candidates() const; +protected: + void regularIncrement(); + + const Child & _agent; + int _group; + int _position; + const std::vector & _these; + const std::vector & _other; + const std::set & _positions; + const std::set & _candidates; +}; + + +class AgentIterator : public std::iterator, ptrdiff_t> { +public: + AgentIterator(const Child & agent, const std::set & candidates, const std::set & positions, + const std::vector & these, const std::vector & other, int mode); + AgentIterator(AgentIterator *other, int group, int posn); + AgentIterator(AgentIterator *other); + ~AgentIterator(); + bool operator==(const AgentIterator& other); + bool operator!=(const AgentIterator& other); + const std::pair operator*(); + AgentIterator& operator++() {base->increment(); return *this; } + AgentIterator operator++(int) {AgentIterator res(this); base->increment(); return res; } + + AgentIterator begin(); + AgentIterator end(); + + int get_position() const; + int get_group() const; + int get_mode() const; + + const Child & get_agent() const { return base->get_agent(); } + const std::vector & get_these() const {return base->get_these(); } + const std::vector & get_other() const {return base->get_other(); } + const std::set & get_positions() const {return base->get_positions(); } + const std::set & get_candidates() const {return base->get_candidates(); } +private: + AgentIteratorBase * base; + int _mode; +}; + + +class DescendingIterator : public AgentIteratorBase { + public: + DescendingIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group=0, int posn=0); + ~DescendingIterator() {} + void increment(); + void begin(); +}; + + +class SkipBigIterator : public AgentIteratorBase { + public: + SkipBigIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int skip, int group, int posn); + ~SkipBigIterator() {} + void increment(); + void begin(); + private: + int _skip; +}; + +class BestIterator : public AgentIteratorBase { + public: + BestIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group=0, int posn=0); + ~BestIterator() {} + void increment(); + void begin(); +}; + +class BestGroupIterator : public AgentIteratorBase { + public: + BestGroupIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group=0, int posn=0); + ~BestGroupIterator() {} + void increment(); + void begin(); +}; + +#endif /* AGENTITERATOR_H */ diff --git a/SMTI/3_NOBIN_1STA_YESMERGED/Allocation.cpp b/SMTI/3_NOBIN_1STA_YESMERGED/Allocation.cpp index 44a6851..46fae7d 100644 --- a/SMTI/3_NOBIN_1STA_YESMERGED/Allocation.cpp +++ b/SMTI/3_NOBIN_1STA_YESMERGED/Allocation.cpp @@ -1,29 +1,17 @@ #include "Allocation.h" +#include "AgentIterator.h" +#include "Graph.h" /* ************************************************************************************* *********************************** DOCTOR ***************************************** ************************************************************************************* */ -void Child::print(){ - cout << "Child " << id << "\t Preferences (" << nbPref << " groups, " << nbTotPref << " in total)\t"; - for(int i=0; i 0) cout << " "; - cout << preferences[i][j]; - cout << "[" << ranks[i][j] << "_" << positions[i][j] << "]"; - } - cout << ") "; - } - cout << endl; -} - -/* ************************************************************************************* - *********************************** HOSPITAL **************************************** - ************************************************************************************* */ - -void Family::print(){ - cout << "Family " << id << "\t Preferences (" << nbPref << " groups, " << nbTotPref << " in total)\t"; +void Child::print(bool family){ + if (family) + cout << "Family "; + else + cout << "Child "; + cout << id << "\t Preferences (" << nbPref << " groups, " << nbTotPref << " in total)\t"; for(int i=0; i, vector >::iterator it; - map, vector > mapFirstChoice; - for(int j=0; j temp(nbChildren,0); - if(families[j].nbPref > 0){ - for(int k=0;k, vector > add; - add.first = temp; - add.second.push_back(j); - mapFirstChoice.insert(add); - } - else{ - (*it).second.push_back(j); - } - } - else count++; - } - -/* for(it = mapFirstChoice.begin(); it!= mapFirstChoice.end(); ++it){ - cout << (*it).second.size() << " x (" << families[(*it).second[0]].preferences[0].size() << ") ["; - for(int i=0;i<(*it).second.size();i++){ - cout << (*it).second[i] << " "; - } - cout << "] == ["; - for(int i=0;i<(*it).first.size();i++){ - cout << (*it).first[i] << " "; - } - cout << "]" << endl; - } - - cout << "Count = " << count << endl;*/ - - // Step 2 -- See worst rank - - vector worstRank(nbChildren); - for(int i=0;i= families[(*it).second[0]].preferences[0].size() ){ - // cout << "Updates from " << co << endl;; co++; - for(int i=0; i < families[(*it).second[0]].preferences[0].size();i++){ - multiset orderedRanks; - multiset::iterator it2; - for(int j=0; j<(*it).second.size();j++){ - orderedRanks.insert(families[(*it).second[j]].ranks[0][i]); - } - // cout << "worstRank of " << families[(*it).second[0]].preferences[0][i] << " updated from " << worstRank[families[(*it).second[0]].preferences[0][i]]; - it2 = orderedRanks.begin(); - advance(it2, families[(*it).second[0]].preferences[0].size() - 1); - worstRank[families[(*it).second[0]].preferences[0][i]]=min(worstRank[families[(*it).second[0]].preferences[0][i]], *(it2)); - // cout << " to " << worstRank[families[(*it).second[0]].preferences[0][i]] << endl; - } - } - } - - // Step 3 -- Remove families after worst rank from child's preferences - +int Allocation::reductionExact(bool children_side, bool supp, bool early_exit) { int nbTotRem = 0; - - for(int i=0; i * thesep; + std::vector * otherp; + std::list *theseMustBeAllocatedp; + std::list *otherMustBeAllocatedp; + if (children_side) { + // Processing the lists of the children, removing families + thesep = &children; + otherp = &families; + theseMustBeAllocatedp = &childrenMustBeAllocated; + otherMustBeAllocatedp = &familiesMustBeAllocated; + number_here = nbChildren; + } else { + thesep = &families; + otherp = &children; + theseMustBeAllocatedp = &familiesMustBeAllocated; + otherMustBeAllocatedp = &childrenMustBeAllocated; + number_here = nbFamilies; + } + std::vector & these = (*thesep); + std::vector & other = (*otherp); + std::list & theseMustBeAllocated = (*theseMustBeAllocatedp); + std::list & otherMustBeAllocated = (*otherMustBeAllocatedp); + for (int i = 0; i < number_here; i++) { + // Early exit! + const float ratio = 0.1; + if (early_exit && (i >= ratio * number_here) && (nbTotRem == 0)) { + return 0; } - children[i].nbPref = worstRank[i] + 1; - children[i].preferences.resize(children[i].nbPref); - children[i].ranks.resize(children[i].nbPref); - children[i].positions.resize(children[i].nbPref); - } - - polish(); - return nbTotRem; -} - -int Allocation::reductionChi1(){ - - // Step 1 -- Create map - - int count = 0; - map, vector >::iterator it; - map, vector > mapFirstChoice; - for(int j=0; j temp(nbFamilies,0); - if(children[j].nbPref > 0){ - for(int k=0;k, vector > add; - add.first = temp; - add.second.push_back(j); - mapFirstChoice.insert(add); - } - else{ - (*it).second.push_back(j); + // A graph is "named" with two integers. The first is a 0 for a candidate + // (aka these) or a 1 for a position (aka other) + Graph g; + int n_1 = 0; + for(int rank = 0; rank < these[i].nbPref; rank++) { + // No point in checking the last rank if we already know this agent must + // be allocated, or if we don't care + if ((rank == these[i].nbPref - 1) && (these[i].mustBeAllocated || !supp)) { + continue; } - } - else count++; - } - -/* for(it = mapFirstChoice.begin(); it!= mapFirstChoice.end(); ++it){ - cout << (*it).second.size() << " x (" << children[(*it).second[0]].preferences[0].size() << ") ["; - for(int i=0;i<(*it).second.size();i++){ - cout << (*it).second[i] << " "; - } - cout << "] == ["; - for(int i=0;i<(*it).first.size();i++){ - cout << (*it).first[i] << " "; - } - cout << "]" << endl; - } - - cout << "Count = " << count << endl;*/ - - // Step 2 -- See worst rank - - vector worstRank(nbFamilies); - for(int i=0;i= children[(*it).second[0]].preferences[0].size() ){ - // cout << "Updates from " << co << endl;; co++; - for(int i=0; i < children[(*it).second[0]].preferences[0].size();i++){ - multiset orderedRanks; - multiset::iterator it2; - for(int j=0; j<(*it).second.size();j++){ - orderedRanks.insert(children[(*it).second[j]].ranks[0][i]); + for(size_t ind = 0; ind < these[i].preferences[rank].size(); ind++) { + int position = these[i].preferences[rank][ind]; + g.addVertex(1, position); + int idxRank = these[i].ranks[rank][ind]; + for(int l = 0; l <= idxRank; l++) { + for(size_t k = 0; k < other[position].preferences[l].size(); k++) { + int other_cand = other[position].preferences[l][k]; + if (other_cand == i) { // Don't add the current candidate to the graph + continue; + } + if (! g.containsVertex(0, other_cand)) { + g.addVertex(0, other_cand); + n_1 += 1; + } + g.addEdge(position, other_cand); + } } - // cout << "worstRank of " << children[(*it).second[0]].preferences[0][i] << " updated from " << worstRank[children[(*it).second[0]].preferences[0][i]]; - it2 = orderedRanks.begin(); - advance(it2, children[(*it).second[0]].preferences[0].size() - 1); - worstRank[children[(*it).second[0]].preferences[0][i]]=min(worstRank[children[(*it).second[0]].preferences[0][i]], *(it2)); - // cout << " to " << worstRank[children[(*it).second[0]].preferences[0][i]] << endl; } - } - } - - // Step 3 -- Remove families after worst rank from child's preferences - - int nbTotRem = 0; - - for(int i=0; i worstRank(nbChildren); - for(int i=0;i allChildren; - int count = 0; - for(int j=0; j= n_1 + 1)) { + break; } - } - if(count >= allChildren.size()){ - worstRank[i] = j; - // cout << "worst rank of " << i << " is " << j << endl; + // First add all positions that must be filled. + for(int position: otherMustBeAllocated) { + // If position is acceptable to i, then skip it. + bool isAcceptable = false; + for(int otherRank = 0; (!isAcceptable) && otherRank < other[position].nbPref; otherRank++) { + for(size_t ind = 0; ind < other[position].preferences[otherRank].size(); ++ind) { + if (other[position].preferences[otherRank][ind] == i) { + isAcceptable = true; + break; + } + } + } + if (isAcceptable) { + continue; + } + g.addVertex(1, position); + for(int otherRank = 0; otherRank < other[position].nbPref; otherRank++) { + for(size_t ind = 0; ind < other[position].preferences[otherRank].size(); ++ind) { + int candidate = other[position].preferences[otherRank][ind]; + if (!g.containsVertex(0, candidate)) { + g.addVertex(0, candidate); + n_1 += 1; + } + g.addEdge(position, candidate); + } + } + g.augment(position); + } + // I'm using a while loop as an if statement, so I need to break out. break; } - } - } - - for(int i=0; i= n_1 + 1)) { + // preprocess on rank! + // Firstly, they must be allocated, so mark as such (if we're in that + // mode) + if (supp && !these[i].mustBeAllocated) { + theseMustBeAllocated.push_back(i); + these[i].mustBeAllocated = true; + newMustAlways = true; + } +#ifdef DEBUG + if ((!children_side) and (i == 6)) { + std::cout << "g.size() = " << g.size() << ", g.matchingSize() = " << g.matchingSize(); + std::cout << ", n_1 = " << n_1 << std::endl; + g.printGraph(); + g.printMatching(); + } + if (children_side) { + std::cout << "child "; + } else { + std::cout << "family "; + } + std::cout << "worst rank of " << i << " is " << rank << " "; + int remHere = 0; +#endif /* DEBUG */ + for (int k = rank + 1; k < these[i].nbPref; k++) { + nbTotRem += these[i].preferences[k].size(); +#ifdef DEBUG + remHere += these[i].preferences[k].size(); +#endif /* DEBUG */ + these[i].nbTotPref -= these[i].preferences[k].size(); + for (unsigned int l = 0; l < these[i].preferences[k].size(); l++) { + int idxFam = these[i].preferences[k][l]; + int idxPos = these[i].positions[k][l]; + int idxRank = these[i].ranks[k][l]; + for (unsigned int m = idxPos + 1; + m < other[idxFam].preferences[idxRank].size(); m++) { + these[other[idxFam].preferences[idxRank][m]] + .positions[other[idxFam].ranks[idxRank][m]] + [other[idxFam].positions[idxRank][m]]--; + } + other[idxFam].nbTotPref--; + other[idxFam].positions[idxRank].erase( + other[idxFam].positions[idxRank].begin() + idxPos); + other[idxFam].ranks[idxRank].erase( + other[idxFam].ranks[idxRank].begin() + idxPos); + other[idxFam].preferences[idxRank].erase( + other[idxFam].preferences[idxRank].begin() + idxPos); + } } - families[idxFam].nbTotPref--; - families[idxFam].positions[idxRank].erase(families[idxFam].positions[idxRank].begin() + idxPos); - families[idxFam].ranks[idxRank].erase(families[idxFam].ranks[idxRank].begin() + idxPos); - families[idxFam].preferences[idxRank].erase(families[idxFam].preferences[idxRank].begin() + idxPos); + these[i].nbPref = rank + 1; + these[i].preferences.resize(these[i].nbPref); + these[i].ranks.resize(these[i].nbPref); + these[i].positions.resize(these[i].nbPref); +#ifdef DEBUG + std::cout << "removed " << remHere << std::endl; +#endif /* DEBUG */ + break; } } - children[i].nbPref = worstRank[i] + 1; - children[i].preferences.resize(children[i].nbPref); - children[i].ranks.resize(children[i].nbPref); - children[i].positions.resize(children[i].nbPref); } - - polish(); + if (nbTotRem > 0) { + polish(); + } + if ((nbTotRem == 0) && (newMustAlways)) { + return -1; + } return nbTotRem; } -int Allocation::reductionChi2(){ - +int Allocation::reductionMine(bool children_side, int mode, bool alt_store) { int nbTotRem = 0; - vector worstRank(nbFamilies); - for(int i=0;i allFamilies; + int number_here; + std::vector * thesep; + std::vector * otherp; + if (children_side) { + thesep = &children; + otherp = &families; + number_here = nbChildren; + } else { + thesep = &families; + otherp = &children; + number_here = nbFamilies; + } + std::vector & these = (*thesep); + std::vector & other = (*otherp); + + for (int i = 0; i < number_here; i++) { + set candidates; + set positions; + vector cand_in(number_here, false); + int cand_size = 0; + int worst_rank = 0; int count = 0; - for(int j=0; j p: iter) { + int j = p.first; + int k = p.second; + if (j > worst_rank) { + worst_rank = j; + } + int idxFam = these[i].preferences[j][k]; + int idxRank = these[i].ranks[j][k]; + positions.insert(idxFam); + count++; + for (int l = 0; l <= idxRank; l++) { + for (unsigned int m = 0; m < other[idxFam].preferences[l].size(); + m++) { + if ((alt_store && cand_in[other[idxFam].preferences[l][m]] == false) || + (!alt_store && candidates.count(other[idxFam].preferences[l][m]) == 0)) { + candidates.insert(other[idxFam].preferences[l][m]); + cand_in[other[idxFam].preferences[l][m]] = true; + cand_size++; + } } } - if(count >= allFamilies.size()){ - worstRank[i] = j; - // cout << "worst rank of " << i << " is " << j << endl; + if (count >= cand_size) { +#ifdef DEBUG + if (children_side) { + std::cout << "child "; + } else { + std::cout << "family "; + } + std::cout << "worst rank of " << i << " is " << worst_rank << std::endl; +#endif /* DEBUG */ + for (int k = worst_rank + 1; k < these[i].nbPref; k++) { + nbTotRem += these[i].preferences[k].size(); + these[i].nbTotPref -= these[i].preferences[k].size(); + for (unsigned int l = 0; l < these[i].preferences[k].size(); l++) { + int idxFam = these[i].preferences[k][l]; + int idxPos = these[i].positions[k][l]; + int idxRank = these[i].ranks[k][l]; + for (unsigned int m = idxPos + 1; + m < other[idxFam].preferences[idxRank].size(); m++) { + these[other[idxFam].preferences[idxRank][m]] + .positions[other[idxFam].ranks[idxRank][m]] + [other[idxFam].positions[idxRank][m]]--; + } + other[idxFam].nbTotPref--; + other[idxFam].positions[idxRank].erase( + other[idxFam].positions[idxRank].begin() + idxPos); + other[idxFam].ranks[idxRank].erase( + other[idxFam].ranks[idxRank].begin() + idxPos); + other[idxFam].preferences[idxRank].erase( + other[idxFam].preferences[idxRank].begin() + idxPos); + } + } + these[i].nbPref = worst_rank + 1; + these[i].preferences.resize(these[i].nbPref); + these[i].ranks.resize(these[i].nbPref); + these[i].positions.resize(these[i].nbPref); break; } } } - - for(int i=0; i 0) { + polish(); } - - polish(); return nbTotRem; } @@ -605,20 +553,94 @@ void Allocation::polish(){ } } -void Allocation::reduction(){ - int nbRed1 = 0; - int nbRed2 = 0; - int nbRed3 = 0; - int nbRed4 = 0; +void Allocation::reduction(int mode){ + total_reduced = 0; int i = 0; - do{ - nbRed1 = reductionFam1(); - nbRed2 = reductionChi1(); - nbRed3 = reductionFam2(); - nbRed4 = reductionChi2(); - cout << "Reduction iteration " << i << " reductionFam1 " << nbRed1 << " reductionChi1 " << nbRed2 << " reductionFam2 " << nbRed3 << " reductionChi2 " << nbRed4 << endl; - i++; - }while(nbRed1 + nbRed2 + nbRed3 + nbRed4 != 0); + int num = 0; + bool keepGoing; + if (mode == 7) { + do { + num = reductionMine(false, 1); + num += reductionMine(true, 1); + cout << "Iteration " << i << " in heuristic removed " << num << std::endl; + i++; + total_reduced += num; + } while (num != 0); + do { + num = reductionExact(false); + num += reductionExact(true); + cout << "Iteration " << i << " in exact mode removed " << num << std::endl; + i++; + total_reduced += num; + } while (num != 0); + } else if (mode == 11) { + do { + num = reductionMine(true, 1); + num += reductionMine(false, 1); + cout << "Iteration " << i << " in heuristic removed " << num << std::endl; + i++; + total_reduced += num; + } while (num != 0); + do { + num = reductionExact(true); + num += reductionExact(false); + cout << "Iteration " << i << " in exact mode removed " << num << std::endl; + i++; + total_reduced += num; + } while (num != 0); + } else { + do{ + keepGoing = false; + if (mode == 6) { + // True means preprocess childrens' lists, removing families. + // False means preprocess families' lists, removing children. + num = reductionExact(false); + num += reductionExact(true); + } else if (mode == 8) { + num = reductionExact(true); + num += reductionExact(false); + } else if (mode == 9) { + num = reductionExact(false, true); + if (num == -1) { + num = 0; + keepGoing = true; + } + int nextNum = reductionExact(true, true); + if (nextNum == -1) { + nextNum = 0; + keepGoing = true; + } + num += nextNum; + } else if (mode == 10) { + num = reductionExact(true, true); + if (num == -1) { + num = 0; + keepGoing = true; + } + int nextNum = reductionExact(false, true); + if (nextNum == -1) { + nextNum = 0; + keepGoing = true; + } + num += nextNum; + } else if (mode == 13) { + num = reductionMine(false, 0, true); + num += reductionMine(true, 0, true); + } else if (mode == 14) { + num = reductionExact(false, false, true); + num += reductionExact(true, false, true); + } else if (mode == 15) { + num = reductionExact(true, false, true); + num += reductionExact(false, false, true); + } else { + num = reductionMine(false, mode); + num += reductionMine(true, mode); + } + cout << "Iteration " << i << " in mode " << mode << " removed " << num << std::endl; + i++; + total_reduced += num; + }while(keepGoing || (num != 0)); + } } void Allocation::printSol(){ @@ -631,7 +653,7 @@ void Allocation::printSol(){ void Allocation::printInfo(const string& pathAndFileout){ string nameFile = pathAndFileout; std::ofstream file(nameFile.c_str(), std::ios::out | std::ios::app); - file << name << "\t" << infos.opt << "\t" << infos.timeCPU << "\t" << infos.timeCPUPP << "\t"<< infos.LB << "\t" << infos.UB << "\t" << infos.contUB << "\t" << infos.nbVar << "\t" << infos.nbCons << "\t" << infos.nbNZ + file << name << "\t" << infos.opt << "\t" << infos.timeCPU << "\t" << infos.timeCPUPP << "\t" << total_reduced << "\t"<< infos.LB << "\t" << infos.UB << "\t" << infos.contUB << "\t" << infos.nbVar << "\t" << infos.nbCons << "\t" << infos.nbNZ << "\t" << infos.contUB2 << "\t" << infos.nbVar2 << "\t" << infos.nbCons2 << "\t" << infos.nbNZ2 << endl; file.close(); } diff --git a/SMTI/3_NOBIN_1STA_YESMERGED/Allocation.h b/SMTI/3_NOBIN_1STA_YESMERGED/Allocation.h index dcd6046..6e45c0c 100644 --- a/SMTI/3_NOBIN_1STA_YESMERGED/Allocation.h +++ b/SMTI/3_NOBIN_1STA_YESMERGED/Allocation.h @@ -4,6 +4,7 @@ using namespace std; #include #include +#include #include #include #include @@ -12,7 +13,7 @@ #include class Child; - class Family; + typedef Child Family; class Assignment; class Allocation; @@ -21,29 +22,15 @@ ************************************************************************************* */ class Child{ - public: - int id; - int nbPref; - int nbTotPref; - vector > preferences; - vector > ranks; - vector > positions; - void print(); - }; - -/* ************************************************************************************* - *********************************** HOSPITAL **************************************** - ************************************************************************************* */ - - class Family{ public: int id; int nbPref; int nbTotPref; + bool mustBeAllocated; vector > preferences; vector > ranks; vector > positions; - void print(); + void print(bool); }; /* ************************************************************************************* @@ -76,6 +63,7 @@ string name; int nbChildren; int nbFamilies; + int total_reduced; vector children; vector families; @@ -84,20 +72,21 @@ vector assignmentByChild; vector assignmentByFamily; + std::list childrenMustBeAllocated; + std::list familiesMustBeAllocated; + Info infos; void load(const string& path, const string& filein); void printProb(); - int reductionFam1(); - int reductionChi1(); - int reductionFam2(); - int reductionChi2(); + int reductionMine(bool children_side=true, int mode=0, bool alt_store=false); + int reductionExact(bool children_side, bool supp=false, bool early_exit=false); void polish(); - void reduction(); + void reduction(int mode); void printSol(); void printInfo(const string& pathAndFileout); void checkSolution(); }; -#endif \ No newline at end of file +#endif diff --git a/SMTI/3_NOBIN_1STA_YESMERGED/Graph.cpp b/SMTI/3_NOBIN_1STA_YESMERGED/Graph.cpp new file mode 100644 index 0000000..0e487e7 --- /dev/null +++ b/SMTI/3_NOBIN_1STA_YESMERGED/Graph.cpp @@ -0,0 +1,107 @@ +#include +#include "Graph.h" + + +// Expected biggest graph, to save on allocations +const size_t expected_size = 50000; + +Graph::Graph() : _exists(2), _adjacents(2), _matching(2), _size(0), _matching_size(0) { + _exists[0] = std::vector(expected_size, false); + _exists[1] = std::vector(expected_size, false); + _adjacents[0] = std::vector>(expected_size); + _adjacents[1] = std::vector>(expected_size); + _matching[0] = std::vector(expected_size, -1); + _matching[1] = std::vector(expected_size, -1); +#ifdef DEBUG + std::cout << "New graph" << std::endl; +#endif /* DEBUG */ +} + +void Graph::addVertex(int side, int name) { + _exists[side][name] = true; + _size += 1; +} + +bool Graph::containsVertex(int side, int name) const { + return _exists[side][name]; +} + +/** + * Adds an edge to the graph. Note that this edge must always be added in the + * form (right, left) for things to work. + */ +void Graph::addEdge(int v1, int v2) { + _adjacents[1][v1].push_back(v2); + _adjacents[0][v2].push_back(v1); +} + +int Graph::size() const { + return _size; +} + +int Graph::matchingSize() const { + return _matching_size; +} + +/** + * Augment the matching, starting at vertex name which is on the right. + */ +void Graph::augment(int name) { +#ifdef DEBUG + std::cout << "Augmenting on " << _indices.at(start) << std::endl; + this->printGraph(); +#endif /* DEBUG */ + std::list path; + std::vector visited(expected_size, false); + path.push_back(name); + internal_augment(name, visited, path); +} + +/** + * Continues an augmentation, on vertex now, which is on the right. + */ +bool Graph::internal_augment(int now, std::vector & visited, + std::list & path) { + for(int next: _adjacents[1][now]) { + // next is on the left + if (visited[next]) { + continue; + } + if (_matching[0][next] == -1) { + // Found an augmenting path. Switch edges and return true. +#ifdef DEBUG + std::cout << "New matching found." << std::endl; +#endif /* DEBUG */ + path.push_back(next); +#ifdef DEBUG + std::cout << "Path is "; + for(auto p: path) { + std::cout << " " << _indices.at(p); + } + std::cout << std::endl; + +#endif /* DEBUG */ + while(!path.empty()) { + int right = path.front(); + path.pop_front(); + int left = path.front(); + path.pop_front(); + _matching[1][right] = left; + _matching[0][left] = right; + } + _matching_size += 1; + return true; + } + int next2 = _matching[0][next]; + path.push_back(next); + path.push_back(next2); + visited[next] = true; + if (internal_augment(next2, visited, path)) { + return true; + } + path.pop_back(); + path.pop_back(); + } + return false; +} + diff --git a/SMTI/3_NOBIN_1STA_YESMERGED/Graph.h b/SMTI/3_NOBIN_1STA_YESMERGED/Graph.h new file mode 100644 index 0000000..5d07f00 --- /dev/null +++ b/SMTI/3_NOBIN_1STA_YESMERGED/Graph.h @@ -0,0 +1,60 @@ +#ifndef GRAPH_H +#define GRAPH_H + +#include +#include +#include +#include +#include +#include + + +static_assert(std::numeric_limits::max() >= ((long unsigned)1 << 63), "size_t is too small"); + +struct pairhash { + public: + std::size_t operator()(const std::pair &x) const { + return (long)x.first * ((long)1 << 32) + x.second; + } +}; + +#ifdef DEBUG +#include +inline std::ostream& operator<<(std::ostream& o, const std::pair &x) { + o << "(" << x.first << ", " << x.second << ")"; + return o; +} +#endif /* DEBUG */ + + +class Graph { + public: + Graph(); + void addVertex(int side, int name); + bool containsVertex(int side, int name) const; + void addEdge(int v1, int v2); + int matched(int vertex) const; + void augment(int vertex); + + int size() const; + int matchingSize() const; + + int name(int vert_index); + +#ifdef DEBUG + void printGraph(); + void printMatching() const; +#endif /* DEBUG */ + + private: + std::vector> _exists; + std::vector>> _adjacents; + std::vector> _matching; + + int _size; + int _matching_size; + + bool internal_augment(int now, std::vector & visited, std::list & path); +}; + +#endif /* GRAPH_H */ diff --git a/SMTI/3_NOBIN_1STA_YESMERGED/main.cpp b/SMTI/3_NOBIN_1STA_YESMERGED/main.cpp index 143da32..dbf3f29 100644 --- a/SMTI/3_NOBIN_1STA_YESMERGED/main.cpp +++ b/SMTI/3_NOBIN_1STA_YESMERGED/main.cpp @@ -1,5 +1,7 @@ #include "main.h" +#define MAXTIME 3600 + /* ************************************************************************************* ************************************* MAIN ***************************************** ************************************************************************************* */ @@ -8,17 +10,19 @@ int main(int argc, char **argv){ // local variables Allocation allo ; + allo.total_reduced = 0; string filein = argv[2]; string path = argv[1]; string pathAndFileout = argv[3]; + int mode = atoi(argv[4]); // functions allo.load(path,filein); - allo.printProb(); - allo.reduction(); - allo.printProb(); + //allo.printProb(); + //allo.reduction(); + //allo.printProb(); - manlove(allo); + manlove(allo, mode); allo.printSol(); allo.checkSolution(); @@ -26,14 +30,23 @@ int main(int argc, char **argv){ } -int manlove(Allocation& allo){ +int manlove(Allocation& allo, int mode){ double initTimeModelCPU = getCPUTime(); GRBEnv env = GRBEnv(); double initTimeModelCPUPP = getCPUTime(); - allo.reduction(); - allo.printProb(); + if (mode != 12) { + allo.reduction(mode); + } + //allo.printProb(); allo.infos.timeCPUPP = getCPUTime() - initTimeModelCPUPP; + if (allo.infos.timeCPUPP > MAXTIME) { + cout << "Preprocessing took over MAXTIME seconds" << endl; + allo.infos.LB = 0; + allo.assignmentByChild.resize(allo.nbChildren, -1); + allo.assignmentByFamily.resize(allo.nbFamilies,-1); + return -1; + } // Model try{ @@ -114,7 +127,7 @@ int manlove(Allocation& allo){ } // Setting of Gurobi - model.getEnv().set(GRB_DoubleParam_TimeLimit, 3600 - (getCPUTime() - initTimeModelCPU)); + model.getEnv().set(GRB_DoubleParam_TimeLimit, MAXTIME - (getCPUTime() - initTimeModelCPU)); model.getEnv().set(GRB_IntParam_Threads, 1); model.getEnv().set(GRB_DoubleParam_MIPGap, 0); model.optimize(); diff --git a/SMTI/3_NOBIN_1STA_YESMERGED/main.h b/SMTI/3_NOBIN_1STA_YESMERGED/main.h index c441859..3bf5282 100644 --- a/SMTI/3_NOBIN_1STA_YESMERGED/main.h +++ b/SMTI/3_NOBIN_1STA_YESMERGED/main.h @@ -11,6 +11,6 @@ float EPSILON = 0.001; - int manlove(Allocation& allo); + int manlove(Allocation& allo, int reduction_mode); #endif diff --git a/SMTI/3_NOBIN_1STA_YESMERGED/makefile b/SMTI/3_NOBIN_1STA_YESMERGED/makefile index 662a970..091fe72 100644 --- a/SMTI/3_NOBIN_1STA_YESMERGED/makefile +++ b/SMTI/3_NOBIN_1STA_YESMERGED/makefile @@ -8,15 +8,15 @@ CPPLIB = -L$(GUROBI_DIR)/lib/ -lgurobi_c++ $(CLIB) GUROBI_OPTS = -I$(INC) $(CPPLIB) -lpthread -lm -m64 CC = g++ -CFLAGS = -O2 -Wall -ansi -pedantic -DIL_STD +CFLAGS = -O2 -Wall -ansi -pedantic -DIL_STD -std=c++11 DEBUG = -pg -g -Wall -ansi -pedantic -DIL_STD -OBJECTS = main.o Allocation.o time.o +OBJECTS = main.o Allocation.o time.o AgentIterator.o Graph.o exec : $(OBJECTS) - $(CC) $(CFLAGS) -o MANLOVE_REDUCTION $(OBJECTS) $(GUROBI_OPTS) + $(CC) $(CFLAGS) -o 3_NOBIN_1STA_YESMERGED $(OBJECTS) $(GUROBI_OPTS) -.cpp.o : +.cpp.o : $< $(CC) $(CFLAGS) $(GUROBI_OPTS) -c $< -o $@ clean : - rm -f $(OBJECTS) MANLOVE_REDUCTION + rm -f $(OBJECTS) 3_NOBIN_1STA_YESMERGED diff --git a/SMTI/3_NOBIN_1STA_YESMERGED_MAXWT/AgentIterator.cpp b/SMTI/3_NOBIN_1STA_YESMERGED_MAXWT/AgentIterator.cpp new file mode 100644 index 0000000..6210288 --- /dev/null +++ b/SMTI/3_NOBIN_1STA_YESMERGED_MAXWT/AgentIterator.cpp @@ -0,0 +1,402 @@ +#include "AgentIterator.h" + +AgentIteratorBase::AgentIteratorBase(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group, int posn) : + _agent(agent), + _these(these), _other(other), + _positions(positions), _candidates(candidates) { + if (_agent.preferences.size() == 0) { + _group = -1; + } else { + _group = group; + } + _position = posn; +} + +AgentIteratorBase::~AgentIteratorBase() { } + +int AgentIteratorBase::get_group() const { + return _group; +} + +int AgentIteratorBase::get_position() const { + return _position; +} + +const Child & AgentIteratorBase::get_agent() const { + return _agent; +} + +const std::vector & AgentIteratorBase::get_these() const { + return _these; +} + +const std::vector & AgentIteratorBase::get_other() const { + return _other; +} +const std::set & AgentIteratorBase::get_positions() const { + return _positions; +} +const std::set & AgentIteratorBase::get_candidates() const { + return _candidates; +} + +void AgentIteratorBase::regularIncrement() { + _position++; + if (_agent.preferences[_group].size() == _position) { + _position = 0; + _group++; + if (_agent.preferences.size() == _group) { + _group = -1; + } + } +} + +bool AgentIterator::operator==(const AgentIterator & other) { + return get_group() == other.get_group() && get_position() == other.get_position(); +} + +bool AgentIterator::operator!=(const AgentIterator & other) { + return ! (*this == other); +} + +const std::pair AgentIterator::operator*() { + return std::pair(get_group(), get_position()); +} + +AgentIterator AgentIterator::begin() { + AgentIterator starter(this, 0, 0); + starter.base->begin(); + return starter; +} + +AgentIterator AgentIterator::end() { + return AgentIterator(this, -1, 0); +} + +AgentIterator::AgentIterator(const Child & agent, const std::set & candidates, const std::set & positions, + const std::vector & these, const std::vector & other, int mode) : + _mode(mode) { + switch (_mode) { + default: + case 0: + base = new DescendingIterator(agent, candidates, positions, these, other, 0, 0); + break; + case 1: + base = new SkipBigIterator(agent, candidates, positions, these, other, 5, 0, 0); + break; + case 2: + base = new BestIterator(agent, candidates, positions, these, other, 0, 0); + break; + case 3: + base = new SkipBigIterator(agent, candidates, positions, these, other, 15, 0, 0); + break; + case 4: + base = new SkipBigIterator(agent, candidates, positions, these, other, 50, 0, 0); + break; + case 5: + base = new BestGroupIterator(agent, candidates, positions, these, other, 0, 0); + break; + } + } + +AgentIterator::AgentIterator(AgentIterator *other) : + _mode(other->get_mode()) { + switch (_mode) { + default: + case 0: + base = new DescendingIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), other->get_group(), other->get_position()); + break; + case 1: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 5, other->get_group(), other->get_position()); + break; + case 2: + base = new BestIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), other->get_group(), other->get_position()); + break; + case 3: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 15, other->get_group(), other->get_position()); + break; + case 4: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 50, other->get_group(), other->get_position()); + break; + case 5: + base = new BestGroupIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), other->get_group(), other->get_position()); + break; + } + } + +AgentIterator::AgentIterator(AgentIterator *other, int group, int posn) : + _mode(other->get_mode()) { + switch (_mode) { + case 0: + base = new DescendingIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), group, posn); + break; + case 1: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 5, group, posn); + break; + case 2: + base = new BestIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), group, posn); + break; + case 3: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 15, group, posn); + break; + case 4: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 50, group, posn); + break; + case 5: + base = new BestGroupIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), group, posn); + break; + } + } + +AgentIterator::~AgentIterator() { + delete base; +} + +int AgentIterator::get_group() const { + return base->get_group(); +} + +int AgentIterator::get_position() const { + return base->get_position(); +} + +int AgentIterator::get_mode() const { + return _mode; +} + +DescendingIterator::DescendingIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group, int posn) : + AgentIteratorBase(agent, candidates, positions, these, other, group, posn) { + } + +void DescendingIterator::begin() { +} + +void DescendingIterator::increment() { + regularIncrement(); +} + +SkipBigIterator::SkipBigIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int skip, int group, int posn) : + AgentIteratorBase(agent, candidates, positions, these, other, group, posn) , _skip(skip) { + } + + +void SkipBigIterator::begin() { + int num_added = 0; + while (true) { + if (get_group() == -1) { + break; + } + num_added = 0; + int other_id = _agent.preferences[_group][_position]; + int other_rank = _agent.ranks[_group][_position]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(pref) == 0) { + num_added++; + } + } + } + if (num_added > _skip) { + regularIncrement(); + } else { + break; + } + } +} + +void SkipBigIterator::increment() { + int num_added = 0; + do { + regularIncrement(); + if (get_group() == -1) { + break; + } + num_added = 0; + int other_id = _agent.preferences[_group][_position]; + int other_rank = _agent.ranks[_group][_position]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(pref) == 0) { + num_added++; + } + } + } + } while (num_added > _skip); +} + +BestIterator::BestIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group, int posn) : + AgentIteratorBase(agent, candidates, positions, these, other, group, posn) { + } + +void BestIterator::increment() { + int lowest_added = -1; + int best_group = -1; + int best_posn = -1; + for(int group_no = 0; group_no < _agent.preferences.size(); ++group_no) { + auto & group = _agent.preferences[group_no]; + for(int posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + int other_rank = _agent.ranks[group_no][posn]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto other_pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(other_pref) == 0) { + num_added++; + } + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_group = group_no; + best_posn = posn; + } + } + } + if (lowest_added != -1) { + _group = best_group; + _position = best_posn; + } else { + _group = -1; + _position = 0; + } +} + +void BestIterator::begin() { + int lowest_added = -1; + int best_group = -1; + int best_posn = -1; + for(int group_no = 0; group_no < _agent.preferences.size(); ++group_no) { + auto & group = _agent.preferences[group_no]; + for(int posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + int other_rank = _agent.ranks[group_no][posn]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto other_pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(other_pref) == 0) { + num_added++; + } + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_group = group_no; + best_posn = posn; + } + } + } + if (lowest_added != -1) { + _group = best_group; + _position = best_posn; + } else { + _group = -1; + _position = 0; + } +} + +BestGroupIterator::BestGroupIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group, int posn) : + AgentIteratorBase(agent, candidates, positions, these, other, group, posn) { + } + +void BestGroupIterator::increment() { + int lowest_added = -1; + int best_posn = -1; + auto & group = _agent.preferences[_group]; + for(int posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + int other_rank = _agent.ranks[_group][posn]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto other_pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(other_pref) == 0) { + num_added++; + } + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_posn = posn; + } + } + if (lowest_added != -1) { + _position = best_posn; + } else { + _group++; + if (_group == _agent.preferences.size()) { + _position = 0; + _group = -1; + } else { + increment(); + } + } +} + +void BestGroupIterator::begin() { + int lowest_added = -1; + int best_posn = -1; + if (_group == -1) { + return; + } + auto & group = _agent.preferences[_group]; + for(int posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + int other_rank = _agent.ranks[_group][posn]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto other_pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(other_pref) == 0) { + num_added++; + } + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_posn = posn; + } + } + if (lowest_added != -1) { + _position = best_posn; + } else { + _group++; + if (_group == _agent.preferences.size()) { + _position = 0; + _group = -1; + } else { + increment(); + } + } +} diff --git a/SMTI/3_NOBIN_1STA_YESMERGED_MAXWT/AgentIterator.h b/SMTI/3_NOBIN_1STA_YESMERGED_MAXWT/AgentIterator.h new file mode 100644 index 0000000..48b96c6 --- /dev/null +++ b/SMTI/3_NOBIN_1STA_YESMERGED_MAXWT/AgentIterator.h @@ -0,0 +1,110 @@ +#ifndef AGENTITERATOR_H +#define AGENTITERATOR_H + +#include + +#include "Allocation.h" + +class AgentIteratorBase { +public: + AgentIteratorBase(const Child & agent, const std::set & candidates, const std::set & positions, + const std::vector & these, const std::vector & other, int group=0, int posn=0); + virtual ~AgentIteratorBase() = 0; + virtual void increment() = 0; + virtual void begin() = 0; + + int get_position() const; + int get_group() const; + const Child & get_agent() const; + const std::vector & get_these() const; + const std::vector & get_other() const; + const std::set & get_positions() const; + const std::set & get_candidates() const; +protected: + void regularIncrement(); + + const Child & _agent; + int _group; + int _position; + const std::vector & _these; + const std::vector & _other; + const std::set & _positions; + const std::set & _candidates; +}; + + +class AgentIterator : public std::iterator, ptrdiff_t> { +public: + AgentIterator(const Child & agent, const std::set & candidates, const std::set & positions, + const std::vector & these, const std::vector & other, int mode); + AgentIterator(AgentIterator *other, int group, int posn); + AgentIterator(AgentIterator *other); + ~AgentIterator(); + bool operator==(const AgentIterator& other); + bool operator!=(const AgentIterator& other); + const std::pair operator*(); + AgentIterator& operator++() {base->increment(); return *this; } + AgentIterator operator++(int) {AgentIterator res(this); base->increment(); return res; } + + AgentIterator begin(); + AgentIterator end(); + + int get_position() const; + int get_group() const; + int get_mode() const; + + const Child & get_agent() const { return base->get_agent(); } + const std::vector & get_these() const {return base->get_these(); } + const std::vector & get_other() const {return base->get_other(); } + const std::set & get_positions() const {return base->get_positions(); } + const std::set & get_candidates() const {return base->get_candidates(); } +private: + AgentIteratorBase * base; + int _mode; +}; + + +class DescendingIterator : public AgentIteratorBase { + public: + DescendingIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group=0, int posn=0); + ~DescendingIterator() {} + void increment(); + void begin(); +}; + + +class SkipBigIterator : public AgentIteratorBase { + public: + SkipBigIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int skip, int group, int posn); + ~SkipBigIterator() {} + void increment(); + void begin(); + private: + int _skip; +}; + +class BestIterator : public AgentIteratorBase { + public: + BestIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group=0, int posn=0); + ~BestIterator() {} + void increment(); + void begin(); +}; + +class BestGroupIterator : public AgentIteratorBase { + public: + BestGroupIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group=0, int posn=0); + ~BestGroupIterator() {} + void increment(); + void begin(); +}; + +#endif /* AGENTITERATOR_H */ diff --git a/SMTI/3_NOBIN_1STA_YESMERGED_MAXWT/Allocation.cpp b/SMTI/3_NOBIN_1STA_YESMERGED_MAXWT/Allocation.cpp new file mode 100644 index 0000000..46fae7d --- /dev/null +++ b/SMTI/3_NOBIN_1STA_YESMERGED_MAXWT/Allocation.cpp @@ -0,0 +1,763 @@ +#include "Allocation.h" +#include "AgentIterator.h" +#include "Graph.h" + +/* ************************************************************************************* + *********************************** DOCTOR ***************************************** + ************************************************************************************* */ + +void Child::print(bool family){ + if (family) + cout << "Family "; + else + cout << "Child "; + cout << id << "\t Preferences (" << nbPref << " groups, " << nbTotPref << " in total)\t"; + for(int i=0; i 0) cout << " "; + cout << preferences[i][j]; + cout << "[" << ranks[i][j] << "_" << positions[i][j] << "]"; + } + cout << ") "; + } + cout << endl; +} + +/* ************************************************************************************* + ********************************** ALLOCATION *************************************** + ************************************************************************************* */ + +void Allocation::load(const string& path, const string& filein){ + // Local variables + istringstream iss; + string parser; + string garbage; + string nameFile = path + filein; + vector > allRanksC, allRanksF, allPreferencesC, allPreferencesF; + + // File opening + ifstream file(nameFile.c_str(), ios::in); + + // File lecture + if (file){ + // Name of the instance is filein + name = filein; + + // Skip the first line + getline(file, parser); iss.str(parser); iss >> garbage; iss.clear(); + + // Read the number of doctors + getline(file, parser); iss.str(parser); iss >> nbFamilies; iss.clear(); + + // Read the number of hospitals + getline(file, parser); iss.str(parser); iss >> nbChildren; iss.clear(); + + // Resize allRanks and allPreferences + allRanksC.resize(nbChildren); allPreferencesC.resize(nbChildren); + allRanksF.resize(nbFamilies); allPreferencesF.resize(nbFamilies); + + // Read the preferences of each child + for (int i = 0; i < nbChildren; i++){ + Child c; + c.mustBeAllocated = false; + int temp; + allRanksC[i].resize(nbFamilies,-1); allPreferencesC[i].resize(nbFamilies,-1); + + istringstream tempIss; + string tempString; + c.nbTotPref = 0; + int rank = 0; + + getline(file, parser); + iss.str(parser); + iss >> c.id; + + for(;;){ + char tempChar = iss.get(); + if(iss.eof()) + break; + else{ + if(tempChar == '('){ + int pref = 0; + getline(iss, tempString, ')'); + tempIss.str(tempString); + vector tempPref; + while(tempIss >> temp){ + allRanksC[i][temp-1] = rank; + allPreferencesC[i][temp-1] = pref; + tempPref.push_back(temp-1); + pref++; + } + c.preferences.push_back(tempPref); + c.nbTotPref+= tempPref.size(); + rank++; + tempIss.clear(); + } + else{ + if((tempChar >= '0') && (tempChar <= '9')){ + iss.putback(tempChar); + vector tempPref; + iss >> temp; + allRanksC[i][temp-1] = rank; + allPreferencesC[i][temp-1] = 0; + tempPref.push_back(temp-1); + c.preferences.push_back(tempPref); + c.nbTotPref+= tempPref.size(); + rank++; + tempIss.clear(); + } + } + } + } + + c.nbPref = c.preferences.size(); + children.push_back(c); + iss.clear(); + } + + // Read the preferences of each family + for (int i = 0; i < nbFamilies; i++){ + Family f; + f.mustBeAllocated = false; + int temp; + allRanksF[i].resize(nbChildren,-1); allPreferencesF[i].resize(nbChildren,-1); + + istringstream tempIss; + string tempString; + + f.nbTotPref = 0; + int rank = 0; + + getline(file, parser); + iss.str(parser); + iss >> f.id; + iss >> garbage; + + for(;;){ + char tempChar = iss.get(); + //cout << "Just read " << tempChar << endl; + if(iss.eof()) + break; + else{ + if(tempChar == '('){ + int pref = 0; + getline(iss, tempString, ')'); + tempIss.str(tempString); + vector tempPref; + while(tempIss >> temp){ + allRanksF[i][temp-1] = rank; + allPreferencesF[i][temp-1] = pref; + tempPref.push_back(temp-1); + pref++; + } + f.preferences.push_back(tempPref); + f.nbTotPref+= tempPref.size(); + rank++; + tempIss.clear(); + } + else{ + if((tempChar >= '0') && (tempChar <= '9')){ + iss.putback(tempChar); + vector tempPref; + iss >> temp; + allRanksF[i][temp-1] = rank; + allPreferencesF[i][temp-1] = 0; + tempPref.push_back(temp-1); + f.preferences.push_back(tempPref); + f.nbTotPref+= tempPref.size(); + rank++; + tempIss.clear(); + } + } + } + } + + f.nbPref = f.preferences.size(); + families.push_back(f); + iss.clear(); + } + + file.close(); + + for (int i = 0; i < nbChildren; i++){ + children[i].ranks = children[i].preferences; + children[i].positions = children[i].preferences; + } + + for (int i = 0; i < nbFamilies; i++){ + families[i].ranks = families[i].preferences; + families[i].positions = families[i].preferences; + } + + // Fill ranks and positions + + for (int i = 0; i < nbChildren; i++){ + for(int k= 0; k < children[i].nbPref; k++){ + for(int l=0; l * thesep; + std::vector * otherp; + std::list *theseMustBeAllocatedp; + std::list *otherMustBeAllocatedp; + if (children_side) { + // Processing the lists of the children, removing families + thesep = &children; + otherp = &families; + theseMustBeAllocatedp = &childrenMustBeAllocated; + otherMustBeAllocatedp = &familiesMustBeAllocated; + number_here = nbChildren; + } else { + thesep = &families; + otherp = &children; + theseMustBeAllocatedp = &familiesMustBeAllocated; + otherMustBeAllocatedp = &childrenMustBeAllocated; + number_here = nbFamilies; + } + std::vector & these = (*thesep); + std::vector & other = (*otherp); + std::list & theseMustBeAllocated = (*theseMustBeAllocatedp); + std::list & otherMustBeAllocated = (*otherMustBeAllocatedp); + for (int i = 0; i < number_here; i++) { + // Early exit! + const float ratio = 0.1; + if (early_exit && (i >= ratio * number_here) && (nbTotRem == 0)) { + return 0; + } + // A graph is "named" with two integers. The first is a 0 for a candidate + // (aka these) or a 1 for a position (aka other) + Graph g; + int n_1 = 0; + for(int rank = 0; rank < these[i].nbPref; rank++) { + // No point in checking the last rank if we already know this agent must + // be allocated, or if we don't care + if ((rank == these[i].nbPref - 1) && (these[i].mustBeAllocated || !supp)) { + continue; + } + for(size_t ind = 0; ind < these[i].preferences[rank].size(); ind++) { + int position = these[i].preferences[rank][ind]; + g.addVertex(1, position); + int idxRank = these[i].ranks[rank][ind]; + for(int l = 0; l <= idxRank; l++) { + for(size_t k = 0; k < other[position].preferences[l].size(); k++) { + int other_cand = other[position].preferences[l][k]; + if (other_cand == i) { // Don't add the current candidate to the graph + continue; + } + if (! g.containsVertex(0, other_cand)) { + g.addVertex(0, other_cand); + n_1 += 1; + } + g.addEdge(position, other_cand); + } + } + } + // If n_1 is sufficiently small, then the largest matching must also be + // small, as the matching can use each vertex from n_1 at most once, so + // we don't even need to try to find a bigger matching. + bool matching_cant_exist = (2*n_1 + 1 <= g.size()); + if (! matching_cant_exist) { + for(size_t ind = 0; ind < these[i].preferences[rank].size(); ind++) { + int position = these[i].preferences[rank][ind]; + g.augment(position); + } + } + // Add P' in this + // Yes, I'm abusing while statements, so I can break out easier. + while (rank == 0) { + // Don't add P' if we don't need to. + if (matching_cant_exist || (g.size() - g.matchingSize() >= n_1 + 1)) { + break; + } + // First add all positions that must be filled. + for(int position: otherMustBeAllocated) { + // If position is acceptable to i, then skip it. + bool isAcceptable = false; + for(int otherRank = 0; (!isAcceptable) && otherRank < other[position].nbPref; otherRank++) { + for(size_t ind = 0; ind < other[position].preferences[otherRank].size(); ++ind) { + if (other[position].preferences[otherRank][ind] == i) { + isAcceptable = true; + break; + } + } + } + if (isAcceptable) { + continue; + } + g.addVertex(1, position); + for(int otherRank = 0; otherRank < other[position].nbPref; otherRank++) { + for(size_t ind = 0; ind < other[position].preferences[otherRank].size(); ++ind) { + int candidate = other[position].preferences[otherRank][ind]; + if (!g.containsVertex(0, candidate)) { + g.addVertex(0, candidate); + n_1 += 1; + } + g.addEdge(position, candidate); + } + } + g.augment(position); + } + // I'm using a while loop as an if statement, so I need to break out. + break; + } + if (matching_cant_exist || (g.size() - g.matchingSize() >= n_1 + 1)) { + // preprocess on rank! + // Firstly, they must be allocated, so mark as such (if we're in that + // mode) + if (supp && !these[i].mustBeAllocated) { + theseMustBeAllocated.push_back(i); + these[i].mustBeAllocated = true; + newMustAlways = true; + } +#ifdef DEBUG + if ((!children_side) and (i == 6)) { + std::cout << "g.size() = " << g.size() << ", g.matchingSize() = " << g.matchingSize(); + std::cout << ", n_1 = " << n_1 << std::endl; + g.printGraph(); + g.printMatching(); + } + if (children_side) { + std::cout << "child "; + } else { + std::cout << "family "; + } + std::cout << "worst rank of " << i << " is " << rank << " "; + int remHere = 0; +#endif /* DEBUG */ + for (int k = rank + 1; k < these[i].nbPref; k++) { + nbTotRem += these[i].preferences[k].size(); +#ifdef DEBUG + remHere += these[i].preferences[k].size(); +#endif /* DEBUG */ + these[i].nbTotPref -= these[i].preferences[k].size(); + for (unsigned int l = 0; l < these[i].preferences[k].size(); l++) { + int idxFam = these[i].preferences[k][l]; + int idxPos = these[i].positions[k][l]; + int idxRank = these[i].ranks[k][l]; + for (unsigned int m = idxPos + 1; + m < other[idxFam].preferences[idxRank].size(); m++) { + these[other[idxFam].preferences[idxRank][m]] + .positions[other[idxFam].ranks[idxRank][m]] + [other[idxFam].positions[idxRank][m]]--; + } + other[idxFam].nbTotPref--; + other[idxFam].positions[idxRank].erase( + other[idxFam].positions[idxRank].begin() + idxPos); + other[idxFam].ranks[idxRank].erase( + other[idxFam].ranks[idxRank].begin() + idxPos); + other[idxFam].preferences[idxRank].erase( + other[idxFam].preferences[idxRank].begin() + idxPos); + } + } + these[i].nbPref = rank + 1; + these[i].preferences.resize(these[i].nbPref); + these[i].ranks.resize(these[i].nbPref); + these[i].positions.resize(these[i].nbPref); +#ifdef DEBUG + std::cout << "removed " << remHere << std::endl; +#endif /* DEBUG */ + break; + } + } + } + if (nbTotRem > 0) { + polish(); + } + if ((nbTotRem == 0) && (newMustAlways)) { + return -1; + } + return nbTotRem; +} + +int Allocation::reductionMine(bool children_side, int mode, bool alt_store) { + int nbTotRem = 0; + int number_here; + std::vector * thesep; + std::vector * otherp; + if (children_side) { + thesep = &children; + otherp = &families; + number_here = nbChildren; + } else { + thesep = &families; + otherp = &children; + number_here = nbFamilies; + } + std::vector & these = (*thesep); + std::vector & other = (*otherp); + + for (int i = 0; i < number_here; i++) { + set candidates; + set positions; + vector cand_in(number_here, false); + int cand_size = 0; + int worst_rank = 0; + int count = 0; + AgentIterator iter(these[i], candidates, positions, these, other, mode); + for(std::pair p: iter) { + int j = p.first; + int k = p.second; + if (j > worst_rank) { + worst_rank = j; + } + int idxFam = these[i].preferences[j][k]; + int idxRank = these[i].ranks[j][k]; + positions.insert(idxFam); + count++; + for (int l = 0; l <= idxRank; l++) { + for (unsigned int m = 0; m < other[idxFam].preferences[l].size(); + m++) { + if ((alt_store && cand_in[other[idxFam].preferences[l][m]] == false) || + (!alt_store && candidates.count(other[idxFam].preferences[l][m]) == 0)) { + candidates.insert(other[idxFam].preferences[l][m]); + cand_in[other[idxFam].preferences[l][m]] = true; + cand_size++; + } + } + } + if (count >= cand_size) { +#ifdef DEBUG + if (children_side) { + std::cout << "child "; + } else { + std::cout << "family "; + } + std::cout << "worst rank of " << i << " is " << worst_rank << std::endl; +#endif /* DEBUG */ + for (int k = worst_rank + 1; k < these[i].nbPref; k++) { + nbTotRem += these[i].preferences[k].size(); + these[i].nbTotPref -= these[i].preferences[k].size(); + for (unsigned int l = 0; l < these[i].preferences[k].size(); l++) { + int idxFam = these[i].preferences[k][l]; + int idxPos = these[i].positions[k][l]; + int idxRank = these[i].ranks[k][l]; + for (unsigned int m = idxPos + 1; + m < other[idxFam].preferences[idxRank].size(); m++) { + these[other[idxFam].preferences[idxRank][m]] + .positions[other[idxFam].ranks[idxRank][m]] + [other[idxFam].positions[idxRank][m]]--; + } + other[idxFam].nbTotPref--; + other[idxFam].positions[idxRank].erase( + other[idxFam].positions[idxRank].begin() + idxPos); + other[idxFam].ranks[idxRank].erase( + other[idxFam].ranks[idxRank].begin() + idxPos); + other[idxFam].preferences[idxRank].erase( + other[idxFam].preferences[idxRank].begin() + idxPos); + } + } + these[i].nbPref = worst_rank + 1; + these[i].preferences.resize(these[i].nbPref); + these[i].ranks.resize(these[i].nbPref); + these[i].positions.resize(these[i].nbPref); + break; + } + } + } + if (nbTotRem > 0) { + polish(); + } + return nbTotRem; +} + +void Allocation::polish(){ + // Remove unused groups in families + for(int j=0; j > preferences; + vector > ranks; + vector > positions; + int idxRem = 0; + for(int k=0;k > preferences; + vector > ranks; + vector > positions; + int idxRem = 0; + for(int k=0;k childAllocated (nbChildren, 0); + vector familyAllocated (nbFamilies, 0); + + // Fill the vectors + for(int i=0; i= 0) familyAllocated[assignmentByChild[i]]++; + } + for(int i=0; i= 0) childAllocated[assignmentByFamily[i]]++; + } + + // Rank of the family assigned to children and vice versa + vector rankC(nbChildren, -1); + for(int i=0;i rankF(nbFamilies, -1); + for(int i=0;i 1){ + cout << "Allocation error: child " << i << " is allocated " << childAllocated[i] << " times " << endl; + mistake = true; + } + else sol1 += childAllocated[i]; + } + + // Check for family used twice + int sol2 = 0; + for(int i=0; i 1){ + cout << "Allocation error: family " << i << " is allocated " << familyAllocated[i] << " times " << endl; + mistake = true; + } + else sol2 += familyAllocated[i]; + } + + + // Check for stability by child + for(int i=0; i + #include +#include + #include + #include + #include + #include + #include + #include + + class Child; + typedef Child Family; + class Assignment; + class Allocation; + +/* ************************************************************************************* + *********************************** DOCTOR ***************************************** + ************************************************************************************* */ + + class Child{ + public: + int id; + int nbPref; + int nbTotPref; + bool mustBeAllocated; + vector > preferences; + vector > ranks; + vector > positions; + void print(bool); + }; + +/* ************************************************************************************* + ************************************* INFO ****************************************** + ************************************************************************************* */ + + class Info{ + public: + bool opt; + double timeCPU; + double timeCPUPP; + double LB; + double UB; + float contUB; + int nbCons; + int nbVar; + int nbNZ; + float contUB2; + int nbCons2; + int nbVar2; + int nbNZ2; + }; + +/* ************************************************************************************* + ********************************** ALLOCATION *************************************** + ************************************************************************************* */ + class Allocation{ + public: + // Data read from the file + string name; + int nbChildren; + int nbFamilies; + int total_reduced; + + vector children; + vector families; + + // Given by the ILP model + vector assignmentByChild; + vector assignmentByFamily; + + std::list childrenMustBeAllocated; + std::list familiesMustBeAllocated; + + Info infos; + + void load(const string& path, const string& filein); + void printProb(); + int reductionMine(bool children_side=true, int mode=0, bool alt_store=false); + int reductionExact(bool children_side, bool supp=false, bool early_exit=false); + void polish(); + void reduction(int mode); + void printSol(); + void printInfo(const string& pathAndFileout); + void checkSolution(); + }; + + +#endif diff --git a/SMTI/3_NOBIN_1STA_YESMERGED_MAXWT/Graph.cpp b/SMTI/3_NOBIN_1STA_YESMERGED_MAXWT/Graph.cpp new file mode 100644 index 0000000..0e487e7 --- /dev/null +++ b/SMTI/3_NOBIN_1STA_YESMERGED_MAXWT/Graph.cpp @@ -0,0 +1,107 @@ +#include +#include "Graph.h" + + +// Expected biggest graph, to save on allocations +const size_t expected_size = 50000; + +Graph::Graph() : _exists(2), _adjacents(2), _matching(2), _size(0), _matching_size(0) { + _exists[0] = std::vector(expected_size, false); + _exists[1] = std::vector(expected_size, false); + _adjacents[0] = std::vector>(expected_size); + _adjacents[1] = std::vector>(expected_size); + _matching[0] = std::vector(expected_size, -1); + _matching[1] = std::vector(expected_size, -1); +#ifdef DEBUG + std::cout << "New graph" << std::endl; +#endif /* DEBUG */ +} + +void Graph::addVertex(int side, int name) { + _exists[side][name] = true; + _size += 1; +} + +bool Graph::containsVertex(int side, int name) const { + return _exists[side][name]; +} + +/** + * Adds an edge to the graph. Note that this edge must always be added in the + * form (right, left) for things to work. + */ +void Graph::addEdge(int v1, int v2) { + _adjacents[1][v1].push_back(v2); + _adjacents[0][v2].push_back(v1); +} + +int Graph::size() const { + return _size; +} + +int Graph::matchingSize() const { + return _matching_size; +} + +/** + * Augment the matching, starting at vertex name which is on the right. + */ +void Graph::augment(int name) { +#ifdef DEBUG + std::cout << "Augmenting on " << _indices.at(start) << std::endl; + this->printGraph(); +#endif /* DEBUG */ + std::list path; + std::vector visited(expected_size, false); + path.push_back(name); + internal_augment(name, visited, path); +} + +/** + * Continues an augmentation, on vertex now, which is on the right. + */ +bool Graph::internal_augment(int now, std::vector & visited, + std::list & path) { + for(int next: _adjacents[1][now]) { + // next is on the left + if (visited[next]) { + continue; + } + if (_matching[0][next] == -1) { + // Found an augmenting path. Switch edges and return true. +#ifdef DEBUG + std::cout << "New matching found." << std::endl; +#endif /* DEBUG */ + path.push_back(next); +#ifdef DEBUG + std::cout << "Path is "; + for(auto p: path) { + std::cout << " " << _indices.at(p); + } + std::cout << std::endl; + +#endif /* DEBUG */ + while(!path.empty()) { + int right = path.front(); + path.pop_front(); + int left = path.front(); + path.pop_front(); + _matching[1][right] = left; + _matching[0][left] = right; + } + _matching_size += 1; + return true; + } + int next2 = _matching[0][next]; + path.push_back(next); + path.push_back(next2); + visited[next] = true; + if (internal_augment(next2, visited, path)) { + return true; + } + path.pop_back(); + path.pop_back(); + } + return false; +} + diff --git a/SMTI/3_NOBIN_1STA_YESMERGED_MAXWT/Graph.h b/SMTI/3_NOBIN_1STA_YESMERGED_MAXWT/Graph.h new file mode 100644 index 0000000..5d07f00 --- /dev/null +++ b/SMTI/3_NOBIN_1STA_YESMERGED_MAXWT/Graph.h @@ -0,0 +1,60 @@ +#ifndef GRAPH_H +#define GRAPH_H + +#include +#include +#include +#include +#include +#include + + +static_assert(std::numeric_limits::max() >= ((long unsigned)1 << 63), "size_t is too small"); + +struct pairhash { + public: + std::size_t operator()(const std::pair &x) const { + return (long)x.first * ((long)1 << 32) + x.second; + } +}; + +#ifdef DEBUG +#include +inline std::ostream& operator<<(std::ostream& o, const std::pair &x) { + o << "(" << x.first << ", " << x.second << ")"; + return o; +} +#endif /* DEBUG */ + + +class Graph { + public: + Graph(); + void addVertex(int side, int name); + bool containsVertex(int side, int name) const; + void addEdge(int v1, int v2); + int matched(int vertex) const; + void augment(int vertex); + + int size() const; + int matchingSize() const; + + int name(int vert_index); + +#ifdef DEBUG + void printGraph(); + void printMatching() const; +#endif /* DEBUG */ + + private: + std::vector> _exists; + std::vector>> _adjacents; + std::vector> _matching; + + int _size; + int _matching_size; + + bool internal_augment(int now, std::vector & visited, std::list & path); +}; + +#endif /* GRAPH_H */ diff --git a/SMTI/3_NOBIN_1STA_YESMERGED_MAXWT/main.cpp b/SMTI/3_NOBIN_1STA_YESMERGED_MAXWT/main.cpp new file mode 100644 index 0000000..c42141b --- /dev/null +++ b/SMTI/3_NOBIN_1STA_YESMERGED_MAXWT/main.cpp @@ -0,0 +1,220 @@ +#include "main.h" + +#define MAXTIME 3600 + +/* ************************************************************************************* + ************************************* MAIN ***************************************** + ************************************************************************************* */ + +int main(int argc, char **argv){ + + // local variables + Allocation allo ; + allo.total_reduced = 0; + string filein = argv[2]; + string path = argv[1]; + string pathAndFileout = argv[3]; + int mode = atoi(argv[4]); + + // functions + allo.load(path,filein); + //allo.printProb(); + //allo.reduction(); + //allo.printProb(); + + int res = manlove(allo, mode); + if (res != -1) { + allo.printSol(); + allo.checkSolution(); + } + allo.printInfo(pathAndFileout); +} + + +int manlove(Allocation& allo, int mode){ + double initTimeModelCPU = getCPUTime(); + GRBEnv env = GRBEnv(); + + double initTimeModelCPUPP = getCPUTime(); + if (mode != 12) { + allo.reduction(mode); + } + + //allo.printProb(); + allo.infos.timeCPUPP = getCPUTime() - initTimeModelCPUPP; + if (allo.infos.timeCPUPP > MAXTIME) { + cout << "Preprocessing took over MAXTIME seconds" << endl; + allo.infos.LB = 0; + allo.assignmentByChild.resize(allo.nbChildren, -1); + allo.assignmentByFamily.resize(allo.nbFamilies,-1); + return -1; + } + + // Model + try{ + // Local variables + GRBModel model = GRBModel(env); + GRBLinExpr objFun = 0; + + vector > > isChildIAllocatedToFamilyJ (allo.nbChildren); + + vector allocationOfChildI(allo.nbChildren); + vector allocationOfFamilyJ(allo.nbFamilies); + vector > fillingOfFamilyJUpToRankK(allo.nbFamilies); + + // Initialization + for (int i = 0; i < allo.nbChildren; i++){ + allocationOfChildI[i] = 0; + isChildIAllocatedToFamilyJ[i].resize(allo.children[i].nbPref); + for (int j = 0; j + #include + #include + #include "gurobi_c++.h" + #include "time.h" + #include "Allocation.h" + + float EPSILON = 0.001; + + int manlove(Allocation& allo, int reduction_mode); + +#endif diff --git a/SMTI/3_NOBIN_1STA_YESMERGED_MAXWT/makefile b/SMTI/3_NOBIN_1STA_YESMERGED_MAXWT/makefile new file mode 100644 index 0000000..a81bed9 --- /dev/null +++ b/SMTI/3_NOBIN_1STA_YESMERGED_MAXWT/makefile @@ -0,0 +1,22 @@ +SYSTEM = x86-64_sles10_4.1 +LIBFORMAT = static_pic + +GUROBI_DIR = /users/grad/wpette/opt/gurobi752/linux64 +CLIB = -L$(GUROBI_DIR)/lib/ -lgurobi75 +INC = $(GUROBI_DIR)/include/ +CPPLIB = -L$(GUROBI_DIR)/lib/ -lgurobi_c++ $(CLIB) +GUROBI_OPTS = -I$(INC) $(CPPLIB) -lpthread -lm -m64 + +CC = g++ +CFLAGS = -g -Wall -ansi -pedantic -DIL_STD -std=c++11 +DEBUG = -pg -g -Wall -ansi -pedantic -DIL_STD +OBJECTS = main.o Allocation.o time.o AgentIterator.o Graph.o + +exec : $(OBJECTS) + $(CC) $(CFLAGS) -o 3_NOBIN_1STA_YESMERGED_MAXWT $(OBJECTS) $(GUROBI_OPTS) + +.cpp.o : $< + $(CC) $(CFLAGS) $(GUROBI_OPTS) -c $< -o $@ + +clean : + rm -f $(OBJECTS) 3_NOBIN_1STA_YESMERGED_MAXWT diff --git a/SMTI/3_NOBIN_1STA_YESMERGED_MAXWT/time.cpp b/SMTI/3_NOBIN_1STA_YESMERGED_MAXWT/time.cpp new file mode 100644 index 0000000..4726bdf --- /dev/null +++ b/SMTI/3_NOBIN_1STA_YESMERGED_MAXWT/time.cpp @@ -0,0 +1,46 @@ +#include "time.h" + +#ifdef _WIN32 +#include +double getWallTime(){ + LARGE_INTEGER time,freq; + if (!QueryPerformanceFrequency(&freq)){ + // Handle error + return 0; + } + if (!QueryPerformanceCounter(&time)){ + // Handle error + return 0; + } + return (double)time.QuadPart / freq.QuadPart; +} +double getCPUTime(){ + FILETIME a,b,c,d; + if (GetProcessTimes(GetCurrentProcess(),&a,&b,&c,&d) != 0){ + // Returns total user time. + // Can be tweaked to include kernel times as well. + return + (double)(d.dwLowDateTime | + ((unsigned long long)d.dwHighDateTime << 32)) * 0.0000001; + }else{ + // Handle error + return 0; + } +} + +// Posix/Linux +#else +#include +#include +double getWallTime(){ + struct timeval time; + if (gettimeofday(&time,NULL)){ + // Handle error + return 0; + } + return (double)time.tv_sec + (double)time.tv_usec * .000001; +} +double getCPUTime(){ + return (double)clock() / CLOCKS_PER_SEC; +} +#endif \ No newline at end of file diff --git a/SMTI/3_NOBIN_1STA_YESMERGED_MAXWT/time.h b/SMTI/3_NOBIN_1STA_YESMERGED_MAXWT/time.h new file mode 100644 index 0000000..6f1cb4f --- /dev/null +++ b/SMTI/3_NOBIN_1STA_YESMERGED_MAXWT/time.h @@ -0,0 +1,15 @@ +#ifndef TIME_H + + #define TIME_H + + #ifdef WIN32 + #include + #else + #include + #include + #endif + + double getWallTime(); + double getCPUTime(); + +#endif diff --git a/SMTI/4_YESBIN_1STA_YESMERGED/AgentIterator.cpp b/SMTI/4_YESBIN_1STA_YESMERGED/AgentIterator.cpp new file mode 100644 index 0000000..88ceb8e --- /dev/null +++ b/SMTI/4_YESBIN_1STA_YESMERGED/AgentIterator.cpp @@ -0,0 +1,404 @@ +#include "AgentIterator.h" + +AgentIteratorBase::AgentIteratorBase(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group, int posn) : + _agent(agent), + _these(these), _other(other), + _positions(positions), _candidates(candidates) { + if (_agent.preferences.size() == 0) { + _group = -1; + } else { + _group = group; + } + _position = posn; +} + +AgentIteratorBase::~AgentIteratorBase() { } + +int AgentIteratorBase::get_group() const { + return _group; +} + +int AgentIteratorBase::get_position() const { + return _position; +} + +const Child & AgentIteratorBase::get_agent() const { + return _agent; +} + +const std::vector & AgentIteratorBase::get_these() const { + return _these; +} + +const std::vector & AgentIteratorBase::get_other() const { + return _other; +} +const std::set & AgentIteratorBase::get_positions() const { + return _positions; +} +const std::set & AgentIteratorBase::get_candidates() const { + return _candidates; +} + +void AgentIteratorBase::regularIncrement() { + _position++; + if (_agent.preferences[_group].size() == _position) { + _position = 0; + _group++; + if (_agent.preferences.size() == _group) { + _group = -1; + } + } +} + +bool AgentIterator::operator==(const AgentIterator & other) { + return get_group() == other.get_group() && get_position() == other.get_position(); +} + +bool AgentIterator::operator!=(const AgentIterator & other) { + return ! (*this == other); +} + +const std::pair AgentIterator::operator*() { + return std::pair(get_group(), get_position()); +} + +AgentIterator AgentIterator::begin() { + AgentIterator starter(this, 0, 0); + starter.base->begin(); + return starter; +} + +AgentIterator AgentIterator::end() { + return AgentIterator(this, -1, 0); +} + +AgentIterator::AgentIterator(const Child & agent, const std::set & candidates, const std::set & positions, + const std::vector & these, const std::vector & other, int mode) : + _mode(mode) { + switch (_mode) { + default: + case 0: + base = new DescendingIterator(agent, candidates, positions, these, other, 0, 0); + break; + case 1: + base = new SkipBigIterator(agent, candidates, positions, these, other, 5, 0, 0); + break; + case 2: + base = new BestIterator(agent, candidates, positions, these, other, 0, 0); + break; + case 3: + base = new SkipBigIterator(agent, candidates, positions, these, other, 15, 0, 0); + break; + case 4: + base = new SkipBigIterator(agent, candidates, positions, these, other, 50, 0, 0); + break; + case 5: + base = new BestGroupIterator(agent, candidates, positions, these, other, 0, 0); + break; + } + } + +AgentIterator::AgentIterator(AgentIterator *other) : + _mode(other->get_mode()) { + switch (_mode) { + default: + case 0: + base = new DescendingIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), other->get_group(), other->get_position()); + break; + case 1: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 5, other->get_group(), other->get_position()); + break; + case 2: + base = new BestIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), other->get_group(), other->get_position()); + break; + case 3: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 15, other->get_group(), other->get_position()); + break; + case 4: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 50, other->get_group(), other->get_position()); + break; + case 5: + base = new BestGroupIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), other->get_group(), other->get_position()); + break; + } + } + +AgentIterator::AgentIterator(AgentIterator *other, int group, int posn) : + _mode(other->get_mode()) { + switch (_mode) { + case 0: + base = new DescendingIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), group, posn); + break; + case 1: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 5, group, posn); + break; + case 2: + base = new BestIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), group, posn); + break; + case 3: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 15, group, posn); + break; + case 4: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 50, group, posn); + break; + case 5: + base = new BestGroupIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), group, posn); + break; + } + } + +AgentIterator::~AgentIterator() { + delete base; +} + +int AgentIterator::get_group() const { + return base->get_group(); +} + +int AgentIterator::get_position() const { + return base->get_position(); +} + +int AgentIterator::get_mode() const { + return _mode; +} + +DescendingIterator::DescendingIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group, int posn) : + AgentIteratorBase(agent, candidates, positions, these, other, group, posn) { + } + +void DescendingIterator::begin() { +} + +void DescendingIterator::increment() { + regularIncrement(); +} + +SkipBigIterator::SkipBigIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int skip, int group, int posn) : + AgentIteratorBase(agent, candidates, positions, these, other, group, posn) , _skip(skip) { + } + + +void SkipBigIterator::begin() { + int num_added = 0; + while (true) { + if (get_group() == -1) { + break; + } + num_added = 0; + int other_id = _agent.preferences[_group][_position]; + int other_rank = _agent.ranks[_group][_position]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(pref) == 0) { + num_added++; + } + } + } + if (num_added > _skip) { + regularIncrement(); + } else { + break; + } + } +} + +void SkipBigIterator::increment() { + int num_added = 0; + do { + regularIncrement(); + if (get_group() == -1) { + break; + } + num_added = 0; + int other_id = _agent.preferences[_group][_position]; + int other_rank = _agent.ranks[_group][_position]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(pref) == 0) { + num_added++; + } + } + } + } while (num_added > _skip); +} + +BestIterator::BestIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group, int posn) : + AgentIteratorBase(agent, candidates, positions, these, other, group, posn) { + } + +void BestIterator::increment() { + int lowest_added = -1; + int best_group = -1; + int best_posn = -1; + for(int group_no = 0; group_no < _agent.preferences.size(); ++group_no) { + auto & group = _agent.preferences[group_no]; + for(int posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + int other_rank = _agent.ranks[group_no][posn]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto other_pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(other_pref) == 0) { + num_added++; + } + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_group = group_no; + best_posn = posn; + } + } + } + if (lowest_added != -1) { + _group = best_group; + _position = best_posn; + std::cout << "Using " << _group << ", " << _position << std::endl; + } else { + _group = -1; + _position = 0; + } +} + +void BestIterator::begin() { + int lowest_added = -1; + int best_group = -1; + int best_posn = -1; + for(int group_no = 0; group_no < _agent.preferences.size(); ++group_no) { + auto & group = _agent.preferences[group_no]; + for(int posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + int other_rank = _agent.ranks[group_no][posn]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto other_pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(other_pref) == 0) { + num_added++; + } + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_group = group_no; + best_posn = posn; + } + } + } + if (lowest_added != -1) { + _group = best_group; + _position = best_posn; + std::cout << "Using " << _group << ", " << _position << std::endl; + } else { + _group = -1; + _position = 0; + } +} + +BestGroupIterator::BestGroupIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group, int posn) : + AgentIteratorBase(agent, candidates, positions, these, other, group, posn) { + } + +void BestGroupIterator::increment() { + int lowest_added = -1; + int best_posn = -1; + auto & group = _agent.preferences[_group]; + for(int posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + int other_rank = _agent.ranks[_group][posn]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto other_pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(other_pref) == 0) { + num_added++; + } + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_posn = posn; + } + } + if (lowest_added != -1) { + _position = best_posn; + } else { + _group++; + if (_group == _agent.preferences.size()) { + _position = 0; + _group = -1; + } else { + increment(); + } + } +} + +void BestGroupIterator::begin() { + int lowest_added = -1; + int best_posn = -1; + if (_group == -1) { + return; + } + auto & group = _agent.preferences[_group]; + for(int posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + int other_rank = _agent.ranks[_group][posn]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto other_pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(other_pref) == 0) { + num_added++; + } + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_posn = posn; + } + } + if (lowest_added != -1) { + _position = best_posn; + } else { + _group++; + if (_group == _agent.preferences.size()) { + _position = 0; + _group = -1; + } else { + increment(); + } + } +} diff --git a/SMTI/4_YESBIN_1STA_YESMERGED/AgentIterator.h b/SMTI/4_YESBIN_1STA_YESMERGED/AgentIterator.h new file mode 100644 index 0000000..48b96c6 --- /dev/null +++ b/SMTI/4_YESBIN_1STA_YESMERGED/AgentIterator.h @@ -0,0 +1,110 @@ +#ifndef AGENTITERATOR_H +#define AGENTITERATOR_H + +#include + +#include "Allocation.h" + +class AgentIteratorBase { +public: + AgentIteratorBase(const Child & agent, const std::set & candidates, const std::set & positions, + const std::vector & these, const std::vector & other, int group=0, int posn=0); + virtual ~AgentIteratorBase() = 0; + virtual void increment() = 0; + virtual void begin() = 0; + + int get_position() const; + int get_group() const; + const Child & get_agent() const; + const std::vector & get_these() const; + const std::vector & get_other() const; + const std::set & get_positions() const; + const std::set & get_candidates() const; +protected: + void regularIncrement(); + + const Child & _agent; + int _group; + int _position; + const std::vector & _these; + const std::vector & _other; + const std::set & _positions; + const std::set & _candidates; +}; + + +class AgentIterator : public std::iterator, ptrdiff_t> { +public: + AgentIterator(const Child & agent, const std::set & candidates, const std::set & positions, + const std::vector & these, const std::vector & other, int mode); + AgentIterator(AgentIterator *other, int group, int posn); + AgentIterator(AgentIterator *other); + ~AgentIterator(); + bool operator==(const AgentIterator& other); + bool operator!=(const AgentIterator& other); + const std::pair operator*(); + AgentIterator& operator++() {base->increment(); return *this; } + AgentIterator operator++(int) {AgentIterator res(this); base->increment(); return res; } + + AgentIterator begin(); + AgentIterator end(); + + int get_position() const; + int get_group() const; + int get_mode() const; + + const Child & get_agent() const { return base->get_agent(); } + const std::vector & get_these() const {return base->get_these(); } + const std::vector & get_other() const {return base->get_other(); } + const std::set & get_positions() const {return base->get_positions(); } + const std::set & get_candidates() const {return base->get_candidates(); } +private: + AgentIteratorBase * base; + int _mode; +}; + + +class DescendingIterator : public AgentIteratorBase { + public: + DescendingIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group=0, int posn=0); + ~DescendingIterator() {} + void increment(); + void begin(); +}; + + +class SkipBigIterator : public AgentIteratorBase { + public: + SkipBigIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int skip, int group, int posn); + ~SkipBigIterator() {} + void increment(); + void begin(); + private: + int _skip; +}; + +class BestIterator : public AgentIteratorBase { + public: + BestIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group=0, int posn=0); + ~BestIterator() {} + void increment(); + void begin(); +}; + +class BestGroupIterator : public AgentIteratorBase { + public: + BestGroupIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group=0, int posn=0); + ~BestGroupIterator() {} + void increment(); + void begin(); +}; + +#endif /* AGENTITERATOR_H */ diff --git a/SMTI/4_YESBIN_1STA_YESMERGED/Allocation.cpp b/SMTI/4_YESBIN_1STA_YESMERGED/Allocation.cpp index 44a6851..46fae7d 100644 --- a/SMTI/4_YESBIN_1STA_YESMERGED/Allocation.cpp +++ b/SMTI/4_YESBIN_1STA_YESMERGED/Allocation.cpp @@ -1,29 +1,17 @@ #include "Allocation.h" +#include "AgentIterator.h" +#include "Graph.h" /* ************************************************************************************* *********************************** DOCTOR ***************************************** ************************************************************************************* */ -void Child::print(){ - cout << "Child " << id << "\t Preferences (" << nbPref << " groups, " << nbTotPref << " in total)\t"; - for(int i=0; i 0) cout << " "; - cout << preferences[i][j]; - cout << "[" << ranks[i][j] << "_" << positions[i][j] << "]"; - } - cout << ") "; - } - cout << endl; -} - -/* ************************************************************************************* - *********************************** HOSPITAL **************************************** - ************************************************************************************* */ - -void Family::print(){ - cout << "Family " << id << "\t Preferences (" << nbPref << " groups, " << nbTotPref << " in total)\t"; +void Child::print(bool family){ + if (family) + cout << "Family "; + else + cout << "Child "; + cout << id << "\t Preferences (" << nbPref << " groups, " << nbTotPref << " in total)\t"; for(int i=0; i, vector >::iterator it; - map, vector > mapFirstChoice; - for(int j=0; j temp(nbChildren,0); - if(families[j].nbPref > 0){ - for(int k=0;k, vector > add; - add.first = temp; - add.second.push_back(j); - mapFirstChoice.insert(add); - } - else{ - (*it).second.push_back(j); - } - } - else count++; - } - -/* for(it = mapFirstChoice.begin(); it!= mapFirstChoice.end(); ++it){ - cout << (*it).second.size() << " x (" << families[(*it).second[0]].preferences[0].size() << ") ["; - for(int i=0;i<(*it).second.size();i++){ - cout << (*it).second[i] << " "; - } - cout << "] == ["; - for(int i=0;i<(*it).first.size();i++){ - cout << (*it).first[i] << " "; - } - cout << "]" << endl; - } - - cout << "Count = " << count << endl;*/ - - // Step 2 -- See worst rank - - vector worstRank(nbChildren); - for(int i=0;i= families[(*it).second[0]].preferences[0].size() ){ - // cout << "Updates from " << co << endl;; co++; - for(int i=0; i < families[(*it).second[0]].preferences[0].size();i++){ - multiset orderedRanks; - multiset::iterator it2; - for(int j=0; j<(*it).second.size();j++){ - orderedRanks.insert(families[(*it).second[j]].ranks[0][i]); - } - // cout << "worstRank of " << families[(*it).second[0]].preferences[0][i] << " updated from " << worstRank[families[(*it).second[0]].preferences[0][i]]; - it2 = orderedRanks.begin(); - advance(it2, families[(*it).second[0]].preferences[0].size() - 1); - worstRank[families[(*it).second[0]].preferences[0][i]]=min(worstRank[families[(*it).second[0]].preferences[0][i]], *(it2)); - // cout << " to " << worstRank[families[(*it).second[0]].preferences[0][i]] << endl; - } - } - } - - // Step 3 -- Remove families after worst rank from child's preferences - +int Allocation::reductionExact(bool children_side, bool supp, bool early_exit) { int nbTotRem = 0; - - for(int i=0; i * thesep; + std::vector * otherp; + std::list *theseMustBeAllocatedp; + std::list *otherMustBeAllocatedp; + if (children_side) { + // Processing the lists of the children, removing families + thesep = &children; + otherp = &families; + theseMustBeAllocatedp = &childrenMustBeAllocated; + otherMustBeAllocatedp = &familiesMustBeAllocated; + number_here = nbChildren; + } else { + thesep = &families; + otherp = &children; + theseMustBeAllocatedp = &familiesMustBeAllocated; + otherMustBeAllocatedp = &childrenMustBeAllocated; + number_here = nbFamilies; + } + std::vector & these = (*thesep); + std::vector & other = (*otherp); + std::list & theseMustBeAllocated = (*theseMustBeAllocatedp); + std::list & otherMustBeAllocated = (*otherMustBeAllocatedp); + for (int i = 0; i < number_here; i++) { + // Early exit! + const float ratio = 0.1; + if (early_exit && (i >= ratio * number_here) && (nbTotRem == 0)) { + return 0; } - children[i].nbPref = worstRank[i] + 1; - children[i].preferences.resize(children[i].nbPref); - children[i].ranks.resize(children[i].nbPref); - children[i].positions.resize(children[i].nbPref); - } - - polish(); - return nbTotRem; -} - -int Allocation::reductionChi1(){ - - // Step 1 -- Create map - - int count = 0; - map, vector >::iterator it; - map, vector > mapFirstChoice; - for(int j=0; j temp(nbFamilies,0); - if(children[j].nbPref > 0){ - for(int k=0;k, vector > add; - add.first = temp; - add.second.push_back(j); - mapFirstChoice.insert(add); - } - else{ - (*it).second.push_back(j); + // A graph is "named" with two integers. The first is a 0 for a candidate + // (aka these) or a 1 for a position (aka other) + Graph g; + int n_1 = 0; + for(int rank = 0; rank < these[i].nbPref; rank++) { + // No point in checking the last rank if we already know this agent must + // be allocated, or if we don't care + if ((rank == these[i].nbPref - 1) && (these[i].mustBeAllocated || !supp)) { + continue; } - } - else count++; - } - -/* for(it = mapFirstChoice.begin(); it!= mapFirstChoice.end(); ++it){ - cout << (*it).second.size() << " x (" << children[(*it).second[0]].preferences[0].size() << ") ["; - for(int i=0;i<(*it).second.size();i++){ - cout << (*it).second[i] << " "; - } - cout << "] == ["; - for(int i=0;i<(*it).first.size();i++){ - cout << (*it).first[i] << " "; - } - cout << "]" << endl; - } - - cout << "Count = " << count << endl;*/ - - // Step 2 -- See worst rank - - vector worstRank(nbFamilies); - for(int i=0;i= children[(*it).second[0]].preferences[0].size() ){ - // cout << "Updates from " << co << endl;; co++; - for(int i=0; i < children[(*it).second[0]].preferences[0].size();i++){ - multiset orderedRanks; - multiset::iterator it2; - for(int j=0; j<(*it).second.size();j++){ - orderedRanks.insert(children[(*it).second[j]].ranks[0][i]); + for(size_t ind = 0; ind < these[i].preferences[rank].size(); ind++) { + int position = these[i].preferences[rank][ind]; + g.addVertex(1, position); + int idxRank = these[i].ranks[rank][ind]; + for(int l = 0; l <= idxRank; l++) { + for(size_t k = 0; k < other[position].preferences[l].size(); k++) { + int other_cand = other[position].preferences[l][k]; + if (other_cand == i) { // Don't add the current candidate to the graph + continue; + } + if (! g.containsVertex(0, other_cand)) { + g.addVertex(0, other_cand); + n_1 += 1; + } + g.addEdge(position, other_cand); + } } - // cout << "worstRank of " << children[(*it).second[0]].preferences[0][i] << " updated from " << worstRank[children[(*it).second[0]].preferences[0][i]]; - it2 = orderedRanks.begin(); - advance(it2, children[(*it).second[0]].preferences[0].size() - 1); - worstRank[children[(*it).second[0]].preferences[0][i]]=min(worstRank[children[(*it).second[0]].preferences[0][i]], *(it2)); - // cout << " to " << worstRank[children[(*it).second[0]].preferences[0][i]] << endl; } - } - } - - // Step 3 -- Remove families after worst rank from child's preferences - - int nbTotRem = 0; - - for(int i=0; i worstRank(nbChildren); - for(int i=0;i allChildren; - int count = 0; - for(int j=0; j= n_1 + 1)) { + break; } - } - if(count >= allChildren.size()){ - worstRank[i] = j; - // cout << "worst rank of " << i << " is " << j << endl; + // First add all positions that must be filled. + for(int position: otherMustBeAllocated) { + // If position is acceptable to i, then skip it. + bool isAcceptable = false; + for(int otherRank = 0; (!isAcceptable) && otherRank < other[position].nbPref; otherRank++) { + for(size_t ind = 0; ind < other[position].preferences[otherRank].size(); ++ind) { + if (other[position].preferences[otherRank][ind] == i) { + isAcceptable = true; + break; + } + } + } + if (isAcceptable) { + continue; + } + g.addVertex(1, position); + for(int otherRank = 0; otherRank < other[position].nbPref; otherRank++) { + for(size_t ind = 0; ind < other[position].preferences[otherRank].size(); ++ind) { + int candidate = other[position].preferences[otherRank][ind]; + if (!g.containsVertex(0, candidate)) { + g.addVertex(0, candidate); + n_1 += 1; + } + g.addEdge(position, candidate); + } + } + g.augment(position); + } + // I'm using a while loop as an if statement, so I need to break out. break; } - } - } - - for(int i=0; i= n_1 + 1)) { + // preprocess on rank! + // Firstly, they must be allocated, so mark as such (if we're in that + // mode) + if (supp && !these[i].mustBeAllocated) { + theseMustBeAllocated.push_back(i); + these[i].mustBeAllocated = true; + newMustAlways = true; + } +#ifdef DEBUG + if ((!children_side) and (i == 6)) { + std::cout << "g.size() = " << g.size() << ", g.matchingSize() = " << g.matchingSize(); + std::cout << ", n_1 = " << n_1 << std::endl; + g.printGraph(); + g.printMatching(); + } + if (children_side) { + std::cout << "child "; + } else { + std::cout << "family "; + } + std::cout << "worst rank of " << i << " is " << rank << " "; + int remHere = 0; +#endif /* DEBUG */ + for (int k = rank + 1; k < these[i].nbPref; k++) { + nbTotRem += these[i].preferences[k].size(); +#ifdef DEBUG + remHere += these[i].preferences[k].size(); +#endif /* DEBUG */ + these[i].nbTotPref -= these[i].preferences[k].size(); + for (unsigned int l = 0; l < these[i].preferences[k].size(); l++) { + int idxFam = these[i].preferences[k][l]; + int idxPos = these[i].positions[k][l]; + int idxRank = these[i].ranks[k][l]; + for (unsigned int m = idxPos + 1; + m < other[idxFam].preferences[idxRank].size(); m++) { + these[other[idxFam].preferences[idxRank][m]] + .positions[other[idxFam].ranks[idxRank][m]] + [other[idxFam].positions[idxRank][m]]--; + } + other[idxFam].nbTotPref--; + other[idxFam].positions[idxRank].erase( + other[idxFam].positions[idxRank].begin() + idxPos); + other[idxFam].ranks[idxRank].erase( + other[idxFam].ranks[idxRank].begin() + idxPos); + other[idxFam].preferences[idxRank].erase( + other[idxFam].preferences[idxRank].begin() + idxPos); + } } - families[idxFam].nbTotPref--; - families[idxFam].positions[idxRank].erase(families[idxFam].positions[idxRank].begin() + idxPos); - families[idxFam].ranks[idxRank].erase(families[idxFam].ranks[idxRank].begin() + idxPos); - families[idxFam].preferences[idxRank].erase(families[idxFam].preferences[idxRank].begin() + idxPos); + these[i].nbPref = rank + 1; + these[i].preferences.resize(these[i].nbPref); + these[i].ranks.resize(these[i].nbPref); + these[i].positions.resize(these[i].nbPref); +#ifdef DEBUG + std::cout << "removed " << remHere << std::endl; +#endif /* DEBUG */ + break; } } - children[i].nbPref = worstRank[i] + 1; - children[i].preferences.resize(children[i].nbPref); - children[i].ranks.resize(children[i].nbPref); - children[i].positions.resize(children[i].nbPref); } - - polish(); + if (nbTotRem > 0) { + polish(); + } + if ((nbTotRem == 0) && (newMustAlways)) { + return -1; + } return nbTotRem; } -int Allocation::reductionChi2(){ - +int Allocation::reductionMine(bool children_side, int mode, bool alt_store) { int nbTotRem = 0; - vector worstRank(nbFamilies); - for(int i=0;i allFamilies; + int number_here; + std::vector * thesep; + std::vector * otherp; + if (children_side) { + thesep = &children; + otherp = &families; + number_here = nbChildren; + } else { + thesep = &families; + otherp = &children; + number_here = nbFamilies; + } + std::vector & these = (*thesep); + std::vector & other = (*otherp); + + for (int i = 0; i < number_here; i++) { + set candidates; + set positions; + vector cand_in(number_here, false); + int cand_size = 0; + int worst_rank = 0; int count = 0; - for(int j=0; j p: iter) { + int j = p.first; + int k = p.second; + if (j > worst_rank) { + worst_rank = j; + } + int idxFam = these[i].preferences[j][k]; + int idxRank = these[i].ranks[j][k]; + positions.insert(idxFam); + count++; + for (int l = 0; l <= idxRank; l++) { + for (unsigned int m = 0; m < other[idxFam].preferences[l].size(); + m++) { + if ((alt_store && cand_in[other[idxFam].preferences[l][m]] == false) || + (!alt_store && candidates.count(other[idxFam].preferences[l][m]) == 0)) { + candidates.insert(other[idxFam].preferences[l][m]); + cand_in[other[idxFam].preferences[l][m]] = true; + cand_size++; + } } } - if(count >= allFamilies.size()){ - worstRank[i] = j; - // cout << "worst rank of " << i << " is " << j << endl; + if (count >= cand_size) { +#ifdef DEBUG + if (children_side) { + std::cout << "child "; + } else { + std::cout << "family "; + } + std::cout << "worst rank of " << i << " is " << worst_rank << std::endl; +#endif /* DEBUG */ + for (int k = worst_rank + 1; k < these[i].nbPref; k++) { + nbTotRem += these[i].preferences[k].size(); + these[i].nbTotPref -= these[i].preferences[k].size(); + for (unsigned int l = 0; l < these[i].preferences[k].size(); l++) { + int idxFam = these[i].preferences[k][l]; + int idxPos = these[i].positions[k][l]; + int idxRank = these[i].ranks[k][l]; + for (unsigned int m = idxPos + 1; + m < other[idxFam].preferences[idxRank].size(); m++) { + these[other[idxFam].preferences[idxRank][m]] + .positions[other[idxFam].ranks[idxRank][m]] + [other[idxFam].positions[idxRank][m]]--; + } + other[idxFam].nbTotPref--; + other[idxFam].positions[idxRank].erase( + other[idxFam].positions[idxRank].begin() + idxPos); + other[idxFam].ranks[idxRank].erase( + other[idxFam].ranks[idxRank].begin() + idxPos); + other[idxFam].preferences[idxRank].erase( + other[idxFam].preferences[idxRank].begin() + idxPos); + } + } + these[i].nbPref = worst_rank + 1; + these[i].preferences.resize(these[i].nbPref); + these[i].ranks.resize(these[i].nbPref); + these[i].positions.resize(these[i].nbPref); break; } } } - - for(int i=0; i 0) { + polish(); } - - polish(); return nbTotRem; } @@ -605,20 +553,94 @@ void Allocation::polish(){ } } -void Allocation::reduction(){ - int nbRed1 = 0; - int nbRed2 = 0; - int nbRed3 = 0; - int nbRed4 = 0; +void Allocation::reduction(int mode){ + total_reduced = 0; int i = 0; - do{ - nbRed1 = reductionFam1(); - nbRed2 = reductionChi1(); - nbRed3 = reductionFam2(); - nbRed4 = reductionChi2(); - cout << "Reduction iteration " << i << " reductionFam1 " << nbRed1 << " reductionChi1 " << nbRed2 << " reductionFam2 " << nbRed3 << " reductionChi2 " << nbRed4 << endl; - i++; - }while(nbRed1 + nbRed2 + nbRed3 + nbRed4 != 0); + int num = 0; + bool keepGoing; + if (mode == 7) { + do { + num = reductionMine(false, 1); + num += reductionMine(true, 1); + cout << "Iteration " << i << " in heuristic removed " << num << std::endl; + i++; + total_reduced += num; + } while (num != 0); + do { + num = reductionExact(false); + num += reductionExact(true); + cout << "Iteration " << i << " in exact mode removed " << num << std::endl; + i++; + total_reduced += num; + } while (num != 0); + } else if (mode == 11) { + do { + num = reductionMine(true, 1); + num += reductionMine(false, 1); + cout << "Iteration " << i << " in heuristic removed " << num << std::endl; + i++; + total_reduced += num; + } while (num != 0); + do { + num = reductionExact(true); + num += reductionExact(false); + cout << "Iteration " << i << " in exact mode removed " << num << std::endl; + i++; + total_reduced += num; + } while (num != 0); + } else { + do{ + keepGoing = false; + if (mode == 6) { + // True means preprocess childrens' lists, removing families. + // False means preprocess families' lists, removing children. + num = reductionExact(false); + num += reductionExact(true); + } else if (mode == 8) { + num = reductionExact(true); + num += reductionExact(false); + } else if (mode == 9) { + num = reductionExact(false, true); + if (num == -1) { + num = 0; + keepGoing = true; + } + int nextNum = reductionExact(true, true); + if (nextNum == -1) { + nextNum = 0; + keepGoing = true; + } + num += nextNum; + } else if (mode == 10) { + num = reductionExact(true, true); + if (num == -1) { + num = 0; + keepGoing = true; + } + int nextNum = reductionExact(false, true); + if (nextNum == -1) { + nextNum = 0; + keepGoing = true; + } + num += nextNum; + } else if (mode == 13) { + num = reductionMine(false, 0, true); + num += reductionMine(true, 0, true); + } else if (mode == 14) { + num = reductionExact(false, false, true); + num += reductionExact(true, false, true); + } else if (mode == 15) { + num = reductionExact(true, false, true); + num += reductionExact(false, false, true); + } else { + num = reductionMine(false, mode); + num += reductionMine(true, mode); + } + cout << "Iteration " << i << " in mode " << mode << " removed " << num << std::endl; + i++; + total_reduced += num; + }while(keepGoing || (num != 0)); + } } void Allocation::printSol(){ @@ -631,7 +653,7 @@ void Allocation::printSol(){ void Allocation::printInfo(const string& pathAndFileout){ string nameFile = pathAndFileout; std::ofstream file(nameFile.c_str(), std::ios::out | std::ios::app); - file << name << "\t" << infos.opt << "\t" << infos.timeCPU << "\t" << infos.timeCPUPP << "\t"<< infos.LB << "\t" << infos.UB << "\t" << infos.contUB << "\t" << infos.nbVar << "\t" << infos.nbCons << "\t" << infos.nbNZ + file << name << "\t" << infos.opt << "\t" << infos.timeCPU << "\t" << infos.timeCPUPP << "\t" << total_reduced << "\t"<< infos.LB << "\t" << infos.UB << "\t" << infos.contUB << "\t" << infos.nbVar << "\t" << infos.nbCons << "\t" << infos.nbNZ << "\t" << infos.contUB2 << "\t" << infos.nbVar2 << "\t" << infos.nbCons2 << "\t" << infos.nbNZ2 << endl; file.close(); } diff --git a/SMTI/4_YESBIN_1STA_YESMERGED/Allocation.h b/SMTI/4_YESBIN_1STA_YESMERGED/Allocation.h index dcd6046..6e45c0c 100644 --- a/SMTI/4_YESBIN_1STA_YESMERGED/Allocation.h +++ b/SMTI/4_YESBIN_1STA_YESMERGED/Allocation.h @@ -4,6 +4,7 @@ using namespace std; #include #include +#include #include #include #include @@ -12,7 +13,7 @@ #include class Child; - class Family; + typedef Child Family; class Assignment; class Allocation; @@ -21,29 +22,15 @@ ************************************************************************************* */ class Child{ - public: - int id; - int nbPref; - int nbTotPref; - vector > preferences; - vector > ranks; - vector > positions; - void print(); - }; - -/* ************************************************************************************* - *********************************** HOSPITAL **************************************** - ************************************************************************************* */ - - class Family{ public: int id; int nbPref; int nbTotPref; + bool mustBeAllocated; vector > preferences; vector > ranks; vector > positions; - void print(); + void print(bool); }; /* ************************************************************************************* @@ -76,6 +63,7 @@ string name; int nbChildren; int nbFamilies; + int total_reduced; vector children; vector families; @@ -84,20 +72,21 @@ vector assignmentByChild; vector assignmentByFamily; + std::list childrenMustBeAllocated; + std::list familiesMustBeAllocated; + Info infos; void load(const string& path, const string& filein); void printProb(); - int reductionFam1(); - int reductionChi1(); - int reductionFam2(); - int reductionChi2(); + int reductionMine(bool children_side=true, int mode=0, bool alt_store=false); + int reductionExact(bool children_side, bool supp=false, bool early_exit=false); void polish(); - void reduction(); + void reduction(int mode); void printSol(); void printInfo(const string& pathAndFileout); void checkSolution(); }; -#endif \ No newline at end of file +#endif diff --git a/SMTI/4_YESBIN_1STA_YESMERGED/Graph.cpp b/SMTI/4_YESBIN_1STA_YESMERGED/Graph.cpp new file mode 100644 index 0000000..0e487e7 --- /dev/null +++ b/SMTI/4_YESBIN_1STA_YESMERGED/Graph.cpp @@ -0,0 +1,107 @@ +#include +#include "Graph.h" + + +// Expected biggest graph, to save on allocations +const size_t expected_size = 50000; + +Graph::Graph() : _exists(2), _adjacents(2), _matching(2), _size(0), _matching_size(0) { + _exists[0] = std::vector(expected_size, false); + _exists[1] = std::vector(expected_size, false); + _adjacents[0] = std::vector>(expected_size); + _adjacents[1] = std::vector>(expected_size); + _matching[0] = std::vector(expected_size, -1); + _matching[1] = std::vector(expected_size, -1); +#ifdef DEBUG + std::cout << "New graph" << std::endl; +#endif /* DEBUG */ +} + +void Graph::addVertex(int side, int name) { + _exists[side][name] = true; + _size += 1; +} + +bool Graph::containsVertex(int side, int name) const { + return _exists[side][name]; +} + +/** + * Adds an edge to the graph. Note that this edge must always be added in the + * form (right, left) for things to work. + */ +void Graph::addEdge(int v1, int v2) { + _adjacents[1][v1].push_back(v2); + _adjacents[0][v2].push_back(v1); +} + +int Graph::size() const { + return _size; +} + +int Graph::matchingSize() const { + return _matching_size; +} + +/** + * Augment the matching, starting at vertex name which is on the right. + */ +void Graph::augment(int name) { +#ifdef DEBUG + std::cout << "Augmenting on " << _indices.at(start) << std::endl; + this->printGraph(); +#endif /* DEBUG */ + std::list path; + std::vector visited(expected_size, false); + path.push_back(name); + internal_augment(name, visited, path); +} + +/** + * Continues an augmentation, on vertex now, which is on the right. + */ +bool Graph::internal_augment(int now, std::vector & visited, + std::list & path) { + for(int next: _adjacents[1][now]) { + // next is on the left + if (visited[next]) { + continue; + } + if (_matching[0][next] == -1) { + // Found an augmenting path. Switch edges and return true. +#ifdef DEBUG + std::cout << "New matching found." << std::endl; +#endif /* DEBUG */ + path.push_back(next); +#ifdef DEBUG + std::cout << "Path is "; + for(auto p: path) { + std::cout << " " << _indices.at(p); + } + std::cout << std::endl; + +#endif /* DEBUG */ + while(!path.empty()) { + int right = path.front(); + path.pop_front(); + int left = path.front(); + path.pop_front(); + _matching[1][right] = left; + _matching[0][left] = right; + } + _matching_size += 1; + return true; + } + int next2 = _matching[0][next]; + path.push_back(next); + path.push_back(next2); + visited[next] = true; + if (internal_augment(next2, visited, path)) { + return true; + } + path.pop_back(); + path.pop_back(); + } + return false; +} + diff --git a/SMTI/4_YESBIN_1STA_YESMERGED/Graph.h b/SMTI/4_YESBIN_1STA_YESMERGED/Graph.h new file mode 100644 index 0000000..5d07f00 --- /dev/null +++ b/SMTI/4_YESBIN_1STA_YESMERGED/Graph.h @@ -0,0 +1,60 @@ +#ifndef GRAPH_H +#define GRAPH_H + +#include +#include +#include +#include +#include +#include + + +static_assert(std::numeric_limits::max() >= ((long unsigned)1 << 63), "size_t is too small"); + +struct pairhash { + public: + std::size_t operator()(const std::pair &x) const { + return (long)x.first * ((long)1 << 32) + x.second; + } +}; + +#ifdef DEBUG +#include +inline std::ostream& operator<<(std::ostream& o, const std::pair &x) { + o << "(" << x.first << ", " << x.second << ")"; + return o; +} +#endif /* DEBUG */ + + +class Graph { + public: + Graph(); + void addVertex(int side, int name); + bool containsVertex(int side, int name) const; + void addEdge(int v1, int v2); + int matched(int vertex) const; + void augment(int vertex); + + int size() const; + int matchingSize() const; + + int name(int vert_index); + +#ifdef DEBUG + void printGraph(); + void printMatching() const; +#endif /* DEBUG */ + + private: + std::vector> _exists; + std::vector>> _adjacents; + std::vector> _matching; + + int _size; + int _matching_size; + + bool internal_augment(int now, std::vector & visited, std::list & path); +}; + +#endif /* GRAPH_H */ diff --git a/SMTI/4_YESBIN_1STA_YESMERGED/main.cpp b/SMTI/4_YESBIN_1STA_YESMERGED/main.cpp index b2bd404..5fb4f9a 100644 --- a/SMTI/4_YESBIN_1STA_YESMERGED/main.cpp +++ b/SMTI/4_YESBIN_1STA_YESMERGED/main.cpp @@ -1,5 +1,7 @@ #include "main.h" +#define MAXTIME 3600 + /* ************************************************************************************* ************************************* MAIN ***************************************** ************************************************************************************* */ @@ -8,30 +10,42 @@ int main(int argc, char **argv){ // local variables Allocation allo ; + allo.total_reduced = 0; string filein = argv[2]; string path = argv[1]; string pathAndFileout = argv[3]; + int mode = atoi(argv[4]); // functions allo.load(path,filein); - allo.printProb(); + //allo.printProb(); - manlove(allo); - - allo.printSol(); - allo.checkSolution(); + int res = manlove(allo, mode); + if (res != -1) { + allo.printSol(); + allo.checkSolution(); + } allo.printInfo(pathAndFileout); } -int manlove(Allocation& allo){ +int manlove(Allocation& allo, int mode){ double initTimeModelCPU = getCPUTime(); GRBEnv env = GRBEnv(); double initTimeModelCPUPP = getCPUTime(); - allo.reduction(); - allo.printProb(); + if (mode != 12) { + allo.reduction(mode); + } + //allo.printProb(); allo.infos.timeCPUPP = getCPUTime() - initTimeModelCPUPP; + if (allo.infos.timeCPUPP > MAXTIME) { + cout << "Preprocessing took over " << MAXTIME << " seconds" << endl; + allo.infos.LB = 0; + allo.assignmentByChild.resize(allo.nbChildren, -1); + allo.assignmentByFamily.resize(allo.nbFamilies,-1); + return -1; + } // Model try{ @@ -126,7 +140,7 @@ int manlove(Allocation& allo){ } // Setting of Gurobi - model.getEnv().set(GRB_DoubleParam_TimeLimit, 3600 - (getCPUTime() - initTimeModelCPU)); + model.getEnv().set(GRB_DoubleParam_TimeLimit, MAXTIME - (getCPUTime() - initTimeModelCPU)); model.getEnv().set(GRB_IntParam_Threads, 1); model.getEnv().set(GRB_DoubleParam_MIPGap, 0); model.optimize(); diff --git a/SMTI/4_YESBIN_1STA_YESMERGED/main.h b/SMTI/4_YESBIN_1STA_YESMERGED/main.h index c441859..3bf5282 100644 --- a/SMTI/4_YESBIN_1STA_YESMERGED/main.h +++ b/SMTI/4_YESBIN_1STA_YESMERGED/main.h @@ -11,6 +11,6 @@ float EPSILON = 0.001; - int manlove(Allocation& allo); + int manlove(Allocation& allo, int reduction_mode); #endif diff --git a/SMTI/4_YESBIN_1STA_YESMERGED/makefile b/SMTI/4_YESBIN_1STA_YESMERGED/makefile index c209696..3398d88 100644 --- a/SMTI/4_YESBIN_1STA_YESMERGED/makefile +++ b/SMTI/4_YESBIN_1STA_YESMERGED/makefile @@ -8,15 +8,15 @@ CPPLIB = -L$(GUROBI_DIR)/lib/ -lgurobi_c++ $(CLIB) GUROBI_OPTS = -I$(INC) $(CPPLIB) -lpthread -lm -m64 CC = g++ -CFLAGS = -O2 -Wall -ansi -pedantic -DIL_STD +CFLAGS = -O2 -Wall -ansi -pedantic -DIL_STD -std=c++11 DEBUG = -pg -g -Wall -ansi -pedantic -DIL_STD -OBJECTS = main.o Allocation.o time.o +OBJECTS = main.o Allocation.o time.o AgentIterator.o Graph.o exec : $(OBJECTS) - $(CC) $(CFLAGS) -o NOBIN_1STA_YESMERGED $(OBJECTS) $(GUROBI_OPTS) + $(CC) $(CFLAGS) -o YESBIN_1STA_YESMERGED $(OBJECTS) $(GUROBI_OPTS) -.cpp.o : +.cpp.o : $< $(CC) $(CFLAGS) $(GUROBI_OPTS) -c $< -o $@ clean : - rm -f $(OBJECTS) NOBIN_1STA_YESMERGED + rm -f $(OBJECTS) YESBIN_1STA_YESMERGED diff --git a/SMTI/4_YESBIN_1STA_YESMERGED_MAXWT/AgentIterator.cpp b/SMTI/4_YESBIN_1STA_YESMERGED_MAXWT/AgentIterator.cpp new file mode 100644 index 0000000..88ceb8e --- /dev/null +++ b/SMTI/4_YESBIN_1STA_YESMERGED_MAXWT/AgentIterator.cpp @@ -0,0 +1,404 @@ +#include "AgentIterator.h" + +AgentIteratorBase::AgentIteratorBase(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group, int posn) : + _agent(agent), + _these(these), _other(other), + _positions(positions), _candidates(candidates) { + if (_agent.preferences.size() == 0) { + _group = -1; + } else { + _group = group; + } + _position = posn; +} + +AgentIteratorBase::~AgentIteratorBase() { } + +int AgentIteratorBase::get_group() const { + return _group; +} + +int AgentIteratorBase::get_position() const { + return _position; +} + +const Child & AgentIteratorBase::get_agent() const { + return _agent; +} + +const std::vector & AgentIteratorBase::get_these() const { + return _these; +} + +const std::vector & AgentIteratorBase::get_other() const { + return _other; +} +const std::set & AgentIteratorBase::get_positions() const { + return _positions; +} +const std::set & AgentIteratorBase::get_candidates() const { + return _candidates; +} + +void AgentIteratorBase::regularIncrement() { + _position++; + if (_agent.preferences[_group].size() == _position) { + _position = 0; + _group++; + if (_agent.preferences.size() == _group) { + _group = -1; + } + } +} + +bool AgentIterator::operator==(const AgentIterator & other) { + return get_group() == other.get_group() && get_position() == other.get_position(); +} + +bool AgentIterator::operator!=(const AgentIterator & other) { + return ! (*this == other); +} + +const std::pair AgentIterator::operator*() { + return std::pair(get_group(), get_position()); +} + +AgentIterator AgentIterator::begin() { + AgentIterator starter(this, 0, 0); + starter.base->begin(); + return starter; +} + +AgentIterator AgentIterator::end() { + return AgentIterator(this, -1, 0); +} + +AgentIterator::AgentIterator(const Child & agent, const std::set & candidates, const std::set & positions, + const std::vector & these, const std::vector & other, int mode) : + _mode(mode) { + switch (_mode) { + default: + case 0: + base = new DescendingIterator(agent, candidates, positions, these, other, 0, 0); + break; + case 1: + base = new SkipBigIterator(agent, candidates, positions, these, other, 5, 0, 0); + break; + case 2: + base = new BestIterator(agent, candidates, positions, these, other, 0, 0); + break; + case 3: + base = new SkipBigIterator(agent, candidates, positions, these, other, 15, 0, 0); + break; + case 4: + base = new SkipBigIterator(agent, candidates, positions, these, other, 50, 0, 0); + break; + case 5: + base = new BestGroupIterator(agent, candidates, positions, these, other, 0, 0); + break; + } + } + +AgentIterator::AgentIterator(AgentIterator *other) : + _mode(other->get_mode()) { + switch (_mode) { + default: + case 0: + base = new DescendingIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), other->get_group(), other->get_position()); + break; + case 1: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 5, other->get_group(), other->get_position()); + break; + case 2: + base = new BestIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), other->get_group(), other->get_position()); + break; + case 3: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 15, other->get_group(), other->get_position()); + break; + case 4: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 50, other->get_group(), other->get_position()); + break; + case 5: + base = new BestGroupIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), other->get_group(), other->get_position()); + break; + } + } + +AgentIterator::AgentIterator(AgentIterator *other, int group, int posn) : + _mode(other->get_mode()) { + switch (_mode) { + case 0: + base = new DescendingIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), group, posn); + break; + case 1: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 5, group, posn); + break; + case 2: + base = new BestIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), group, posn); + break; + case 3: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 15, group, posn); + break; + case 4: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 50, group, posn); + break; + case 5: + base = new BestGroupIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), group, posn); + break; + } + } + +AgentIterator::~AgentIterator() { + delete base; +} + +int AgentIterator::get_group() const { + return base->get_group(); +} + +int AgentIterator::get_position() const { + return base->get_position(); +} + +int AgentIterator::get_mode() const { + return _mode; +} + +DescendingIterator::DescendingIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group, int posn) : + AgentIteratorBase(agent, candidates, positions, these, other, group, posn) { + } + +void DescendingIterator::begin() { +} + +void DescendingIterator::increment() { + regularIncrement(); +} + +SkipBigIterator::SkipBigIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int skip, int group, int posn) : + AgentIteratorBase(agent, candidates, positions, these, other, group, posn) , _skip(skip) { + } + + +void SkipBigIterator::begin() { + int num_added = 0; + while (true) { + if (get_group() == -1) { + break; + } + num_added = 0; + int other_id = _agent.preferences[_group][_position]; + int other_rank = _agent.ranks[_group][_position]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(pref) == 0) { + num_added++; + } + } + } + if (num_added > _skip) { + regularIncrement(); + } else { + break; + } + } +} + +void SkipBigIterator::increment() { + int num_added = 0; + do { + regularIncrement(); + if (get_group() == -1) { + break; + } + num_added = 0; + int other_id = _agent.preferences[_group][_position]; + int other_rank = _agent.ranks[_group][_position]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(pref) == 0) { + num_added++; + } + } + } + } while (num_added > _skip); +} + +BestIterator::BestIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group, int posn) : + AgentIteratorBase(agent, candidates, positions, these, other, group, posn) { + } + +void BestIterator::increment() { + int lowest_added = -1; + int best_group = -1; + int best_posn = -1; + for(int group_no = 0; group_no < _agent.preferences.size(); ++group_no) { + auto & group = _agent.preferences[group_no]; + for(int posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + int other_rank = _agent.ranks[group_no][posn]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto other_pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(other_pref) == 0) { + num_added++; + } + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_group = group_no; + best_posn = posn; + } + } + } + if (lowest_added != -1) { + _group = best_group; + _position = best_posn; + std::cout << "Using " << _group << ", " << _position << std::endl; + } else { + _group = -1; + _position = 0; + } +} + +void BestIterator::begin() { + int lowest_added = -1; + int best_group = -1; + int best_posn = -1; + for(int group_no = 0; group_no < _agent.preferences.size(); ++group_no) { + auto & group = _agent.preferences[group_no]; + for(int posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + int other_rank = _agent.ranks[group_no][posn]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto other_pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(other_pref) == 0) { + num_added++; + } + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_group = group_no; + best_posn = posn; + } + } + } + if (lowest_added != -1) { + _group = best_group; + _position = best_posn; + std::cout << "Using " << _group << ", " << _position << std::endl; + } else { + _group = -1; + _position = 0; + } +} + +BestGroupIterator::BestGroupIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group, int posn) : + AgentIteratorBase(agent, candidates, positions, these, other, group, posn) { + } + +void BestGroupIterator::increment() { + int lowest_added = -1; + int best_posn = -1; + auto & group = _agent.preferences[_group]; + for(int posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + int other_rank = _agent.ranks[_group][posn]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto other_pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(other_pref) == 0) { + num_added++; + } + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_posn = posn; + } + } + if (lowest_added != -1) { + _position = best_posn; + } else { + _group++; + if (_group == _agent.preferences.size()) { + _position = 0; + _group = -1; + } else { + increment(); + } + } +} + +void BestGroupIterator::begin() { + int lowest_added = -1; + int best_posn = -1; + if (_group == -1) { + return; + } + auto & group = _agent.preferences[_group]; + for(int posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + int other_rank = _agent.ranks[_group][posn]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto other_pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(other_pref) == 0) { + num_added++; + } + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_posn = posn; + } + } + if (lowest_added != -1) { + _position = best_posn; + } else { + _group++; + if (_group == _agent.preferences.size()) { + _position = 0; + _group = -1; + } else { + increment(); + } + } +} diff --git a/SMTI/4_YESBIN_1STA_YESMERGED_MAXWT/AgentIterator.h b/SMTI/4_YESBIN_1STA_YESMERGED_MAXWT/AgentIterator.h new file mode 100644 index 0000000..48b96c6 --- /dev/null +++ b/SMTI/4_YESBIN_1STA_YESMERGED_MAXWT/AgentIterator.h @@ -0,0 +1,110 @@ +#ifndef AGENTITERATOR_H +#define AGENTITERATOR_H + +#include + +#include "Allocation.h" + +class AgentIteratorBase { +public: + AgentIteratorBase(const Child & agent, const std::set & candidates, const std::set & positions, + const std::vector & these, const std::vector & other, int group=0, int posn=0); + virtual ~AgentIteratorBase() = 0; + virtual void increment() = 0; + virtual void begin() = 0; + + int get_position() const; + int get_group() const; + const Child & get_agent() const; + const std::vector & get_these() const; + const std::vector & get_other() const; + const std::set & get_positions() const; + const std::set & get_candidates() const; +protected: + void regularIncrement(); + + const Child & _agent; + int _group; + int _position; + const std::vector & _these; + const std::vector & _other; + const std::set & _positions; + const std::set & _candidates; +}; + + +class AgentIterator : public std::iterator, ptrdiff_t> { +public: + AgentIterator(const Child & agent, const std::set & candidates, const std::set & positions, + const std::vector & these, const std::vector & other, int mode); + AgentIterator(AgentIterator *other, int group, int posn); + AgentIterator(AgentIterator *other); + ~AgentIterator(); + bool operator==(const AgentIterator& other); + bool operator!=(const AgentIterator& other); + const std::pair operator*(); + AgentIterator& operator++() {base->increment(); return *this; } + AgentIterator operator++(int) {AgentIterator res(this); base->increment(); return res; } + + AgentIterator begin(); + AgentIterator end(); + + int get_position() const; + int get_group() const; + int get_mode() const; + + const Child & get_agent() const { return base->get_agent(); } + const std::vector & get_these() const {return base->get_these(); } + const std::vector & get_other() const {return base->get_other(); } + const std::set & get_positions() const {return base->get_positions(); } + const std::set & get_candidates() const {return base->get_candidates(); } +private: + AgentIteratorBase * base; + int _mode; +}; + + +class DescendingIterator : public AgentIteratorBase { + public: + DescendingIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group=0, int posn=0); + ~DescendingIterator() {} + void increment(); + void begin(); +}; + + +class SkipBigIterator : public AgentIteratorBase { + public: + SkipBigIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int skip, int group, int posn); + ~SkipBigIterator() {} + void increment(); + void begin(); + private: + int _skip; +}; + +class BestIterator : public AgentIteratorBase { + public: + BestIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group=0, int posn=0); + ~BestIterator() {} + void increment(); + void begin(); +}; + +class BestGroupIterator : public AgentIteratorBase { + public: + BestGroupIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group=0, int posn=0); + ~BestGroupIterator() {} + void increment(); + void begin(); +}; + +#endif /* AGENTITERATOR_H */ diff --git a/SMTI/4_YESBIN_1STA_YESMERGED_MAXWT/Allocation.cpp b/SMTI/4_YESBIN_1STA_YESMERGED_MAXWT/Allocation.cpp new file mode 100644 index 0000000..46fae7d --- /dev/null +++ b/SMTI/4_YESBIN_1STA_YESMERGED_MAXWT/Allocation.cpp @@ -0,0 +1,763 @@ +#include "Allocation.h" +#include "AgentIterator.h" +#include "Graph.h" + +/* ************************************************************************************* + *********************************** DOCTOR ***************************************** + ************************************************************************************* */ + +void Child::print(bool family){ + if (family) + cout << "Family "; + else + cout << "Child "; + cout << id << "\t Preferences (" << nbPref << " groups, " << nbTotPref << " in total)\t"; + for(int i=0; i 0) cout << " "; + cout << preferences[i][j]; + cout << "[" << ranks[i][j] << "_" << positions[i][j] << "]"; + } + cout << ") "; + } + cout << endl; +} + +/* ************************************************************************************* + ********************************** ALLOCATION *************************************** + ************************************************************************************* */ + +void Allocation::load(const string& path, const string& filein){ + // Local variables + istringstream iss; + string parser; + string garbage; + string nameFile = path + filein; + vector > allRanksC, allRanksF, allPreferencesC, allPreferencesF; + + // File opening + ifstream file(nameFile.c_str(), ios::in); + + // File lecture + if (file){ + // Name of the instance is filein + name = filein; + + // Skip the first line + getline(file, parser); iss.str(parser); iss >> garbage; iss.clear(); + + // Read the number of doctors + getline(file, parser); iss.str(parser); iss >> nbFamilies; iss.clear(); + + // Read the number of hospitals + getline(file, parser); iss.str(parser); iss >> nbChildren; iss.clear(); + + // Resize allRanks and allPreferences + allRanksC.resize(nbChildren); allPreferencesC.resize(nbChildren); + allRanksF.resize(nbFamilies); allPreferencesF.resize(nbFamilies); + + // Read the preferences of each child + for (int i = 0; i < nbChildren; i++){ + Child c; + c.mustBeAllocated = false; + int temp; + allRanksC[i].resize(nbFamilies,-1); allPreferencesC[i].resize(nbFamilies,-1); + + istringstream tempIss; + string tempString; + c.nbTotPref = 0; + int rank = 0; + + getline(file, parser); + iss.str(parser); + iss >> c.id; + + for(;;){ + char tempChar = iss.get(); + if(iss.eof()) + break; + else{ + if(tempChar == '('){ + int pref = 0; + getline(iss, tempString, ')'); + tempIss.str(tempString); + vector tempPref; + while(tempIss >> temp){ + allRanksC[i][temp-1] = rank; + allPreferencesC[i][temp-1] = pref; + tempPref.push_back(temp-1); + pref++; + } + c.preferences.push_back(tempPref); + c.nbTotPref+= tempPref.size(); + rank++; + tempIss.clear(); + } + else{ + if((tempChar >= '0') && (tempChar <= '9')){ + iss.putback(tempChar); + vector tempPref; + iss >> temp; + allRanksC[i][temp-1] = rank; + allPreferencesC[i][temp-1] = 0; + tempPref.push_back(temp-1); + c.preferences.push_back(tempPref); + c.nbTotPref+= tempPref.size(); + rank++; + tempIss.clear(); + } + } + } + } + + c.nbPref = c.preferences.size(); + children.push_back(c); + iss.clear(); + } + + // Read the preferences of each family + for (int i = 0; i < nbFamilies; i++){ + Family f; + f.mustBeAllocated = false; + int temp; + allRanksF[i].resize(nbChildren,-1); allPreferencesF[i].resize(nbChildren,-1); + + istringstream tempIss; + string tempString; + + f.nbTotPref = 0; + int rank = 0; + + getline(file, parser); + iss.str(parser); + iss >> f.id; + iss >> garbage; + + for(;;){ + char tempChar = iss.get(); + //cout << "Just read " << tempChar << endl; + if(iss.eof()) + break; + else{ + if(tempChar == '('){ + int pref = 0; + getline(iss, tempString, ')'); + tempIss.str(tempString); + vector tempPref; + while(tempIss >> temp){ + allRanksF[i][temp-1] = rank; + allPreferencesF[i][temp-1] = pref; + tempPref.push_back(temp-1); + pref++; + } + f.preferences.push_back(tempPref); + f.nbTotPref+= tempPref.size(); + rank++; + tempIss.clear(); + } + else{ + if((tempChar >= '0') && (tempChar <= '9')){ + iss.putback(tempChar); + vector tempPref; + iss >> temp; + allRanksF[i][temp-1] = rank; + allPreferencesF[i][temp-1] = 0; + tempPref.push_back(temp-1); + f.preferences.push_back(tempPref); + f.nbTotPref+= tempPref.size(); + rank++; + tempIss.clear(); + } + } + } + } + + f.nbPref = f.preferences.size(); + families.push_back(f); + iss.clear(); + } + + file.close(); + + for (int i = 0; i < nbChildren; i++){ + children[i].ranks = children[i].preferences; + children[i].positions = children[i].preferences; + } + + for (int i = 0; i < nbFamilies; i++){ + families[i].ranks = families[i].preferences; + families[i].positions = families[i].preferences; + } + + // Fill ranks and positions + + for (int i = 0; i < nbChildren; i++){ + for(int k= 0; k < children[i].nbPref; k++){ + for(int l=0; l * thesep; + std::vector * otherp; + std::list *theseMustBeAllocatedp; + std::list *otherMustBeAllocatedp; + if (children_side) { + // Processing the lists of the children, removing families + thesep = &children; + otherp = &families; + theseMustBeAllocatedp = &childrenMustBeAllocated; + otherMustBeAllocatedp = &familiesMustBeAllocated; + number_here = nbChildren; + } else { + thesep = &families; + otherp = &children; + theseMustBeAllocatedp = &familiesMustBeAllocated; + otherMustBeAllocatedp = &childrenMustBeAllocated; + number_here = nbFamilies; + } + std::vector & these = (*thesep); + std::vector & other = (*otherp); + std::list & theseMustBeAllocated = (*theseMustBeAllocatedp); + std::list & otherMustBeAllocated = (*otherMustBeAllocatedp); + for (int i = 0; i < number_here; i++) { + // Early exit! + const float ratio = 0.1; + if (early_exit && (i >= ratio * number_here) && (nbTotRem == 0)) { + return 0; + } + // A graph is "named" with two integers. The first is a 0 for a candidate + // (aka these) or a 1 for a position (aka other) + Graph g; + int n_1 = 0; + for(int rank = 0; rank < these[i].nbPref; rank++) { + // No point in checking the last rank if we already know this agent must + // be allocated, or if we don't care + if ((rank == these[i].nbPref - 1) && (these[i].mustBeAllocated || !supp)) { + continue; + } + for(size_t ind = 0; ind < these[i].preferences[rank].size(); ind++) { + int position = these[i].preferences[rank][ind]; + g.addVertex(1, position); + int idxRank = these[i].ranks[rank][ind]; + for(int l = 0; l <= idxRank; l++) { + for(size_t k = 0; k < other[position].preferences[l].size(); k++) { + int other_cand = other[position].preferences[l][k]; + if (other_cand == i) { // Don't add the current candidate to the graph + continue; + } + if (! g.containsVertex(0, other_cand)) { + g.addVertex(0, other_cand); + n_1 += 1; + } + g.addEdge(position, other_cand); + } + } + } + // If n_1 is sufficiently small, then the largest matching must also be + // small, as the matching can use each vertex from n_1 at most once, so + // we don't even need to try to find a bigger matching. + bool matching_cant_exist = (2*n_1 + 1 <= g.size()); + if (! matching_cant_exist) { + for(size_t ind = 0; ind < these[i].preferences[rank].size(); ind++) { + int position = these[i].preferences[rank][ind]; + g.augment(position); + } + } + // Add P' in this + // Yes, I'm abusing while statements, so I can break out easier. + while (rank == 0) { + // Don't add P' if we don't need to. + if (matching_cant_exist || (g.size() - g.matchingSize() >= n_1 + 1)) { + break; + } + // First add all positions that must be filled. + for(int position: otherMustBeAllocated) { + // If position is acceptable to i, then skip it. + bool isAcceptable = false; + for(int otherRank = 0; (!isAcceptable) && otherRank < other[position].nbPref; otherRank++) { + for(size_t ind = 0; ind < other[position].preferences[otherRank].size(); ++ind) { + if (other[position].preferences[otherRank][ind] == i) { + isAcceptable = true; + break; + } + } + } + if (isAcceptable) { + continue; + } + g.addVertex(1, position); + for(int otherRank = 0; otherRank < other[position].nbPref; otherRank++) { + for(size_t ind = 0; ind < other[position].preferences[otherRank].size(); ++ind) { + int candidate = other[position].preferences[otherRank][ind]; + if (!g.containsVertex(0, candidate)) { + g.addVertex(0, candidate); + n_1 += 1; + } + g.addEdge(position, candidate); + } + } + g.augment(position); + } + // I'm using a while loop as an if statement, so I need to break out. + break; + } + if (matching_cant_exist || (g.size() - g.matchingSize() >= n_1 + 1)) { + // preprocess on rank! + // Firstly, they must be allocated, so mark as such (if we're in that + // mode) + if (supp && !these[i].mustBeAllocated) { + theseMustBeAllocated.push_back(i); + these[i].mustBeAllocated = true; + newMustAlways = true; + } +#ifdef DEBUG + if ((!children_side) and (i == 6)) { + std::cout << "g.size() = " << g.size() << ", g.matchingSize() = " << g.matchingSize(); + std::cout << ", n_1 = " << n_1 << std::endl; + g.printGraph(); + g.printMatching(); + } + if (children_side) { + std::cout << "child "; + } else { + std::cout << "family "; + } + std::cout << "worst rank of " << i << " is " << rank << " "; + int remHere = 0; +#endif /* DEBUG */ + for (int k = rank + 1; k < these[i].nbPref; k++) { + nbTotRem += these[i].preferences[k].size(); +#ifdef DEBUG + remHere += these[i].preferences[k].size(); +#endif /* DEBUG */ + these[i].nbTotPref -= these[i].preferences[k].size(); + for (unsigned int l = 0; l < these[i].preferences[k].size(); l++) { + int idxFam = these[i].preferences[k][l]; + int idxPos = these[i].positions[k][l]; + int idxRank = these[i].ranks[k][l]; + for (unsigned int m = idxPos + 1; + m < other[idxFam].preferences[idxRank].size(); m++) { + these[other[idxFam].preferences[idxRank][m]] + .positions[other[idxFam].ranks[idxRank][m]] + [other[idxFam].positions[idxRank][m]]--; + } + other[idxFam].nbTotPref--; + other[idxFam].positions[idxRank].erase( + other[idxFam].positions[idxRank].begin() + idxPos); + other[idxFam].ranks[idxRank].erase( + other[idxFam].ranks[idxRank].begin() + idxPos); + other[idxFam].preferences[idxRank].erase( + other[idxFam].preferences[idxRank].begin() + idxPos); + } + } + these[i].nbPref = rank + 1; + these[i].preferences.resize(these[i].nbPref); + these[i].ranks.resize(these[i].nbPref); + these[i].positions.resize(these[i].nbPref); +#ifdef DEBUG + std::cout << "removed " << remHere << std::endl; +#endif /* DEBUG */ + break; + } + } + } + if (nbTotRem > 0) { + polish(); + } + if ((nbTotRem == 0) && (newMustAlways)) { + return -1; + } + return nbTotRem; +} + +int Allocation::reductionMine(bool children_side, int mode, bool alt_store) { + int nbTotRem = 0; + int number_here; + std::vector * thesep; + std::vector * otherp; + if (children_side) { + thesep = &children; + otherp = &families; + number_here = nbChildren; + } else { + thesep = &families; + otherp = &children; + number_here = nbFamilies; + } + std::vector & these = (*thesep); + std::vector & other = (*otherp); + + for (int i = 0; i < number_here; i++) { + set candidates; + set positions; + vector cand_in(number_here, false); + int cand_size = 0; + int worst_rank = 0; + int count = 0; + AgentIterator iter(these[i], candidates, positions, these, other, mode); + for(std::pair p: iter) { + int j = p.first; + int k = p.second; + if (j > worst_rank) { + worst_rank = j; + } + int idxFam = these[i].preferences[j][k]; + int idxRank = these[i].ranks[j][k]; + positions.insert(idxFam); + count++; + for (int l = 0; l <= idxRank; l++) { + for (unsigned int m = 0; m < other[idxFam].preferences[l].size(); + m++) { + if ((alt_store && cand_in[other[idxFam].preferences[l][m]] == false) || + (!alt_store && candidates.count(other[idxFam].preferences[l][m]) == 0)) { + candidates.insert(other[idxFam].preferences[l][m]); + cand_in[other[idxFam].preferences[l][m]] = true; + cand_size++; + } + } + } + if (count >= cand_size) { +#ifdef DEBUG + if (children_side) { + std::cout << "child "; + } else { + std::cout << "family "; + } + std::cout << "worst rank of " << i << " is " << worst_rank << std::endl; +#endif /* DEBUG */ + for (int k = worst_rank + 1; k < these[i].nbPref; k++) { + nbTotRem += these[i].preferences[k].size(); + these[i].nbTotPref -= these[i].preferences[k].size(); + for (unsigned int l = 0; l < these[i].preferences[k].size(); l++) { + int idxFam = these[i].preferences[k][l]; + int idxPos = these[i].positions[k][l]; + int idxRank = these[i].ranks[k][l]; + for (unsigned int m = idxPos + 1; + m < other[idxFam].preferences[idxRank].size(); m++) { + these[other[idxFam].preferences[idxRank][m]] + .positions[other[idxFam].ranks[idxRank][m]] + [other[idxFam].positions[idxRank][m]]--; + } + other[idxFam].nbTotPref--; + other[idxFam].positions[idxRank].erase( + other[idxFam].positions[idxRank].begin() + idxPos); + other[idxFam].ranks[idxRank].erase( + other[idxFam].ranks[idxRank].begin() + idxPos); + other[idxFam].preferences[idxRank].erase( + other[idxFam].preferences[idxRank].begin() + idxPos); + } + } + these[i].nbPref = worst_rank + 1; + these[i].preferences.resize(these[i].nbPref); + these[i].ranks.resize(these[i].nbPref); + these[i].positions.resize(these[i].nbPref); + break; + } + } + } + if (nbTotRem > 0) { + polish(); + } + return nbTotRem; +} + +void Allocation::polish(){ + // Remove unused groups in families + for(int j=0; j > preferences; + vector > ranks; + vector > positions; + int idxRem = 0; + for(int k=0;k > preferences; + vector > ranks; + vector > positions; + int idxRem = 0; + for(int k=0;k childAllocated (nbChildren, 0); + vector familyAllocated (nbFamilies, 0); + + // Fill the vectors + for(int i=0; i= 0) familyAllocated[assignmentByChild[i]]++; + } + for(int i=0; i= 0) childAllocated[assignmentByFamily[i]]++; + } + + // Rank of the family assigned to children and vice versa + vector rankC(nbChildren, -1); + for(int i=0;i rankF(nbFamilies, -1); + for(int i=0;i 1){ + cout << "Allocation error: child " << i << " is allocated " << childAllocated[i] << " times " << endl; + mistake = true; + } + else sol1 += childAllocated[i]; + } + + // Check for family used twice + int sol2 = 0; + for(int i=0; i 1){ + cout << "Allocation error: family " << i << " is allocated " << familyAllocated[i] << " times " << endl; + mistake = true; + } + else sol2 += familyAllocated[i]; + } + + + // Check for stability by child + for(int i=0; i + #include +#include + #include + #include + #include + #include + #include + #include + + class Child; + typedef Child Family; + class Assignment; + class Allocation; + +/* ************************************************************************************* + *********************************** DOCTOR ***************************************** + ************************************************************************************* */ + + class Child{ + public: + int id; + int nbPref; + int nbTotPref; + bool mustBeAllocated; + vector > preferences; + vector > ranks; + vector > positions; + void print(bool); + }; + +/* ************************************************************************************* + ************************************* INFO ****************************************** + ************************************************************************************* */ + + class Info{ + public: + bool opt; + double timeCPU; + double timeCPUPP; + double LB; + double UB; + float contUB; + int nbCons; + int nbVar; + int nbNZ; + float contUB2; + int nbCons2; + int nbVar2; + int nbNZ2; + }; + +/* ************************************************************************************* + ********************************** ALLOCATION *************************************** + ************************************************************************************* */ + class Allocation{ + public: + // Data read from the file + string name; + int nbChildren; + int nbFamilies; + int total_reduced; + + vector children; + vector families; + + // Given by the ILP model + vector assignmentByChild; + vector assignmentByFamily; + + std::list childrenMustBeAllocated; + std::list familiesMustBeAllocated; + + Info infos; + + void load(const string& path, const string& filein); + void printProb(); + int reductionMine(bool children_side=true, int mode=0, bool alt_store=false); + int reductionExact(bool children_side, bool supp=false, bool early_exit=false); + void polish(); + void reduction(int mode); + void printSol(); + void printInfo(const string& pathAndFileout); + void checkSolution(); + }; + + +#endif diff --git a/SMTI/4_YESBIN_1STA_YESMERGED_MAXWT/Graph.cpp b/SMTI/4_YESBIN_1STA_YESMERGED_MAXWT/Graph.cpp new file mode 100644 index 0000000..0e487e7 --- /dev/null +++ b/SMTI/4_YESBIN_1STA_YESMERGED_MAXWT/Graph.cpp @@ -0,0 +1,107 @@ +#include +#include "Graph.h" + + +// Expected biggest graph, to save on allocations +const size_t expected_size = 50000; + +Graph::Graph() : _exists(2), _adjacents(2), _matching(2), _size(0), _matching_size(0) { + _exists[0] = std::vector(expected_size, false); + _exists[1] = std::vector(expected_size, false); + _adjacents[0] = std::vector>(expected_size); + _adjacents[1] = std::vector>(expected_size); + _matching[0] = std::vector(expected_size, -1); + _matching[1] = std::vector(expected_size, -1); +#ifdef DEBUG + std::cout << "New graph" << std::endl; +#endif /* DEBUG */ +} + +void Graph::addVertex(int side, int name) { + _exists[side][name] = true; + _size += 1; +} + +bool Graph::containsVertex(int side, int name) const { + return _exists[side][name]; +} + +/** + * Adds an edge to the graph. Note that this edge must always be added in the + * form (right, left) for things to work. + */ +void Graph::addEdge(int v1, int v2) { + _adjacents[1][v1].push_back(v2); + _adjacents[0][v2].push_back(v1); +} + +int Graph::size() const { + return _size; +} + +int Graph::matchingSize() const { + return _matching_size; +} + +/** + * Augment the matching, starting at vertex name which is on the right. + */ +void Graph::augment(int name) { +#ifdef DEBUG + std::cout << "Augmenting on " << _indices.at(start) << std::endl; + this->printGraph(); +#endif /* DEBUG */ + std::list path; + std::vector visited(expected_size, false); + path.push_back(name); + internal_augment(name, visited, path); +} + +/** + * Continues an augmentation, on vertex now, which is on the right. + */ +bool Graph::internal_augment(int now, std::vector & visited, + std::list & path) { + for(int next: _adjacents[1][now]) { + // next is on the left + if (visited[next]) { + continue; + } + if (_matching[0][next] == -1) { + // Found an augmenting path. Switch edges and return true. +#ifdef DEBUG + std::cout << "New matching found." << std::endl; +#endif /* DEBUG */ + path.push_back(next); +#ifdef DEBUG + std::cout << "Path is "; + for(auto p: path) { + std::cout << " " << _indices.at(p); + } + std::cout << std::endl; + +#endif /* DEBUG */ + while(!path.empty()) { + int right = path.front(); + path.pop_front(); + int left = path.front(); + path.pop_front(); + _matching[1][right] = left; + _matching[0][left] = right; + } + _matching_size += 1; + return true; + } + int next2 = _matching[0][next]; + path.push_back(next); + path.push_back(next2); + visited[next] = true; + if (internal_augment(next2, visited, path)) { + return true; + } + path.pop_back(); + path.pop_back(); + } + return false; +} + diff --git a/SMTI/4_YESBIN_1STA_YESMERGED_MAXWT/Graph.h b/SMTI/4_YESBIN_1STA_YESMERGED_MAXWT/Graph.h new file mode 100644 index 0000000..5d07f00 --- /dev/null +++ b/SMTI/4_YESBIN_1STA_YESMERGED_MAXWT/Graph.h @@ -0,0 +1,60 @@ +#ifndef GRAPH_H +#define GRAPH_H + +#include +#include +#include +#include +#include +#include + + +static_assert(std::numeric_limits::max() >= ((long unsigned)1 << 63), "size_t is too small"); + +struct pairhash { + public: + std::size_t operator()(const std::pair &x) const { + return (long)x.first * ((long)1 << 32) + x.second; + } +}; + +#ifdef DEBUG +#include +inline std::ostream& operator<<(std::ostream& o, const std::pair &x) { + o << "(" << x.first << ", " << x.second << ")"; + return o; +} +#endif /* DEBUG */ + + +class Graph { + public: + Graph(); + void addVertex(int side, int name); + bool containsVertex(int side, int name) const; + void addEdge(int v1, int v2); + int matched(int vertex) const; + void augment(int vertex); + + int size() const; + int matchingSize() const; + + int name(int vert_index); + +#ifdef DEBUG + void printGraph(); + void printMatching() const; +#endif /* DEBUG */ + + private: + std::vector> _exists; + std::vector>> _adjacents; + std::vector> _matching; + + int _size; + int _matching_size; + + bool internal_augment(int now, std::vector & visited, std::list & path); +}; + +#endif /* GRAPH_H */ diff --git a/SMTI/4_YESBIN_1STA_YESMERGED_MAXWT/main.cpp b/SMTI/4_YESBIN_1STA_YESMERGED_MAXWT/main.cpp new file mode 100644 index 0000000..81d2621 --- /dev/null +++ b/SMTI/4_YESBIN_1STA_YESMERGED_MAXWT/main.cpp @@ -0,0 +1,219 @@ +#include "main.h" + +#define MAXTIME 3600 + +/* ************************************************************************************* + ************************************* MAIN ***************************************** + ************************************************************************************* */ + +int main(int argc, char **argv){ + + // local variables + Allocation allo ; + allo.total_reduced = 0; + string filein = argv[2]; + string path = argv[1]; + string pathAndFileout = argv[3]; + int mode = atoi(argv[4]); + + // functions + allo.load(path,filein); + //allo.printProb(); + + int res = manlove(allo, mode); + if (res != -1) { + allo.printSol(); + allo.checkSolution(); + } + allo.printInfo(pathAndFileout); +} + + +int manlove(Allocation& allo, int mode){ + double initTimeModelCPU = getCPUTime(); + GRBEnv env = GRBEnv(); + + double initTimeModelCPUPP = getCPUTime(); + if (mode != 12) { + allo.reduction(mode); + } + //allo.printProb(); + allo.infos.timeCPUPP = getCPUTime() - initTimeModelCPUPP; + if (allo.infos.timeCPUPP > MAXTIME) { + cout << "Preprocessing took over " << MAXTIME << " seconds" << endl; + allo.infos.LB = 0; + allo.assignmentByChild.resize(allo.nbChildren, -1); + allo.assignmentByFamily.resize(allo.nbFamilies,-1); + return -1; + } + + // Model + try{ + // Local variables + GRBModel model = GRBModel(env); + GRBLinExpr objFun = 0; + + vector > > isChildIAllocatedToFamilyJ (allo.nbChildren); + + vector > hIBFF (allo.nbFamilies); + vector > hIBFC (allo.nbChildren); + + // Initialization + for (int i = 0; i < allo.nbChildren; i++){ + isChildIAllocatedToFamilyJ[i].resize(allo.children[i].nbPref); + hIBFC[i].resize(allo.children[i].nbPref); + for (int j = 0; j 0) exp += hIBFC[i][j-1]; + model.addConstr(hIBFC[i][j] == exp); + } + } + + for (int j = 0; j < allo.nbFamilies; j++){ + for (int k = 0; k 0) exp += hIBFF[j][k-1]; + model.addConstr(hIBFF[j][k] == exp); + } + } + + + // Stability constraints + for (int i = 0; i < allo.nbChildren; i++){ + for (int j = 0; j + #include + #include + #include "gurobi_c++.h" + #include "time.h" + #include "Allocation.h" + + float EPSILON = 0.001; + + int manlove(Allocation& allo, int reduction_mode); + +#endif diff --git a/SMTI/4_YESBIN_1STA_YESMERGED_MAXWT/makefile b/SMTI/4_YESBIN_1STA_YESMERGED_MAXWT/makefile new file mode 100644 index 0000000..bd048da --- /dev/null +++ b/SMTI/4_YESBIN_1STA_YESMERGED_MAXWT/makefile @@ -0,0 +1,22 @@ +SYSTEM = x86-64_sles10_4.1 +LIBFORMAT = static_pic + +GUROBI_DIR = /users/grad/wpette/opt/gurobi752/linux64 +CLIB = -L$(GUROBI_DIR)/lib/ -lgurobi75 +INC = $(GUROBI_DIR)/include/ +CPPLIB = -L$(GUROBI_DIR)/lib/ -lgurobi_c++ $(CLIB) +GUROBI_OPTS = -I$(INC) $(CPPLIB) -lpthread -lm -m64 + +CC = g++ +CFLAGS = -O2 -Wall -ansi -pedantic -DIL_STD -std=c++11 +DEBUG = -pg -g -Wall -ansi -pedantic -DIL_STD +OBJECTS = main.o Allocation.o time.o AgentIterator.o Graph.o + +exec : $(OBJECTS) + $(CC) $(CFLAGS) -o YESBIN_1STA_YESMERGED_MAXWT $(OBJECTS) $(GUROBI_OPTS) + +.cpp.o : $< + $(CC) $(CFLAGS) $(GUROBI_OPTS) -c $< -o $@ + +clean : + rm -f $(OBJECTS) YESBIN_1STA_YESMERGED_MAXWT diff --git a/SMTI/4_YESBIN_1STA_YESMERGED_MAXWT/time.cpp b/SMTI/4_YESBIN_1STA_YESMERGED_MAXWT/time.cpp new file mode 100644 index 0000000..4726bdf --- /dev/null +++ b/SMTI/4_YESBIN_1STA_YESMERGED_MAXWT/time.cpp @@ -0,0 +1,46 @@ +#include "time.h" + +#ifdef _WIN32 +#include +double getWallTime(){ + LARGE_INTEGER time,freq; + if (!QueryPerformanceFrequency(&freq)){ + // Handle error + return 0; + } + if (!QueryPerformanceCounter(&time)){ + // Handle error + return 0; + } + return (double)time.QuadPart / freq.QuadPart; +} +double getCPUTime(){ + FILETIME a,b,c,d; + if (GetProcessTimes(GetCurrentProcess(),&a,&b,&c,&d) != 0){ + // Returns total user time. + // Can be tweaked to include kernel times as well. + return + (double)(d.dwLowDateTime | + ((unsigned long long)d.dwHighDateTime << 32)) * 0.0000001; + }else{ + // Handle error + return 0; + } +} + +// Posix/Linux +#else +#include +#include +double getWallTime(){ + struct timeval time; + if (gettimeofday(&time,NULL)){ + // Handle error + return 0; + } + return (double)time.tv_sec + (double)time.tv_usec * .000001; +} +double getCPUTime(){ + return (double)clock() / CLOCKS_PER_SEC; +} +#endif \ No newline at end of file diff --git a/SMTI/4_YESBIN_1STA_YESMERGED_MAXWT/time.h b/SMTI/4_YESBIN_1STA_YESMERGED_MAXWT/time.h new file mode 100644 index 0000000..6f1cb4f --- /dev/null +++ b/SMTI/4_YESBIN_1STA_YESMERGED_MAXWT/time.h @@ -0,0 +1,15 @@ +#ifndef TIME_H + + #define TIME_H + + #ifdef WIN32 + #include + #else + #include + #include + #endif + + double getWallTime(); + double getCPUTime(); + +#endif diff --git a/SMTI/8_YESBIN_2STA_YESMERGED/AgentIterator.cpp b/SMTI/8_YESBIN_2STA_YESMERGED/AgentIterator.cpp new file mode 100644 index 0000000..6210288 --- /dev/null +++ b/SMTI/8_YESBIN_2STA_YESMERGED/AgentIterator.cpp @@ -0,0 +1,402 @@ +#include "AgentIterator.h" + +AgentIteratorBase::AgentIteratorBase(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group, int posn) : + _agent(agent), + _these(these), _other(other), + _positions(positions), _candidates(candidates) { + if (_agent.preferences.size() == 0) { + _group = -1; + } else { + _group = group; + } + _position = posn; +} + +AgentIteratorBase::~AgentIteratorBase() { } + +int AgentIteratorBase::get_group() const { + return _group; +} + +int AgentIteratorBase::get_position() const { + return _position; +} + +const Child & AgentIteratorBase::get_agent() const { + return _agent; +} + +const std::vector & AgentIteratorBase::get_these() const { + return _these; +} + +const std::vector & AgentIteratorBase::get_other() const { + return _other; +} +const std::set & AgentIteratorBase::get_positions() const { + return _positions; +} +const std::set & AgentIteratorBase::get_candidates() const { + return _candidates; +} + +void AgentIteratorBase::regularIncrement() { + _position++; + if (_agent.preferences[_group].size() == _position) { + _position = 0; + _group++; + if (_agent.preferences.size() == _group) { + _group = -1; + } + } +} + +bool AgentIterator::operator==(const AgentIterator & other) { + return get_group() == other.get_group() && get_position() == other.get_position(); +} + +bool AgentIterator::operator!=(const AgentIterator & other) { + return ! (*this == other); +} + +const std::pair AgentIterator::operator*() { + return std::pair(get_group(), get_position()); +} + +AgentIterator AgentIterator::begin() { + AgentIterator starter(this, 0, 0); + starter.base->begin(); + return starter; +} + +AgentIterator AgentIterator::end() { + return AgentIterator(this, -1, 0); +} + +AgentIterator::AgentIterator(const Child & agent, const std::set & candidates, const std::set & positions, + const std::vector & these, const std::vector & other, int mode) : + _mode(mode) { + switch (_mode) { + default: + case 0: + base = new DescendingIterator(agent, candidates, positions, these, other, 0, 0); + break; + case 1: + base = new SkipBigIterator(agent, candidates, positions, these, other, 5, 0, 0); + break; + case 2: + base = new BestIterator(agent, candidates, positions, these, other, 0, 0); + break; + case 3: + base = new SkipBigIterator(agent, candidates, positions, these, other, 15, 0, 0); + break; + case 4: + base = new SkipBigIterator(agent, candidates, positions, these, other, 50, 0, 0); + break; + case 5: + base = new BestGroupIterator(agent, candidates, positions, these, other, 0, 0); + break; + } + } + +AgentIterator::AgentIterator(AgentIterator *other) : + _mode(other->get_mode()) { + switch (_mode) { + default: + case 0: + base = new DescendingIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), other->get_group(), other->get_position()); + break; + case 1: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 5, other->get_group(), other->get_position()); + break; + case 2: + base = new BestIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), other->get_group(), other->get_position()); + break; + case 3: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 15, other->get_group(), other->get_position()); + break; + case 4: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 50, other->get_group(), other->get_position()); + break; + case 5: + base = new BestGroupIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), other->get_group(), other->get_position()); + break; + } + } + +AgentIterator::AgentIterator(AgentIterator *other, int group, int posn) : + _mode(other->get_mode()) { + switch (_mode) { + case 0: + base = new DescendingIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), group, posn); + break; + case 1: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 5, group, posn); + break; + case 2: + base = new BestIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), group, posn); + break; + case 3: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 15, group, posn); + break; + case 4: + base = new SkipBigIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), 50, group, posn); + break; + case 5: + base = new BestGroupIterator(other->get_agent(), other->get_candidates(), other->get_positions(), + other->get_these(), other->get_other(), group, posn); + break; + } + } + +AgentIterator::~AgentIterator() { + delete base; +} + +int AgentIterator::get_group() const { + return base->get_group(); +} + +int AgentIterator::get_position() const { + return base->get_position(); +} + +int AgentIterator::get_mode() const { + return _mode; +} + +DescendingIterator::DescendingIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group, int posn) : + AgentIteratorBase(agent, candidates, positions, these, other, group, posn) { + } + +void DescendingIterator::begin() { +} + +void DescendingIterator::increment() { + regularIncrement(); +} + +SkipBigIterator::SkipBigIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int skip, int group, int posn) : + AgentIteratorBase(agent, candidates, positions, these, other, group, posn) , _skip(skip) { + } + + +void SkipBigIterator::begin() { + int num_added = 0; + while (true) { + if (get_group() == -1) { + break; + } + num_added = 0; + int other_id = _agent.preferences[_group][_position]; + int other_rank = _agent.ranks[_group][_position]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(pref) == 0) { + num_added++; + } + } + } + if (num_added > _skip) { + regularIncrement(); + } else { + break; + } + } +} + +void SkipBigIterator::increment() { + int num_added = 0; + do { + regularIncrement(); + if (get_group() == -1) { + break; + } + num_added = 0; + int other_id = _agent.preferences[_group][_position]; + int other_rank = _agent.ranks[_group][_position]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(pref) == 0) { + num_added++; + } + } + } + } while (num_added > _skip); +} + +BestIterator::BestIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group, int posn) : + AgentIteratorBase(agent, candidates, positions, these, other, group, posn) { + } + +void BestIterator::increment() { + int lowest_added = -1; + int best_group = -1; + int best_posn = -1; + for(int group_no = 0; group_no < _agent.preferences.size(); ++group_no) { + auto & group = _agent.preferences[group_no]; + for(int posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + int other_rank = _agent.ranks[group_no][posn]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto other_pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(other_pref) == 0) { + num_added++; + } + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_group = group_no; + best_posn = posn; + } + } + } + if (lowest_added != -1) { + _group = best_group; + _position = best_posn; + } else { + _group = -1; + _position = 0; + } +} + +void BestIterator::begin() { + int lowest_added = -1; + int best_group = -1; + int best_posn = -1; + for(int group_no = 0; group_no < _agent.preferences.size(); ++group_no) { + auto & group = _agent.preferences[group_no]; + for(int posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + int other_rank = _agent.ranks[group_no][posn]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto other_pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(other_pref) == 0) { + num_added++; + } + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_group = group_no; + best_posn = posn; + } + } + } + if (lowest_added != -1) { + _group = best_group; + _position = best_posn; + } else { + _group = -1; + _position = 0; + } +} + +BestGroupIterator::BestGroupIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group, int posn) : + AgentIteratorBase(agent, candidates, positions, these, other, group, posn) { + } + +void BestGroupIterator::increment() { + int lowest_added = -1; + int best_posn = -1; + auto & group = _agent.preferences[_group]; + for(int posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + int other_rank = _agent.ranks[_group][posn]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto other_pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(other_pref) == 0) { + num_added++; + } + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_posn = posn; + } + } + if (lowest_added != -1) { + _position = best_posn; + } else { + _group++; + if (_group == _agent.preferences.size()) { + _position = 0; + _group = -1; + } else { + increment(); + } + } +} + +void BestGroupIterator::begin() { + int lowest_added = -1; + int best_posn = -1; + if (_group == -1) { + return; + } + auto & group = _agent.preferences[_group]; + for(int posn = 0; posn < group.size(); ++posn) { + int other_id = group[posn]; + if (_positions.count(other_id) != 0) { + continue; + } + int num_added = 0; + int other_rank = _agent.ranks[_group][posn]; + for(int group_ind = 0; group_ind <= other_rank; group_ind++) { + for(auto other_pref: _other[other_id].preferences[group_ind]) { + if (_candidates.count(other_pref) == 0) { + num_added++; + } + } + } + if ((lowest_added == -1) || (num_added < lowest_added)) { + lowest_added = num_added; + best_posn = posn; + } + } + if (lowest_added != -1) { + _position = best_posn; + } else { + _group++; + if (_group == _agent.preferences.size()) { + _position = 0; + _group = -1; + } else { + increment(); + } + } +} diff --git a/SMTI/8_YESBIN_2STA_YESMERGED/AgentIterator.h b/SMTI/8_YESBIN_2STA_YESMERGED/AgentIterator.h new file mode 100644 index 0000000..48b96c6 --- /dev/null +++ b/SMTI/8_YESBIN_2STA_YESMERGED/AgentIterator.h @@ -0,0 +1,110 @@ +#ifndef AGENTITERATOR_H +#define AGENTITERATOR_H + +#include + +#include "Allocation.h" + +class AgentIteratorBase { +public: + AgentIteratorBase(const Child & agent, const std::set & candidates, const std::set & positions, + const std::vector & these, const std::vector & other, int group=0, int posn=0); + virtual ~AgentIteratorBase() = 0; + virtual void increment() = 0; + virtual void begin() = 0; + + int get_position() const; + int get_group() const; + const Child & get_agent() const; + const std::vector & get_these() const; + const std::vector & get_other() const; + const std::set & get_positions() const; + const std::set & get_candidates() const; +protected: + void regularIncrement(); + + const Child & _agent; + int _group; + int _position; + const std::vector & _these; + const std::vector & _other; + const std::set & _positions; + const std::set & _candidates; +}; + + +class AgentIterator : public std::iterator, ptrdiff_t> { +public: + AgentIterator(const Child & agent, const std::set & candidates, const std::set & positions, + const std::vector & these, const std::vector & other, int mode); + AgentIterator(AgentIterator *other, int group, int posn); + AgentIterator(AgentIterator *other); + ~AgentIterator(); + bool operator==(const AgentIterator& other); + bool operator!=(const AgentIterator& other); + const std::pair operator*(); + AgentIterator& operator++() {base->increment(); return *this; } + AgentIterator operator++(int) {AgentIterator res(this); base->increment(); return res; } + + AgentIterator begin(); + AgentIterator end(); + + int get_position() const; + int get_group() const; + int get_mode() const; + + const Child & get_agent() const { return base->get_agent(); } + const std::vector & get_these() const {return base->get_these(); } + const std::vector & get_other() const {return base->get_other(); } + const std::set & get_positions() const {return base->get_positions(); } + const std::set & get_candidates() const {return base->get_candidates(); } +private: + AgentIteratorBase * base; + int _mode; +}; + + +class DescendingIterator : public AgentIteratorBase { + public: + DescendingIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group=0, int posn=0); + ~DescendingIterator() {} + void increment(); + void begin(); +}; + + +class SkipBigIterator : public AgentIteratorBase { + public: + SkipBigIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int skip, int group, int posn); + ~SkipBigIterator() {} + void increment(); + void begin(); + private: + int _skip; +}; + +class BestIterator : public AgentIteratorBase { + public: + BestIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group=0, int posn=0); + ~BestIterator() {} + void increment(); + void begin(); +}; + +class BestGroupIterator : public AgentIteratorBase { + public: + BestGroupIterator(const Child & agent, const std::set & candidates, + const std::set & positions, const std::vector & these, + const std::vector & other, int group=0, int posn=0); + ~BestGroupIterator() {} + void increment(); + void begin(); +}; + +#endif /* AGENTITERATOR_H */ diff --git a/SMTI/8_YESBIN_2STA_YESMERGED/Allocation.cpp b/SMTI/8_YESBIN_2STA_YESMERGED/Allocation.cpp index 44a6851..2687110 100644 --- a/SMTI/8_YESBIN_2STA_YESMERGED/Allocation.cpp +++ b/SMTI/8_YESBIN_2STA_YESMERGED/Allocation.cpp @@ -1,29 +1,17 @@ #include "Allocation.h" +#include "AgentIterator.h" +#include "Graph.h" /* ************************************************************************************* *********************************** DOCTOR ***************************************** ************************************************************************************* */ -void Child::print(){ - cout << "Child " << id << "\t Preferences (" << nbPref << " groups, " << nbTotPref << " in total)\t"; - for(int i=0; i 0) cout << " "; - cout << preferences[i][j]; - cout << "[" << ranks[i][j] << "_" << positions[i][j] << "]"; - } - cout << ") "; - } - cout << endl; -} - -/* ************************************************************************************* - *********************************** HOSPITAL **************************************** - ************************************************************************************* */ - -void Family::print(){ - cout << "Family " << id << "\t Preferences (" << nbPref << " groups, " << nbTotPref << " in total)\t"; +void Child::print(bool family){ + if (family) + cout << "Family "; + else + cout << "Child "; + cout << id << "\t Preferences (" << nbPref << " groups, " << nbTotPref << " in total)\t"; for(int i=0; i, vector >::iterator it; - map, vector > mapFirstChoice; - for(int j=0; j temp(nbChildren,0); - if(families[j].nbPref > 0){ - for(int k=0;k, vector > add; - add.first = temp; - add.second.push_back(j); - mapFirstChoice.insert(add); - } - else{ - (*it).second.push_back(j); +int Allocation::reductionExact(bool children_side, bool supp) { + int nbTotRem = 0; + int number_here = nbChildren; + std::vector * thesep; + std::vector * otherp; + std::list *theseMustBeAllocatedp; + std::list *otherMustBeAllocatedp; + if (children_side) { + // Processing the lists of the children, removing families + thesep = &children; + otherp = &families; + theseMustBeAllocatedp = &childrenMustBeAllocated; + otherMustBeAllocatedp = &familiesMustBeAllocated; + number_here = nbChildren; + } else { + thesep = &families; + otherp = &children; + theseMustBeAllocatedp = &familiesMustBeAllocated; + otherMustBeAllocatedp = &childrenMustBeAllocated; + number_here = nbFamilies; + } + std::vector & these = (*thesep); + std::vector & other = (*otherp); + std::list & theseMustBeAllocated = (*theseMustBeAllocatedp); + std::list & otherMustBeAllocated = (*otherMustBeAllocatedp); + for (int i = 0; i < number_here; i++) { + // A graph is "named" with two integers. The first is a 0 for a candidate + // (aka these) or a 1 for a position (aka other) + Graph g; + int n_1 = 0; + for(int rank = 0; rank < these[i].nbPref; rank++) { + // No point in checking the last rank if we already know this agent must + // be allocated, or if we don't care + if ((rank == these[i].nbPref - 1) && (these[i].mustBeAllocated || !supp)) { + continue; } - } - else count++; - } - -/* for(it = mapFirstChoice.begin(); it!= mapFirstChoice.end(); ++it){ - cout << (*it).second.size() << " x (" << families[(*it).second[0]].preferences[0].size() << ") ["; - for(int i=0;i<(*it).second.size();i++){ - cout << (*it).second[i] << " "; - } - cout << "] == ["; - for(int i=0;i<(*it).first.size();i++){ - cout << (*it).first[i] << " "; - } - cout << "]" << endl; - } - - cout << "Count = " << count << endl;*/ - - // Step 2 -- See worst rank - - vector worstRank(nbChildren); - for(int i=0;i= families[(*it).second[0]].preferences[0].size() ){ - // cout << "Updates from " << co << endl;; co++; - for(int i=0; i < families[(*it).second[0]].preferences[0].size();i++){ - multiset orderedRanks; - multiset::iterator it2; - for(int j=0; j<(*it).second.size();j++){ - orderedRanks.insert(families[(*it).second[j]].ranks[0][i]); + for(size_t ind = 0; ind < these[i].preferences[rank].size(); ind++) { + int position = these[i].preferences[rank][ind]; + g.addVertex(1, position); + int idxRank = these[i].ranks[rank][ind]; + for(int l = 0; l <= idxRank; l++) { + for(size_t k = 0; k < other[position].preferences[l].size(); k++) { + int other_cand = other[position].preferences[l][k]; + if (other_cand == i) { // Don't add the current candidate to the graph + continue; + } + if (! g.containsVertex(0, other_cand)) { + g.addVertex(0, other_cand); + n_1 += 1; + } + g.addEdge(position, other_cand); + } } - // cout << "worstRank of " << families[(*it).second[0]].preferences[0][i] << " updated from " << worstRank[families[(*it).second[0]].preferences[0][i]]; - it2 = orderedRanks.begin(); - advance(it2, families[(*it).second[0]].preferences[0].size() - 1); - worstRank[families[(*it).second[0]].preferences[0][i]]=min(worstRank[families[(*it).second[0]].preferences[0][i]], *(it2)); - // cout << " to " << worstRank[families[(*it).second[0]].preferences[0][i]] << endl; } - } - } - - // Step 3 -- Remove families after worst rank from child's preferences - - int nbTotRem = 0; - - for(int i=0; i, vector >::iterator it; - map, vector > mapFirstChoice; - for(int j=0; j temp(nbFamilies,0); - if(children[j].nbPref > 0){ - for(int k=0;k, vector > add; - add.first = temp; - add.second.push_back(j); - mapFirstChoice.insert(add); } - else{ - (*it).second.push_back(j); - } - } - else count++; - } - -/* for(it = mapFirstChoice.begin(); it!= mapFirstChoice.end(); ++it){ - cout << (*it).second.size() << " x (" << children[(*it).second[0]].preferences[0].size() << ") ["; - for(int i=0;i<(*it).second.size();i++){ - cout << (*it).second[i] << " "; - } - cout << "] == ["; - for(int i=0;i<(*it).first.size();i++){ - cout << (*it).first[i] << " "; - } - cout << "]" << endl; - } - - cout << "Count = " << count << endl;*/ - - // Step 2 -- See worst rank - - vector worstRank(nbFamilies); - for(int i=0;i= children[(*it).second[0]].preferences[0].size() ){ - // cout << "Updates from " << co << endl;; co++; - for(int i=0; i < children[(*it).second[0]].preferences[0].size();i++){ - multiset orderedRanks; - multiset::iterator it2; - for(int j=0; j<(*it).second.size();j++){ - orderedRanks.insert(children[(*it).second[j]].ranks[0][i]); + // Add P' in this + // Yes, I'm abusing while statements, so I can break out easier. + while (rank == 0) { + // Don't add P' if we don't need to. + if (matching_cant_exist || (g.size() - g.matchingSize() >= n_1 + 1)) { + break; } - // cout << "worstRank of " << children[(*it).second[0]].preferences[0][i] << " updated from " << worstRank[children[(*it).second[0]].preferences[0][i]]; - it2 = orderedRanks.begin(); - advance(it2, children[(*it).second[0]].preferences[0].size() - 1); - worstRank[children[(*it).second[0]].preferences[0][i]]=min(worstRank[children[(*it).second[0]].preferences[0][i]], *(it2)); - // cout << " to " << worstRank[children[(*it).second[0]].preferences[0][i]] << endl; - } - } - } - - // Step 3 -- Remove families after worst rank from child's preferences - - int nbTotRem = 0; - - for(int i=0; i worstRank(nbChildren); - for(int i=0;i allChildren; - int count = 0; - for(int j=0; j= n_1 + 1)) { + // preprocess on rank! + // Firstly, they must be allocated, so mark as such (if we're in that + // mode) + if (supp && !these[i].mustBeAllocated) { + theseMustBeAllocated.push_back(i); + these[i].mustBeAllocated = true; } - } - if(count >= allChildren.size()){ - worstRank[i] = j; - // cout << "worst rank of " << i << " is " << j << endl; +#ifdef DEBUG + if ((!children_side) and (i == 6)) { + std::cout << "g.size() = " << g.size() << ", g.matchingSize() = " << g.matchingSize(); + std::cout << ", n_1 = " << n_1 << std::endl; + g.printGraph(); + g.printMatching(); + } + if (children_side) { + std::cout << "child "; + } else { + std::cout << "family "; + } + std::cout << "worst rank of " << i << " is " << rank << " "; + int remHere = 0; +#endif /* DEBUG */ + for (int k = rank + 1; k < these[i].nbPref; k++) { + nbTotRem += these[i].preferences[k].size(); +#ifdef DEBUG + remHere += these[i].preferences[k].size(); +#endif /* DEBUG */ + these[i].nbTotPref -= these[i].preferences[k].size(); + for (unsigned int l = 0; l < these[i].preferences[k].size(); l++) { + int idxFam = these[i].preferences[k][l]; + int idxPos = these[i].positions[k][l]; + int idxRank = these[i].ranks[k][l]; + for (unsigned int m = idxPos + 1; + m < other[idxFam].preferences[idxRank].size(); m++) { + these[other[idxFam].preferences[idxRank][m]] + .positions[other[idxFam].ranks[idxRank][m]] + [other[idxFam].positions[idxRank][m]]--; + } + other[idxFam].nbTotPref--; + other[idxFam].positions[idxRank].erase( + other[idxFam].positions[idxRank].begin() + idxPos); + other[idxFam].ranks[idxRank].erase( + other[idxFam].ranks[idxRank].begin() + idxPos); + other[idxFam].preferences[idxRank].erase( + other[idxFam].preferences[idxRank].begin() + idxPos); + } + } + these[i].nbPref = rank + 1; + these[i].preferences.resize(these[i].nbPref); + these[i].ranks.resize(these[i].nbPref); + these[i].positions.resize(these[i].nbPref); +#ifdef DEBUG + std::cout << "removed " << remHere << std::endl; +#endif /* DEBUG */ break; } } } - - for(int i=0; i 0) { + polish(); } - - polish(); return nbTotRem; } -int Allocation::reductionChi2(){ - +int Allocation::reductionMine(bool children_side, int mode) { int nbTotRem = 0; - vector worstRank(nbFamilies); - for(int i=0;i allFamilies; - int count = 0; - for(int j=0; j * thesep; + std::vector * otherp; + if (children_side) { + thesep = &children; + otherp = &families; + number_here = nbChildren; + } else { + thesep = &families; + otherp = &children; + number_here = nbFamilies; + } + std::vector & these = (*thesep); + std::vector & other = (*otherp); + + for (int i = 0; i < number_here; i++) { + set candidates; + set positions; + int worst_rank = 0; + unsigned int count = 0; + AgentIterator iter(these[i], candidates, positions, these, other, mode); + for(std::pair p: iter) { + int j = p.first; + int k = p.second; + if (j > worst_rank) { + worst_rank = j; + } + int idxFam = these[i].preferences[j][k]; + int idxRank = these[i].ranks[j][k]; + positions.insert(idxFam); + count++; + for (int l = 0; l <= idxRank; l++) { + for (unsigned int m = 0; m < other[idxFam].preferences[l].size(); + m++) { + candidates.insert(other[idxFam].preferences[l][m]); } } - if(count >= allFamilies.size()){ - worstRank[i] = j; - // cout << "worst rank of " << i << " is " << j << endl; + if (count >= candidates.size()) { +#ifdef DEBUG + if (children_side) { + std::cout << "child "; + } else { + std::cout << "family "; + } + std::cout << "worst rank of " << i << " is " << worst_rank << std::endl; +#endif /* DEBUG */ + for (int k = worst_rank + 1; k < these[i].nbPref; k++) { + nbTotRem += these[i].preferences[k].size(); + these[i].nbTotPref -= these[i].preferences[k].size(); + for (unsigned int l = 0; l < these[i].preferences[k].size(); l++) { + int idxFam = these[i].preferences[k][l]; + int idxPos = these[i].positions[k][l]; + int idxRank = these[i].ranks[k][l]; + for (unsigned int m = idxPos + 1; + m < other[idxFam].preferences[idxRank].size(); m++) { + these[other[idxFam].preferences[idxRank][m]] + .positions[other[idxFam].ranks[idxRank][m]] + [other[idxFam].positions[idxRank][m]]--; + } + other[idxFam].nbTotPref--; + other[idxFam].positions[idxRank].erase( + other[idxFam].positions[idxRank].begin() + idxPos); + other[idxFam].ranks[idxRank].erase( + other[idxFam].ranks[idxRank].begin() + idxPos); + other[idxFam].preferences[idxRank].erase( + other[idxFam].preferences[idxRank].begin() + idxPos); + } + } + these[i].nbPref = worst_rank + 1; + these[i].preferences.resize(these[i].nbPref); + these[i].ranks.resize(these[i].nbPref); + these[i].positions.resize(these[i].nbPref); break; } } } - - for(int i=0; i 0) { + polish(); } - - polish(); return nbTotRem; } @@ -605,20 +536,50 @@ void Allocation::polish(){ } } -void Allocation::reduction(){ - int nbRed1 = 0; - int nbRed2 = 0; - int nbRed3 = 0; - int nbRed4 = 0; +void Allocation::reduction(int mode){ + total_reduced = 0; int i = 0; - do{ - nbRed1 = reductionFam1(); - nbRed2 = reductionChi1(); - nbRed3 = reductionFam2(); - nbRed4 = reductionChi2(); - cout << "Reduction iteration " << i << " reductionFam1 " << nbRed1 << " reductionChi1 " << nbRed2 << " reductionFam2 " << nbRed3 << " reductionChi2 " << nbRed4 << endl; - i++; - }while(nbRed1 + nbRed2 + nbRed3 + nbRed4 != 0); + int num = 0; + if (mode == 7) { + do { + num = reductionMine(false, 1); + num += reductionMine(true, 1); + cout << "Iteration " << i << " in heuristic removed " << num << std::endl; + i++; + total_reduced += num; + } while (num != 0); + do { + num = reductionExact(false); + num += reductionExact(true); + cout << "Iteration " << i << " in exact mode removed " << num << std::endl; + i++; + total_reduced += num; + } while (num != 0); + } else { + do{ + if (mode == 6) { + // True means preprocess childrens' lists, removing families. + // False means preprocess families' lists, removing children. + num = reductionExact(false); + num += reductionExact(true); + } else if (mode == 8) { + num = reductionExact(true); + num += reductionExact(false); + } else if (mode == 9) { + num = reductionExact(false, true); + num += reductionExact(true, true); + } else if (mode == 10) { + num = reductionExact(true, true); + num += reductionExact(false, true); + } else { + num = reductionMine(false, mode); + num += reductionMine(true, mode); + } + cout << "Iteration " << i << " in mode " << mode << " removed " << num << std::endl; + i++; + total_reduced += num; + }while(num != 0); + } } void Allocation::printSol(){ @@ -631,7 +592,7 @@ void Allocation::printSol(){ void Allocation::printInfo(const string& pathAndFileout){ string nameFile = pathAndFileout; std::ofstream file(nameFile.c_str(), std::ios::out | std::ios::app); - file << name << "\t" << infos.opt << "\t" << infos.timeCPU << "\t" << infos.timeCPUPP << "\t"<< infos.LB << "\t" << infos.UB << "\t" << infos.contUB << "\t" << infos.nbVar << "\t" << infos.nbCons << "\t" << infos.nbNZ + file << name << "\t" << infos.opt << "\t" << infos.timeCPU << "\t" << infos.timeCPUPP << "\t" << total_reduced << "\t"<< infos.LB << "\t" << infos.UB << "\t" << infos.contUB << "\t" << infos.nbVar << "\t" << infos.nbCons << "\t" << infos.nbNZ << "\t" << infos.contUB2 << "\t" << infos.nbVar2 << "\t" << infos.nbCons2 << "\t" << infos.nbNZ2 << endl; file.close(); } diff --git a/SMTI/8_YESBIN_2STA_YESMERGED/Allocation.h b/SMTI/8_YESBIN_2STA_YESMERGED/Allocation.h index dcd6046..def9c6e 100644 --- a/SMTI/8_YESBIN_2STA_YESMERGED/Allocation.h +++ b/SMTI/8_YESBIN_2STA_YESMERGED/Allocation.h @@ -4,6 +4,7 @@ using namespace std; #include #include +#include #include #include #include @@ -12,7 +13,7 @@ #include class Child; - class Family; + typedef Child Family; class Assignment; class Allocation; @@ -21,29 +22,15 @@ ************************************************************************************* */ class Child{ - public: - int id; - int nbPref; - int nbTotPref; - vector > preferences; - vector > ranks; - vector > positions; - void print(); - }; - -/* ************************************************************************************* - *********************************** HOSPITAL **************************************** - ************************************************************************************* */ - - class Family{ public: int id; int nbPref; int nbTotPref; + bool mustBeAllocated; vector > preferences; vector > ranks; vector > positions; - void print(); + void print(bool); }; /* ************************************************************************************* @@ -76,6 +63,7 @@ string name; int nbChildren; int nbFamilies; + int total_reduced; vector children; vector families; @@ -84,20 +72,21 @@ vector assignmentByChild; vector assignmentByFamily; + std::list childrenMustBeAllocated; + std::list familiesMustBeAllocated; + Info infos; void load(const string& path, const string& filein); void printProb(); - int reductionFam1(); - int reductionChi1(); - int reductionFam2(); - int reductionChi2(); + int reductionMine(bool children_side=true, int mode=0); + int reductionExact(bool children_side=true, bool supp=false); void polish(); - void reduction(); + void reduction(int mode); void printSol(); void printInfo(const string& pathAndFileout); void checkSolution(); }; -#endif \ No newline at end of file +#endif diff --git a/SMTI/8_YESBIN_2STA_YESMERGED/Graph.cpp b/SMTI/8_YESBIN_2STA_YESMERGED/Graph.cpp new file mode 100644 index 0000000..3bcccb0 --- /dev/null +++ b/SMTI/8_YESBIN_2STA_YESMERGED/Graph.cpp @@ -0,0 +1,107 @@ +#include +#include "Graph.h" + + +// Expected biggest graph, to save on allocations +const size_t expected_size = 2048; + +Graph::Graph() : _exists(2), _adjacents(2), _matching(2), _size(0), _matching_size(0) { + _exists[0] = std::vector(expected_size, false); + _exists[1] = std::vector(expected_size, false); + _adjacents[0] = std::vector>(expected_size); + _adjacents[1] = std::vector>(expected_size); + _matching[0] = std::vector(expected_size, -1); + _matching[1] = std::vector(expected_size, -1); +#ifdef DEBUG + std::cout << "New graph" << std::endl; +#endif /* DEBUG */ +} + +void Graph::addVertex(int side, int name) { + _exists[side][name] = true; + _size += 1; +} + +bool Graph::containsVertex(int side, int name) const { + return _exists[side][name]; +} + +/** + * Adds an edge to the graph. Note that this edge must always be added in the + * form (right, left) for things to work. + */ +void Graph::addEdge(int v1, int v2) { + _adjacents[1][v1].push_back(v2); + _adjacents[0][v2].push_back(v1); +} + +int Graph::size() const { + return _size; +} + +int Graph::matchingSize() const { + return _matching_size; +} + +/** + * Augment the matching, starting at vertex name which is on the right. + */ +void Graph::augment(int name) { +#ifdef DEBUG + std::cout << "Augmenting on " << _indices.at(start) << std::endl; + this->printGraph(); +#endif /* DEBUG */ + std::list path; + std::vector visited(expected_size, false); + path.push_back(name); + internal_augment(name, visited, path); +} + +/** + * Continues an augmentation, on vertex now, which is on the right. + */ +bool Graph::internal_augment(int now, std::vector & visited, + std::list & path) { + for(int next: _adjacents[1][now]) { + // next is on the left + if (visited[next]) { + continue; + } + if (_matching[0][next] == -1) { + // Found an augmenting path. Switch edges and return true. +#ifdef DEBUG + std::cout << "New matching found." << std::endl; +#endif /* DEBUG */ + path.push_back(next); +#ifdef DEBUG + std::cout << "Path is "; + for(auto p: path) { + std::cout << " " << _indices.at(p); + } + std::cout << std::endl; + +#endif /* DEBUG */ + while(!path.empty()) { + int right = path.front(); + path.pop_front(); + int left = path.front(); + path.pop_front(); + _matching[1][right] = left; + _matching[0][left] = right; + } + _matching_size += 1; + return true; + } + int next2 = _matching[0][next]; + path.push_back(next); + path.push_back(next2); + visited[next] = true; + if (internal_augment(next2, visited, path)) { + return true; + } + path.pop_back(); + path.pop_back(); + } + return false; +} + diff --git a/SMTI/8_YESBIN_2STA_YESMERGED/Graph.h b/SMTI/8_YESBIN_2STA_YESMERGED/Graph.h new file mode 100644 index 0000000..5d07f00 --- /dev/null +++ b/SMTI/8_YESBIN_2STA_YESMERGED/Graph.h @@ -0,0 +1,60 @@ +#ifndef GRAPH_H +#define GRAPH_H + +#include +#include +#include +#include +#include +#include + + +static_assert(std::numeric_limits::max() >= ((long unsigned)1 << 63), "size_t is too small"); + +struct pairhash { + public: + std::size_t operator()(const std::pair &x) const { + return (long)x.first * ((long)1 << 32) + x.second; + } +}; + +#ifdef DEBUG +#include +inline std::ostream& operator<<(std::ostream& o, const std::pair &x) { + o << "(" << x.first << ", " << x.second << ")"; + return o; +} +#endif /* DEBUG */ + + +class Graph { + public: + Graph(); + void addVertex(int side, int name); + bool containsVertex(int side, int name) const; + void addEdge(int v1, int v2); + int matched(int vertex) const; + void augment(int vertex); + + int size() const; + int matchingSize() const; + + int name(int vert_index); + +#ifdef DEBUG + void printGraph(); + void printMatching() const; +#endif /* DEBUG */ + + private: + std::vector> _exists; + std::vector>> _adjacents; + std::vector> _matching; + + int _size; + int _matching_size; + + bool internal_augment(int now, std::vector & visited, std::list & path); +}; + +#endif /* GRAPH_H */ diff --git a/SMTI/8_YESBIN_2STA_YESMERGED/main.cpp b/SMTI/8_YESBIN_2STA_YESMERGED/main.cpp index f4e2ae3..28e6d30 100644 --- a/SMTI/8_YESBIN_2STA_YESMERGED/main.cpp +++ b/SMTI/8_YESBIN_2STA_YESMERGED/main.cpp @@ -1,5 +1,7 @@ #include "main.h" +#define MAXTIME 3600 + /* ************************************************************************************* ************************************* MAIN ***************************************** ************************************************************************************* */ @@ -11,27 +13,38 @@ int main(int argc, char **argv){ string filein = argv[2]; string path = argv[1]; string pathAndFileout = argv[3]; + int mode = atoi(argv[4]); // functions allo.load(path, filein); - allo.printProb(); + //allo.printProb(); - manlove(allo); - - allo.printSol(); - allo.checkSolution(); + int res = manlove(allo, mode); + if (res != -1) { + allo.printSol(); + allo.checkSolution(); + } allo.printInfo(pathAndFileout); } -int manlove(Allocation& allo){ +int manlove(Allocation& allo, int mode){ double initTimeModelCPU = getCPUTime(); GRBEnv env = GRBEnv(); double initTimeModelCPUPP = getCPUTime(); - allo.reduction(); - allo.printProb(); + if (mode != 12) { + allo.reduction(mode); + } + //allo.printProb(); allo.infos.timeCPUPP = getCPUTime() - initTimeModelCPUPP; + if (allo.infos.timeCPUPP > MAXTIME) { + cout << "Preprocessing took over " << MAXTIME << " seconds" << endl; + allo.infos.LB = 0; + allo.assignmentByChild.resize(allo.nbChildren, -1); + allo.assignmentByFamily.resize(allo.nbFamilies, -1); + return -1; + } // Model try{ @@ -139,7 +152,7 @@ int manlove(Allocation& allo){ } // Setting of Gurobi - model.getEnv().set(GRB_DoubleParam_TimeLimit, 3600 - (getCPUTime() - initTimeModelCPU)); + model.getEnv().set(GRB_DoubleParam_TimeLimit, MAXTIME - (getCPUTime() - initTimeModelCPU)); model.getEnv().set(GRB_IntParam_Threads, 1); model.getEnv().set(GRB_DoubleParam_MIPGap, 0); model.optimize(); diff --git a/SMTI/8_YESBIN_2STA_YESMERGED/main.h b/SMTI/8_YESBIN_2STA_YESMERGED/main.h index c441859..3bf5282 100644 --- a/SMTI/8_YESBIN_2STA_YESMERGED/main.h +++ b/SMTI/8_YESBIN_2STA_YESMERGED/main.h @@ -11,6 +11,6 @@ float EPSILON = 0.001; - int manlove(Allocation& allo); + int manlove(Allocation& allo, int reduction_mode); #endif diff --git a/SMTI/8_YESBIN_2STA_YESMERGED/makefile b/SMTI/8_YESBIN_2STA_YESMERGED/makefile index 9b4aeb1..82b1239 100644 --- a/SMTI/8_YESBIN_2STA_YESMERGED/makefile +++ b/SMTI/8_YESBIN_2STA_YESMERGED/makefile @@ -8,14 +8,14 @@ CPPLIB = -L$(GUROBI_DIR)/lib/ -lgurobi_c++ $(CLIB) GUROBI_OPTS = -I$(INC) $(CPPLIB) -lpthread -lm -m64 CC = g++ -CFLAGS = -O2 -Wall -ansi -pedantic -DIL_STD +CFLAGS = -O2 -Wall -ansi -pedantic -DIL_STD -std=c++11 DEBUG = -pg -g -Wall -ansi -pedantic -DIL_STD -OBJECTS = main.o Allocation.o time.o +OBJECTS = main.o Allocation.o time.o AgentIterator.o Graph.o exec : $(OBJECTS) $(CC) $(CFLAGS) -o YESBIN_2STA_YESMERGED $(OBJECTS) $(GUROBI_OPTS) -.cpp.o : +.cpp.o : $< $(CC) $(CFLAGS) $(GUROBI_OPTS) -c $< -o $@ clean : diff --git a/SMTI/README.md b/SMTI/README.md new file mode 100644 index 0000000..5d87cd7 --- /dev/null +++ b/SMTI/README.md @@ -0,0 +1,14 @@ +# Naming + +The following table relates these folders to the names used in the paper + +| Folder name | Algorithm index in paper +|-------------|-------------------------| +|1_NOBIN_1STA_NOMERGED | M1 | +|2_YESBIN_1STA_NOMERGED | M2 | +|3_NOBIN_1STA_YESMERGED | M3 | +|4_YESBIN_1STA_YESMERGED | M4 | +|7_NOBIN_2STA_YESMERGED | M5 | +|8_YESBIN_2STA_YESMERGED | M6 | + +The folder 1_NOBIN_1STA_NOMERGED_NOPRE is M1 but with preprocessing disabled.