Camargue
dualgroup.hpp
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7 #ifndef CMR_DUALGROUP_H
8 #define CMR_DUALGROUP_H
9 
10 #include "lp_interface.hpp"
11 #include "hypergraph.hpp"
12 
13 #include <iostream>
14 #include <stdexcept>
15 #include <utility>
16 #include <vector>
17 #include <unordered_map>
18 
19 namespace CMR {
20 namespace LP {
21 
24 template <typename numtype>
25 struct DualGroup {
26  DualGroup() = default;
27 
29  DualGroup(bool remove_neg, const LP::Relaxation &relax,
30  const Sep::ExternalCuts &ext_cuts);
31 
32  DualGroup(DualGroup &&D) noexcept :
33  node_pi(std::move(D.node_pi)),
34  node_pi_est(std::move(D.node_pi_est)),
35  cut_pi(std::move(D.cut_pi)),
36  clique_pi(std::move(D.clique_pi)) {}
37 
38  DualGroup &operator=(DualGroup &&D) noexcept
39  {
40  node_pi = std::move(D.node_pi);
41  node_pi_est = std::move(D.node_pi_est);
42  cut_pi = std::move(D.cut_pi);
43  clique_pi = std::move(D.clique_pi);
44  return *this;
45  }
46 
47  std::vector<numtype> node_pi;
48  std::vector<numtype> node_pi_est;
49  std::vector<numtype> cut_pi;
50 
52  std::unordered_map<Sep::Clique, numtype> clique_pi;
53 };
54 
65 template <typename numtype>
66 DualGroup<numtype>::DualGroup(bool remove_neg, const LP::Relaxation &relax,
67  const Sep::ExternalCuts &ext_cuts) try
68 {
69  using HyperGraph = Sep::HyperGraph;
70  using CutType = HyperGraph::Type;
71  using std::vector;
72  using std::cout;
73  using std::cerr;
74  using std::endl;
75 
76  vector<double> full_pi;
77  vector<double> d_node_pi;
78  vector<double> d_cut_pi;
79 
80  const vector<HyperGraph> &cuts = ext_cuts.get_cuts();
81  const Sep::CliqueBank &clique_bank = ext_cuts.get_cbank();
82  const vector<int> &def_tour = clique_bank.ref_tour();
83 
84  int node_count = def_tour.size();
85 
86  if (relax.num_rows() != node_count + cuts.size()) {
87  cerr << "Relaxation row count: " << relax.num_rows() << ", "
88  << "ExternalCuts expects: "
89  << (node_count + cuts.size()) << "\n";
90  throw std::logic_error("Size mismatch.");
91  }
92 
93  clique_pi.reserve(clique_bank.size());
94  relax.get_pi(full_pi, 0, relax.num_rows() - 1);
95 
96  node_pi = vector<numtype>(full_pi.begin(), full_pi.begin() + node_count);
98 
99  if (!cuts.empty())
100  cut_pi = vector<numtype>(full_pi.begin() + node_count, full_pi.end());
101 
102  if (node_pi.size() != node_count || cut_pi.size() != cuts.size())
103  throw std::logic_error("Node pi or cut pi size mismatch");
104 
105  if (remove_neg) {
106  for (int i = 0; i < cuts.size(); ++i) {
107  if (cuts[i].get_sense() == 'G') {
108  if (cut_pi[i] < 0) {
109  cout << "\tCorrection: setting >= dual "
110  << cut_pi[i] << " to zero.\n";
111  cut_pi[i] = 0;
112  }
113  } else if (cuts[i].get_sense() == 'L') {
114  if (cut_pi[i] > 0) {
115  cout << "\tCorrection: setting <= dual "
116  << cut_pi[i] << " to zero.\n";
117  cut_pi[i] = 0;
118  }
119  }
120  }
121  }
122 
123  //get clique_pi for non-domino cuts
124  for (int i = 0; i < cuts.size(); ++i) {
125  const HyperGraph &H = cuts[i];
126 
127  if (H.cut_type() == CutType::Non)
128  throw std::logic_error("Tried to get_duals with Non cut present.");
129 
130  if (H.cut_type() == CutType::Domino)
131  continue;
132 
133  numtype pival = cut_pi[i];
134 
135  for (const Sep::Clique::Ptr &clq_ref : H.get_cliques()) {
136  if (clique_pi.count(*clq_ref) == 0)
137  clique_pi[*clq_ref] = 0.0;
138 
139  clique_pi[*clq_ref] += pival;
140  }
141  }
142  //use clique_pi to build node_pi for all cliques with nonzero pi
143  for (const std::pair<Sep::Clique, numtype> &kv : clique_pi) {
144  const Sep::Clique &clq = kv.first;
145  numtype pival = kv.second;
146 
147  if (pival > 0.0) {
148  for (const Segment &seg : clq.seg_list()) {
149  for (int k = seg.start; k <= seg.end; ++k) {
150  int node = def_tour[k];
151 
152  node_pi[node] += pival;
153  node_pi_est[node] += pival;
154  }
155  }
156  } else if (pival < 0.0) {
157  for (const Segment &seg : clq.seg_list()) {
158  for (int k = seg.start; k <= seg.end; ++k) {
159  int node = def_tour[k];
160 
161  node_pi[node] += pival;
162  }
163  }
164  }
165  }
166 
167 
168  //now get node_pi_est for domino cuts, skipping standard ones
169  for (int i = 0; i < cuts.size(); ++i) {
170  const HyperGraph &H = cuts[i];
171  if (H.cut_type() != CutType::Domino)
172  continue;
173 
174  numtype pival = cut_pi[i];
175  if (pival <= 0.0)
176  continue;
177 
178  const Sep::Clique::Ptr &handle_ref = H.get_cliques()[0];
179  for (const Segment &seg : handle_ref->seg_list()) {
180  for (int k = seg.start; k <= seg.end; ++k) {
181  int node = def_tour[k];
182  node_pi_est[node] += pival;
183  }
184  }
185 
186  for (const Sep::Tooth::Ptr &T : H.get_teeth())
187  for (const Sep::Clique &tpart : T->set_pair())
188  for (const Segment &seg : tpart.seg_list())
189  for (int k = seg.start; k <= seg.end; ++k) {
190  int node = def_tour[k];
191 
192  node_pi_est[node] += pival;
193  }
194  }
195 } catch (const std::exception &e) {
196  std::cerr << e.what() << "\n";
197  throw std::runtime_error("Problem in DualGroup constructor.");
198 }
199 
200 
201 }
202 }
203 
204 
205 #endif
void get_pi(std::vector< double > &pi, int begin, int end) const
Get a range of dual values.
Definition: lp_interface.cpp:926
std::unordered_map< Sep::Clique, numtype > clique_pi
Dual values/multiplicities for Cliques.
Definition: dualgroup.hpp:52
Type
Enumeration for the types of HyperGraph inequalities.
Definition: hypergraph.hpp:65
Representing cuts outside the LP solver.
The external storage of a collection of HyperGraph cuts in a Relaxation.
Definition: hypergraph.hpp:126
std::vector< numtype > node_pi
Dual values for degree constraints.
Definition: dualgroup.hpp:47
std::shared_ptr< Clique > Ptr
shared_ptr alias declaration.
Definition: cliq.hpp:54
int size() const
The number of unique Cliques in the bank.
Definition: cliq.hpp:195
Interface to the LP solver.
const std::vector< Segment > & seg_list() const
A constant reference to the list of segments in the Clique.
Definition: cliq.hpp:60
std::vector< numtype > node_pi_est
Overestimates of node_pi.
Definition: dualgroup.hpp:48
int num_rows() const
Number of rows in the model.
Definition: lp_interface.cpp:346
std::vector< numtype > cut_pi
Dual values for cuts.
Definition: dualgroup.hpp:49
Storage of a repository of Cliques, for use in building a HyperGraph.
Definition: cliq.hpp:167
Class for storing segment lists representing edges of a hypergraph.
Definition: cliq.hpp:34
std::shared_ptr< Tooth > Ptr
Pointer alias declaration.
Definition: cliq.hpp:104
Class for storing an lp relaxation via interface to an lp solver.
Definition: lp_interface.hpp:33
External representation of a cut added to the lp relaxation.
Definition: hypergraph.hpp:31
The namespace for this project.
Definition: abc_nodesel.hpp:20
Class template for storing dual LP solutions.
Definition: dualgroup.hpp:25
DualGroup()=default
Construct an empty DualGroup.
Simple utility struct for storing an interval of nodes.
Definition: util.hpp:198