/
ConstraintGraph.cpp
297 lines (263 loc) · 7.94 KB
/
ConstraintGraph.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
#include <cassert>
#include "util.h"
#include "ConstraintGraph.h"
const char * color_string[]={"H","L","G"};
// get the real index of the GNode in ConstraintGraph::node
#define get_node_idx(n) (((n).type==ROW?0:row) + (n).idx)
#define access_node(n) node_list[get_node_idx(n)]
// access the edge of two nodes u,v NOTE: no self edge!
#define access_edge(u,v) edge[get_node_idx(u)][get_node_idx(v)]
#define get_color(n) node_list[get_node_idx(n)].color
#define set_color(n,c) get_color(n) = (c)
#define next_color(c) (c)==HI?LO:HI
COLOR ConstraintGraph::get_node_color(const GNode & node){
return get_color(node);
}
ConstraintGraph::ConstraintGraph(int width,int height):
row(height),col(width),
node_list( GNodeVector(row+col) ),
edge( vector< GEdgeVector >(row+col) ){
// initialize the node's type
for (int i = 0; i<row; i++) {
node_list[i]=GNode(ROW,i);
}
for (int j = 0; j<col; j++) {
node_list[j+row]=GNode(COL,j);
}
// initialize the 2nd dimension of edge
for (size_t i= 0; i < edge.size(); i++) {
edge[i] = GEdgeVector(row+col);
// initialize the matrix element
for (int j = 0; j < row+col; j++) {
edge[i][j].u=node_list[i];
edge[i][j].v=node_list[j];
}
}
}
ConstraintGraph::~ConstraintGraph(){ }
// given two node u,v check if there is e=(u,v)
bool ConstraintGraph::has_edge(const GNode &u,const GNode &v){
GEdge &e = access_edge(u,v);
return e.type != NOEDGE;
}
// add an edge between u,v
bool ConstraintGraph::do_add_edge(const GNode &u,const GNode &v,EType type){
GEdge &uv = access_edge(u,v);
GEdge &vu = access_edge(v,u);
GNode &unode = access_node(u);
GNode &vnode = access_node(v);
if( uv.type == NOEDGE || uv.type == type ){// safely add edge
uv.type = type;
uv.count++;
unode.ecount++;
vu.type = type; // symmetric
vu.count++;
vnode.ecount++;
}
else
report_exit("Trying to add incompatible edge type");
return true;
}
// remove (one) edge between node u,v
// note that when the node becomes standalone, also rip its color
bool ConstraintGraph::remove_edge(const GNode &u,const GNode &v){
GEdge &uv = access_edge(u,v);
GEdge &vu = access_edge(v,u);
GNode &unode = access_node(u);
GNode &vnode = access_node(v);
assert( uv.count == vu.count );
// edge not exist,
if( uv.count == 0 ) return false;
uv.count--;
if( uv.count == 0 ) uv.type = NOEDGE;
unode.ecount--;
if( unode.ecount == 0 ) erase_color(u);
vu.count--; // symmetric
if( vu.count == 0 ) vu.type = NOEDGE;
vnode.ecount--;
if( vnode.ecount == 0 ) erase_color(v);
return true;
}
// reset the color of node to G
// return its PREVIOUS color
COLOR ConstraintGraph::erase_color(const GNode & node){
COLOR pre;
GNode & n = access_node(node);
pre=n.color;
n.color = G;
return pre;
}
// try to add edge with color awareness
// return EXIST if the edge exists already
bool ConstraintGraph::add_edge_color(const GNode &u,const GNode &v, EType type)
{
// first check if edge exist
int a=get_node_idx(u);
int b=get_node_idx(v);
//GEdge & uv = access_edge(u,v);
GEdge & uv = edge[a][b];
if( uv.type != NOEDGE ){// already has an edge
if( uv.type != type ) return false; // type incompatible
else do_add_edge(u,v,type); // safely add dummy edge
}
// now we ensure u-v edge NOT exist(NOEDGE)
// check if adding this edge will conflict
// explore all 9 cases: {G,H,V} X {G,H,V}
assert( u != v );
GNode & unode = access_node(u);
GNode & vnode = access_node(v);
COLOR ucolor = get_color(u);
COLOR vcolor = get_color(v);
// node u standalone, which means color = G
if( ucolor == G ){
assert( unode.ecount == 0 );
do_add_edge(u,v,type); // safely add edge
if( vcolor == G ){ // G,G: color them
set_color(unode,HI);
if( type == DIFF ) set_color(vnode,LO);
else set_color(vnode,HI);
}
else if( vcolor == HI ){// G,H
if( type == DIFF ) set_color(unode,LO);
else set_color(unode,HI);
}
else{// G,L
if( type == DIFF ) set_color(unode,HI);
else set_color(unode,LO);
}
return SUCCESS;
}
// v standlone(symmetric to previous case)
else if( vcolor == G ) {
assert( vnode.ecount == 0 );
do_add_edge(v,u,type); // safely add edge
if( ucolor == G ){ // G,G: color them
set_color(unode,LO);
if( type == DIFF ) set_color(vnode,HI);
else set_color(vnode,LO);
}
else if( ucolor == HI ){// H,G
if( type == DIFF ) set_color(vnode,LO);
else set_color(vnode,HI);
}
else{// L,G
if( type == DIFF ) set_color(vnode,HI);
else set_color(vnode,LO);
}
return SUCCESS;
}
else{// u,v not standalone => u,v has colors, but not connected
if( (ucolor != vcolor &&
type == DIFF) || // different color, DIFF edge
(ucolor == vcolor &&
type == SAME)) // same color, SAME edge
{// type compatible
do_add_edge(u,v,type); // safely link them
return SUCCESS;
}
// H-L, H-H or L-L
// try to swap the color
// of one connected component
//ConstraintGraph bak(*this); // make backup
reverse_color(v); // reverse the coloring of v component
COLOR u_newcolor = get_color(u);
if( ucolor != u_newcolor ){
// if u's color changed=>2-color failed
//*this = bak;
return FAIL;
}
else{
do_add_edge(u,v,type);// safely link them
return SUCCESS;
}
}
}
// recursively reverse the color of a componenet, which contains `node'
void ConstraintGraph::recur_reverse_color(const GNode &node,
BoolVector & mark){
int idx = get_node_idx(node);
// check if this node has been visited
if( mark[idx] == true ) return;
else mark[idx] = true;
COLOR origin_color = get_color(node);
COLOR new_color = next_color(origin_color);
set_color(node,new_color);
// reverse color all its adjacent nodes
vector<GEdge> & adj_nodes = edge[idx];
for (int v_idx=0; v_idx<row+col;v_idx++) {
// 1.no need to check itself
// 2.only check if edge exist
GEdge & e = adj_nodes[v_idx];
if( v_idx != idx && e.type != NOEDGE ){
assert( e.v != node );
recur_reverse_color(e.v,mark);
}
}
}
// reverse the color of a component, which containing `node'
void ConstraintGraph::reverse_color(const GNode &node){
BoolVector mark(row+col,false);
recur_reverse_color(node,mark);
}
// color `node' using the color `to_assign'
// and try color all its adjacent nodes
bool ConstraintGraph::recur_color(const GNode &node,COLOR to_assign){
assert( to_assign != G ); // color will not be G!!
COLOR cur_color = get_color(node);
// this node has been colored to H or L
if( cur_color == to_assign )
return true;
// this node has colored to different color, fail!
else if( cur_color != G )
return false;
// it is G, color it, and all its neighbours
set_color(node,to_assign);
COLOR opposite_color = next_color(to_assign);
int idx = get_node_idx(node);
vector<GEdge> & elist = edge[idx];
for(int i = 0; i < row+col; i++) {
GEdge & e = elist[i];
if( i!=idx && e.count > 0){
bool result;
if( e.type == DIFF )
result = recur_color(e.v,opposite_color);
else
result = recur_color(e.v,to_assign);
if( result == false ) return false;
}
}
// safely colored all neighbour
return true;
}
// color all the connected component, but not standalone node
// try to assign color to the graph on the base of current coloring
// return true if successful
bool ConstraintGraph::try_coloring(){
for (int i = 0; i < row+col; i++) {
// degree must greater than 0, otherwise keep color=G
if( node_list[i].ecount == 0 ) continue;
// don't need to color again if has color
if( node_list[i].color != G ) continue;
//vector<GEdge> &elist = edge[i];
bool result = recur_color(node_list[i],HI);
if( result == false ) return false;
}
// safely colored all connected component
return true;
}
COLOR ConstraintGraph::get_node_color(NType type,int idx){
GNode nd(type,idx);
return get_node_color(nd);
}
// COL wins ROW
// if same type, smaller index wins
bool operator <(GNode u,GNode v){
return (u.type == COL && v.type == ROW) ||
(u.type == v.type && u.idx < v.idx);
}
bool operator == (GNode u,GNode v){
return u.type == v.type && u.idx == v.idx;
}
bool operator != (GNode u, GNode v){
return !(u == v);
}