-
Notifications
You must be signed in to change notification settings - Fork 0
/
skeleton.hpp
402 lines (307 loc) · 11.6 KB
/
skeleton.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
#ifndef SKELETON_H
#define SKELETON_H
/*****************************************************************************\
* This file is part of DynGB. *
* *
* DynGB is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 2 of the License, or *
* (at your option) any later version. *
* *
* DynGB is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with DynGB. If not, see <http://www.gnu.org/licenses/>. *
\*****************************************************************************/
/**
@brief implementation of classes for double description method
@author John Perry
\version 1.0
@date October 2014
@copyright The University of Southern Mississippi
@ingroup CLSSolvers
*/
#include <set>
#include <vector>
#include <iostream>
using std::cout; using std::endl;
#include "lp_solver.hpp"
#include "polynomial.hpp"
#include "system_constants.hpp"
namespace LP_Solvers {
/**
@brief an edge @f$(r_1,r_2)@f$ connecting the two rays @f$ r_1 @f$ and @f$ r_2 @f$
@author John Perry
\version 1.0
@date October 2014
@copyright The University of Southern Mississippi
@ingroup CLSSolvers
@details This class encapsulates an edge, the other major part of a skeleton.
Edges describe how the rays of the skeleton are connected.
Edges are ordered, so that the smaller ray always comes first.
@warning An edge's rays should have the same dimension.
To start with, it doesn't make mathematical sense to “join”
two rays of different dimension.
Moreover, comparison of edges requires comparison of rays,which requires
that the rays have the same dimension.
(But you wouldn't be dumb enough to do this in the first place.)
*/
class Edge {
public:
/** @name Construction */
///@{
/** @brief Creates a new edge that joins the two rays. */
Edge(const Ray &, const Ray &);
/** @brief Copies the rays in @c other to two new rays. */
Edge(const Edge &);
///@}
/** @name Destruction */
///@{
~Edge() {} /**< Does nothing beyond what the compiler would do. */
///@}
/** @name Basic properties */
///@{
/** @brief Returns the first ray listed in this edge. */
inline Ray get_first_ray() const { return first; };
/** @brief Returns the second ray listed in this edge. */
inline Ray get_second_ray() const { return second; };
///@}
/** @name Comparison */
///@{
friend bool operator==(const Edge & e1, const Edge & e2);
friend bool operator<(const Edge & e1, const Edge & e2);
///@}
/** @name I/O */
///@{
friend ostream & operator<<(ostream &ostr, const Edge &e);
///@}
/** @name Modification */
///@{
/** @brief Assignment operator */
Edge & operator=(const Edge &);
///@}
private:
Ray first, second; /**< the rays defining this edge */
};
/**
@brief Equal if and only if.
@param e1 an edge
@param e2 an edge
@return @c true if and only if the edges have identical entries
*/
bool operator==(const Edge &e1, const Edge &e2);
/**
@brief Compares two edges lexicographically.
@details If the first ray in @c this edge is smaller,
then @c this edge is smaller.
Otherwise, if the first rays are equal, and the second ray in @c this edge
is smaller, then @c this edge is smaller.
@return @c true if and only if the first edge is lexicographically smaller
@param e1 an edge
@param e2 an edge
*/
bool operator<(const Edge & e1, const Edge & e2);
///@}
/**
@brief Output has the form @f$ \{ \mathbf{r}_1, \mathbf{r}_2 \} @f$
where @f$ \mathbf{r}_1 @f$ is the first ray in this edge, etc.
@param ostr output stream to write to
@param e edge to write
@return the output stream
*/
ostream & operator<<(ostream &ostr, const Edge &e);
/**
\ingroup CLSSolvers
@brief counts the number of constraints active in both sets
@return the number of constraints common to both sets.
*/
int number_of_common_constraints(bool *, bool *, unsigned);
/**
\ingroup CLSSolvers
@brief indicates which constraints are active for both sets
@return the intersection between the given sets of constraints.
*/
vector<bool> intersections_of_active_constraints(bool *, bool *, unsigned);
/**
\ingroup CLSSolvers
@brief indicates which constraints are active for both sets
@param a first set
@param b second set
@param result set where @c true occurs only if it does in both @p a and @p b
@param m number of entries in @p a and @p b
@return the intersection between the given sets of constraints.
*/
void intersections_of_active_constraints(
bool * a, bool * b, bool * result, unsigned m
);
/**
\ingroup CLSSolvers
@brief determines whether the first set of active constraints is a subset
of the second
@return @c true if and only if the first set is a subset of the second.
*/
bool is_first_subset_of_second(bool *, bool *, unsigned);
/**
\ingroup CLSSolvers
@brief computes the union of the specified edge sets
@return union of the specified edge sets
*/
set<Edge> union_of_edge_sets(const set<Edge> &, const set<Edge> &);
/**
@brief skeleton of a polyhedral cone, with methods allowing definition and refinement
@author John Perry
\version 1.1
@date October 2014
@copyright The University of Southern Mississippi
@ingroup CLSSolvers
@details This class implements the Double Description Method,
an iterative algorithm for computing the skeleton of a cone.
This particular version uses Zolotykh's GraphAdj criterion
@cite Zolotych_DoubleDescription.
The iterative nature means that the cone can be updated with new constraints,
passed to that algorithm, and the skeleton will be automatically recomputed.
*/
class Skeleton : public LP_Solver {
public:
/** @name Construction */
///@{
/** @brief Initialization common to all constructors */
void common_initialization(NVAR_TYPE);
/**
@brief Constructs a basic skeleton in the given number of dimensions,
initialized to the axes, or (equivalently) to the set of constraints
@f$ x_i \geq 0 @f$.
The rays are informed of their active constraints.
@pre the argument should be at least two
@post the skeleton of the positive orthant
*/
explicit Skeleton(NVAR_TYPE);
/**
@brief Constructs a skeleton described by the given system of constraints.
Practically speaking, it first generates a basic skeleton,
then iterates on the given constraints.
@pre `u.size() == v.size()` for all `u`, `v` in the vector
@post unless the system supplied was inconsistent, a valid skeleton of the
corresponding polyhedral cone
@warning Your program will almost certainly fail
if you do not respect the precondition.
*/
Skeleton(NVAR_TYPE, const vector<Constraint> &);
/** @brief Performs a deep copy of `other`. */
explicit Skeleton(const Skeleton &);
virtual bool copy(const LP_Solver *) override;
///@}
/** @name Destruction */
///@{
/**
@brief Currently does nothing the compiler wouldn't do.
*/
virtual ~Skeleton();
///@}
/** @name Basic properties */
///@{
inline NVAR_TYPE get_dimension() const override { return dim; };
/** @brief Returns the number of edges defining the skeleton. */
inline unsigned long get_number_of_edges() { return edges.size(); };
/** @brief Returns the edges that define the skeleton. */
inline set<Edge> get_edges() { return edges; };
/** @brief Returns the number of constraints defining the skeleton. */
inline unsigned long get_number_of_constraints() const override {
return constraints.size();
};
/** @brief Returns the constraints that define the skeleton. */
inline const vector<Constraint> & get_constraints() {
return constraints;
};
/** @brief Returns the indicated constraint. Numbering starts at 0. */
inline const Constraint & get_constraint(int index) {
return constraints[index];
};
///@}
/** @name Computation */
///@{
/** @brief returns the set of constraints in the skeleton active at @c u */
//inline vector<bool> which_constraints_active_at(const Ray & u) const {
inline void which_constraints_active_at(const Ray & u, bool * result) const {
for (unsigned i = 0; i < constraints.size(); ++i) {
if (u.is_active_at(constraints[i]))
result[i] = true;
else
result[i] = false;
}
}
/** @brief tests for consistency of a potentially new constraint. */
inline bool is_consistent(const Constraint & c) const {
bool inconsistent = true;
for (
auto riter = rays.begin();
inconsistent and riter != rays.end();
++riter
) {
if (((*riter) * c) > 0)
inconsistent = false;
}
return not inconsistent;
}
///@}
/** @name Modification */
///@{
/**
@brief Adds the indicated constraints (plural!) and re-computes the skeleton.
\return `true` if and only if the new constraints are consistent with the
current constraints
@warning Checking the return value is crucial!
If the function returns @c false, you have an inconsistent system!
While the <i>present</i> cone will remain consistent,
<b>the function will not roll back previous changes you have made</b>,
so if you want to iterate again,
your best bet is to copy the skeleton, and try that copy.
Accept the new constraints only if that copy succeeds,
in which case, you might as well discard the original, and keep the copy.
*/
virtual bool solve(const vector<Constraint> &) override;
/**
@brief Adds the indicated constraint (singular!) and re-computes the skeleton.
\return `true` if and only if the new constraint is consistent with the
current constraints
@warning Checking the return value is crucial!
If the function returns `false`, you have an inconsistent system!
While the <i>present</i> cone will remain consistent,
<b>the function will not roll back previous changes you have made</b>,
so if you want to iterate again,
your best bet is to copy the skeleton, and try that copy.
Accept the new constraints only if that copy succeeds,
in which case, you might as well discard the original, and keep the copy.
*/
virtual bool solve(const Constraint &) override;
/**
@brief Re-computes the edges in the skeleton
using Zolotych's `GraphAdj` algorithm and returns the result.
*/
set<Edge> adjacencies_by_graphs(const set<Ray> &);
/**
@brief Assignment operator; empties current set & copies from other.
*/
Skeleton & operator=(const Skeleton &);
///@}
/** @name I/O */
///@{
friend ostream & operator<<(ostream & os, const Skeleton & s);
///@}
private:
int dim; /**< dimension of skeleton */
set<Edge> edges; /**< edges defining skeleton */
vector<Constraint> constraints; /**< constraints defining skeleton */
};
/**
@brief prints out the constraints, then the rays, then the edges of @p s.
@param os output stream to print to
@param s skeleton to print
@return the output stream
*/
ostream & operator<<(ostream & os, const Skeleton & s);
}
#endif