-
Notifications
You must be signed in to change notification settings - Fork 0
/
graph.h
555 lines (491 loc) · 12.1 KB
/
graph.h
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
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
#ifndef GRAPH_LIB
#define GRAPH_LIB 0
#include <iostream>
#include <vector>
#include <string>
#include "g6tools.h"
class m3sgraph;
struct NeighborData
{
int index; //vertex index in graph
int neighbors; //number of neighbors
int listsize;
int* list;
NeighborData()
{
index = -1; //undefined
neighbors = 0;
listsize = -1; //uninitialized
list = NULL;
}
bool GetInfo (int i, m3sgraph& g);
};
class m3sgraph
{
// m3sgraph is a minimal memory matrix simple graph. This graph
// is slow to access but quite small on memory consumption. For
// example:
// a graph of size 100 would require about:
// -10000 bytes if represented with a boolean matrix
// -4950 bytes if representated by only an upper triangle
// -825 (cieling of 4950/6)bytes using g6 type notation
// -619 (cieling of 4950/8)bytes using a m3sgraph
// Since the graph is represented on the bit level, accessing info
// can be slower than a full matrix, however if multiple graphs are
// needed simultaneously, it is preferable.
private:
//BitByteTools bbt;
long long unsigned int size;
unsigned int length; // int is 32bit
unsigned char* graph;
std::vector<NeighborData*> neighborlist;
bool neghborlistIsUpdated;
public:
m3sgraph();
~m3sgraph();
m3sgraph(const m3sgraph& g); //copy constructor
m3sgraph& operator=(const m3sgraph& g); //assignment operator overload
bool operator==(const m3sgraph &other);
bool operator!=(const m3sgraph &other);
void SetEdge(long long unsigned int a,long long unsigned int b, bool v);
bool GetEdge(long long unsigned int a,long long unsigned int b);
void AddVertex();
void RemoveVertex(long long unsigned int v);
bool SetGraph(const char* g6); //convert from Graph6 format
bool SetGraph(std::istream& in); //convert from Graph6 format
long long unsigned int GetDeg(long long unsigned int a);
std::vector<long long unsigned int> GetDegSeq(); //works only with small graphs (size -> 32bit int)
std::string GetG6();
long long unsigned int GetSize();
void Draw(std::ostream& out);
void PopulateNeighborlist();
std::vector<NeighborData*>* GetNeighborListing() {return &neighborlist;}
};
m3sgraph::m3sgraph()
{
size = 0;
length = 0;
graph = NULL;
neghborlistIsUpdated = false;
}
m3sgraph::~m3sgraph()
{return;//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~what?~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// if(graph != NULL)
// delete[] graph;
}
m3sgraph::m3sgraph(const m3sgraph &g)
{
size = g.size;
length = g.length;
graph = new unsigned char[length];
for(unsigned int i=0; i<length;i++)
{
graph[i]=g.graph[i];
}
}
m3sgraph& m3sgraph::operator=(const m3sgraph& g)
{
if(this != &g) //check to see if its the same object or not (circumventing self assignment?)
{
delete[] graph; //remove old graph data
size = g.size;
length = g.length;
graph = new unsigned char[length];
for(unsigned int i=0; i<length;i++)
{
graph[i]=g.graph[i];
}
}
return *this;
}
bool m3sgraph::operator ==(const m3sgraph &other)
{
if(size != other.size)
return false;
/*if(length != length.size)
return false*/ //unnecessary since for a particular size length must be the same
for(unsigned int i=0; i<length;i++)
{
if(int(graph[i])!=int(other.graph[i]))
return false;
}
return true;
}
bool m3sgraph::operator !=(const m3sgraph &other)
{
return !(*this == other);
}
void m3sgraph::SetEdge(long long unsigned int a,long long unsigned int b, bool v)
{
long long unsigned int tmp;
unsigned char bit = 0;
if(a==b)
return;
if(a>b)
{//use 'a' as column
tmp = a;
a=b;
b=tmp;
}
tmp = ((b-1)*(b))/2; //previous coloumns summed up
tmp += a; //elements from this column added
bit = bit = 128 >> (tmp%8);
tmp = tmp/8;
graph[tmp]|= bit;
if(!v)
{
graph[tmp]^= bit;
}
return;
}
bool m3sgraph::GetEdge(long long unsigned int a,long long unsigned int b)
{
long long unsigned int tmp;
unsigned char bit = 0;
if(a==b)
return false;
if(a>b) //use 'a' as column
{
tmp = a;
a=b;
b=tmp;
}
tmp = ((b-1)*(b))/2; //previous coloumns summed up
tmp += a+1; //elements from this column added
if(tmp%8==0)
{
bit = 1;
tmp = tmp/8 - 1; //byte index
}
else
{
bit = 128 >> ((tmp%8)-1);
tmp = tmp/8; //byte index
}
if(((graph[tmp])&bit)==bit)
return true;
return false;
}
void m3sgraph::AddVertex()
{
if(size == 0)
{
size+=1;
return; //no edges in a 1 vertex graph
}
if(size == 1)
{
graph = new unsigned char[1];
graph[0]=0;
size++;
length++;
return;
}
long long unsigned int tmp = (size*(size-1))/2; //current # of used bits
//number of actual bits to add (max # = size, since the current size is 1 less
//than the intended size:
if(tmp%8==0)
{
tmp = size; //bits to add
}
else
{// tmp%8 is number of bits used in last byte
if(size > (8-(tmp%8))) //if the remaining bits in last byte
{ //are less than the maximum required bits(size)
tmp = size - (8-(tmp%8)); //reduce by existing # of unused bits
}
else
tmp = 0; //no additional bits required
}
if(tmp!=0)
{
//number of bytes to add
if(tmp%8==0)
{
tmp = tmp/8;
}
else
{
tmp = (tmp/8)+1;
}
unsigned char* tmpg = graph;
graph = new unsigned char[length + tmp];
for(long long unsigned int i = 0; i< length; i++)
{
graph[i]=tmpg[i];
//std::cout << "m3u byte - " << i << " of " << length + tmp << ":" <<int(graph[i]) << std::endl;
}
for(long long unsigned int i = 0; i< tmp; i++)
{
graph[length+i]=0;
//std::cout << "new m3u byte - " << length + i<< " of " << length + tmp << ":" <<int(graph[length+i]) << std::endl;
}
length = length + tmp;
//delete[] tmpg;****************************************
}
size++;
}
void m3sgraph::RemoveVertex(long long unsigned int v)
{
unsigned char* old = graph;
long long unsigned int bitcount = ((size-2)*(size-1))/2;
long long unsigned int tmpInt64;
unsigned int newlength;
unsigned int cbyte; //byte column starts in
unsigned int cbit; //first bit of column
if(bitcount%8==0)
newlength = bitcount/8;
else
newlength = bitcount/8 + 1;
graph = new unsigned char[newlength];
tmpInt64 = (v*(v-1))/2;//sum of previous columns
cbyte = tmpInt64/8;//correct index: if evenly divided we start at next byte so
//there is no need to reduce by 1, else if it does not
//divide evenly, there is no need to reduce by 1 since the
//remainder and begining of column are in the next byte
cbit = tmpInt64%8; //bit of byte to start ignoring
//number of bits to remove from column = v
for(unsigned int i=0; i<cbyte; i++)//copy whole bytes until begining of
{ //column to remove
graph[i]=old[i];
}
unsigned char tmpUchar = 128;
graph[cbyte] = 0;//is this necessary?
for(int i=0; i<cbit; i++)//copy remainin g bits before beginning
{
//std::cout << int(old[cbyte]) << " " << int(tmpUchar) <<" " << int(tmpUchar&old[cbyte])<< std::endl;
//if(tmpUchar == tmpUchar&old[cbyte]) //NOTE:Unknown anomaly
if(int(tmpUchar) == int(tmpUchar&old[cbyte]))
{
graph[cbyte] |=tmpUchar;
}
tmpUchar >>= 1;//shift right by 1
}
if(v == size - 1)//last vertex
{
size--;
delete[] old;
return;
}
unsigned int cbit2;
unsigned int cbyte2;
tmpInt64 = (((v+1)*v)/2); //bits including the column for v
cbit2 = tmpInt64%8; //bit to start copying from
cbyte2 = tmpInt64/8; //byte to start copying from
unsigned char tmpUchar2 = 128 >> cbit2;
tmpUchar = 128 >> cbit;
while(cbyte2 < length)
{
while(tmpUchar2 > 0)
{
if(int(tmpUchar2) == int(old[cbyte2]&tmpUchar2))
{
graph[cbyte] |= tmpUchar;
}
tmpUchar >>= 1;
tmpUchar2 >>=
1;
if(tmpUchar == 0)
{
tmpUchar = 128;
cbyte++;
}
}
tmpUchar2 = 128;
cbyte2++;
}
delete[] old;
size--;
return;
}
bool m3sgraph::SetGraph(std::istream& in)
{
std::string str;
std::getline(in,str);
return SetGraph(str.c_str());
}
bool m3sgraph::SetGraph(const char* g6)
{
size = g6::GetSize(g6);
if(size==0)
return false;
length = size - 1;
length = (length*(size))/2; //number of elements in upper matrix
if(length%8 > 0)
length = (length/8)+1;
else
length = (length/8);
graph = new unsigned char[length];
long long unsigned int byte = 0;
unsigned char bit = 128;
bool** matrix = g6::GetMatrix(g6);
graph[byte]=0;
for(long long unsigned int i=0; i<size; i++)
{
for(long long unsigned int j=0; j<i; j++)
{
if(bit==0)
{
bit = 128;
byte++;
graph[byte]=0;
}
if(matrix[j][i])
{
graph[byte] |= bit;
}
bit >>= 1;
}
}
return true;
}
long long unsigned int m3sgraph::GetDeg(long long unsigned int a)
{
long long unsigned int count = 0;
for(long long unsigned int i=0; i<size; i++)
{
if(GetEdge(a,i))
{
count++;
}
}
return count;
}
std::vector<long long unsigned int> m3sgraph::GetDegSeq()
{
std::vector<long long unsigned int> seq;
if(this->size==0)
{
return seq;
}
for(long long unsigned int i =0; i< size; i++)
{
seq.push_back(GetDeg(i));
}
return seq;
}
std::string m3sgraph::GetG6()
{
if(size == 0)
return "";
long long unsigned int count = ((size*(size-1))/2);
if(count%6==0)
count = count/6;
else
count = (count/6)+1;
long long unsigned int byte = 0;
unsigned char bit;
std::string g6;
if(size < 63)
{
g6 += (char)(size+63);
}else if (size < 258047)
{
g6 += (char)126;
for(int i = 12; i>=0; i-=6)
{
bit = size >> i;
g6 += (char)((bit & '?')+63);
}
}
else
{
g6 += (char)126;
g6 += (char)126;
for(int i = 30; i>=0; i-=6)
{
bit = size >> i;
g6 += (char)((bit & '?')+63);
}
}
for(int i=0; i<count; i++)
{
switch(i%4)
{
case 0:
bit = graph[byte];
bit >>=2;
g6+=char(bit+63);
break;
case 1:
bit = graph[byte];
bit <<= 4;
byte++;
bit |= graph[byte] >> 4;
g6 +=char((bit&63)+63);
break;
case 2:
bit = graph[byte];
bit <<= 2;
byte++;
bit |= graph[byte] >> 6;
g6 +=char((bit&63)+63);
break;
case 3:
bit = graph[byte];
g6 +=char((bit&63)+63);
byte++;
break;
}
}
return g6;
}
long long unsigned int m3sgraph::GetSize()
{
return size;
}
//Draws Adjacency Matrix
void m3sgraph::Draw(std::ostream& out)
{
for(long long unsigned int j=0; j<size; j++)
{
for(long long unsigned int k=0; k<size; k++)
{
if(GetEdge(j,k))
out << 1;
else
out <<0;
}
out << std::endl;
}
out <<"======================"<< std::endl;
}
void m3sgraph::PopulateNeighborlist()
{
if(!neghborlistIsUpdated)
{
neighborlist.clear();
neighborlist.resize(size,NULL);
for(int i=0; i<size; i++)
{
neighborlist[i]=new NeighborData;
neighborlist[i]->GetInfo(i,*this);
}
//neghborlistIsUpdated = true;
}
}
bool NeighborData::GetInfo (int i, m3sgraph& g)
{
index = i;
int size = g.GetSize();
int* tmp = new int [size-1];
neighbors=0; //neighbor count
for(int n=0; n<size; n++)
{
if(g.GetEdge(i,n))
{
tmp[neighbors] = n;
neighbors++;
}
}
if(list!=NULL)
delete[] list;
list = new int[neighbors];
for(int n=0; n<neighbors; n++)
{
list[n]=tmp[n];
}
delete[] tmp;
return true;
}
#endif