Add graph references

This commit is contained in:
Abdelrahman Said
2026-06-28 13:49:01 +01:00
parent 0a9807e448
commit a11edf0c53
2578 changed files with 868045 additions and 0 deletions
@@ -0,0 +1,203 @@
/*
igraph library.
Copyright (C) 2021 The igraph development team <igraph@igraph.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <igraph.h>
#include "test_utilities.h"
#include <stdlib.h>
void test_spanner(igraph_t *graph, igraph_vector_int_t *spanner, double stretch, igraph_vector_t *weights) {
igraph_int_t no_of_nodes = igraph_vcount(graph);
igraph_int_t no_of_edges = igraph_ecount(graph);
igraph_t spanner_graph;
igraph_vector_t spanner_weights;
igraph_matrix_t res_spanner, res_graph;
/* create the spanner graph with igraph_subgraph_from_edges() as recommended in the docs,
then compare it with the original graph and validate the stretch factor */
if (weights) {
igraph_cattribute_EAN_setv(graph, "weight", weights);
}
igraph_subgraph_from_edges(graph, &spanner_graph, igraph_ess_vector(spanner), 0);
igraph_vector_init(&spanner_weights, igraph_vector_int_size(spanner));
if (weights){
igraph_cattribute_EANV(&spanner_graph, "weight", igraph_ess_all(IGRAPH_EDGEORDER_ID), &spanner_weights);
} else {
igraph_vector_fill(&spanner_weights, 1);
}
// compare number of nodes
IGRAPH_ASSERT(igraph_vcount(&spanner_graph) == no_of_nodes);
// compare number of edges. We expect the number of edges to decrease in
// all cases but the trivial ones
if (stretch > 1 && no_of_edges > 1) {
IGRAPH_ASSERT(igraph_ecount(&spanner_graph) < no_of_edges);
}
// print the number of nodes, the number of original edges and the new edge
// count. This is not validated (there is no expected output) but it helps
// to gauge whether the algorithm is not simply keeping most of the edges
printf(
"%" IGRAPH_PRId ", %" IGRAPH_PRId " --> %" IGRAPH_PRId "\n",
no_of_nodes, no_of_edges, igraph_ecount(&spanner_graph)
);
// Validate the stretch factor
igraph_matrix_init(&res_spanner, 0, 0);
igraph_matrix_init(&res_graph, 0, 0);
igraph_distances(graph, weights, &res_graph, igraph_vss_all(), igraph_vss_all(), IGRAPH_ALL);
igraph_distances(&spanner_graph, &spanner_weights, &res_spanner, igraph_vss_all(), igraph_vss_all(), IGRAPH_ALL);
for (igraph_int_t x = 0; x < no_of_nodes; x++) {
for (igraph_int_t y = 0; y < no_of_nodes; y++) {
if (x == y) {
continue;
}
IGRAPH_ASSERT(MATRIX(res_spanner, x, y) <= MATRIX(res_graph, x, y) * stretch);
}
}
igraph_matrix_destroy(&res_graph);
igraph_matrix_destroy(&res_spanner);
// Clean up
igraph_vector_destroy(&spanner_weights);
igraph_destroy(&spanner_graph);
}
int main(void) {
igraph_t graph;
igraph_vector_t weights;
igraph_vector_int_t spanner;
igraph_int_t no_of_edges;
/* Initialize attribute handler; we will use edge attributes in test_spanner() */
igraph_set_attribute_table(&igraph_cattribute_table);
/* Seed the RNG to make the test output predictable */
igraph_rng_seed(igraph_rng_default(), 42);
/* Create the output vector -- this will be re-used several times */
igraph_vector_int_init(&spanner, 0);
/* Trivial spanner with stretch of one */
printf("Complete graph with stretch of one\n");
igraph_full(&graph, 20, IGRAPH_UNDIRECTED, 0);
igraph_spanner(&graph, &spanner, 1, NULL);
test_spanner(&graph, &spanner, 1, NULL);
igraph_destroy(&graph);
/* Test spanner for random weighted complete graph */
printf("Weighted complete graph with random weights and stretch = 10\n");
igraph_full(&graph, 20, IGRAPH_UNDIRECTED, 0);
no_of_edges = igraph_ecount(&graph);
igraph_vector_init(&weights, no_of_edges);
for (int i = 0; i < no_of_edges; i++) {
double generated_number = igraph_rng_get_unif(igraph_rng_default(), 1, 100);
VECTOR(weights)[i] = generated_number;
}
igraph_spanner(&graph, &spanner, 10, &weights);
test_spanner(&graph, &spanner, 10, &weights);
igraph_vector_destroy(&weights);
igraph_destroy(&graph);
/* Test spanner for unweighted complete graph */
printf("Unweighted complete graph with stretch = 5\n");
igraph_full(&graph, 20, IGRAPH_UNDIRECTED, 0);
igraph_spanner(&graph, &spanner, 5, NULL);
test_spanner(&graph, &spanner, 5, NULL);
igraph_destroy(&graph);
/* Random Erdos-Renyi graph */
printf("Random Erdos-Renyi graph\n");
igraph_erdos_renyi_game_gnp(&graph, 200, 0.25, IGRAPH_UNDIRECTED, IGRAPH_SIMPLE_SW, IGRAPH_EDGE_UNLABELED);
no_of_edges = igraph_ecount(&graph);
igraph_vector_init(&weights, no_of_edges);
for (igraph_int_t i = 0; i < no_of_edges; i++) {
double generated_number = igraph_rng_get_unif(igraph_rng_default(), 1, 100);
VECTOR(weights)[i] = generated_number;
}
igraph_spanner(&graph, &spanner, 7, &weights);
test_spanner(&graph, &spanner, 7, &weights);
igraph_vector_destroy(&weights);
igraph_destroy(&graph);
/* Geometric random graph */
printf("Geometric random graph, unweighted\n");
igraph_grg_game(&graph, 100, 0.2, /* torus = */ 0, 0, 0);
igraph_spanner(&graph, &spanner, 7, 0);
test_spanner(&graph, &spanner, 7, 0);
igraph_destroy(&graph);
/* Singleton graph */
printf("Singleton graph\n");
igraph_empty(&graph, 1, IGRAPH_UNDIRECTED);
igraph_spanner(&graph, &spanner, 2, 0);
test_spanner(&graph, &spanner, 2, 0);
igraph_destroy(&graph);
/* Null graph */
printf("Null graph\n");
igraph_empty(&graph, 0, IGRAPH_UNDIRECTED);
igraph_spanner(&graph, &spanner, 2, 0);
test_spanner(&graph, &spanner, 2, 0);
igraph_destroy(&graph);
VERIFY_FINALLY_STACK();
/* Error conditions */
igraph_set_error_handler(igraph_error_handler_ignore);
igraph_erdos_renyi_game_gnp(&graph, 200, 0.9, IGRAPH_UNDIRECTED, IGRAPH_SIMPLE_SW, IGRAPH_EDGE_UNLABELED);
no_of_edges = igraph_ecount(&graph);
igraph_vector_init(&weights, no_of_edges);
for (igraph_int_t i = 0; i < no_of_edges; i++) {
double generated_number = igraph_rng_get_unif(igraph_rng_default(), 1, 100);
VECTOR(weights)[i] = generated_number;
}
printf("Negative weight\n");
VECTOR(weights)[10] = -42;
IGRAPH_ASSERT(igraph_spanner(&graph, &spanner, 7, &weights) == IGRAPH_EINVAL);
VECTOR(weights)[10] = 42;
printf("NaN weight\n");
VECTOR(weights)[10] = IGRAPH_NAN;
IGRAPH_ASSERT(igraph_spanner(&graph, &spanner, 7, &weights) == IGRAPH_EINVAL);
VECTOR(weights)[10] = 42;
printf("Invalid spanning factor\n");
IGRAPH_ASSERT(igraph_spanner(&graph, &spanner, 0.5, &weights) == IGRAPH_EINVAL);
printf("Invalid weight vector length\n");
igraph_vector_resize(&weights, no_of_edges - 1);
IGRAPH_ASSERT(igraph_spanner(&graph, &spanner, 7, &weights) == IGRAPH_EINVAL);
igraph_vector_destroy(&weights);
igraph_destroy(&graph);
/* Regression test for https://github.com/igraph/igraph/issues/2487
* Edge directions should be ignored in directed graphs. */
igraph_rng_seed(igraph_rng_default(), 42);
igraph_small(&graph, 2, IGRAPH_DIRECTED, 0, 1, -1);
igraph_spanner(&graph, &spanner, 1.72, NULL);
igraph_destroy(&graph);
igraph_vector_int_destroy(&spanner);
return IGRAPH_SUCCESS;
}