CMR  1.3.0
violator_search.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 #include <boost/numeric/ublas/matrix_proxy.hpp>
4 
5 #include "matrix_internal.h"
6 #include "algorithm.hpp"
7 #include "matroid.hpp"
8 #include "signing.hpp"
9 #include "logger.hpp"
10 #include "total_unimodularity.hpp"
11 
12 namespace tu
13 {
14  namespace detail
15  {
16 
17  inline matroid_element_set find_smallest_irregular_minor(const decomposed_matroid* decomposition, bool collect_extra_elements = true)
18  {
19  if (decomposition->is_leaf())
20  {
21  const decomposed_matroid_leaf* leaf = (decomposed_matroid_leaf*) decomposition;
22 
23  if (leaf->is_regular())
24  return matroid_element_set();
25 
26  matroid_element_set result;
27  std::copy(leaf->elements().begin(), leaf->elements().end(), std::inserter(result, result.end()));
28  if (collect_extra_elements)
29  std::copy(leaf->extra_elements().begin(), leaf->extra_elements().end(), std::inserter(result, result.end()));
30  return result;
31  }
32  else
33  {
34  const decomposed_matroid_separator* separator = (decomposed_matroid_separator*) decomposition;
35 
36  matroid_element_set first_elements = find_smallest_irregular_minor(separator->first(), collect_extra_elements);
37  matroid_element_set second_elements = find_smallest_irregular_minor(separator->second(), collect_extra_elements);
38  if (first_elements.empty())
39  return second_elements;
40  else if (second_elements.empty())
41  return first_elements;
42  else
43  return (first_elements.size() < second_elements.size()) ? first_elements : second_elements;
44  }
45  }
46 
47  template <typename InputIterator, typename OutputIterator1, typename OutputIterator2>
48  std::pair <OutputIterator1, OutputIterator2> split_elements(InputIterator first, InputIterator beyond, OutputIterator1 rows,
49  OutputIterator2 columns)
50  {
51  for (; first != beyond; ++first)
52  {
53  if (*first > 0)
54  *columns++ = *first;
55  else
56  *rows++ = *first;
57  }
58  return std::make_pair(rows, columns);
59  }
60 
61  template <typename MatrixType>
62  void create_indirect_matroid(const MatrixType& input_matrix, const matroid_element_set& row_elements, const matroid_element_set& column_elements,
63  integer_matroid& sub_matroid, submatrix_indices& sub_indices)
64  {
65  CMR_UNUSED(input_matrix);
66 
67  sub_matroid.resize(row_elements.size(), column_elements.size());
68  submatrix_indices::vector_type row_vector(row_elements.size());
69  submatrix_indices::vector_type column_vector(column_elements.size());
70 
71  size_t index = row_elements.size() - 1;
72  for (matroid_element_set::const_iterator iter = row_elements.begin(); iter != row_elements.end(); ++iter)
73  {
74  sub_matroid.name1(index) = *iter;
75  row_vector[index] = -1 - *iter;
76  --index;
77  }
78 
79  index = 0;
80  for (matroid_element_set::const_iterator iter = column_elements.begin(); iter != column_elements.end(); ++iter)
81  {
82  sub_matroid.name2(index) = *iter;
83  column_vector[index] = -1 + *iter;
84  ++index;
85  }
86 
87  sub_indices.rows = submatrix_indices::indirect_array_type(row_vector.size(), row_vector);
88  sub_indices.columns = submatrix_indices::indirect_array_type(column_vector.size(), column_vector);
89 
90  }
91 
93  {
94  public:
95  violator_strategy(const integer_matrix& input_matrix, const matroid_element_set& row_elements, const matroid_element_set& column_elements,
96  logger& log) :
97  _input_matrix(input_matrix), _row_elements(row_elements), _column_elements(column_elements), _log(log)
98  {
99  //std::cout << "Searching for violator in " << _input_matrix.size1() << " x " << _input_matrix.size2() << " matrix." << std::endl;
100 
101  if (log.is_progressive() || _log.is_verbose())
102  {
103  std::cout << "\nMatrix is NOT totally unimodular. Searching the violating submatrix...\n" << std::endl;
104  }
105  }
106 
112  {
113 
114  }
115 
116  virtual void search() = 0;
117 
118  inline void create_matrix(submatrix_indices& indices) const
119  {
120  integer_matroid sub_matroid;
122  }
123 
124  protected:
125 
126  virtual void shrink(const matroid_element_set& row_elements, const matroid_element_set& column_elements)
127  {
128  typedef boost::numeric::ublas::matrix_indirect <const integer_matrix, submatrix_indices::indirect_array_type> indirect_matrix_t;
129 
131  submatrix_indices sub_indices;
132 
133  create_indirect_matroid(_input_matrix, row_elements, column_elements, matroid, sub_indices);
134  indirect_matrix_t sub_matrix(_input_matrix, sub_indices.rows, sub_indices.columns);
135 
136  if (is_totally_unimodular(sub_matrix))
137  {
138  std::cout << "submatrix is t.u., but should not:" << std::endl;
139  matrix_print(sub_matrix);
140 
141  assert (false);
142  }
143 
144  _row_elements = row_elements;
145  _column_elements = column_elements;
146 
147  }
148 
149  inline bool test(const matroid_element_set& row_elements, const matroid_element_set& column_elements)
150  {
151  typedef boost::numeric::ublas::matrix_indirect <const integer_matrix, submatrix_indices::indirect_array_type> indirect_matrix_t;
152 
154  submatrix_indices sub_indices;
155 
156  create_indirect_matroid(_input_matrix, row_elements, column_elements, matroid, sub_indices);
157  indirect_matrix_t sub_matrix(_input_matrix, sub_indices.rows, sub_indices.columns);
158 
160 
161  decomposed_matroid* decomposition;
162  integer_matrix matrix(sub_matrix);
163 
164  //if (_log.is_progressive() || _log.is_verbose())
165  //{
166  // std::cout << "Testing a " << row_elements.size() << " x " << column_elements.size() << " submatrix." << std::endl;
167  // integer_matrix M = sub_matrix;
168  // bool result = ghouila_houri_is_totally_unimodular(M);
169  // std::cout << "GH: " << (result ? "TU" : "non-TU" ) << std::endl;
170  //}
171 
172  if (!is_signed_matrix(matrix))
173  {
174  if (_log.is_progressive() || _log.is_verbose())
175  {
176  std::cout << "Submatrix did not pass the signing test. It is NOT totally unimodular.\n" << std::endl;
177  }
178  shrink(row_elements, column_elements);
179  return false;
180  }
181 
183  support_matrix(matrix);
184 
186  bool is_tu;
187  boost::tie(is_tu, decomposition) = decompose_binary_matroid(matroid, matrix, matroid_element_set(), true, _log);
188 
189  if (is_tu)
190  {
191  if (_log.is_progressive() || _log.is_verbose())
192  {
193  std::cout << "\nSubmatrix is totally unimodular.\n" << std::endl;
194  }
195  delete decomposition;
196  return true;
197  }
198 
200 
201 
202  // matroid_element_set rows, columns, elements = detail::find_smallest_irregular_minor(decomposition);
203  delete decomposition;
204 
205  // detail::split_elements(elements.begin(), elements.end(), std::inserter(rows, rows.end()), std::inserter(columns, columns.end()));
206 
207  if (_log.is_progressive() || _log.is_verbose())
208  {
209  // if (rows.size() < row_elements.size() || columns.size() < column_elements.size())
210  // {
211  // std::cout << "\nThe " << row_elements.size() << " x " << column_elements.size() << " submatrix is NOT totally unimodular. A "
212  // << rows.size() << " x " << columns.size() << " non-totally unimodular submatrix was identified, too.\n" << std::endl;
213  // }
214  // else
215  // {
216  std::cout << "\nThe " << row_elements.size() << " x " << column_elements.size() << " submatrix is NOT totally unimodular.\n" << std::endl;
217  // }
218  }
219 
220  //if (rows.size() < row_elements.size() || columns.size() < column_elements.size())
221  // shrink(rows, columns);
222  //else
223  shrink(row_elements, column_elements);
224 
225  return false;
226  }
227 
228  inline bool test_forbidden(const matroid_element_set& forbidden_elements)
229  {
231  matroid_element_set rows, columns;
232  for (matroid_element_set::const_iterator iter = _row_elements.begin(); iter != _row_elements.end(); ++iter)
233  {
234  if (forbidden_elements.find(*iter) == forbidden_elements.end())
235  {
236  rows.insert(*iter);
237  }
238  }
239  for (matroid_element_set::const_iterator iter = _column_elements.begin(); iter != _column_elements.end(); ++iter)
240  {
241  if (forbidden_elements.find(*iter) == forbidden_elements.end())
242  {
243  columns.insert(*iter);
244  }
245  }
246 
247  return test(rows, columns);
248  }
249 
250  protected:
255  };
256 
258  {
259  public:
260  single_violator_strategy(const integer_matrix& input_matrix, const matroid_element_set& row_elements,
261  const matroid_element_set& column_elements, logger& log) :
262  violator_strategy(input_matrix, row_elements, column_elements, log)
263  {
264 
265  }
266 
272  {
273 
274  }
275 
276  virtual void search()
277  {
278  std::vector <int> all_elements;
279  std::copy(_row_elements.begin(), _row_elements.end(), std::back_inserter(all_elements));
280  std::copy(_column_elements.begin(), _column_elements.end(), std::back_inserter(all_elements));
281 
282  for (std::vector <int>::const_iterator iter = all_elements.begin(); iter != all_elements.end(); ++iter)
283  {
284  if (_row_elements.find(*iter) == _row_elements.end() && _column_elements.find(*iter) == _column_elements.end())
285  continue;
286 
289  rows.erase(*iter);
290  columns.erase(*iter);
291  test(rows, columns);
292  }
293  }
294  };
295 
297  {
298  public:
299  greedy_violator_strategy(const integer_matrix& input_matrix, const matroid_element_set& row_elements,
300  const matroid_element_set& column_elements, logger& log) :
301  violator_strategy(input_matrix, row_elements, column_elements, log)
302  {
303 
304  }
305 
311  {
312 
313  }
314 
322  bool test_bundles(const std::vector <matroid_element_set>& bundles)
323  {
324  for (std::vector <matroid_element_set>::const_iterator bundle_iter = bundles.begin(); bundle_iter != bundles.end(); ++bundle_iter)
325  {
326  if (!test_forbidden(*bundle_iter))
327  {
328  return true;
329  }
330  }
331  return false;
332  }
333 
334  virtual void search()
335  {
336  for (float rate = 0.8f; rate > 0.02f; rate *= 0.5f)
337  {
338  size_t row_amount, column_amount;
339  if (rate > 0.04f)
340  {
341  row_amount = int(_row_elements.size() * rate);
342  column_amount = int(_column_elements.size() * rate);
343  if (row_amount == 0 || column_amount == 0)
344  {
345  row_amount = 1;
346  column_amount = 1;
347  rate = 0.03f;
348  }
349  }
350  else
351  {
352  row_amount = 1;
353  column_amount = 1;
354  }
355 
356  if (_log.is_progressive() || _log.is_verbose())
357  std::cout << "\nGreedy loop starting, forbidden sets will have size " << row_amount << " and " << column_amount << std::endl;
358 
359  typedef std::vector <matroid_element_set::value_type> matroid_element_vector;
360  matroid_element_vector shuffled_rows, shuffled_columns;
361  std::copy(_row_elements.begin(), _row_elements.end(), std::back_inserter(shuffled_rows));
362  std::copy(_column_elements.begin(), _column_elements.end(), std::back_inserter(shuffled_columns));
363 
364  std::random_shuffle(shuffled_rows.begin(), shuffled_rows.end());
365  std::random_shuffle(shuffled_columns.begin(), shuffled_columns.end());
366 
367  std::vector <matroid_element_set> bundles;
368 
369  for (matroid_element_vector::const_iterator iter = shuffled_rows.begin(); iter + row_amount <= shuffled_rows.end(); iter += row_amount)
370  {
371  bundles.push_back(matroid_element_set());
372  std::copy(iter, iter + row_amount, std::inserter(bundles.back(), bundles.back().end()));
373  }
374 
375  for (matroid_element_vector::const_iterator iter = shuffled_columns.begin(); iter + column_amount <= shuffled_columns.end(); iter
376  += column_amount)
377  {
378  bundles.push_back(matroid_element_set());
379  std::copy(iter, iter + column_amount, std::inserter(bundles.back(), bundles.back().end()));
380  }
381 
382  if (test_bundles(bundles))
383  {
384  rate *= 2.0f;
385  }
386  }
387  }
388  };
389 
390  }
391 
392 } /* namespace tu */
Definition: matroid_decomposition.hpp:83
virtual bool is_regular() const
Definition: matroid_decomposition.hpp:163
Definition: matroid_decomposition.hpp:179
decomposed_matroid * first() const
Definition: matroid_decomposition.hpp:219
decomposed_matroid * second() const
Definition: matroid_decomposition.hpp:228
Definition: matroid_decomposition.hpp:26
virtual bool is_leaf() const =0
const matroid_element_set & extra_elements() const
Definition: matroid_decomposition.hpp:68
const matroid_element_set & elements() const
Definition: matroid_decomposition.hpp:59
Definition: violator_search.hpp:297
bool test_bundles(const std::vector< matroid_element_set > &bundles)
Definition: violator_search.hpp:322
virtual ~greedy_violator_strategy()
Definition: violator_search.hpp:310
virtual void search()
Definition: violator_search.hpp:334
greedy_violator_strategy(const integer_matrix &input_matrix, const matroid_element_set &row_elements, const matroid_element_set &column_elements, logger &log)
Definition: violator_search.hpp:299
Definition: violator_search.hpp:258
single_violator_strategy(const integer_matrix &input_matrix, const matroid_element_set &row_elements, const matroid_element_set &column_elements, logger &log)
Definition: violator_search.hpp:260
virtual void search()
Definition: violator_search.hpp:276
virtual ~single_violator_strategy()
Definition: violator_search.hpp:271
Definition: violator_search.hpp:93
virtual void shrink(const matroid_element_set &row_elements, const matroid_element_set &column_elements)
Definition: violator_search.hpp:126
bool test(const matroid_element_set &row_elements, const matroid_element_set &column_elements)
Definition: violator_search.hpp:149
matroid_element_set _row_elements
Definition: violator_search.hpp:252
virtual ~violator_strategy()
Definition: violator_search.hpp:111
void create_matrix(submatrix_indices &indices) const
Definition: violator_search.hpp:118
logger & _log
Definition: violator_search.hpp:254
violator_strategy(const integer_matrix &input_matrix, const matroid_element_set &row_elements, const matroid_element_set &column_elements, logger &log)
Definition: violator_search.hpp:95
bool test_forbidden(const matroid_element_set &forbidden_elements)
Definition: violator_search.hpp:228
const integer_matrix & _input_matrix
Definition: violator_search.hpp:251
matroid_element_set _column_elements
Definition: violator_search.hpp:253
Definition: logger.hpp:19
bool is_progressive() const
Definition: logger.hpp:67
bool is_verbose() const
Definition: logger.hpp:58
Definition: matroid.hpp:22
void resize(size_t size1, size_t size2)
Definition: matroid.hpp:63
name_type & name2(size_t index)
Definition: matroid.hpp:116
name_type & name1(size_t index)
Definition: matroid.hpp:96
#define CMR_UNUSED(x)
Definition: env.h:24
matroid_element_set find_smallest_irregular_minor(const decomposed_matroid *decomposition, bool collect_extra_elements=true)
Definition: violator_search.hpp:17
std::pair< OutputIterator1, OutputIterator2 > split_elements(InputIterator first, InputIterator beyond, OutputIterator1 rows, OutputIterator2 columns)
Definition: violator_search.hpp:48
void create_indirect_matroid(const MatrixType &input_matrix, const matroid_element_set &row_elements, const matroid_element_set &column_elements, integer_matroid &sub_matroid, submatrix_indices &sub_indices)
Definition: violator_search.hpp:62
Definition: algorithm.hpp:14
bool is_signed_matrix(const integer_matrix &matrix)
Definition: total_unimodularity.cpp:397
void support_matrix(integer_matrix &matrix)
Definition: total_unimodularity.cpp:462
boost::numeric::ublas::matrix< long long > integer_matrix
Definition: common.hpp:27
std::pair< bool, decomposed_matroid * > decompose_binary_matroid(MatroidType &matroid, MatrixType &matrix, matroid_element_set extra_elements, bool construct_decomposition, logger &log)
Forward declaration.
Definition: algorithm.hpp:484
std::set< int > matroid_element_set
Definition: matroid_decomposition.hpp:19
bool is_totally_unimodular(const integer_matrix &matrix, log_level level)
Definition: total_unimodularity.cpp:47
Definition: common.hpp:15
indirect_array_type columns
Definition: common.hpp:20
boost::numeric::ublas::vector< size_t > vector_type
Definition: common.hpp:16
boost::numeric::ublas::indirect_array< vector_type > indirect_array_type
Definition: common.hpp:17
indirect_array_type rows
Definition: common.hpp:19