lpinterface
 All Classes Namespaces Files Functions Variables Enumerations Enumerator
data_objects.hpp
1 #ifndef LPINTERFACE_DATA_OBJECTS_H
2 #define LPINTERFACE_DATA_OBJECTS_H
3 
4 #include <algorithm>
5 #include <cmath>
6 #include <cstddef>
7 #include <set>
8 #include <type_traits>
9 #include <vector>
10 
11 #include "common.hpp"
12 #include "errors.hpp"
13 
14 namespace lpint {
15 
16 // matrix entry is templated over T, with T restricted to
17 // arithmetic types i.e. numbers
27 template <typename T>
28 class MatrixEntry {
29  static_assert(std::is_arithmetic<T>::value,
30  "MatrixEntry<T> requires T to be arithmetic");
31 
32  private:
33  using iterator = typename std::vector<T>::iterator;
34  using const_iterator = typename std::vector<T>::const_iterator;
35 
36  public:
37  using Index = int;
38  using SizeType = std::size_t;
39 
40  using iterator_category = std::forward_iterator_tag;
41  using value_type = T;
42  using difference_type = int;
43  using pointer = value_type*;
44  using reference = value_type&;
45 
46  MatrixEntry() = default;
47  MatrixEntry(MatrixEntry<T>&&) = default;
48  MatrixEntry(const MatrixEntry<T>&) = delete;
49  MatrixEntry<T>& operator=(const MatrixEntry<T>&) = delete;
50  MatrixEntry<T>& operator=(MatrixEntry<T>&&) = default;
51 
52  explicit MatrixEntry(const std::size_t size)
53  : values_(size), nonzero_indices_(size) {}
54 
55  MatrixEntry(const std::vector<T>& values, const std::vector<Index>& indices)
56  : values_(values), nonzero_indices_(indices) {
57  if (values_.size() != nonzero_indices_.size()) {
59  }
60  check_entry_valid();
61  }
62  virtual ~MatrixEntry() = default;
63 
71  T operator[](const SizeType index) const {
72  auto index_in_data =
73  std::find(nonzero_indices_.begin(), nonzero_indices_.end(), index);
74  if (index_in_data == nonzero_indices_.end()) {
75  return T();
76  } else {
77 #if NDEBUG
78  return values_[static_cast<SizeType>(index_in_data -
79  nonzero_indices_.begin())];
80 #else
81  return values_.at(
82  static_cast<SizeType>(index_in_data - nonzero_indices_.begin()));
83 #endif
84  }
85  }
86 
88  T lower_bound() const {
89  return std::min_element(values_.begin(), values_.end());
90  }
91 
93  T upper_bound() const {
94  return std::max_element(values_.begin(), values_.end());
95  }
96 
98  typename std::vector<T>::size_type num_nonzero() const {
99  return values_.size();
100  }
101 
103  const std::vector<T>& values() const { return values_; }
104 
106  std::vector<T>& values() { return values_; }
107 
109  const std::vector<Index>& nonzero_indices() const { return nonzero_indices_; }
110 
112  std::vector<Index>& nonzero_indices() { return nonzero_indices_; }
113 
116  iterator begin() { return values_.begin(); }
117 
119  const_iterator begin() const { return values_.begin(); }
120 
122  iterator end() { return values_.end(); }
123 
125  const_iterator end() const { return values_.end(); }
126 
127  private:
128  std::vector<T> values_;
129  std::vector<Index> nonzero_indices_; // indices of nonzero entries
130 
131  void check_entry_valid() {
132  // matrix entries are invalid if there are
133  // duplicate nonzero indices present
134  std::set<Index> index_set(nonzero_indices_.begin(), nonzero_indices_.end());
135  if (nonzero_indices_.size() != index_set.size()) {
137  }
138  }
139 };
140 
141 // TODO: fix this for the case that left and right are non-equal permutations
142 // of each other, e.g. left == Entry {[1, 2] [0, 1]}, right == Entry {[2, 1],
143 // [0, 1]}. This example currently incorrectly evaluates as equal.
144 template <class T>
145 bool operator==(const MatrixEntry<T>& left, const MatrixEntry<T>& right) {
146  return std::is_permutation(left.nonzero_indices().begin(),
147  left.nonzero_indices().end(),
148  right.nonzero_indices().begin()) &&
149  std::is_permutation(left.values().begin(), left.values().end(),
150  right.values().begin());
151 }
152 
153 template <typename T>
154 class Column : public MatrixEntry<T> {
155  public:
156  using Index = typename MatrixEntry<T>::Index;
157  using SizeType = typename MatrixEntry<T>::SizeType;
158 
159  public:
160  explicit Column(const std::size_t size) : MatrixEntry<T>(size) {}
161  Column() = default;
162  Column(const std::vector<T>& values, const std::vector<Index>& indices)
163  : MatrixEntry<T>(values, indices) {}
164  explicit Column(MatrixEntry<T>&& m) : MatrixEntry<T>(std::move(m)) {}
165 };
166 
167 template <typename T>
168 class Row : public MatrixEntry<T> {
169  public:
170  using Index = typename MatrixEntry<T>::Index;
171  using SizeType = typename MatrixEntry<T>::SizeType;
172 
173  public:
174  explicit Row(const std::size_t size) : MatrixEntry<T>(size) {}
175  Row() = default;
176  Row(const std::vector<T>& values, const std::vector<Index>& indices)
177  : MatrixEntry<T>(values, indices) {}
178  explicit Row(MatrixEntry<T>&& m) : MatrixEntry<T>(std::move(m)) {}
179 };
180 
191 template <typename T>
192 struct Constraint {
193  static_assert(std::is_arithmetic<T>::value,
194  "T must be arithmetic in order to be ordered");
195  Constraint() : row(), lower_bound(), upper_bound() {}
196  Constraint(Row<T>&& r, T lb, T ub)
197  : row(std::move(r)), lower_bound(lb), upper_bound(ub) {}
198 
199  Row<T> row;
204 };
205 
206 template <class T>
207 bool operator==(const Constraint<T>& left, const Constraint<T>& right) {
208  return fabs(left.upper_bound - right.upper_bound) < DOUBLE_TOLERANCE &&
209  fabs(left.lower_bound - right.lower_bound) < DOUBLE_TOLERANCE &&
210  left.row == right.row;
211 }
212 
222 template <typename T>
223 struct Objective {
224  Objective() = default;
225  // We can leave variable_types empty, since
226  // Gurobi assumes continuous variables by default.
227  // This might be different in other solvers, so
228  // we'll have to carefully check when adding support.
229  explicit Objective(std::vector<T>&& vals) : values(std::move(vals)) {}
231  std::vector<T> values;
232 };
233 
234 template <class T>
235 bool operator==(const Objective<T>& left, const Objective<T>& right) {
236  return left.values == right.values;
237 }
238 
253 class Variable {
254  public:
258  Variable() = default;
265  Variable(double lb, double ub) : lower_bound_(lb), upper_bound_(ub)
266  {
267  if (lb > ub) {
269  }
270  }
271 
273  double upper() const { return upper_bound_; }
275  double lower() const { return lower_bound_; }
276 
277  private:
278  double lower_bound_ = 0.0;
279  double upper_bound_ = LPINT_INFINITY;
280 };
281 
282 inline bool operator==(const Variable& left, const Variable& right) {
283  return left.lower() == right.lower() && left.upper() == right.upper();
284 }
285 
286 inline std::ostream& operator<<(std::ostream& os, const Variable& var) {
287  os << "Variable { lower = " << var.lower() << ", upper = " << var.upper()
288  << " }";
289  return os;
290 }
291 
297 template <typename T>
298 struct Solution {
300  std::vector<T> primal;
302  std::vector<T> dual;
305 };
306 
307 // LCOV_EXCL_START
308 template <typename T>
309 inline std::ostream& operator<<(std::ostream& os,
310  const Constraint<T>& constraint) {
311  os << constraint.lower_bound << " <= " << constraint.row
312  << " <= " << constraint.upper_bound;
313  return os;
314 }
315 
316 template <typename T>
317 inline std::ostream& operator<<(std::ostream& os, const Objective<T>& obj) {
318  if (obj.values.size() == 0) {
319  os << "Objective {}";
320  return os;
321  }
322  os << "Objective {";
323  std::size_t n = obj.values.size();
324  for (std::size_t i = 0; i < n; i++) {
325  os << obj.values[i] << ", ";
326  }
327  os << "\b\b}";
328  return os;
329 }
330 
331 template <typename T>
332 inline std::ostream& operator<<(std::ostream& os, const MatrixEntry<T>& row) {
333  if (row.num_nonzero() == 0) {
334  os << "Entry {[] []}";
335  return os;
336  }
337  os << "Entry {[";
338  for (const auto& val : row.values()) {
339  os << val << " ";
340  }
341  os << "\b] [";
342  for (const auto& val : row.nonzero_indices()) {
343  os << val << " ";
344  }
345  os << "\b]}";
346  return os;
347 }
348 // LCOV_EXCL_STOP
349 
350 } // namespace lpint
351 
352 #endif // LPINTERFACE_DATA_OBJECTS_H
const std::vector< T > & values() const
Get a const reference to the underlying value array.
Definition: data_objects.hpp:103
Struct to represent right-hand side of LP constraints. In linear programming, we have constraints of ...
Definition: data_objects.hpp:192
Attempt to construct a variable with invalid bounds.
Definition: errors.hpp:70
Definition: data_objects.hpp:168
const std::vector< Index > & nonzero_indices() const
Get a const reference to the underlying nonzero indices.
Definition: data_objects.hpp:109
std::vector< T > & values()
Get a reference to the underlying value array.
Definition: data_objects.hpp:106
iterator begin()
Definition: data_objects.hpp:116
constexpr double LPINT_INFINITY
Constant representing floating point infinity.
Definition: common.hpp:10
const_iterator end() const
Obtain a const iterator to the end of the underlying value array.
Definition: data_objects.hpp:125
std::vector< Index > & nonzero_indices()
Get a reference to the underlying nonzero indices.
Definition: data_objects.hpp:112
double upper() const
Retrieve the upper bound of this variable.
Definition: data_objects.hpp:273
Definition: data_objects.hpp:154
Attempt to add a matrix entry containing duplicate indices.
Definition: errors.hpp:54
Definition: errors.hpp:122
Variable()=default
Construct a non-negative variable.
const_iterator begin() const
Obtain a const iterator to the begin of the underlying value array.
Definition: data_objects.hpp:119
T objective_value
Value of the objective .
Definition: data_objects.hpp:304
std::vector< T >::size_type num_nonzero() const
Return the number of nonzero entries in the matrix entry.
Definition: data_objects.hpp:98
T operator[](const SizeType index) const
Indexing operator; can be used identically to a dense vector. Will perform bounds checking ifndef NDE...
Definition: data_objects.hpp:71
Matrix entry type, for use in sparse matrix. The matrix entry base class is specialized as Row and Co...
Definition: data_objects.hpp:28
T upper_bound() const
Returns the largest entry of this matrix element.
Definition: data_objects.hpp:93
double lower() const
Retrieve the lower bound of this variable.
Definition: data_objects.hpp:275
std::vector< T > dual
Values in the dual solution vector.
Definition: data_objects.hpp:302
Variable(double lb, double ub)
Construct a new Variable object.
Definition: data_objects.hpp:265
T lower_bound
Lower bound of constraint equation.
Definition: data_objects.hpp:201
Class representing a variable in the LP.
Definition: data_objects.hpp:253
Struct representing the objective vector. A linear program has the canonical form This structure rep...
Definition: data_objects.hpp:223
iterator end()
Obtain an iterator to the end of the underlying value array.
Definition: data_objects.hpp:122
T upper_bound
Upper bound of constraint equation.
Definition: data_objects.hpp:203
std::vector< T > values
Values of elements in the objective vector.
Definition: data_objects.hpp:231
T lower_bound() const
Returns the smallest entry of this matrix element.
Definition: data_objects.hpp:88
Struct representing the solution of a linear program.
Definition: data_objects.hpp:298
std::vector< T > primal
Values in the primal solution vector.
Definition: data_objects.hpp:300