From 91a2731d35db1429f1e67d52addfbf1cf04dac43 Mon Sep 17 00:00:00 2001 From: Alinson Xavier Date: Fri, 20 Mar 2015 09:57:16 -0400 Subject: [PATCH] Implement max flow algorithm --- src/flow.c | 154 ++++++++++++++++++++++++++++++++++++++++++++ src/flow.h | 27 ++++++++ src/graph.c | 182 ++++++++++++++++++++++++++++++++++------------------ src/graph.h | 50 +++++++++++---- src/gtsp.c | 66 +++++++++++-------- src/gtsp.h | 12 +--- src/main.c | 77 +++++++++++++++++++++- src/tsp.c | 26 ++++---- 8 files changed, 468 insertions(+), 126 deletions(-) create mode 100644 src/flow.c create mode 100644 src/flow.h diff --git a/src/flow.c b/src/flow.c new file mode 100644 index 0000000..4ad2188 --- /dev/null +++ b/src/flow.c @@ -0,0 +1,154 @@ +#include +#include +#include "gtsp.h" +#include "flow.h" +#include "util.h" + +int flow_find_max_flow( + const struct Graph *digraph, + const double *capacities, + struct Node *from, + struct Node *to, + double *flow, + double *value) +{ + int rval = 0; + + int path_length; + struct Edge **path_edges = 0; + double path_capacity; + + double *residual_caps = 0; + + residual_caps = (double *) malloc(digraph->edge_count * sizeof(double)); + abort_if(!residual_caps, "could not allocate residual_caps"); + + path_edges = (struct Edge **) malloc( + digraph->edge_count * sizeof(struct Edge *)); + abort_if(!path_edges, "could not allocate path_edges"); + + for (int i = 0; i < digraph->edge_count; i++) + { + flow[i] = 0; + residual_caps[i] = capacities[i]; + abort_if(!digraph->edges[i].reverse, + "digraph must have reverse edge information"); + } + + *value = 0; + + while (1) + { + flow_find_augmenting_path(digraph, residual_caps, from, to, + &path_length, path_edges, &path_capacity); + + if (path_length == 0) break; + + (*value) += path_capacity; + + for (int i = 0; i < path_length; i++) + { + struct Edge *e = &digraph->edges[path_edges[i]->index]; + + residual_caps[e->index] -= path_capacity; + residual_caps[e->reverse->index] += path_capacity; + + flow[e->index] += path_capacity; + flow[e->reverse->index] -= path_capacity; + } + } + + CLEANUP: + if (path_edges) free(path_edges); + if (residual_caps) free(residual_caps); + return rval; +} + +int flow_find_augmenting_path( + const struct Graph *graph, + const double *residual_caps, + struct Node *from, + struct Node *to, + int *path_length, + struct Edge **path_edges, + double *path_capacity) +{ + int rval = 0; + + struct Node **queue = 0; + int queue_start = 0; + int queue_end = 0; + + struct Node **parents = 0; + struct Edge **parent_edges = 0; + + int node_count = graph->node_count; + + queue = (struct Node **) malloc(node_count * sizeof(struct Node *)); + parents = (struct Node **) malloc(node_count * sizeof(struct Node *)); + parent_edges = (struct Edge **) malloc(node_count * sizeof(struct Edge *)); + + abort_if(!queue, "could not allocate queue"); + abort_if(!parents, "could not allocate parents"); + abort_if(!parent_edges, "could not allocate parent_edges"); + + for (int i = 0; i < node_count; i++) + graph->nodes[i].mark = 0; + + int found = 0; + queue[queue_end++] = from; + + while (queue_end > queue_start) + { + struct Node *n = queue[queue_start++]; + + n->mark = 2; + + for (int i = 0; i < n->degree; i++) + { + struct Node *neighbor = n->adj[i].neighbor; + struct Edge *edge = n->adj[i].edge; + + if (neighbor->mark > 0) continue; + if (residual_caps[edge->index] < LP_EPSILON) continue; + + parents[neighbor->index] = n; + parent_edges[neighbor->index] = edge; + + queue[queue_end++] = neighbor; + neighbor->mark = 1; + + if (neighbor == to) + { + found = 1; + break; + } + } + + if (found) break; + } + + *path_length = 0; + *path_capacity = DBL_MAX; + + if (queue_end == queue_start) goto CLEANUP; + + struct Node *n = to; + while (n != from) + { + struct Edge *edge = parent_edges[n->index]; + path_edges[*path_length] = edge; + + double c = residual_caps[edge->index]; + if (c < *path_capacity) *path_capacity = c; + + n = parents[n->index]; + (*path_length)++; + } + + CLEANUP: + if (parents) free(parents); + if (parent_edges) free(parent_edges); + if (queue) free(queue); + return rval; +} \ No newline at end of file diff --git a/src/flow.h b/src/flow.h new file mode 100644 index 0000000..80d829c --- /dev/null +++ b/src/flow.h @@ -0,0 +1,27 @@ +// +// Created by isoron on 19/03/15. +// + +#ifndef _PROJECT_FLOW_H_ +#define _PROJECT_FLOW_H_ + +int flow_find_augmenting_path( + const struct Graph *graph, + const double *residual_caps, + struct Node *from, + struct Node *to, + int *path_length, + struct Edge **path_edges, + double *path_capacity); + +int flow_find_max_flow( + const struct Graph *digraph, + const double *capacities, + struct Node *from, + struct Node *to, + double *flow, + double *value); + +#include "graph.h" + +#endif //_PROJECT_FLOW_H_ diff --git a/src/graph.c b/src/graph.c index 65133cc..ee40b78 100644 --- a/src/graph.c +++ b/src/graph.c @@ -1,106 +1,162 @@ #include -#include "main.h" #include "graph.h" #include "util.h" #include "lp.h" -void graph_dfs( - int n, struct Graph *G, double *x, int *island_size, int *island_nodes) +void graph_init(struct Graph *graph) { - *(island_nodes + (*island_size)) = n; - (*island_size)++; + if (!graph) return; - struct Node *pn = &G->node_list[n]; - pn->mark = 1; - - for (int i = 0; i < pn->deg; i++) - { - if (x[pn->adj[i].e] > LP_EPSILON) - { - int neighbor = pn->adj[i].n; - - if (G->node_list[neighbor].mark == 0) - graph_dfs(neighbor, G, x, island_size, island_nodes); - } - } + graph->nodes = 0; + graph->adj = 0; + graph->node_count = 0; + graph->edge_count = 0; } -void graph_init(struct Graph *G) +void graph_free(struct Graph *graph) { - if (!G) return; + if (!graph) return; - G->node_list = 0; - G->adj_space = 0; - G->node_count = 0; - G->edge_count = 0; + if (graph->nodes) free(graph->nodes); + if (graph->adj) free(graph->adj); } -void graph_free(struct Graph *G) -{ - if (!G) return; - - if (G->node_list) free(G->node_list); - if (G->adj_space) free(G->adj_space); -} - -int graph_build(int node_count, int edge_count, int *edge_list, struct Graph *G) +int graph_build( + int node_count, + int edge_count, + int *edges, + int is_directed, + struct Graph *graph) { int rval = 0; struct Node *n; - struct AdjObj *p; + struct Adjacency *p; - G->node_list = (struct Node *) malloc(node_count * sizeof(struct Node)); - G->adj_space = - (struct AdjObj *) malloc(2 * edge_count * sizeof(struct AdjObj)); + graph->edges = (struct Edge *) malloc(edge_count * sizeof(struct Edge)); + graph->nodes = (struct Node *) malloc(node_count * sizeof(struct Node)); + graph->adj = (struct Adjacency *) malloc( + 2 * edge_count * sizeof(struct Adjacency)); - abort_if(!G->node_list, "could not allocate G->node_list"); - abort_if(!G->adj_space, "could not allocate G->adj_space"); + abort_if(!graph->edges, "could not allocate G->edges\n"); + abort_if(!graph->nodes, "could not allocate G->nodes"); + abort_if(!graph->adj, "could not allocate G->adj"); for (int i = 0; i < node_count; i++) - G->node_list[i].deg = 0; + { + graph->nodes[i].index = i; + graph->nodes[i].degree = 0; + } for (int i = 0; i < edge_count; i++) { - int a = edge_list[2 * i]; - int b = edge_list[2 * i + 1]; - G->node_list[a].deg++; - G->node_list[b].deg++; + int a = edges[2 * i]; + int b = edges[2 * i + 1]; + graph->nodes[a].degree++; + if(!is_directed) graph->nodes[b].degree++; + + graph->edges[i].reverse = 0; + graph->edges[i].index = i; + graph->edges[i].from = &graph->nodes[a]; + graph->edges[i].to = &graph->nodes[b]; } - p = G->adj_space; + p = graph->adj; for (int i = 0; i < node_count; i++) { - G->node_list[i].adj = p; - p += G->node_list[i].deg; - G->node_list[i].deg = 0; + graph->nodes[i].adj = p; + p += graph->nodes[i].degree; + graph->nodes[i].degree = 0; } for (int i = 0; i < edge_count; i++) { - int a = edge_list[2 * i]; - int b = edge_list[2 * i + 1]; - n = &G->node_list[a]; - n->adj[n->deg].n = b; - n->adj[n->deg].e = i; - n->deg++; - n = &G->node_list[b]; - n->adj[n->deg].n = a; - n->adj[n->deg].e = i; - n->deg++; + int a = edges[2 * i]; + int b = edges[2 * i + 1]; + + n = &graph->nodes[a]; + n->adj[n->degree].neighbor_index = b; + n->adj[n->degree].edge_index = i; + n->adj[n->degree].neighbor = &graph->nodes[b]; + n->adj[n->degree].edge = &graph->edges[i]; + n->degree++; + + if(!is_directed) + { + n = &graph->nodes[b]; + n->adj[n->degree].neighbor_index = a; + n->adj[n->degree].edge_index = i; + n->adj[n->degree].neighbor = &graph->nodes[b]; + n->adj[n->degree].edge = &graph->edges[i]; + n->degree++; + } } - G->node_count = node_count; - G->edge_count = edge_count; + graph->node_count = node_count; + graph->edge_count = edge_count; CLEANUP: if (rval) { - if (G->node_list) free(G->node_list); - if (G->adj_space) free(G->adj_space); + if (graph->edges) free(graph->edges); + if (graph->nodes) free(graph->nodes); + if (graph->adj) free(graph->adj); } return rval; } +void graph_dfs( + int n, struct Graph *G, double *x, int *island_size, int *island_nodes) +{ + *(island_nodes + (*island_size)) = n; + (*island_size)++; + + struct Node *pn = &G->nodes[n]; + pn->mark = 1; + + for (int i = 0; i < pn->degree; i++) + { + if (x[pn->adj[i].edge_index] > LP_EPSILON) + { + int neighbor = pn->adj[i].neighbor_index; + + if (G->nodes[neighbor].mark == 0) + graph_dfs(neighbor, G, x, island_size, island_nodes); + } + } +} + +int graph_build_directed_from_undirected( + const struct Graph *graph, struct Graph *digraph) +{ + int rval = 0; + + int *edges = 0; + + edges = (int *) malloc(4 * graph->edge_count * sizeof(int)); + abort_if(!edges, "could not allocate edges"); + + for (int i = 0; i < graph->edge_count; i++) + { + struct Edge *e = &graph->edges[i]; + edges[4 * i] = edges[4 * i + 3] = e->from->index; + edges[4 * i + 1] = edges[4 * i + 2] = e->to->index; + } + + rval = graph_build(graph->node_count, 2 * graph->edge_count, edges, 1, + digraph); + abort_if(rval, "graph_build failed"); + + for (int i = 0; i < graph->edge_count; i++) + { + digraph->edges[2 * i].reverse = &digraph->edges[i * 2 + 1]; + digraph->edges[2 * i + 1].reverse = &digraph->edges[i * 2]; + } + + CLEANUP: + if (!edges) free(edges); + return rval; +} + void get_delta( int island_node_count, int *island_nodes, @@ -122,4 +178,4 @@ void get_delta( for (int i = 0; i < island_node_count; i++) marks[island_nodes[i]] = 0; -} \ No newline at end of file +} diff --git a/src/graph.h b/src/graph.h index 406b752..39ef49e 100644 --- a/src/graph.h +++ b/src/graph.h @@ -3,39 +3,60 @@ #include "main.h" -struct AdjObj +struct Adjacency { - /* Index of neighbor node */ - int n; + int edge_index; + int neighbor_index; - /* Index of adj joining neighbor */ - int e; + struct Edge *edge; + struct Node *neighbor; }; struct Node { - int deg; - struct AdjObj *adj; int mark; + + int index; + int degree; + + struct Adjacency *adj; +}; + +struct Edge +{ + int index; + int weight; + + struct Node *from; + struct Node *to; + + struct Edge *reverse; }; struct Graph { int node_count; int edge_count; - struct Node *node_list; - struct AdjObj *adj_space; + + struct Edge *edges; + struct Node *nodes; + + struct Adjacency *adj; }; void graph_dfs( int n, struct Graph *G, double *x, int *icount, int *island); -void graph_init(struct Graph *G); +void graph_init(struct Graph *graph); -void graph_free(struct Graph *G); +void graph_free(struct Graph *graph); -int graph_build - (int node_count, int edge_count, int *edge_list, struct Graph *G); +int graph_build( + int node_count, + int edge_count, + int *edges, + int is_directed, + struct Graph *graph); void get_delta( int nsize, @@ -46,4 +67,7 @@ void get_delta( int *delta, int *marks); +int graph_build_directed_from_undirected + (const struct Graph *graph, struct Graph *digraph); + #endif diff --git a/src/gtsp.c b/src/gtsp.c index f731bd8..164d0f8 100644 --- a/src/gtsp.c +++ b/src/gtsp.c @@ -6,20 +6,19 @@ int GTSP_init_data(struct GTSP *data) { - data->node_count = 0; - data->edge_count = 0; - data->edges = 0; data->clusters = 0; data->cluster_count = 0; data->x_coordinates = 0; data->y_coordinates = 0; + graph_init(data->graph); + return 0; } void GTSP_free(struct GTSP *data) { if (!data) return; - if (data->edges) free(data->edges); + if (data->graph) graph_free(data->graph); if (data->clusters) free(data->clusters); if (data->x_coordinates) free(data->x_coordinates); if (data->y_coordinates) free(data->y_coordinates); @@ -30,21 +29,33 @@ int GTSP_create_random_problem( { int rval = 0; - struct Edge *edges = 0; + int *edges = 0; + int *weights = 0; int *clusters = 0; double *x_coords = 0; double *y_coords = 0; + struct Graph *graph = 0; + int edge_count = (node_count * (node_count - 1)) / 2; - edges = (struct Edge *) malloc(edge_count * sizeof(struct Edge)); + graph = (struct Graph*) malloc(sizeof(struct Graph)); + abort_if(!graph, "could not allocate graph\n"); + + graph_init(graph); + + edges = (int *) malloc(2 * edge_count * sizeof(int)); + weights = (int *) malloc(edge_count * sizeof(int)); clusters = (int *) malloc(node_count * sizeof(int)); + abort_if(!edges, "could not allocate data->edges\n"); + abort_if(!weights, "could not allocate weights\n"); abort_if(!clusters, "could not allocate clusters\n"); x_coords = (double *) malloc(node_count * sizeof(double)); y_coords = (double *) malloc(node_count * sizeof(double)); + abort_if(!x_coords, "could not allocate x_coords\n"); abort_if(!y_coords, "could not allocate y_coords\n"); @@ -52,21 +63,22 @@ int GTSP_create_random_problem( x_coords, y_coords, clusters); abort_if(rval, "generate_random_clusters_2d failed"); - int current_edge = 0; + int curr_edge = 0; for (int i = 0; i < edge_count; i++) for (int j = i + 1; j < node_count; j++) { - edges[current_edge].from = i; - edges[current_edge].to = j; - edges[current_edge].weight = + edges[curr_edge * 2] = i; + edges[curr_edge * 2 + 1] = j; + weights[curr_edge] = get_euclidean_distance(x_coords, y_coords, i, j); - current_edge++; + curr_edge++; } - data->node_count = node_count; - data->edge_count = edge_count; - data->edges = edges; + rval = graph_build(node_count, edge_count, edges, 0, graph); + abort_if(rval, "graph_build failed"); + + data->graph = graph; data->clusters = clusters; data->cluster_count = cluster_count; data->x_coordinates = x_coords; @@ -85,11 +97,11 @@ int GTSP_init_lp(struct LP *lp, struct GTSP *data) { int rval = 0; - int node_count = data->node_count; - int edge_count = data->edge_count; + int node_count = data->graph->node_count; + int edge_count = data->graph->edge_count; int cluster_count = data->cluster_count; int *clusters = data->clusters; - struct Edge *edges = data->edges; + struct Edge *edges = data->graph->edges; for (int i = 0; i < node_count; i++) { @@ -122,7 +134,7 @@ int GTSP_init_lp(struct LP *lp, struct GTSP *data) { double obj = (double) edges[i].weight; double cmatval[] = {1.0, 1.0}; - int cmatind[] = {edges[i].from, edges[i].to}; + int cmatind[] = {edges[i].from->index, edges[i].to->index}; rval = LP_add_cols(lp, 1, 2, &obj, &cmatbeg, cmatind, cmatval, &lb, &ub); @@ -142,9 +154,9 @@ int GTSP_write_data(struct GTSP *data, char *filename) file = fopen(filename, "w"); abort_if(!file, "could not open file"); - fprintf(file, "%d %d\n", data->node_count, data->cluster_count); + fprintf(file, "%d %d\n", data->graph->node_count, data->cluster_count); - for (int i = 0; i < data->node_count; i++) + for (int i = 0; i < data->graph->node_count; i++) { fprintf(file, "%.2lf %.2lf %d\n", data->x_coordinates[i], data->y_coordinates[i], data->clusters[i]); @@ -159,25 +171,27 @@ int GTSP_write_solution(struct GTSP *data, char *filename, double *x) { int rval = 0; - struct Edge *edges = data->edges; - int node_count = data->node_count; + struct Edge *edges = data->graph->edges; + int node_count = data->graph->node_count; + int edge_count = data->graph->edge_count; FILE *file; file = fopen(filename, "w"); abort_if(!file, "could not open file"); int positive_edge_count = 0; - for (int i = 0; i < data->edge_count; i++) + for (int i = 0; i < edge_count; i++) if (x[i + node_count] > 0.5) positive_edge_count++; fprintf(file, "%d\n", positive_edge_count); - for (int i = 0; i < data->edge_count; i++) + for (int i = 0; i < edge_count; i++) if (x[i + node_count] > 0.5) - fprintf(file, "%d %d\n", edges[i].from, edges[i].to); + fprintf(file, "%d %d\n", edges[i].from->index, edges[i].to->index); CLEANUP: if (file) fclose(file); return rval; -} \ No newline at end of file +} + diff --git a/src/gtsp.h b/src/gtsp.h index b4ed5f3..0198cce 100644 --- a/src/gtsp.h +++ b/src/gtsp.h @@ -6,19 +6,11 @@ #define _PROJECT_GTSP_H_ #include "lp.h" - -struct Edge -{ - int from; - int to; - int weight; -}; +#include "graph.h" struct GTSP { - int node_count; - int edge_count; - struct Edge *edges; + struct Graph *graph; int *clusters; int cluster_count; diff --git a/src/main.c b/src/main.c index 51aa8cd..c243066 100644 --- a/src/main.c +++ b/src/main.c @@ -8,6 +8,7 @@ #include "tsp.h" #include "branch_and_cut.h" #include "gtsp.h" +#include "flow.h" char *INPUT_FILENAME = 0; unsigned int SEED = 0; @@ -19,6 +20,79 @@ static int parse_arguments_tsp(int ac, char **av); static void print_usage_tsp(char *f); +int test_max_flow() +{ + int rval = 0; + + int *edges = 0; + double *capacities = 0; + double *flow = 0; + double flow_value; + + FILE *f = fopen("tmp/flow.in", "r"); + abort_if(!f, "could not open input file"); + + struct Graph graph; + graph_init(&graph); + + int node_count, edge_count; + + rval = fscanf(f, "%d %d ", &node_count, &edge_count); + abort_if(rval != 2, "invalid input format"); + + edges = (int *) malloc(4 * edge_count * sizeof(int)); + abort_if(!edges, "could not allocate edges\n"); + + capacities = (double *) malloc(2 * edge_count * sizeof(double)); + abort_if(!capacities, "could not allocate capacities"); + + for (int i = 0; i < edge_count; i++) + { + int from, to, cap; + + rval = fscanf(f, "%d %d %d ", &from, &to, &cap); + abort_if(rval != 3, "invalid input format"); + + edges[i*4] = edges[i*4+3] = from; + edges[i*4+1] = edges[i*4 + 2] = to; + capacities[2 * i] = cap; + capacities[2 * i + 1] = 0; + } + + rval = graph_build(node_count, 2 * edge_count, edges, 1, &graph); + abort_if(rval, "graph_build failed"); + + for (int i = 0; i < edge_count; i++) + { + graph.edges[2*i].reverse = &graph.edges[2*i+1]; + graph.edges[2*i+1].reverse = &graph.edges[2*i]; + } + + flow = (double *) malloc(graph.edge_count * sizeof(double)); + abort_if(!flow, "could not allocate flow"); + + struct Node *from = &graph.nodes[0]; + struct Node *to = &graph.nodes[graph.node_count - 1]; + + rval = flow_find_max_flow(&graph, capacities, from, to, flow, &flow_value); + abort_if(rval, "flow_find_max_flow failed"); + + log_info("Optimal flow has value %f\n", flow_value); + for (int i = 0; i < graph.edge_count; i++) + { + struct Edge *e = &graph.edges[i]; + if(flow[e->index] <= 0) continue; + + log_info(" %d %d %6.2f / %6.2f\n", e->from->index, e->to->index, flow[e->index], capacities[e->index]); + } + + CLEANUP: + if (capacities) free(capacities); + if (edges) free(edges); + if (flow) free(flow); + return rval; +} + int main_tsp(int ac, char **av) { int rval = 0; @@ -172,7 +246,8 @@ static int parse_arguments_tsp(int ac, char **av) int main(int ac, char **av) { - return main_gtsp(ac, av); + return test_max_flow(); +// return main_gtsp(ac, av); // return main_tsp(ac, av); } diff --git a/src/tsp.c b/src/tsp.c index c81ea39..33052e0 100644 --- a/src/tsp.c +++ b/src/tsp.c @@ -38,7 +38,7 @@ int TSP_init_lp(struct LP *lp, struct TSPData *data) abort_if(rval, "LP_new_row failed"); } - /* Build a column for each edge of the graph */ + /* Build a column for each edge_index of the graph */ double lb = 0.0; double ub = 1.0; int cmatbeg = 0; @@ -83,7 +83,7 @@ int TSP_find_violated_subtour_elimination_cut( abort_if(rval, "LP_optimize failed"); abort_if(is_infeasible, "LP is infeasible"); - rval = graph_build(ncount, edge_count, edges, &G); + rval = graph_build(ncount, edge_count, edges, 0, &G); abort_if(rval, "graph_build failed"); x = (double *) malloc(edge_count * sizeof(double)); @@ -185,7 +185,7 @@ int TSP_is_graph_connected( { for (int i = 0; i < G->node_count; i++) { - G->node_list[i].mark = 0; + G->nodes[i].mark = 0; island_nodes[i] = -1; } @@ -193,7 +193,7 @@ int TSP_is_graph_connected( for (int i = 0; i < G->node_count; i++) { - if (G->node_list[i].mark != 0) continue; + if (G->nodes[i].mark != 0) continue; island_sizes[current_island] = 0; @@ -224,29 +224,29 @@ int TSP_find_closest_neighbor_tour( struct Graph G; graph_init(&G); - rval = graph_build(node_count, edge_count, edges, &G); + rval = graph_build(node_count, edge_count, edges, 0, &G); abort_if(rval, "graph_build failed"); for (int j = 0; j < node_count; j++) - G.node_list[j].mark = 0; + G.nodes[j].mark = 0; for (int j = 0; j < node_count; j++) { if (j == node_count - 1) - G.node_list[start].mark = 0; + G.nodes[start].mark = 0; - struct Node *pn = &G.node_list[current_node]; + struct Node *pn = &G.nodes[current_node]; pn->mark = 1; int closest_neighbor = -1; int closest_edge_length = 10000000; - for (int i = 0; i < pn->deg; i++) + for (int i = 0; i < pn->degree; i++) { - int edge = pn->adj[i].e; - int neighbor = pn->adj[i].n; + int edge = pn->adj[i].edge_index; + int neighbor = pn->adj[i].neighbor_index; - if (G.node_list[neighbor].mark == 1) continue; + if (G.nodes[neighbor].mark == 1) continue; if (elen[edge] > closest_edge_length) continue; closest_neighbor = neighbor; @@ -439,7 +439,7 @@ double TSP_find_initial_solution(struct TSPData *data) { double best_val = 1e99; - log_verbose("Finding closest neighbor tour\n"); + log_verbose("Finding closest neighbor_index tour\n"); for (int i = 0; i < data->node_count; i++) { int path_length = 0;