Graph Convolutional Branch and Bound v1.0.0
A TSP solver that combines a graph convolutional network with a 1-Tree branch-and-bound.
Loading...
Searching...
No Matches
branch_and_bound.c
Go to the documentation of this file.
1
15#include "branch_and_bound.h"
16
17
18void dfs(SubProblem *subProblem) {
19 List *stack = new_list();
20 unsigned short num_nodes = subProblem->oneTree.num_nodes;
21 Node start;
22 int parentId[num_nodes];
23 unsigned short pathLength[num_nodes];
24 bool visited[num_nodes];
25
26 for (unsigned short i = 0; i < num_nodes; i++) {
27 Node current = subProblem->oneTree.nodes[i];
29 start = current;
30 }
31 parentId[i] = -1;
32 pathLength[i] = 0;
33 visited[i] = false;
34 }
35
36 add_elem_list_bottom(stack, &start);
37
38 while (stack->size > 0 && parentId[start.positionInGraph] == -1) {
39 Node *currentNode = get_list_elem_index(stack, 0);
40 delete_list_elem_index(stack, 0);
41 if (!visited[currentNode->positionInGraph]) {
42 visited[currentNode->positionInGraph] = true;
43 for (unsigned short i = 0; i < currentNode->num_neighbours; i++) {
44 unsigned short dest = currentNode->neighbours[i];
45 if (!visited[dest]) {
46 pathLength[dest] = pathLength[currentNode->positionInGraph] + 1;
47 parentId[dest] = currentNode->positionInGraph;
48 Node *neighbour = &subProblem->oneTree.nodes[dest];
49 add_elem_list_index(stack, neighbour, 0);
50 } else if (parentId[dest] == -1) {
51 // start node
52 unsigned short path = pathLength[currentNode->positionInGraph] + 1;
53 if (path > 2) {
54 parentId[dest] = currentNode->positionInGraph;
55 pathLength[dest] = path;
56 }
57 }
58 }
59 }
60 }
61 del_list(stack);
62
63 int fromNode = -1;
64 int toNode = start.positionInGraph;
65
66 //printf("Path Length: %d\n", pathLength[toNode]);
67
68 if (pathLength[toNode] > 2) {
69 while (fromNode != start.positionInGraph) {
70 fromNode = parentId[toNode];
71 Edge current_in_cycle = problem->graph.edges_matrix[fromNode][toNode];
72 subProblem->cycleEdges[subProblem->num_edges_in_cycle].src = current_in_cycle.src;
73 subProblem->cycleEdges[subProblem->num_edges_in_cycle].dest = current_in_cycle.dest;
74 subProblem->num_edges_in_cycle++;
75 toNode = fromNode;
76 }
77 }
78
79}
80
81
82bool check_hamiltonian(SubProblem *subProblem) {
83 dfs(subProblem);
84 return subProblem->num_edges_in_cycle == subProblem->oneTree.num_edges;
85}
86
87
88BBNodeType mst_to_one_tree(SubProblem *currentSubproblem, Graph *graph) {
89
90 Node candidate = graph->nodes[problem->candidateNodeId];
91 int bestEdgesPos[2];
92 double bestEdgesWeight[2];
93 unsigned short src = candidate.positionInGraph;
94 unsigned short others [candidate.num_neighbours];
95 unsigned short num_others = 0;
96 unsigned short toAdd = 0;
97
98 for (unsigned short i = 0; i < candidate.num_neighbours && toAdd<=2; i++) {
99 unsigned short dest = candidate.neighbours[i];
100
101 if (currentSubproblem->num_mandatory_edges > 0 &&
102 currentSubproblem->constraints[src][dest] == MANDATORY) {
103 bestEdgesWeight[toAdd] = graph->edges_matrix[src][dest].weight;
104 bestEdgesPos[toAdd] = graph->edges_matrix[src][dest].positionInGraph;
105 toAdd++;
106 } else if (currentSubproblem->num_forbidden_edges == 0 ||
107 currentSubproblem->constraints[src][dest] == NOTHING) {
108 others[num_others] = dest;
109 num_others++;
110 }
111 }
112 if (toAdd > 2 || (toAdd + num_others) < 2) {
113 return CLOSED_UNFEASIBLE;
114 } else if (toAdd == 2){
115 add_edge(&currentSubproblem->oneTree, &graph->edges[bestEdgesPos[0]]);
116 add_edge(&currentSubproblem->oneTree, &graph->edges[bestEdgesPos[1]]);
117 return OPEN;
118 } else if(toAdd == 1){
119 add_edge(&currentSubproblem->oneTree, &graph->edges[bestEdgesPos[0]]);
120
121 double bestFoundWeight = INFINITE;
122 int bestFoundPos = -1;
123
124 for (unsigned short j = 0; j < num_others; j++) {
125 unsigned short dest = others[j];
126 Edge candidateEdge = graph->edges_matrix[src][dest];
127
128 if (bestFoundWeight > candidateEdge.weight) {
129 bestFoundPos = candidateEdge.positionInGraph;
130 bestFoundWeight = candidateEdge.weight;
131 }
132 }
133
134 add_edge(&currentSubproblem->oneTree, &graph->edges[bestFoundPos]);
135
136 return OPEN;
137 } else{
138
139 bestEdgesPos[0] = -1;
140 bestEdgesPos[1] = -1;
141 bestEdgesWeight[0] = INFINITE;
142 bestEdgesWeight[1] = INFINITE;
143
144 for (unsigned short j = 0; j < num_others; j++) {
145 unsigned short dest = others[j];
146 Edge candidateEdge = graph->edges_matrix[src][dest];
147
148 if (bestEdgesWeight[0] > candidateEdge.weight) {
149 bestEdgesPos[1] = bestEdgesPos[0];
150 bestEdgesWeight[1] = bestEdgesWeight[0];
151 bestEdgesPos[0] = candidateEdge.positionInGraph;
152 bestEdgesWeight[0] = candidateEdge.weight;
153 } else if (bestEdgesWeight[1] > candidateEdge.weight) {
154 bestEdgesPos[1] = candidateEdge.positionInGraph;
155 bestEdgesWeight[1] = candidateEdge.weight;
156 }
157 }
158
159 add_edge(&currentSubproblem->oneTree, &graph->edges[bestEdgesPos[0]]);
160 add_edge(&currentSubproblem->oneTree, &graph->edges[bestEdgesPos[1]]);
161
162 return OPEN;
163 }
164}
165
166
167void initialize_matrix(SubProblem *subProblem) {
168
169 subProblem->num_mandatory_edges = 0;
170 subProblem->num_forbidden_edges = 0;
171 for (short i = 0; i < MAX_VERTEX_NUM; i++) {
172 for (short j = i; j < MAX_VERTEX_NUM; j++) {
173 if(j == i){
174 subProblem->constraints[i][j] = FORBIDDEN;
175
176 } else{
177 subProblem->constraints[i][j] = NOTHING;
178 subProblem->constraints[j][i] = NOTHING;
179 }
180 }
181 }
182}
183
184
185bool infer_constraints(SubProblem * subProblem){
186
187 bool valid = true;
188
189 for (short i = 0; i < MAX_VERTEX_NUM && valid; i++) {
190
191 short num_nothing_node = 0;
192 short num_mandatory_node = 0;
193 short num_forbidden_node = 0;
194 short nothing_nodes[MAX_VERTEX_NUM];
195
196 for (short j = 0; j < MAX_VERTEX_NUM; j++) {
197 if (subProblem->constraints[i][j] == NOTHING) {
198 nothing_nodes[num_nothing_node] = j;
199 num_nothing_node++;
200 } else if (subProblem->constraints[i][j] == MANDATORY) {
201 num_mandatory_node++;
202 } else {
203 num_forbidden_node++;
204 }
205 }
206
207 if (num_mandatory_node == 2) {
208 for (short j = 0; j < num_nothing_node; j++) {
209 subProblem->constraints[i][nothing_nodes[j]] = FORBIDDEN;
210 subProblem->constraints[nothing_nodes[j]][i] = FORBIDDEN;
211 subProblem->num_forbidden_edges++;
213 }
214 } else if (num_mandatory_node > 2 || (MAX_VERTEX_NUM - num_forbidden_node < 2)) {
215 valid = false;
216 } else if (MAX_VERTEX_NUM - num_forbidden_node == 2) {
217
218 if (num_nothing_node + num_mandatory_node == 2) {
219 for (short j = 0; j < num_nothing_node; j++) {
220 subProblem->constraints[i][nothing_nodes[j]] = MANDATORY;
221 subProblem->constraints[nothing_nodes[j]][i] = MANDATORY;
222 subProblem->mandatoryEdges[subProblem->num_mandatory_edges].src = i;
223 subProblem->mandatoryEdges[subProblem->num_mandatory_edges].dest = nothing_nodes[j];
224 subProblem->num_mandatory_edges++;
226 }
227 }
228 }
229 }
230 return valid;
231}
232
233
234void copy_constraints(SubProblem *subProblem, const SubProblem *otherSubProblem) {
235 subProblem->num_mandatory_edges = 0;
236 subProblem->num_forbidden_edges = 0;
237 for (short i = 0; i < MAX_VERTEX_NUM; i++) {
238
239 for (short j = i; j < MAX_VERTEX_NUM; j++) {
240 subProblem->constraints[i][j] = otherSubProblem->constraints[i][j];
241 subProblem->constraints[j][i] = otherSubProblem->constraints[j][i];
242
243 if(subProblem->constraints[i][j] == MANDATORY){
244 subProblem->mandatoryEdges[subProblem->num_mandatory_edges].src = i;
245 subProblem->mandatoryEdges[subProblem->num_mandatory_edges].dest = j;
246 subProblem->num_mandatory_edges++;
247 }
248 else if(subProblem->constraints[i][j] == FORBIDDEN){
249 subProblem->num_forbidden_edges++;
250 }
251 }
252 }
253}
254
255
256void branch(SubProblemsList *openSubProblems, SubProblem *currentSubProblem){
257
258 if (currentSubProblem->treeLevel + 1 > problem->totTreeLevels) {
260 }
261
262 Edge to_branch = problem->graph.edges[currentSubProblem->edge_to_branch];
263 double prob_edge = to_branch.prob;
264
265 for (short i = 0; i < 2; i++) {
267 SubProblem child;
268 child.num_edges_in_cycle = 0;
269 child.type = OPEN;
270 child.prob = currentSubProblem->prob;
271 child.id = problem->generatedBBNodes;
272 child.fatherId = currentSubProblem->id;
273 child.value = currentSubProblem->value;
274 child.treeLevel = currentSubProblem->treeLevel + 1;
275 child.edge_to_branch = -1;
276 copy_constraints(&child, currentSubProblem);
277
278 if(HYBRID) {
279
280 if (prob_edge >= PROB_BRANCH) {
281 if (i == 0) {
282 child.constraints[to_branch.src][to_branch.dest] = MANDATORY;
283 child.constraints[to_branch.dest][to_branch.src] = MANDATORY;
284 child.mandatoryEdges[child.num_mandatory_edges].src = to_branch.src;
285 child.mandatoryEdges[child.num_mandatory_edges].dest = to_branch.dest;
286 child.num_mandatory_edges++;
287 } else {
288 child.constraints[to_branch.src][to_branch.dest] = FORBIDDEN;
289 child.constraints[to_branch.dest][to_branch.src] = FORBIDDEN;
290 child.num_forbidden_edges++;
291 }
292 } else {
293 if (i == 0) {
294 child.constraints[to_branch.src][to_branch.dest] = FORBIDDEN;
295 child.constraints[to_branch.dest][to_branch.src] = FORBIDDEN;
296 child.num_forbidden_edges++;
297 } else {
298 child.constraints[to_branch.src][to_branch.dest] = MANDATORY;
299 child.constraints[to_branch.dest][to_branch.src] = MANDATORY;
300 child.mandatoryEdges[child.num_mandatory_edges].src = to_branch.src;
301 child.mandatoryEdges[child.num_mandatory_edges].dest = to_branch.dest;
302 child.num_mandatory_edges++;
303 }
304 }
305 }
306 else{
307 if (i == 0) {
308 child.constraints[to_branch.src][to_branch.dest] = MANDATORY;
309 child.constraints[to_branch.dest][to_branch.src] = MANDATORY;
310 child.mandatoryEdges[child.num_mandatory_edges].src = to_branch.src;
311 child.mandatoryEdges[child.num_mandatory_edges].dest = to_branch.dest;
312 child.num_mandatory_edges++;
313 } else {
314 child.constraints[to_branch.src][to_branch.dest] = FORBIDDEN;
315 child.constraints[to_branch.dest][to_branch.src] = FORBIDDEN;
316 child.num_forbidden_edges++;
317 }
318 }
319
320 if(infer_constraints(&child)){
321 long position = -1;
322
324 openSubProblems);
325 for (size_t j = 0; j < openSubProblems->size && position == -1; j++) {
326 SubProblem *open_subProblem = SubProblemList_iterator_get_next(subProblem_iterators);
327 if (compare_subproblems(&child, open_subProblem)) {
328 position = (long) j;
329 }
330 }
331 delete_SubProblemList_iterator(subProblem_iterators);
332 if (position == -1) {
333 add_elem_SubProblemList_bottom(openSubProblems, &child);
334 } else {
335 add_elem_SubProblemList_index(openSubProblems, &child, position);
336 }
337 }
338 }
339}
340
341
342double max_edge_path_1Tree(SubProblem *currentSubProb, double *replacement_costs,
343 unsigned short start_node, unsigned short end_node){
344 List *stack = new_list();
345 unsigned short num_nodes = currentSubProb->oneTree.num_nodes;
346 Node start;
347
348 bool visited[num_nodes];
349 int parentId[num_nodes];
350
351 for (unsigned short i = 0; i < num_nodes; i++) {
352 Node current = currentSubProb->oneTree.nodes[i];
353 if (current.positionInGraph == start_node) {
354 start = current;
355 }
356 visited[i] = false;
357 parentId[i] = -1;
358 }
359
360 add_elem_list_bottom(stack, &start);
361
362 while (stack->size > 0 && parentId[end_node] == -1) {
363 Node *currentNode = get_list_elem_index(stack, 0);
364 delete_list_elem_index(stack, 0);
365 if (!visited[currentNode->positionInGraph]) {
366 visited[currentNode->positionInGraph] = true;
367 for (unsigned short i = 0; i < currentNode->num_neighbours; i++) {
368 unsigned short dest = currentNode->neighbours[i];
369 if (!visited[dest] && problem->candidateNodeId != dest) {
370 parentId[dest] = currentNode->positionInGraph;
371 Node *neighbour = &currentSubProb->oneTree.nodes[dest];
372 add_elem_list_index(stack, neighbour, 0);
373 }
374 }
375 }
376 }
377 del_list(stack);
378
379
380 unsigned short fromNode = -1;
381 unsigned short toNode = end_node;
382 double max_edge_weight = -1;
383 double edge_nin_1tree_weight = problem->graph.edges_matrix[start_node][end_node].weight;
384
385 while (fromNode != start_node) {
386 fromNode = parentId[toNode];
387
388 short position_in_1_tree = -1;
389
390 if(currentSubProb->oneTree.edges_matrix[fromNode][toNode] != -1){
391
392 if(currentSubProb->constraints[fromNode][toNode] == NOTHING) {
393
394 position_in_1_tree = currentSubProb->oneTree.edges_matrix[fromNode][toNode];
395
396 Edge current_in_path = currentSubProb->oneTree.edges[position_in_1_tree];
397 double current_edge_weight = problem->graph.edges_matrix[current_in_path.src][current_in_path.dest].weight;
398
399 if (current_edge_weight > max_edge_weight) {
400 max_edge_weight = current_edge_weight;
401 }
402
403 if (edge_nin_1tree_weight < current_edge_weight + replacement_costs[current_in_path.positionInGraph]) {
404 replacement_costs[current_in_path.positionInGraph] = edge_nin_1tree_weight - current_edge_weight;
405 }
406 }
407
408 toNode = fromNode;
409
410 } else{
411 printf("ERROR: Edge not found in 1-tree\n");
412 exit(1);
413 }
414 }
415
416
417 return max_edge_weight == -1 ? -INFINITE: max_edge_weight;
418}
419
420
421int variable_fixing(SubProblem *currentSubProb){
422 int num_fixed = 0;
423 double replacement_costs [MAX_VERTEX_NUM - 2]; // for all the edges in the 1-tree except the best replacement to maintain the 1-tree
424 double best_candidate_replacement = INFINITE;
425
426 for (int i = 0; i < MAX_VERTEX_NUM - 2; i++){
427 replacement_costs[i] = INFINITE;
428 }
429
430 for (unsigned int i = 0; i < problem->graph.num_edges; i++){
431 Edge current_edge = problem->graph.edges[i];
432
433 if(currentSubProb->constraints[current_edge.src][current_edge.dest] == NOTHING){
434 if(currentSubProb->oneTree.edges_matrix[current_edge.src][current_edge.dest] == -1){
435
436 double max_edge_path = 0;
437
438 if(current_edge.dest != problem->candidateNodeId && current_edge.src != problem->candidateNodeId){
439 max_edge_path = max_edge_path_1Tree(currentSubProb, replacement_costs,current_edge.src, current_edge.dest);
440 }
441
442 else{
443
444 double first_candidate_edge_weight = problem->graph.edges_matrix[problem->candidateNodeId][currentSubProb->oneTree.nodes[problem->candidateNodeId].neighbours[0]].weight;
445 double second_candidate_edge_weight = problem->graph.edges_matrix[problem->candidateNodeId][currentSubProb->oneTree.nodes[problem->candidateNodeId].neighbours[1]].weight;
446
447 if (first_candidate_edge_weight > second_candidate_edge_weight){
448 max_edge_path = first_candidate_edge_weight;
449 } else{
450 max_edge_path = second_candidate_edge_weight;
451 }
452 }
453
454 if (currentSubProb->oneTree.cost + current_edge.weight - max_edge_path >= problem->bestValue){
455 currentSubProb->constraints[current_edge.src][current_edge.dest] = FORBIDDEN;
456 currentSubProb->constraints[current_edge.dest][current_edge.src] = FORBIDDEN;
457 currentSubProb->num_forbidden_edges++;
458 num_fixed++;
459 }
460
461 }
462
463 if(current_edge.src == problem->candidateNodeId || current_edge.dest == problem->candidateNodeId){
464 if(current_edge.weight < best_candidate_replacement){
465 best_candidate_replacement = current_edge.weight;
466 }
467 }
468 }
469 }
470
471
472 for (int i = 0; i < MAX_VERTEX_NUM; i++){
473 Edge edge_1tree = currentSubProb->oneTree.edges[i];
474 double edge_1tree_weight = problem->graph.edges_matrix[edge_1tree.src][edge_1tree.dest].weight;
475
476 if(currentSubProb->constraints[edge_1tree.src][edge_1tree.dest] == NOTHING) {
477 if (edge_1tree.src != problem->candidateNodeId && edge_1tree.dest != problem->candidateNodeId) {
478 if (currentSubProb->oneTree.cost + replacement_costs[i] - edge_1tree_weight >= problem->bestValue) {
479 currentSubProb->constraints[edge_1tree.src][edge_1tree.dest] = MANDATORY;
480 currentSubProb->constraints[edge_1tree.dest][edge_1tree.src] = MANDATORY;
481 currentSubProb->mandatoryEdges[currentSubProb->num_mandatory_edges].src = edge_1tree.src;
482 currentSubProb->mandatoryEdges[currentSubProb->num_mandatory_edges].dest = edge_1tree.dest;
483 currentSubProb->num_mandatory_edges++;
484 num_fixed++;
485 }
486 } else {
487 if(currentSubProb->oneTree.cost + best_candidate_replacement - edge_1tree_weight >= problem->bestValue){
488 currentSubProb->constraints[edge_1tree.src][edge_1tree.dest] = MANDATORY;
489 currentSubProb->constraints[edge_1tree.dest][edge_1tree.src] = MANDATORY;
490 currentSubProb->mandatoryEdges[currentSubProb->num_mandatory_edges].src = edge_1tree.src;
491 currentSubProb->mandatoryEdges[currentSubProb->num_mandatory_edges].dest = edge_1tree.dest;
492 currentSubProb->num_mandatory_edges++;
493 num_fixed++;
494 }
495 }
496 }
497 }
498
499 return num_fixed;
500}
501
502
503void constrained_kruskal(Graph * graph, SubProblem * subProblem, unsigned short candidateId) {
504 create_mst(&subProblem->oneTree,graph->nodes, graph->num_nodes);
505 Forest forest;
506 create_forest_constrained(&forest, graph->nodes, graph->num_nodes, candidateId);
507 wrap_quick_sort(graph);
508
509 unsigned short num_edges_inMST = 0;
510 for (unsigned short i = 0; i < subProblem->num_mandatory_edges; i++) {
511 ConstrainedEdge current_mandatory = subProblem->mandatoryEdges[i];
512 Edge mandatory_edge = graph->edges_matrix[current_mandatory.src][current_mandatory.dest];
513 unsigned short src = mandatory_edge.src;
514 unsigned short dest = mandatory_edge.dest;
515
516 if (src != candidateId && dest != candidateId) {
517
518 Set *set1_root = find(&forest.sets[src]);
519 Set *set2_root = find(&forest.sets[dest]);
520 if (set1_root->num_in_forest != set2_root->num_in_forest) {
521 merge(set1_root, set2_root);
522 // add the edge to the MST
523 add_edge(&subProblem->oneTree, &mandatory_edge);
524 num_edges_inMST++;
525 }
526 }
527 }
528
529 unsigned short num_edges_inG = 0;
530
531 while (num_edges_inG < graph->num_edges && num_edges_inMST < graph->num_nodes - 2) {
532
533 Edge current_edge = graph->edges[num_edges_inG];
534
535 unsigned short src = current_edge.src;
536 unsigned short dest = current_edge.dest;
537
538 if (src != candidateId && dest != candidateId){
539
540 if (subProblem->num_forbidden_edges == 0 || subProblem->constraints[src][dest] != FORBIDDEN) {
541
542 Set *set1_root = find(&forest.sets[src]);
543 Set *set2_root = find(&forest.sets[dest]);
544
545 if (set1_root->num_in_forest != set2_root->num_in_forest) {
546 merge(set1_root, set2_root);
547 // add the edge to the MST
548 add_edge(&subProblem->oneTree, &current_edge);
549 num_edges_inMST++;
550 }
551 }
552 }
553
554 num_edges_inG++;
555 }
556
557 if (num_edges_inMST == graph->num_nodes - 2) {
558 subProblem->oneTree.isValid = true;
559 } else {
560 subProblem->oneTree.isValid = false;
561 }
562}
563
564
565void constrained_prim(Graph * graph, SubProblem * subProblem, unsigned short candidateId) {
566
567 Graph graph_copy = *graph;
568 create_mst(&subProblem->oneTree,graph->nodes, graph->num_nodes);
569 FibonacciHeap heap;
571
572 OrdTreeNode tree_nodes[graph->num_nodes];
573 bool in_heap [graph->num_nodes];
574 double values [graph->num_nodes];
575 int fathers [graph->num_nodes];
576
577 bool start = true;
578
579 for (unsigned short i = 0; i < graph->num_nodes; i++){
580 in_heap[i] = false;
581 fathers[i] = -1;
582 values[i] = start ? FLT_MAX/2 : FLT_MAX;
583 start = false;
584 }
585
586 for (unsigned short i = 0; i < subProblem->num_mandatory_edges; i++){
587 ConstrainedEdge current_mandatory = subProblem->mandatoryEdges[i];
588 unsigned short src = current_mandatory.src;
589 unsigned short dest = current_mandatory.dest;
590
591 if(src != candidateId && dest != candidateId) {
592
593 graph_copy.edges_matrix[src][dest].weight = -((double) problem->graph.num_nodes);
594 graph_copy.edges_matrix[dest][src].weight = -((double) problem->graph.num_nodes);
595 graph_copy.edges[graph->edges_matrix[src][dest].positionInGraph].weight = -((double) problem->graph.num_nodes);
596 }
597 }
598
599
600 for (unsigned short i = 0; i < graph_copy.num_nodes; i++) {
601 if(i != candidateId){
602 create_insert_node(&heap, &tree_nodes[i], i, values[i]);
603 in_heap[i] = true;
604 }
605 }
606
607 while(heap.num_nodes != 0){
608 int min_pos = extract_min(&heap);
609 if(min_pos == -1){
610 fprintf(stderr, "Error: min_pos == -1\n");
611 exit(1);
612 }
613 else{
614 in_heap[min_pos] = false;
615 for(unsigned short i = 0; i < graph_copy.nodes[min_pos].num_neighbours; i++){
616 unsigned short neigh = graph_copy.nodes[min_pos].neighbours[i];
617 if(neigh != min_pos && in_heap[neigh]) {
618 double weight = graph_copy.edges_matrix[min_pos][neigh].weight;
619 if (weight < tree_nodes[neigh].value){
620 if (subProblem->num_forbidden_edges == 0 || subProblem->constraints[min_pos][neigh] != FORBIDDEN){
621 fathers[neigh] = min_pos;
622 decrease_value(&heap, &tree_nodes[neigh], weight);
623 }
624 }
625 }
626 }
627 }
628 }
629
630 for(unsigned short i = 0; i < graph->num_nodes; i++){
631 if(fathers[i] != -1){
632 add_edge(&subProblem->oneTree, &graph->edges_matrix[i][fathers[i]]);
633 }
634 }
635
636 if(subProblem->oneTree.num_edges == graph->num_nodes - 2){
637 subProblem->oneTree.isValid = true;
638 }
639 else{
640 subProblem->oneTree.isValid = false;
641 }
642
643}
644
645
646// a better than b?
647bool compare_subproblems(const SubProblem *a, const SubProblem *b) {
648 if (HYBRID) {
649 return (b->value - a->value) > EPSILON ||
650 ( (b->value > a->value) && (a->prob - b->prob) >= BETTER_PROB);
651 } else {
652 return (b->value - a->value) > EPSILON;
653 }
654}
655
656
657void bound(SubProblem *currentSubProb) {
658
659 if ((problem->bestSolution.value - currentSubProb->value) > EPSILON || currentSubProb->treeLevel == 1) {
660 currentSubProb->timeToReach = ((float) (clock() - problem->start)) / CLOCKS_PER_SEC;
662
663 double pi[MAX_VERTEX_NUM] = {0};
664 double v[MAX_VERTEX_NUM] = {0};
665 double v_old[MAX_VERTEX_NUM] = {0};
666 double total_pi = 0;
667 int k = 10;
668 int max_iter = currentSubProb->treeLevel == 1 ? (int) NUM_HK_INITIAL_ITERATIONS : (int) NUM_HK_ITERATIONS;
669 max_iter += k;
670 double best_lower_bound = 0;
671 double t_0;
672 SubProblemsList generatedSubProblems;
673 new_SubProblemList(&generatedSubProblems);
674 Graph *used_graph = &problem->graph;
675 bool first_iter = true;
676
677 double prob_branch [MAX_EDGES_NUM] = {0};
678
679 for (int iter = 1; iter <= max_iter; iter++) {
680
681 SubProblem analyzedSubProblem = *currentSubProb;
682 BBNodeType type;
683 if(!first_iter) {
684 for (unsigned short j = 0; j < problem->graph.num_edges; j++) {
685 if ((pi[used_graph->edges[j].src] +
686 pi[used_graph->edges[j].dest]) != 0) {
687 used_graph->edges[j].weight += (pi[used_graph->edges[j].src] +
688 pi[used_graph->edges[j].dest]);
689 used_graph->edges_matrix[used_graph->edges[j].src][used_graph->edges[j].dest].weight = used_graph->edges[j].weight;
690 used_graph->edges_matrix[used_graph->edges[j].dest][used_graph->edges[j].src].weight = used_graph->edges[j].weight;
691 used_graph->orderedEdges = false;
692 }
693 }
694 }
695
696 if(PRIM){
697 constrained_prim(used_graph, &analyzedSubProblem, problem->candidateNodeId);
698 }
699 else{
700 constrained_kruskal(used_graph, &analyzedSubProblem, problem->candidateNodeId);
701 }
702
703 if (analyzedSubProblem.oneTree.isValid) {
704 type = mst_to_one_tree(&analyzedSubProblem, used_graph);
705
706 if (type == OPEN) {
707 analyzedSubProblem.prob = analyzedSubProblem.oneTree.prob;
708 analyzedSubProblem.type = type;
709 analyzedSubProblem.value = 0;
710
711 for (int e = 0; e < problem->graph.num_nodes; e++) {
712 Edge *edge = &analyzedSubProblem.oneTree.edges[e];
713 analyzedSubProblem.value += problem->graph.edges_matrix[edge->src][edge->dest].weight;
714
715 if (iter > max_iter - k) {
716 prob_branch[problem->graph.edges_matrix[edge->src][edge->dest].positionInGraph] =
717 ((prob_branch[problem->graph.edges_matrix[edge->src][edge->dest].positionInGraph] *
718 (double) k) + 1) / ((double) k);
719 }
720 }
721
722 if (problem->bestValue - analyzedSubProblem.value <= EPSILON) {
723 analyzedSubProblem.type = CLOSED_BOUND;
724 } else {
725 analyzedSubProblem.num_edges_in_cycle = 0;
726 if (check_hamiltonian(&analyzedSubProblem)) {
727 problem->bestValue = analyzedSubProblem.value;
728 analyzedSubProblem.type = iter == 1 ? CLOSED_1TREE: CLOSED_SUBGRADIENT;
729 problem->bestSolution = analyzedSubProblem;
730 printf("Updated best value: %f, at time: %f\n", problem->bestValue, ((float) (clock() - problem->start)) / CLOCKS_PER_SEC);
731 } else {
732 analyzedSubProblem.type = OPEN;
733 }
734 }
735
736 if(analyzedSubProblem.type != OPEN){
737 if(iter == 1 || (analyzedSubProblem.type == CLOSED_SUBGRADIENT)) {
738 currentSubProb->type = analyzedSubProblem.type;
739 return;
740 }
741 }
742
743 double current_lb = analyzedSubProblem.oneTree.cost - (2 * total_pi);
744
745 if (current_lb > best_lower_bound || first_iter) {
746 best_lower_bound = current_lb;
747 if (first_iter) {
748 first_iter = false;
749 used_graph = &problem->reformulationGraph;
750 }
751
752 t_0 = best_lower_bound / (2 * MAX_VERTEX_NUM);
753 }
754
755 // change the graph to the original one, because the dual variables are calculated on the original graph
756 *used_graph = problem->graph;
757 add_elem_SubProblemList_bottom(&generatedSubProblems, &analyzedSubProblem);
758
759 for (unsigned short i = 0; i < problem->graph.num_nodes; i++) {
760 v[i] = (double) (analyzedSubProblem.oneTree.nodes[i].num_neighbours - 2);
761 }
762
763 double t =
764 (((double) (iter - 1)) * (((double) (2 * max_iter) - 5) / (2 * (double) (max_iter - 1))) * t_0)
765 - (((double) iter - 2) * t_0) +
766 ((t_0 * ((double) iter - 1) * ((double) iter - 2)) /
767 (2 * ((double) max_iter - 1) * ((double) max_iter - 2)));
768
769 total_pi = 0;
770
771 for (unsigned short j = 0; j < problem->graph.num_nodes; j++) {
772 if (v[j] != 0) {
773 pi[j] += (double) ((0.6 * t * v[j]) + (0.4 * t * v_old[j]));
774 }
775 v_old[j] = v[j];
776 total_pi += pi[j];
777 }
778 }
779
780 else{
781 currentSubProb->type = CLOSED_UNFEASIBLE;
782 return;
783 }
784 } else {
785 currentSubProb->type = CLOSED_UNFEASIBLE;
786 return;
787 }
788
789 }
790
791 *currentSubProb = *get_SubProblemList_elem_index(&generatedSubProblems,0);
792 currentSubProb->oneTree.cost = currentSubProb->value; // mi serve valore originale per variabile fixing
793 SubProblem best_subproblem = *currentSubProb;
794 SubProblemsListIterator *subProblem_iterators = create_SubProblemList_iterator(&generatedSubProblems);
795 for (size_t j = 0; j < generatedSubProblems.size; j++) {
796 SubProblem *generatedSubProblem = SubProblemList_iterator_get_next(subProblem_iterators);
797 if (generatedSubProblem->value > best_subproblem.value &&
798 generatedSubProblem->value <= best_lower_bound) {
799 best_subproblem = *generatedSubProblem;
800 }
801 }
802 currentSubProb->type = best_subproblem.type;
803 currentSubProb->value = best_subproblem.value; // metto valore massimo trovato per migliorare ordinamento
804 delete_SubProblemList_iterator(subProblem_iterators);
805 delete_SubProblemList(&generatedSubProblems);
806 //printf("\nBest lower bound: %f, Best value: %f\n", best_lower_bound, best_subproblem.value);
807
808 if(currentSubProb->type == OPEN) {
809 double best_prob_branch = -1;
810 double best_prob = -1;
811
812 for (int i = 0; i < problem->graph.num_edges; i++) {
813
814 Edge current_edge = problem->graph.edges[i];
815
816 if (currentSubProb->constraints[current_edge.src][current_edge.dest] == NOTHING) {
817
818 if(best_subproblem.oneTree.edges_matrix[current_edge.src][current_edge.dest] != -1){
819 if ((fabs(prob_branch[i] - 0.5) < fabs(best_prob_branch - 0.5)) ||
820 (HYBRID && (fabs(prob_branch[i] - 0.5) == fabs(best_prob_branch - 0.5))
821 && (current_edge.prob > best_prob))) {
822
823 best_prob_branch = prob_branch[i];
824 best_prob = current_edge.prob;
825 currentSubProb->edge_to_branch = i;
826 }
827
828 }
829 }
830 }
831 //printf("\nBest edge to branch: %d, with score %f and prob %f; BEST VALUE: %f\n", currentSubProb->edge_to_branch, best_prob_branch, best_prob, problem->bestValue);
832 }
833 } else {
834 currentSubProb->type = CLOSED_BOUND;
835 }
836}
837
838
840 return ((clock() - problem->start) / CLOCKS_PER_SEC) > TIME_LIMIT_SECONDS;
841}
842
843
844void nearest_prob_neighbour(unsigned short start_node) {
845 SubProblem nn_subProblem;
846 nn_subProblem.num_forbidden_edges = 0;
847 nn_subProblem.num_mandatory_edges = 0;
848 nn_subProblem.num_edges_in_cycle = 0;
849 nn_subProblem.timeToReach = ((float) (clock() - problem->start)) / CLOCKS_PER_SEC;
851 unsigned short current_node = start_node;
852 bool visited[MAX_VERTEX_NUM] = {false};
853 ConstrainedEdge cycleEdge;
854
855 for (unsigned short visited_count = 0; visited_count < problem->graph.num_nodes; visited_count++) {
856
857 if (visited_count == problem->graph.num_nodes - 1) {
858 add_edge(&nn_subProblem.oneTree, &problem->graph.edges_matrix[current_node][start_node]);
859 cycleEdge.src = current_node;
860 cycleEdge.dest = start_node;
861 nn_subProblem.cycleEdges[nn_subProblem.num_edges_in_cycle] = cycleEdge;
862 nn_subProblem.num_edges_in_cycle++;
863 } else {
864 double best_edge_value = INFINITE;
865 unsigned short best_neighbour = current_node;
866 for (unsigned short i = 0; i < problem->graph.nodes[current_node].num_neighbours; i++) {
867
868 if (problem->graph.edges_matrix[current_node][problem->graph.nodes[current_node].neighbours[i]].weight <
869 best_edge_value
870 && !visited[problem->graph.nodes[current_node].neighbours[i]]) {
871 best_edge_value = problem->graph.edges_matrix[current_node][problem->graph.nodes[current_node].neighbours[i]].weight;
872 best_neighbour = problem->graph.nodes[current_node].neighbours[i];
873 }
874 }
875 add_edge(&nn_subProblem.oneTree, &problem->graph.edges_matrix[current_node][best_neighbour]);
876 cycleEdge.src = current_node;
877 cycleEdge.dest = best_neighbour;
878 nn_subProblem.cycleEdges[nn_subProblem.num_edges_in_cycle] = cycleEdge;
879 nn_subProblem.num_edges_in_cycle++;
880 visited[current_node] = true;
881 current_node = best_neighbour;
882 }
883 }
884 nn_subProblem.value = nn_subProblem.oneTree.cost;
885 nn_subProblem.oneTree.isValid = true;
886 nn_subProblem.type = CLOSED_NN;
887 nn_subProblem.prob = nn_subProblem.oneTree.prob;
888
889 if (HYBRID) {
890 SubProblem prob_nn_subProblem;
891 prob_nn_subProblem.num_forbidden_edges = 0;
892 prob_nn_subProblem.num_mandatory_edges = 0;
893 prob_nn_subProblem.num_edges_in_cycle = 0;
894 create_mst(&prob_nn_subProblem.oneTree, problem->graph.nodes, problem->graph.num_nodes);
895 bool prob_visited[MAX_VERTEX_NUM] = {false};
896 current_node = start_node;
897
898 for (unsigned short visited_count = 0; visited_count < problem->graph.num_nodes; visited_count++) {
899
900 if (visited_count == problem->graph.num_nodes - 1) {
901 add_edge(&prob_nn_subProblem.oneTree, &problem->graph.edges_matrix[current_node][start_node]);
902 cycleEdge.src = current_node;
903 cycleEdge.dest = start_node;
904 prob_nn_subProblem.cycleEdges[prob_nn_subProblem.num_edges_in_cycle] = cycleEdge;
905 prob_nn_subProblem.num_edges_in_cycle++;
906 } else {
907 double best_edge_prob = -1;
908 unsigned short best_neighbour = current_node;
909 for (unsigned short i = 0; i < problem->graph.nodes[current_node].num_neighbours; i++) {
910
911 if (problem->graph.edges_matrix[current_node][problem->graph.nodes[current_node].neighbours[i]].prob >
912 best_edge_prob
913 && !prob_visited[problem->graph.nodes[current_node].neighbours[i]]) {
914 best_edge_prob = problem->graph.edges_matrix[current_node][problem->graph.nodes[current_node].neighbours[i]].prob;
915 best_neighbour = problem->graph.nodes[current_node].neighbours[i];
916 }
917 }
918 add_edge(&prob_nn_subProblem.oneTree, &problem->graph.edges_matrix[current_node][best_neighbour]);
919 cycleEdge.src = current_node;
920 cycleEdge.dest = best_neighbour;
921 prob_nn_subProblem.cycleEdges[prob_nn_subProblem.num_edges_in_cycle] = cycleEdge;
922 prob_nn_subProblem.num_edges_in_cycle++;
923 prob_visited[current_node] = true;
924 current_node = best_neighbour;
925 }
926 }
927 prob_nn_subProblem.value = prob_nn_subProblem.oneTree.cost;
928 prob_nn_subProblem.oneTree.isValid = true;
929 prob_nn_subProblem.type = CLOSED_NN_HYBRID;
930 prob_nn_subProblem.prob = prob_nn_subProblem.oneTree.prob;
931
932 bool better_prob = prob_nn_subProblem.value < nn_subProblem.value;
933 SubProblem *best = better_prob ? &prob_nn_subProblem : &nn_subProblem;
934
935 if (best->value < problem->bestValue) {
936 problem->bestValue = best->value;
937 problem->bestSolution = *best;
938 }
939
940 } else {
941 if (nn_subProblem.value < problem->bestValue) {
942 problem->bestValue = nn_subProblem.value;
943 problem->bestSolution = nn_subProblem;
944 }
945 }
946
947}
948
949
950// "a" is better than "b" if its LB is higher
952 if (HYBRID) {
953 return (a->value - b->value) > EPSILON ||
954 ((a->value > b->value) && (a->prob - b->prob) >= BETTER_PROB);
955 } else {
956 return (a->value - b->value) >= EPSILON;
957 }
958}
959
960
961unsigned short find_candidate_node(void) {
962
963 unsigned short best_candidate = 0;
964 SubProblem best_subProblem;
965 best_subProblem.value = 0;
966 best_subProblem.prob = 0;
967
968 for (unsigned short i = 0; i < problem->graph.num_nodes; i++) {
969 SubProblem currentCandidate;
971 currentCandidate.num_forbidden_edges = 0;
972 currentCandidate.num_mandatory_edges = 0;
973
975
976 if(PRIM){
977 constrained_prim(&problem->graph, &currentCandidate, i);
978 }
979 else{
980 constrained_kruskal(&problem->graph, &currentCandidate, i);
981 }
982 mst_to_one_tree(&currentCandidate, &problem->graph);
983 currentCandidate.value = currentCandidate.oneTree.cost;
984 currentCandidate.prob = currentCandidate.oneTree.prob;
985
986 if (compare_candidate_node(&currentCandidate, &best_subProblem)) {
987 best_candidate = i;
988 best_subProblem.value = currentCandidate.value;
989 best_subProblem.prob = currentCandidate.prob;
990 }
991
992 }
993 return best_candidate;
994}
995
996
998
999 bool feasible = true;
1000 for (short i = 0; feasible && i < graph->num_nodes; i++) {
1001 Node current_node = graph->nodes[i];
1002 if (current_node.num_neighbours < 2) {
1003 feasible = false;
1004 printf("\nThe graph is not feasible for the BB algorithm. Node %i has less than 2 neighbors.",
1005 current_node.positionInGraph);
1006 }
1007 }
1008 return feasible;
1009}
1010
1011
1012void branch_and_bound(Problem *current_problem) {
1013
1014 problem = current_problem;
1015
1017
1018 problem->start = clock();
1021 problem->bestSolution.id = 0;
1027 problem->interrupted = false;
1031
1032 SubProblem subProblem;
1033 subProblem.treeLevel = 1;
1034 subProblem.id = problem->generatedBBNodes;
1035 subProblem.fatherId = 0;
1036 subProblem.type = OPEN;
1037 subProblem.prob = 0;
1038 subProblem.value = INFINITE;
1039 subProblem.num_edges_in_cycle = 0;
1040 subProblem.edge_to_branch = -1;
1041 initialize_matrix(&subProblem);
1042
1043
1044 SubProblemsList subProblems;
1045 new_SubProblemList(&subProblems);
1046 add_elem_SubProblemList_bottom(&subProblems, &subProblem);
1047
1048 while (subProblems.size != 0 && !time_limit_reached()) {
1049 SubProblem current_sub_problem = *get_SubProblemList_elem_index(&subProblems, 0);
1050 delete_SubProblemList_elem_index(&subProblems, 0);
1051 bound(&current_sub_problem);
1052 if (current_sub_problem.type == OPEN && current_sub_problem.edge_to_branch != -1) {
1053 problem->num_fixed_edges += variable_fixing(&current_sub_problem);
1054 branch(&subProblems, &current_sub_problem);
1055 }
1056 }
1057
1058 if (time_limit_reached()) {
1059 problem->interrupted = true;
1060 }
1061
1062 problem->end = clock();
1063 delete_SubProblemList(&subProblems);
1064 }
1065}
1066
1067
1068void set_problem(Problem *current_problem) {
1069 problem = current_problem;
1070}
1071
1072
1073void print_subProblem(const SubProblem *subProblem) {
1074
1075 char *type;
1076 if (subProblem->type == OPEN) {
1077 type = "OPEN";
1078 } else if (subProblem->type == CLOSED_UNFEASIBLE) {
1079 type = "CLOSED_UNFEASIBLE";
1080 } else if (subProblem->type == CLOSED_BOUND) {
1081 type = "CLOSED_BOUND";
1082 } else if (subProblem->type == CLOSED_NN) {
1083 type = "CLOSED_NEAREST_NEIGHBOR";
1084 } else if (subProblem->type == CLOSED_NN_HYBRID) {
1085 type = "CLOSED_NEAREST_NEIGHBOR_HYBRID";
1086 } else {
1087 type = "CLOSED_SUBGRADIENT";
1088 }
1089 printf("\nSUBPROBLEM with cost = %lf, type = %s, level of the BB tree = %i, prob_tour = %lf, BBNode number = %u and time to obtain = %lfs, edge to branch = %i\n",
1090 subProblem->value, type, subProblem->treeLevel, subProblem->prob, subProblem->id,
1091 subProblem->timeToReach, subProblem->edge_to_branch);
1092
1093 //print_mst_original_weight(&subProblem->oneTree, &problem->graph);
1094
1095 printf("\nCycle with %i edges:", subProblem->num_edges_in_cycle);
1096 unsigned short last_dest = 0;
1097 for (unsigned short i = 0; i < subProblem->num_edges_in_cycle; i++) {
1098 ConstrainedEdge edge_cycle = subProblem->cycleEdges[i];
1099 unsigned short src = edge_cycle.src;
1100 unsigned short dest = edge_cycle.dest;
1101
1102 if (i == 0){
1103 if (src == subProblem->cycleEdges[subProblem->num_edges_in_cycle - 1].dest ||
1104 src == subProblem->cycleEdges[subProblem->num_edges_in_cycle - 1].src){
1105 printf(" %i <-> %i,", src, dest);
1106 last_dest = dest;
1107 }
1108 else{
1109 printf(" %i <-> %i,", dest, src);
1110 last_dest = src;
1111 }
1112 } else{
1113 if(src == last_dest){
1114 if (i == subProblem->num_edges_in_cycle - 1) {
1115 printf(" %i <-> %i", src, dest);
1116 } else {
1117 printf(" %i <-> %i,", src, dest);
1118 }
1119
1120 last_dest = dest;
1121 }
1122 else{
1123 if (i == subProblem->num_edges_in_cycle - 1) {
1124 printf(" %i <-> %i", dest, src);
1125 } else {
1126 printf(" %i <-> %i,", dest, src);
1127 }
1128 last_dest = src;
1129 }
1130 }
1131 }
1132
1133 printf("\n%i Mandatory edges:", subProblem->num_mandatory_edges);
1134 printf("\n%i Forbidden edges:", subProblem->num_forbidden_edges);
1135 printf("\n");
1136}
1137
1138void print_problem(void) {
1139 printf("Optimal tour found with candidate node = %i, elapsed time = %lfs and interrupted = %s\n",
1140 problem->candidateNodeId, ((double) (problem->end - problem->start)) / CLOCKS_PER_SEC,
1141 problem->interrupted ? "TRUE" : "FALSE");
1142
1143 printf("\nMST solved with: %s algorithm\n", PRIM ? "Prim" : "Kruskal");
1144
1145 printf("\nGHOSH_UB = %lf, SUBPROBLEM_UB = %lf\n", GHOSH_UB, EPSILON);
1146
1147 printf("\nB-&-B tree with generated BBNodes = %u, explored BBNodes = %u and max tree level = %u\n",
1149
1150 printf("\nNumber of fixed edges = %i\n", problem->num_fixed_edges);
1151
1153}
void add_elem_SubProblemList_index(SubProblemsList *list, SubProblem *element, size_t index)
Add a SubProblem at a specific index of a SubProblem List.
Definition: b_and_b_data.c:75
SubProblem * get_SubProblemList_elem_index(SubProblemsList *list, size_t index)
Get a SubProblem from a specific index of a SubProblem List.
Definition: b_and_b_data.c:146
void delete_SubProblemList_iterator(SubProblemsListIterator *iterator)
Delete a SubProblem List iterator.
Definition: b_and_b_data.c:198
void delete_SubProblemList_elem_index(SubProblemsList *list, size_t index)
Remove a SubProblem from a specific index of a SubProblem List.
Definition: b_and_b_data.c:113
void add_elem_SubProblemList_bottom(SubProblemsList *list, SubProblem *element)
Add a SubProblem to the bottom of a SubProblem List.
Definition: b_and_b_data.c:59
SubProblemsListIterator * create_SubProblemList_iterator(SubProblemsList *list)
Create a new SubProblem List iterator on a SubProblem List.
Definition: b_and_b_data.c:159
void new_SubProblemList(SubProblemsList *list)
Create a new SubProblem List.
Definition: b_and_b_data.c:17
void delete_SubProblemList(SubProblemsList *list)
Delete a SubProblem List.
Definition: b_and_b_data.c:23
SubProblem * SubProblemList_iterator_get_next(SubProblemsListIterator *iterator)
Get the next element of a SubProblem List iterator.
Definition: b_and_b_data.c:188
@ FORBIDDEN
The Edge is forbidden.
Definition: b_and_b_data.h:37
@ MANDATORY
The Edge is mandatory.
Definition: b_and_b_data.h:36
@ NOTHING
The Edge has no constraints.
Definition: b_and_b_data.h:35
BBNodeType
The labels used to identify the type of a SubProblem.
Definition: b_and_b_data.h:22
@ OPEN
The SubProblem is a feasible 1Tree, with a value lower than the best solution found so far.
Definition: b_and_b_data.h:23
@ CLOSED_NN
The SubProblem is a feasible 1Tree founded with the Nearest Neighbor algorithm, it is the first feasi...
Definition: b_and_b_data.h:24
@ CLOSED_1TREE
The SubProblem is closed by calculating the 1Tree.
Definition: b_and_b_data.h:28
@ CLOSED_NN_HYBRID
The SubProblem is a feasible 1Tree founded with the Hybrid version of Nearest Neighbor algorithm,...
Definition: b_and_b_data.h:25
@ CLOSED_BOUND
The SubProblem is a feasible 1Tree, with a value greater than the best solution found so far.
Definition: b_and_b_data.h:26
@ CLOSED_UNFEASIBLE
The SubProblem is not a feasible 1Tree, and so discarded.
Definition: b_and_b_data.h:27
@ CLOSED_SUBGRADIENT
The SubProblem is closed in the subgradient algorithm, the ascending dual.
Definition: b_and_b_data.h:29
void initialize_matrix(SubProblem *subProblem)
BBNodeType mst_to_one_tree(SubProblem *currentSubproblem, Graph *graph)
Transforms a MST into a 1Tree.
bool compare_subproblems(const SubProblem *a, const SubProblem *b)
Compare two OPEN SubProblems.
bool check_feasibility(Graph *graph)
Check if the Graph associated to the Problem is feasible.
void branch_and_bound(Problem *current_problem)
The Branch and Bound algorithm.
void constrained_kruskal(Graph *graph, SubProblem *subProblem, unsigned short candidateId)
void constrained_prim(Graph *graph, SubProblem *subProblem, unsigned short candidateId)
void nearest_prob_neighbour(unsigned short start_node)
This function is used to find the first feasible tour.
void dfs(SubProblem *subProblem)
A Depth First Search algorithm on a Graph.
bool compare_candidate_node(SubProblem *a, SubProblem *b)
void copy_constraints(SubProblem *subProblem, const SubProblem *otherSubProblem)
Copy the matrix of constraints of a SubProblem into another.
void print_subProblem(const SubProblem *subProblem)
Get all metrics of a certain SubProblem.
unsigned short find_candidate_node(void)
Select the candidate Node, i.e. the starting vertex of the tour.
bool check_hamiltonian(SubProblem *subProblem)
Function that checks if the 1Tree of a SubProblem is a tour.
bool infer_constraints(SubProblem *subProblem)
Infer the values of some edge variables of a SubProblem.
void set_problem(Problem *current_problem)
Define the problem to solve.
void bound(SubProblem *currentSubProb)
The Held-Karp bound function with the subgradient algorithm.
bool time_limit_reached(void)
Check if the time limit has been reached.
double max_edge_path_1Tree(SubProblem *currentSubProb, double *replacement_costs, unsigned short start_node, unsigned short end_node)
int variable_fixing(SubProblem *currentSubProb)
The function used to fix the edge variables to be mandatory or forbidden.
void branch(SubProblemsList *openSubProblems, SubProblem *currentSubProblem)
The Shutler's branching rule.
void print_problem(void)
Get all metrics of the problem.
The declaration of all the methods used by the Branch and Bound algorithm.
static Problem * problem
The pointer to the problem to solve.
void create_insert_node(FibonacciHeap *heap, OrdTreeNode *node, unsigned short key, double value)
A wrapper function to create a Node and insert it in the Fibonacci Heap.
int extract_min(FibonacciHeap *heap)
Extract the minimum Node from the Fibonacci Heap.
void create_fibonacci_heap(FibonacciHeap *heap)
Create an empty Fibonacci Heap.
void decrease_value(FibonacciHeap *heap, OrdTreeNode *node, double new_value)
Decrease the value of a Node in the Fibonacci Heap.
void wrap_quick_sort(Graph *graph)
The wrapper of the quick sort algorithm.
Definition: kruskal.c:123
void delete_list_elem_index(List *list, size_t index)
Deletes the DllElem at the indicated index of the List.
void add_elem_list_bottom(List *list, void *element)
Adds an DllElem to the bottom of the List.
void add_elem_list_index(List *list, void *element, size_t index)
Adds an DllElem at the index indicated of the List.
void del_list(List *list)
Delete an instance of a List.
List * new_list(void)
Create a new instance of a List.
void * get_list_elem_index(List *list, size_t index)
Retrieves a pointer to an DllElem from the List.
void merge(Set *set1, Set *set2)
Merge two Sets in the Forest if they are not already in the same Set.
Definition: mfset.c:53
Set * find(Set *set)
Find the root of a Set.
Definition: mfset.c:44
void create_forest_constrained(Forest *forest, const Node *nodes, unsigned short num_nodes, unsigned short candidateId)
Create a new Forest with n Sets, each Set containing a Node, with constraints.
Definition: mfset.c:17
void add_edge(MST *tree, const Edge *edge)
Add an Edge to the MST.
Definition: mst.c:38
void create_mst(MST *mst, const Node *nodes, unsigned short num_nodes)
Create a Minimum Spanning Tree from a set of Nodes.
Definition: mst.c:17
#define EPSILON
The first constant used to compare two SubProblem in the branch and bound algorithm.
#define NUM_HK_ITERATIONS
The maximum number of dual iterations for nodes of the branch and bound tree that are not the root.
#define GHOSH_UB
The first upper bound for the problem, see: https://www.semanticscholar.org/paper/Expected-Travel-Amo...
#define PRIM
The maximum number of Node in the Graph.
#define PROB_BRANCH
The way with generate the children of a SubProblem.
#define MAX_EDGES_NUM
The maximum number of edges in the Graph.
#define INFINITE
The maximum number to set the initial value of Problem and SubProblem.
#define BETTER_PROB
The third constant used to compare two SubProblem in the branch and bound algorithm.
#define TIME_LIMIT_SECONDS
The maximum time to run the algorithm. Default: 10 minutes.
#define NUM_HK_INITIAL_ITERATIONS
The maximum number of dual iterations for the root of the branch and bound tree.
A reduced form of an Edge in the Graph, with only the source and destination Nodes.
Definition: mst.h:21
unsigned short src
The source Node of the Edge.
Definition: mst.h:22
unsigned short dest
The destination Node of the Edge.
Definition: mst.h:23
Structure of an Edge.
Definition: graph.h:40
unsigned short dest
ID of the destination vertex.
Definition: graph.h:42
unsigned short src
ID of the source vertex.
Definition: graph.h:41
double prob
Probability of the Edge to be in an optimal tour.
Definition: graph.h:45
double weight
Weight of the Edge, 1 if the data_structures is not weighted.
Definition: graph.h:44
unsigned short positionInGraph
Position of the Edge in the list of Edges of the Graph.
Definition: graph.h:46
The Fibonacci Heap datastructure as collection of Heap-ordered Trees.
unsigned short num_nodes
The number of Nodes in the Heap.
A Forest is a list of Sets.
Definition: mfset.h:28
Set sets[MAX_VERTEX_NUM]
Array of Sets.
Definition: mfset.h:30
Structure of a Graph.
Definition: graph.h:51
Edge edges_matrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM]
Adjacency matrix of the Graph.
Definition: graph.h:59
unsigned short num_edges
Number of Edges in the Graph.
Definition: graph.h:55
bool orderedEdges
True if the Edges are ordered by weight, false otherwise.
Definition: graph.h:56
Edge edges[MAX_EDGES_NUM]
Array of Edges.
Definition: graph.h:58
Node nodes[MAX_VERTEX_NUM]
Array of Nodes.
Definition: graph.h:57
unsigned short num_nodes
Number of Nodes in the Graph.
Definition: graph.h:54
The double linked list.
Definition: linked_list.h:35
size_t size
The current size of the List.
Definition: linked_list.h:38
unsigned short num_nodes
The number of Nodes in the MST.
Definition: mst.h:32
short edges_matrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM]
-1 if there is no Edge between the two Nodes, otherwise the index of the Edge in the MST.
Definition: mst.h:36
double prob
The probability of the MST, i.e. the average of the probabilities of its Edges.
Definition: mst.h:31
Edge edges[MAX_VERTEX_NUM]
The set of Edges in the MST, these are |V| because the MST can be a 1-Tree.
Definition: mst.h:35
Node nodes[MAX_VERTEX_NUM]
The set of Nodes in the MST.
Definition: mst.h:34
unsigned short num_edges
The number of Edges in the MST.
Definition: mst.h:33
bool isValid
True if the MST has the correct number of Edges, false otherwise.
Definition: mst.h:29
double cost
The total cost of the MST, i.e. the sum of the weights of the Edges.
Definition: mst.h:30
Structure of a Node.
Definition: graph.h:30
unsigned short num_neighbours
Number of neighbours of the Node.
Definition: graph.h:34
unsigned short positionInGraph
Position of the Node in the list of Nodes of the Graph, i.e. its unique ID.
Definition: graph.h:33
unsigned short neighbours[MAX_VERTEX_NUM - 1]
Array of IDs of the Node's neighbors.
Definition: graph.h:35
A Heap-ordered Tree Node where the key of the parent is <= the key of its children.
The struct used to represent the overall problem.
Definition: b_and_b_data.h:62
Graph reformulationGraph
The Graph used to perform the dual reformulation of Edge weights.
Definition: b_and_b_data.h:64
bool interrupted
True if the algorithm has been interrupted by timeout.
Definition: b_and_b_data.h:72
SubProblem bestSolution
The best solution found so far.
Definition: b_and_b_data.h:67
clock_t end
The time when the algorithm ended.
Definition: b_and_b_data.h:74
clock_t start
The time when the algorithm started.
Definition: b_and_b_data.h:73
Graph graph
The Graph of the problem.
Definition: b_and_b_data.h:63
unsigned short candidateNodeId
The id of the candidate node.
Definition: b_and_b_data.h:65
unsigned int num_fixed_edges
The number of fixed edges in the Branch and Bound tree.
Definition: b_and_b_data.h:71
unsigned int generatedBBNodes
The number of nodes generated in the Branch and Bound tree.
Definition: b_and_b_data.h:69
unsigned short totTreeLevels
The total number of levels in the Branch and Bound tree.
Definition: b_and_b_data.h:66
double bestValue
The cost of the best solution found so far.
Definition: b_and_b_data.h:68
unsigned int exploredBBNodes
The number of nodes explored in the Branch and Bound tree.
Definition: b_and_b_data.h:70
A Set is a node in the Forest.
Definition: mfset.h:19
unsigned short num_in_forest
Number of the position of the Set in the Forest.
Definition: mfset.h:23
The struct used to represent a SubProblem or node of the Branch and Bound tree.
Definition: b_and_b_data.h:42
ConstraintType constraints[MAX_VERTEX_NUM][MAX_VERTEX_NUM]
The constraints of the edges in the SubProblem.
Definition: b_and_b_data.h:57
ConstrainedEdge mandatoryEdges[MAX_VERTEX_NUM]
The mandatory edges in the SubProblem.
Definition: b_and_b_data.h:56
float timeToReach
The time needed to reach the SubProblem, in seconds.
Definition: b_and_b_data.h:48
ConstrainedEdge cycleEdges[MAX_VERTEX_NUM]
The edges in the cycle of the SubProblem.
Definition: b_and_b_data.h:52
unsigned short num_forbidden_edges
The number of forbidden edges in the SubProblem.
Definition: b_and_b_data.h:53
double prob
The probability of the SubProblem to be the best tour.
Definition: b_and_b_data.h:51
unsigned int id
The id of the SubProblem, an incremental number.
Definition: b_and_b_data.h:44
double value
The cost of the SubProblem.
Definition: b_and_b_data.h:46
unsigned int fatherId
The id of the father of the SubProblem.
Definition: b_and_b_data.h:45
int edge_to_branch
The id of the edge to branch in the SubProblem.
Definition: b_and_b_data.h:55
BBNodeType type
The label of the SubProblem.
Definition: b_and_b_data.h:43
MST oneTree
The 1Tree of the SubProblem.
Definition: b_and_b_data.h:49
unsigned short treeLevel
The level of the SubProblem in the Branch and Bound tree.
Definition: b_and_b_data.h:47
unsigned short num_mandatory_edges
The number of mandatory edges in the SubProblem.
Definition: b_and_b_data.h:54
unsigned short num_edges_in_cycle
The number of edges in the cycle of the SubProblem.
Definition: b_and_b_data.h:50
The iterator of the list of SubProblems.
Definition: b_and_b_data.h:95
The list of open SubProblems.
Definition: b_and_b_data.h:87
size_t size
The size of the list.
Definition: b_and_b_data.h:90