1 /*
2 IGraph library.
3 Copyright (C) 2006-2012 Gabor Csardi <csardi.gabor@gmail.com>
4 334 Harvard st, Cambridge, MA, 02138 USA
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA
20
21 */
22
23 %{
24
25 /*
26 IGraph library.
27 Copyright (C) 2006-2012 Gabor Csardi <csardi.gabor@gmail.com>
28 334 Harvard st, Cambridge, MA, 02138 USA
29
30 This program is free software; you can redistribute it and/or modify
31 it under the terms of the GNU General Public License as published by
32 the Free Software Foundation; either version 2 of the License, or
33 (at your option) any later version.
34
35 This program is distributed in the hope that it will be useful,
36 but WITHOUT ANY WARRANTY; without even the implied warranty of
37 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38 GNU General Public License for more details.
39
40 You should have received a copy of the GNU General Public License
41 along with this program; if not, write to the Free Software
42 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
43 02110-1301 USA
44
45 */
46
47 #include <stdio.h>
48 #include <string.h>
49 #include <math.h>
50
51 #include "igraph_types.h"
52 #include "igraph_memory.h"
53 #include "igraph_error.h"
54 #include "igraph_attributes.h"
55 #include "config.h"
56
57 #include "core/math.h"
58 #include "io/pajek-header.h"
59 #include "io/parsers/pajek-parser.h" /* it must come first because of YYSTYPE */
60 #include "io/parsers/pajek-lexer.h"
61 #include "internal/hacks.h"
62
63 int igraph_pajek_yyerror(YYLTYPE* locp,
64 igraph_i_pajek_parsedata_t *context,
65 const char *s);
66
67 int igraph_i_pajek_add_string_vertex_attribute(const char *name,
68 const char *value,
69 int len,
70 igraph_i_pajek_parsedata_t *context);
71 int igraph_i_pajek_add_string_edge_attribute(const char *name,
72 const char *value,
73 int len,
74 igraph_i_pajek_parsedata_t *context);
75 int igraph_i_pajek_add_numeric_vertex_attribute(const char *name,
76 igraph_real_t value,
77 igraph_i_pajek_parsedata_t *context);
78 int igraph_i_pajek_add_numeric_edge_attribute(const char *name,
79 igraph_real_t value,
80 igraph_i_pajek_parsedata_t *context);
81 int igraph_i_pajek_add_numeric_attribute(igraph_trie_t *names,
82 igraph_vector_ptr_t *attrs,
83 long int count,
84 const char *attrname,
85 igraph_integer_t vid,
86 igraph_real_t number);
87 int igraph_i_pajek_add_string_attribute(igraph_trie_t *names,
88 igraph_vector_ptr_t *attrs,
89 long int count,
90 const char *attrname,
91 igraph_integer_t vid,
92 const char *str);
93
94 int igraph_i_pajek_add_bipartite_type(igraph_i_pajek_parsedata_t *context);
95 int igraph_i_pajek_check_bipartite(igraph_i_pajek_parsedata_t *context);
96
97 extern igraph_real_t igraph_pajek_get_number(const char *str, long int len);
98 extern long int igraph_i_pajek_actvertex;
99 extern long int igraph_i_pajek_actedge;
100
101 #define scanner context->scanner
102
103 %}
104
105 %pure-parser
106 /* bison: do not remove the equals sign; macOS XCode ships with bison 2.3, which
107 * needs the equals sign */
108 %name-prefix="igraph_pajek_yy"
109 %defines
110 %locations
111 %error-verbose
112 %parse-param { igraph_i_pajek_parsedata_t* context }
113 %lex-param { void *scanner }
114
115 %union {
116 long int intnum;
117 double realnum;
118 struct {
119 char *str;
120 int len;
121 } string;
122 }
123
124 %type <intnum> longint;
125 %type <intnum> arcfrom;
126 %type <intnum> arcto;
127 %type <intnum> edgefrom;
128 %type <intnum> edgeto;
129 %type <realnum> number;
130 %type <string> word;
131 %type <string> vpwordpar;
132 %type <string> epwordpar;
133 %type <intnum> vertex;
134
135 %token NEWLINE
136 %token NUM
137 %token ALNUM
138 %token QSTR
139 %token PSTR
140 %token NETWORKLINE
141 %token VERTICESLINE
142 %token ARCSLINE
143 %token EDGESLINE
144 %token ARCSLISTLINE
145 %token EDGESLISTLINE
146 %token MATRIXLINE
147 %token ERROR
148
149 %token VP_X_FACT
150 %token VP_Y_FACT
151 %token VP_IC
152 %token VP_BC
153 %token VP_LC
154 %token VP_LR
155 %token VP_LPHI
156 %token VP_BW
157 %token VP_FOS
158 %token VP_PHI
159 %token VP_R
160 %token VP_Q
161 %token VP_LA
162 %token VP_FONT
163 %token VP_URL
164 %token VP_SIZE
165
166 %token EP_C
167 %token EP_S
168 %token EP_A
169 %token EP_W
170 %token EP_H1
171 %token EP_H2
172 %token EP_A1
173 %token EP_A2
174 %token EP_K1
175 %token EP_K2
176 %token EP_AP
177 %token EP_P
178 %token EP_L
179 %token EP_LP
180 %token EP_LR
181 %token EP_LPHI
182 %token EP_LC
183 %token EP_LA
184 %token EP_SIZE
185 %token EP_FOS
186
187 %%
188
189 input: nethead vertices edgeblock {
190 if (context->vcount2 > 0) { igraph_i_pajek_check_bipartite(context); }
191 };
192
193 nethead: /* empty */ | NETWORKLINE words NEWLINE;
194
195 vertices: verticeshead NEWLINE vertdefs;
196
197 verticeshead: VERTICESLINE longint {
198 context->vcount=$2;
199 context->vcount2=0;
200 }
201 | VERTICESLINE longint longint {
202 context->vcount=$2;
203 context->vcount2=$3;
204 igraph_i_pajek_add_bipartite_type(context);
205 };
206
207 vertdefs: /* empty */ | vertdefs vertexline;
208
209 vertexline: NEWLINE |
210 vertex NEWLINE |
211 vertex { context->actvertex=$1; } vertexid vertexcoords shape params NEWLINE { }
212 ;
213
214 vertex: longint { $$=$1; context->mode=1; };
215
216 vertexid: word {
217 igraph_i_pajek_add_string_vertex_attribute("id", $1.str, $1.len, context);
218 igraph_i_pajek_add_string_vertex_attribute("name", $1.str, $1.len, context);
219 };
220
221 vertexcoords: /* empty */
222 | number number {
223 igraph_i_pajek_add_numeric_vertex_attribute("x", $1, context);
224 igraph_i_pajek_add_numeric_vertex_attribute("y", $2, context);
225 }
226 | number number number {
227 igraph_i_pajek_add_numeric_vertex_attribute("x", $1, context);
228 igraph_i_pajek_add_numeric_vertex_attribute("y", $2, context);
229 igraph_i_pajek_add_numeric_vertex_attribute("z", $3, context);
230 };
231
232 shape: /* empty */ | word {
233 igraph_i_pajek_add_string_vertex_attribute("shape", $1.str, $1.len, context);
234 };
235
236 params: /* empty */ | params param;
237
238 param:
239 vpword
240 | VP_X_FACT number {
241 igraph_i_pajek_add_numeric_vertex_attribute("xfact", $2, context);
242 }
243 | VP_Y_FACT number {
244 igraph_i_pajek_add_numeric_vertex_attribute("yfact", $2, context);
245 }
246 | VP_IC number number number { /* RGB color */
247 igraph_i_pajek_add_numeric_vertex_attribute("color-red", $2, context);
248 igraph_i_pajek_add_numeric_vertex_attribute("color-green", $3, context);
249 igraph_i_pajek_add_numeric_vertex_attribute("color-blue", $4, context);
250 }
251 | VP_BC number number number {
252 igraph_i_pajek_add_numeric_vertex_attribute("framecolor-red", $2, context);
253 igraph_i_pajek_add_numeric_vertex_attribute("framecolor-green", $3, context);
254 igraph_i_pajek_add_numeric_vertex_attribute("framecolor-blue", $4, context);
255 }
256 | VP_LC number number number {
257 igraph_i_pajek_add_numeric_vertex_attribute("labelcolor-red", $2, context);
258 igraph_i_pajek_add_numeric_vertex_attribute("labelcolor-green", $3, context);
259 igraph_i_pajek_add_numeric_vertex_attribute("labelcolor-blue", $4, context);
260 }
261 | VP_LR number {
262 igraph_i_pajek_add_numeric_vertex_attribute("labeldist", $2, context);
263 }
264 | VP_LPHI number {
265 igraph_i_pajek_add_numeric_vertex_attribute("labeldegree2", $2, context);
266 }
267 | VP_BW number {
268 igraph_i_pajek_add_numeric_vertex_attribute("framewidth", $2, context);
269 }
270 | VP_FOS number {
271 igraph_i_pajek_add_numeric_vertex_attribute("fontsize", $2, context);
272 }
273 | VP_PHI number {
274 igraph_i_pajek_add_numeric_vertex_attribute("rotation", $2, context);
275 }
276 | VP_R number {
277 igraph_i_pajek_add_numeric_vertex_attribute("radius", $2, context);
278 }
279 | VP_Q number {
280 igraph_i_pajek_add_numeric_vertex_attribute("diamondratio", $2, context);
281 }
282 | VP_LA number {
283 igraph_i_pajek_add_numeric_vertex_attribute("labeldegree", $2, context);
284 }
285 | VP_SIZE number {
286 igraph_i_pajek_add_numeric_vertex_attribute("vertexsize", $2, context);
287 }
288 ;
289
290 vpword: VP_FONT { context->mode=3; } vpwordpar {
291 context->mode=1;
292 igraph_i_pajek_add_string_vertex_attribute("font", $3.str, $3.len, context);
293 }
294 | VP_URL { context->mode=3; } vpwordpar {
295 context->mode=1;
296 igraph_i_pajek_add_string_vertex_attribute("url", $3.str, $3.len, context);
297 }
298 | VP_IC { context->mode=3; } vpwordpar {
299 context->mode=1;
300 igraph_i_pajek_add_string_vertex_attribute("color", $3.str, $3.len, context);
301 }
302 | VP_BC { context->mode=3; } vpwordpar {
303 context->mode=1;
304 igraph_i_pajek_add_string_vertex_attribute("framecolor",
305 $3.str, $3.len, context);
306 }
307 | VP_LC { context->mode=3; } vpwordpar {
308 context->mode=1;
309 igraph_i_pajek_add_string_vertex_attribute("labelcolor",
310 $3.str, $3.len, context);
311 }
312 ;
313
314 vpwordpar: word { $$=$1; };
315
316 edgeblock: /* empty */ | edgeblock arcs | edgeblock edges | edgeblock arcslist | edgeblock edgeslist | edgeblock adjmatrix;
317
318 arcs: ARCSLINE NEWLINE arcsdefs { context->directed=1; }
319 | ARCSLINE number NEWLINE arcsdefs { context->directed=1; };
320
321 arcsdefs: /* empty */ | arcsdefs arcsline;
322
323 arcsline: NEWLINE |
324 arcfrom arcto { context->actedge++;
325 context->mode=2; } weight edgeparams NEWLINE {
326 igraph_vector_push_back(context->vector, $1-1);
327 igraph_vector_push_back(context->vector, $2-1); }
328 ;
329
330 arcfrom: longint;
331
332 arcto: longint;
333
334 edges: EDGESLINE NEWLINE edgesdefs { context->directed=0; }
335 | EDGESLINE number NEWLINE edgesdefs { context->directed=0; }
336
337 edgesdefs: /* empty */ | edgesdefs edgesline;
338
339 edgesline: NEWLINE |
340 edgefrom edgeto { context->actedge++;
341 context->mode=2; } weight edgeparams NEWLINE {
342 igraph_vector_push_back(context->vector, $1-1);
343 igraph_vector_push_back(context->vector, $2-1); }
344 ;
345
346 edgefrom: longint;
347
348 edgeto: longint;
349
350 weight: /* empty */ | number {
351 igraph_i_pajek_add_numeric_edge_attribute("weight", $1, context);
352 };
353
354 edgeparams: /* empty */ | edgeparams edgeparam;
355
356 edgeparam:
357 epword
358 | EP_C number number number {
359 igraph_i_pajek_add_numeric_edge_attribute("color-red", $2, context);
360 igraph_i_pajek_add_numeric_edge_attribute("color-green", $3, context);
361 igraph_i_pajek_add_numeric_edge_attribute("color-blue", $4, context);
362 }
363 | EP_S number {
364 igraph_i_pajek_add_numeric_edge_attribute("arrowsize", $2, context);
365 }
366 | EP_W number {
367 igraph_i_pajek_add_numeric_edge_attribute("edgewidth", $2, context);
368 }
369 | EP_H1 number {
370 igraph_i_pajek_add_numeric_edge_attribute("hook1", $2, context);
371 }
372 | EP_H2 number {
373 igraph_i_pajek_add_numeric_edge_attribute("hook2", $2, context);
374 }
375 | EP_A1 number {
376 igraph_i_pajek_add_numeric_edge_attribute("angle1", $2, context);
377 }
378 | EP_A2 number {
379 igraph_i_pajek_add_numeric_edge_attribute("angle2", $2, context);
380 }
381 | EP_K1 number {
382 igraph_i_pajek_add_numeric_edge_attribute("velocity1", $2, context);
383 }
384 | EP_K2 number {
385 igraph_i_pajek_add_numeric_edge_attribute("velocity2", $2, context);
386 }
387 | EP_AP number {
388 igraph_i_pajek_add_numeric_edge_attribute("arrowpos", $2, context);
389 }
390 | EP_LP number {
391 igraph_i_pajek_add_numeric_edge_attribute("labelpos", $2, context);
392 }
393 | EP_LR number {
394 igraph_i_pajek_add_numeric_edge_attribute("labelangle", $2, context);
395 }
396 | EP_LPHI number {
397 igraph_i_pajek_add_numeric_edge_attribute("labelangle2", $2, context);
398 }
399 | EP_LA number {
400 igraph_i_pajek_add_numeric_edge_attribute("labeldegree", $2, context);
401 }
402 | EP_SIZE number { /* what is this??? */
403 igraph_i_pajek_add_numeric_edge_attribute("arrowsize", $2, context);
404 }
405 | EP_FOS number {
406 igraph_i_pajek_add_numeric_edge_attribute("fontsize", $2, context);
407 }
408 ;
409
410 epword: EP_A { context->mode=4; } epwordpar {
411 context->mode=2;
412 igraph_i_pajek_add_string_edge_attribute("arrowtype", $3.str, $3.len, context);
413 }
414 | EP_P { context->mode=4; } epwordpar {
415 context->mode=2;
416 igraph_i_pajek_add_string_edge_attribute("linepattern", $3.str, $3.len, context);
417 }
418 | EP_L { context->mode=4; } epwordpar {
419 context->mode=2;
420 igraph_i_pajek_add_string_edge_attribute("label", $3.str, $3.len, context);
421 }
422 | EP_LC { context->mode=4; } epwordpar {
423 context->mode=2;
424 igraph_i_pajek_add_string_edge_attribute("labelcolor", $3.str, $3.len, context);
425 }
426 | EP_C { context->mode=4; } epwordpar {
427 context->mode=2;
428 igraph_i_pajek_add_string_edge_attribute("color", $3.str, $3.len, context);
429 }
430 ;
431
432 epwordpar: word { context->mode=2; $$=$1; };
433
434 arcslist: ARCSLISTLINE NEWLINE arcslistlines { context->directed=1; };
435
436 arcslistlines: /* empty */ | arcslistlines arclistline;
437
438 arclistline: NEWLINE | arclistfrom arctolist NEWLINE;
439
440 arctolist: /* empty */ | arctolist arclistto;
441
442 arclistfrom: longint { context->mode=0; context->actfrom=labs($1)-1; };
443
444 arclistto: longint {
445 igraph_vector_push_back(context->vector, context->actfrom);
446 igraph_vector_push_back(context->vector, labs($1)-1);
447 };
448
449 edgeslist: EDGESLISTLINE NEWLINE edgelistlines { context->directed=0; };
450
451 edgelistlines: /* empty */ | edgelistlines edgelistline;
452
453 edgelistline: NEWLINE | edgelistfrom edgetolist NEWLINE;
454
455 edgetolist: /* empty */ | edgetolist edgelistto;
456
457 edgelistfrom: longint { context->mode=0; context->actfrom=labs($1)-1; };
458
459 edgelistto: longint {
460 igraph_vector_push_back(context->vector, context->actfrom);
461 igraph_vector_push_back(context->vector, labs($1)-1);
462 };
463
464 /* -----------------------------------------------------*/
465
466 adjmatrix: matrixline NEWLINE adjmatrixlines;
467
468 matrixline: MATRIXLINE { context->actfrom=0;
469 context->actto=0;
470 context->directed=(context->vcount2==0);
471 };
472
473 adjmatrixlines: /* empty */ | adjmatrixlines adjmatrixline;
474
475 adjmatrixline: adjmatrixnumbers NEWLINE { context->actfrom++; context->actto=0; };
476
477 adjmatrixnumbers: /* empty */ | adjmatrixentry adjmatrixnumbers;
478
479 adjmatrixentry: number {
480 if ($1 != 0) {
481 if (context->vcount2==0) {
482 context->actedge++;
483 igraph_i_pajek_add_numeric_edge_attribute("weight", $1, context);
484 igraph_vector_push_back(context->vector, context->actfrom);
485 igraph_vector_push_back(context->vector, context->actto);
486 } else if (context->vcount2 + context->actto < context->vcount) {
487 context->actedge++;
488 igraph_i_pajek_add_numeric_edge_attribute("weight", $1, context);
489 igraph_vector_push_back(context->vector, context->actfrom);
490 igraph_vector_push_back(context->vector,
491 context->vcount2+context->actto);
492 }
493 }
494 context->actto++;
495 };
496
497 /* -----------------------------------------------------*/
498
499 longint: NUM { $$=igraph_pajek_get_number(igraph_pajek_yyget_text(scanner),
500 igraph_pajek_yyget_leng(scanner)); };
501
502 number: NUM { $$=igraph_pajek_get_number(igraph_pajek_yyget_text(scanner),
503 igraph_pajek_yyget_leng(scanner)); };
504
505 words: /* empty */ | words word;
506
507 word: ALNUM { $$.str=igraph_pajek_yyget_text(scanner);
508 $$.len=igraph_pajek_yyget_leng(scanner); }
509 | NUM { $$.str=igraph_pajek_yyget_text(scanner);
510 $$.len=igraph_pajek_yyget_leng(scanner); }
511 | QSTR { $$.str=igraph_pajek_yyget_text(scanner)+1;
512 $$.len=igraph_pajek_yyget_leng(scanner)-2; };
513
514 %%
515
516 int igraph_pajek_yyerror(YYLTYPE* locp,
517 igraph_i_pajek_parsedata_t *context,
518 const char *s) {
519 snprintf(context->errmsg, sizeof(context->errmsg)/sizeof(char)-1,
520 "Parse error in Pajek file, line %i (%s)",
521 locp->first_line, s);
522 return 0;
523 }
524
igraph_pajek_get_number(const char * str,long int length)525 igraph_real_t igraph_pajek_get_number(const char *str, long int length) {
526 igraph_real_t num;
527 char *tmp=IGRAPH_CALLOC(length+1, char);
528
529 strncpy(tmp, str, length);
530 tmp[length]='\0';
531 sscanf(tmp, "%lf", &num);
532 IGRAPH_FREE(tmp);
533 return num;
534 }
535
536 /* TODO: NA's */
537
igraph_i_pajek_add_numeric_attribute(igraph_trie_t * names,igraph_vector_ptr_t * attrs,long int count,const char * attrname,igraph_integer_t vid,igraph_real_t number)538 int igraph_i_pajek_add_numeric_attribute(igraph_trie_t *names,
539 igraph_vector_ptr_t *attrs,
540 long int count,
541 const char *attrname,
542 igraph_integer_t vid,
543 igraph_real_t number) {
544 long int attrsize=igraph_trie_size(names);
545 long int id;
546 igraph_vector_t *na;
547 igraph_attribute_record_t *rec;
548
549 igraph_trie_get(names, attrname, &id);
550 if (id == attrsize) {
551 /* add a new attribute */
552 rec=IGRAPH_CALLOC(1, igraph_attribute_record_t);
553 na=IGRAPH_CALLOC(1, igraph_vector_t);
554 igraph_vector_init(na, count);
555 rec->name=strdup(attrname);
556 rec->type=IGRAPH_ATTRIBUTE_NUMERIC;
557 rec->value=na;
558 igraph_vector_ptr_push_back(attrs, rec);
559 }
560 rec=VECTOR(*attrs)[id];
561 na=(igraph_vector_t*)rec->value;
562 if (igraph_vector_size(na) == vid) {
563 IGRAPH_CHECK(igraph_vector_push_back(na, number));
564 } else if (igraph_vector_size(na) < vid) {
565 long int origsize=igraph_vector_size(na);
566 IGRAPH_CHECK(igraph_vector_resize(na, (long int)vid+1));
567 for (;origsize<count; origsize++) {
568 VECTOR(*na)[origsize] = IGRAPH_NAN;
569 }
570 VECTOR(*na)[(long int) vid] = number;
571 } else {
572 VECTOR(*na)[(long int) vid] = number;
573 }
574
575 return 0;
576 }
577
578 /* TODO: NA's */
579
igraph_i_pajek_add_string_attribute(igraph_trie_t * names,igraph_vector_ptr_t * attrs,long int count,const char * attrname,igraph_integer_t vid,const char * str)580 int igraph_i_pajek_add_string_attribute(igraph_trie_t *names,
581 igraph_vector_ptr_t *attrs,
582 long int count,
583 const char *attrname,
584 igraph_integer_t vid,
585 const char *str) {
586 long int attrsize=igraph_trie_size(names);
587 long int id;
588 igraph_strvector_t *na;
589 igraph_attribute_record_t *rec;
590 long int i;
591
592 igraph_trie_get(names, attrname, &id);
593 if (id == attrsize) {
594 /* add a new attribute */
595 rec=IGRAPH_CALLOC(1, igraph_attribute_record_t);
596 na=IGRAPH_CALLOC(1, igraph_strvector_t);
597 igraph_strvector_init(na, count);
598 for (i=0; i<count; i++) {
599 igraph_strvector_set(na, i, "");
600 }
601 rec->name=strdup(attrname);
602 rec->type=IGRAPH_ATTRIBUTE_STRING;
603 rec->value=na;
604 igraph_vector_ptr_push_back(attrs, rec);
605 }
606 rec=VECTOR(*attrs)[id];
607 na=(igraph_strvector_t*)rec->value;
608 if (igraph_strvector_size(na) <= vid) {
609 long int origsize=igraph_strvector_size(na);
610 IGRAPH_CHECK(igraph_strvector_resize(na, vid+1));
611 for (;origsize<count; origsize++) {
612 igraph_strvector_set(na, origsize, "");
613 }
614 }
615 igraph_strvector_set(na, vid, str);
616
617 return 0;
618 }
619
igraph_i_pajek_add_string_vertex_attribute(const char * name,const char * value,int len,igraph_i_pajek_parsedata_t * context)620 int igraph_i_pajek_add_string_vertex_attribute(const char *name,
621 const char *value,
622 int len,
623 igraph_i_pajek_parsedata_t *context) {
624 char *tmp;
625 int ret;
626
627 tmp=IGRAPH_CALLOC(len+1, char);
628 if (tmp==0) {
629 IGRAPH_ERROR("cannot add element to hash table", IGRAPH_ENOMEM);
630 }
631 IGRAPH_FINALLY(igraph_free, tmp);
632 strncpy(tmp, value, len);
633 tmp[len]='\0';
634
635 ret=igraph_i_pajek_add_string_attribute(context->vertex_attribute_names,
636 context->vertex_attributes,
637 context->vcount,
638 name, context->actvertex-1,
639 tmp);
640
641 IGRAPH_FREE(tmp);
642 IGRAPH_FINALLY_CLEAN(1);
643
644 return ret;
645 }
646
igraph_i_pajek_add_string_edge_attribute(const char * name,const char * value,int len,igraph_i_pajek_parsedata_t * context)647 int igraph_i_pajek_add_string_edge_attribute(const char *name,
648 const char *value,
649 int len,
650 igraph_i_pajek_parsedata_t *context) {
651 char *tmp;
652 int ret;
653
654 tmp=IGRAPH_CALLOC(len+1, char);
655 if (tmp==0) {
656 IGRAPH_ERROR("cannot add element to hash table", IGRAPH_ENOMEM);
657 }
658 IGRAPH_FINALLY(igraph_free, tmp);
659 strncpy(tmp, value, len);
660 tmp[len]='\0';
661
662 ret=igraph_i_pajek_add_string_attribute(context->edge_attribute_names,
663 context->edge_attributes,
664 context->actedge,
665 name, context->actedge-1,
666 tmp);
667
668 IGRAPH_FREE(tmp);
669 IGRAPH_FINALLY_CLEAN(1);
670
671 return ret;
672 }
673
igraph_i_pajek_add_numeric_vertex_attribute(const char * name,igraph_real_t value,igraph_i_pajek_parsedata_t * context)674 int igraph_i_pajek_add_numeric_vertex_attribute(const char *name,
675 igraph_real_t value,
676 igraph_i_pajek_parsedata_t *context) {
677
678 return
679 igraph_i_pajek_add_numeric_attribute(context->vertex_attribute_names,
680 context->vertex_attributes,
681 context->vcount,
682 name, context->actvertex-1,
683 value);
684 }
685
igraph_i_pajek_add_numeric_edge_attribute(const char * name,igraph_real_t value,igraph_i_pajek_parsedata_t * context)686 int igraph_i_pajek_add_numeric_edge_attribute(const char *name,
687 igraph_real_t value,
688 igraph_i_pajek_parsedata_t *context) {
689
690 return
691 igraph_i_pajek_add_numeric_attribute(context->edge_attribute_names,
692 context->edge_attributes,
693 context->actedge,
694 name, context->actedge-1,
695 value);
696 }
697
igraph_i_pajek_add_bipartite_type(igraph_i_pajek_parsedata_t * context)698 int igraph_i_pajek_add_bipartite_type(igraph_i_pajek_parsedata_t *context) {
699
700 const char *attrname="type";
701 igraph_trie_t *names=context->vertex_attribute_names;
702 igraph_vector_ptr_t *attrs=context->vertex_attributes;
703 int i, n=context->vcount, n1=context->vcount2;
704 long int attrid, attrsize=igraph_trie_size(names);
705 igraph_attribute_record_t *rec;
706 igraph_vector_t *na;
707
708 if (n1 > n) {
709 IGRAPH_ERROR("Invalid number of vertices in bipartite Pajek file",
710 IGRAPH_PARSEERROR);
711 }
712
713 igraph_trie_get(names, attrname, &attrid);
714 if (attrid != attrsize) {
715 IGRAPH_ERROR("Duplicate 'type' attribute in Pajek file, "
716 "this should not happen", IGRAPH_EINTERNAL);
717 }
718
719 /* add a new attribute */
720 rec=IGRAPH_CALLOC(1, igraph_attribute_record_t);
721 na=IGRAPH_CALLOC(1, igraph_vector_t);
722 igraph_vector_init(na, n);
723 rec->name=strdup(attrname);
724 rec->type=IGRAPH_ATTRIBUTE_NUMERIC;
725 rec->value=na;
726 igraph_vector_ptr_push_back(attrs, rec);
727
728 for (i=0; i<n1; i++) {
729 VECTOR(*na)[i] = 0;
730 }
731 for (i=n1; i<n; i++) {
732 VECTOR(*na)[i] = 1;
733 }
734
735 return 0;
736 }
737
igraph_i_pajek_check_bipartite(igraph_i_pajek_parsedata_t * context)738 int igraph_i_pajek_check_bipartite(igraph_i_pajek_parsedata_t *context) {
739 const igraph_vector_t *edges=context->vector;
740 int i, n1=context->vcount2;
741 int ne=igraph_vector_size(edges);
742
743 for (i=0; i<ne; i+=2) {
744 int v1=VECTOR(*edges)[i];
745 int v2=VECTOR(*edges)[i+1];
746 if ( (v1 < n1 && v2 < n1) || (v1 > n1 && v2 > n1) ) {
747 IGRAPH_WARNING("Invalid edge in bipartite graph");
748 }
749 }
750
751 return 0;
752 }
753