mCRL2
Loading...
Searching...
No Matches
MaxMeasureLiftingStrategy.cpp
Go to the documentation of this file.
1// Copyright (c) 2009-2013 University of Twente
2// Copyright (c) 2009-2013 Michael Weber <michaelw@cs.utwente.nl>
3// Copyright (c) 2009-2013 Maks Verver <maksverver@geocities.com>
4// Copyright (c) 2009-2013 Eindhoven University of Technology
5//
6// Distributed under the Boost Software License, Version 1.0.
7// (See accompanying file LICENSE_1_0.txt or copy at
8// http://www.boost.org/LICENSE_1_0.txt)
9
11
12/* TODO: write short description of how this works! */
13
15 const ParityGame &game, const SmallProgressMeasures &spm,
16 Order order, Metric metric )
17 : LiftingStrategy2(), spm_(spm), order_(order), metric_(metric),
18 next_id_(0),
19 insert_id_(order < HEAP ? new uint64_t[game.graph().V()] : 0),
20 pq_pos_(new verti[game.graph().V()]),
21 pq_(new verti[game.graph().V()]), pq_size_(0)
22{
23 std::fill(&pq_pos_[0], &pq_pos_[game.graph().V()], NO_VERTEX);
24}
25
27{
28 // FIXME: this can be implemented with less swapping if I think harder.
29 for (verti j; i > 0 && cmp(i, j = (i - 1)/2) > 0; i = j) swap(i, j);
30}
31
33{
34 // FIXME: this can be implemented with less swapping if I think harder.
35 for (;;)
36 {
37 verti j = 2*i + 1;
38 verti k = 2*i + 2;
39 int d = j < pq_size_ ? cmp(i, j) : 1;
40 int e = k < pq_size_ ? cmp(i, k) : 1;
41
42 if (d < 0 && e < 0)
43 {
44 // both children are larger than current node
45 if (cmp(j, k) >= 0)
46 {
47 // left child is largest
48 swap(i, j);
49 i = j;
50 }
51 else
52 {
53 // right child is largest;
54 swap(i, k);
55 i = k;
56 }
57 }
58 else
59 if (d < 0)
60 {
61 // left child is larger
62 swap(i, j);
63 i = j;
64 }
65 else
66 if (e < 0)
67 {
68 // right child is larger
69 swap(i, k);
70 i = k;
71 }
72 else
73 {
74 // both children are smaller; we're done
75 break;
76 }
77 }
78}
79
81{
82 verti v = pq_[i], w = pq_[j];
83 pq_[i] = w;
84 pq_[j] = v;
85 pq_pos_[w] = i;
86 pq_pos_[v] = j;
87}
88
90{
91 mCRL2log(mcrl2::log::debug) <<"push(" << v << ")" << std::endl;
92 assert(pq_pos_[v] == NO_VERTEX);
93 pq_[pq_size_] = v;
94 pq_pos_[v] = pq_size_;
95 ++pq_size_;
96 if (insert_id_) insert_id_[v] = next_id_++;
97 bumped_.push_back(pq_pos_[v]);
98}
99
101{
102 mCRL2log(mcrl2::log::debug) << "bump(" << v << ")" << std::endl;
103 bumped_.push_back(pq_pos_[v]);
104}
105
107{
108#ifdef DEBUG
109 static long long ops;
110 ops += bumped_.size() + 1;
111#endif
112
113 if (!bumped_.empty())
114 {
115 // Move bumped vertices up the heap.
116 std::sort(bumped_.begin(), bumped_.end());
117 bumped_.erase( std::unique(bumped_.begin(), bumped_.end()),
118 bumped_.end() );
119 for (std::vector<verti>::iterator it = bumped_.begin();
120 it != bumped_.end(); ++it) move_up(*it);
121
122 // CHECKME: why is this necessary for MAX_STEP too?
123 // shouldn't this just be for MIN_STEP?
124 if (metric_ != MAX_VALUE)
125 {
126 /* Note: minimization is a bit trickier than maximization, since
127 we need to move bumped vertices down the heap (rather than up
128 when maximizing) but pushed vertices still need to move up.
129
130 Unfortunately, we can't easily distinguish between bumped or
131 pushed or pushed-and-then-bumped vertices, so the easiest safe
132 way to handle the situation is to move up first, and then down.
133
134 FIXME: optimize this?
135 */
136
137 // Move bumped vertices down the heap.
138 for (std::vector<verti>::reverse_iterator it = bumped_.rbegin();
139 it != bumped_.rend(); ++it) move_down(*it);
140 }
141 bumped_.clear();
142 }
143
144 if (pq_size_ == 0) return NO_VERTEX;
145
146#ifdef DEBUG
147 if (ops >= pq_size_)
148 {
149 Logger::debug("checking heap integrity");
150 assert(check());
151 ops -= pq_size_;
152 }
153#endif
154
155 // Extract top element from the heap.
156 verti v = pq_[0];
157 mCRL2log(mcrl2::log::debug) << "pop() -> " << v << std::endl;
158 pq_pos_[v] = NO_VERTEX;
159 if (--pq_size_ > 0)
160 {
161 pq_[0] = pq_[pq_size_];
162 pq_pos_[pq_[0]] = 0;
163 move_down(0);
164 }
165 return v;
166}
167
168static int cmp_ids(uint64_t x, uint64_t y)
169{
170 return (x > y) - (x < y);
171}
172
173/* This returns +1 if lifting v1 to v2 would increase the progress measure
174 by a larger difference than lifting w1 to w2.
175
176 Assumes v1 >= v2 and w1 >= w2 (for the first v_len and w_len elements
177 respectively) and that all vectors are within bounds. (If they are not,
178 the results are still somewhat sensible, but it may be possible that two
179 vectors compare unequal even though their steps are equally large.)
180*/
181static int cmp_step( const verti *v1, const verti *v2, int v_len, bool v_carry,
182 const verti *w1, const verti *w2, int w_len, bool w_carry )
183{
184 for (int i = 0; i < v_len || i < w_len; ++i)
185 {
186 int a = i < v_len ? v2[i] - v1[i] : 0;
187 int b = i < w_len ? w2[i] - w1[i] : 0;
188 if (a != b) return (a > b) - (a < b);
189 }
190 if (v_carry || w_carry)
191 {
192 if (!w_carry) return +1;
193 if (!v_carry) return -1;
194 if (v_len < w_len) return +1;
195 if (v_len > w_len) return -1;
196 }
197 return 0;
198}
199
201{
202 verti v = pq_[i], w = pq_[j];
203 int d = 0;
204
205 switch (metric_)
206 {
207 case MAX_VALUE:
210 break;
211
212 case MIN_VALUE:
215 break;
216
217 case MAX_STEP:
218#ifdef DEBUG
219 // We assume vertices are only queued when they can be lifted;
220 // i.e. their value is less than (or equal to) their successor:
221 assert(spm_.vector_cmp(v, spm_.get_successor(v), spm_.len(v))
222 < spm_.compare_strict(v));
223 assert(spm_.vector_cmp(w, spm_.get_successor(w), spm_.len(w))
224 < spm_.compare_strict(w));
225#endif
229 spm_.len(w), spm_.compare_strict(w) );
230 break;
231 }
232
233 if (d == 0)
234 {
235 // Tie-break on insertion order: smallest insert-id first in queue
236 // mode, or largest insert-id first in stack mode.
237 switch (order_)
238 {
239 case QUEUE: d = cmp_ids(insert_id_[w], insert_id_[v]); break;
240 case STACK: d = cmp_ids(insert_id_[v], insert_id_[w]); break;
241 default: break;
242 }
243 }
244
245 return d;
246}
247
249{
250 for (verti i = 1; i < pq_size_; ++i)
251 {
252 if (cmp(i, (i - 1)/2) > 0) return false;
253 }
254
255 for (verti i = 0; i < pq_size_; ++i)
256 {
257 if (pq_pos_[pq_[i]] != i) return false;
258 }
259
260 const verti V = spm_.game().graph().V();
261 for (verti v = 0; v < V; ++v)
262 {
263 if (pq_pos_[v] != NO_VERTEX)
264 {
265 if (pq_[pq_pos_[v]] != v) return false;
266 }
267 }
268
269 return true;
270}
271
273{
274 return version == 2;
275}
276
278 const ParityGame& /*game*/, const SmallProgressMeasures &/*spm*/ )
279{
280 return nullptr;
281}
282
284 const ParityGame &game, const SmallProgressMeasures &spm )
285{
286 return new MaxMeasureLiftingStrategy2(game, spm, order_, metric_);
287}
std::size_t verti
type used to number vertices
Definition Graph.h:24
#define NO_VERTEX
Definition Graph.h:27
static int cmp_step(const verti *v1, const verti *v2, int v_len, bool v_carry, const verti *w1, const verti *w2, int w_len, bool w_carry)
static int cmp_ids(uint64_t x, uint64_t y)
const std::unique_ptr< verti[]> pq_pos_
for each vertex: position in the p.q. or -1
std::unique_ptr< uint64_t[]> insert_id_
for each vertex: last insertion time
const Order order_
vertex extraction order
const std::unique_ptr< verti[]> pq_
priority queue of lifted vertices
const SmallProgressMeasures & spm_
SPM instance being solved.
uint64_t next_id_
number of insertions
MaxMeasureLiftingStrategy2(const ParityGame &game, const SmallProgressMeasures &spm, Order order, Metric metric)
verti pq_size_
priority queue size
const Metric metric_
comparison metric
const MaxMeasureLiftingStrategy2::Order order_
const MaxMeasureLiftingStrategy2::Metric metric_
LiftingStrategy * create(const ParityGame &, const SmallProgressMeasures &)
LiftingStrategy2 * create2(const ParityGame &game, const SmallProgressMeasures &spm)
const StaticGraph & graph() const
Definition ParityGame.h:256
std::size_t len_
length of SPM vectors
bool compare_strict(verti v) const
const ParityGame & game() const
verti get_successor(verti v) const
int vector_cmp(const verti vec1[], const verti vec2[], int N) const
virtual const verti * vec(verti v) const =0
verti V() const
Definition Graph.h:179
#define mCRL2log(LEVEL)
mCRL2log(LEVEL) provides the stream used to log.
Definition logger.h:391