File: SetCover.cpp

package info (click to toggle)
setcover 0.0~git20161128.b1de791-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 148 kB
  • sloc: cpp: 435; makefile: 51
file content (180 lines) | stat: -rw-r--r-- 6,589 bytes parent folder | download | duplicates (2)
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
//
//  SetCover.cpp
//  graphcluster
//
//  Created by Martin Steinegger on 21.05.13.
//  Copyright (c) 2013 Martin Steinegger. All rights reserved.
//

#include "SetCover.h"
#include <string.h> // memset


set_cover::set_cover(unsigned int set_size,
                     unsigned int uniqu_element_size,
                     unsigned int weight_range,
                     unsigned int all_element_count,
                     unsigned int * element_size_lookup){
    this->set_size = set_size;
    this->element_size = uniqu_element_size;
    this->weight_range = weight_range;
    this->ordered_by_score_set = new set*[weight_range+1]; // score range
    memset(this->ordered_by_score_set, 0, sizeof(set *)*(weight_range+1)); // init with 0 (no element is set)
    
    this->element_lookup     = new linear_multi_array<set::element*>(element_size_lookup,uniqu_element_size,all_element_count);
    this->set_elements = (set::element *) malloc(sizeof(set::element)*all_element_count);
    
    this->sets = (set *) malloc(sizeof(set)*(set_size+1));
    this->add_position = 0;
}

set_cover::~set_cover(){
    free(set_elements);
    free(sets);
    delete element_lookup;
    delete[] ordered_by_score_set;
}


set * set_cover::create_set_at_weight_position(int weight,set * set_to_add){
    set * weighted_position_start_set=this->ordered_by_score_set[weight];
    
    if(weighted_position_start_set == 0) { // first element is not yet set
        set_to_add->next = NULL;
        set_to_add->last = NULL;
    }else{  // first element is already setted
        weighted_position_start_set->last = set_to_add;
        set_to_add->next = weighted_position_start_set;
    }
    this->ordered_by_score_set[weight] = set_to_add;
    return set_to_add;
}

void set_cover::add_set(const int set_id, const int set_weight,
                        const unsigned int * element_ids,
                        const unsigned short * weights,
                        const int element_size){
    
    set::element * element_last_ptr = NULL;
    set::element * element_first_ptr = NULL;
    set * curr_set = &this->sets[set_id];
    curr_set->next = NULL;
    curr_set->last = NULL;
    curr_set->elements = NULL;		
    curr_set =create_set_at_weight_position(set_weight,curr_set);
    curr_set->set_id = set_id;
    curr_set->weight = set_weight;
    
    // set up doubled linked list + fill element_lookup
    for(int i = 0 ; i < element_size; i++) {
        // init elemnt with id, weight information
        set::element * curr_element_ptr=&set_elements[add_position+i];
        curr_element_ptr->element_id=element_ids[i];
        curr_element_ptr->weight=weights[i];
        if(element_first_ptr == NULL) // first ptr is not yet set
            element_first_ptr = curr_element_ptr;
        // navigation (double linked list, parent)
        curr_element_ptr->parent_set = curr_set;
        curr_element_ptr->last = element_last_ptr;
        if(element_last_ptr != NULL) // not in first iteration
            element_last_ptr->next = curr_element_ptr;
        element_last_ptr = curr_element_ptr;
        // element_lookup fill up
        int element_id=curr_element_ptr->element_id;
        element_lookup->add_value_at(element_id,curr_element_ptr);
    }
    add_position += element_size;
    if(element_last_ptr!=NULL)
        element_last_ptr->next = NULL; // last element points to NULL
    curr_set->elements = element_first_ptr; // set element pointer to current_set

}



void set_cover::removeSet(set * s){
    set::element * element=s->elements;
    int s_set_id = s->set_id;
    unplug_set(s);
    do{ // for(Element element in elements
        set::element * element_to_remove;
        int element_id=element->element_id;
        
        std::pair<set::element**,int> element_lookup_structur=element_lookup->get_array(element_id);
        set::element ** element_lookup_array = element_lookup_structur.first;
        int array_size = element_lookup_structur.second;
        for(int i =0; i < array_size;i++){
            element_to_remove = element_lookup_array[i];
            set * parent_set = element_to_remove->parent_set;
            if(parent_set!=NULL && parent_set->set_id!=s_set_id){
                unplug_set(parent_set);
                parent_set->weight  -= element_to_remove->weight;
                parent_set->elements = unplug_element(element_to_remove,parent_set->elements);
                create_set_at_weight_position(parent_set->weight,parent_set);

            }
            //delete element_to_remove;
        }

    }while((element=element->next) != NULL);
}

set::element * set_cover::unplug_element(set::element * element_to_unplug,set::element * first_element) {
    set::element * last_element=element_to_unplug->last;
    set::element * next_element=element_to_unplug->next;
    element_to_unplug->last       = NULL;
    element_to_unplug->next       = NULL;
    element_to_unplug->parent_set = NULL;

    if(last_element == NULL && next_element==NULL){
        return NULL;
    }if(last_element == NULL){ // first element
        next_element->last = NULL;
        return next_element;
    } else if (next_element == NULL) { // end of list
        last_element->next = NULL;
    } else { // middle of the list
        last_element->next = next_element;
        next_element->last = last_element;
    }
    return first_element;
}


void set_cover::unplug_set(set * set_to_unplug){
    set * last_set = set_to_unplug->last;
    set * next_set = set_to_unplug->next;
    set_to_unplug->next = NULL;
    set_to_unplug->last = NULL;
    if(last_set == NULL && next_set == NULL){ // only one element left
        ordered_by_score_set[set_to_unplug->weight] = NULL;
    }else if(last_set == NULL){ // first set
        next_set->last = NULL;
        ordered_by_score_set[set_to_unplug->weight] = next_set;
    } else if (next_set == NULL) { // last set
        last_set->next = NULL;
    } else { // set in the middle
        last_set->next = next_set;
        next_set->last = last_set;
    }
}



std::list<set *> set_cover::execute_set_cover(){
    //covered_vertex is a bit set which holds the covered states for all vertexes
    std::list<set *> result;
    for(int i = weight_range; i > 0;) {
        while(this->ordered_by_score_set[i] == NULL && i > 0){
            i--;
        }
        if(i==0){ // if i == 0 than score = 0 -> no element in set anymore
            break;
        }
        set * max_set = this->ordered_by_score_set[i];
        
        removeSet(max_set);
        result.push_back(max_set); // O(1)
    }
    return result;
}