int main() {
  
  igraph_t g;
  igraph_strvector_t names;

  igraph_i_set_attribute_table(&igraph_cattribute_table);
  
  /* save a simple ring graph */
  igraph_ring(&g, 10, IGRAPH_DIRECTED, 0 /* mutual */, 1 /* circular */);
  igraph_write_graph_pajek(&g, stdout);
  
  /* add some vertex attributes */
  igraph_strvector_init(&names, 0);
  igraph_strvector_add(&names, "A");
  igraph_strvector_add(&names, "B");
  igraph_strvector_add(&names, "C");
  igraph_strvector_add(&names, "D");
  igraph_strvector_add(&names, "E");
  igraph_strvector_add(&names, "F");
  igraph_strvector_add(&names, "G");
  igraph_strvector_add(&names, "H");
  igraph_strvector_add(&names, "I");
  igraph_strvector_add(&names, "J");
  SETVASV(&g, "id", &names);
  igraph_strvector_destroy(&names);

  /* save the graph with vertex names */
  igraph_write_graph_pajek(&g, stdout);

  igraph_strvector_init(&names, 0);
  igraph_strvector_add(&names, "square");
  igraph_strvector_add(&names, "square");
  igraph_strvector_add(&names, "square");
  igraph_strvector_add(&names, "square");
  igraph_strvector_add(&names, "escaping spaces");
  igraph_strvector_add(&names, "square");
  igraph_strvector_add(&names, "square");
  igraph_strvector_add(&names, "escaping \\backslashes\\");
  igraph_strvector_add(&names, "square");
  igraph_strvector_add(&names, "escaping \"quotes\"");
  SETVASV(&g, "shape", &names);
  igraph_strvector_destroy(&names);

  /* save the graph with escaped shapes */
  igraph_write_graph_pajek(&g, stdout);

  /* destroy the graph */
  igraph_destroy(&g);
  return 0;
}
Beispiel #2
0
int main() {

  igraph_strvector_t sv1, sv2;
  char *str1;
  int i;

  /* igraph_strvector_init, igraph_strvector_destroy */
  igraph_strvector_init(&sv1, 10);
  igraph_strvector_destroy(&sv1);
  igraph_strvector_init(&sv1, 0);
  igraph_strvector_destroy(&sv1);

  /* igraph_strvector_get, igraph_strvector_set */
  igraph_strvector_init(&sv1, 5);
  for (i=0; i<igraph_strvector_size(&sv1); i++) {
    igraph_strvector_get(&sv1, i, &str1);
    printf("---%s---\n", str1);
  }
  igraph_strvector_set(&sv1, 0, "zero");
  igraph_strvector_set(&sv1, 1, "one");
  igraph_strvector_set(&sv1, 2, "two");
  igraph_strvector_set(&sv1, 3, "three");
  igraph_strvector_set(&sv1, 4, "four");
  for (i=0; i<igraph_strvector_size(&sv1); i++) {
    igraph_strvector_get(&sv1, i, &str1);
    printf("---%s---\n", str1);
  }

  /* igraph_strvector_remove_section, igraph_strvector_remove, 
     igraph_strvector_resize, igraph_strvector_size */
  igraph_strvector_remove_section(&sv1, 0, 5);
  if (igraph_strvector_size(&sv1) != 0) {
    return 1;
  }
  igraph_strvector_resize(&sv1, 10);
  igraph_strvector_set(&sv1, 0, "zero");
  igraph_strvector_set(&sv1, 1, "one");
  igraph_strvector_set(&sv1, 2, "two");
  igraph_strvector_set(&sv1, 3, "three");
  igraph_strvector_set(&sv1, 4, "four");
  igraph_strvector_resize(&sv1, 5);
  for (i=0; i<igraph_strvector_size(&sv1); i++) {
    igraph_strvector_get(&sv1, i, &str1);
    printf("---%s---\n", str1);
  }
  igraph_strvector_resize(&sv1, 0);
  if (igraph_strvector_size(&sv1) != 0) {
    return 1;
  }
  igraph_strvector_resize(&sv1, 10);
  igraph_strvector_set(&sv1, 0, "zero");
  igraph_strvector_set(&sv1, 1, "one");
  igraph_strvector_set(&sv1, 2, "two");
  igraph_strvector_set(&sv1, 3, "three");
  igraph_strvector_set(&sv1, 4, "four");
  igraph_strvector_resize(&sv1, 5);
  for (i=0; i<igraph_strvector_size(&sv1); i++) {
    igraph_strvector_get(&sv1, i, &str1);
    printf("---%s---\n", str1);
  }  

  /* igraph_strvector_move_interval */
  igraph_strvector_move_interval(&sv1, 3, 5, 0);
  for (i=0; i<igraph_strvector_size(&sv1); i++) {
    igraph_strvector_get(&sv1, i, &str1);
    printf("---%s---\n", str1);
  }

  /* igraph_strvector_copy */
  igraph_strvector_copy(&sv2, &sv1);
  for (i=0; i<igraph_strvector_size(&sv2); i++) {
    igraph_strvector_get(&sv2, i, &str1);
    printf("---%s---\n", str1);
  }
  igraph_strvector_resize(&sv1, 0);
  igraph_strvector_destroy(&sv2);
  igraph_strvector_copy(&sv2, &sv1);
  if (igraph_strvector_size(&sv2) != 0) {
    return 2;
  }
  igraph_strvector_destroy(&sv2);

  /* igraph_strvector_add */
  igraph_strvector_add(&sv1, "zeroth");
  igraph_strvector_add(&sv1, "first");
  igraph_strvector_add(&sv1, "second");
  igraph_strvector_add(&sv1, "third");
  igraph_strvector_add(&sv1, "fourth");
  for (i=0; i<igraph_strvector_size(&sv1); i++) {
    igraph_strvector_get(&sv1, i, &str1);
    printf("---%s---\n", str1);
  }

  /* TODO: igraph_strvector_permdelete */
  /* TODO: igraph_strvector_remove_negidx */
  
  igraph_strvector_destroy(&sv1);

  /* append */
  printf("---\n");
  igraph_strvector_init(&sv1, 0);
  igraph_strvector_init(&sv2, 0);
  igraph_strvector_append(&sv1, &sv2);
  strvector_print(&sv1);
  printf("---\n");
  
  igraph_strvector_resize(&sv1, 3);
  igraph_strvector_append(&sv1, &sv2);
  strvector_print(&sv1);
  printf("---\n");   

  igraph_strvector_append(&sv2, &sv1);
  strvector_print(&sv2);
  printf("---\n");   
  
  igraph_strvector_set(&sv1, 0, "0");
  igraph_strvector_set(&sv1, 1, "1");
  igraph_strvector_set(&sv1, 2, "2");
  igraph_strvector_set(&sv2, 0, "3");
  igraph_strvector_set(&sv2, 1, "4");
  igraph_strvector_set(&sv2, 2, "5");
  igraph_strvector_append(&sv1, &sv2);
  strvector_print(&sv1);
  
  igraph_strvector_destroy(&sv1);
  igraph_strvector_destroy(&sv2);
  
  /* clear */
  igraph_strvector_init(&sv1, 3);
  igraph_strvector_set(&sv1, 0, "0");
  igraph_strvector_set(&sv1, 1, "1");
  igraph_strvector_set(&sv1, 2, "2");
  igraph_strvector_clear(&sv1);
  if (igraph_strvector_size(&sv1) != 0) {
    return 3;
  }
  igraph_strvector_resize(&sv1, 4);
  strvector_print(&sv1);
  igraph_strvector_set(&sv1, 0, "one");
  igraph_strvector_set(&sv1, 2, "two");
  strvector_print(&sv1);
  igraph_strvector_destroy(&sv1);

  /* STR */
  
  igraph_strvector_init(&sv1, 5);
  igraph_strvector_set(&sv1, 0, "one");
  igraph_strvector_set(&sv1, 1, "two");
  igraph_strvector_set(&sv1, 2, "three");
  igraph_strvector_set(&sv1, 3, "four");
  igraph_strvector_set(&sv1, 4, "five");
  strvector_print(&sv1);
  igraph_strvector_destroy(&sv1);

  if (!IGRAPH_FINALLY_STACK_EMPTY) return 4;
  
  return 0;
}
Beispiel #3
0
int ggen_write_graph(igraph_t *g, FILE *output)
{
	Agraph_t *cg;
	Agnode_t *f,*t;
	Agedge_t *edge;
	igraph_vector_ptr_t vertices;
	igraph_eit_t eit;
	int err;
	unsigned long i,j;
	unsigned long vcount = igraph_vcount(g);
	igraph_integer_t from,to;
	char name[GGEN_DEFAULT_NAME_SIZE];
	char *str = NULL;
	igraph_strvector_t gnames,vnames,enames;
	igraph_vector_t gtypes,vtypes,etypes;
	Agsym_t *attr;
	/* see warning below */
	igraph_error_handler_t *error_handler;

	err = igraph_vector_ptr_init(&vertices,vcount);
	if(err) return 1;

	/* WARNING: this should be changed if igraph-0.6 gets
	 * stable.
	 * We need to ignore some igraph_cattribute errors
	 * because we try to retrieve special attributes (ggen specifics).
	 * igraph version 0.6 include a cattribute_has_attr that should be
	 * used instead of ignoring errors.
	 */
	error_handler = igraph_set_error_handler(igraph_error_handler_ignore);

	/* open graph
	 * its name is saved in __ggen_graph_name if it exists
	 */
	str =(char *) GAS(g,GGEN_GRAPH_NAME_ATTR);
	if(!str)
		cg = agopen(GGEN_DEFAULT_GRAPH_NAME,Agdirected,NULL);
	else
		cg = agopen(str,Agdirected,NULL);

	if(!cg)
	{
		err = 1;
		goto d_v;
	}

	/* save a pointer to each vertex */
	for(i = 0; i < vcount; i++)
	{
		/* find a vertex name */
		str = vid2vname_unsafe(name,g,i);
		if(!str)
			f = agnode(cg,name,1);
		else
			f = agnode(cg,str,1);
		VECTOR(vertices)[i] = (void *)f;
	}

	/* We have finished with dangerous attributes accesses */
	igraph_set_error_handler(error_handler);

	/* now loop through edges in the igraph */
	err = igraph_eit_create(g,igraph_ess_all(IGRAPH_EDGEORDER_ID),&eit);
	if(err) goto c_ag;

	for(IGRAPH_EIT_RESET(eit); !IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit))
	{
		err = igraph_edge(g,IGRAPH_EIT_GET(eit),&from,&to);
		if(err) goto d_eit;

		f = (Agnode_t *) VECTOR(vertices)[(unsigned long)from];
		t = (Agnode_t *) VECTOR(vertices)[(unsigned long)to];
		agedge(cg,f,t,NULL,1);
	}

	/* find all properties */
	igraph_strvector_init(&gnames,1);
	igraph_strvector_init(&vnames,vcount);
	igraph_strvector_init(&enames,igraph_ecount(g));
	igraph_vector_init(&gtypes,1);
	igraph_vector_init(&vtypes,vcount);
	igraph_vector_init(&etypes,igraph_ecount(g));

	err = igraph_cattribute_list(g,&gnames,&gtypes,&vnames,&vtypes,&enames,&etypes);
	if(err) goto d_eit;

	/* add graph properties */
	for(i = 0; i < igraph_strvector_size(&gnames); i++)
	{
		if(strcmp(GGEN_GRAPH_NAME_ATTR,STR(gnames,i)))
		{
			if(VECTOR(gtypes)[i]==IGRAPH_ATTRIBUTE_NUMERIC) {
				snprintf(name,GGEN_DEFAULT_NAME_SIZE,"%f",
						(double)GAN(g,STR(gnames,i)));
				agattr(cg,AGRAPH,(char *)STR(gnames,i),name);
			}
			else
				agattr(cg,AGRAPH,(char *)STR(gnames,i),
						(char *)GAS(g,STR(gnames,i)));
		}
	}

	/* add vertex properties */
	for(i = 0; i < igraph_strvector_size(&vnames); i++)
	{
		if(strcmp(GGEN_VERTEX_NAME_ATTR,STR(vnames,i)))
		{
			/* creates the attribute but we still need to set it for each vertex */
			attr = agattr(cg,AGNODE,(char *)STR(vnames,i),GGEN_CGRAPH_DEFAULT_VALUE);
			for(j = 0; j < vcount; j++)
			{
				f = (Agnode_t *) VECTOR(vertices)[j];
				if(VECTOR(vtypes)[i]==IGRAPH_ATTRIBUTE_NUMERIC) {
					snprintf(name,GGEN_DEFAULT_NAME_SIZE,"%f",
							(double)VAN(g,STR(vnames,i),j));
					agxset(f,attr,name);
				}
				else
					agxset(f,attr,(char *)VAS(g,STR(vnames,i),j));
			}
		}
	}

	/* add edges properties */
	for(i = 0; i < igraph_strvector_size(&enames); i++)
	{
		/* creates the attribute but we still need to set it for each edge */
		attr = agattr(cg,AGEDGE,(char *)STR(enames,i),GGEN_CGRAPH_DEFAULT_VALUE);
		for(j = 0; j < igraph_ecount(g); j++)
		{
			igraph_edge(g,j,&from,&to);
			f = (Agnode_t *) VECTOR(vertices)[(unsigned long)from];
			t = (Agnode_t *) VECTOR(vertices)[(unsigned long)to];
			edge = agedge(cg,f,t,NULL,0);
			if(VECTOR(etypes)[i]==IGRAPH_ATTRIBUTE_NUMERIC) {
				snprintf(name,GGEN_DEFAULT_NAME_SIZE,"%f",
						(double)EAN(g,STR(enames,i),j));
				agxset(edge,attr,name);
			}
			else
				agxset(edge,attr,(char *)EAS(g,STR(enames,i),j));
		}
	}

	/* write the graph */
	err = agwrite(cg,(void *)output);
