progress
This commit is contained in:
@@ -9,6 +9,9 @@ add_executable(graphe main.c
|
|||||||
structs.c
|
structs.c
|
||||||
structs.h
|
structs.h
|
||||||
render.h
|
render.h
|
||||||
render.c)
|
render.c
|
||||||
|
algorithms.h
|
||||||
|
communities.c
|
||||||
|
louvain.c)
|
||||||
|
|
||||||
target_link_libraries(graphe SDL2::SDL2 m)
|
target_link_libraries(graphe SDL2::SDL2 m)
|
||||||
|
|||||||
48
algorithms.h
Normal file
48
algorithms.h
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
//
|
||||||
|
// Created by Tiago Batista Cardoso on 2/26/2026.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef GRAPHE_ALGORITHMS_H
|
||||||
|
#define GRAPHE_ALGORITHMS_H
|
||||||
|
|
||||||
|
#include "structs.h"
|
||||||
|
|
||||||
|
// -- k-clique communities
|
||||||
|
struct community_t {
|
||||||
|
int *members; // node ids in this community
|
||||||
|
int size;
|
||||||
|
};
|
||||||
|
typedef struct community_t community_t;
|
||||||
|
|
||||||
|
struct community_result_t {
|
||||||
|
community_t *communities;
|
||||||
|
int count;
|
||||||
|
int *node_community; // node_community[i] = community index of node i (-1 if none)
|
||||||
|
};
|
||||||
|
typedef struct community_result_t community_result_t;
|
||||||
|
|
||||||
|
community_result_t *find_k_clique_communities(const graph_t *graph, int k);
|
||||||
|
void free_community_result(community_result_t *result);
|
||||||
|
|
||||||
|
// -- louvain
|
||||||
|
struct louvain_result_t {
|
||||||
|
int *node_community; // node_community[i] = community id of node i
|
||||||
|
int count; // total number of communities
|
||||||
|
double modularity; // final modularity score
|
||||||
|
};
|
||||||
|
typedef struct louvain_result_t louvain_result_t;
|
||||||
|
|
||||||
|
louvain_result_t *compute_louvain(const graph_t *graph);
|
||||||
|
void free_louvain_result(louvain_result_t *result);
|
||||||
|
|
||||||
|
// -- hybrid algorithm
|
||||||
|
struct hybrid_result_t {
|
||||||
|
int *node_community; // node_community[i] = community id of node i
|
||||||
|
int count; // total number of communities
|
||||||
|
};
|
||||||
|
typedef struct hybrid_result_t hybrid_result_t;
|
||||||
|
|
||||||
|
hybrid_result_t *hybrid_community_detection(const graph_t *graph, int k);
|
||||||
|
void free_hybrid_result(hybrid_result_t *result);
|
||||||
|
|
||||||
|
#endif
|
||||||
166
communities.c
Normal file
166
communities.c
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
//
|
||||||
|
// Created by Tiago Batista Cardoso on 2/26/2026.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "algorithms.h"
|
||||||
|
|
||||||
|
static int has_edge(const graph_t *graph, int u, int v)
|
||||||
|
{
|
||||||
|
node_t *n = graph->adj_lists[u];
|
||||||
|
while (n) {
|
||||||
|
if (n->id == v)
|
||||||
|
return 1;
|
||||||
|
n = n->next;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int **list;
|
||||||
|
int count;
|
||||||
|
int capacity;
|
||||||
|
int k;
|
||||||
|
} clique_store_t;
|
||||||
|
|
||||||
|
static void store_clique(clique_store_t *store, int *current)
|
||||||
|
{
|
||||||
|
if (store->count >= store->capacity) {
|
||||||
|
store->capacity *= 2;
|
||||||
|
store->list =
|
||||||
|
realloc(store->list, store->capacity * sizeof(int *));
|
||||||
|
}
|
||||||
|
int *copy = malloc(store->k * sizeof(int));
|
||||||
|
memcpy(copy, current, store->k * sizeof(int));
|
||||||
|
store->list[store->count++] = copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void enumerate_cliques(const graph_t *graph, clique_store_t *store,
|
||||||
|
int *current, int depth, int start)
|
||||||
|
{
|
||||||
|
if (depth == store->k) {
|
||||||
|
store_clique(store, current);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int v = start; v < graph->n; v++) {
|
||||||
|
// v must be connected to all nodes already in current
|
||||||
|
int ok = 1;
|
||||||
|
for (int i = 0; i < depth; i++) {
|
||||||
|
if (!has_edge(graph, current[i], v)) {
|
||||||
|
ok = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!ok)
|
||||||
|
continue;
|
||||||
|
current[depth] = v;
|
||||||
|
enumerate_cliques(graph, store, current, depth + 1, v + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int uf_find(int *parent, int x)
|
||||||
|
{
|
||||||
|
while (parent[x] != x) {
|
||||||
|
parent[x] = parent[parent[x]];
|
||||||
|
x = parent[x];
|
||||||
|
}
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void uf_union(int *parent, int *rank, int a, int b)
|
||||||
|
{
|
||||||
|
a = uf_find(parent, a);
|
||||||
|
b = uf_find(parent, b);
|
||||||
|
if (a == b)
|
||||||
|
return;
|
||||||
|
if (rank[a] < rank[b]) {
|
||||||
|
int t = a;
|
||||||
|
a = b;
|
||||||
|
b = t;
|
||||||
|
}
|
||||||
|
parent[b] = a;
|
||||||
|
if (rank[a] == rank[b])
|
||||||
|
rank[a]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
community_result_t *find_k_clique_communities(const graph_t *graph, int k)
|
||||||
|
{
|
||||||
|
int n = graph->n;
|
||||||
|
|
||||||
|
// find all k-cliques
|
||||||
|
clique_store_t store = { .list = malloc(64 * sizeof(int *)),
|
||||||
|
.count = 0,
|
||||||
|
.capacity = 64,
|
||||||
|
.k = k };
|
||||||
|
int *current = malloc(k * sizeof(int));
|
||||||
|
enumerate_cliques(graph, &store, current, 0, 0);
|
||||||
|
free(current);
|
||||||
|
|
||||||
|
printf("[communities] found %d %d-cliques\n", store.count, k);
|
||||||
|
|
||||||
|
int *parent = malloc(store.count * sizeof(int));
|
||||||
|
int *rank = calloc(store.count, sizeof(int));
|
||||||
|
for (int i = 0; i < store.count; i++)
|
||||||
|
parent[i] = i;
|
||||||
|
|
||||||
|
for (int i = 0; i < store.count; i++) {
|
||||||
|
for (int j = i + 1; j < store.count; j++) {
|
||||||
|
// Count shared nodes
|
||||||
|
int shared = 0;
|
||||||
|
for (int a = 0; a < k; a++)
|
||||||
|
for (int b = 0; b < k; b++)
|
||||||
|
if (store.list[i][a] ==
|
||||||
|
store.list[j][b])
|
||||||
|
shared++;
|
||||||
|
if (shared >= k - 1)
|
||||||
|
uf_union(parent, rank, i, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
community_result_t *result = malloc(sizeof(community_result_t));
|
||||||
|
result->node_community = malloc(n * sizeof(int));
|
||||||
|
for (int i = 0; i < n; i++)
|
||||||
|
result->node_community[i] = -1;
|
||||||
|
|
||||||
|
for (int i = 0; i < store.count; i++) {
|
||||||
|
int community_id = uf_find(parent, i);
|
||||||
|
for (int j = 0; j < k; j++) {
|
||||||
|
int node = store.list[i][j];
|
||||||
|
result->node_community[node] = community_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int *id_map = malloc(store.count * sizeof(int));
|
||||||
|
memset(id_map, -1, store.count * sizeof(int));
|
||||||
|
int next_id = 0;
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
int c = result->node_community[i];
|
||||||
|
if (c == -1)
|
||||||
|
continue;
|
||||||
|
if (id_map[c] == -1)
|
||||||
|
id_map[c] = next_id++;
|
||||||
|
result->node_community[i] = id_map[c];
|
||||||
|
}
|
||||||
|
result->count = next_id;
|
||||||
|
printf("[communities] found %d communities\n", result->count);
|
||||||
|
|
||||||
|
// cleanup
|
||||||
|
for (int i = 0; i < store.count; i++)
|
||||||
|
free(store.list[i]);
|
||||||
|
free(store.list);
|
||||||
|
free(parent);
|
||||||
|
free(rank);
|
||||||
|
free(id_map);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_community_result(community_result_t *result)
|
||||||
|
{
|
||||||
|
if (!result)
|
||||||
|
return;
|
||||||
|
free(result->node_community);
|
||||||
|
free(result);
|
||||||
|
}
|
||||||
215
louvain.c
Normal file
215
louvain.c
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
//
|
||||||
|
// Created by Tiago Batista Cardoso on 2/26/2026.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include "algorithms.h"
|
||||||
|
|
||||||
|
// -- helper methods
|
||||||
|
|
||||||
|
// total number of edges
|
||||||
|
static int count_edges(const graph_t *graph)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
for (int i = 0; i < graph->n; i++) {
|
||||||
|
node_t *n = graph->adj_lists[i];
|
||||||
|
while (n) {
|
||||||
|
count++;
|
||||||
|
n = n->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count / 2; // undirected
|
||||||
|
}
|
||||||
|
|
||||||
|
// degree of node i
|
||||||
|
static int degree(const graph_t *graph, int i)
|
||||||
|
{
|
||||||
|
int d = 0;
|
||||||
|
node_t *n = graph->adj_lists[i];
|
||||||
|
while (n) {
|
||||||
|
d++;
|
||||||
|
n = n->next;
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sum of weights of edges from node i to community c
|
||||||
|
static double k_i_in(const graph_t *graph, int i, int c, int *community)
|
||||||
|
{
|
||||||
|
double sum = 0.0;
|
||||||
|
node_t *n = graph->adj_lists[i];
|
||||||
|
while (n) {
|
||||||
|
if (community[n->id] == c)
|
||||||
|
sum += 1.0;
|
||||||
|
n = n->next;
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sum of degrees of all nodes in community c
|
||||||
|
static double sigma_tot(const graph_t *graph, int c, int *community)
|
||||||
|
{
|
||||||
|
double sum = 0.0;
|
||||||
|
for (int i = 0; i < graph->n; i++)
|
||||||
|
if (community[i] == c)
|
||||||
|
sum += degree(graph, i);
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ΔQ = [ (k_i_in - sigma_tot * k_i / 2m) / m ]
|
||||||
|
static double delta_modularity(const graph_t *graph, int i, int c,
|
||||||
|
int *community, double m)
|
||||||
|
{
|
||||||
|
double ki = degree(graph, i);
|
||||||
|
double ki_in = k_i_in(graph, i, c, community);
|
||||||
|
double sig = sigma_tot(graph, c, community);
|
||||||
|
|
||||||
|
return (ki_in - (sig * ki) / (2.0 * m)) / m;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int phase1(const graph_t *graph, int *community, double m)
|
||||||
|
{
|
||||||
|
int n = graph->n;
|
||||||
|
int improved = 1;
|
||||||
|
int total_moves = 0;
|
||||||
|
|
||||||
|
while (improved) {
|
||||||
|
improved = 0;
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
int best_community = community[i];
|
||||||
|
double best_gain = 0.0;
|
||||||
|
|
||||||
|
// Collect neighboring communities
|
||||||
|
int *neighbor_communities = calloc(n, sizeof(int));
|
||||||
|
int nc_count = 0;
|
||||||
|
node_t *nb = graph->adj_lists[i];
|
||||||
|
while (nb) {
|
||||||
|
int c = community[nb->id];
|
||||||
|
// Check if already in list
|
||||||
|
int found = 0;
|
||||||
|
for (int x = 0; x < nc_count; x++)
|
||||||
|
if (neighbor_communities[x] == c) {
|
||||||
|
found = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!found)
|
||||||
|
neighbor_communities[nc_count++] = c;
|
||||||
|
nb = nb->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// temporarily remove i from its community
|
||||||
|
int old_community = community[i];
|
||||||
|
community[i] = -1;
|
||||||
|
|
||||||
|
// try moving i to each neighboring community
|
||||||
|
for (int x = 0; x < nc_count; x++) {
|
||||||
|
int c = neighbor_communities[x];
|
||||||
|
if (c == old_community)
|
||||||
|
continue;
|
||||||
|
double gain = delta_modularity(graph, i, c,
|
||||||
|
community, m) -
|
||||||
|
delta_modularity(graph, i,
|
||||||
|
old_community,
|
||||||
|
community, m);
|
||||||
|
if (gain > best_gain) {
|
||||||
|
best_gain = gain;
|
||||||
|
best_community = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
community[i] = best_community;
|
||||||
|
|
||||||
|
if (best_community != old_community) {
|
||||||
|
improved = 1;
|
||||||
|
total_moves++;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(neighbor_communities);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return total_moves;
|
||||||
|
}
|
||||||
|
|
||||||
|
static double compute_modularity(const graph_t *graph, int *community, double m)
|
||||||
|
{
|
||||||
|
int n = graph->n;
|
||||||
|
double Q = 0.0;
|
||||||
|
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
node_t *nb = graph->adj_lists[i];
|
||||||
|
while (nb) {
|
||||||
|
int j = nb->id;
|
||||||
|
if (community[i] == community[j])
|
||||||
|
Q += 1.0 - ((double)degree(graph, i) *
|
||||||
|
degree(graph, j)) /
|
||||||
|
(2.0 * m);
|
||||||
|
nb = nb->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Q / (2.0 * m);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int compact(int *community, int n)
|
||||||
|
{
|
||||||
|
int *map = malloc(n * sizeof(int));
|
||||||
|
memset(map, -1, n * sizeof(int));
|
||||||
|
int next = 0;
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
if (community[i] == -1)
|
||||||
|
continue;
|
||||||
|
if (map[community[i]] == -1)
|
||||||
|
map[community[i]] = next++;
|
||||||
|
community[i] = map[community[i]];
|
||||||
|
}
|
||||||
|
free(map);
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
louvain_result_t *compute_louvain(const graph_t *graph)
|
||||||
|
{
|
||||||
|
int n = graph->n;
|
||||||
|
double m = (double)count_edges(graph);
|
||||||
|
|
||||||
|
if (m == 0) {
|
||||||
|
printf("[louvain] no edges found\n");
|
||||||
|
louvain_result_t *r = malloc(sizeof(louvain_result_t));
|
||||||
|
r->node_community = calloc(n, sizeof(int));
|
||||||
|
r->count = n;
|
||||||
|
r->modularity = 0.0;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
// each node starts in its own community
|
||||||
|
int *community = malloc(n * sizeof(int));
|
||||||
|
for (int i = 0; i < n; i++)
|
||||||
|
community[i] = i;
|
||||||
|
|
||||||
|
printf("[louvain] m = %.0f, n = %d\n", m, n);
|
||||||
|
|
||||||
|
int moves = phase1(graph, community, m);
|
||||||
|
printf("[louvain] phase 1 done — %d moves\n", moves);
|
||||||
|
|
||||||
|
double Q = compute_modularity(graph, community, m);
|
||||||
|
printf("[louvain] modularity Q = %.4f\n", Q);
|
||||||
|
|
||||||
|
int count = compact(community, n);
|
||||||
|
printf("[louvain] %d communities detected\n", count);
|
||||||
|
|
||||||
|
louvain_result_t *result = malloc(sizeof(louvain_result_t));
|
||||||
|
result->node_community = community;
|
||||||
|
result->count = count;
|
||||||
|
result->modularity = Q;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_louvain_result(louvain_result_t *result)
|
||||||
|
{
|
||||||
|
if (!result)
|
||||||
|
return;
|
||||||
|
free(result->node_community);
|
||||||
|
free(result);
|
||||||
|
}
|
||||||
12
main.c
12
main.c
@@ -1,17 +1,14 @@
|
|||||||
#include "structs.h"
|
#include "structs.h"
|
||||||
#include "render.h"
|
#include "render.h"
|
||||||
#include <stdlib.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
|
|
||||||
#define WINDOW_WIDTH 800
|
#define WINDOW_WIDTH 800
|
||||||
#define WINDOW_HEIGHT 600
|
#define WINDOW_HEIGHT 600
|
||||||
|
|
||||||
int main(void)
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
srand(time(0));
|
// Figure 1
|
||||||
|
graph_t *g = generate_graph(20, 1, 0.04, 122);
|
||||||
graph_t *g = generate_graph(20, 1, 0.04);
|
|
||||||
|
|
||||||
SDL_Init(SDL_INIT_VIDEO);
|
SDL_Init(SDL_INIT_VIDEO);
|
||||||
|
|
||||||
@@ -21,7 +18,8 @@ int main(void)
|
|||||||
SDL_Renderer *renderer =
|
SDL_Renderer *renderer =
|
||||||
SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
|
SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
|
||||||
|
|
||||||
render_graph(renderer, g);
|
// Figure 2
|
||||||
|
render_graph(renderer, g, LOUVAIN);
|
||||||
|
|
||||||
SDL_Event e;
|
SDL_Event e;
|
||||||
int running = 1;
|
int running = 1;
|
||||||
|
|||||||
56
render.c
56
render.c
@@ -1,3 +1,5 @@
|
|||||||
|
#include "render.h"
|
||||||
|
#include "algorithms.h"
|
||||||
#include "structs.h"
|
#include "structs.h"
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
@@ -19,7 +21,7 @@ typedef struct layout_node_t layout_node_t;
|
|||||||
// display a simple node of radius r
|
// display a simple node of radius r
|
||||||
static void draw_node(SDL_Renderer *renderer, int cx, int cy, int r)
|
static void draw_node(SDL_Renderer *renderer, int cx, int cy, int r)
|
||||||
{
|
{
|
||||||
SDL_SetRenderDrawColor(renderer, 215, 153, 33, 255);
|
//SDL_SetRenderDrawColor(renderer, 215, 153, 33, 255);
|
||||||
for (int dy = -r; dy <= r; dy++) {
|
for (int dy = -r; dy <= r; dy++) {
|
||||||
int dx = (int)sqrt((double)(r * r - dy * dy));
|
int dx = (int)sqrt((double)(r * r - dy * dy));
|
||||||
SDL_RenderDrawLine(renderer, cx - dx, cy + dy, cx + dx,
|
SDL_RenderDrawLine(renderer, cx - dx, cy + dy, cx + dx,
|
||||||
@@ -118,7 +120,19 @@ static layout_node_t *compute_layout(const graph_t *graph)
|
|||||||
return nodes;
|
return nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
void render_graph(SDL_Renderer *renderer, const graph_t *graph)
|
static SDL_Color community_colors[] = {
|
||||||
|
{ 251, 73, 52, 255 }, // gruvbox red
|
||||||
|
{ 250, 189, 47, 255 }, // gruvbox yellow
|
||||||
|
{ 142, 192, 124, 255 }, // gruvbox green
|
||||||
|
{ 131, 165, 152, 255 }, // gruvbox aqua
|
||||||
|
{ 69, 133, 136, 255 }, // gruvbox blue
|
||||||
|
{ 211, 134, 155, 255 }, // gruvbox pink
|
||||||
|
{ 254, 128, 25, 255 }, // gruvbox orange
|
||||||
|
};
|
||||||
|
#define N_COLORS (sizeof(community_colors) / sizeof(community_colors[0]))
|
||||||
|
|
||||||
|
void render_graph(SDL_Renderer *renderer, const graph_t *graph,
|
||||||
|
VISUALIZATION_TYPE type)
|
||||||
{
|
{
|
||||||
if (!renderer || !graph || !graph->adj_lists)
|
if (!renderer || !graph || !graph->adj_lists)
|
||||||
return;
|
return;
|
||||||
@@ -129,11 +143,21 @@ void render_graph(SDL_Renderer *renderer, const graph_t *graph)
|
|||||||
if (!layout)
|
if (!layout)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Clear background
|
community_result_t *communities = NULL;
|
||||||
|
louvain_result_t *louvain = NULL;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case CLIQUE:
|
||||||
|
communities = find_k_clique_communities(graph, 3);
|
||||||
|
break;
|
||||||
|
case LOUVAIN:
|
||||||
|
louvain = compute_louvain(graph);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
SDL_SetRenderDrawColor(renderer, 48, 48, 48, 255);
|
SDL_SetRenderDrawColor(renderer, 48, 48, 48, 255);
|
||||||
SDL_RenderClear(renderer);
|
SDL_RenderClear(renderer);
|
||||||
|
|
||||||
// Draw edges
|
|
||||||
SDL_SetRenderDrawColor(renderer, 189, 189, 189, 255);
|
SDL_SetRenderDrawColor(renderer, 189, 189, 189, 255);
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
node_t *neighbor = graph->adj_lists[i];
|
node_t *neighbor = graph->adj_lists[i];
|
||||||
@@ -155,10 +179,34 @@ void render_graph(SDL_Renderer *renderer, const graph_t *graph)
|
|||||||
int x = (int)layout[i].x;
|
int x = (int)layout[i].x;
|
||||||
int y = (int)layout[i].y;
|
int y = (int)layout[i].y;
|
||||||
|
|
||||||
|
int c;
|
||||||
|
SDL_Color col;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case CLIQUE:
|
||||||
|
c = communities->node_community[i];
|
||||||
|
col = (c == -1) ? (SDL_Color){ 150, 150, 150, 255 } :
|
||||||
|
community_colors[c % N_COLORS];
|
||||||
|
break;
|
||||||
|
case LOUVAIN:
|
||||||
|
c = louvain->node_community[i];
|
||||||
|
col = (c == -1) ? (SDL_Color){ 168, 153, 132, 255 } :
|
||||||
|
community_colors[c % N_COLORS];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
SDL_SetRenderDrawColor(renderer, col.r, col.g, col.b, col.a);
|
||||||
|
|
||||||
// Node fill
|
// Node fill
|
||||||
draw_node(renderer, x, y, NODE_RADIUS);
|
draw_node(renderer, x, y, NODE_RADIUS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (communities != NULL) {
|
||||||
|
free_community_result(communities);
|
||||||
|
}
|
||||||
|
if (louvain != NULL) {
|
||||||
|
free_louvain_result(louvain);
|
||||||
|
}
|
||||||
|
|
||||||
free(layout);
|
free(layout);
|
||||||
SDL_RenderPresent(renderer);
|
SDL_RenderPresent(renderer);
|
||||||
}
|
}
|
||||||
|
|||||||
15
render.h
15
render.h
@@ -1,4 +1,17 @@
|
|||||||
|
//
|
||||||
|
// Created by Tiago Batista Cardoso on 2/23/2026.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef GRAPHE_RENDER_H
|
||||||
|
#define GRAPHE_RENDER_H
|
||||||
|
|
||||||
#include "structs.h"
|
#include "structs.h"
|
||||||
#include <SDL2/SDL_render.h>
|
#include <SDL2/SDL_render.h>
|
||||||
|
|
||||||
void render_graph(SDL_Renderer *renderer, const graph_t *graph);
|
enum VISUALIZATION_TYPE { CLIQUE, LOUVAIN };
|
||||||
|
typedef enum VISUALIZATION_TYPE VISUALIZATION_TYPE;
|
||||||
|
|
||||||
|
void render_graph(SDL_Renderer *renderer, const graph_t *graph,
|
||||||
|
VISUALIZATION_TYPE);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
17
structs.c
17
structs.c
@@ -28,19 +28,6 @@ graph_t *create_graph(int n, double p, double q)
|
|||||||
return new_graph;
|
return new_graph;
|
||||||
}
|
}
|
||||||
|
|
||||||
//void add_edge(graph_t *graph, int src, int dest)
|
|
||||||
//{
|
|
||||||
// // src -> dest
|
|
||||||
// node_t *new_node = create_node(dest);
|
|
||||||
// new_node->next = graph->adj_lists[src];
|
|
||||||
// graph->adj_lists[src] = new_node;
|
|
||||||
//
|
|
||||||
// // dest -> src
|
|
||||||
// new_node = create_node(src);
|
|
||||||
// new_node->next = graph->adj_lists[dest];
|
|
||||||
// graph->adj_lists[dest] = new_node;
|
|
||||||
//}
|
|
||||||
|
|
||||||
void add_edge(graph_t *graph, int src, int dest)
|
void add_edge(graph_t *graph, int src, int dest)
|
||||||
{
|
{
|
||||||
// Guard against self-loops and out-of-bounds
|
// Guard against self-loops and out-of-bounds
|
||||||
@@ -89,7 +76,7 @@ graph_t *basic_graph()
|
|||||||
return basic;
|
return basic;
|
||||||
}
|
}
|
||||||
|
|
||||||
graph_t *generate_graph(int n, double p, double q)
|
graph_t *generate_graph(int n, double p, double q, int seed)
|
||||||
{
|
{
|
||||||
clock_t start, end;
|
clock_t start, end;
|
||||||
double cpu_time_used;
|
double cpu_time_used;
|
||||||
@@ -100,6 +87,8 @@ graph_t *generate_graph(int n, double p, double q)
|
|||||||
graph_t *result = create_graph(n, p, q);
|
graph_t *result = create_graph(n, p, q);
|
||||||
int remaining = n;
|
int remaining = n;
|
||||||
|
|
||||||
|
srand(seed);
|
||||||
|
|
||||||
// Calcul des repartitions aleatoires
|
// Calcul des repartitions aleatoires
|
||||||
int n1 = rand() % (remaining + 1);
|
int n1 = rand() % (remaining + 1);
|
||||||
remaining -= n1;
|
remaining -= n1;
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ node_t *create_node(int id);
|
|||||||
graph_t *create_graph(int n, double p, double q);
|
graph_t *create_graph(int n, double p, double q);
|
||||||
void add_edge(graph_t *graph, int src, int dest);
|
void add_edge(graph_t *graph, int src, int dest);
|
||||||
graph_t *basic_graph();
|
graph_t *basic_graph();
|
||||||
graph_t *generate_graph(int n, double p, double q);
|
graph_t *generate_graph(int n, double p, double q, int seed);
|
||||||
void displayGraph(graph_t *graph);
|
void displayGraph(graph_t *graph);
|
||||||
void free_graph(graph_t *graph);
|
void free_graph(graph_t *graph);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user