You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
358 lines
12 KiB
C
358 lines
12 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <mpi.h>
|
|
|
|
// Definizione di alcune costanti globali
|
|
#define PI 3.14159265358979323
|
|
#define TEMPERATURE_DECAY_RATE 0.98
|
|
#define MIN_DISTANCE 10.0 // Distanza minima tra i nodi
|
|
|
|
// Strutture
|
|
typedef struct {
|
|
double x;
|
|
double y;
|
|
} Force;
|
|
|
|
typedef struct {
|
|
double x;
|
|
double y;
|
|
} Node;
|
|
|
|
typedef struct {
|
|
size_t start;
|
|
size_t end;
|
|
} Edge;
|
|
|
|
typedef struct {
|
|
Node* nodes;
|
|
Edge* edges;
|
|
size_t node_count;
|
|
size_t edge_count;
|
|
} SimpleGraph;
|
|
|
|
|
|
// Prototipi delle funzioni
|
|
SimpleGraph readGraphFile(char* file_name);
|
|
void calculateRepulsion(Force* net_forces, SimpleGraph* graph, size_t start, size_t end);
|
|
void calculateAttraction(Force* net_forces, SimpleGraph* graph, size_t start, size_t end);
|
|
Force* initializeForceVector(SimpleGraph graph);
|
|
void moveNodes(Force* net_forces, SimpleGraph* graph, size_t start, size_t end);
|
|
void getMaxNodeDimensions(SimpleGraph* graph, double* maxX, double* maxY);
|
|
|
|
|
|
int peso;
|
|
double temperature;
|
|
double k; // Distanza ideale
|
|
double scaleFactor; // Fattore di scala iniziale
|
|
double offsetX; // Offset iniziale
|
|
double offsetY;
|
|
|
|
|
|
int main(int argc, char* argv[]) {
|
|
MPI_Init(&argc, &argv);
|
|
|
|
int rank, size;
|
|
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
|
|
MPI_Comm_size(MPI_COMM_WORLD, &size);
|
|
|
|
if (argc < 5) {
|
|
if (rank == 0) {
|
|
printf("Uso corretto: %s nome_file iterazioni temperatura peso\n", argv[0]);
|
|
}
|
|
MPI_Finalize();
|
|
return 1; // Esce dal programma con codice di errore
|
|
}
|
|
|
|
char* file_name = argv[1];
|
|
int it = atoi(argv[2]);
|
|
temperature = atof(argv[3]);
|
|
peso = atoi(argv[4]);
|
|
|
|
SimpleGraph graph;
|
|
if (rank == 0) {
|
|
graph = readGraphFile(file_name);
|
|
}
|
|
|
|
// Broadcast del numero di nodi e archi a tutti i processi
|
|
MPI_Bcast(&graph.node_count, 1, MPI_UNSIGNED_LONG, 0, MPI_COMM_WORLD);
|
|
MPI_Bcast(&graph.edge_count, 1, MPI_UNSIGNED_LONG, 0, MPI_COMM_WORLD);
|
|
|
|
if (rank != 0) {
|
|
graph.nodes = malloc(graph.node_count * sizeof(Node));
|
|
graph.edges = malloc(graph.edge_count * sizeof(Edge));
|
|
}
|
|
MPI_Bcast(graph.nodes, graph.node_count * sizeof(Node), MPI_BYTE, 0, MPI_COMM_WORLD);
|
|
MPI_Bcast(graph.edges, graph.edge_count * sizeof(Edge), MPI_BYTE, 0, MPI_COMM_WORLD);
|
|
double screenWidth = 2240 - 10;
|
|
double screenHeight = 1400 - 10;
|
|
k = sqrt((screenWidth * screenHeight) / graph.node_count);
|
|
|
|
|
|
double offsetX = 0.0;
|
|
double offsetY = 0.0;
|
|
Force* net_forces = initializeForceVector(graph);
|
|
double maxX, maxY;
|
|
getMaxNodeDimensions(&graph, &maxX, &maxY);
|
|
double scaleFactor = fmin(screenWidth / (2 * maxX), screenHeight / (2 * maxY));
|
|
if (!net_forces) {
|
|
fprintf(stderr, "Error allocating memory for forces\n");
|
|
MPI_Abort(MPI_COMM_WORLD, 1);
|
|
}
|
|
for (int i = 0; i < it; i++) {
|
|
calculateRepulsion(net_forces, &graph, rank * graph.node_count / size, (rank + 1) * graph.node_count / size);
|
|
calculateAttraction(net_forces, &graph, rank * graph.edge_count / size, (rank + 1) * graph.edge_count / size);
|
|
MPI_Barrier(MPI_COMM_WORLD);
|
|
if (rank == 0) {
|
|
Force* dati = initializeForceVector(graph);
|
|
// Buffer per ricevere tutte le forze dai processi
|
|
Force* all_forces = malloc(size * graph.node_count * sizeof(Force));
|
|
|
|
// Array per i counts e i displacements
|
|
int* counts = malloc(size * sizeof(int)); //Numero di elementi ricevuti da ogni processo
|
|
int* displacements = malloc(size * sizeof(int)); //Index di partenza
|
|
|
|
for (int i = 0; i < size; i++) {
|
|
counts[i] = graph.node_count * sizeof(Force);
|
|
displacements[i] = i * graph.node_count * sizeof(Force);
|
|
}
|
|
|
|
// Raccoglie le forze da tutti i processi
|
|
MPI_Gatherv(net_forces, graph.node_count * sizeof(Force), MPI_BYTE,
|
|
all_forces, counts, displacements, MPI_BYTE,
|
|
0, MPI_COMM_WORLD);
|
|
|
|
// Somma le forze ricevute
|
|
for (int i = 0; i < size; i++) {
|
|
for (int j = 0; j < graph.node_count; j++) {
|
|
net_forces[j].x += all_forces[i * graph.node_count + j].x;
|
|
net_forces[j].y += all_forces[i * graph.node_count + j].y;
|
|
}
|
|
}
|
|
|
|
moveNodes(net_forces, &graph, 0, graph.node_count);
|
|
|
|
// Libera la memoria allocata
|
|
free(all_forces);
|
|
free(counts);
|
|
free(displacements);
|
|
} else {
|
|
// Invio delle forze al processo radice
|
|
MPI_Gatherv(net_forces, graph.node_count * sizeof(Force), MPI_BYTE,
|
|
NULL, NULL, NULL, MPI_BYTE,
|
|
0, MPI_COMM_WORLD);
|
|
}
|
|
MPI_Barrier(MPI_COMM_WORLD);
|
|
if (temperature > 1.0) {
|
|
temperature *= TEMPERATURE_DECAY_RATE;
|
|
}
|
|
|
|
MPI_Bcast(graph.nodes, graph.node_count * sizeof(Node), MPI_BYTE, 0, MPI_COMM_WORLD);
|
|
for (int i = 0; i< graph.node_count; i++){
|
|
net_forces[i].x = 0.0;
|
|
net_forces[i].y = 0.0;
|
|
}
|
|
MPI_Barrier(MPI_COMM_WORLD);
|
|
|
|
}
|
|
|
|
if (rank == 0) {
|
|
FILE* output = fopen("out.txt", "w");
|
|
if (!output) {
|
|
printf("Impossibile aprire il file di output per la scrittura.\n");
|
|
MPI_Finalize();
|
|
return 0;
|
|
}
|
|
fprintf(output, "%zu %d\n", graph.node_count, peso);
|
|
|
|
// Scrivi le posizioni dei nodi
|
|
for (size_t i = 0; i < graph.node_count; i++) {
|
|
fprintf(output, "%zu %f %f\n", i, graph.nodes[i].x, graph.nodes[i].y);
|
|
}
|
|
|
|
fprintf(output, "%zu\n", graph.edge_count);
|
|
|
|
// Scrivi gli archi
|
|
for (size_t i = 0; i < graph.edge_count; i++) {
|
|
fprintf(output, "%zu %zu\n", graph.edges[i].start, graph.edges[i].end);
|
|
}
|
|
|
|
fclose(output);
|
|
}
|
|
|
|
free(graph.nodes);
|
|
free(graph.edges);
|
|
MPI_Finalize();
|
|
return 0;
|
|
}
|
|
|
|
SimpleGraph readGraphFile(char* file_name) {
|
|
FILE* input = fopen(file_name, "r");
|
|
if (!input) {
|
|
fprintf(stderr, "Error opening file\n");
|
|
MPI_Abort(MPI_COMM_WORLD, 1);
|
|
}
|
|
SimpleGraph graph;
|
|
fscanf(input, "%zu", &graph.node_count); // Legge il numero totale di nodi
|
|
|
|
// Creazione di un array temporaneo per memorizzare i dati degli archi
|
|
size_t temp_capacity = 100; // Capacità iniziale, aumenta dinamicamente se necessario
|
|
size_t temp_edge_count = 0;
|
|
Edge* temp_edges = malloc(temp_capacity * sizeof(Edge));
|
|
|
|
if (!temp_edges) {
|
|
fprintf(stderr, "Error allocating memory for edges\n");
|
|
MPI_Abort(MPI_COMM_WORLD, 1);
|
|
}
|
|
|
|
size_t node1, node2;
|
|
double pesett;
|
|
|
|
if (!peso) { // Se non è presente il peso, legge due alla volta
|
|
while (fscanf(input, "%zu %zu", &node1, &node2) == 2) {
|
|
if (temp_edge_count >= temp_capacity) {
|
|
// Aumenta la capacità dell'array temporaneo
|
|
temp_capacity *= 2;
|
|
temp_edges = realloc(temp_edges, temp_capacity * sizeof(Edge));
|
|
if (!temp_edges) {
|
|
fprintf(stderr, "Error reallocating memory for edges\n");
|
|
MPI_Abort(MPI_COMM_WORLD, 1);
|
|
}
|
|
}
|
|
temp_edges[temp_edge_count].start = node1;
|
|
temp_edges[temp_edge_count].end = node2;
|
|
temp_edge_count++;
|
|
}
|
|
} else { // Se è presente il peso, legge tre alla volta
|
|
while (fscanf(input, "%zu %zu %lf", &node1, &node2, &pesett) == 3) {
|
|
if (temp_edge_count >= temp_capacity) {
|
|
// Aumenta la capacità dell'array temporaneo
|
|
temp_capacity *= 2;
|
|
temp_edges = realloc(temp_edges, temp_capacity * sizeof(Edge));
|
|
if (!temp_edges) {
|
|
fprintf(stderr, "Error reallocating memory for edges\n");
|
|
MPI_Abort(MPI_COMM_WORLD, 1);
|
|
}
|
|
}
|
|
temp_edges[temp_edge_count].start = node1;
|
|
temp_edges[temp_edge_count].end = node2;
|
|
temp_edge_count++;
|
|
}
|
|
}
|
|
|
|
fclose(input);
|
|
|
|
graph.nodes = malloc(graph.node_count * sizeof(Node));
|
|
if (!graph.nodes) {
|
|
fprintf(stderr, "Error allocating memory for nodes\n");
|
|
MPI_Abort(MPI_COMM_WORLD, 1);
|
|
}
|
|
|
|
graph.edges = malloc(temp_edge_count * sizeof(Edge));
|
|
if (!graph.edges) {
|
|
fprintf(stderr, "Error allocating memory for edges\n");
|
|
MPI_Abort(MPI_COMM_WORLD, 1);
|
|
}
|
|
|
|
// Inizializza le posizioni dei nodi
|
|
for (size_t i = 0; i < graph.node_count; i++) {
|
|
graph.nodes[i].x = cos((2*PI*i)/graph.node_count);
|
|
graph.nodes[i].y = sin((2*PI*i)/graph.node_count);
|
|
}
|
|
|
|
memcpy(graph.edges, temp_edges, temp_edge_count * sizeof(Edge));
|
|
graph.edge_count = temp_edge_count;
|
|
|
|
free(temp_edges);
|
|
return graph;
|
|
}
|
|
|
|
void calculateRepulsion(Force* net_forces, SimpleGraph* graph, size_t start, size_t end) {
|
|
for (size_t i = start; i < end; i++) {
|
|
for (size_t j = 0; j < graph->node_count; j++) {
|
|
if (i != j) {
|
|
double dx = graph->nodes[i].x - graph->nodes[j].x;
|
|
double dy = graph->nodes[i].y - graph->nodes[j].y;
|
|
double distance = sqrt(dx * dx + dy * dy);
|
|
|
|
if (distance < MIN_DISTANCE) {
|
|
distance = MIN_DISTANCE;
|
|
}
|
|
|
|
double force_magnitude = k * k / distance;
|
|
double force_x = force_magnitude * (dx / distance);
|
|
double force_y = force_magnitude * (dy / distance);
|
|
|
|
net_forces[i].x += force_x;
|
|
net_forces[i].y += force_y;
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void calculateAttraction(Force* net_forces, SimpleGraph* graph, size_t start, size_t end) {
|
|
for (size_t i = start; i < end; i++) {
|
|
size_t node1 = graph->edges[i].start;
|
|
size_t node2 = graph->edges[i].end;
|
|
double dx = graph->nodes[node2].x - graph->nodes[node1].x;
|
|
double dy = graph->nodes[node2].y - graph->nodes[node1].y;
|
|
double distance = sqrt(dx * dx + dy * dy);
|
|
double force = distance * distance / k;
|
|
if (distance < MIN_DISTANCE) {
|
|
distance = MIN_DISTANCE;
|
|
}
|
|
net_forces[node1].x += force * dx / distance;
|
|
net_forces[node1].y += force * dy / distance;
|
|
net_forces[node2].x -= force * dx / distance;
|
|
net_forces[node2].y -= force * dy / distance;
|
|
|
|
}
|
|
}
|
|
|
|
Force* initializeForceVector(SimpleGraph graph) {
|
|
Force* net_forces = malloc(graph.node_count * sizeof(Force));
|
|
if (!net_forces) {
|
|
fprintf(stderr, "Error allocating memory for forces\n");
|
|
MPI_Abort(MPI_COMM_WORLD, 1);
|
|
}
|
|
for (size_t i = 0; i < graph.node_count; i++) {
|
|
net_forces[i].x = 0;
|
|
net_forces[i].y = 0;
|
|
}
|
|
return net_forces;
|
|
}
|
|
|
|
void moveNodes(Force* net_forces, SimpleGraph* graph, size_t start, size_t end) {
|
|
for (size_t i = start; i < end; i++) {
|
|
double dx = net_forces[i].x;
|
|
double dy = net_forces[i].y;
|
|
|
|
|
|
double displacement = sqrt(dx * dx + dy * dy);
|
|
if (displacement > temperature) {
|
|
dx = dx / displacement * temperature;
|
|
dy = dy / displacement * temperature;
|
|
}
|
|
|
|
graph->nodes[i].x += dx;
|
|
graph->nodes[i].y += dy;
|
|
}
|
|
}
|
|
|
|
void getMaxNodeDimensions(SimpleGraph* graph, double* maxX, double* maxY) {
|
|
*maxX = 0.0;
|
|
*maxY = 0.0;
|
|
|
|
for (size_t i = 0; i < graph->node_count; i++) {
|
|
if (fabs(graph->nodes[i].x) > *maxX) {
|
|
*maxX = fabs(graph->nodes[i].x);
|
|
}
|
|
if (fabs(graph->nodes[i].y) > *maxY) {
|
|
*maxY = fabs(graph->nodes[i].y);
|
|
}
|
|
}
|
|
}
|