diff --git a/containers/graph.c b/containers/graph.c new file mode 100644 index 0000000..6c2f3d0 --- /dev/null +++ b/containers/graph.c @@ -0,0 +1,752 @@ +#include "graph.h" + +//TODO +// Test if graph_p != NULL + +#define GRAPH_MAX_NAME_LENGTH 256 + + +/** + * Creation and initialization + */ +graph_t* graph_new(char mask, int initial_num_vertices, int SYNC_MODE) +{ + graph_t *g = (graph_t*)malloc(sizeof(graph_t)); + + if((mask & GRAPH_MIXED_DIRECTED) == GRAPH_MIXED_DIRECTED) + g->directed = GRAPH_MIXED_DIRECTED; + else if(mask & GRAPH_DIRECTED) + g->directed = GRAPH_DIRECTED; + else + g->directed = GRAPH_NON_DIRECTED; //default value + + g->cyclic = (mask & GRAPH_ACYCLIC)? 0: 1; + //g->multiple = (mask & GRAPH_MULTIPLE)? 1: 0; + g->multiple = 0; + g->strict = mask & GRAPH_STRICT; + g->non_negative = mask & GRAPH_NON_NEGATIVE_WEIGHT; + + g->num_edges = 0; + g->num_vertices = 0; + + g->sync_mode = SYNC_MODE; + g->vertices = array_list_new(initial_num_vertices,1.5,SYNC_MODE); + g->removed_vertices = linked_list_new (SYNC_MODE); + g->dict = kh_init(gr); + + return g; + +} +/** + * Destruction + */ + +int graph_free(void (*vertex_data_callback) (void* vertex_data), void (*edge_data_callback) (void* edge_data), graph_t* graph_p) +{ + graph_clear(vertex_data_callback,edge_data_callback,graph_p); + array_list_free(graph_p->vertices, NULL); + linked_list_free(graph_p->removed_vertices, NULL); + kh_destroy(gr, graph_p->dict); + free(graph_p); +} + + +int graph_clear(void (*vertex_data_callback) (void* vertex_data), void (*edge_data_callback) (void* edge_data), graph_t* graph_p) +{ + int i; + vertex_t *v; + edge_t* e; + linked_list_iterator_t *iter; + + if(graph_p->num_vertices) + iter = (linked_list_iterator_t *)malloc(sizeof(linked_list_iterator_t)); + + for (i = 0; i < graph_p->num_vertices; i++) + { + + v = (vertex_t*)array_list_get(i, graph_p->vertices); + if(v->src == NULL){ + free(v); + continue; + } + if(edge_data_callback) + { + iter = linked_list_iterator_init(v->dst, iter); // free dst data + e = (edge_t*) linked_list_iterator_curr(iter); + + while (e != NULL) + { + edge_data_callback(e->data); + e = (edge_t*)linked_list_iterator_next(iter); + } + + + iter = linked_list_iterator_init(v->nd, iter); // free nd data and edge (only when e->src_id==-1, else sets to -1) + e = (edge_t*) linked_list_iterator_curr(iter); + while (e != NULL) + { + if(e->src_id != -1) + e->src_id = -1; + else{ + edge_data_callback(e->data); + free(e); + } + e = (edge_t*)linked_list_iterator_next(iter); + + } + } + else + { + iter = linked_list_iterator_init(v->nd, iter); // free nd edge (only when e->src_id==-1, else sets to -1) + e = (edge_t*) linked_list_iterator_curr(iter); + while (e != NULL) + { + if(e->src_id != -1) + e->src_id = -1; + else + free(e); + + e = (edge_t*)linked_list_iterator_next(iter); + } + } + + linked_list_free(v->src, NULL); + linked_list_free(v->dst, free); // free dst edge + linked_list_free(v->nd, NULL); + + free(v->name); + if(vertex_data_callback) + vertex_data_callback(v->data); + + free(v); + + + } + if(graph_p->num_vertices) + linked_list_iterator_free(iter); + array_list_clear(graph_p->vertices, NULL); + linked_list_clear(graph_p->removed_vertices, NULL); + + kh_clear(gr, graph_p->dict); + graph_p->num_edges = 0; + graph_p->num_vertices = 0; + +} + +/** + * Vertex Functions + */ + + +int graph_find_vertex(char* name, graph_t* graph_p){ + + khiter_t k = kh_get(gr,graph_p->dict,name); + + if(k == kh_end(graph_p->dict)) //If it was not found, ret -1 + return -1; + else + return kh_value(graph_p->dict, k); +} + +vertex_t* graph_get_vertex_s(char* vertex_name, graph_t * graph_p) +{ + int id = graph_find_vertex(vertex_name, graph_p); + if(id < 0) + return NULL; + else + return graph_get_vertex_i(id, graph_p); +} +vertex_t* graph_get_vertex_i(int vertex_id, graph_t * graph_p) +{ + vertex_t* v = NULL; + + if (vertex_id < graph_p->num_vertices && vertex_id >= 0) + { + v = (vertex_t*)array_list_get(vertex_id, graph_p->vertices); + if (v != NULL) + if (v->src == NULL) // v is in the removed_vertex list + v = NULL; + } + return v; +} + +int graph_exists_vertex_s(char* name, graph_t* graph_p) +{ + int id = graph_find_vertex(name, graph_p); + if(id >= 0) + { + return graph_exists_vertex_i(id, graph_p); + } + else + return -1; +} + +int graph_exists_vertex_i(int id, graph_t* graph_p) +{ + if( (id < graph_p->num_vertices || id >= 0 ) && graph_get_vertex_i(id, graph_p) != NULL) + return 0; + else + return -1; +} + + +int graph_reachable_vertex(int src, int dst, graph_t* graph_p){ + + if(src == dst) + return 0; + + linked_list_t* queue = linked_list_new(graph_p->sync_mode); + vertex_t* v, *v_dst; + edge_t *e; + linked_list_iterator_t *iter = (linked_list_iterator_t*)malloc(sizeof(linked_list_iterator_t)); + int i, fin = 0, dst_id; + char *c = (char*)calloc(graph_p->num_vertices, sizeof(char)); + + v = graph_get_vertex_i(src, graph_p); + v_dst = graph_get_vertex_i(dst, graph_p); + if(v != NULL && v_dst != NULL) + { + linked_list_insert_last(v, queue); + c[v->id] = 1; + while(v = (vertex_t*)linked_list_remove_first(queue)) + { + linked_list_iterator_init(v->dst, iter); + e = (edge_t*)linked_list_iterator_curr(iter); + while(e != NULL) + { + if(c[e->dst_id]==0){ + if(e->dst_id == dst){ + fin = 1; + break; + } + linked_list_insert_last(graph_get_vertex_i(e->dst_id, graph_p),queue); + c[e->dst_id] = 1; + } + e=(edge_t*)linked_list_iterator_next(iter); + } + if(!fin){ + linked_list_iterator_init(v->nd, iter); + e = (edge_t*)linked_list_iterator_curr(iter); + while(e != NULL) + { + dst_id = (e->dst_id != v->id)? e->dst_id: e->src_id; + if(c[dst_id]==0){ + if(dst_id == dst){ + fin = 1; + break; + } + linked_list_insert_last(graph_get_vertex_i(dst_id, graph_p),queue); + c[dst_id] = 1; + } + e=(edge_t*)linked_list_iterator_next(iter); + } + } + } + } + linked_list_iterator_free(iter); + linked_list_free(queue, NULL); + free(c); + return fin-1; +} + + +/*! + * @abstract + * + * @return >= 0 : vertex index + * -1 : Error at array_list_insert + * -2 : Error at kh_put. It already exists on the hash_table + * -3 : Error name == NULL + */ +int graph_add_vertex(char* name, void* vertex_data, graph_t* graph_p){ + + vertex_t *v; + + if (name==NULL) + return -3; + + if (linked_list_size(graph_p->removed_vertices)) + { + v = linked_list_get_first(graph_p->removed_vertices); + linked_list_remove_first(graph_p->removed_vertices); + } + else + { + v = (vertex_t*)malloc(sizeof(vertex_t)); + if(array_list_insert(v, graph_p->vertices) == 0){ + free(v); + return -1; + } + + graph_p->num_vertices++; + v->id = array_list_size(graph_p->vertices)-1; + } + //int id = graph_find_vertex(name, g); // Even if it already exists, it has to create a new one + + + int ret; + khiter_t k = kh_put(gr, graph_p->dict, name, &ret); + if (!ret){ + free(v); + kh_del(gr, graph_p->dict, k); + return -2; + } + //Created && appended OK + + + v->data = vertex_data; + + v->src = linked_list_new(graph_p->sync_mode); + v->dst = linked_list_new(graph_p->sync_mode); + v->nd = linked_list_new(graph_p->sync_mode); + + int length = strnlen(name,GRAPH_MAX_NAME_LENGTH)+1; + v->name = (char*)malloc(length); + strncpy(v->name, name, length); + + kh_value(graph_p->dict,k) = v->id; + + return v->id; +} + + +/** + * @return 0 OK + * -1 Not existing vertex + */ +int graph_remove_vertex_s(char* vertex_name, void (*vertex_data_callback) (void* vertex_data),void (*edge_data_callback) (void* edge_data), graph_t* graph_p) +{ + int vertex_id = graph_find_vertex(vertex_name,graph_p); + return graph_remove_vertex_i(vertex_id, vertex_data_callback, edge_data_callback, graph_p); +} +int graph_remove_vertex_i(int vertex_id, void (*vertex_data_callback) (void* vertex_data),void (*edge_data_callback) (void* edge_data), graph_t* graph_p) +{ + if(vertex_id < 0 || vertex_id >= graph_p->num_vertices) + return -1; + + vertex_t *v = graph_get_vertex_i(vertex_id, graph_p); + if(v == NULL) + return 0; + linked_list_iterator_t *iter = linked_list_iterator_new(v->src); + edge_t *e = (edge_t*)linked_list_iterator_curr(iter); + while(e != NULL) + { + linked_list_iterator_next(iter); + graph_remove_edge_e(e, GRAPH_DIRECTED, edge_data_callback, graph_p); + e = (edge_t*)linked_list_iterator_curr(iter); + } + + iter = linked_list_iterator_init(v->dst, iter); + e = linked_list_iterator_curr(iter); + while(e != NULL) + { + linked_list_iterator_next(iter); + graph_remove_edge_e(e, GRAPH_DIRECTED, edge_data_callback, graph_p); + e = (edge_t*)linked_list_iterator_curr(iter); + } + + iter = linked_list_iterator_init(v->nd, iter); + e = linked_list_iterator_curr(iter); + while(e != NULL) + { + linked_list_iterator_next(iter); + graph_remove_edge_e(e, GRAPH_NON_DIRECTED, edge_data_callback, graph_p); + e = (edge_t*)linked_list_iterator_curr(iter); + } + linked_list_iterator_free(iter); + + linked_list_free(v->src, NULL); + linked_list_free(v->dst, NULL); // free dst edge + linked_list_free(v->nd, NULL); + v->src = v->dst = v->nd = NULL; + + kh_del(gr,graph_p->dict, kh_get(gr,graph_p->dict, v->name)); + + free(v->name); + v->name = NULL; + if(vertex_data_callback) + vertex_data_callback(v->data); + v->data = NULL; + linked_list_insert(v, graph_p->removed_vertices); + + return 0; +} + +/** + * Edge Functions + */ + +int graph_add_edge_i(int src, int dst, void* edge_data, char edge_type, graph_t* graph_p) +{ + return graph_add_edge_iw(src, dst, edge_data, edge_type, 1, graph_p); +} +int graph_add_edge_s(char* src, char* dst, void* edge_data, char edge_type, graph_t* graph_p) +{ + return graph_add_edge_sw(src, dst, edge_data, edge_type, 1, graph_p); +} +int graph_add_edge_sw(char* src, char* dst, void* edge_data, char edge_type, float weight, graph_t* graph_p) +{ + int s = graph_find_vertex(src,graph_p); + int d = graph_find_vertex(dst,graph_p); + return graph_add_edge_iw(s, d, edge_data, edge_type, weight, graph_p); +} + +/** + * + * + * @return 0 : OK + * -1 : src or dst are not in graph + * -2 : edge_type non supported + * -3 : edge_type non compatible with the graph directed type + * -4 : edge breaks acyclity + * -5 : edge breaks multiplicity + * -6 : Weight must be possitive + */ +int graph_add_edge_iw(int src, int dst, void* edge_data, char edge_type, float weight, graph_t* graph_p){ + + //if(array_list_size(graph_p->vertices) <= src || array_list_size(graph_p->vertices) <= dst || src < 0 || dst < 0) + // return -1; + if (graph_get_vertex_i(src, graph_p) == NULL || graph_get_vertex_i(src, graph_p) == NULL) + return -1; + + + edge_t * e; + + //if(!graph_p->multiple) + if(graph_get_edge_i(src,dst,edge_type, graph_p) != NULL) + return -5; + + if(!graph_p->cyclic && graph_p->strict){//if acyclic + if(edge_type == GRAPH_NON_DIRECTED) + if(graph_reachable_vertex(src, dst, graph_p)==0) + return -4; + if(graph_reachable_vertex(dst, src, graph_p)==0) + return -4; + } + + if(graph_p->non_negative && weight < 0) //FIXME weight < 0 || weight <= 0 ?? + return -6; + + //if(graph_exists_vertex_i(src, graph_p) < 0 || graph_exists_vertex_i(dst, graph_p) < 0 ) + // return -6; + + e = (edge_t*)malloc(sizeof(edge_t)); + e->src_id = src; + e->dst_id = dst; + e->data = edge_data; + e->weight = weight; + + switch(edge_type)// TODO comprobacion multiple... + { + case GRAPH_DIRECTED: + if(graph_p->directed == GRAPH_NON_DIRECTED && graph_p->strict == GRAPH_STRICT){ + free(e); + return -3; + } + + linked_list_insert(e,(graph_get_vertex_i(src,graph_p))->dst); + linked_list_insert(e,(graph_get_vertex_i(dst,graph_p))->src); + break; + case GRAPH_NON_DIRECTED: + if(graph_p->directed == GRAPH_DIRECTED && graph_p->strict == GRAPH_STRICT){ + free(e); + return -3; + } + linked_list_insert(e,(graph_get_vertex_i(src,graph_p))->nd); + linked_list_insert(e,(graph_get_vertex_i(dst,graph_p))->nd); + + break; + default: + free(e); + return -2; + } + graph_p->num_edges++; + return 0; + +} + + + +edge_t* graph_get_edge_s(char* src, char* dst, char edge_type, graph_t* graph_p) +{ + int s = graph_find_vertex(src,graph_p); + int d = graph_find_vertex(dst,graph_p); + if(s >= 0 && d >= 0) //opt + return graph_get_edge_i(s,d,edge_type, graph_p); + else + return NULL; +} + + +edge_t* graph_get_edge_i(int src, int dst, char edge_type, graph_t* graph_p) +{ + linked_list_iterator_t *iter; + + if(graph_exists_vertex_i(src, graph_p) < 0 || graph_exists_vertex_i(dst, graph_p) < 0 ) + return NULL; + + vertex_t *v = graph_get_vertex_i(src,graph_p); + edge_t *e; + if(edge_type == GRAPH_DIRECTED) + { + iter = linked_list_iterator_new(v->dst); + e = (edge_t*)linked_list_iterator_curr(iter); + while(e != NULL) + { + if(e->dst_id == dst) + { + linked_list_iterator_free(iter); + return e; + } + e = (edge_t*)linked_list_iterator_next(iter); + } + linked_list_iterator_free(iter); + } + else if(edge_type == GRAPH_NON_DIRECTED){ + int nd_dst; + + iter = linked_list_iterator_new(v->nd); + e = (edge_t*)linked_list_iterator_curr(iter); + while(e != NULL) + { + nd_dst = (e->src_id==src)? e->dst_id: e->src_id; + if(nd_dst == dst) + { + linked_list_iterator_free(iter); + return e; + } + e = (edge_t*)linked_list_iterator_next(iter); + } + linked_list_iterator_free(iter); + } + return NULL; +} + + +/*linked_list_t* graph_get_edge(int src, int dst, char edge_type, graph_t* graph_p) +{ + linked_list_t *l = linked_list_new(graph_p->sync_mode); + if(array_list_size(graph_p->vertices) <= src || array_list_size(graph_p->vertices) <= dst || src < 0 || dst < 0) + return l; + + linked_list_iterator_t *iter; + + vertex_t *v = (vertex_t*)graph_get_vertex_i(src,graph_p); + edge_t *e; + if(edge_type & GRAPH_DIRECTED) + { + iter = linked_list_iterator_new(v->dst); + e = (edge_t*)linked_list_iterator_curr(iter); + while(e != NULL) + { + if(e->dst_id == dst) + { + linked_list_insert(e->data,l); + } + e = (edge_t*)linked_list_iterator_next(iter); + } + linked_list_iterator_free(iter); + } + if(edge_type & GRAPH_NON_DIRECTED) + { + int nd_dst; + + iter = linked_list_iterator_new(v->nd); + e = (edge_t*)linked_list_iterator_curr(iter); + while(e != NULL) + { + nd_dst = (e->src_id==src)? e->dst_id: e->src_id; + if(nd_dst == dst) + { + linked_list_insert(e->data,l); + } + e = (edge_t*)linked_list_iterator_next(iter); + } + linked_list_iterator_free(iter); + } + return l; +} +*/ + + +/** + * @return 0 OK + * -1 Edge doesn't exist + * -2 Corrupted edge + */ +int graph_remove_edge_s(char* src, char* dst, char edge_type, void (*edge_data_callback) (void* edge_data), graph_t* graph_p) +{ + edge_t* e = graph_get_edge_s( src, dst, edge_type, graph_p); + if(e!=NULL) + return graph_remove_edge_e(e,edge_type, edge_data_callback, graph_p); + else + return -1; +} +int graph_remove_edge_i(int src, int dst, char edge_type, void (*edge_data_callback) (void* edge_data), graph_t* graph_p) +{ + + edge_t *e = graph_get_edge_i( src, dst, edge_type, graph_p); + + if(e!=NULL) + return graph_remove_edge_e(e,edge_type, edge_data_callback, graph_p); + else + return -1; +} +int graph_remove_edge_e(edge_t *edge_p, char edge_type, void (*edge_data_callback) (void* edge_data), graph_t* graph_p) +{ + if(edge_p == NULL) + return -1; + + + linked_list_iterator_t *iter; + vertex_t *v_src = graph_get_vertex_i(edge_p->src_id, graph_p); + vertex_t *v_dst = graph_get_vertex_i(edge_p->dst_id, graph_p); + if(v_src == NULL || v_dst == NULL) + return -2; + if(edge_type & GRAPH_DIRECTED){ + linked_list_remove(edge_p, v_src->dst); + linked_list_remove(edge_p, v_dst->src); + } + else if(edge_type & GRAPH_NON_DIRECTED) + { + linked_list_remove(edge_p, v_src->nd); + linked_list_remove(edge_p, v_dst->nd); + } + if(edge_data_callback) + edge_data_callback(edge_p->data); + free(edge_p); + graph_p->num_edges--; + return 0; +} + + + + +/** + * Others + */ + +int graph_print(graph_t* graph_p) +{ + int i; + vertex_t *v; + edge_t* e; + linked_list_iterator_t *iter; + if(graph_p->num_vertices) + iter = (linked_list_iterator_t *)malloc(sizeof(linked_list_iterator_t)); + + for (i = 0; i < graph_p->num_vertices; i++) + { + v = graph_get_vertex_i(i, graph_p); + if(v == NULL) + continue; + printf("%s _____ id(%d)\n src\n", v->name, v->id); + + iter = linked_list_iterator_init(v->src, iter); + e = (edge_t*) linked_list_iterator_curr(iter); + while (e != NULL) + { + printf ("\t%s <- %s\n" + , (graph_get_vertex_i(e->dst_id, graph_p))->name + , (graph_get_vertex_i(e->src_id, graph_p))->name); + e = (edge_t*)linked_list_iterator_next(iter); + } + printf(" dst\n"); + + iter = linked_list_iterator_init(v->dst, iter); + e = (edge_t*) linked_list_iterator_curr(iter); + while (e != NULL) + { + printf ("\t%s -> %s\n" + , (graph_get_vertex_i(e->src_id, graph_p))->name + , (graph_get_vertex_i(e->dst_id, graph_p))->name); + e = (edge_t*)linked_list_iterator_next(iter); + } + printf(" nd\n"); + + iter = linked_list_iterator_init(v->nd, iter); + e = (edge_t*) linked_list_iterator_curr(iter); + while (e != NULL) + { + printf ("\t%s -- %s\n" + , (graph_get_vertex_i(e->src_id, graph_p))->name + , (graph_get_vertex_i(e->dst_id, graph_p))->name); + e = (edge_t*)linked_list_iterator_next(iter); + } + printf("\n"); + printf("\n"); + } + + if(graph_p->num_vertices) + linked_list_iterator_free(iter); +} + + + +int graph_print_dot(char* file_name, graph_t* graph_p) +{ + FILE *f; + int i; + vertex_t *v; + edge_t* e; + linked_list_iterator_t *iter; + + if(file_name == NULL) + f = stdout; + else + f = fopen(file_name, "w"); + + if(graph_p->num_vertices) + iter = (linked_list_iterator_t *)malloc(sizeof(linked_list_iterator_t)); + + fprintf(f,"digraph {\n"); + + for (i = 0; i < graph_p->num_vertices; i++) + { + v = graph_get_vertex_i(i, graph_p); + if(v == NULL) + continue; + + if(!linked_list_size(v->src) && !linked_list_size(v->dst) && !linked_list_size(v->nd)) + fprintf(f,"\t%s;\n", v->name); + + iter = linked_list_iterator_init(v->dst, iter); + e = (edge_t*) linked_list_iterator_curr(iter); + while (e != NULL) + { + fprintf(f,"\t%s -> %s [label=\"%.2f\"];\n" + , (graph_get_vertex_i(e->src_id, graph_p))->name + , (graph_get_vertex_i(e->dst_id, graph_p))->name + , e->weight); + e = (edge_t*)linked_list_iterator_next(iter); + } + + iter = linked_list_iterator_init(v->nd, iter); + e = (edge_t*) linked_list_iterator_curr(iter); + while (e != NULL) + { + if( e->src_id == v->id) + { + fprintf(f,"\t%s -> %s [dir=none,label=\"%.2f\"];\n" + , (graph_get_vertex_i(e->src_id, graph_p))->name + , (graph_get_vertex_i(e->dst_id, graph_p))->name + , e->weight); + } + e = (edge_t*)linked_list_iterator_next(iter); + } + } + fprintf(f,"}\n"); + if(file_name != NULL) + fclose(f); + if(graph_p->num_vertices) + linked_list_iterator_free(iter); +} + +int graph_get_order (graph_t* graph_p) +{ + return graph_p->num_vertices - linked_list_size(graph_p->removed_vertices); +} +int graph_get_size (graph_t* graph_p) +{ + return graph_p->num_edges; +} diff --git a/containers/graph.h b/containers/graph.h new file mode 100644 index 0000000..c78faf5 --- /dev/null +++ b/containers/graph.h @@ -0,0 +1,165 @@ + +/** + * graph.h + * + * Podemos dar la opcion a cambiar el tipo de grafo despues de crearlo, + * es decir, si se permite el cambio automatico/manual de modo de grafo "si" "no" "depende" + * + * + * //typedef int vertex_id; ?? + * + * + * Hitos 2013-06-20: + * Tipos de parametros (_s, _i, _...) + * Elimina Goood + * Parser salida Good (con peso en aristas) + * graph_go no recursivo + * + * TODO: + * Darle coherencia + * check + * Correcto sincronismo (sync_mode) + * + * DUDAS: + * #define GRAPH_STRICT 0b00010000 + * check no pasa el valgrind + * add vertex sin nombre?? + * opcion a dar el peso o no? add_edge_iw, add_edge_i, add_edge_sw, add_edge_w + */ + +#ifndef _GRAPH_H_ +#define _GRAPH_H_ + + +#include "linked_list.h" +#include "array_list.h" +#include "containers.h" +#include "khash.h" + +KHASH_MAP_INIT_STR(gr,int) + + +typedef struct edge { + int src_id; + int dst_id; + void *data; + float weight; + //char* name; + +} edge_t; + +typedef int vertex_id_t; + +typedef struct vertex { + void *data; + linked_list_t *src; + linked_list_t *dst; + linked_list_t *nd; + char* name; + vertex_id_t id; +} vertex_t; + +typedef struct graph { + khash_t(gr) *dict; + array_list_t *vertices; + linked_list_t *removed_vertices; + int num_vertices; //() + int num_edges; //() + + short int directed; //si, no y mixto + short int cyclic; + short int multiple; + short int strict; + short int non_negative; + //reemplazar todo por una mascara? + + int sync_mode; +} graph_t; + + + +#define GRAPH_NON_DIRECTED 0b00000001 +#define GRAPH_DIRECTED 0b00000010 +#define GRAPH_MIXED_DIRECTED 0b00000011 +#define GRAPH_CYCLIC 0b00000000 +#define GRAPH_ACYCLIC 0b00000100 +#define GRAPH_STRICT 0b00001000 +#define GRAPH_NON_NEGATIVE_WEIGHT 0b00010000 +//#define GRAPH_MULTIPLE 0b00010000 + +/** + * Creation and initialization + */ +graph_t* graph_new(char mask, int initial_num_vertices, int SYNC_MODE); + +/** + * Destruction + */ + +int graph_free(void (*vertex_data_callback) (void* vertex_data), void (*edge_data_callback) (void* edge_data), graph_t*); + +int graph_clear(void (*vertex_data_callback) (void* vertex_data), void (*edge_data_callback) (void* edge_data), graph_t*); + +/** + * Vertex Functions + */ +int graph_add_vertex(char* name, void* vertex_data, graph_t*); + +int graph_find_vertex(char* name, graph_t*); // assumes only one ocurrence + +int graph_exists_vertex_s(char* name, graph_t*); +int graph_exists_vertex_i(int id, graph_t*); +//contains?? + +int graph_reachable_vertex(int src, int dst, graph_t*); + +vertex_t* graph_get_vertex_s(char* vertex_name, graph_t * graph_p); +vertex_t* graph_get_vertex_i(int vertex_id, graph_t * graph_p); + +void* graph_get_vertex_data_s(char* name, graph_t*); +void* graph_get_vertex_data_i(int id, graph_t*); +/* +linked_list_t* graph_vertex_neighborhood_s(char* name, graph_t*); +linked_list_t* graph_vertex_neighborhood_i(int id, graph_t*); + +linked_list_t* graph_vertex_neighborhood_out_s(char* name, graph_t*); +linked_list_t* graph_vertex_neighborhood_out_i(int id, graph_t*); + +linked_list_t* graph_vertex_neighborhood_in_s(char* name, graph_t*); +linked_list_t* graph_vertex_neighborhood_in_i(int id, graph_t*); +//adjacent +*/ + +int graph_remove_vertex_s(char* vertex_name, void (*vertex_data_callback) (void* vertex_data),void (*edge_data_callback) (void* edge_data), graph_t*); +int graph_remove_vertex_i(int vertex_id, void (*vertex_data_callback) (void* vertex_data),void (*edge_data_callback) (void* edge_data), graph_t*); + + +/** + * Edge Functions + */ +int graph_add_edge_s(char* src, char* dst, void* edge_data, char edge_type, graph_t*); +int graph_add_edge_i(int src, int dst, void* edge_data, char edge_type, graph_t*); +int graph_add_edge_sw(char* src, char* dst, void* edge_data, char edge_type, float weight, graph_t*); +int graph_add_edge_iw(int src, int dst, void* edge_data, char edge_type, float weight, graph_t*); + +int graph_remove_edge_s(char* src, char* dst, char edge_type, void (*edge_data_callback) (void* edge_data), graph_t*); +int graph_remove_edge_i(int src, int dst, char edge_type, void (*edge_data_callback) (void* edge_data), graph_t*); +int graph_remove_edge_e(edge_t *edge_p, char edge_type, void (*edge_data_callback) (void* edge_data), graph_t*); + +edge_t* graph_get_edge_s(char* src, char* dst, char edge_type, graph_t*); +edge_t* graph_get_edge_i(int src, int dst, char edge_type, graph_t*); + +/** + * Path Functions + */ +//linked_list_t* graph_path_get(int src, int dst, graph_t*); + +/** + * Others + */ +int graph_print(graph_t*); +int graph_print_dot(char* file_name, graph_t*); +int graph_get_order (graph_t*); // vertex number +int graph_get_size (graph_t*); // edge number + +#endif //_GRAPH_H_ diff --git a/containers/linked_list.c b/containers/linked_list.c index cc3d7d8..8b3bd98 100644 --- a/containers/linked_list.c +++ b/containers/linked_list.c @@ -79,7 +79,7 @@ size_t linked_list_index_of(void *item, linked_list_t *linked_list_p) { size_t i = 0; linked_list_item_t *curr_item = linked_list_p->first; while(curr_item != NULL) { - if(linked_list_p->compare_fn(curr_item, item) == 0) { + if(linked_list_p->compare_fn(curr_item->item, item) == 0) { ret_value = i; break; } @@ -103,7 +103,7 @@ int linked_list_contains(void *item, linked_list_t *linked_list_p) { int is_contained = 0; linked_list_item_t *curr_item = linked_list_p->first; while(curr_item != NULL) { - if(linked_list_p->compare_fn(curr_item, item) == 0) { + if(linked_list_p->compare_fn(curr_item->item, item) == 0) { is_contained = 1; break; } @@ -259,7 +259,41 @@ int linked_list_insert_all_at(size_t index, void** item_p, size_t num_items, lin void* linked_list_remove(void *item, linked_list_t *linked_list_p) { - return NULL; + assert(linked_list_p && item); + + if(linked_list_p->mode == COLLECTION_MODE_SYNCHRONIZED) { + pthread_mutex_lock(&linked_list_p->lock); + } + + linked_list_item_t* list_item = linked_list_p->first; + + while(list_item != NULL && list_item->item != item) { + list_item = list_item->next; + } + + if (list_item) { + if (list_item != linked_list_p->first) + list_item->prev->next = list_item->next; + else{ + if(linked_list_p->first = list_item->next) + list_item->next->prev = NULL; + } + if (list_item != linked_list_p->last) + list_item->next->prev = list_item->prev; + else{ + if(linked_list_p->last = list_item->prev) + list_item->prev->next = NULL; + } + + linked_list_p->size--; + + linked_list_item_free(list_item, NULL); + } + + if(linked_list_p->mode == COLLECTION_MODE_SYNCHRONIZED) { + pthread_mutex_unlock(&linked_list_p->lock); + } + return item; } void* linked_list_remove_first(linked_list_t *linked_list_p) { @@ -278,6 +312,8 @@ void* linked_list_remove_first(linked_list_t *linked_list_p) { if (linked_list_p->first) { linked_list_p->first->prev = NULL; } + else + linked_list_p->last = NULL; //jj linked_list_p->size--; item = list_item->item; linked_list_item_free(list_item, NULL); @@ -308,6 +344,8 @@ void* linked_list_remove_last(linked_list_t *linked_list_p) { if (linked_list_p->last) { linked_list_p->last->next = NULL; } + else + linked_list_p->first = NULL; //jj linked_list_p->size--; item = list_item->item; linked_list_item_free(list_item, NULL); @@ -327,6 +365,11 @@ void* linked_list_remove_at(size_t index, linked_list_t *linked_list_p) { void *item = NULL; if(index >= 0 && index < linked_list_p->size) { + if(index == 0) //jj + return linked_list_remove_first(linked_list_p); + if(index == linked_list_p->size-1) + return linked_list_remove_last(linked_list_p); + if(linked_list_p->mode == COLLECTION_MODE_SYNCHRONIZED) { pthread_mutex_lock(&linked_list_p->lock); } diff --git a/containers/test/SConscript b/containers/test/SConscript index a8aaf94..a60ef17 100644 --- a/containers/test/SConscript +++ b/containers/test/SConscript @@ -13,4 +13,27 @@ check_linked_list = env.Program('linked_list.test', source = ['linked_list_test.c', '%s/containers/linked_list.o' % commons_path ] - ) \ No newline at end of file + ) + + +env2 = Environment(CFLAGS = '-std=c99 -D_XOPEN_SOURCE=600 -D_GNU_SOURCE', + CPPPATH = ['#', commons_path, '/usr/include', '/usr/local/include', commons_path ], + LIBPATH = ['/usr/lib', '/usr/local/lib' ], + LIBS = ['check', 'curl', 'm', 'z', 'rt'] + ) +Import("debug") + +if debug == 1: + env2['CFLAGS'] += ' -O0 -g' +else: + env2['CFLAGS'] += ' -O3' + + +graph_time_test = env2.Program('graph_time_test', + ['graph_time_test.c', + '%s/commons/string_utils.o' % commons_path, + '%s/commons/log.o' % commons_path, + Glob('%s/containers/*.o' % commons_path), + Glob('%s/containers/cprops/*.o' % commons_path) + ] + ) diff --git a/containers/test/graph_test.c b/containers/test/graph_test.c new file mode 100644 index 0000000..8bbfc7d --- /dev/null +++ b/containers/test/graph_test.c @@ -0,0 +1,242 @@ + +#include +#include +#include + +#include "../graph.h" +graph_t *g; +Suite *create_test_suite(void); + +//************************** +// Checked fixtures * +//************************** + + +START_TEST(test_empty_graph) { + + g = graph_new(GRAPH_DIRECTED | GRAPH_CYCLIC, 20, COLLECTION_MODE_ASYNCHRONIZED); + + fail_if( graph_remove_vertex_i(0, NULL, NULL, g) != -1, "Removing inexistent vertex: return should be -1"); + fail_if( graph_remove_edge_i(0, 1, GRAPH_DIRECTED, NULL, g) != -1, "Removing inexistent vertex: return should be -1"); + fail_if( graph_remove_edge_i(0, 0, GRAPH_DIRECTED, NULL, g) != -1, "Removing inexistent vertex: return should be -1"); + + graph_free(NULL, NULL, g); +} +END_TEST + + +START_TEST(test_small_graph) { + + g = graph_new(GRAPH_DIRECTED | GRAPH_ACYCLIC |GRAPH_STRICT, 20, COLLECTION_MODE_ASYNCHRONIZED); + int ret = graph_add_vertex("A", NULL, g); + + fail_if( ret < 0, "add_vertex: return should be the new id but id=%d", ret); + ret = graph_add_vertex("B", NULL, g); + fail_if( ret < 0, "add_vertex: return should be the new id but id=%d", ret); + ret = graph_add_vertex("C", NULL, g); + fail_if( ret < 0, "add_vertex: return should be the new id but id=%d", ret); + + + ret = graph_add_edge_sw("A", "B", NULL, GRAPH_DIRECTED, 2, g); + fail_if( ret != 0, "add_vertex: return should be 0 but ret=%d", ret); + + ret = graph_add_edge_sw("D", "B", NULL, GRAPH_DIRECTED, 2, g); + fail_if( ret != -1, "add_vertex: non existent vertex: return should be -1 but ret=%d", ret); + + ret = graph_add_edge_sw("A", "C", NULL, 9, 2, g); + fail_if( ret != -2, "add_vertex: non supported edge type: return should be -2 but ret=%d", ret); + + ret = graph_add_edge_sw("C", "A", NULL, GRAPH_NON_DIRECTED, 2, g); + fail_if( ret != -3, "add_vertex: non compatible direction type: return should be -3 but ret=%d", ret); + + ret = graph_add_edge_sw("B", "B", NULL, GRAPH_DIRECTED, 2, g); + fail_if( ret != -4, "add_vertex: breaking acyclity: return should be -4 but ret=%d", ret); + + ret = graph_add_edge_sw("A", "B", NULL, GRAPH_DIRECTED, 2, g); + fail_if( ret != -5, "add_vertex: breaking multiplicity: return should be -5 but ret=%d", ret); + + ret = graph_add_edge_sw("C", "B", NULL, GRAPH_DIRECTED, 2, g); + fail_if( ret != 0, "add_vertex: return should be 0 but ret=%d", ret); + + //ret = graph_add_vertex(NULL, NULL, g); + //fail_if( ret < 10, "add_vertex: return should be the new id but id=%d", ret); + + graph_print(g); + + graph_print_dot("check_graph.gv", g); + + graph_free(NULL, NULL, g); +} +END_TEST + + +START_TEST(test_big_graph) { + +} +END_TEST + + +/* ****************************** + * Main entry point * + * ******************************/ + +int main (int argc, char *argv) { + Suite *fs = create_test_suite(); + SRunner *fs_runner = srunner_create(fs); + srunner_run_all(fs_runner, CK_NORMAL); + int number_failed = srunner_ntests_failed (fs_runner); + srunner_free (fs_runner); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + + +Suite *create_test_suite(void) { + TCase *tc_create_free = tcase_create("Create and free"); + + //tcase_add_checked_fixture(tc_create_free, create_graph, free_graph); + tcase_add_test(tc_create_free, test_empty_graph); + tcase_add_test(tc_create_free, test_small_graph); + tcase_add_test(tc_create_free, test_big_graph); + //tcase_add_test(tc_create_free, test_create_free); + + //TCase *tc_iterators = tcase_create("Iterators"); + //tcase_add_checked_fixture(tc_iterators, create_graph, free_graph); + //tcase_add_test(tc_iterators, test_iterators); + + // Add test cases to a test suite + Suite *fs = suite_create("Graph"); + suite_add_tcase(fs, tc_create_free); + //suite_add_tcase(fs, tc_iterators); + + return fs; +} + + + + + +/* + + + +#include +#include + +#include "../graph/graph.h" +graph_t *g; +void foo() +{ + + +} + +void free_cond(void* c) +{ + if(c) + free(c); +} + +void* new_mem(const char* c) +{ + return NULL; + char* v = malloc(20); + int i; + for(i = 0; i < 20 && c[i] != 0; i++) + v[i]=c[i]; + v[i] = 0; + return v; +} + +int main() +{ + printf("Holamundo\n"); + + g = graph_new(GRAPH_MIXED_DIRECTED | GRAPH_ACYCLIC, 20, COLLECTION_MODE_ASYNCHRONIZED); + + + graph_add_vertex("A", NULL, g); + graph_add_vertex("B", NULL, g); + graph_add_vertex("C", NULL, g); + graph_add_vertex("D", malloc(29), g); + + graph_add_edge_i(0,1, new_mem("Hola"), GRAPH_DIRECTED,2, g); + graph_add_edge_i(1,2, new_mem("Hola"), GRAPH_DIRECTED,2, g); + void* v = malloc(23); + if(graph_add_edge_i(2,0, v, GRAPH_DIRECTED,2, g)<0) + free(v); + + + graph_print(g); + printf("Clear\n"); + graph_clear(free_cond,free_cond,g); + + graph_add_vertex("A", NULL, g); + graph_add_vertex("S", NULL, g); + graph_add_vertex("D", NULL, g); + graph_add_vertex("F", NULL, g); + graph_add_vertex("G", NULL, g); + + graph_add_edge_s("A","S",NULL,GRAPH_DIRECTED,2,g); + graph_add_edge_s("S","D",NULL,GRAPH_DIRECTED,2,g); + graph_add_edge_s("S","D",NULL,GRAPH_DIRECTED,2,g); + graph_add_edge_s("G","D",NULL,GRAPH_DIRECTED,2,g); + graph_add_edge_s("A","D",NULL,GRAPH_NON_DIRECTED,2,g); + graph_add_edge_s("D","D",NULL,GRAPH_DIRECTED,2,g); + graph_add_edge_s("A","F",NULL,GRAPH_NON_DIRECTED,2,g); + + + graph_add_edge_s("F","G",new_mem("Pepe"),GRAPH_DIRECTED,2,g); + graph_add_edge_s("F","G",new_mem("Pepon"),GRAPH_DIRECTED,2,g); + graph_add_edge_s("F","G",new_mem("Null"),GRAPH_DIRECTED,2,g); + + + graph_add_edge_s("G","S",NULL,GRAPH_NON_DIRECTED,9,g); + graph_add_edge_s("F","S",NULL,GRAPH_DIRECTED,2,g); + + edge_t * e = graph_get_edge_i(3,4,GRAPH_DIRECTED,g); + if(e != NULL) + printf("Edge Tomado %s\n",(char*)e->data); + graph_remove_edge_e(e,GRAPH_DIRECTED,free_cond,g); + graph_remove_edge_s("A","S",GRAPH_DIRECTED,free_cond,g); + graph_remove_edge_s("A","Sasdfasd",GRAPH_DIRECTED,free_cond,g); + graph_remove_edge_s("A","G",GRAPH_DIRECTED,free_cond,g); + //printf("Edge Eliminado\n"); + + + //graph_print(g); + //printf("Go go to Eliminar vertice\n"); + //graph_remove_vertex_s("A",NULL,free_cond,g); + + //graph_add_vertex("GAUSON", NULL, g); +/* linked_list_iterator_t *iter = linked_list_iterator_new(l); + char* c = (char*)linked_list_iterator_curr(iter); + while(c != NULL) + { + printf("CHAR DEL LINKED : %s\n",c); + c = (char*)linked_list_iterator_next(iter); + + } + linked_list_iterator_free(iter); + linked_list_free(l, NULL); + */ + /* + graph_add_edge_s("GAUSON", "F", NULL, GRAPH_NON_DIRECTED,3.1415, g); + graph_add_edge_s("GAUSON", "F", NULL, GRAPH_DIRECTED,2, g); + graph_add_edge_s("F", "GAUSON", NULL, GRAPH_DIRECTED,1.618, g); + + + //graph_remove_vertex_s("dsfg",NULL,free_cond,g); + //graph_remove_vertex_s("S",NULL,free_cond,g); + + graph_print(g); + + graph_print_dot("grafo.gv",g); + + //printf("Existe camino entre 0 y 3? %d\n", graph_path_exists(0,3,g)); + + graph_free(NULL,free_cond,g); + + return 0; +} + +*/ diff --git a/containers/test/graph_time_test.c b/containers/test/graph_time_test.c new file mode 100644 index 0000000..d53f91d --- /dev/null +++ b/containers/test/graph_time_test.c @@ -0,0 +1,87 @@ +#include +//#include +#include "../graph.h" + +void stop_crono(char* mensaje, struct timespec * ini_time) +{ + struct timespec timedif, fin_time; + + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &fin_time);//----------------------- + timedif.tv_sec = fin_time.tv_sec - ini_time->tv_sec; + timedif.tv_nsec = fin_time.tv_nsec - ini_time->tv_nsec; + if (timedif.tv_nsec < 0) + { + timedif.tv_nsec += 1000000000; + timedif.tv_sec--; + } + printf(mensaje, (int)timedif.tv_sec, timedif.tv_nsec); +} + +int main (void) +{ + struct timespec ini_time; + + graph_t *g; + int num_vertices = 1000000; + int num_edges = 10000000; + int name_length = 255; + char ** names; + int i; + + srand(time(NULL)); + + names = (char**) malloc (sizeof(char*)*num_vertices); + + for (i = 0; i < num_vertices; i++) + { + //itoa(i, names[i], 10); + names[i] = (char*) malloc (sizeof(char)*name_length); + sprintf(names[i], "%d", i); + //printf ("name[%d] = %s\n", i, names[i]); + } + + printf("grafo con %d nodos\n", num_vertices); + + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ini_time);//+++++++++++++++++++++++++++++++++++ + + g = graph_new (GRAPH_CYCLIC | GRAPH_DIRECTED, num_vertices, COLLECTION_MODE_ASYNCHRONIZED); + + stop_crono("tiempo en crear el grafo: t = %d s y %ld ns\n", &ini_time);//----------------------- + + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ini_time);//++++++++++++++++++++++++++++++++++ + + for (i = 0; i < num_vertices; i++) + graph_add_vertex (names[i], NULL, g); + + stop_crono("tiempo rellenar vertices aleatorios: t = %d s y %ld ns\n", &ini_time);//----------------------- + + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ini_time);//+++++++++++++++++++++++++++++++++ + + for (i = 0; i < num_edges; i++) + graph_add_edge_iw(rand()%num_vertices, rand()%num_vertices, NULL, GRAPH_DIRECTED, 1, g); + + stop_crono("tiempo en relenar edges aleatorios = %d s y %ld ns\n", &ini_time);//----------------- + + printf("solo cumplian las condiciones %d edges\n", g->num_edges); + + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ini_time);//+++++++++++++++++++++++++++++++++++ + + graph_print_dot("grafo_tiempo.gv", g); + + stop_crono("tiempo en print dot: t = %d s y %ld ns\n", &ini_time);//----------------------- + + + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ini_time);//+++++++++++++++++++++++++++++++++++ + + graph_free(NULL, NULL, g); + + stop_crono("tiempo en liberar grafo: t = %d s y %ld ns\n", &ini_time);//----------------------- + + for (i = 0; i < num_vertices; i++) + free(names[i]); + + free (names); + + printf("\n"); + return 0; +} diff --git a/containers/test/linked_list_test.c b/containers/test/linked_list_test.c index 8a2fb0d..7fa8c25 100644 --- a/containers/test/linked_list_test.c +++ b/containers/test/linked_list_test.c @@ -47,6 +47,10 @@ START_TEST(test_insert_and_remove) { fail_if((int) linked_list_get_last(list) != 5, "Get: Position #5 (last) must contain number 5"); fail_if((int) linked_list_remove_first(list) != 0, "Remove: Position #0 (first) must contain number 0"); + fail_if((int) linked_list_insert_first(NULL, list) != 1, "Insert: Position #0"); + fail_if((int) linked_list_remove_at(0, list) != 0, "Remove: Position #0 must contain number 0"); + fail_if((int) linked_list_insert_last(NULL, list) != 1, "Insert: Position last"); + fail_if((int) linked_list_remove_at(linked_list_size(list)-1, list) != 0, "Remove: Position size-1(last) must contain number 0"); fail_if((int) linked_list_remove_last(list) != 5, "Remove: Position #5 (last) must contain number 5"); fail_if((int) linked_list_remove_at(2, list) != 3, "Remove: Position #2 must contain number 3");