diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2bc5abb..d03a231 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,24 +36,6 @@ jobs: - 'debian:12-slim' - 'fedora:37' steps: - # See https://github.com/shadow/tgen/issues/44#issuecomment-1693982909 - - name: Install debian:11 backports - if: ${{ matrix.container == 'debian:12-slim' }} - run: | - cat < /etc/apt/sources.list.d/bullseye.sources - Types: deb - URIs: http://deb.debian.org/debian - Suites: bullseye bullseye-updates - Components: main - Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg - - Types: deb - URIs: http://deb.debian.org/debian-security - Suites: bullseye-security - Components: main - Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg - EOF - - name: Update packages run: | case ${{ matrix.container }} in @@ -75,14 +57,6 @@ jobs: libglib2.0-dev \ libigraph-dev ;; - debian:12*) - # See https://github.com/shadow/tgen/issues/44#issuecomment-1693982909 - apt-get install -y \ - ${{ matrix.cc }} \ - cmake \ - libglib2.0-dev \ - libigraph-dev/bullseye - ;; debian*) apt-get install -y \ ${{ matrix.cc }} \ @@ -175,7 +149,7 @@ jobs: python3 -m venv build/toolsenv source build/toolsenv/bin/activate # Drastically improves time to install requirements on platforms with - # older pip in system backages, such as debian-10. + # older pip in system packages, such as debian-10. pip3 install --upgrade pip pip3 install -r tools/requirements.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d535f1..773b623 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,12 +16,7 @@ include(FindPkgConfig) find_package(RT REQUIRED) find_package(M REQUIRED) -# We don't yet support igraph 0.10.0+, which has some API changes. -# See https://github.com/shadow/tgen/issues/44 -# -# Older versions of cmake don't support the `<` operator here; only `<=`. -pkg_check_modules(IGRAPH REQUIRED igraph<=0.9.9999) - +pkg_check_modules(IGRAPH REQUIRED igraph) pkg_check_modules(GLIB REQUIRED glib-2.0) ## Parse out igraph version. Needed to work around breaking API changes in igraph. diff --git a/src/tgen-graph.c b/src/tgen-graph.c index c9c16c6..04266df 100644 --- a/src/tgen-graph.c +++ b/src/tgen-graph.c @@ -393,7 +393,8 @@ static GError* _tgengraph_parseGraphEdges(TGenGraph* g) { if(!error) { g->edgeCount = igraph_ecount(g->graph); if(g->edgeCount != edgeCount) { - tgen_warning("igraph_vcount %d does not match iterator count %d", g->edgeCount, edgeCount); + tgen_warning("igraph_vcount %ld does not match iterator count %ld", + (long int) g->edgeCount, (long int) edgeCount); } tgen_info("%u graph edges ok", (guint) g->edgeCount); @@ -416,15 +417,15 @@ static gboolean _tgengraph_hasSelfLoop(TGenGraph* g, igraph_integer_t vertexInde TGEN_ASSERT(g); gboolean isLoop = FALSE; - igraph_vector_t* resultNeighborVertices = g_new0(igraph_vector_t, 1); - gint result = igraph_vector_init(resultNeighborVertices, 0); + igraph_vector_int_t* resultNeighborVertices = g_new0(igraph_vector_int_t, 1); + gint result = igraph_vector_int_init(resultNeighborVertices, 0); if(result == IGRAPH_SUCCESS) { result = igraph_neighbors(g->graph, resultNeighborVertices, vertexIndex, IGRAPH_OUT); if(result == IGRAPH_SUCCESS) { - glong nVertices = igraph_vector_size(resultNeighborVertices); + glong nVertices = igraph_vector_int_size(resultNeighborVertices); for (gint i = 0; i < nVertices; i++) { - igraph_integer_t dstVertexIndex = igraph_vector_e(resultNeighborVertices, i); + igraph_integer_t dstVertexIndex = igraph_vector_int_get(resultNeighborVertices, i); if(vertexIndex == dstVertexIndex) { isLoop = TRUE; break; @@ -433,7 +434,7 @@ static gboolean _tgengraph_hasSelfLoop(TGenGraph* g, igraph_integer_t vertexInde } } - igraph_vector_destroy(resultNeighborVertices); + igraph_vector_int_destroy(resultNeighborVertices); g_free(resultNeighborVertices); return isLoop; } @@ -442,10 +443,10 @@ static glong _tgengraph_countIncomingEdges(TGenGraph* g, igraph_integer_t vertex /* Count up the total number of incoming edges */ /* initialize a vector to hold the result neighbor vertices for this action */ - igraph_vector_t* resultNeighborVertices = g_new0(igraph_vector_t, 1); + igraph_vector_int_t* resultNeighborVertices = g_new0(igraph_vector_int_t, 1); /* initialize with 0 entries, since we dont know how many neighbors we have */ - gint result = igraph_vector_init(resultNeighborVertices, 0); + gint result = igraph_vector_int_init(resultNeighborVertices, 0); if(result != IGRAPH_SUCCESS) { tgen_critical("igraph_vector_init return non-success code %i", result); g_free(resultNeighborVertices); @@ -456,17 +457,17 @@ static glong _tgengraph_countIncomingEdges(TGenGraph* g, igraph_integer_t vertex result = igraph_neighbors(g->graph, resultNeighborVertices, vertexIndex, IGRAPH_IN); if(result != IGRAPH_SUCCESS) { tgen_critical("igraph_neighbors return non-success code %i", result); - igraph_vector_destroy(resultNeighborVertices); + igraph_vector_int_destroy(resultNeighborVertices); g_free(resultNeighborVertices); return -1; } /* handle the results */ - glong totalIncoming = igraph_vector_size(resultNeighborVertices); + glong totalIncoming = igraph_vector_int_size(resultNeighborVertices); tgen_debug("found %li incoming 1-hop neighbors to vertex %li", totalIncoming, (glong)vertexIndex); /* cleanup */ - igraph_vector_destroy(resultNeighborVertices); + igraph_vector_int_destroy(resultNeighborVertices); g_free(resultNeighborVertices); return totalIncoming; @@ -1068,10 +1069,11 @@ static GError* _tgengraph_parseGraphVertices(TGenGraph* g) { if(!error) { g->vertexCount = igraph_vcount(g->graph); if(g->vertexCount != vertexCount) { - tgen_warning("igraph_vcount %d does not match iterator count %d", g->vertexCount, vertexCount); + tgen_warning("igraph_vcount %ld does not match iterator count %ld", + (long int) g->vertexCount, (long int) vertexCount); } - tgen_info("%u graph vertices ok", (guint) g->vertexCount); + tgen_info("%ld graph vertices ok", (long int) g->vertexCount); } return error; @@ -1091,10 +1093,10 @@ static GError* _tgengraph_parseGraphProperties(TGenGraph* g) { "igraph_is_connected return non-success code %i", result); } - result = igraph_clusters(g->graph, NULL, NULL, &(g->clusterCount), IGRAPH_WEAK); + result = igraph_connected_components(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); + "igraph_connected_components return non-success code %i", result); } /* it must be connected */ @@ -1109,13 +1111,13 @@ static GError* _tgengraph_parseGraphProperties(TGenGraph* g) { /* now check list of all attributes */ igraph_strvector_t gnames, vnames, enames; - igraph_vector_t gtypes, vtypes, etypes; + igraph_vector_int_t gtypes, vtypes, etypes; igraph_strvector_init(&gnames, 25); - igraph_vector_init(>ypes, 25); + igraph_vector_int_init(>ypes, 25); igraph_strvector_init(&vnames, 25); - igraph_vector_init(&vtypes, 25); + igraph_vector_int_init(&vtypes, 25); igraph_strvector_init(&enames, 25); - igraph_vector_init(&etypes, 25); + igraph_vector_int_init(&etypes, 25); result = igraph_cattribute_list(g->graph, &gnames, >ypes, &vnames, &vtypes, &enames, &etypes); if(result != IGRAPH_SUCCESS) { @@ -1125,16 +1127,16 @@ static GError* _tgengraph_parseGraphProperties(TGenGraph* g) { GError* error = NULL; gint i = 0; - for(i = 0; !error && i < igraph_strvector_size(&gnames); i++) { - gchar* name = NULL; - igraph_strvector_get(&gnames, (glong) i, &name); + #ifdef DEBUG + for(i = 0; !error && i < igraph_strvector_size(&gnames); i++) { + const gchar* name = igraph_strvector_get(&gnames, (igraph_integer_t) i); tgen_debug("found graph attribute '%s'", name); } + #endif for(i = 0; !error && i < igraph_strvector_size(&vnames); i++) { - gchar* name = NULL; - igraph_strvector_get(&vnames, (glong) i, &name); + const gchar* name = igraph_strvector_get(&vnames, (igraph_integer_t) i); tgen_debug("found vertex attribute '%s'", name); @@ -1150,8 +1152,7 @@ static GError* _tgengraph_parseGraphProperties(TGenGraph* g) { } for(i = 0; !error && i < igraph_strvector_size(&enames); i++) { - gchar* name = NULL; - igraph_strvector_get(&enames, (glong) i, &name); + const gchar* name = igraph_strvector_get(&enames, (igraph_integer_t) i); tgen_debug("found edge attribute '%s'", name); @@ -1167,11 +1168,11 @@ static GError* _tgengraph_parseGraphProperties(TGenGraph* g) { } igraph_strvector_destroy(&gnames); - igraph_vector_destroy(>ypes); + igraph_vector_int_destroy(>ypes); igraph_strvector_destroy(&vnames); - igraph_vector_destroy(&vtypes); + igraph_vector_int_destroy(&vtypes); igraph_strvector_destroy(&enames); - igraph_vector_destroy(&etypes); + igraph_vector_int_destroy(&etypes); if(error) { tgen_warning("failed to verify graph properties and attributes"); @@ -1271,9 +1272,6 @@ TGenGraph* tgengraph_new(gchar* path) { * from multiple threads at the same time. this is not a problem when shadow * uses dlmopen to get a private namespace for each plugin. */ - /* use the built-in C attribute handler */ - igraph_attribute_table_t* oldHandler = igraph_set_attribute_table(&igraph_cattribute_table); - g->graph = _tgengraph_loadNewGraph(g->graphPath); if(!g->graph) { error = g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, @@ -1290,9 +1288,6 @@ TGenGraph* tgengraph_new(gchar* path) { if(!error) { error = _tgengraph_parseGraphVertices(g); } - - /* replace the old handler */ - igraph_set_attribute_table(oldHandler); } if(error) { @@ -1332,10 +1327,10 @@ GQueue* tgengraph_getNextActionIDs(TGenGraph* g, TGenActionID actionID) { igraph_integer_t srcVertexIndex = (igraph_integer_t) actionID; /* initialize a vector to hold the result neighbor vertices for this action */ - igraph_vector_t* resultNeighborVertices = g_new0(igraph_vector_t, 1); + igraph_vector_int_t* resultNeighborVertices = g_new0(igraph_vector_int_t, 1); /* initialize with 0 entries, since we dont know how many neighbors we have */ - gint result = igraph_vector_init(resultNeighborVertices, 0); + gint result = igraph_vector_int_init(resultNeighborVertices, 0); if(result != IGRAPH_SUCCESS) { tgen_critical("igraph_vector_init return non-success code %i", result); g_free(resultNeighborVertices); @@ -1346,13 +1341,13 @@ GQueue* tgengraph_getNextActionIDs(TGenGraph* g, TGenActionID actionID) { result = igraph_neighbors(g->graph, resultNeighborVertices, srcVertexIndex, IGRAPH_OUT); if(result != IGRAPH_SUCCESS) { tgen_critical("igraph_neighbors return non-success code %i", result); - igraph_vector_destroy(resultNeighborVertices); + igraph_vector_int_destroy(resultNeighborVertices); g_free(resultNeighborVertices); return NULL; } /* handle the results */ - glong nVertices = igraph_vector_size(resultNeighborVertices); + glong nVertices = igraph_vector_int_size(resultNeighborVertices); tgen_debug("found %li outgoing neighbors from vertex %li", nVertices, (glong)srcVertexIndex); /* only follow one edge of all edges with the 'weight' attribute (do a weighted choice) @@ -1364,7 +1359,7 @@ GQueue* tgengraph_getNextActionIDs(TGenGraph* g, TGenActionID actionID) { for (gint i = 0; i < nVertices; i++) { /* we have source, get destination */ - igraph_integer_t dstVertexIndex = igraph_vector_e(resultNeighborVertices, i); + igraph_integer_t dstVertexIndex = igraph_vector_int_get(resultNeighborVertices, i); TGenAction* nextAction = _tgengraph_getAction(g, dstVertexIndex); if(!nextAction) { @@ -1378,7 +1373,7 @@ GQueue* tgengraph_getNextActionIDs(TGenGraph* g, TGenActionID actionID) { result = igraph_get_eid(g->graph, &edgeIndex, srcVertexIndex, dstVertexIndex, IGRAPH_DIRECTED, TRUE); if(result != IGRAPH_SUCCESS) { tgen_critical("igraph_get_eid return non-success code %i", result); - igraph_vector_destroy(resultNeighborVertices); + igraph_vector_int_destroy(resultNeighborVertices); g_free(resultNeighborVertices); g_queue_free(nextActions); g_queue_free(chooseActions); @@ -1425,7 +1420,7 @@ GQueue* tgengraph_getNextActionIDs(TGenGraph* g, TGenActionID actionID) { } /* cleanup */ - igraph_vector_destroy(resultNeighborVertices); + igraph_vector_int_destroy(resultNeighborVertices); g_free(resultNeighborVertices); g_queue_free(chooseActions); g_queue_free(chooseWeights); diff --git a/src/tgen-igraph-compat.h b/src/tgen-igraph-compat.h index 799be0c..d8b41fc 100644 --- a/src/tgen-igraph-compat.h +++ b/src/tgen-igraph-compat.h @@ -5,9 +5,30 @@ #ifndef TGEN_IGRAPH_COMPAT_H_ #define TGEN_IGRAPH_COMPAT_H_ -/* Renamed in in igraph 0.9.0 */ +/* Renamed in igraph 0.9.0 */ #if IGRAPH_VERSION_MAJOR==0 && IGRAPH_VERSION_MINOR<9 #define igraph_set_attribute_table igraph_i_set_attribute_table #endif +/* Changed in igraph 0.10.0 */ +#if IGRAPH_VERSION_MAJOR == 0 && IGRAPH_VERSION_MINOR < 10 +// Renamed +#define igraph_connected_components igraph_clusters +#define IGRAPH_ATTRIBUTE_UNSPECIFIED IGRAPH_ATTRIBUTE_DEFAULT +// Change to int types +#define igraph_vector_int_t igraph_vector_t +#define igraph_vector_int_init igraph_vector_init +#define igraph_vector_int_size igraph_vector_size +#define igraph_vector_int_get igraph_vector_e +#define igraph_vector_int_destroy igraph_vector_destroy +// Removed the name arg and return it instead +inline const char *igraph_strvector_get_compat(igraph_strvector_t *sv, + igraph_integer_t idx) { + char *name_ = NULL; + (igraph_strvector_get)(sv, idx, &name_); + return (const char *)name_; +} +#define igraph_strvector_get igraph_strvector_get_compat +#endif + #endif \ No newline at end of file diff --git a/src/tgen-main.c b/src/tgen-main.c index 592bc06..bf41e33 100644 --- a/src/tgen-main.c +++ b/src/tgen-main.c @@ -10,6 +10,7 @@ #include #include "tgen.h" +#include "tgen-igraph-compat.h" static void _tgenmain_cleanup(gint status, gpointer arg) { if(arg) { @@ -82,6 +83,9 @@ static gint _tgenmain_run(gint argc, gchar *argv[]) { tgen_message("Set SIG_IGN for signal SIGPIPE"); } + /* use the built-in C attribute handler. this is set once and then left alone. */ + igraph_set_attribute_table(&igraph_cattribute_table); + /* parse the config file */ TGenGraph* graph = tgengraph_new(argv[1]); if (!graph) { diff --git a/src/tgen-markovmodel.c b/src/tgen-markovmodel.c index 4fc5e79..e0a8ba7 100644 --- a/src/tgen-markovmodel.c +++ b/src/tgen-markovmodel.c @@ -109,7 +109,7 @@ static gboolean tgenmarkovmodel_attributeTypeMismatch(const igraph_t *graph, igr tgen_warning("Internal error: igraph_cattribute_table.gettype missing; unable to validate attribute types"); return FALSE; } - igraph_attribute_type_t type = IGRAPH_ATTRIBUTE_DEFAULT; + igraph_attribute_type_t type = IGRAPH_ATTRIBUTE_UNSPECIFIED; if (igraph_cattribute_table.gettype(graph, &type, elemtype, name) != IGRAPH_SUCCESS) { // The igraph documentation says it'll abort on any error, but in case // it doesn't, error out here. @@ -880,10 +880,6 @@ static igraph_t* _tgenmarkovmodel_loadGraph(FILE* graphFileStream, const gchar* rewind(graphFileStream); igraph_t* graph = g_new0(igraph_t, 1); - - /* make sure we use the correct attribute handler */ - igraph_set_attribute_table(&igraph_cattribute_table); - result = igraph_read_graph_graphml(graph, graphFileStream, 0); if (result != IGRAPH_SUCCESS) { diff --git a/test/test-markovmodel.c b/test/test-markovmodel.c index 819f88a..63b3961 100644 --- a/test/test-markovmodel.c +++ b/test/test-markovmodel.c @@ -2,7 +2,9 @@ #include #include +#include +#include "tgen-igraph-compat.h" #include "tgen-log.h" #include "tgen-markovmodel.h" @@ -87,6 +89,9 @@ gint main(gint argc, gchar *argv[]) { return EXIT_FAILURE; } + /* use the built-in C attribute handler. this is set once and then left alone. */ + igraph_set_attribute_table(&igraph_cattribute_table); + guint32 seed = (guint32)atoi(argv[1]); gchar* path = g_strdup(argv[2]); gchar* name = g_path_get_basename(path);