1 #ifndef _EXT_GRS_UF_MPQ_H_
2 #define _EXT_GRS_UF_MPQ_H_
5 * Project: libFIRM/extension module/GRS-matcher
6 * File name: ext/grs/uf_mpq.h
7 * Purpose: provides a union find structure (uf) (disjoint sets)
8 * and a meldable priority queue implementation (mpq)
9 * for pattern edges (note: in case of the uf edges are
10 * represented by their edge ids. This is because a
11 * disjoint integer set implementation is used.)
12 * @note The uf-concept used in this impl allows
13 * only elems greater than zero, but there are
14 * elems greater or EQUAL zero supported!
16 * Created: 7. June 2005
18 * Copyright: (c) 2005 Universität Karlsruhe
19 * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
33 #define MAX(a,b) ( (a)>=(b) ? (a) : (b) )
37 typedef double uf_value_t;
39 static int *uf_parent;
40 static uf_value_t *uf_value;
41 static uf_value_t *uf_update;
43 static int uf_current_size = 1000;
44 static int uf_max_size = 0;
45 static int uf_already_used = 0;
47 /** initialize the union find structure */
48 void ext_grs_uf_init(int max_elem) {
50 int max_size = max_elem + 1;
52 if (uf_already_used == 0) {
53 uf_current_size = MAX(max_size, 1000);
54 uf_parent = NEW_ARR_F(int, uf_current_size);
55 uf_value = NEW_ARR_F(uf_value_t, uf_current_size);
56 uf_update = NEW_ARR_F(uf_value_t, uf_current_size);
60 if (max_size > uf_current_size) {
61 uf_current_size = max_size;
62 ARR_RESIZE(*uf_parent, uf_parent, uf_current_size);
63 ARR_RESIZE(*uf_value, uf_value, uf_current_size);
64 ARR_RESIZE(*uf_update, uf_update, uf_current_size);
67 memset(uf_parent, 0, max_size * sizeof(*uf_parent));
68 memset(uf_value, 0, max_size * sizeof(*uf_value));
69 memset(uf_update, 0, max_size * sizeof(*uf_update));
71 uf_max_size = max_size;
74 /** find the value of the given elem */
75 uf_value_t ext_grs_uf_find_value(int elem) {
77 int old_parent = uf_parent[elem];
79 uf_value_t eff_parent_update = 0;
80 uf_value_t new_update = 0;
82 /* check wether the given elem is in range */
83 assert (elem < uf_max_size && "union find elem out of bounds");
85 /* if elem is a root... */
86 if (old_parent <= 0) {
87 /* ...simply return the elems effective value */
88 return uf_value[elem] + uf_update[elem];
91 /* if the old parent is a root... */
92 if (uf_parent[old_parent] <= 0) {
93 /* ...simply return the elems effective value */
94 return uf_value[elem] + uf_update[elem] + uf_update[old_parent];
97 /* otherwise get effective parental update recursively */
98 eff_parent_update = ext_grs_uf_find_value(old_parent) - uf_value[old_parent];
100 /* do path compression: */
101 /* let the old parents parent be the new parent, which must be the
102 * current root (by returning from recursion this has been set up by
103 * the recusrsive ascend to the root) */
104 new_root = uf_parent[old_parent];
105 uf_parent[elem] = new_root;
107 /* adapt the update vaule */
108 new_update = uf_update[elem] + eff_parent_update - uf_update[new_root];
109 uf_update[elem] = new_update;
111 /* return the effective value of the elem */
112 return uf_value[elem] + new_update;
115 /** find the root of the set <code>elem</code> belongs to */
116 int ext_grs_uf_find(int elem) {
118 /* check wether the given elem is in range */
119 assert (elem < uf_max_size && "union find elem out of bounds");
121 /* if elem is a root... */
122 if (uf_parent[elem] <= 0) {
123 /* ...simply return the elems effective value */
127 /* otherwise call find_value() for the elem (which performs path
128 * compression for the elem) */
129 ext_grs_uf_find_value(elem);
131 /* after path compression the parrent of elem has to be a root */
132 assert(uf_parent[uf_parent[elem]] <= 0 && "after path compression the parent should be a root");
133 return uf_parent[elem];
136 /** unite the sets given by the roots <code>root1</code> and <code>root2</code> */
137 int ext_grs_uf_unite(int root1, int root2) {
139 /* check wether the given elements are roots */
140 assert (uf_parent[root1] <= 0 && uf_parent[root2] <= 0 && "not a root element");
142 /* check wether the given elem is in range */
143 assert (root1 < uf_max_size && root2 < uf_max_size &&
144 "union find elem out of bounds");
146 /* the less deeper set is connected to the more deeper set */
147 if (uf_parent[root1] < uf_parent[root2]) {
148 uf_parent[root2] = root1;
149 uf_update[root2] -= uf_update[root1];
153 uf_parent[root1] = root2;
154 uf_update[root1] -= uf_update[root2];
155 if (uf_parent[root1] == uf_parent[root2])
165 /* Folgende Funktion FALSCH????? */
168 /** add the given value <code>a</code> to the values of all
169 * elements of the set given by <code>root</code> */
170 void ext_grs_uf_change_value(int root, uf_value_t a) {
172 /* check wether the given elem is in range */
173 assert (root < uf_max_size && "union find elem out of bounds");
175 assert (uf_parent[root] <= 0 && "not a root element");
176 uf_update[root] += a;
188 /* the meldable priority queue implementation */
194 * iterate over a list starting with <code>pos</code> up to the lists end
196 #define list_for_each_from(pos, head) \
197 for ( ; pos != (head); pos = pos->next )
199 #define GET_ACTUAL_EDGE_COST(e) \
200 ((e)->cost - ext_grs_uf_find_value((e)->arg->aiid + 1))
204 /** a priority queue of edges */
205 typedef lc_list_t ext_grs_mpq_t;
211 static struct obstack obst;
212 static int obst_already_initlzd = 0;
215 /** initialize the meldable priority queue inplementation */
216 void ext_grs_mpq_init(void)
218 if (! obst_already_initlzd) {
222 obstack_free(&obst, NULL);
225 obst_already_initlzd = 1;
228 /** create a new empty priority queue */
229 ext_grs_mpq_t *ext_grs_mpq_create(void)
231 ext_grs_mpq_t *mpq = obstack_alloc(&obst, sizeof(*mpq));
233 assert(obst_already_initlzd = 1 && "mpq structure not initialized yet");
236 LC_INIT_LIST_HEAD(mpq);
240 /** insert the given elem in the given priority queue */
241 void ext_grs_mpq_insert(ext_grs_mpq_t *pq, ext_grs_edge_t *e)
244 ext_grs_edge_t *edge;
246 assert (pq != NULL && "NULL pointer is not a valid priority queue");
248 if (lc_list_empty(pq)) {
249 lc_list_add(& e->mpq_list, pq);
253 /* go through pq untill the appropriate position is reached */
254 lc_list_for_each(pos, pq) {
255 edge = lc_list_entry(pos, ext_grs_edge_t, mpq_list);
256 if (GET_ACTUAL_EDGE_COST(e) <= GET_ACTUAL_EDGE_COST(edge)) {
257 lc_list_add_tail( & e->mpq_list, & edge->mpq_list );
262 lc_list_add( & e->mpq_list, & edge->mpq_list );
266 /** get the an item with a minimal prio or NULL if <code>pq</code> is empty */
267 ext_grs_edge_t *ext_grs_mpq_find_min(ext_grs_mpq_t *pq)
269 assert (pq != NULL && "NULL pointer is not a valid priority queue");
271 /* return NULL if pq is empty */
272 if (lc_list_empty(pq)) return NULL;
274 /* return first item otherwise */
275 return lc_list_entry(pq->next, ext_grs_edge_t, mpq_list);
278 /** Remove and return an item with a minimal prio, if <code>pq</code> is empty
280 * @note The member <code>list</code> of the returned item
281 * is in an undefined state. */
282 ext_grs_edge_t *ext_grs_mpq_delete_min(ext_grs_mpq_t *pq)
284 ext_grs_edge_t *first_edge;
286 assert (pq != NULL && "NULL pointer is not a vaild priority queue");
288 /* return NULL if pq is empty */
289 if (lc_list_empty(pq)) return NULL;
291 /* otherwise remove and return the first item */
292 first_edge = lc_list_entry(pq->next, ext_grs_edge_t, mpq_list);
293 lc_list_del(& first_edge->mpq_list);
297 void ext_grs_mpq_dump(ext_grs_mpq_t *pq);
299 /** Meld two item disjoint priority queues <code>pq1</code> and <code>pq2</code>.
300 * ATTENTION: The given priority queues will be <b>destroyed!</b> */
301 ext_grs_mpq_t *ext_grs_mpq_meld(ext_grs_mpq_t *pq1, ext_grs_mpq_t *pq2)
303 lc_list_t *pos1, *pos2, *n;
304 ext_grs_edge_t *e1, *e2;
305 int last = 1; /* tells wether that pq1 has been iteratied till the end and never breaked */
307 assert (pq1 != NULL && pq2 != NULL && "NULL pointer is not a vaild priority queue");
308 assert (pq1 != pq2 && "cannot meld an pq with itself");
312 ext_grs_mpq_dump(pq1);
314 ext_grs_mpq_dump(pq2);
318 /* if pq1 is empty return pq2 */
319 if (lc_list_empty(pq1)) return pq2;
321 /* insert the items of pq2 into pq1 (at appropriate positions) */
322 pos1 = pq1->next; /* start walking pq1 from beginning */
323 lc_list_for_each_safe (pos2, n, pq2) {
324 e2 = lc_list_entry(pos2, ext_grs_edge_t, mpq_list);
325 list_for_each_from (pos1, pq1) {
326 e1 = lc_list_entry(pos1, ext_grs_edge_t, mpq_list);
327 if (GET_ACTUAL_EDGE_COST(e2) <= GET_ACTUAL_EDGE_COST(e1)) {
334 /* pq1 has been iterated till the end */
335 /* insert item2 before the curent position in pq1 */
336 lc_list_move(& e2->mpq_list, & e1->mpq_list);
340 /* insert item2 before the curent position in pq1 */
341 lc_list_move_tail(& e2->mpq_list, & e1->mpq_list);
342 /* continue in pq1 with the current item */
343 pos1 = & e1->mpq_list;
344 /* maybe next time the end of pq1 is reached */
350 printf("Result queue:\n");
351 ext_grs_mpq_dump(pq1);
359 /** Remove the given item from the given priority queue.
360 * @note The list of the deleted item is in an undifind state afterwards. */
361 void ext_grs_mpq_delete(ext_grs_edge_t *e)
363 /* remove the item from its priority queue */
364 lc_list_del(& e->mpq_list);
368 void ext_grs_mpq_dump(ext_grs_mpq_t *pq) {
372 lc_list_for_each(pos, pq) {
373 ext_grs_edge_t *edge = lc_list_entry(pos, ext_grs_edge_t, mpq_list);
374 printf("\t(name, cost, actual cost) = (%s, %lf, %lf)\n",
375 edge->name, edge->cost, GET_ACTUAL_EDGE_COST(edge));
382 #endif /*_UF_MPQ_H_*/