smntc
an in-memory multimodal graph database
Loading...
Searching...
No Matches
Graph.c
Go to the documentation of this file.
1#include <stdlib.h>
2#include "errors.h"
3#include "Inventory.h"
4
5#include <stdio.h>
6
7// edge
8// source vertex -----------------------------> target vertex
9// source tail target head
10//
11// +--------+------------+---------------+------------+------------+---------------+-----------+
12// | | ONE | TWO | THREE | FOUR | FIVE | SIX |
13// +--------+------------+---------------+------------+------------+---------------+-----------+
14// | VERTEX | identifier | successor | tail count | head count | last tail | last head |
15// +--------+------------+---------------+------------+------------+---------------+-----------+
16// | EDGE | source | previous tail | next tail | target | previous head | next head |
17// +--------+------------+---------------+------------+------------+---------------+-----------+
18
19
20struct Graph {
21 struct Inventory *one;
22 struct Inventory *two;
24 struct Inventory *four;
25 struct Inventory *five;
26 struct Inventory *six;
27};
28
29struct Graph *Graph_construct(unsigned int length, int *error)
30{
31 struct Graph * this = malloc(sizeof(struct Graph));
32
33 if (0 == this) {
34 *error = ERROR_NO_MEMORY;
35 return 0;
36 }
37
38 this->one = Inventory_construct(length, error);
39
40 if (0 == this) {
41 *error = ERROR_NO_MEMORY;
42 return 0;
43 }
44
45 this->two = Inventory_construct(length, error);
46
47 if (0 == this) {
48 *error = ERROR_NO_MEMORY;
49 return 0;
50 }
51
52 this->three = Inventory_construct(length, error);
53
54 if (0 == this) {
55 *error = ERROR_NO_MEMORY;
56 return 0;
57 }
58
59 this->four= Inventory_construct(length, error);
60
61 if (0 == this) {
62 *error = ERROR_NO_MEMORY;
63 return 0;
64 }
65
66 this->five = Inventory_construct(length, error);
67
68 if (0 == this) {
69 *error = ERROR_NO_MEMORY;
70 return 0;
71 }
72
73 this->six = Inventory_construct(length, error);
74
75 if (0 == this) {
76 *error = ERROR_NO_MEMORY;
77 return 0;
78 }
79
80 // install gauge
81
82 Inventory_append(this->one, 1, error);
83
84 if (*error) {
85 return 0;
86 }
87
88 Inventory_append(this->two, 2, error);
89
90 if (*error) {
91 return 0;
92 }
93
94 Inventory_append(this->three, 3, error);
95
96 if (*error) {
97 return 0;
98 }
99
100 Inventory_append(this->four, 4, error);
101
102 if (*error) {
103 return 0;
104 }
105
106 Inventory_append(this->five, 5, error);
107
108 if (*error) {
109 return 0;
110 }
111
112 Inventory_append(this->six, 6, error);
113
114 if (*error) {
115 return 0;
116 }
117
118 return this;
119}
120
121struct Graph *Graph_destruct(struct Graph *this)
122{
123 if (0 != this) {
124 free(this->one);
125 free(this->two);
126 free(this->three);
127 free(this->four);
128 free(this->five);
129 free(this->six);
130 free(this);
131 }
132
133 return 0;
134}
135
136unsigned int Graph_addVertex(struct Graph *this, int *error)
137{
138 unsigned int vertex = Inventory_getNext(this->one);
139
140 Inventory_append(this->one, vertex, error);
141
142 if (*error) {
143 return 0;
144 }
145
146 Inventory_append(this->two, 0, error);
147
148 if (*error) {
149 return 0;
150 }
151
152 Inventory_append(this->three, 0, error);
153
154 if (*error) {
155 return 0;
156 }
157
158 Inventory_append(this->four, 0, error);
159
160 if (*error) {
161 return 0;
162 }
163
164 Inventory_append(this->five, 0, error);
165
166 if (*error) {
167 return 0;
168 }
169
170 Inventory_append(this->six, 0, error);
171
172 if (*error) {
173 return 0;
174 }
175
176 return vertex;
177}
178
179int Graph_hasEdge(const struct Graph *this, unsigned int source, unsigned int target, int *error)
180{
181 unsigned int sourceIdentifier = Inventory_read(this->one, source, error);
182
183 if (*error) {
184 return 0;
185 }
186
187 if (sourceIdentifier != source) {
188 *error = ERROR_NOT_A_VERTEX;
189 return 0;
190 }
191
192 unsigned int targetIdentifier = Inventory_read(this->one, target, error);
193
194 if (*error) {
195 return 0;
196 }
197
198 if (targetIdentifier != target) {
199 *error = ERROR_NOT_A_VERTEX;
200 return 0;
201 }
202
203 unsigned int tailCount = Inventory_read(this->three, source, error);
204
205 if (*error) {
206 return 0;
207 }
208 unsigned int headCount = Inventory_read(this->four, target, error);
209
210 if (*error) {
211 return 0;
212 }
213
214 if (tailCount < headCount) {
215
216 unsigned int tail = Inventory_read(this->five, source, error);
217
218 if (*error) {
219 return 0;
220 }
221
222 if (0 == tail) {
223 return 0;
224 }
225
226 unsigned int tailTarget = Inventory_read(this->four, tail, error);
227
228 if (tailTarget == target) {
229 return 1;
230 }
231
232 while (1) {
233
234 tail = Inventory_read(this->two, tail, error);
235
236 if (*error) {
237 return 0;
238 }
239
240 if (0 == tail) {
241 return 0;
242 }
243
244 tailTarget = Inventory_read(this->four, tail, error);
245
246 if (*error) {
247 return 0;
248 }
249
250 if (tailTarget == target) {
251 return 1;
252 }
253 }
254
255 } else {
256
257 unsigned int head = Inventory_read(this->six, target, error);
258
259 if (*error) {
260 return 0;
261 }
262
263 if (0 == head) {
264 return 0;
265 }
266
267 unsigned int headSource = Inventory_read(this->one, head, error);
268
269 if (headSource == source) {
270 return 1;
271 }
272
273 while (1) {
274
275 head = Inventory_read(this->five, head, error);
276
277 if (*error) {
278 return 0;
279 }
280
281 if (0 == head) {
282 return 0;
283 }
284
285 headSource = Inventory_read(this->one, head, error);
286
287 if (*error) {
288 return 0;
289 }
290
291 if (headSource == source) {
292 return 1;
293 }
294 }
295 }
296}
297
298void Graph_addEdge(struct Graph *this, unsigned int source, unsigned int target, int *error)
299{
300 if (Graph_hasEdge(this, source, target, error)) { // checks for identifiers as well
301 return;
302 }
303
304 // start edge
305
306 unsigned int edge = Inventory_getNext(this->one);
307
308 Inventory_append(this->one, source, error);
309
310 if (*error) {
311 return;
312 }
313
314 Inventory_append(this->three, 0, error);
315
316 if (*error) {
317 return;
318 }
319
320 Inventory_append(this->four, target, error);
321
322 if (*error) {
323 return;
324 }
325
326 Inventory_append(this->six, 0, error);
327
328 if (*error) {
329 return;
330 }
331
332 // update counters
333
334 unsigned int tailCounter = Inventory_read(this->three, source, error);
335
336 if (*error) {
337 return;
338 }
339
340 Inventory_update(this->three, source, tailCounter + 1, error);
341
342 if (*error) {
343 return;
344 }
345
346 unsigned int headCounter = Inventory_read(this->four, target, error);
347
348 if (*error) {
349 return;
350 }
351
352 Inventory_update(this->four, target, headCounter + 1, error);
353
354 if (*error) {
355 return;
356 }
357
358 // get last edges
359
360 unsigned int lastTail = Inventory_read(this->five, source, error);
361
362 if (*error) {
363 return;
364 }
365
366 unsigned int lastHead = Inventory_read(this->six, target, error);
367
368 if (*error) {
369 return;
370 }
371
372 if (0 == lastTail && 0 == lastHead) {
373
374 // finish edge
375
376 Inventory_append(this->two, 0, error);
377
378 if (*error) {
379 return;
380 }
381
382 Inventory_append(this->five, 0, error);
383
384 if (*error) {
385 return;
386 }
387
388 } else if (0 != lastTail && 0 == lastHead) {
389
390 // finish edge
391
392 Inventory_append(this->two, lastTail, error);
393
394 if (*error) {
395 return;
396 }
397
398 Inventory_append(this->five, 0, error);
399
400 if (*error) {
401 return;
402 }
403
404 // update previous
405
406 Inventory_update(this->three, lastTail, edge, error);
407
408 if (*error) {
409 return;
410 }
411
412 } else if (0 == lastTail && 0 != lastHead) {
413
414 // finish edge
415
416 Inventory_append(this->two, 0, error);
417
418 if (*error) {
419 return;
420 }
421
422 Inventory_append(this->five, lastHead, error);
423
424 if (*error) {
425 return;
426 }
427
428 // update previous
429
430 Inventory_update(this->six, lastHead, edge, error);
431
432 if (*error) {
433 return;
434 }
435
436 } else if (0 != lastTail && 0 != lastHead) {
437
438 // finish edge
439
440 Inventory_append(this->two, lastTail, error);
441
442 if (*error) {
443 return;
444 }
445
446 Inventory_append(this->five, lastHead, error);
447
448 if (*error) {
449 return;
450 }
451
452 // update previous
453
454 Inventory_update(this->three, lastTail, edge, error);
455
456 if (*error) {
457 return;
458 }
459
460 Inventory_update(this->six, lastHead, edge, error);
461
462 if (*error) {
463 return;
464 }
465 }
466
467 // connect edge to vertices
468
469 Inventory_update(this->five, source, edge, error);
470
471 if (*error) {
472 return;
473 }
474
475 Inventory_update(this->six, target, edge, error);
476
477 if (*error) {
478 return;
479 }
480}
481
482unsigned int Graph_countSources(const struct Graph *this, unsigned int target, int *error)
483{
484 unsigned int identifier = Inventory_read(this->one, target, error);
485
486 if (*error) {
487 return 0;
488 }
489
490 if (identifier != target) {
491 *error = ERROR_NOT_A_VERTEX;
492 return 0;
493 }
494
495 unsigned int headCount = Inventory_read(this->four, target, error);
496
497 if (*error) {
498 return 0;
499 }
500
501 return headCount;
502}
503
504unsigned int Graph_countTargets(const struct Graph *this, unsigned int source, int *error)
505{
506 unsigned int identifier = Inventory_read(this->one, source, error);
507
508 if (*error) {
509 return 0;
510 }
511
512 if (identifier != source) {
513 *error = ERROR_NOT_A_VERTEX;
514 return 0;
515 }
516
517 unsigned int tailCount = Inventory_read(this->three, source, error);
518
519 if (*error) {
520 return 0;
521 }
522
523 return tailCount;
524}
525
526void Graph_readSources(const struct Graph *this, unsigned int target, unsigned int length, unsigned int *sources, int *error)
527{
528 if (0 == length) {
529 return;
530 }
531
532 unsigned int identifier = Inventory_read(this->one, target, error);
533
534 if (*error) {
535 return;
536 }
537
538 if (identifier != target) {
539 *error = ERROR_NOT_A_VERTEX;
540 return;
541 }
542
543 unsigned int headCount = Inventory_read(this->four, target, error);
544
545 if (*error) {
546 return;
547 }
548
549 if (0 == headCount) {
550 return;
551 }
552
553 if (headCount > length) {
555 return;
556 }
557
558 unsigned int head = Inventory_read(this->six, target, error);
559
560 if (*error) {
561 return;
562 }
563
564 if (0 == head) {
565 return;
566 }
567
568 unsigned int headSource = Inventory_read(this->one, head, error);
569
570 unsigned int index = 0;
571
572 sources[index] = headSource;
573
574 while (1) {
575
576 if (index == length) {
578 return;
579 }
580
581 head = Inventory_read(this->five, head, error);
582
583 if (*error) {
584 return;
585 }
586
587 if (0 == head) {
588 return;
589 }
590
591 headSource = Inventory_read(this->one, head, error);
592
593 if (*error) {
594 return;
595 }
596
597 index++;
598
599 sources[index] = headSource;
600 }
601}
602
603void Graph_readTargets(const struct Graph *this, unsigned int source, unsigned int length, unsigned int *targets, int *error)
604{
605 if (0 == length) {
606 return;
607 }
608
609 unsigned int identifier = Inventory_read(this->one, source, error);
610
611 if (*error) {
612 return;
613 }
614
615 if (identifier != source) {
616 *error = ERROR_NOT_A_VERTEX;
617 return;
618 }
619
620 unsigned int tailCount = Inventory_read(this->three, source, error);
621
622 if (*error) {
623 return;
624 }
625
626 if (0 == tailCount) {
627 return;
628 }
629
630 if ( tailCount > length) {
632 return;
633 }
634
635 unsigned int tail = Inventory_read(this->five, source, error);
636
637 if (*error) {
638 return;
639 }
640
641 if (0 == tail) {
642 return;
643 }
644
645 unsigned int tailTarget = Inventory_read(this->four, tail, error);
646
647 unsigned int index = 0;
648
649 targets[index] = tailTarget;
650
651 while (1) {
652
653 if (index == length) {
655 return;
656 }
657
658 tail = Inventory_read(this->two, tail, error);
659
660 if (*error) {
661 return;
662 }
663
664 if (0 == tail) {
665 return;
666 }
667
668 tailTarget = Inventory_read(this->four, tail, error);
669
670 if (*error) {
671 return;
672 }
673
674 index++;
675
676 targets[index] = tailTarget;
677 }
678}
679
680unsigned int Graph_readLastSource(const struct Graph *this, unsigned int target, int *error)
681{
682 unsigned int identifier = Inventory_read(this->one, target, error);
683
684 if (*error) {
685 return 0;
686 }
687
688 if (identifier != target) {
689 *error = ERROR_NOT_A_VERTEX;
690 return 0;
691 }
692
693 unsigned int head = Inventory_read(this->six, target, error);
694
695 if (*error) {
696 return 0;
697 }
698
699 if (0 == head) {
700 return 0;
701 }
702
703 unsigned int headSource = Inventory_read(this->one, head, error);
704
705 if (*error) {
706 return 0;
707 }
708
709 return headSource;
710}
711
712unsigned int Graph_readLastTarget(const struct Graph *this, unsigned int source, int *error)
713{
714 unsigned int identifier = Inventory_read(this->one, source, error);
715
716 if (*error) {
717 return 0;
718 }
719
720 if (identifier != source) {
721 *error = ERROR_NOT_A_VERTEX;
722 return 0;
723 }
724
725 unsigned int tail = Inventory_read(this->five, source, error);
726
727 if (*error) {
728 return 0;
729 }
730
731 if (0 == tail) {
732 return 0;
733 }
734
735 unsigned int tailTarget = Inventory_read(this->four, tail, error);
736
737 if (*error) {
738 return 0;
739 }
740
741 return tailTarget;
742}
743
744void Graph_addCluster(struct Graph *this, unsigned int length, unsigned int *vertices, int *error)
745{
746 if (0 == length) {
747 return;
748 }
749
750 if (1 == length) {
751 vertices[0] = Graph_addVertex(this, error);
752 return;
753 }
754
755 for (unsigned int index = 0; index < length; index++) {
756
757 vertices[index] = Graph_addVertex(this, error);
758
759 if (*error) {
760 return;
761 }
762
763 if (index > 0) {
764
765 Inventory_update(this->two, vertices[index] - 1, vertices[index], error);
766
767 if (*error) {
768 return;
769 }
770 }
771 }
772
773 Inventory_update(this->two, vertices[length - 1], vertices[0], error);
774}
775
776void Graph_readCluster(const struct Graph *this, unsigned int predecessor, unsigned int length, unsigned int *vertices, int *error)
777{
778 if (0 == length) {
779 return;
780 }
781
782 unsigned int identifier = Inventory_read(this->one, predecessor, error);
783
784 if (*error) {
785 return;
786 }
787
788 if (identifier != predecessor) {
789 *error = ERROR_NOT_A_VERTEX;
790 return;
791 }
792
793 if (1 == length) {
794 vertices[0] = predecessor;
795 return;
796 }
797
798 unsigned int count = 0;
799 unsigned int vertex = predecessor;
800
801 while (1) {
802
803 vertices[count] = vertex;
804
805 vertex = Inventory_read(this->two, vertex, error);
806
807 if (*error) {
808 return;
809 }
810
811 if (vertex == predecessor) {
812 return;
813 }
814
815 count++;
816
817 if (count >= length) {
819 return;
820 }
821 }
822}
823
824unsigned int Graph_protrudeCluster(struct Graph *this, unsigned int predecessor, int *error)
825{
826 unsigned int identifier = Inventory_read(this->one, predecessor, error);
827
828 if (*error) {
829 return 0;
830 }
831
832 if (identifier != predecessor) {
833 *error = ERROR_NOT_A_VERTEX;
834 return 0;
835 }
836
837 unsigned int successor = Inventory_read(this->two, predecessor, error);
838
839 if (*error) {
840 return 0;
841 }
842
843 if (0 == successor) {
844
845 successor = Graph_addVertex(this, error);
846
847 if (*error) {
848 return 0;
849 }
850
851 Inventory_update(this->two, predecessor, successor, error);
852
853 if (*error) {
854 return 0;
855 }
856
857 Inventory_update(this->two, successor, predecessor, error);
858
859 if (*error) {
860 return 0;
861 }
862
863 return successor;
864 }
865
866 while (1) {
867
868 unsigned int nextSuccessor = Inventory_read(this->two, successor, error);
869
870 if (*error) {
871 return 0;
872 }
873
874 if (nextSuccessor != predecessor) {
875 successor = nextSuccessor;
876 continue;
877 }
878
879 unsigned int newVertex = Graph_addVertex(this, error);
880
881 if (*error) {
882 return 0;
883 }
884
885 Inventory_update(this->two, predecessor, newVertex, error);
886
887 if (*error) {
888 return 0;
889 }
890
891 Inventory_update(this->two, newVertex, successor, error);
892
893 return newVertex;
894 }
895}
896
897unsigned int Graph_getLength(const struct Graph *this)
898{
899 return Inventory_getNext(this->one);
900}
901
902void Graph_import(struct Graph *this, unsigned int index, unsigned int one, unsigned int two, unsigned int three, unsigned int four, unsigned int five, unsigned int six, int *error)
903{
904 Inventory_appendUnchecked(this->one, one, error);
905
906 if (*error) {
907 return;
908 }
909
910 Inventory_appendUnchecked(this->two, two, error);
911
912 if (*error) {
913 return;
914 }
915
916 Inventory_appendUnchecked(this->three, three, error);
917
918 if (*error) {
919 return;
920 }
921
922 Inventory_appendUnchecked(this->four, four, error);
923
924 if (*error) {
925 return;
926 }
927
928 Inventory_appendUnchecked(this->five, five, error);
929
930 if (*error) {
931 return;
932 }
933
934 Inventory_appendUnchecked(this->six, six, error);
935}
936
937void Graph_export(struct Graph *this, unsigned int index, unsigned int *one, unsigned int *two, unsigned int *three, unsigned int *four, unsigned int *five, unsigned int *six, int *error)
938{
939 *one = Inventory_read(this->one, index, error);
940
941 if (*error) {
942 return;
943 }
944
945 *two = Inventory_read(this->two, index, error);
946
947 if (*error) {
948 return;
949 }
950
951 *three = Inventory_read(this->three, index, error);
952
953 if (*error) {
954 return;
955 }
956
957 *four = Inventory_read(this->four, index, error);
958
959 if (*error) {
960 return;
961 }
962
963 *five = Inventory_read(this->five, index, error);
964
965 if (*error) {
966 return;
967 }
968
969 *six = Inventory_read(this->six, index, error);
970}
void Graph_import(struct Graph *this, unsigned int index, unsigned int one, unsigned int two, unsigned int three, unsigned int four, unsigned int five, unsigned int six, int *error)
Definition Graph.c:902
int Graph_hasEdge(const struct Graph *this, unsigned int source, unsigned int target, int *error)
It checks if a graph storage has a directed edge between two vertices.
Definition Graph.c:179
void Graph_readSources(const struct Graph *this, unsigned int target, unsigned int length, unsigned int *sources, int *error)
It reads all source vertices that have an edge leading to a particular target vertex.
Definition Graph.c:526
unsigned int Graph_countTargets(const struct Graph *this, unsigned int source, int *error)
It counts all target vertices that have an edge leading from a particular source vertex.
Definition Graph.c:504
struct Graph * Graph_construct(unsigned int length, int *error)
It constructs a graph storage.
Definition Graph.c:29
unsigned int Graph_getLength(const struct Graph *this)
Definition Graph.c:897
unsigned int Graph_countSources(const struct Graph *this, unsigned int target, int *error)
It counts all source vertices that have an edge leading to a particular target vertex.
Definition Graph.c:482
void Graph_addEdge(struct Graph *this, unsigned int source, unsigned int target, int *error)
It adds a directed edge from a source vertex to a target vertex.
Definition Graph.c:298
unsigned int Graph_protrudeCluster(struct Graph *this, unsigned int predecessor, int *error)
Definition Graph.c:824
unsigned int Graph_readLastTarget(const struct Graph *this, unsigned int source, int *error)
It reads the last target vertex of a source vertex, if it exists.
Definition Graph.c:712
void Graph_export(struct Graph *this, unsigned int index, unsigned int *one, unsigned int *two, unsigned int *three, unsigned int *four, unsigned int *five, unsigned int *six, int *error)
Definition Graph.c:937
unsigned int Graph_readLastSource(const struct Graph *this, unsigned int target, int *error)
It reads the last source vertex of a target vertex, if it exists.
Definition Graph.c:680
struct Graph * Graph_destruct(struct Graph *this)
It destructs a graph storage.
Definition Graph.c:121
void Graph_readCluster(const struct Graph *this, unsigned int predecessor, unsigned int length, unsigned int *vertices, int *error)
Definition Graph.c:776
void Graph_readTargets(const struct Graph *this, unsigned int source, unsigned int length, unsigned int *targets, int *error)
It reads all target vertices that have an edge leading from a particular source vertex.
Definition Graph.c:603
unsigned int Graph_addVertex(struct Graph *this, int *error)
It adds a vertex into a graph storage.
Definition Graph.c:136
void Graph_addCluster(struct Graph *this, unsigned int length, unsigned int *vertices, int *error)
Definition Graph.c:744
unsigned int Inventory_read(const struct Inventory *this, unsigned int path, int *error)
Definition Inventory.c:92
void Inventory_update(struct Inventory *this, unsigned int path, unsigned int content, int *error)
Definition Inventory.c:77
struct Inventory * Inventory_construct(unsigned int length, int *error)
Definition Inventory.c:11
unsigned int Inventory_getNext(const struct Inventory *this)
Definition Inventory.c:44
void Inventory_append(struct Inventory *this, unsigned int content, int *error)
Definition Inventory.c:49
void Inventory_appendUnchecked(struct Inventory *this, unsigned int content, int *error)
Definition Inventory.c:66
#define ERROR_NO_MEMORY
Definition errors.h:5
#define ERROR_GRAPH_BUFFER_TOO_SMALL
Definition errors.h:9
#define ERROR_NOT_A_VERTEX
Definition errors.h:10
Definition Graph.c:20
struct Inventory * three
Definition Graph.c:23
struct Inventory * two
Definition Graph.c:22
struct Inventory * one
Definition Graph.c:21
struct Inventory * six
Definition Graph.c:26
struct Inventory * five
Definition Graph.c:25
struct Inventory * four
Definition Graph.c:24