d_eit:
	igraph_eit_destroy(&eit);
c_ag:
	agclose(cg);
d_v:
	igraph_vector_ptr_destroy(&vertices);
	return err;
}
Beispiel #4
0
static GError* _tgengraph_parseGraphProperties(TGenGraph* g) {
    TGEN_ASSERT(g);
    gint result = 0;

    tgen_debug("checking graph properties...");

    /* IGRAPH_WEAK means the undirected version of the graph is connected
     * IGRAPH_STRONG means a vertex can reach all others via a directed path */
    result = igraph_is_connected(g->graph, &(g->isConnected), IGRAPH_WEAK);
    if(result != IGRAPH_SUCCESS) {
        return g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
                "igraph_is_connected return non-success code %i", result);
    }

    igraph_integer_t clusterCount;
    result = igraph_clusters(g->graph, NULL, NULL, &(g->clusterCount), IGRAPH_WEAK);
    if(result != IGRAPH_SUCCESS) {
        return g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
                "igraph_clusters return non-success code %i", result);
    }

    /* it must be connected */
    if(!g->isConnected || g->clusterCount > 1) {
        return g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
                "graph must be but is not connected");
    }

    g->isDirected = igraph_is_directed(g->graph);

    tgen_debug("checking graph attributes...");

    /* now check list of all attributes */
    igraph_strvector_t gnames, vnames, enames;
    igraph_vector_t gtypes, vtypes, etypes;
    igraph_strvector_init(&gnames, 25);
    igraph_vector_init(&gtypes, 25);
    igraph_strvector_init(&vnames, 25);
    igraph_vector_init(&vtypes, 25);
    igraph_strvector_init(&enames, 25);
    igraph_vector_init(&etypes, 25);

    result = igraph_cattribute_list(g->graph, &gnames, &gtypes, &vnames, &vtypes, &enames, &etypes);
    if(result != IGRAPH_SUCCESS) {
        return g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
                "igraph_cattribute_list return non-success code %i", result);
    }

    gint i = 0;
    for(i = 0; i < igraph_strvector_size(&gnames); i++) {
        gchar* name = NULL;
        igraph_strvector_get(&gnames, (glong) i, &name);

        tgen_debug("found graph attribute '%s'", name);
    }
    for(i = 0; i < igraph_strvector_size(&vnames); i++) {
        gchar* name = NULL;
        igraph_strvector_get(&vnames, (glong) i, &name);

        tgen_debug("found vertex attribute '%s'", name);
        g->knownAttributes |= _tgengraph_vertexAttributeToFlag(name);
    }
    for(i = 0; i < igraph_strvector_size(&enames); i++) {
        gchar* name = NULL;
        igraph_strvector_get(&enames, (glong) i, &name);

        tgen_debug("found edge attribute '%s'", name);
        g->knownAttributes |= _tgengraph_edgeAttributeToFlag(name);
    }

    igraph_strvector_destroy(&gnames);
    igraph_vector_destroy(&gtypes);
    igraph_strvector_destroy(&vnames);
    igraph_vector_destroy(&vtypes);
    igraph_strvector_destroy(&enames);
    igraph_vector_destroy(&etypes);

    tgen_info("successfully verified graph properties and attributes");

    return NULL;
}
Beispiel #5
0
int print_attributes(const igraph_t *g) {

  igraph_vector_t gtypes, vtypes, etypes;
  igraph_strvector_t gnames, vnames, enames;
  long int i;

  igraph_vector_t vec;
  igraph_strvector_t svec;
  long int j;

  igraph_vector_init(&gtypes, 0);
  igraph_vector_init(&vtypes, 0);
  igraph_vector_init(&etypes, 0);
  igraph_strvector_init(&gnames, 0);
  igraph_strvector_init(&vnames, 0);
  igraph_strvector_init(&enames, 0);

  igraph_cattribute_list(g, &gnames, &gtypes, &vnames, &vtypes, 
			 &enames, &etypes);

  /* Graph attributes */
  for (i=0; i<igraph_strvector_size(&gnames); i++) {
    printf("%s=", STR(gnames, i));
    if (VECTOR(gtypes)[i]==IGRAPH_ATTRIBUTE_NUMERIC) {
      igraph_real_printf(GAN(g, STR(gnames,i)));
      putchar(' ');
    } else {
      printf("\"%s\" ", GAS(g, STR(gnames,i)));
    }
  }
  printf("\n");

  for (i=0; i<igraph_vcount(g); i++) {
    long int j;
    printf("Vertex %li: ", i);
    for (j=0; j<igraph_strvector_size(&vnames); j++) {
      printf("%s=", STR(vnames, j));
      if (VECTOR(vtypes)[j]==IGRAPH_ATTRIBUTE_NUMERIC) {
	igraph_real_printf(VAN(g, STR(vnames,j), i));
	putchar(' ');
      } else {
	printf("\"%s\" ", VAS(g, STR(vnames,j), i));
      }
    }
    printf("\n");
  }

  for (i=0; i<igraph_ecount(g); i++) {
    long int j;
    printf("Edge %li (%i-%i): ", i, (int)IGRAPH_FROM(g,i), (int)IGRAPH_TO(g,i));
    for (j=0; j<igraph_strvector_size(&enames); j++) {
      printf("%s=", STR(enames, j));
      if (VECTOR(etypes)[j]==IGRAPH_ATTRIBUTE_NUMERIC) {
	igraph_real_printf(EAN(g, STR(enames, j), i));
	putchar(' ');
      } else {
	printf("\"%s\" ", EAS(g, STR(enames, j), i));
      }
    }
    printf("\n");
  }

  /* Check vector-based query functions */
  igraph_vector_init(&vec, 0);
  igraph_strvector_init(&svec, 0);
  
  for (j=0; j<igraph_strvector_size(&vnames); j++) {
    if (VECTOR(vtypes)[j]==IGRAPH_ATTRIBUTE_NUMERIC) {
      igraph_cattribute_VANV(g, STR(vnames, j), igraph_vss_all(), &vec);
      for (i=0; i<igraph_vcount(g); i++) {
	igraph_real_t num=VAN(g, STR(vnames, j), i);
	if (num != VECTOR(vec)[i] &&
	    (!isnan(num) || !isnan(VECTOR(vec)[i]))) {
	  exit(51);
	}
      }
    } else {
      igraph_cattribute_VASV(g, STR(vnames, j), igraph_vss_all(), &svec);
      for (i=0; i<igraph_vcount(g); i++) {
	const char *str=VAS(g, STR(vnames, j), i);
	if (strcmp(str,STR(svec, i))) {
	  exit(52);
	}
      }
    }
  }

  for (j=0; j<igraph_strvector_size(&enames); j++) {
    if (VECTOR(etypes)[j]==IGRAPH_ATTRIBUTE_NUMERIC) {
      igraph_cattribute_EANV(g, STR(enames, j), 
			     igraph_ess_all(IGRAPH_EDGEORDER_ID), &vec);
      for (i=0; i<igraph_ecount(g); i++) {
	igraph_real_t num=EAN(g, STR(enames, j), i);
	if (num != VECTOR(vec)[i] && 
	    (!isnan(num) || !isnan(VECTOR(vec)[i]))) {
	  exit(53);
	}
      }
    } else {
      igraph_cattribute_EASV(g, STR(enames, j), 
			     igraph_ess_all(IGRAPH_EDGEORDER_ID), &svec);
      for (i=0; i<igraph_ecount(g); i++) {
	const char *str=EAS(g, STR(enames, j), i);
	if (strcmp(str,STR(svec, i))) {
	  exit(54);
	}
      }
    }
  }

  igraph_strvector_destroy(&svec);
  igraph_vector_destroy(&vec);

  igraph_strvector_destroy(&enames);
  igraph_strvector_destroy(&vnames);
  igraph_strvector_destroy(&gnames);
  igraph_vector_destroy(&etypes);
  igraph_vector_destroy(&vtypes);
  igraph_vector_destroy(&gtypes);

  return 0;
}
Beispiel #6
0
int main() {
  
  igraph_t g, g2;
  FILE *ifile;
  igraph_vector_t gtypes, vtypes, etypes;
  igraph_strvector_t gnames, vnames, enames;
  long int i;
  igraph_vector_t y;
  igraph_strvector_t id;
  char str[20];

  /* turn on attribute handling */
  igraph_i_set_attribute_table(&igraph_cattribute_table);
  
  ifile=fopen("LINKS.NET", "r");
  if (ifile==0) {
    return 10;
  }
  igraph_read_graph_pajek(&g, ifile);
  fclose(ifile);

  igraph_vector_init(&gtypes, 0);
  igraph_vector_init(&vtypes, 0);
  igraph_vector_init(&etypes, 0);
  igraph_strvector_init(&gnames, 0);
  igraph_strvector_init(&vnames, 0);
  igraph_strvector_init(&enames, 0);
  
  igraph_cattribute_list(&g, &gnames, &gtypes, &vnames, &vtypes, 
			 &enames, &etypes);
  
  /* List attribute names and types */
  printf("Graph attributes: ");
  for (i=0; i<igraph_strvector_size(&gnames); i++) {
    printf("%s (%i) ", STR(gnames, i), (int)VECTOR(gtypes)[i]);
  }
  printf("\n");
  printf("Vertex attributes: ");
  for (i=0; i<igraph_strvector_size(&vnames); i++) {
    printf("%s (%i) ", STR(vnames, i), (int)VECTOR(vtypes)[i]);
  }
  printf("\n");
  printf("Edge attributes: ");
  for (i=0; i<igraph_strvector_size(&enames); i++) {
    printf("%s (%i) ", STR(enames, i), (int)VECTOR(etypes)[i]);
  }
  printf("\n");

  print_attributes(&g);

  /* Copying a graph */
  igraph_copy(&g2, &g);
  print_attributes(&g2);
  igraph_destroy(&g2);
  
  /* Adding vertices */
  igraph_add_vertices(&g, 3, 0);
  print_attributes(&g);

  /* Adding edges */
  igraph_add_edge(&g, 1, 1);
  igraph_add_edge(&g, 2, 5);
  igraph_add_edge(&g, 3, 6);
  print_attributes(&g);

  /* Deleting vertices */
  igraph_delete_vertices(&g, igraph_vss_1(1));
  igraph_delete_vertices(&g, igraph_vss_1(4));
  print_attributes(&g);

  /* Deleting edges */
  igraph_delete_edges(&g, igraph_ess_1(igraph_ecount(&g)-1));
  igraph_delete_edges(&g, igraph_ess_1(0));
  print_attributes(&g);

  /* Set graph attributes */
  SETGAN(&g, "id", 10);
  if (GAN(&g, "id") != 10) {
    return 11;
  }
  SETGAS(&g, "name", "toy");
  if (strcmp(GAS(&g, "name"), "toy")) {
    return 12;
  }
  
  /* Delete graph attributes */
  DELGA(&g, "id");
  DELGA(&g, "name");
  igraph_cattribute_list(&g, &gnames, 0,0,0,0,0);
  if (igraph_strvector_size(&gnames) != 0) {
    return 14;
  }  

  /* Delete vertex attributes */
  DELVA(&g, "x");
  DELVA(&g, "shape");
  DELVA(&g, "xfact");
  DELVA(&g, "yfact");
  igraph_cattribute_list(&g, 0,0, &vnames, 0,0,0);  
  if (igraph_strvector_size(&vnames) != 2) {
    return 15;
  }
  
  /* Delete edge attributes */
  igraph_cattribute_list(&g, 0,0,0,0,&enames,0);
  i=igraph_strvector_size(&enames);
  DELEA(&g, "hook1");
  DELEA(&g, "hook2"); 
  DELEA(&g, "label");
  igraph_cattribute_list(&g, 0,0,0,0,&enames,0);
  if (igraph_strvector_size(&enames) != i-3) {
    return 16;
  }
  
  /* Set vertex attributes */
  SETVAN(&g, "y", 0, -1);
  SETVAN(&g, "y", 1, 2.1);
  if (VAN(&g, "y", 0) != -1 || 
      VAN(&g, "y", 1) != 2.1) {
    return 17;
  }
  SETVAS(&g, "id", 0, "foo");
  SETVAS(&g, "id", 1, "bar");
  if (strcmp(VAS(&g, "id", 0), "foo") ||
      strcmp(VAS(&g, "id", 1), "bar")) {
    return 18;
  }

  /* Set edge attributes */
  SETEAN(&g, "weight", 2, 100.0);
  SETEAN(&g, "weight", 0, -100.1);
  if (EAN(&g, "weight", 2) != 100.0 ||
      EAN(&g, "weight", 0) != -100.1) {
    return 19;
  }
  SETEAS(&g, "color", 2, "RED");
  SETEAS(&g, "color", 0, "Blue");
  if (strcmp(EAS(&g, "color", 2), "RED") ||
      strcmp(EAS(&g, "color", 0), "Blue")) {
    return 20;
  }      

  /* Set vector attributes as vector */
  igraph_vector_init(&y, igraph_vcount(&g));
  igraph_vector_fill(&y, 1.23);
  SETVANV(&g, "y", &y);
  igraph_vector_destroy(&y);
  for (i=0; i<igraph_vcount(&g); i++) {    
    if (VAN(&g, "y", i) != 1.23) {
      return 21;
    }
  }
  igraph_vector_init_seq(&y, 0, igraph_vcount(&g)-1);
  SETVANV(&g, "foobar", &y);
  igraph_vector_destroy(&y);
  for (i=0; i<igraph_vcount(&g); i++) {
    if (VAN(&g, "foobar", i) != i) {
      return 22;
    }
  }  
  
  igraph_strvector_init(&id, igraph_vcount(&g));
  for (i=0; i<igraph_vcount(&g); i++) {
    snprintf(str, sizeof(str)-1, "%li", i);
    igraph_strvector_set(&id, i, str);
  }
  SETVASV(&g, "foo", &id);
  igraph_strvector_destroy(&id);
  for (i=0; i<igraph_vcount(&g); i++) {
    printf("%s ", VAS(&g, "foo", i));
  }
  printf("\n");
  igraph_strvector_init(&id, igraph_vcount(&g));
  for (i=0; i<igraph_vcount(&g); i++) {
    snprintf(str, sizeof(str)-1, "%li", i);
    igraph_strvector_set(&id, i, str);
  }
  SETVASV(&g, "id", &id);
  igraph_strvector_destroy(&id);
  for (i=0; i<igraph_vcount(&g); i++) {
    printf("%s ", VAS(&g, "id", i));
  }
  printf("\n");  
  
  /* Set edge attributes as vector */
  igraph_vector_init(&y, igraph_ecount(&g));
  igraph_vector_fill(&y, 12.3);
  SETEANV(&g, "weight", &y);
  igraph_vector_destroy(&y);
  for (i=0; i<igraph_ecount(&g); i++) {    
    if (EAN(&g, "weight", i) != 12.3) {
      return 23;
    }
  }
  igraph_vector_init_seq(&y, 0, igraph_ecount(&g)-1);
  SETEANV(&g, "foobar", &y);
  igraph_vector_destroy(&y);
  for (i=0; i<igraph_ecount(&g); i++) {
    if (VAN(&g, "foobar", i) != i) {
      return 24;
    }
  }  
  
  igraph_strvector_init(&id, igraph_ecount(&g));
  for (i=0; i<igraph_ecount(&g); i++) {
    snprintf(str, sizeof(str)-1, "%li", i);
    igraph_strvector_set(&id, i, str);
  }
  SETEASV(&g, "foo", &id);
  igraph_strvector_destroy(&id);
  for (i=0; i<igraph_ecount(&g); i++) {
    printf("%s ", EAS(&g, "foo", i));
  }
  printf("\n");
  igraph_strvector_init(&id, igraph_ecount(&g));
  for (i=0; i<igraph_ecount(&g); i++) {
    snprintf(str, sizeof(str)-1, "%li", i);
    igraph_strvector_set(&id, i, str);
  }
  SETEASV(&g, "color", &id);
  igraph_strvector_destroy(&id);
  for (i=0; i<igraph_ecount(&g); i++) {
    printf("%s ", EAS(&g, "color", i));
  }
  printf("\n");    

  /* Delete all remaining attributes */
  DELALL(&g);
  igraph_cattribute_list(&g, &gnames, &gtypes, &vnames, &vtypes, &enames, &etypes);
  if (igraph_strvector_size(&gnames) != 0 ||
      igraph_strvector_size(&vnames) != 0 ||
      igraph_strvector_size(&enames) != 0) {
    return 25;
  }

  /* Destroy */
  igraph_vector_destroy(&gtypes);
  igraph_vector_destroy(&vtypes);
  igraph_vector_destroy(&etypes);  
  igraph_strvector_destroy(&gnames);
  igraph_strvector_destroy(&vnames);
  igraph_strvector_destroy(&enames);

  igraph_destroy(&g);

  return 0;
}
void igraph_i_graphml_add_attribute_key(const xmlChar** attrs, 
					struct igraph_i_graphml_parser_state *state) {
  xmlChar **it;
  igraph_trie_t *trie=0;
  igraph_vector_ptr_t *ptrvector=0;
  long int id;
  int ret;
  igraph_i_graphml_attribute_record_t *rec=
    igraph_Calloc(1, igraph_i_graphml_attribute_record_t);

  if (!state->successful) return;
   
   if (rec==0) { 
    igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, 
		 IGRAPH_ENOMEM);
    igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
    return;
  }
  IGRAPH_FINALLY(igraph_free, rec);
  for (it=(xmlChar**)attrs; *it; it+=2) {
    if (xmlStrEqual(*it, toXmlChar("id"))) {
      const char *id=(const char*)(*(it+1));
      rec->id=strdup(id);
    } else if (xmlStrEqual(*it, toXmlChar("attr.name"))) {
      const char *name=fromXmlChar(*(it+1));
      rec->record.name=strdup(name);
    } else if (xmlStrEqual(*it, toXmlChar("attr.type"))) {
      if (xmlStrEqual(*(it+1), (xmlChar*)"boolean")) { 
	rec->type=I_GRAPHML_BOOLEAN;
	rec->record.type=IGRAPH_ATTRIBUTE_NUMERIC;	    
      } else if (xmlStrEqual(*(it+1), toXmlChar("string"))) {
	rec->type=I_GRAPHML_STRING;
	rec->record.type=IGRAPH_ATTRIBUTE_STRING;
      } else if (xmlStrEqual(*(it+1), toXmlChar("float"))) { 
	rec->type=I_GRAPHML_FLOAT;
	rec->record.type=IGRAPH_ATTRIBUTE_NUMERIC;
      } else if (xmlStrEqual(*(it+1), toXmlChar("double"))) { 
	rec->type=I_GRAPHML_DOUBLE;
	rec->record.type=IGRAPH_ATTRIBUTE_NUMERIC;
      } else if (xmlStrEqual(*(it+1), toXmlChar("int"))) {
	rec->type=I_GRAPHML_INTEGER;
	rec->record.type=IGRAPH_ATTRIBUTE_NUMERIC;
      } else if (xmlStrEqual(*(it+1), toXmlChar("long"))) {
	rec->type=I_GRAPHML_LONG;
	rec->record.type=IGRAPH_ATTRIBUTE_NUMERIC;
      } else {
	igraph_error("Cannot parse GraphML file, unknown attribute type", 
		     __FILE__, __LINE__, IGRAPH_PARSEERROR);
        igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file, unknown attribute type");
        return;
      }
    } else if (xmlStrEqual(*it, toXmlChar("for"))) {
      /* graph, vertex or edge attribute? */
      if (xmlStrEqual(*(it+1), toXmlChar("graph"))) { 
	trie=&state->g_names;
	ptrvector=&state->g_attrs;
      } else if (xmlStrEqual(*(it+1), toXmlChar("node"))) {
	trie=&state->v_names;
	ptrvector=&state->v_attrs;
      } else if (xmlStrEqual(*(it+1), toXmlChar("edge"))) {
	trie=&state->e_names;
	ptrvector=&state->e_attrs;
      } else {
	igraph_error("Cannot parse GraphML file, unknown attribute type",
		     __FILE__, __LINE__, IGRAPH_PARSEERROR);
        igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file, unknown attribute type");
        return;
      }
    }
  }

  if (trie == 0 && state->successful) {
    igraph_error("Cannot parse GraphML file, missing 'for' attribute", __FILE__, __LINE__, IGRAPH_PARSEERROR);
    igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file, missing 'for' attribute");
    return;
  }
	
  /* add to trie, attribues */
  igraph_trie_get(trie, rec->id, &id);
  if (id != igraph_trie_size(trie)-1) {
    igraph_error("Cannot parse GraphML file, duplicate attribute", 
		 __FILE__, __LINE__, IGRAPH_PARSEERROR);
    igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file, duplicate attribute");
    return;
  }
  ret=igraph_vector_ptr_push_back(ptrvector, rec);
  if (ret) {
    igraph_error("Cannot read GraphML file", __FILE__, __LINE__, ret);
    igraph_i_graphml_sax_handler_error(state, "Cannot read GraphML file");
    return;
  }

  /* create the attribute values */
  switch (rec->record.type) {
    igraph_vector_t *vec;
    igraph_strvector_t *strvec;
  case IGRAPH_ATTRIBUTE_NUMERIC:
    vec=igraph_Calloc(1, igraph_vector_t);
    if (vec==0) {
      igraph_error("Cannot parse GraphML file", __FILE__, __LINE__,
		   IGRAPH_ENOMEM);
      igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
      return;
    }
    rec->record.value=vec;
    igraph_vector_init(vec, 0);    
    break;
  case IGRAPH_ATTRIBUTE_STRING:
    strvec=igraph_Calloc(1, igraph_strvector_t);
    if (strvec==0) {
      igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, 
		   IGRAPH_ENOMEM);
      igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
      return;
    }
    rec->record.value=strvec;
    igraph_strvector_init(strvec, 0);
    break;
  default: break;
  }

  IGRAPH_FINALLY_CLEAN(1);	/* rec */
}
void igraph_i_graphml_sax_handler_start_document(void *state0) {
  struct igraph_i_graphml_parser_state *state=
    (struct igraph_i_graphml_parser_state*)state0;
  int ret;
  
  state->st=START;
  state->successful=1;
  state->edges_directed=0;
  state->destroyed=0;
  state->data_key=0;
  state->error_message=0;
  state->data_char=0;
  
  ret=igraph_vector_ptr_init(&state->v_attrs, 0);
  if (ret) {
    igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, ret);
    igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
    return;
  }
  IGRAPH_FINALLY(igraph_vector_ptr_destroy, &state->v_attrs);
  ret=igraph_vector_ptr_init(&state->e_attrs, 0);
  if (ret) {
    igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, ret);
    igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
    return;
  }
  IGRAPH_FINALLY(igraph_vector_ptr_destroy, &state->e_attrs);
  ret=igraph_vector_ptr_init(&state->g_attrs, 0);
  if (ret) {
    igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, ret);
    igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
    return;
  }
  IGRAPH_FINALLY(igraph_vector_ptr_destroy, &state->g_attrs);
  ret=igraph_vector_init(&state->edgelist, 0);
  if (ret) {
    igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, ret);
    igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
    return;
  }
  IGRAPH_FINALLY(igraph_vector_destroy, &state->edgelist);
  ret=igraph_trie_init(&state->node_trie, 1);
  if (ret) {
    igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, ret);
    igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
    return;
  }
  IGRAPH_FINALLY(igraph_trie_destroy, &state->node_trie);
  ret=igraph_strvector_init(&state->edgeids, 0);
  if (ret) {
    igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, ret);
    igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
    return;
  }
  IGRAPH_FINALLY(igraph_strvector_destroy, &state->edgeids);
  ret=igraph_trie_init(&state->v_names, 0);
  if (ret) {
    igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, ret);
    igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
    return;
  }
  IGRAPH_FINALLY(igraph_trie_destroy, &state->v_names);
  ret=igraph_trie_init(&state->e_names, 0);
  if (ret) {
    igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, ret);
    igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
    return;
  }
  IGRAPH_FINALLY(igraph_trie_destroy, &state->e_names);
  ret=igraph_trie_init(&state->g_names, 0);
  if (ret) {
    igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, ret);
    igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
    return;
  }
  IGRAPH_FINALLY(igraph_trie_destroy, &state->g_names);
  
  IGRAPH_FINALLY_CLEAN(9);
  IGRAPH_FINALLY(igraph_i_graphml_destroy_state, state);
}