-
Notifications
You must be signed in to change notification settings - Fork 0
/
skeleton.cpp
492 lines (462 loc) · 15.3 KB
/
skeleton.cpp
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
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
/**
\brief implementation of classes for double description method
\author John Perry
\version 1.0
\date October 2014
@copyright The University of Southern Mississippi
*/
/*****************************************************************************\
* 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/>. *
\*****************************************************************************/
#ifndef SKELETON_C
#define SKELETON_C
#include <iostream>
#include <cstdlib>
#include <algorithm>
using std::set_union;
#include "system_constants.hpp"
//#include "goda.hpp"
#include "skeleton.hpp"
namespace LP_Solvers {
Edge::Edge(const Ray &first_ray, const Ray &second_ray)
: first(first_ray), second(second_ray)
{
if (first < second)
first.swap(second);
}
Edge::Edge(const Edge &old_edge)
: first(old_edge.first), second(old_edge.second)
{
// nothing to do
}
ostream & operator<<(ostream & ostr, const Edge &e)
{
ostr << "{ " << e.first << " , " << e.second << " }";
return ostr;
}
bool operator==(const Edge &e1, const Edge &e2)
{ return e1.first == e2.first && e1.second == e2.second; }
bool operator < (const Edge &first, const Edge &second)
{
bool result = true;
if (first.first < second.first)
{
// do nothing
}
else if (second.first < first.first)
result = false;
else // first entries equal; look at second
if (first.second < second.second)
{
// do nothing
}
else
result = false;
return result;
}
Edge & Edge::operator=(const Edge &other)
{
if (!(*this == other))
{
first = other.first;
second = other.second;
}
return *this;
}
void Skeleton::common_initialization(NVAR_TYPE dimension)
{
//cout << "creating skeleton with dimension " << dimension << endl;
dim = dimension;
// initialize the constraints
CONSTR_TYPE * constr_coords = new CONSTR_TYPE[dim];
for (NVAR_TYPE i = 0; i < dim; ++i) constr_coords[i] = 0;
// add the constraint xi >= 0 for each i = 0, ..., dim - 1
for (NVAR_TYPE i = 0; i < dim; ++i)
{
constr_coords[i] = 1;
constraints.push_back(Constraint(dim, constr_coords));
constr_coords[i] = 0;
}
delete [] constr_coords;
// initialize the rays, one for each axis
for (NVAR_TYPE i = 0; i < dim; ++i)
{
Ray new_ray(dim, i);
rays.insert(new_ray);
}
// initialize the edges
// currently, all the rays are adjacent
for (auto riter = rays.begin(); riter != rays.end(); ++riter)
for (auto siter = rays.begin(); siter != rays.end(); ++siter)
if (*riter != *siter)
{
Edge new_edge(*riter, *siter);
edges.insert(new_edge);
}
}
Skeleton::Skeleton(NVAR_TYPE dimension)
{
common_initialization(dimension);
}
Skeleton::Skeleton(NVAR_TYPE dimension, const vector<Constraint> &constraints)
//: Skeleton(dimension)
{
common_initialization(dimension);
solve(constraints);
}
Skeleton::Skeleton(const Skeleton &old_skeleton)
: constraints(old_skeleton.constraints),
edges(old_skeleton.edges), dim(old_skeleton.dim)
{
rays = old_skeleton.rays;
// nothing more to do
}
bool Skeleton::copy(const LP_Solver * other) {
const Skeleton * old_skeleton = dynamic_cast<const Skeleton *>(other);
if (old_skeleton != nullptr) {
constraints.clear(); rays.clear(); edges.clear();
for (const Constraint & c : old_skeleton->constraints)
constraints.push_back(c);
for (const Ray & r : old_skeleton->rays)
rays.emplace(r);
for (const Edge & e : old_skeleton->edges)
edges.emplace(e);
/*constraints = old_skeleton->constraints;
rays = old_skeleton->rays;
edges = old_skeleton->edges;*/
dim = old_skeleton->dim;
}
return (old_skeleton != nullptr);
}
Skeleton::~Skeleton()
{
}
bool Skeleton::solve(const Constraint &constraint)
{
// cout << "processing constraint " << constraint << endl;
// innocent until proven guilty
bool consistent = true;
// sort the rays into the ones above, below, or on the constraint
set<Ray> rays_above, rays_below, rays_on;
for (auto riter = rays.begin(); riter != rays.end(); ++riter)
{
DOTPROD_TYPE dp = (*riter) * constraint; // overloaded * as dot product :-)
if (dp > 0)
{
rays_above.insert(*riter);
// cout << *riter << " is above constraint\n";
}
else if (dp < 0)
{
rays_below.insert(*riter);
// cout << *riter << " is below constraint\n";
}
else
{
Ray old_ray = *riter;
rays_on.insert(old_ray);
// cout << *riter << " is on constraint\n";
}
}
// cout << rays_above.size() << " rays above; " << rays_below.size() << " rays below; " << rays_on.size() << " rays on\n";
// check for constitency
if (rays_above.size() == 0)
{
consistent = false;
//cout << "long test inconsistent\n";
}
// proceed only if constraint is consistent, and *not* redundant;
// redundancy can be checked by making sure
// that at least one ray is below the constraint
if (consistent and rays_below.size() != 0)
{
set<Edge> edges_above, edges_on;
for (auto eiter = edges.begin(); eiter != edges.end(); ++eiter)
{
Edge e = *eiter;
Ray u = e.get_first_ray();
Ray v = e.get_second_ray();
//cout << "edge " << u << ',' << v << endl;
// identify the edges that lie above and on this constraint
if ((u*constraint >= 0) and (v*constraint >= 0))
{
// cout << "old edge preserved: " << u << ',' << v << "\n";
edges_above.insert(e);
}
}
for (auto eiter = edges.begin(); eiter != edges.end(); ++eiter)
{
Edge e = *eiter;
Ray u = e.get_first_ray();
Ray v = e.get_second_ray();
DOTPROD_TYPE a = u*constraint;
DOTPROD_TYPE b = v*constraint;
// identify edges that pass through the constraint
// (one ray above, one ray below)
if (a > 0 and b < 0)
{
Ray w = a*v - b*u;
w.simplify_ray();
rays_on.insert(w);
edges_on.insert(Edge(u,w));
// cout << "new ray (u,v) is " << w << " with constraints " << endl;
}
else if (b > 0 and a < 0)
{
Ray w = b*u - a*v;
w.simplify_ray();
rays_on.insert(w);
edges_on.insert(Edge(v,w));
// cout << "new ray (v,u) is " << w << " with constraints " << endl;
}
}
// clear the old rays, add the new ones (above and on the constraint)
rays.clear();
for (auto riter = rays_above.begin(); riter != rays_above.end(); ++riter)
{
rays.insert(*riter);
}
// cout << "inserted rays above; rays on is\n";
// for (auto riter = rays_on.begin(); riter != rays_on.end(); ++riter) { cout << '\t' << *riter << endl; }
for (auto riter = rays_on.begin(); riter != rays_on.end(); ++riter)
{
// cout << "inserting " << *riter << endl;
//cout << "return value: " << *(get<0>(rays.insert(*riter)));
rays.insert(*riter);
//for (auto siter = rays.begin(); siter != rays.end(); ++siter) { cout << '\t' << *siter << endl; }
}
//cout << rays.size() << " rays\n";
// for (auto riter = rays.begin(); riter != rays.end(); ++riter) { cout << '\t' << *riter << endl; }
// add the good constraint
constraints.push_back(constraint);
// determine new edges
set<Edge> edges_new = adjacencies_by_graphs(rays_on);
// combine new edges with old ones that are known to be valid
edges = union_of_edge_sets(union_of_edge_sets(edges_above, edges_on), edges_new);
//cout << edges.size() << " edges\n";
//for (auto eiter = edges.begin(); eiter != edges.end(); ++eiter) { cout << *eiter << ' '; } cout << '\n';
}
return consistent;
}
bool Skeleton::solve(const vector<Constraint> &new_constraints)
{
// innocent until proven guilty
bool consistent = true;
//cout << "adding " << new_constraints.size() << "constraints\n";
//for (const constraint & c : new_constraints)
// cout << '\t' << c << endl;
// process each constraint sequentially
for (
auto nciter = new_constraints.begin();
consistent and nciter != new_constraints.end();
++nciter
)
{
// perform short test of consistency first
consistent = is_consistent(*nciter) and solve(*nciter);
//if (!consistent)
//{
// cout << "inconsistent\n";
// cout << "failed ray: " << *nciter;
// cout << "skeleton: \n" << *this;
//}
}
//cout << rays.size() << " corner vectors\n";
return consistent;
}
int number_of_common_constraints(
//vector<bool> &a, vector<bool> &b
bool * a, bool * b, unsigned m
)
{
int result = 0;
/*for (auto aiter = a.begin(); aiter != a.end(); ++aiter)
{
//cout << "checking " << *aiter << " in other: " << (b.find(*aiter) != b.end()) << endl;
if (b.find(*aiter) != b.end())
++result;
} */
for (unsigned i = 0; i < m; ++i)
if (a[i] and b[i]) ++result;
return result;
}
//vector<bool> intersections_of_active_constraints(
//vector<bool> &a, vector<bool> &b
void intersections_of_active_constraints(
bool * a, bool * b, bool * result, unsigned m
)
{
// highly unoptimized, but off the top of my head i don't know how to do better
//vector<bool> result(a.size());
/*for (auto aiter = a.begin(); aiter != a.end(); ++aiter)
if (b.find(*aiter) != b.end())
result.insert(*aiter);*/
for (unsigned i = 0; i < m; ++i)
result[i] = (a[i] and b[i]);
//return result;
}
bool is_first_subset_of_second(
//vector<bool> & a, vector<bool> & b
bool * a, bool * b, unsigned m
)
{
// highly unoptimized, but off the top of my head i don't know how to do better
bool result = true;
for (unsigned i = 0; result and i < m; ++i)
if (a[i]) result = b[i];
return result;
}
set<Edge> union_of_edge_sets(const set<Edge> & a, const set<Edge> & b)
{
// optimized with a hint for the position (riter) of the new element
set<Edge> result;
for (const Edge & e : a) result.insert(e);
for (const Edge & e : b) result.insert(e);
return result;
}
set<Edge> Skeleton::adjacencies_by_graphs(const set<Ray> & new_rays)
{
static unsigned long invocations;
set<Edge> new_edges;
set<Ray> tested_rays;
bool * Zu = new bool [constraints.size()] { false };
bool * Zv = new bool [constraints.size()] { false };
bool * w_active = new bool [constraints.size()] { false };
bool * Zuv = new bool [constraints.size()] { false };
// loop through each new ray, examining active constraints shared with other rays
for (auto riter = new_rays.begin(); riter != new_rays.end(); ++riter)
{
Ray u = *riter;
tested_rays.insert(u);
which_constraints_active_at(u, Zu);
// D's rays have at least dim - 2 active constraints in common with u
// (see Proposition 3 in Zolotych's paper)
set<Ray> D;
for (auto siter = new_rays.begin(); siter != new_rays.end(); ++siter)
if (*riter != *siter)
{
Ray v = *siter;
which_constraints_active_at(v, Zv);
//cout << "checking constraints of " << u << " against " << v << " for " << dim << endl;
//if (number_of_common_constraints(*Zu, *Zv) >= dim - 2)
if (number_of_common_constraints(Zu, Zv, constraints.size()) >= dim - 2)
{
//cout << "accept " << u << ',' << v << " from active constraints\n";
D.insert(v);
} else {
//cout << "reject " << u << ',' << v << " from active constraints\n";
}
}
// check u with each v in D, making sure their active constraints
// are not a subset of the active constraints of any w in D
// (see Proposition 4 (graph test) in Zolotych's paper)
unsigned ijk = 0;
for (auto diter = D.begin(); diter != D.end(); ++diter)
{
Ray v = *diter;
if (tested_rays.find(v) == tested_rays.end()) // avoid doubling edges
{
which_constraints_active_at(v, Zv);
// WARNING: I have commented out the following line, because it seems
// unnecessary: v is in D iff the size of the intersection is at least
// dim - 2. If there are unexpected bugs, this commenting should be
// reconsidered.
// if (intersections_of_active_constraints(Zu, Zv).size() >= dim - 2)
{
bool can_be_added = true;
intersections_of_active_constraints(Zu, Zv, Zuv, constraints.size());
for (
auto dditer = D.begin();
dditer != D.end() and can_be_added;
++dditer
)
{
Ray w = *dditer;
if (!(w == v)) {
which_constraints_active_at(w, w_active);
if (is_first_subset_of_second(Zuv, w_active, constraints.size()))
{
//cout << "rejecting " << u << ',' << v << " because of " << w << endl;
can_be_added = false;
}
}
}
if (can_be_added)
{
Edge new_edge(u, v);
//cout << "edge " << new_edge << " passes all criteria\n";
new_edges.insert(new_edge);
}
}
}
}
}
delete [] Zu;
delete [] Zv;
delete [] w_active;
delete [] Zuv;
return new_edges;
}
ostream & operator << (ostream & ostr, const Skeleton &skel)
{
// header, start constraints
ostr << "Skeleton defined by constraints" << endl;
for (
vector<Constraint>::const_iterator citer=skel.constraints.begin();
citer != skel.constraints.end();
++citer
)
ostr << '\t' << *citer << endl;
// rays
ostr << "has " << skel.rays.size() << " rays" << endl;
for (auto riter=skel.rays.begin(); riter != skel.rays.end(); ++riter)
ostr << '\t' << *riter << endl;
//edges
ostr << "connected in " << skel.edges.size() << " edges" << endl;
for (auto eiter=skel.edges.begin(); eiter != skel.edges.end(); ++eiter)
ostr << '\t' << *eiter << endl;
// footer
ostr << "End of skeleton" << endl;
return ostr;
}
Skeleton & Skeleton::operator=(const Skeleton & other)
{
rays.clear();
edges.clear();
constraints.clear();
dim = other.dim;
for (
auto siter = other.rays.begin();
siter != other.rays.end();
++siter
)
rays.insert(*siter);
for (
auto eiter = other.edges.begin();
eiter != other.edges.end();
++eiter
)
edges.insert(*eiter);
for (
vector<Constraint>::const_iterator citer = other.constraints.begin();
citer != other.constraints.end();
++citer
)
constraints.push_back(*citer);
return *this;
}
}
#endif