diff --git a/pace-2020/CMakeLists.txt b/pace-2020/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..39aa0857cd025e125b6ca28580e012214ae4c9aa --- /dev/null +++ b/pace-2020/CMakeLists.txt @@ -0,0 +1,28 @@ +cmake_minimum_required(VERSION 3.5) +project(sga C) + +set(CMAKE_C_STANDARD 11) + +include_directories(.) + +add_definitions(-DPACE_2020) + +add_executable(sga + graph.c + graph.h + lire.c + lire.h + lists.c + lists.h + main.c + heap.c + heap.h + tree.c tree.h + decompose.c decompose.h + separator.c separator.h + utils.c utils.h + sets.c sets.h compression.c compression.h main.h components.c components.h swaps.c swaps.h) + +target_link_libraries(sga m) + + diff --git a/pace-2020/Makefile b/pace-2020/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ab13e10aa847014335b1e73b6bf774234164602c --- /dev/null +++ b/pace-2020/Makefile @@ -0,0 +1,69 @@ + +DEBUG=no + +ifeq ($(DEBUG),yes) + CFLAGS= -I sga -g -Wall -pedantic -std=c99 +else + CFLAGS= -I sga -std=c99 -O3 +endif + + +ifeq ($(PACE),yes) + PACE_FLAG= -DPACE_2020 +endif + + +all: treedepth + + +treedepth: obj/main.o obj/lists.o obj/lire.o obj/graph.o obj/fibheap.o obj/tree.o obj/separator.o obj/decompose.o obj/heap.o obj/sets.o obj/utils.o obj/compression.o obj/components.o obj/swaps.o + gcc $(CFLAGS) obj/main.o obj/lists.o obj/lire.o obj/graph.o obj/fibheap.o obj/tree.o obj/separator.o obj/decompose.o obj/heap.o obj/sets.o obj/utils.o obj/compression.o obj/components.o obj/swaps.o -o treedepth + +obj/swaps.o: sga/swaps.c sga/swaps.h sga/graph.h sga/utils.h sga/sets.h sga/lists.h sga/tree.h sga/decompose.h sga/main.h + gcc $(CFLAGS) -c sga/swaps.c -o obj/swaps.o + + +obj/components.o: sga/components.c sga/components.h sga/graph.h sga/utils.h sga/sets.h sga/lists.h sga/heap.h + gcc $(CFLAGS) -c sga/components.c -o obj/components.o + +obj/compression.o: sga/compression.c sga/compression.h sga/graph.h sga/utils.h sga/tree.h sga/sets.h + gcc $(CFLAGS) -c sga/compression.c -o obj/compression.o + +obj/utils.o: sga/utils.c sga/utils.h + gcc $(CFLAGS) -c sga/utils.c -o obj/utils.o + +obj/sets.o: sga/sets.c sga/sets.h + gcc $(CFLAGS) -c sga/sets.c -o obj/sets.o + +obj/decompose.o: sga/decompose.c sga/decompose.h sga/separator.h sga/graph.h sga/utils.h sga/tree.h sga/compression.h sga/separator.h sga/heap.h sga/main.h sga/components.h sga/swaps.h + gcc $(CFLAGS) $(PACE_FLAG) -c sga/decompose.c -o obj/decompose.o + +obj/separator.o: sga/separator.c sga/separator.h sga/graph.h sga/utils.h sga/components.h sga/main.h sga/heap.h + gcc $(CFLAGS) -c sga/separator.c -o obj/separator.o + +obj/tree.o: sga/tree.c sga/tree.h sga/graph.h sga/utils.h sga/sets.h sga/decompose.h + gcc $(CFLAGS) -c sga/tree.c -o obj/tree.o + +obj/main.o: sga/main.c sga/lists.h sga/lire.h sga/graph.h sga/main.h + gcc $(CFLAGS) $(PACE_FLAG) -c sga/main.c -o obj/main.o + +obj/graph.o: sga/graph.c sga/graph.h sga/lists.h + gcc $(CFLAGS) -c sga/graph.c -o obj/graph.o + +obj/lists.o: sga/lists.c sga/lists.h + gcc $(CFLAGS) -c sga/lists.c -o obj/lists.o + +obj/lire.o: sga/lire.c sga/lire.h sga/lists.h sga/graph.h sga/main.h + gcc $(CFLAGS) -c sga/lire.c -o obj/lire.o + +obj/fibheap.o: sga/fibheap.c sga/fibheap.h + gcc $(CFLAGS) -c sga/fibheap.c -o obj/fibheap.o + +obj/heap.o: sga/heap.c sga/heap.h + gcc $(CFLAGS) -c sga/heap.c -o obj/heap.o + +clean: + rm -f treedepth \ + rm -f obj/*.o + + diff --git a/pace-2020/components.c b/pace-2020/components.c new file mode 100644 index 0000000000000000000000000000000000000000..9e549ba36b9a2d8698952f508815929e8c49b0ff --- /dev/null +++ b/pace-2020/components.c @@ -0,0 +1,282 @@ +// +// Created by Stephane on 24/03/2020. +// + +#include <assert.h> + +#include "components.h" +#include "graph.h" +#include "heap.h" +#include "lists.h" +#include "sets.h" +#include "utils.h" + + +int *iComp = NULL; // for each vertex, the number of its component +int *compSizes; +int *compNbEdges; +int *compFirsts; +int * tableSortVComp; + +//int *firstOfComp; // the first vertex of the component, useful when the component size is 1 +int sizeCompMax; + +int *queue = NULL, *first, *last; + + +void allocSearchConnectedComponents(Graph g) { + iComp = malloc(g->n*sizeof(int)); + compSizes = malloc(g->n*sizeof(int)); + compNbEdges = malloc(g->n*sizeof(int)); + compFirsts = malloc(g->n*sizeof(int)); + tableSortVComp = malloc(g->n*sizeof(int)); + //firstOfComp = malloc(g->n*sizeof(int)); + queue = malloc(g->n*sizeof(int)); +} + + + + +// Search connected components of the subgraph delimited by V +// verif is just used to verify for each vertex that it is in the current set (useless for greedy search) +int searchConnectedComponents(SET V, int S[], int n, Graph g) { + + int nbComp = 0; + int nbNodes = 0; + sizeCompMax = 0; + + for (int i = 0; i < n; i++) + iComp[S[i]] = NONE; + + // Call BFS exploration from each node of S[] + for (int i = 0; i < n; i++) { + if (iComp[S[i]] == NONE) { + iComp[S[i]] = nbComp; + compSizes[nbComp] = 1; + //firstOfComp[nbComp] = S[i]; + first = last = queue; + *last++ = S[i]; + compExploreBFS(nbComp, V, S, n, g, 1); + if (compSizes[nbComp] > sizeCompMax) sizeCompMax = compSizes[nbComp]; + nbNodes += compSizes[nbComp]; + nbComp++; + if (nbNodes == n) break; + } + } + return nbComp; +} + + + +void compExploreBFS(int num, SET V, int S[], int n, Graph g, int verif) { + while (last != first) { + int *p = g->lists[*first]; + first = first+1; + if (first == queue+g->n) first = queue; + while (*p != NONE) { + if ( ! verif || (isInSet(*p, V, S, n))) { // isInSet is OK since S[] is sorted + if (iComp[*p] == NONE) { + iComp[*p] = num; + compSizes[num]++; + *last++ = *p; + if (last == queue + g->n) last = queue; + } + } + p ++; + } + } +} + + + +// Special version for separators: the neighbors of each vertex are ordered so as that those in S +// occur first. Search components for the subgraph corresponding to the heap (H->ind[] is NONE if not in the heap) +void compExploreBFSSubgraph(int num, Heap H, int nbN[], Graph g); + +int searchConnectedComponentsInHeap(Heap H, int nbNiS[], Graph g) { + + int nbComp = 0; + int nbNodes = 0; + sizeCompMax = 0; + + for (int i = 0; i < H->n; i++) + iComp[H->val[i]] = NONE; + + for (int i = 0; i < H->n; i++) { + + if (iComp[H->val[i]] == NONE) { + + iComp[H->val[i]] = nbComp; + compSizes[nbComp] = 1; + compNbEdges[nbComp] = 0; + first = last = queue; + *last++ = H->val[i]; + + compExploreBFSSubgraph(nbComp, H, nbNiS, g); + + compNbEdges[nbComp] = compNbEdges[nbComp]/2; + if (compSizes[nbComp] > sizeCompMax) sizeCompMax = compSizes[nbComp]; + nbNodes += compSizes[nbComp]; + nbComp ++; + if (nbNodes == H->n) break; + } + } + return nbComp; +} + +void compExploreBFSSubgraph(int num, Heap H, int nbN[], Graph g) { + + while (last != first) { + int *p = g->lists[*first]; + int *pp = p+nbN[*first]; + + first = first+1; + if (first == queue+g->n) first = queue; + + while (p != pp) { + if (H->ind[*p] != NONE) { + compNbEdges[num] ++; + if (iComp[*p] == NONE) { + iComp[*p] = num; + compSizes[num] ++; + *last++ = *p; + if (last == queue + g->n) last = queue; + } + } + p++; + } + } +} + + + + + + +// Special version for greedy decomposition: the exploration can be stopped +// once we know that the neighbors of the last removed vertex are all reachable + +#define UNVISITED_NEIGHBOR -2 +#define IGNORED_NODE -3 +int nbNeighborsToVisit; + +void compExploreBFSAF(int u, int num, SET V, Heap heap, Graph g) { + while (last != first) { + int *p = g->lists[*first]; + first = first+1; + if (first == queue+g->n) first = queue; + while (*p != NONE) { + if (heap->ind[*p] != NONE) { // (isInSet(*p, V, S, n)) should be false here (S[] not ordered) + if ((iComp[*p] == NONE) || (iComp[*p] == UNVISITED_NEIGHBOR)) { + if (iComp[*p] == UNVISITED_NEIGHBOR) { + if ((-- nbNeighborsToVisit == 0) && (num == 0)) // first component, all neighbors have been discovered + return; + } + iComp[*p] = num; + compSizes[num]++; + *last++ = *p; + if (last == queue + g->n) last = queue; + } + } + p ++; + } + } +} + + +int searchConnectedComponentsGreedy(SET V, Heap heap, Graph g, int removedVertex) { + int nbComp = 0; + int nbNodes = 0; + sizeCompMax = 0; + nbNeighborsToVisit = 0; + + for (int i = 0; i < heap->n; i++) + iComp[heap->val[i]] = NONE; + + // Mark neighbors which are in the heap + for (int *p = g->lists[removedVertex]; *p != NONE; p ++) { + if (conHeap->ind[*p] != NONE) { // (isInSet(*p, V, S, n)) not good (suppose vertices are ordered in S[] + iComp[*p] = UNVISITED_NEIGHBOR; + nbNeighborsToVisit++; + } + else iComp[*p] = IGNORED_NODE; + } + + // NORMAL !! if (nbNeighborsToVisit != nbN4Con[removedVertex]) {printf("%d %d\n", nbNeighborsToVisit, nbN4Con[removedVertex]); exit(0);} + + for (int *p = g->lists[removedVertex]; *p != NONE; p ++) { + if (iComp[*p] == UNVISITED_NEIGHBOR) { + iComp[*p] = nbComp; + compSizes[nbComp] = 1; + nbNeighborsToVisit --; + if ((nbNeighborsToVisit == 0) && (nbComp == 0)) return 1; // a unique neighbor + + first = last = queue; + *last++ = *p; + compExploreBFSAF(*p, nbComp, V, heap, g); + + if ((nbNeighborsToVisit == 0) && (nbComp == 0)) return 1; + if (compSizes[nbComp] > sizeCompMax) sizeCompMax = compSizes[nbComp]; + nbNodes += compSizes[nbComp]; + nbComp++; + if (nbNodes == heap->n) break; + } + } + return nbComp; +} + + + + +int nbCCE = 0; + +void compExplore(int u, int num, SET V, int S[], int n, Graph g, int depth) { + LIST q = g->adj[u]; + int nbNeighbors = 0; + nbCCE ++; + + //if (nbCCE >= 2011872) printf("depth=%d n=%d u=%d size=%d\n", depth, n, u, compSizes[num]); + + while (q != NULL) { + nbNeighbors ++; + if (nbNeighbors > g->nadj[u]) {printf("too many neighbors !\n"); exit(0);} + if ((isInSet(q->val, V, S, n)) && (iComp[q->val] == NONE)) { //((IN(q->val, V)) && (iComp[q->val] == NONE)) { + iComp[q->val] = num; + compSizes[num] ++; + compExplore(q->val, num, V, S, n, g, depth+1); + } + q = q->suiv; + } +} + + + +// +// utils +// + + +// the vertices in S[] are ordered by their component number. sizes[] are initialized. +// Uses iComp[] and compSizes[] returned by searchConnectedComponentsGreedy() or +// searchConnectedComponents() +void sortListByComponent(int S[], int n, int nbComp, int sizes[]) { + + for (int i = 0; i < n; i ++) { + tableSortVComp[i] = S[i]; + } + compFirsts[0] = 0; + sizes[0] = compSizes[0]; + for (int i = 1; i < nbComp; i ++) { + sizes[i] = compSizes[i]; + compFirsts[i] = compFirsts[i - 1] + compSizes[i - 1]; + } + + for (int *p = tableSortVComp; p < tableSortVComp+n; p ++) { + int pos = compFirsts[iComp[*p]]; + compFirsts[iComp[*p]] ++; + S[pos] = *p; + } +} + + + diff --git a/pace-2020/components.h b/pace-2020/components.h new file mode 100644 index 0000000000000000000000000000000000000000..75c9307bebb3c14c0521432b2a9b6067338f380b --- /dev/null +++ b/pace-2020/components.h @@ -0,0 +1,30 @@ +// +// Created by Stephane on 24/03/2020. +// + +#ifndef SGA_COMPONENTS_H +#define SGA_COMPONENTS_H + +#include "graph.h" +#include "heap.h" +#include "sets.h" + + +extern int * iComp; +extern int *compSizes; +extern int *compNbEdges; +extern int * tableSortVComp; + +extern int sizeCompMax; +//extern int *firstOfComp; + + +void allocSearchConnectedComponents(Graph g); +int searchConnectedComponents(SET V, int S[], int n, Graph g); +int searchConnectedComponentsGreedy(SET V, Heap heap, Graph g, int removedVertex); +void compExplore(int u, int num, SET V, int S[], int n, Graph g, int depth); +void compExploreBFS(int num, SET V, int S[], int n, Graph g, int verif); +int searchConnectedComponentsInHeap(Heap H, int nbNiS[], Graph g); +void sortListByComponent(int S[], int n, int nbComp, int sizes[]); + +#endif //SGA_COMPONENTS_H diff --git a/pace-2020/compression.c b/pace-2020/compression.c new file mode 100644 index 0000000000000000000000000000000000000000..7e27280157d098d541d6edba9edcd7e3797d5faa --- /dev/null +++ b/pace-2020/compression.c @@ -0,0 +1,159 @@ +// +// Created by Stephane on 14/03/2020. +// + + + + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include "compression.h" +#include "graph.h" +#include "tree.h" +#include "sets.h" +#include "utils.h" + + + +// Pull up subtrees that are independent with the node + + + +// Pull up node children which are independent with the vertex of node +int pullUpChildren(Node node, Graph g, int depth) { + Node p, next; + int v = node->vertex; + int nbPU = 0; + int trace = 1; + + int prevFHeight = node->father->height; + + + p = node->fbs; + while (p != NULL) { + next = p->next; + if (independent(v, p, g)) { + if (pullUp(p)) { nbPU ++; if (trace) printf("pull up %d:%d->%d\n", p->vertex, depth, depth-1); } + } + p = next; + } + + // the father of node has been updated + + if (nbPU > 0) { + if ((node->father != NULL) && (node->father->father != NULL)) + decHeightNodeUpdate(node->father->father, prevFHeight); + } + return nbPU; +} + + +// Explore and pull up nodes children when it is usefull (that is if it concerns critical nodes). +// at this level some children of node may be pulled up + +void exploreAndCompress(Node node, Graph g, int depth) { + Node p; + int height = node->height; + int prevFHeight = (node->father != NULL) ? node->father->height : 0; + int trace = 0; + int nbPU; + + if (trace) printf("[%d] DEB compress h=%d\n", depth, node->height); + + // For the height of node to decrease critical children of node must be either compressed + // or pulled up. + + //START: + p = node->fbs; + nbPU = 0; + while (p != NULL) { + if (p->height+1 == height) { // In the other case p is not involved in the height of node + exploreAndCompress(p, g, depth+1); + if (((node->father != NULL)) && independent(node->vertex, p, g)) { + if (pullUp(p)) { nbPU ++; if (trace) printf("pull up %d:%d->%d\n", p->vertex, depth, depth-1); } + } + } + p = p->next; + } + + if ( ! verifyTree(node, depth)) { printf("verify2 \n"); exit(0); } + + //if ( ! verifyTree(node->father, depth-1)) { printf("verify3 father\n"); exit(1); } + + if ((node->father != NULL) && (node->father->height != prevFHeight) && (node->father->father != NULL)) { + decHeightNodeUpdate(node->father->father, prevFHeight); + if ( ! verifyTree(node->father, depth-1)) { printf("verify4 father\n"); exit(1); } + } + + //if (nbPU > 0) goto START; + +} + + +void exploreAndCompressOLD(Node node, Graph g, int depth) { + Node p = node->fbs; + int height = node->height; + int trace = 1; + + if (trace) printf("[%d] DEB compress h=%d\n", depth, node->height); + if ( ! verifyTree(node, depth)) { printf("verify1 \n"); exit(0); } + + // For the height of node to decrease critical children of node must be either compressed + // or pulled up. + + while (p != NULL) { + if (p->height+1 == height) { // In the other case p is not involved in the height of node + exploreAndCompress(p, g, depth+1); + } + p = p->next; + } + // Here, node has perhaps new children (that were children of some children) an is up to date + + if (node->father != NULL) + pullUpChildren(node, g, depth); + + // Here perhaps node lose children. If its height has not changed so does the height of its father. + + if ((node->height < height) && (node->father != NULL)) { + if (trace) printf("update father :: node:%d->%d father:%d x %d\n", + height, node->height, node->father->height, node->father->nbhmax); + updateDecHeightOnBranch(node->father, node->height); + if (node->father->father != NULL) + forceUpdateDecHeightOnBranch(node->father->father, node->father->height); + } + if ( ! verifyTree(node, depth)) { printf("verify2 \n"); exit(0); } + if (trace) { + if (height != node->height) + printf("[%d] END compress h=%d height node %d : %d->%d\n", depth, node->height, node->vertex, height, + node->height); + else + printf("[%d] END compress h=%d\n", depth, node->height); + } + + if ( ! verifyTree(node->father, depth-1)) { + printf("verify3 father\n"); + exit(1); + } +} + + + + + + + + + + + + + + + + + + diff --git a/pace-2020/compression.h b/pace-2020/compression.h new file mode 100644 index 0000000000000000000000000000000000000000..0dfcca74e9ca46965575582a542d0571fcbb17e3 --- /dev/null +++ b/pace-2020/compression.h @@ -0,0 +1,17 @@ +// +// Created by Stephane on 14/03/2020. +// + +#ifndef SRC_COMPRESSION_H +#define SRC_COMPRESSION_H + + +#include "graph.h" +#include "tree.h" + + +int pullUpChildren(Node node, Graph g, int depth); +void exploreAndCompress(Node node, Graph g, int depth); + + +#endif //SRC_COMPRESSION_H diff --git a/pace-2020/decompose.c b/pace-2020/decompose.c new file mode 100644 index 0000000000000000000000000000000000000000..b25463ffb258f7dab82beeb27c8d0385fc79e502 --- /dev/null +++ b/pace-2020/decompose.c @@ -0,0 +1,947 @@ +// +// Created by Stephane on 10/03/2020. +// + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include "decompose.h" +#include "components.h" +#include "compression.h" +#include "swaps.h" +#include "graph.h" +#include "main.h" +#include "separator.h" +#include "tree.h" +#include "utils.h" +#include "heap.h" + +extern int trace; +extern char * last_name; + + +int *bestTree; +int bestHeight; +int bestEvalMode = NONE; + + +Separator separator; + +Node * theNodes; + +SET * theSets; +int nbAllocatedSets; + +int ** components; +int ** componentsOf; +int nbAllocatedComponents; +int topComponents; + + + +int nbCallsDecompose = 0; +int nbCallsDecomposeComponents = 0; + +extern int indpdNbCalls; + +int mustVerifyDecomposition = 0; + + + +void updateBestDecomposition(Node root, Graph g) { + if ((root != NULL) && (root->height < bestHeight)) { + bestHeight = root->height; + saveToTable(bestTree, g); + bestEvalMode = modeEvalSeparator; + } +} + + + +void allocAndInitializeDecomposition(Graph g) { + separator = newSeparator(g->n, g); + + allocSeparation(g); + allocNodes(g); + nbAllocatedSets = 100; + allocSets(g, nbAllocatedSets); + + nbAllocatedComponents = 100; + allocComponents(g, nbAllocatedComponents); + allocSearchConnectedComponents(g); + + bestTree = malloc(g->n * sizeof(int)); + bestHeight = g->n+1; +} + +void initializeRun(Graph g, int S[], int pos[]) { + topComponents = 0; + + for (int i = 0; i < g->n; i ++) { + S[i] = i; + pos[i] = i; + } +} + +void markRemoved(int S[], int n, int pos[]) { + for (int i = 0; i < n; i ++) + pos[S[i]] = NONE; +} + + +#ifdef STATS_SEPARATION +extern clock_t *timesSep; +extern int *nbSearches; +extern int *sumSizes; +#endif + + +void testDecompose(Graph g, int nbRuns, int algo) { + int *S = malloc(g->n * sizeof(int)); // list of vertices + int *posS = malloc(g->n * sizeof(int)); // booleans for separation + int *nbCriticalNodes = malloc(g->n * sizeof(int)); // to calculate the numbers of critical nodes at each level + int bestHDec = g->n+1; + Node root; + int h0, h1, h2; + int nbEffectiveRuns = 0; + int nbRunsAttempted = 0; + int trace = 0; + + if (g->n > 300000) nbRunsSeparation = 1; + + if (perForceChoiceNotInC == NONE) + perForceChoiceNotInC = (g->n > 7600) ? 10 : 0; + + clock_t startTimeRun; + clock_t startTimeImprove; + clock_t totalTimeDecompose = 0; + clock_t totalTimeImprove = 0; + + allocAndInitializeDecomposition(g); + allocConnectionsHeap(g); + + if (preliminaryGreedyDecomposition && (algo != GREEDY_ALGORITHM) && (g->n < maxSizePrelimGreedy)) { + nbEffectiveRuns ++; + initConHeap(g); + root = greedyDecompose(conHeap, 0, g, g->n+1, 1); + if (trace) printf("greedy first decomp h=%d %.1fs\n", root->height, (float) (clock()-startTime)/CLOCKS_PER_SEC); + if (root != NULL) updateBestDecomposition(root, g); + if (stopSearch) goto SAVE_AND_EXIT; + } + + for (int i = 0; i < nbRuns; i ++) { + + startTimeRun = clock(); + if ((startTimeRun-startTime)/CLOCKS_PER_SEC >= time_limit) + break; + + if (algo == SEPARE_AND_EXPLORE) { + initializePriorities(g); + initializeRun(g, S, posS); + } + + int maxDepth = bestHDec*(100+depthThreshold)/100; + if (noSwapsInFirstRuns) maxDepth = bestHDec+1; + + initConHeap(g); + + if (algo == GREEDY_ALGORITHM) { + root = greedyDecompose(conHeap, 0, g, maxDepth, 1); + if (trace) printf("greedy decomp h=%d %.1fs\n", (root == NULL) ? -1 : root->height, (float) (clock()-startTime)/CLOCKS_PER_SEC); + } + else if (algo == SEPARE_AND_EXPLORE) { + root = decompose(S, g->n, posS, 0, g, maxDepth, 0); + if (trace) printf("decompose h=%d %.1fs\n", (root == NULL) ? -1 : root->height, (float) (clock()-startTime)/CLOCKS_PER_SEC); + } + + nbRunsAttempted ++; + if (stopSearch) break; + + totalTimeDecompose += (clock()-startTimeRun); + + if (root == NULL) { + if (nbRunsSeparation < 50) nbRunsSeparation ++; + continue; + } + + nbEffectiveRuns ++; + h0 = root->height; + if (root->height < bestHDec) bestHDec = root->height; + + if (printStats) printStatsOnCriticalNodes(root, nbCriticalNodes); + + updateBestDecomposition(root, g); + + if (noSwapsInFirstRuns) { + if ((clock()-startTime) / CLOCKS_PER_SEC < timeWithNoSwaps * time_limit / 100) continue; // Shunt improve at the beginning + root = buildTreeFromTable(bestTree, g); + noSwapsInFirstRuns = 0; + nbRuns = 1000000; + } + + startTimeImprove = clock(); + if (pullUpIndependentSubtrees || searchSwapsInCriticalBranch) { + root = makeSwapsInCriticalBranch(root, g); + if (trace) printf("improve %d --> %d %.1fs\n", h0, root->height, (float) (clock()-startTime)/CLOCKS_PER_SEC); + updateBestDecomposition(root, g); // useless + } + totalTimeImprove += (clock()-startTimeImprove); + + if (stopSearch) break; + + if (mustVerifyDecomposition) if ( ( ! verifyTree(root, 0)) || ( ! verifyDecomposition(root, g)) ) exit(0); + + if (0) printf("decompose h=%d --> %d %.1fs \n", h0, root->height, (float) (clock()-startTimeRun)/CLOCKS_PER_SEC); + +#ifdef THE_OLD_IMPROVEMENT + if ( ! improve) { if (trace) printf("\n"); continue; } + if (root->height > bestHDec*(100+depthThreshold)/100) {if (trace) printf("abandon\n"); continue;} + IMPROVE_TREE: + + if (stopSearch) break; + + if (compressTree) { + exploreAndCompress(root, g, 0); + h1 = root->height; + verifyTree(root, 0); + + if (trace) printf("h1=%d %.1fs %d ", h1, (float) (clock() - startTimeRun) / CLOCKS_PER_SEC, indpdNbCalls); + if (root->height < bestHeight) { + bestHeight = root->height; + saveToTable(bestTree, g); + if (trace) printf("\nbestC=%d ", root->height); + } + + if (stopSearch) break; + } + + searchForksSwaps(root, g, root->height); + h2 = root->height; + verifyTree( root, 0); + + if (trace) printf("h2=%d %.1fs %d ", h2, (float) (clock()-startTimeRun)/CLOCKS_PER_SEC, indpdNbCalls); + if (root->height < bestHeight) { bestHeight = root->height; saveToTable(bestTree, g); if (trace) printf("\nbestFS=%d ", root->height); } + + if (h2 < h0) goto IMPROVE_TREE; + + if (trace) printf("\n"); +#endif + } + +#ifdef STATS_SEPARATION + for (int i = 0; ; i ++) { + if (nbSearches[i] == 0) break; + printf("[%d] %d x %.1fs (size=%d)\n", i, nbSearches[i], + (float) (timesSep[i] / nbSearches[i]) / CLOCKS_PER_SEC, sumSizes[i]/nbSearches[i]); + } +#endif + +SAVE_AND_EXIT: + if (printResult) printf("%s %d %d runs=%d/%d calls=%d+%d+%d h=%d %.2fs + %.2fs hdec=%d mode=%d\n", + last_name, g->n, g->m, nbEffectiveRuns, nbRunsAttempted, + nbCallsDecompose, nbCallsDecomposeComponents, nbCallsSwapNode, + bestHeight, + (float) totalTimeDecompose/CLOCKS_PER_SEC, (float) totalTimeImprove/CLOCKS_PER_SEC, + bestHDec, bestEvalMode); + if (printSolution) { + PACEOutput(fileSolution, bestHeight, bestTree, g); + } +} + + +// +// Decomposition : SEPARE_AND_EXPLORE +// + +Node decompose(int *S, int n, int pos[], int depth, Graph g, int hmax, int connected) { + + nbCallsDecompose ++; + //int nbCalls = nbCallsDecompose; + + if (trace) printf("[%d] call %d n=%d \n", depth, nbCallsDecompose, n); + + assert(depth <= g->n); + + if (stopSearch) return NULL; + if (n == 0) return NULL; + if (hmax <= 0) return NULL; + + if (n <= 3) { markRemoved(S, n, pos); return makeSmallTree(S, n, g); } + + if (0 && n <= sizeSwitchToGreedy) { + conHeap->val = S; + conHeap->n = n; + // must first rebuild conHeap + return greedyDecompose(conHeap, depth, g, hmax, 1); + } + + SET set = NULL; + if (n > 105) { + if (theSets[depth] == NULL) reAllocSets(100, g); + set = makeSet(S, n, theSets[depth]); + } + else + Introsort(S, S, S + n - 1); + + // Search connected components + if (depth > 0) { + int nbComp = searchConnectedComponents(set, S, n, g); + if (stopSearch) return NULL; + if (nbComp > 1) { + if (trace) printf("components: %d ", nbComp); + return decomposeConnectedComponents(iComp, nbComp, S, n, pos, depth, g, hmax); + } + } + + int nbEdges = initializeNbNeighbors(set, S, n, pos, g); // for searchSeparator() + + if (2*nbEdges == n*(n-1)) { + markRemoved(S, n, pos); + return makeSingleBranch(S, n, NULL, g); + } + + //searchSeparator(S, n, set, g, separator, (n < 20) ? 1 : nbRunsSeparation, (n < 20) ? 1 : nbFlushes, NULL, 0); + searchSeparator(S, n, set, g, separator, nbRunsSeparation, nbFlushes, depth); + + if (stopSearch) return NULL; + + if (0) { + improveSeparation(separator, g, 0); // Seg fault with 100 runs "./treedepth -file ../public/heur_007.gr " + printf("improve :: %d %d %d\n", separator->B->n, separator->C->n, separator->A->n); + } + + //root = makeSingleBranchWithDisconnectedVertices(separator->C->val, separator->C->n, separator->nbABDV, g); + Node root = makeSingleBranch(separator->C->val, separator->C->n, nbNInABCopy, g); + + Node theLastOfTheBranch = bottomNode; + markRemoved(separator->C->val, separator->C->n, pos); + + int nA = separator->A->n; + int nB = separator->B->n; + int nC = separator->C->n; + Node A, B; + + if (0) { for (int i = 0; i < depth; i ++) printf(" "); printf("%d %d %d\n", 1000*nA/n, 1000*nB/n, 1000*nC/n); } + + assert(nC > 0); // Indeed, the subgraph is connected here. + + + int *listA = S; + int *listB = S+nA; // no need for S after here + + if (trace) printf(" sep: %d,%d,%d\n", nA, nB, nC); + + copyList(listA, separator->A->val, nA); + copyList(listB, separator->B->val, nB); + + // Here nbNeighborsInA and nbNeighborsInB contain for each vertex in listA and listB + // its number of neighbors in listA and listB. No need to recalculate in initSeparator. + + if (nA >= nB) { + A = decompose(listA, nA, pos, depth + 1, g, hmax - nC, 0); + if (stopSearch) return NULL; + if ((A == NULL) && (nA > 0)) { + root = NULL; + goto FIN; + } + B = decompose(listB, nB, pos, depth + 1, g, hmax - nC, 0); + if (stopSearch) return NULL; + if ((B == NULL) && (nB > 0)) { + root = NULL; + goto FIN; + } + } + else { + B = decompose(listB, nB, pos, depth + 1, g, hmax - nC, 0); + if (stopSearch) return NULL; + if ((B == NULL) && (nB > 0)) { + root = NULL; + goto FIN; + } + A = decompose(listA, nA, pos, depth + 1, g, hmax - nC, 0); + if (stopSearch) return NULL; + if ((A == NULL) && (nA > 0)) { + root = NULL; + goto FIN; + } + } + + + if (0) if (sizeForest(A)+ sizeForest(B)+ sizeForest(root) != nA+nB+nC) { + printf("nA=%d nB=%d nC=%d A:%d B:%d root:%d\n", nA, nB, nC, sizeForest(A), sizeForest(B), sizeForest(root)); + exit(0); + } + + + if (root == NULL) { + if (A == NULL) { root = B; goto FIN; } + if (B == NULL) { root = A; goto FIN; } + //assert(A->next == NULL); + //assert(B->next == NULL); + root = A; + while (A->next != NULL) A = A->next; + A->next = B; + assert((root->next == NULL) || (depth > 0)); + goto FIN; + } + + + if (A != NULL) { + if (A->next == NULL) + addChild(A, theLastOfTheBranch); + else { + while (A != NULL) { + Node next = A->next; + addChild(A, theLastOfTheBranch); + A = next; + } + } + } + + + if (B != NULL) { + if (B->next == NULL) + addChild(B, theLastOfTheBranch); + else { + while (B != NULL) { + Node next = B->next; + addChild(B, theLastOfTheBranch); + B = next; + } + } + } + + if (theLastOfTheBranch->father != NULL) + updateIncHeightOnBranch(theLastOfTheBranch->father, theLastOfTheBranch->height); + + //updateBranchUp(theLastOfTheBranch, root); + FIN: + + //verifyTree(root, depth); + return root; +} + + +Node decomposeConnectedComponents(int *iComp, int nbComp, int *S, int n, int pos[], int depth, Graph g, int hmax) { + + Node list = NULL, node; + + nbCallsDecomposeComponents ++; + + int *sizes = malloc(nbComp*sizeof(int)); // To memorize sizes after first explorations + + sortListByComponent(S, n, nbComp, sizes); + int nbV = 0; + + for (int i = 0; i < nbComp; i ++) { + if (stopSearch) { list = NULL; break; } + + node = decompose(S+nbV, sizes[i], pos, depth, g, hmax, 1); + + if ((node == NULL) || (stopSearch)) return NULL; + + node->next = list; + if (list != NULL) list->prev = node; + list = node; + + nbV += sizes[i]; + } + + return list; + +#ifdef OLD_VERSION + int *component, *componentOf; + + if (components[topComponents] == NULL) reAllocComponents(g, 100); + component = components[topComponents]; + componentOf = componentsOf[topComponents]; + topComponents ++; + + // Memorize iComp[] that may be used in next calls + for (int i = 0; i < n; i ++) + componentOf[i] = iComp[S[i]]; + + for (int i = 0; i < nbComp; i ++) { + if (stopSearch) { list = NULL; break; } + + int size = extractList(i, S, n, componentOf, component); + + node = decompose(component, size, depth, g, hmax, 1); + if (node == NULL) { topComponents --; return NULL; } + + node->next = list; + if (list != NULL) list->prev = node; + list = node; + } + + topComponents --; + return list; +#endif +} + + + +// +// Greedy-decompose (V,E) +// 1. select vertex u with highest degree, +// 2. C:=disconnectedComponents(V-{u},E), +// 3. tree:=<u>, +// 4. for each c in C do +// 5. addChild(Greedy-decompose(c,E), tree), +// 6. return tree, + +int lastRemovedVertex = NONE; + +Node greedyDecompose(Heap conHeap, int depth, Graph g, int hmax, int connected) { + + nbCallsDecompose ++; + + if (depth > maxDepthGreedy) return NULL; + + //int localNbCalls = nbCallsDecompose; + + if (trace) printf("[%d] call %d n=%d max=%d ", depth, nbCallsDecompose, conHeap->n, maxNbN4Con); + + if (stopSearch) return NULL; + if (conHeap->n == 0) return NULL; + if (hmax == 0) return NULL; + + if (conHeap->n <= SIZE_SMALL_TREE) { + Node root = makeSmallTree(conHeap->val, conHeap->n, g); + heapRemoveAll(conHeap); + return root; + } + + // Isolated vertices + if (nbUnconnectedVertices > 0) { + //assert(connected == 0); + if (trace) printf(" :: %d unconnected vertices :: %d --> %d\n", nbUnconnectedVertices, conHeap->n, conHeap->n - nbUnconnectedVertices); + Node last; + Node root = makeListWithUnconnectedVertices(conHeap, g, &last); + if (conHeap->n > 0) { + nbUnconnectedVertices = 0; + Node sibling = greedyDecompose(conHeap, depth + 1, g, hmax, 0); + if (sibling == NULL) + return NULL; + last->next = sibling; + } + return root; + } + + // Search disconnected components + if (( ! connected) && (depth > 0) && (lastRemovedVertex != NONE) && + (nbN4Con[lastRemovedVertex] != 1)) { // added 7/04/2020 + int nbComp = searchConnectedComponentsGreedy(NULL, conHeap, g, lastRemovedVertex); + if (nbComp > 1) { //if (trace) { printf("components [%d] ", nbComp); for (int i = 0; i < nbComp; i ++) printf("%d,", compSizes[i]); printf("\n");} + return greedyDecomposeComponents(iComp, nbComp, conHeap, depth, g, hmax); + } + } + + if (stopSearch) return NULL; + + // Build a tree whose root is a node with highest degree + + int vertex = vertexWithManyConnections(conHeap, MAX_CONNECTED_BEST_AT_RANDOM); + + if (trace) printf("remove %d (nbN=%d)\n", vertex, nbN4Con[vertex]); + + //if (nbInListWithThisValue(maxNbN4Con, conHeap->val, conHeap->n, nbN4Con) != nbMax4Con) { printf("AAA max=%d %d et non pas %d\n",maxNbN4Con, nbInListWithThisValue(maxNbN4Con, conHeap->val, conHeap->n, nbN4Con), nbMax4Con); exit(0); } + + heapRemove(vertex, conHeap); + + if (nbN4Con[vertex] == maxNbN4Con) { + if (--nbMax4Con == 0) updateNbMaxConInHeap(conHeap); + } + + if (nbN4Con[vertex] == 0) nbUnconnectedVertices --; + + //printf("1. max=%d nbMax=%d --> ", maxNbN4Con, nbMax4Con); + //if (nbInListWithThisValue(maxNbN4Con, conHeap->val, conHeap->n, nbN4Con) != nbMax4Con) { printf("BBB max=%d %d et non pas %d\n",maxNbN4Con, nbInListWithThisValue(maxNbN4Con, conHeap->val, conHeap->n, nbN4Con), nbMax4Con); exit(0); } + + updateHeapNbNAfterRemoval(vertex, conHeap, g); + + //assert(conHeap->n > 0); + if (nbMax4Con == 0) updateNbMaxConInHeap(conHeap); + + //printf("2. max=%d nbMax=%d\n", maxNbN4Con, nbMax4Con); + //if (nbInListWithThisValue(maxNbN4Con, conHeap->val, conHeap->n, nbN4Con) != nbMax4Con) { printf("CCC max=%d %d et non pas %d\n",maxNbN4Con, nbInListWithThisValue(maxNbN4Con, conHeap->val, conHeap->n, nbN4Con), nbMax4Con); exit(0); } + + Node root = theNodes[vertex]; + resetNode(root); + + lastRemovedVertex = vertex; + + Node children = greedyDecompose(conHeap, depth+1, g, hmax, 0); + + if (children == NULL) + return NULL; + + if (children->next == NULL) + addChild(children, root); + else { + while (children != NULL) { + Node child = children; + children = children->next; + addChild(child, root); + } + } + + //verifyTree(root, 0); + + return root; +} + + + +Node greedyDecomposeComponents(int iComp[], int nbComp, Heap conHeap, int depth, Graph g, int hmax) { +// Normally there is no component of size 1 + nbCallsDecomposeComponents ++; + int numCall = nbCallsDecomposeComponents; + + int *sizes = malloc(nbComp*sizeof(int)); // To memorize sizes after first explorations + + sortListByComponent(conHeap->val, conHeap->n, nbComp, sizes); + + if (trace) { + printf(" :: split call %d : %d components : ", nbCallsDecomposeComponents, nbComp); + for (int i = 0; i < nbComp; i ++) printf("%d ", sizes[i]); + printf("\n"); + } + + // The number of neighbors of u in S[] is the number of neighbors of u in its component + // No need to update. + Node list = NULL, node; + int nb = 0; + int *val = conHeap->val; + for (int i = 0; i < nbComp; i ++) { + + if (stopSearch) { conHeap->val = val; free(sizes); return NULL; } + + conHeap->n = sizes[i]; + conHeap->val = val+nb; + nb += sizes[i]; + + if (i == nbComp-1) free(sizes); + + lastRemovedVertex = NONE; + + if (conHeap->n <= SIZE_SMALL_TREE) { + node = makeSmallTree(conHeap->val, conHeap->n, g); + heapRemoveAll(conHeap); + } + else if (rebuildConHeap(conHeap)) { + // clique + node = makeSingleBranch(conHeap->val, conHeap->n, NULL, g); + heapRemoveAll(conHeap); + } + else + node = greedyDecompose(conHeap, depth, g, hmax, 1); // the component is connected + + if (0 && ! verifyDecomposition(node, g)) { printf("Error: decCompCall %d depth=%d\n", numCall, depth); exit(0); } + + if (node == NULL) { conHeap->val = val; if (i != nbComp-1) free(sizes); return NULL; } + + node->next = list; + if (list != NULL) list->prev = node; + list = node; + } + + conHeap->val = val; + //free(sizes); + + return list; +} + + + + +Node makeListWithUnconnectedVertices(Heap heap, Graph g, Node *last) { + // unconnected vertices are at the end of the heap + // They are just removed from the heap, the degree of their already removed neighbors is not updated + int firstUV = heap->n - nbUnconnectedVertices; + Node node = NULL; + *last = NULL; + + for (int i = heap->n - 1; i >= firstUV ; i --) { + int u = heap->val[i]; + assert (nbN4Con[u] == 0); + //heapRemove(heap->val[i], heap); + heap->ind[u] = NONE; + Node p = theNodes[u]; + resetNode(p); + if (*last == NULL) *last = p; + p->next = node; + node = p; + } + heap->n = firstUV; + return node; +} + + +Node makeSmallTree(int *S, int n, Graph g) { + + if (n == 0) return NULL; + + Node u = theNodes[S[0]]; + resetNode(u); + + if (n == 1) return u; + + Node v = theNodes[S[1]]; + resetNode(v); + + if (n == 2) { + if (areNeighbours(u->vertex, v->vertex, g)) { + addChild(v, u); + return u; + } + //connectSiblings(u, v); + u->next = v; + return u; + } + + Node w = theNodes[S[2]]; + resetNode(w); + + int status = 0; + if (areNeighbours(u->vertex, v->vertex, g)) + status += 1; + if (areNeighbours(u->vertex, w->vertex, g)) + status += 2; + if (areNeighbours(v->vertex, w->vertex, g)) + status += 4; + + + if (status == 7) { // Clique -> branch + addChild(w, v); + addChild(v, u); + return u; + } + + if (status == 6) { // (u,w) (v,w) -> w(u,v) + addChild(u, w); + addChild(v, w); + return w; + } + + if (status == 4) { // (v,w) -> w(v),u + addChild(v, w); + w->next = u; // addChild(u, w); + return w; + } + + if (status == 2) { // (u,w) -> w(u),v + addChild(u, w); + w->next = v; // addChild(v, w) + //connectSiblings(w, v); + return w; + } + + if (status == 5) { // (u,v) (v,w) -> v(u,w) + addChild(w, v); + addChild(u, v); + return v; + } + + if (status == 1) { // (u,v) -> v(u),w + addChild(u, v); + v->next = w; // addChild(w, v); + //connectSiblings(v, w); + return v; + } + + if (status == 3) { // (u,v) (u,w) -> u(v,w) + addChild(v, u); + addChild(w, u); + return u; + } + + //addChild(v, u); + //addChild(w, u); + //return u; + + // (status == 0) :: (u,v) (u,w) -> u(v,w) + u->next = v; + v->next = w; + //connect3Siblings(u, v, w); + + return u; +} + + + + + +// +// Utils +// + + + +void allocNodes(Graph g) { + theNodes = malloc(g->n*sizeof(Node)); + for (int i = 0; i < g->n; i ++) + theNodes[i] = newNode(i, g); +} + +void allocSets(Graph g, int max) { + theSets = calloc((size_t) (g->n), sizeof(SET)); + for (int i = 0; i < max; i ++) + theSets[i] = allocSet(g->n + 100); +} + + +void allocComponents(Graph g, int max) { + components = calloc((size_t) (g->n), sizeof(int *)); + componentsOf = calloc((size_t) (g->n), sizeof(int *)); + for (int i = 0; i < max; i ++) { + components[i] = malloc((size_t) (g->n) * sizeof(int)); + componentsOf[i] = malloc((size_t) (g->n) * sizeof(int)); + } +} + + + +// Alloc new sets if necessary +void reAllocSets(int size, Graph g) { + + for (int i = nbAllocatedSets; i < nbAllocatedSets+size; i++) { + theSets[i] = allocSet(g->n); + } + nbAllocatedSets += size; +} + + +void reAllocComponents(Graph g, int size) { + for (int i = nbAllocatedComponents; i < nbAllocatedComponents+size; i ++) { + components[i] = malloc((size_t) (g->n) * sizeof(int)); + componentsOf[i] = malloc((size_t) (g->n) * sizeof(int)); + } + nbAllocatedComponents += size; +} + + + + +void PACEOutput(FILE *file, int height, int fathers[], Graph g) { + + if (file == NULL) file = stdout; + + fprintf(file, "%d\n", height); + + for (int i = 0; i < g->n; i ++) { + fprintf(file, "%d\n", fathers[i]); + } +} + + +void saveToTable(int T[], Graph g) { + for (int i = 0; i < g->n; i ++) { + T[i] = (theNodes[i]->father == NULL) ? 0 : (theNodes[i]->father->vertex+1); + } +} + +Node buildTreeFromTable(int T[], Graph g) { + Node root = NULL; + + for (int i = 0; i < g->n; i ++) + theNodes[i]->father = theNodes[i]->next = theNodes[i]->fbs = NULL; + + for (int i = 0; i < g->n; i ++) { + Node father = (T[i] == 0) ? NULL : theNodes[T[i]-1]; + theNodes[i]->father = father; + if (father != NULL) { + theNodes[i]->next = father->fbs; + father->fbs = theNodes[i]; + } else + root = theNodes[i]; + } + return root; +} + + +// Verify that the decomposition tree is correct for the edges of g +// Note : tree may be a partial decomposition of g (does not contain all the vertices of g) +int exploreAndSetFathers(Node p, int F[]) { + Node q = p->fbs; + if (F[p->vertex] != NONE) { printf("vertex %d occurs twice !\n", p->vertex); return 0; } + while (q != NULL) { + if ( ! exploreAndSetFathers(q, F)) return 0; + F[q->vertex] = p->vertex; + q = q->next; + } + return 1; +} + +int areInSameBranch(int u, int v, int F[]) { + int i = u; + while ((i != NONE) && (i != v)) + i = F[i]; + if (i == v) return 1; + i = v; + while ((i != NONE) && (i != u)) + i = F[i]; + return (i == u); +} + +int verifyDecomposition(Node tree, Graph g) { + //printf("43e neighbor of %d = %d\n", 13280-1, g->lists[13280-1][43]); + if (sizeTree(tree) != g->n) { printf("Error size %d nodes\n", sizeTree(tree)); return 0; } + int F[g->n]; + for (int i = 0; i < g->n; i ++) + F[i] = NONE; + if ( ! exploreAndSetFathers(tree, F)) return 0; + int nbNONE = 0; + for (int u = 0; u < g->n; u ++) if (F[u] == NONE) nbNONE ++; + if (nbNONE != 1) { printf("Error : %d nodes not in tree\n", nbNONE-1); return 0; } + //printf(" in same branch 13280 16624 : %d\n", areInSameBranch(13280-1, 16624-1, F)); + for (int u = 0; u < g->n; u ++) { + if (F[u] != NONE) { + for (int *p = g->lists[u]; *p != NONE; p ++) { + //if ((u == 13280-1) && (*p == 16624-1)) printf("test edge %d %d %d\n", u, *p, (int) (p-g->lists[u])); + //if ((u == 16624-1) && (*p == 13280-1)) printf("test edge %d %d %d\n", u, *p, (int) (p-g->lists[u])); + if (F[*p] != NONE) { + // g contains edge (u,q->val) and u and q->val are in the tree + //if ((u == 16624-1) && (*p == 13280-1)) printf("edge %d %d %d\n", u, *p, (int) (p-g->lists[u])); + //if ((u == 13280-1) && (*p == 16624-1)) printf("edge %d %d %d\n", u, *p, (int) (p-g->lists[u])); + if ( ! areInSameBranch(u, *p, F)) { + printf("Error edge (%d,%d)\n", u, *p); + return 0; + } + } + } + } +#ifdef NOTDEF + if (F[u] != NONE) { + LIST q = g->adj[u]; + while (q != NULL) { + if ((u == 13280) && (q->val == 16624)) printf("Yahou\n"); + if ((u == 16624) && (q->val == 13280)) printf("Yahou\n"); + if (F[q->val] != NONE) { + // g contains edge (u,q->val) and u and q->val are in the tree + if ( ! areInSameBranch(u, q->val, F)) { + printf("Error edge (%d,%d)\n", u, q->val); + return 0; + } + } + q = q->suiv; + } + } +#endif + } + return 1; +} + + + +void printStatsOnCriticalNodes(Node root, int *nbCriticalNodes) { + makeStatsCriticalNodes(root, nbCriticalNodes); +//for (int i = 0; i < root->height; i++) printf("[%d] %d\n", i, nbCriticalNodes[i]); + printf("[%d] %d\n", 0, nbCriticalNodes[0]); + for (int i = 1; i < root->height; i++) if (nbCriticalNodes[i] != nbCriticalNodes[i-1]) printf("[%d] %d\n", i, nbCriticalNodes[i]); + printf("[%d] %d\n", root->height-1, nbCriticalNodes[root->height-1]); +} + diff --git a/pace-2020/decompose.h b/pace-2020/decompose.h new file mode 100644 index 0000000000000000000000000000000000000000..baa1060913a92edb68c46bd468e61ca8662c26d7 --- /dev/null +++ b/pace-2020/decompose.h @@ -0,0 +1,58 @@ +// +// Created by Stephane on 10/03/2020. +// + +#ifndef SRC_DECOMPOSE_H +#define SRC_DECOMPOSE_H + +#include <stdio.h> + +#include "graph.h" +#include "separator.h" +#include "sets.h" +#include "tree.h" + + +#define SEPARE_AND_EXPLORE 0 +#define GREEDY_ALGORITHM 1 + +#define SIZE_SMALL_TREE 3 + + +extern int *bestTree; +extern int bestHeight; + + +extern Separator separator; + +extern Node * theNodes; + +extern int time_limit; + + +void updateBestDecomposition(Node root, Graph g); + +void testDecompose(Graph g, int nbRuns, int algo); + +Node decompose(int *S, int n, int pos[], int depth, Graph g, int hmax, int connected); +Node greedyDecompose(Heap conHeap, int depth, Graph g, int hmax, int connected); + +Node makeListWithUnconnectedVertices(Heap heap, Graph g, Node *last); +Node makeSmallTree(int *S, int n, Graph g); +Node decomposeConnectedComponents(int *iComp, int nbComp, int *S, int n, int pos[], int depth, Graph g, int hmax); +Node greedyDecomposeComponents(int iComp[], int nbComp, Heap conHeap, int depth, Graph g, int hmax); + +int isSmallerNeighborsInB(int a, int b); +void allocNodes(Graph g); +void allocSets(Graph g, int max); +void reAllocSets(int size, Graph g); +void allocComponents(Graph g, int max); +void reAllocComponents(Graph g, int size); +void PACEOutput(FILE *file, int height, int fathers[], Graph g); +void saveToTable(int T[], Graph g); +Node buildTreeFromTable(int T[], Graph g); + +int verifyDecomposition(Node tree, Graph g); +void printStatsOnCriticalNodes(Node root, int *nbCriticalNodes); + +#endif //SRC_DECOMPOSE_H diff --git a/pace-2020/graph.c b/pace-2020/graph.c new file mode 100644 index 0000000000000000000000000000000000000000..88fd461dcae597698b40ceccc88f449d5f9bc373 --- /dev/null +++ b/pace-2020/graph.c @@ -0,0 +1,422 @@ +/* + * graph.c + * graphes + * + * Created by St�phane on 19/02/18. + * Copyright 2018 __MyCompanyName__. All rights reserved. + * + */ + +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +//#include <tcl.h> + +#include "lists.h" +#include "decompose.h" +#include "graph.h" +#include "heap.h" +#include "main.h" +#include "sets.h" +#include "utils.h" + + +int maxMemory = 8000; + + +Graph newGraph(int n, int m, LIST *adj, int *nadj) { + Graph g; + + g = malloc(sizeof(struct graph)); + + g->n = n; + g->m = m; + if (adj == NULL) { + g->adj = calloc(n, sizeof(LIST)); + g->nadj = calloc(n, sizeof(int)); + } + else { + g->adj = adj; + g->nadj = nadj; + g->lists = malloc(g->n*sizeof(int *)); + g->slists = malloc(g->n*sizeof(int *)); + for (int i = 0; i < n; i ++) { + g->lists[i] = malloc((g->nadj[i]+1)*sizeof(int)); + g->lists[i][g->nadj[i]] = NONE; + g->slists[i] = malloc((g->nadj[i]+1)*sizeof(int)); + g->slists[i][g->nadj[i]] = NONE; + g->nadj[i] = 0; + } + for (int i = 0; i < n; i ++) { + LIST p = adj[i]; + while (p != NULL) { + g->lists[i][g->nadj[i]] = g->slists[i][g->nadj[i]] = p->val; + g->nadj[i] ++; + p = p->suiv; + } + + } + } + + g->neighbors = malloc(g->n*sizeof(SET)); + + if ((algo == GREEDY_ALGORITHM) || ((g->n/64)*(g->n/128)/1024 > maxMemory)) { // n=260000 --> mem=8000 + for (int i = 0; i < n; i ++) g->neighbors[i] = NULL; + return g; + } + + for (int i = 0; i < n; i ++) { + + SET neighbors = allocSet(g->n); + if (adj != NULL) { + int *p = g->lists[i]; + while (*p != NONE) { + ADDe(*p, neighbors); + p ++; + } + } + g->neighbors[i] = neighbors; + } + +#ifdef NOTDEF + g->nodes = malloc(n*sizeof(NODE_FIBO)); + assert(g->nodes != NULL); + for (int i = 0; i < n; i ++) { + g->nodes[i] = newHeapNode(i, 0, NULL, NULL, NULL, NULL, 0, 1, NULL); + } +#endif + + return g; +} + + + +// Determine if u and v are neighbors. +int areNeighbours(int u, int v, Graph g) { + + if (g->neighbors[v] != NULL) + return IN(u, g->neighbors[v]); + + if (g->nadj[u] <= g->nadj[v]) { + for (int *p = g->lists[u]; *p != NONE; p++) { + if (*p == v) return 1; + } + return 0; + } + + for (int *p = g->lists[v]; *p != NONE; p++) { + if (*p == u) return 1; + } + return 0; +} + + +void printGraph(Graph g) { + for (int i = 0; i < g->n; i ++) { + for (LIST p = g->adj[i]; p != NULL; p = p->suiv) + printf("%d -- %d\n", i, p->val); + } +} + + +// Count the number of vertices of list[] which are in the heap F (used to count the number of neighbors in the heap). +int nbVerticeInHeap(int list[], int n, Heap F, Graph g) { + int nb = 0; + for (int *p = list; p < list+n; p ++) { + if (F->ind[*p] != NONE) + nb ++; + } + return nb; +} + +int nbNeighborsInHeap(int u, Heap F, Graph g) { + LIST p = g->adj[u]; + int nb = 0; + while (p != NULL) { + if (F->ind[p->val] != NONE) + nb ++; + p = p->suiv; + } + return nb; +} + + +int nbNeighborsInList(int u, SET V, int *S, int n, Graph g) { + LIST p = g->adj[u]; + int nbN = 0; + + while (p != NULL) { + if (isInSet(p->val, V, S, n)) { + nbN ++; + } + p = p->suiv; + } + return nbN; +} + +int hasNoNeighborInSet(int vertex, SET V, Graph g) { + for (int *p = g->lists[vertex]; *p != NONE; p ++) + if (IN(*p, V)) return 0; + return 1; +} + +int hasNeighborsInSubtree(int vertex, SET V, Graph g) { + int nb = 0; + for (int *p = g->lists[vertex]; *p != NONE; p ++) + if (IN(*p, V)) nb ++; + return nb; +} + + +int haveSameNeighbors(int u, int v, Graph g) { + int *q; + for (int *p = g->lists[u]; *p != NONE; p ++) { + for (q = g->lists[v]; *q != NONE; q++) + if (*p == *q) break; + if (*q == NONE) return 0; + } + return 1; +} + + + +// +// Connections in current set +// + +Heap conHeap = NULL; // contains the vertices ordered by their number of neighbors in the cluster +int *nbN4Con; // for each vertex the number of its neighbors in the cluster +int nbE4Con, nbMax4Con, maxNbN4Con; +int nbUnconnectedVertices; + +int hasMoreConnections(int a, int b) { + return (nbN4Con[a] > nbN4Con[b]); +} + +void allocConnectionsHeap(Graph g) { + conHeap = allocHeap(g->n, hasMoreConnections); + nbN4Con = malloc(g->n * sizeof(int)); +} + +// +// Update the max value in the heap and its number of occurrences +// + +void exploreCountMax(int i, int T[], int n) { + if (nbN4Con[T[i]] == maxNbN4Con) { + nbMax4Con ++; + if (2*i+1 < n) { + exploreCountMax(2*i+1, T, n); + if (2*i+2 < n) + exploreCountMax(2*i+2, T, n); + } + } +} + +void updateNbMaxConInHeap(Heap heap) { + + if (heap->n == 0) { nbMax4Con = 0; return; } + + maxNbN4Con = nbN4Con[heap->val[0]]; + nbMax4Con = 0; + exploreCountMax(0, heap->val, heap->n); +} + + + +// Rebuilt the heap. Suppose that there is no unconnected components here (called after decomposeConnectedComponents) +// returns 1 if the heap is a clique +int rebuildConHeap(Heap heap) { + nbE4Con = 0; + nbUnconnectedVertices = 0; // Comes from decomposeConnectedComponents normally with no unconnected vertices + maxNbN4Con = -1; + int minNbN4Con = conHeap->n + 1; + for (int i = 0; i < conHeap->n; i ++) { + conHeap->ind[conHeap->val[i]] = i; + nbE4Con += nbN4Con[conHeap->val[i]]; + if (nbN4Con[conHeap->val[i]] == 0) nbUnconnectedVertices ++; + if (nbN4Con[conHeap->val[i]] < minNbN4Con) minNbN4Con = nbN4Con[conHeap->val[i]]; + if (nbN4Con[conHeap->val[i]] > maxNbN4Con) { maxNbN4Con = nbN4Con[conHeap->val[i]]; nbMax4Con = 1; } + else if (nbN4Con[conHeap->val[i]] == maxNbN4Con) nbMax4Con ++; + } + makeHeap(conHeap); + if (minNbN4Con == heap->n - 1) return 1; + return 0; + //heapVerif(conHeap, nbN4Con); +} + +// The initial construction of the heap: there can be unconnected components ! +void initConHeap(Graph g) { + + //conHeap = allocHeap(g->n, hasMoreConnections); + //nbN4Con = malloc(g->n * sizeof(int)); + + nbE4Con = 0; + nbMax4Con = 0; + maxNbN4Con = -1; + nbUnconnectedVertices = 0; + conHeap->n = 0; + + for (int i = 0; i < g->n; i++) { + heapJustAdd(i, conHeap); + nbN4Con[i] = g->nadj[i]; + nbE4Con += nbN4Con[i]; + if (nbN4Con[i] > maxNbN4Con) { maxNbN4Con = nbN4Con[i]; nbMax4Con = 1; } + else if (nbN4Con[i] == maxNbN4Con) nbMax4Con ++; + if (nbN4Con[i] == 0) nbUnconnectedVertices ++; + } + + shakeList(conHeap->val, conHeap->ind, conHeap->n, g->n / 2); + + makeHeap(conHeap); +} + + +int countNbUnconnectedInHeap(Heap F) { + int nb = 0; + for (int i = 0; i < F->n; i ++) + if (nbN4Con[F->val[i]] == 0) nb ++; + return nb; +} + + + +// Here other vertices may have index not NONE but they can not be in u component and then they are not neighbors +int updateHeapNbNAfterRemoval(int u, Heap heap, Graph g) { + + int nbRemovedEdges = 0; + + //assert(nbUnconnectedVertices == countNbUnconnectedInHeap(heap)); + for (int *pp = g->lists[u]; *pp != NONE; pp ++) { + + nbN4Con[*pp] --; + + if (heap->ind[*pp] != NONE) { + + // if ( nbOccs(*pp, heap->val, heap->n) != 1) printf("%d OUYE\n", *pp); + + nbRemovedEdges ++; + + if (nbN4Con[*pp]+1 == maxNbN4Con) nbMax4Con --; + + if (nbN4Con[*pp] == 0) { // put unconnected vertice at the end of the heap (can leave current branch) + int pos = heap->ind[*pp]; + if (0 && (nbUnconnectedVertices+1 != countNbUnconnectedInHeap(heap))) { printf("nbunconnected is not good : %d / %d\n", countNbUnconnectedInHeap(heap), nbUnconnectedVertices+1);exit(0); } + heapSwap(pos, heap->n - 1 - nbUnconnectedVertices, heap); + // update the heap + if ((pos > 0) && (nbN4Con[heap->val[pos]] > nbN4Con[*pp]+1)) + heapBubbleUp(pos, heap); + else if (nbN4Con[heap->val[pos]] < nbN4Con[*pp]+1) + heapBubbleDown(heap, pos); + nbUnconnectedVertices++; + } + else { + heapBubbleDown(heap, heap->ind[*pp]); + } + } + } + //assert(nbUnconnectedVertices == countNbUnconnectedInHeap(heap)); + return nbRemovedEdges; +} + + +// returns the position of a vertex of S[] with many neighbors in S[] (depending of mode). +int vertexWithManyConnections(Heap heap, int mode) { + + assert(heap->n != 0); + + if (heap->n == 1) return heap->val[0]; + + if (mode == MAX_CONNECTED_WEIGHTED_AT_RANDOM) {// Unsupported: nbE4Con is not up to date + nbE4Con = 0; + for (int i = 0; i < heap->n; i ++) + nbE4Con += nbN4Con[heap->val[i]]; + return chooseWeightedRandom(nbN4Con, heap->val, heap->n, nbE4Con); + } + + if (mode == MAX_CONNECTED_BEST_AT_RANDOM) + return heap->val[rand()%nbMax4Con]; // perhaps not a vertex with the max number of neighbors + + return heap->val[0]; +} + + + +// +// UNUSED +// + +SET set4Con; // the set of vertices that are considered to evaluate connectivity + +void updateNeighbors4Con(int u, Graph g) { + LIST p = g->adj[u]; + while (p != NULL) { + if (IN(p->val, set4Con) && (conHeap->ind[p->val] != NONE)) { + nbN4Con[p->val]++; + heapDecreaseKey(p->val, conHeap); + } + p = p->suiv; + } +} + + +int vertexMaxConnectivity(int *S, int n, SET V, Graph g) { + set4Con = V; + + if (conHeap == NULL) { + conHeap = allocHeap(g->n, hasMoreConnections); + nbN4Con = malloc(g->n * sizeof(int)); + } + + int best = S[0]; + float eval = connectivity(S[0], S, n, g); + + for (int i = 1; i < n; i ++) { + float e = connectivity(S[i], S, n, g); + if (e > eval) { + eval = e; + best = S[i]; + } + } + return best; +} + + +// Evaluates the degree of connectivity of a vertice. +// The heap contains the vertices ordered by the number of neighbors in the cluster built from u +float connectivity(int u, int S[], int n, Graph g) { + + int nbVertices = 1, nbEdges = 0; + float density = 0; + + resetHeap(conHeap); + for (int i = 0; i < n; i ++) { heapJustAdd(S[i], conHeap); nbN4Con[i] = 0; } + + heapRemove(u, conHeap); + updateNeighbors4Con(u, g); + + while (conHeap->n > 0) { + nbVertices ++; + nbEdges += nbN4Con[conHeap->val[0]]; + //printf("%d %d density=%.1f\n", nbVertices, nbEdges, density); + if ((float) nbEdges/nbVertices < density) + break; + density = (float) nbEdges/nbVertices; + int v = heapExtractMin(conHeap); + updateNeighbors4Con(v, g); + } + if (0) printf("cluster %d : %d/%d %d edges density=%.1f\n", u, nbVertices, n, nbEdges, density); + return density; +} + + + + + + + + + + + diff --git a/pace-2020/graph.h b/pace-2020/graph.h new file mode 100644 index 0000000000000000000000000000000000000000..a425598cdb1ef3a9cad2203d29512cc36496064e --- /dev/null +++ b/pace-2020/graph.h @@ -0,0 +1,76 @@ + +#ifndef _H_graph +#define _H_graph + +/* + * graph.h + * graphes + * + * Created by St�phane on 19/02/18. + * Copyright 2018 __MyCompanyName__. All rights reserved. + * + */ + + +#include "lists.h" +#include "heap.h" +#include "sets.h" + + + +#define ALL_TERMINALS 0 +#define ONLY_LEAVES 1 + +// Choice of a vertex (choose at random among the best or use a weighted random choice) +#define MAX_CONNECTED_WEIGHTED_AT_RANDOM 0 +#define MAX_CONNECTED_BEST_AT_RANDOM 1 + + + +typedef struct graph * Graph; + +struct graph { + int n; /* nb vertices */ + int m; /* nb edges */ + LIST *adj; + int **slists; // neighbors sorted lists + int **lists; // neighbors lists (reordered before separation to place first current vertices) + int *nadj; + + SET *neighbors; +}; + + +// For the heap sorted with numbers of connections +extern Heap conHeap; +extern int *nbN4Con; // for each vertex the number of its neighbors in the cluster +extern int nbE4Con, nbMax4Con, maxNbN4Con; +extern int nbUnconnectedVertices; + + +Graph newGraph(int n, int m, LIST *adj, int *nadj); +int areNeighbours(int u, int v, Graph g); +void printGraph(Graph g); +int nbNeighborsInHeap(int u, Heap F, Graph g); +int nbVerticeInHeap(int list[], int n, Heap F, Graph g); +int nbNeighborsInList(int u, SET V, int *S, int n, Graph g); +int hasNoNeighborInSet(int vertex, SET V, Graph g); +int hasNeighborsInSubtree(int vertex, SET V, Graph g); +int haveSameNeighbors(int u, int v, Graph g); + +int hasMoreConnections(int a, int b); +void allocConnectionsHeap(Graph g); +int updateHeapNbNAfterRemoval(int u, Heap heap, Graph g); +int vertexWithManyConnections(Heap heap, int mode); +void updateNbMaxConInHeap(Heap H); +int rebuildConHeap(Heap heap); +void initConHeap(Graph g); +int vertexMaxConnectivity(int *S, int n, SET V, Graph g); +float connectivity(int u, int S[], int n, Graph g); + +#endif + + + + + diff --git a/pace-2020/heap.c b/pace-2020/heap.c new file mode 100644 index 0000000000000000000000000000000000000000..16f4c7c1b1ea54ebadc99faef10742237d11d26f --- /dev/null +++ b/pace-2020/heap.c @@ -0,0 +1,394 @@ +/* + * tas.c + * packing-satmod + * + * Created by St�phane on 11/11/14. + * Copyright 2014 __MyCompanyName__. All rights reserved. + * + */ +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +//#include <tcl.h> + +#include "heap.h" +#include "utils.h" + + +Heap allocHeap (int size, int (*lt)(int, int)) { + Heap F; + + F = malloc(sizeof(struct heap)); + assert(F != NULL); + + F->size = size; + F->n = 0; + F->val = malloc(size*sizeof(int)); + assert(F->val != NULL); + F->ind = malloc(size*sizeof(int)); + assert(F->ind != NULL); + + F->lt = lt; + + return F; +} + + +void heapSetCompare(Heap F, int (*lt)(int, int)) { + F->lt = lt; +} + + +void freeHeap(Heap F) { + free(F->val); + free(F->ind); + free(F); +} + + +void resetHeap(Heap F) { + F->n = 0; +} + + +void heapSwap (int i, int j, Heap F) { + int x = F->val[i]; + F->val[i] = F->val[j]; + F->ind[F->val[i]] = i; + F->val[j] = x; + F->ind[x] = j; +} + + +void heapBubbleDown(Heap F, int i) { + int i_min; + + DEBUT: + i_min = i; + + if (FG(i) >= F->n) + return; + + if (F->lt(F->val[FG(i)], F->val[i_min])) + i_min = FG(i); + + if ((FD(i) < F->n) && F->lt(F->val[FD(i)], F->val[i_min])) + i_min = FD(i); + + if (i_min != i) { + heapSwap(i, i_min, F); + i = i_min; + goto DEBUT; + } +} + + +void makeHeap(Heap F) { + int i; + + for (i = (F->n-1)/2; i >= 0; i --) + heapBubbleDown(F, i); +} + + +int heapExtractMin (Heap F) { + int min = F->val[0]; + + F->ind[min] = NONE; + + F->n --; + F->val[0] = F->val[F->n]; + F->ind[F->val[0]] = 0; + + heapBubbleDown(F, 0); + //heapVerif(F, weight); + + return min; +} + + + +void heapRemove (int x, Heap F) { + int i = F->ind[x]; + + F->ind[x] = NONE; + + F->n --; + + if (i == F->n) + return; + + F->val[i] = F->val[F->n]; + F->ind[F->val[i]] = i; + + if (F->lt(x, F->val[i])) //(weight[F->val[i]] > weight[x]) + heapBubbleDown(F, i); + else + heapBubbleUp(i, F); + //heapVerif(F, weight); +} + + +void heapJustRemove (int x, Heap F) { + int i = F->ind[x]; + + F->ind[x] = NONE; + + F->n --; + + if (i == F->n) + return; + + F->val[i] = F->val[F->n]; + F->ind[F->val[i]] = i; +} + +void heapRemoveAll(Heap heap) { + for (int i = 0; i < heap->n; i ++) + heap->ind[heap->val[i]] = NONE; + heap->n = 0; +} + + +/* Decrease the value of x to w. */ +void heapBubbleUp (int i, Heap F) { + while ( (i > 0) && (F->lt(F->val[i], F->val[PERE(i)])) ) { // (weight[F->val[PERE(i)]] > w) ) { + heapSwap(PERE(i), i, F); + i = PERE(i); + } +} + + +/* Decrease the value of x to w. */ +void heapDecreaseKey (int x, Heap F) { + heapBubbleUp(F->ind[x], F); +} + + + +void heapInsert (int x, Heap F) { + F->val[F->n] = x; + F->ind[x] = F->n; + F->n ++; + heapBubbleUp(F->n-1, F); +} + + +void heapJustAdd (int x, Heap F) { + F->val[F->n] = x; + F->ind[x] = F->n; + F->n ++; +} + + + + +void heapVerif(Heap F, int *values) { + for (int i = 0; i < F->n; i ++) { + if ((FG(i) < F->n) && (F->lt(F->val[FG(i)], F->val[i]))) { //(w[F->val[i]] > w[F->val[FG(i)]])) { + printf("heap mal configured %d/%d :: \n", F->val[i], F->val[FG(i)]); + heapPrint(F, values, FG(i)+1, 1585189); + exit(0); + } + if ((FD(i) < F->n) && (F->lt(F->val[FD(i)], F->val[i]))) { //(w[F->val[i]] > w[F->val[FD(i)]])) { + printf("heap mal configured %d/%d :: \n", F->val[i], F->val[FD(i)]); + heapPrint(F, values, FD(i)+1, 1585189); + exit(0); + } + } +} + + +void heapPrint(Heap F, int *weight, int n, int infini) { + for (int i = 0; i < n; i ++) + if (weight[F->val[i]] >= infini) + printf("- "); + else + printf("%d ", weight[F->val[i]]); + printf("\n"); +} + +void heapPrintMax(Heap F, int *weight) { + int max = weight[F->val[0]]; + printf("heap max=%d ", max); + for (int i = 0; i < F->n; i ++) + if (weight[F->val[i]] == max) + printf("%d ", F->val[i]); + printf("\n"); +} + + + +int isInHeap(int x, Heap F) { + return (F->ind[x] != NONE); +} + + + +// +// minheap :: Heap used to partition the elements that have the value min from the others (for a given evaluation val[]) +// + +// unused +int minheapCalculMin(Heap F, int val[]) { + int min = val[F->val[0]]; + for (int i = 1; i < F->n; i ++) + if (val[F->val[i]] < min) min = val[F->val[i]]; + return min; +} + +// Recalculate min after all min have been removed, bound is the minimal value of the min +void minheapUpdateMin(Heap F, int bound, int val[]) { + int newmin = val[F->val[0]]; + if (newmin > bound) { + for (int i = 1; i < F->n; i++) + if (val[F->val[i]] < newmin) { + newmin = val[F->val[i]]; + if (newmin == bound) break; + } + } + F->min = newmin; +} + +void minheapSearchAndPackMins(Heap F, int val[]) { + F->min = val[F->val[0]]; + for (int i = 1; i < F->n; i ++) + if (val[F->val[i]] < F->min) F->min = val[F->val[i]]; + F->nbmin = 0; + for (int i = 0; i < F->n; i ++) + if (val[F->val[i]] == F->min) { + heapSwap(F->nbmin, i, F); + F->nbmin ++; + } +} + + + +void minheapPackMins(Heap F, int val[]) { + // Suppose that F->min is up to date + F->nbmin = 0; + for (int i = 0; i < F->n; i ++) + if (val[F->val[i]] == F->min) { + heapSwap(F->nbmin, i, F); + F->nbmin ++; + } +} + + +void minheapRemove(int x, Heap F, int val[]) { + int i = F->ind[x]; + int *p = F->val + i; + + F->ind[x] = NONE; + + F->n --; + //if (F->n == 0) { F->nbmin = 0; return; } + + if (val[x] > F->min) { + // x is not a min + if (i < F->n) { + *p = F->val[F->n]; + F->ind[*p] = i; + } + return; + } + + // x is a min + + F->nbmin --; + + // x was the last of the list + if (i == F->n) return; + + // x was the uniq element with min value + if (F->nbmin == 0) { + // copy last element at position i and rebuild mins + int last = F->val[F->n]; + *p = last; + F->ind[last] = i; + minheapUpdateMin(F, F->min+1, val); + minheapPackMins(F, val); + return; + } + + // Copy last min at the position i + if (i != F->nbmin) { + *p = F->val[F->nbmin]; + F->ind[*p] = i; + } + // Copy last non min element after the mins if necessary + if (F->n > F->nbmin) { + F->val[F->nbmin] = F->val[F->n]; + F->ind[F->val[F->nbmin]] = F->nbmin; + } +} + + +void minheapJustRemove(int x, Heap F, int val[]) { + int i = F->ind[x]; + int *p = F->val + i; + + F->ind[x] = NONE; + + F->n --; + + if (val[x] > F->min) { + // x is not a min + if (i < F->n) { + *p = F->val[F->n]; + F->ind[*p] = i; + } + return; + } + + // x is a min + + F->nbmin --; + + // x was the last of the list + if (i == F->n) return; + + // Copy last min at the position i + if (i != F->nbmin) { + *p = F->val[F->nbmin]; + F->ind[*p] = i; + } + // Copy last non min element after the mins if necessary + if (F->n > F->nbmin) { + F->val[F->nbmin] = F->val[F->n]; + F->ind[F->val[F->nbmin]] = F->nbmin; + } +} + + +// The value val[x] of x has decreased strictly +void minheapDecreaseValue(int x, Heap F, int val[]) { + + if (val[x] < F->min) { + F->min = val[x]; + F->nbmin = 1; + if (F->ind[x] > 0) heapSwap(0, F->ind[x], F); + return; + } + if (val[x] == F->min) { + if (F->ind[x] >= F->nbmin) heapSwap(F->nbmin, F->ind[x], F); + F->nbmin ++; + } +} + + + + + + + + + + + + + + + diff --git a/pace-2020/heap.h b/pace-2020/heap.h new file mode 100644 index 0000000000000000000000000000000000000000..4371d7be6431c309c5ee7584eafe40ae398e2dd5 --- /dev/null +++ b/pace-2020/heap.h @@ -0,0 +1,72 @@ + +#ifndef _H_tas +#define _H_tas + +/* + * tas.h + * packing-satmod + * + * Created by St�phane on 11/11/14. + * Copyright 2014 __MyCompanyName__. All rights reserved. + * + */ + + +typedef struct heap +{ + int size; /* Allocated size. */ + int n; /* Number of values in the heap. */ + int *val; + int *ind; /* Indexes of the values in val[]. */ + int (*lt)(int, int); + int min; // for a certain evaluation, the minimal value for the elements of the heap + int nbmin; // the number of elements in the heap that have for evaluation the value min +} + * Heap; + + + +#define FG(i) ((i)*2+1) +#define FD(i) ((i)*2+2) +#define PERE(i) (((i)-1)/2) + + + +Heap allocHeap (int size, int (*lt)(int, int)); +void freeHeap(Heap F); +void heapSetCompare(Heap F, int (*lt)(int, int)); +void resetHeap(Heap F); +void heapBubbleDown(Heap F, int i); +void makeHeap(Heap F); +int heapExtractMin (Heap F); +void heapBubbleUp (int i, Heap F); +void heapRemove (int x, Heap F); +void heapJustRemove (int x, Heap F); +void heapRemoveAll(Heap heap); +void heapDecreaseKey (int x, Heap F); +void heapInsert (int x, Heap F); +void heapJustAdd (int x, Heap F); +void heapSwap (int i, int j, Heap F); +void heapPrint(Heap F, int *weight, int n, int infini); +void heapVerif(Heap F, int *w); +void heapPrintMax(Heap F, int *weight); +int isInHeap(int x, Heap F); + +// minheaps +void minheapUpdateMin(Heap F, int bound, int val[]); +void minheapSearchAndPackMins(Heap F, int val[]); +void minheapPackMins(Heap F, int val[]); +void minheapRemove(int x, Heap F, int val[]); +void minheapJustRemove(int x, Heap F, int val[]); +void minheapDecreaseValue(int x, Heap F, int val[]); + + +#endif + + + + + + + + diff --git a/pace-2020/lire.c b/pace-2020/lire.c new file mode 100644 index 0000000000000000000000000000000000000000..01631ae90fcb4ee735ff86b9b77f8e154719333f --- /dev/null +++ b/pace-2020/lire.c @@ -0,0 +1,74 @@ +/* + * lire.c + * graphes + * + * Created by Stéphane on 12/02/18. + * Copyright 2018 __MyCompanyName__. All rights reserved. + * + */ + +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "graph.h" +#include "lists.h" +#include "lire.h" +#include "main.h" + + +/* + SECTION Graph + Nodes 6405 + Edges 10454 + E 1 2 5 + ... +*/ + + +int countGraphe(FILE *f) +{ + int nb_sommets, nb_aretes; + + fscanf(f, "%*s%*s%d%d", &nb_sommets, &nb_aretes); + + return nb_sommets; +} + + +Graph lireGraphe(FILE *f) +{ + int s1, s2; + int nb_sommets, nb_aretes, nba; + LIST *adj; + + //fscanf(f, "%",&s1, &s2) + fscanf(f, "%*s%*s%d%d", &nb_sommets, &nb_aretes); + + int *nadj = calloc(nb_sommets, sizeof(int)); + + adj = calloc(nb_sommets, sizeof(LIST)); + assert(adj != NULL); + + nba = nb_aretes; + while (1) { + if (fscanf(f, "%d%d",&s1, &s2) != 2) + break; + s1 --; s2 --; + adj[s2] = newLNode( s1, adj[s2], 1); + adj[s1] = newLNode( s2, adj[s1], 1); + + nadj[s1] ++; + nadj[s2] ++; + + nba --; + } + + //assert(nba == 0); + + Graph g = newGraph(nb_sommets, nb_aretes, adj, nadj); + + return g; +} + diff --git a/pace-2020/lire.h b/pace-2020/lire.h new file mode 100644 index 0000000000000000000000000000000000000000..f5f4d7f808d2ad3c1e9aba180bbe56a4bd7a7be9 --- /dev/null +++ b/pace-2020/lire.h @@ -0,0 +1,35 @@ + +#ifndef _H_lire +#define _H_lire + +/* + * lire.h + * graphes + * + * Created by St�phane on 12/02/18. + * Copyright 2018 __MyCompanyName__. All rights reserved. + * + */ + +#include <stdio.h> + +#include "graph.h" + + +#define STANDARD 0 +#define STEINER_TREES_PACE_2018 1 + +int countGraphe(FILE *f); + +Graph lireGraphe(FILE *f); + + + + + + + +#endif + + + diff --git a/pace-2020/lists.c b/pace-2020/lists.c new file mode 100644 index 0000000000000000000000000000000000000000..6edf207d88677a72018cc1ae0c1d7d1d728fc598 --- /dev/null +++ b/pace-2020/lists.c @@ -0,0 +1,33 @@ +/* + * lists.c + * graphes + * + * Created by St�phane on 12/02/18. + * Copyright 2018 __MyCompanyName__. All rights reserved. + * + */ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> + + +#include "lists.h" +#include "utils.h" + + +// Lists + +LIST newLNode(int v, LIST s, int w) { + LIST sommet = (LIST) malloc(sizeof(struct maillon)); + assert(sommet != NULL); + sommet->val = v; + sommet->suiv = s; + sommet->w = w; + return sommet; +} + + + + + diff --git a/pace-2020/lists.h b/pace-2020/lists.h new file mode 100644 index 0000000000000000000000000000000000000000..7163efa782e0f51f6d69baa99d2cee9baa0998d1 --- /dev/null +++ b/pace-2020/lists.h @@ -0,0 +1,29 @@ +#ifndef _H_lists +#define _H_lists + +/* + * lists.h + * graphes + * + * Created by St�phane on 12/02/18. + * Copyright 2018 __MyCompanyName__. All rights reserved. + * + */ + + +typedef struct maillon * LIST; + +struct maillon { + int val; + int w; + LIST suiv; +}; + + + +LIST newLNode(int v, LIST s, int w); + + +#endif + + diff --git a/pace-2020/main.c b/pace-2020/main.c new file mode 100644 index 0000000000000000000000000000000000000000..9802f621b043db831393c0a4d148686bb2dab42f --- /dev/null +++ b/pace-2020/main.c @@ -0,0 +1,320 @@ + +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include <ctype.h> + +#ifndef __USE_POSIX +#define __USE_POSIX +#endif + +#include <signal.h> +#include <time.h> + + +#include "decompose.h" +#include "graph.h" +#include "lire.h" +#include "lists.h" +#include "main.h" +#include "separator.h" +#include "utils.h" + + +volatile sig_atomic_t stopSearch = 0; + + +char file_name[555], *last_name; +FILE *fileSolution = NULL; + +#ifdef PACE_2020 +int pace_2020 = 1; +#else +int pace_2020 = 0; +#endif + + +int nb_runs = 1000000; + +int algo = SEPARE_AND_EXPLORE ; //SEPARE_AND_EXPLORE; GREEDY_ALGORITHM + + +int noSwapsInFirstRuns = 0; // Do not improve for the first explorations +int timeWithNoSwaps = 50; // proportion of the total time with no improvement + +int sizeSwitchToGreedy = 0; // switch to greedy algorithm when nb vertices is les than this. +int preliminaryGreedyDecomposition = 0; // perform a preliminary greedy search, +int maxSizePrelimGreedy = 350000; //350000; for instance heur_187 +int maxDepthGreedy = 777; //25000; + + +int depthThreshold = 1; // threshold above which the current run is abandoned, compared with the best first height + + +int perForceChoiceNotInC = NONE; // Initialized before each separation if modeEvalAtRandom is true +int perChooseInCAtRandom = 1; // Choice in C at random + +int nbRunsSeparation = 30; // 1 or 5 +int maxTimeSeparation = 30; // test optilion 27/05: 80, 28/05: 60 +int nbFlushes = 101; // default is 100, +int ratioMin = 5; // min=5 max=55 +int ratioMax = 55; // too small ratioMax stops the flush (>50) + + +int modeEvalSeparator = EVAL_CARD; // EVAL_SQRT_CARD EVAL_TREE_HEIGHT_COMPLETE_GRAPH EVAL_MINIMIZE_C EVAL_CARD EVAL_MIN_A_B +double coeffHeightNbEdges = 2.0; // coefficient used to estimate the height for a given number of edges. Ponderates the evaluation against the cardinal of C. +int modeEvalAtRandom = 0; + + + +int searchSwapsInCriticalBranch = 1; // improve version april 2020 +int pullUpIndependentSubtrees = 1; // before swaps, pull up independent critical subtrees +int maxMakeSwapsRestarts = 10; // the number of restarts of the improve process Without height decrease + + + + +int printStats = 0; + +int compressTree = 0; // not used + +int trace = 0; + +clock_t startTime; + +int printSolution = 0; +int printResult = 1; +int time_limit = 30; + + + + +void term(int signum) { + stopSearch = 1; +} + + + +/*********************************************** + * Main * + **********************************************/ + +int main (int nargs, char ** args) +{ + Graph g; + FILE *f = stdin; + + if (1) { + struct sigaction action; + memset(&action, 0, sizeof(struct sigaction)); + action.sa_handler = term; + sigaction(SIGTERM, &action, NULL); +// signal(SIGTERM, sig_handler); +// signal(SIGINT, sig_handler); + } + + srand(time(NULL)); + + + if (pace_2020) { + printSolution = 1; + printResult = 0; + time_limit = 1803; + preliminaryGreedyDecomposition = 1; + goto START_SOLVE; + } + + + for (int i = 1; i < nargs; i ++) { + + if (strcmp(args[i], "-file") == 0) { + i ++; + if (i == nargs) + goto USAGE; + strcpy(file_name, args[i]); + f = fopen(file_name, "r"); + if (f == NULL) { + printf("unable to open file %s\n", file_name); + goto USAGE; + } + } + + else if (strcmp(args[i], "-save_solution") == 0) { + i ++; + if (i == nargs) + goto USAGE; + fileSolution = fopen(args[i], "w"); + if (fileSolution == NULL) { + printf("Output abandoned :: unable to open file %s\n", args[i]); + goto USAGE; + } + printSolution = 1; + } + + else if (strcmp(args[i], "-auto") == 0) { + noSwapsInFirstRuns = 1; + nb_runs = 10000; + } + + else if (strcmp(args[i], "-runs") == 0) { + i ++; + if (i == nargs) + goto USAGE; + nb_runs = atoi(args[i]); + } + + else if (strcmp(args[i], "-s") == 0) { + i ++; + if (i == nargs) + goto USAGE; + srand(atoi(args[i])); + } + + else if (strcmp(args[i], "-time") == 0) { + i ++; + if (i == nargs) + goto USAGE; + time_limit = atoi(args[i]); + } + + else if (strcmp(args[i], "-trace") == 0) { + trace = 1; + } + + else if (strcmp(args[i], "-no_solution") == 0) { + printSolution = 0; + } + + else if (strcmp(args[i], "-no_improve") == 0) { + searchSwapsInCriticalBranch = 0; + pullUpIndependentSubtrees = 0; + } + + else if (strcmp(args[i], "-no_pullup") == 0) { + pullUpIndependentSubtrees = 0; + } + + else if (strcmp(args[i], "-no_swaps") == 0) { + searchSwapsInCriticalBranch = 0; + } + + else if (strcmp(args[i], "-sep_runs") == 0) { + i ++; + if (i == nargs) + goto USAGE; + nbRunsSeparation = atoi(args[i]); + } + + else if (strcmp(args[i], "-max_time_sep") == 0) { + i ++; + if (i == nargs) + goto USAGE; + maxTimeSeparation = atoi(args[i]); + } + + else if (strcmp(args[i], "-per_choice_AB") == 0) { + i ++; + if (i == nargs) + goto USAGE; + perForceChoiceNotInC = atoi(args[i]); + } + + else if (strcmp(args[i], "-per_chrand_C") == 0) { + i ++; + if (i == nargs) + goto USAGE; + perChooseInCAtRandom = atoi(args[i]); + } + + else if (strcmp(args[i], "-flushes") == 0) { + i ++; + if (i == nargs) + goto USAGE; + nbFlushes = atoi(args[i]); + } + + else if (strcmp(args[i], "-ratios") == 0) { + i ++; + if (i == nargs) + goto USAGE; + ratioMin = atoi(args[i]); + i ++; + if (i == nargs) + goto USAGE; + ratioMax = atoi(args[i]); + } + + else if (strcmp(args[i], "-threshold") == 0) { + i ++; + if (i == nargs) + goto USAGE; + depthThreshold = atoi(args[i]); + } + + else if (strcmp(args[i], "-eval") == 0) { + i ++; + if (i == nargs) + goto USAGE; + modeEvalSeparator = atoi(args[i]); + modeEvalAtRandom = 0; + } + + else if (strcmp(args[i], "-tree_height_eval") == 0) { + i ++; + if (i == nargs) + goto USAGE; + modeEvalSeparator = EVAL_TREE_HEIGHT_COMPLETE_GRAPH; + modeEvalAtRandom = 0; + coeffHeightNbEdges = (double) (atoi(args[i])) / 100; + } + + else if (strcmp(args[i], "-greedy") == 0) { + algo = GREEDY_ALGORITHM; + } + + else if (strcmp(args[i], "-separe") == 0) { + algo = SEPARE_AND_EXPLORE; + } + + + else + goto USAGE; + + } + + if (f != stdin) { + char *s = file_name; + last_name = s; + while (*s != '\0') { + if (*s == '/') + last_name = s+1; + s ++; + } + } + + +START_SOLVE: + + startTime = clock(); + + g = lireGraphe(f); + + if (trace) printf("n=%d m=%d\n", g->n, g->m); + + + testDecompose(g, nb_runs, algo); + + return 0; + + USAGE: + printf("Usage :: ./treedepth [-file <file name>] [-greedy] [-separe] [-runs <nb runs>] [-s <number>] [-trace] \\" + "[-save_solution <file name>] [-no_solution] [-no_improve] [-no_pullup] [-no_swaps]\\" + "[-sep_runs <nb runs>] [-max_time_sep <duration>] [-flushes <nb flushes>] \\" + "[-per_choice_AB <per>] [-per_chrand_C <per>] \\" + "[-ratios <min> <max>] [-threshold <per>] [-eval <mode>] \\" + "[-greedy] [-separe]\n"); + return 0; +} diff --git a/pace-2020/main.h b/pace-2020/main.h new file mode 100644 index 0000000000000000000000000000000000000000..aad01da1360fc9df7b89fea32ec7eae8508e94a2 --- /dev/null +++ b/pace-2020/main.h @@ -0,0 +1,61 @@ +// +// Created by Stephane on 18/03/2020. +// + +#ifndef SGA_MAIN_H +#define SGA_MAIN_H + +#include <signal.h> +#include <stdio.h> +#include <time.h> + + +extern volatile sig_atomic_t stopSearch; + +extern int pace_2020; + +extern int noSwapsInFirstRuns; +extern int timeWithNoSwaps; + +extern int algo; +extern int sizeSwitchToGreedy; + +extern int time_limit; +extern clock_t startTime; + +extern FILE *fileSolution; +extern int printSolution; +extern int printResult; + + +extern int nbRunsSeparation; +extern int maxTimeSeparation; +extern int nbFlushes; + +extern int perForceChoiceNotInC; +extern int perChooseInCAtRandom; + +extern int ratioMax; +extern int ratioMin; + +extern int modeEvalSeparator; +extern double coeffHeightNbEdges; +extern int modeEvalAtRandom; + +extern int searchSwapsInCriticalBranch; +extern int pullUpIndependentSubtrees; +extern int maxMakeSwapsRestarts; + +extern int preliminaryGreedyDecomposition; +extern int maxSizePrelimGreedy; +extern int maxDepthGreedy; + +extern int depthThreshold; + +extern int printStats; + +extern int compressTree; + + + +#endif //SGA_MAIN_H diff --git a/pace-2020/separator.c b/pace-2020/separator.c new file mode 100644 index 0000000000000000000000000000000000000000..77030e2a45f22e8f11c32ac4b2c4e00c6ea40b94 --- /dev/null +++ b/pace-2020/separator.c @@ -0,0 +1,1329 @@ +// +// Created by Stephane on 10/03/2020. +// + +#include <assert.h> +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +#include "components.h" +#include "graph.h" +#include "main.h" +#include "separator.h" +#include "utils.h" +#include "heap.h" + + + +// Options separation +int chooseSeedNeighborMaxDegree = 0; + +int separatorJustMemorizeReceptorSize = 1; +int separatorJustMemoSizeMin = 10000; + +int verifyTheSeparator = 0; + + +int useMinPartitions = 2; // 0: maintain heap, 1-2: just put min elements at the beginning. +// 1: maintain mins 2: calculate mins only when necessary + + + +// +// Datas structures +// + +int *nbNeighborsInB; +int *nbNeighborsInA; +int nbEdgesInA, nbEdgesInB; + +int *dateABDisconnected; // Current date for AB Diconnected vertices of C (date=number of current separe call) +int *nbNeighborsABDisconnected; // For AB Disconnected vertices : Number of neighbors in C which are AB disconnected + +int *priorities; + +int *verticesToThrow; + +// Copies to memorize nb neighbors and not recalculate at each separation run +int * nbNInDestCopy; // To build the best separator +int * nbNInABCopy; // To memorize the number of neighbors in A an B of C vertices for best separator +int * nbNeighborsInS; +int nbEACopy, nbEdgesInS; +int minDegree, nbMinD; // minimal degree of vertices of S, initialised in initializeNbNeighbors() +int maxDegree, nbMaxD; + + +int nbCallsSepare = 0; + +int nbCallsSearchSeparator = 0; + +Separator sep = NULL; +Separator bestSep = NULL; +double bestEval; +int bestIsUninitialized; + + +int sizeMin; +int sizeMax; + + +// Connected components +int *component; + + +// +// Warning: the preliminary call to initializeNbNeighbors() place first in the lists of neighbors +// those that are in the current set S[]. It is then unnecessary to verify each time that the vertex +// belongs to the current set. + +#ifdef STATS_SEPARATION +clock_t *timesSep = NULL; +int *nbSearches; +int *sumSizes; +#endif + +int searchSeparator(int *S, int n, SET V, Graph g, Separator theSeparator, int nTries, int nFlushes, int depth) { + +#ifdef STATS_SEPARATION + if (timesSep == NULL) { + timesSep = calloc(10000, sizeof(clock_t)); + nbSearches = calloc(10000, sizeof(int)); + sumSizes = calloc(10000, sizeof(int)); + } +#endif + + if (sep == NULL) sep = newSeparator(g->n, g); + if (bestSep == NULL) bestSep = newSeparator(g->n, g); + + nbCallsSearchSeparator ++; + + theSeparator->C->n = g->n+1; + bestEval = -1.0; + bestIsUninitialized = 1; + + sizeMin = n * ratioMin / 100; + if (sizeMin == 0) sizeMin = 1; + + sizeMax = n * ratioMax / 100; + + //saveNbNeighbors(S, n); + + if (modeEvalAtRandom) { + if (rand()%2 == 1) modeEvalSeparator = EVAL_CARD; + else modeEvalSeparator = rand() % 4; + } + + if (0) { + // test for heur_105: much better when equal to 0 + perForceChoiceNotInC = 0; + perChooseInCAtRandom = 0; + } + + clock_t start = clock(); + + for (int i = 0; i < nTries; i ++) { + + randomizePriorities(S, n, g); + + initSeparator(V, S, n, g, sep); + + separe(S, n, V, g, sep, nFlushes, modeEvalSeparator); + + if ((stopSearch) || ((clock()-start)/CLOCKS_PER_SEC > maxTimeSeparation/(depth+1))) break; + } + + if (0 && depth < 3) printf("depth=%d tSep=%.1fs total=%.1fs\n", depth, + (float) (clock()-start)/CLOCKS_PER_SEC, + (float) (clock()-startTime)/CLOCKS_PER_SEC); + +#ifdef STATS_SEPARATION + timesSep[depth] += clock()-start; + nbSearches[depth] ++; + sumSizes[depth] += n; +#endif + + if (bestIsUninitialized) + exit(0); + + if (bestEval > 0) + copySeparator(bestSep, theSeparator); + else + copySeparator(sep, theSeparator); + + //if (verifyTheSeparator && (! verifySeparator(S, n, theSeparator))) exit(0); + + return 1; +} + + + + +int chooseFirstVertex(int *S, int n, Graph g) { + if (1) { + // Test choose as first vertex one with small degree with a neighbor with max degree + int t = rand() % nbMaxD; + for (int *p = S;; p++) + if (nbNeighborsInS[*p] == maxDegree) + if (t-- == 0) { + int *q = g->lists[*p]; + int vmin = *q; + int min = nbNeighborsInS[*q]; + q ++; + while (q < g->lists[*p]+nbNeighborsInS[*p]) { + if (nbNeighborsInS[*q] < min) { + min = nbNeighborsInS[*q]; + vmin = *q; + } + q ++; + } + return vmin; + } + return NONE; + } + else { + int t = rand() % nbMinD; + for (int *p = S;; p++) + if (nbNeighborsInS[*p] == minDegree) + if (t-- == 0) return *p; + return NONE; + } + + if (n <= 10) return S[rand()%n]; + int dmin, vmin; + vmin = S[rand()%n]; + dmin = nbNeighborsInS[vmin]; + for (int i = 0; i < 5; i ++) { + int v = S[rand()%n]; + if (nbNeighborsInS[v] < dmin) { dmin = nbNeighborsInS[v]; vmin = v; } + } + return vmin; +} + + + + +int separe(int *S, int n, SET V, Graph g, Separator s, int nbFlushs, int mode) { + + int firstVertex; + + nbCallsSepare ++; + + Heap A = s->A; + Heap B = s->B; + Heap C = s->C; + + for (int i = 0; i < nbFlushs; i ++) { + + if (useMinPartitions) { + minheapUpdateMin(B, -1, nbNeighborsInB); + minheapPackMins(B, nbNeighborsInB); + if (chooseSeedNeighborMaxDegree) + firstVertex = (i > 0) ? NONE : chooseFirstVertex(S, n, g); + else + firstVertex = (i > 0) ? NONE : B->val[rand()%B->nbmin]; + } + else { + makeHeap(B); + firstVertex = (i > 0) ? NONE : chooseFirstVertex(S, n, g); + } + + heapSetCompare(C, compareCVerticesFlushBtoA); + makeHeap(C); + + flushBtoA(A, B, C, V, S, n, mode, firstVertex, g); + + if (stopSearch) break; + + if (++ i == nbFlushs) break; + + if (useMinPartitions) { + minheapUpdateMin(A, -1, nbNeighborsInA); + minheapPackMins(A, nbNeighborsInA); + } + else + makeHeap(A); + + heapSetCompare(C, compareCVerticesFlushAtoB); + makeHeap(C); + + flushAtoB(A, B, C, V, S, n, mode, g); + + if (stopSearch) break; + } + + copySeparator(bestSep, s); + + //if ( ! verifySeparator(S, n, s)) exit(0); + + return 1; +} + + +double evalSep(int nA, int nB, int nC, int mA, int mB, int mode, int direction) { + + // Should consider here the particular cases (B->n=0, C->n=0,...) + + int min = (nA > nB) ? nB : nA; + int max = (nA > nB) ? nA : nB; + int delta = max-min; + int maxE = (mA > mB) ? mA : mB; + int minE = (mA > mB) ? mB : mA; + + if ((nA == 0) || (nB == 0)) return 0; + + + if (mode == EVAL_ESSAI) { + // minimize C size while the numbers of constraints in A and B are small and closed + return (1.0 / (1+nC) / (1+nC) / sqrt(1.0+maxE-minE)); + } + + if (mode == EVAL_TREE_HEIGHT_COMPLETE_GRAPH) + // approx tree height + return (1.0 / (nC + sqrt((double) (coeffHeightNbEdges * maxE )))); + + + if ((mode == EVAL_0) || (mode == EVAL_SQRT_CARD)) { + double ra = sqrt((double) (nA)); + double rb = sqrt((double) (nB)); + double rab = sqrt((double) (nA + nB)); + double deltaSqrt = (ra > rb) ? (ra - rb) : (rb - ra); + if (mode == EVAL_0) return ((rab - deltaSqrt)*(rab - deltaSqrt) / (1+nC) / (1+nC)); + if (nC > 0) return ((rab - deltaSqrt) / nC / nC); + return ((rab - deltaSqrt) / (1+nC)); + } + + if (mode == EVAL_CARD) return ((double) (min) / (nC+1)); // modified 1/05 + + if (mode == EVAL_LEVEL_DENSITY) { + // evaluate the cost to place vertices of C and the smallest among A and B + // evaluating the number of vertices of these sets per level + if (nA < nB) return ((double) (nA+nC) / (nC + sqrt(sqrt((double) 2.0*mB)))); + else return ((double) (nB+nC) / (nC + sqrt(sqrt((double) 2.0*mA))) ); + } + + if (mode == EVAL_MINIMIZE_C) return ((double) 1 / (1+nC)); + + if (mode == EVAL_MAX_SOURCE_DENSITY) { + if (direction == FLUSH_B_A) { // try to isolate a strongly connected kernel in B + if (nB == 0) return 0; + if (nB <= sizeMin) return 1.0 / (nC + 1) / (nC + 1); + return 2.0 * mB / (nB - 1) / (nB - 1) / (nC + 1) / (nC + 1); + } + // direction = FLUSH_A_B + if (nA == 0) return 0; + if (nA == 1) return 1.0 / (nC + 1); + return 2.0 * mA / (nA - 1) / (nA - 1) / (nC + 1) / (nC + 1); + } + + // few vertices + if (nA+nB+nC <= 7) return ((nC > 0) ? 1.0 / (1+delta) / (1+delta) / nC : 1.0 / (1+delta)); + + if (mode == EVAL_MIN_A_B) return min; + + if (mode == EVAL_MAX_C_DENSITY) return ((nC > 0) ? (double) (nbEdgesInS-mA-mB)/nC : nbEdgesInS); + + if (mode == EVAL_MAX_CDENS_MIN_AB_SIZES) return ((nC > 0) ? (double) (nbEdgesInS-mA-mB)/nC/(delta+1) : nbEdgesInS); + + if (mode == EVAL_MAX_AB_SIZES_MIN_AB_EDGES) + return ((double) min/(1 + ((mA > mB) ? mA : mB))); + + return 0; +} + + + +// +// Choose and remove a vertex from A, B or C (a vertex with few neighbors in B or A) +// + +int chooseEltInC(Heap C) { + if (rand() % 100 < perChooseInCAtRandom) { + int e = C->val[rand() % (C->n)]; + return e; + } + return C->val[0]; // the vertex that has the fewer neighbors in the from set +} + + + +#define CHOICE_AB_MIN_AB 0 +#define CHOICE_AB_MIN_AB_MAX_C 1 + +int choiceModeInAandB = CHOICE_AB_MIN_AB_MAX_C; + +int chooseEltInB(Heap B) { + + if (choiceModeInAandB == CHOICE_AB_MIN_AB) { + if (useMinPartitions) return B->val[rand()%B->nbmin]; + return B->val[0]; + } + + if (choiceModeInAandB == CHOICE_AB_MIN_AB_MAX_C) { + // Search a vertex in B with minimal number of neighbors in B and max in C. + int best = B->val[0]; + int nbBMin = nbNeighborsInB[B->val[0]]; + int nbCMax = nbNeighborsInS[B->val[0]] - nbNeighborsInB[B->val[0]]; + int i = 1; + while (i < B->n) { + if (nbNeighborsInB[B->val[i]] > nbBMin) break; + if (nbNeighborsInS[B->val[i]] - nbNeighborsInB[B->val[i]] > nbCMax) { + best = B->val[i]; + nbCMax = nbNeighborsInS[B->val[i]] - nbNeighborsInB[B->val[i]]; + } + i++; + } + return best; + } + return B->val[0]; +} + + + +int chooseEltInA(Heap A) { + + if (choiceModeInAandB == CHOICE_AB_MIN_AB) { + if (useMinPartitions) return A->val[rand()%A->nbmin]; + return A->val[0]; + } + + // (choiceModeInAandB == CHOICE_AB_MIN_AB_MAX_C) + int i = 1, best = A->val[0]; + int nbAMin = nbNeighborsInA[A->val[0]]; + int nbCMax = nbNeighborsInS[A->val[0]] - nbNeighborsInA[A->val[0]]; + while (i < A->n) { + if (nbNeighborsInA[A->val[i]] > nbAMin) break; + if (nbNeighborsInS[A->val[i]] - nbNeighborsInA[A->val[i]] > nbCMax) { + best = A->val[i]; + nbCMax = nbNeighborsInS[A->val[i]] - nbNeighborsInA[A->val[i]]; + } + i++; + } + return best; + + return A->val[0]; +} + + + +int testSourceConnected = 0; +int thresholdConComponents = 13; + +void flushBtoA(Heap A, Heap B, Heap C, SET V, int S[], int n, int mode, int seed, Graph g) { + int e = NONE; + int bestASize = NONE; + + if (seed != NONE) { + e = seed; + goto REMOVE_FROM_B; + } + + while (1) { + int sizeB = B->n; + + if (stopSearch) break; + + if ((C->n > 0) && ((B->n == 0) || (rand()%100 >= perForceChoiceNotInC))) { // Should stop if C is empty ? + e = chooseEltInC(C); + heapRemove(e, C); + nbEdgesInA += nbNeighborsInA[e]; + } + else { + if (e == NONE) e = B->val[0]; // initial case if no seed is given + else { + if ((useMinPartitions == 2) && (B->nbmin <= 0)) minheapSearchAndPackMins(B, nbNeighborsInB); + e = chooseEltInB(B); + } + + REMOVE_FROM_B: + if (useMinPartitions == 1) minheapRemove(e, B, nbNeighborsInB); + else if (useMinPartitions == 2) minheapJustRemove(e, B, nbNeighborsInB); + else heapRemove(e, B); + nbEdgesInB = nbEdgesInB-nbNeighborsInB[e]; + decreaseNbNeighborsInB(e, B, C, V, S, n, g); + } + + // insert e in A + heapJustAdd(e, A); + increaseNbNeighborsInA(e, C, V, S, n, g); + + // move e neighbors which are in B to C + removeNeighborsFromB(e, A, B, C, V, S, n, g); + + if (A->n >= sizeMax) break; + + if (B->n < sizeMin) break; + + if (A->n >= sizeMin) { + int nB = B->n, nEB = nbEdgesInB; + + if (testSourceConnected && (B->n > thresholdConComponents) && (B->n < sizeB)) { + int nbComp = searchConnectedComponentsInHeap(B, nbNeighborsInS, g); + if (nbComp > 1) { + int imax = indexMaxInList(compSizes, nbComp); + nB = compSizes[imax]; + nEB = compNbEdges[imax]; + } + } + + double e = evalSep(A->n, nB, C->n, nbEdgesInA, nEB, mode, FLUSH_B_A); + + if ((bestIsUninitialized) || (e > bestEval)) { + // There can be vertices in C with no neighbor in B + if (1) pourCintoA(A, nbNeighborsInB, nbNeighborsInA, &nbEdgesInA, C, g, 1); + bestIsUninitialized = 0; + bestEval = e; + if (separatorJustMemorizeReceptorSize && (g->n >= separatorJustMemoSizeMin)) + bestASize = A->n; + else + copySeparator(sep, bestSep); + } + } + } + if ((bestIsUninitialized) && (A->n < n)) { + if (1) pourCintoA(A, nbNeighborsInB, nbNeighborsInA, &nbEdgesInA, C, g, 1); + bestIsUninitialized = 0; + bestEval = e; + copySeparator(sep, bestSep); + return; + } + if ((separatorJustMemorizeReceptorSize) && (bestASize != NONE)) { + copySeparator(sep, bestSep); + builtBestSeparator(bestSep->A, bestSep->B, bestSep->C, nbNeighborsInA, nbNeighborsInB, bestASize, g); + } +} + + + + +void flushAtoB(Heap A, Heap B, Heap C, SET V, int S[], int n, int mode, Graph g) { + int e = NONE; + int bestBSize = NONE; + + while (1) { + + int sizeA = A->n; + + if (stopSearch) break; + + if ((C->n > 0) && ((A->n == 0) || (rand()%100 >= perForceChoiceNotInC)) ) { + e = chooseEltInC(C); + heapRemove(e, C); + nbEdgesInB += nbNeighborsInB[e]; + } + else { + if (e == NONE) e = A->val[0]; + else { + if ((useMinPartitions == 2) && (A->nbmin <= 0)) minheapSearchAndPackMins(A, nbNeighborsInA); + e = chooseEltInA(A); + } + if (useMinPartitions == 1) minheapRemove(e, A, nbNeighborsInA); + else if (useMinPartitions == 2) minheapJustRemove(e, A, nbNeighborsInA); + else heapRemove(e, A); + nbEdgesInA -= nbNeighborsInA[e]; + decreaseNbNeighborsInA(e, A, C, V, S, n, g); + } + + // insert e in B + heapJustAdd(e, B); + increaseNbNeighborsInB(e, C, V, S, n, g); + + // move e neighbors which are in A to C + removeNeighborsFromA(e, A, B, C, V, S, n, g); + + if (B->n >= sizeMax) break; + + if (A->n < sizeMin) break; // 25/05 + + if (B->n >= sizeMin) { + int nA = A->n, nEA = nbEdgesInA; + + if (testSourceConnected && (A->n > thresholdConComponents) && (A->n < sizeA)) { + int nbComp = searchConnectedComponentsInHeap(A, nbNeighborsInS, g); + if (nbComp > 1) { + int imax = indexMaxInList(compSizes, nbComp); + nA = compSizes[imax]; + nEA = compNbEdges[imax]; + } + } + + double e = evalSep(nA, B->n, C->n, nEA, nbEdgesInB, mode, FLUSH_A_B); + + if ((bestIsUninitialized) || (e > bestEval)) { + if (1) pourCintoA(B, nbNeighborsInA, nbNeighborsInB, &nbEdgesInB, C, g, 1); + bestIsUninitialized = 0; + bestEval = e; + if (separatorJustMemorizeReceptorSize && (g->n >= separatorJustMemoSizeMin)) { + bestBSize = B->n; + } + else + copySeparator(sep, bestSep); + } + } + } + if ((separatorJustMemorizeReceptorSize) && (bestBSize != NONE)) { + int nB = B->n; + copySeparator(sep, bestSep); + builtBestSeparator(bestSep->B, bestSep->A, bestSep->C, nbNeighborsInB, nbNeighborsInA, bestBSize, g); + } +} + + + +void builtBestSeparator(Heap dest, Heap src, Heap C, int nbNdest[], int nbNsrc[], int size, Graph g) { + // get nb neighbors (must not be modified for next calls to flush()) + memcpy(nbNInDestCopy, nbNdest, g->n * sizeof(int)); + + // put back last vertices from dest to C + for (int i = dest->n-1; i >= size; i --) { + int e = dest->val[i]; + dest->ind[e] = NONE; + heapJustAdd(e, C); + for (int *pp = g->lists[e]; *pp != NONE; pp ++) + nbNInDestCopy[*pp] --; + } + + // Memorize the number of neighbors in dest and src for C vertices (used for the single branch ordering) + for (int *p = C->val; p < C->val+C->n; p ++) + nbNInABCopy[*p] = nbNInDestCopy[*p]+nbNsrc[*p]; + + dest->n = size; + + // move vertices of C which have no neighbors in dest, in src + int i = 0; + while (i < C->n) { + int e = C->val[i]; + if (nbNInDestCopy[e] == 0) { + C->n --; + C->val[i] = C->val[C->n]; + C->ind[C->val[i]] = i; + C->ind[e] = NONE; + heapJustAdd(e, src); + for (int *pp = g->lists[e]; *pp != NONE; pp ++) + nbNInABCopy[*pp] ++; + } + else i ++; + } + +} + + + + + +// FlushBtoA() :: e has been moved to A. e neighbors which are in B must be moved to C. +void removeNeighborsFromB(int e, Heap A, Heap B, Heap C, SET V, int *S, int n, Graph g) { + int nbToThrow = 0; + + for (int *p = g->lists[e]; p-g->lists[e] < nbNeighborsInS[e]; p ++) { //(*p != NONE) : useless, first neighbors are in S + if (B->ind[*p] != NONE) { + + if (nbNeighborsInB[*p] == 0) verticesToThrow[nbToThrow ++] = *p; + + if (useMinPartitions == 1) + minheapRemove(*p, B, nbNeighborsInB); + else if (useMinPartitions == 2) + minheapJustRemove(*p, B, nbNeighborsInB); + else + heapRemove(*p, B); + + heapInsert(*p, C); + nbEdgesInB -= nbNeighborsInB[*p]; + + decreaseNbNeighborsInB(*p, B, C, V, S, n, g); + } + } + + if ((nbToThrow == 0) || (C->n == 0) || (B->n <= 1)) return; + + for (int *p = verticesToThrow; p < verticesToThrow+nbToThrow; p ++) + { + if ((C->n == 0) || (B->n <= 1)) return; + if ((C->ind[*p] != NONE) && (nbNeighborsInB[*p] == 0)) { + heapRemove(*p, C); + heapJustAdd(*p, A); + nbEdgesInA += nbNeighborsInA[*p]; + increaseNbNeighborsInA(*p, C, V, S, n, g); + } + } +} + + + +void removeNeighborsFromA(int e, Heap A, Heap B, Heap C, SET V, int *S, int n, Graph g) { + int movesToB = 0; + for (int *p = g->lists[e]; p-g->lists[e] < nbNeighborsInS[e]; p ++) { + if (A->ind[*p] != NONE) { + + if (nbNeighborsInA[*p] == 0) movesToB ++; + + if (useMinPartitions == 1) + minheapRemove(*p, A, nbNeighborsInA); + else if (useMinPartitions == 2) + minheapRemove(*p, A, nbNeighborsInA); + else + heapRemove(*p, A); + + heapInsert(*p, C); + nbEdgesInA -= nbNeighborsInA[*p]; + + decreaseNbNeighborsInA(*p, A, C, V, S, n, g); + } + } + + if ((movesToB == 0) || (C->n == 0) || (A->n <= 1)) return; + + for (int *p = g->lists[e]; p-g->lists[e] < nbNeighborsInS[e]; p ++) { + if ((C->n == 0) || (A->n <= 1)) return; + if ((C->ind[*p] != NONE) && (nbNeighborsInA[*p] == 0)) { + heapRemove(*p, C); + heapJustAdd(*p, B); + nbEdgesInB += nbNeighborsInB[*p]; + increaseNbNeighborsInB(*p, C, V, S, n, g); + } + } +} + + + +int isSmallerNeighborsInB(int a, int b) { + if (nbNeighborsInB[a] < nbNeighborsInB[b]) + return 1; + if (nbNeighborsInB[a] > nbNeighborsInB[b]) + return 0; + return (priorities[a] > priorities[b]); +} + + +int isSmallerNeighborsInA(int a, int b) { + if (nbNeighborsInA[a] < nbNeighborsInA[b]) + return 1; + if (nbNeighborsInA[a] > nbNeighborsInA[b]) + return 0; + return (priorities[a] > priorities[b]); +} + + +int modeChoiceInCflushBA = 0; +int modeChoiceInCflushAB = 0; + +// Comparator for C vertices: fewer neighbors in B is better (more neighbors in A also) +// Returns 1 if a is smaller (better) than b +int compareCVerticesFlushBtoA(int a, int b) { + + if (nbNeighborsInB[a] == 0) { + if ((nbNeighborsInB[b] == 0) && (nbNeighborsInA[a] < nbNeighborsInA[b])) return 0; + return 1; + } + if (nbNeighborsInB[b] == 0) return 0; + + int nbNaB = nbNeighborsInB[a]; + int nbNaA = nbNeighborsInA[a]; + int nbNbB = nbNeighborsInB[b]; + int nbNbA = nbNeighborsInA[b]; + + if (modeChoiceInCflushBA == 0) { + if (nbNeighborsInB[a] < nbNeighborsInB[b]) + return 1; + if (nbNeighborsInB[a] > nbNeighborsInB[b]) + return 0; + if (nbNeighborsInA[a] > nbNeighborsInA[b]) + return 1; + if (nbNeighborsInA[a] < nbNeighborsInA[b]) + return 0; + return (priorities[a] > priorities[b]); + } + + if (modeChoiceInCflushBA == 1) { + // If the difference bteween the numbers of neighbors in B is small but one has many more neighbors in A, then prefer this one + if (nbNaB < nbNbB) { + if (nbNaA >= nbNbA) return 1; + return (nbNbA - nbNaA < (nbNbB - nbNaB + 2) * (nbNbB - nbNaB + 2) - 1); + } + if (nbNaB > nbNbB) { + if (nbNaA <= nbNbA) return 0; + return (nbNaA - nbNbA >= (nbNaB - nbNbB + 2) * (nbNaB - nbNbB + 2) - 1); + } + if (nbNaA == nbNbA) return (priorities[a] > priorities[b]); + return (nbNaA > nbNbA); + } + + + if (modeChoiceInCflushBA == 2) { + if (nbNaB < nbNbB) { + if (nbNaA >= nbNbA) return 1; + if ((nbNaA == 0) || (100 * nbNbA) / nbNaA >= 100 * (1 + nbNbB - nbNaB)) return 0; + return 1; + } + if (nbNaB > nbNbB) { + if (nbNaA <= nbNbA) return 0; + if ((nbNbA == 0) || (100 * nbNaA) / nbNbA >= 100 * (1 + nbNaB - nbNbB)) return 1; + return 0; + } + if (nbNaA == nbNbA) return (priorities[a] > priorities[b]); + return (nbNaA > nbNbA); + } + return 1; + + if (0) { + float ea = nbNeighborsInB[a] * nbNeighborsInB[a] / nbNeighborsInA[a]; + float eb = nbNeighborsInB[b] * nbNeighborsInB[b] / nbNeighborsInA[b]; + + if (ea < eb) return 1; + if (ea > eb) return 0; + return (priorities[a] > priorities[b]); + } +} + + + +int compareCVerticesFlushAtoB(int a, int b) { + + if (nbNeighborsInA[a] == 0) { + if ((nbNeighborsInA[b] == 0) && (nbNeighborsInB[a] < nbNeighborsInB[b])) return 0; + return 1; + } + if (nbNeighborsInA[b] == 0) return 0; + + + if (modeChoiceInCflushAB == 0) { + if (nbNeighborsInA[a] < nbNeighborsInA[b]) + return 1; + if (nbNeighborsInA[a] > nbNeighborsInA[b]) + return 0; + if (nbNeighborsInB[a] > nbNeighborsInB[b]) + return 1; + if (nbNeighborsInB[a] < nbNeighborsInB[b]) + return 0; + return (priorities[a] > priorities[b]); + } + + + if (modeChoiceInCflushAB == 1) { + if (nbNeighborsInA[a] < nbNeighborsInA[b]) { + if (nbNeighborsInB[a] >= nbNeighborsInB[b]) return 1; + if (nbNeighborsInB[b] - nbNeighborsInB[a] >= + (nbNeighborsInA[b] - nbNeighborsInA[a] + 1) * (nbNeighborsInA[b] - nbNeighborsInA[a] + 1) ) + return 0; + return 1; + } + if (nbNeighborsInA[a] > nbNeighborsInA[b]) { + if (nbNeighborsInB[a] <= nbNeighborsInB[b]) return 0; + if (nbNeighborsInB[a] - nbNeighborsInB[b] >= + (nbNeighborsInA[a] - nbNeighborsInA[b] + 1) * (nbNeighborsInA[a] - nbNeighborsInA[b] + 1) ) + return 1; + return 0; + } + //if (nbNeighborsInB[a] == nbNeighborsInB[b]) { + if (nbNeighborsInB[a] > nbNeighborsInB[b]) return 1; + if (nbNeighborsInB[a] < nbNeighborsInB[b]) return 0; + return (priorities[a] > priorities[b]); + } + + if (modeChoiceInCflushAB == 2) { + if (nbNeighborsInA[a] < nbNeighborsInA[b]) { + if (nbNeighborsInB[a] >= nbNeighborsInB[b]) return 1; + if ((nbNeighborsInB[a] == 0) || ((100*nbNeighborsInB[b]) / nbNeighborsInB[a] >= + 100 * (1 + nbNeighborsInA[b] - nbNeighborsInA[a]) )) + return 0; + return 1; + } + if (nbNeighborsInA[a] > nbNeighborsInA[b]) { + if (nbNeighborsInB[a] <= nbNeighborsInB[b]) return 0; + if ((nbNeighborsInB[b] == 0) || ((100*nbNeighborsInB[a]) / nbNeighborsInB[b] >= + 100 * (1 + nbNeighborsInA[a] - nbNeighborsInA[b]) )) + return 1; + return 0; + } + //if (nbNeighborsInB[a] == nbNeighborsInB[b]) { + if (nbNeighborsInB[a] > nbNeighborsInB[b]) return 1; + if (nbNeighborsInB[a] < nbNeighborsInB[b]) return 0; + return (priorities[a] > priorities[b]); + } + return 1; +} + + + +// +// Dust separator: for vertices of C that have no neighbor in A or B +// + +void pourCintoA(Heap A, int nbNFrom[], int nbNTo[], int *nbEdges, Heap C, Graph g, int justAdd) { + for (int i = 0; i < C->n; i++) { + int e = C->val[i]; + if (nbNFrom[e] == 0) { + heapRemove(e, C); + if (justAdd) + heapJustAdd(e, A); + else + heapInsert(e, A); + *nbEdges = *nbEdges + nbNTo[e]; + for (int *p = g->lists[e]; *p != NONE; p ++) nbNTo[*p]++; + } + } +} + + +// +// C improvement +// + +int nbCVerticesWithNoNeighborInAAndB(Heap C, SET V, int *S, int n, Graph g) { + if (C->n == 0) return 0; + int nb = 0; + for (int *p = C->val; p < C->val+C->n; p ++) { + if ((nbNeighborsInB[*p] == 0) && (nbNeighborsInA[*p] == 0)) nb ++; + } + return nb; +} + +// Search vertices of C with no neighbor in A nor in B, count the number of neighbors in C, +// finally order them (those with the fewer neighbors in C first) and make a selection +// of independent such vertices. Each of them will form an isolated vertex. +void selectABDisconnectedVertices(Separator sep, SET V, int *S, int n, int date, Graph g) { + Heap C = sep->C; + if (C->n == 0) { sep->nbABDV = 0; return ; } + int nb = 0; + for (int *p = C->val; p < C->val+C->n; p ++) { + if ((nbNeighborsInB[*p] == 0) && (nbNeighborsInA[*p] == 0)) { + dateABDisconnected[*p] = date; // mark *p as an AB Disconnected certex for current separe call + nbNeighborsABDisconnected[*p] = 0; + swapValues(C->val+nb, p); + nb ++; + } + } + if (nb == 0) { sep->nbABDV = 0; return;} + + printf("nb AB Disconnected = %d :: ", nb); + for (int i = 0; i < nb; i ++) printf("%d (%d,%d) ", C->val[i], nbNeighborsInB[C->val[i]], nbNeighborsInA[C->val[i]]); + printf("\n"); + printList(sep->A->val, sep->A->n); + printList(sep->B->val, sep->B->n); + printList(C->val, C->n); + + + if (nb <= 1) { sep->nbABDV = nb; return ; } + + sep->nbABDV = 1; + return ; + + // Calculate the degree of each AB Disconnected vertex in the set of AB Disconnected vertices. + for (int *p = C->val; p < C->val+nb; p ++) { + for (int *q = g->lists[*p]; q < g->lists[*p]+nbNeighborsInS[*p]; q ++) { + if (dateABDisconnected[*q] == date) + nbNeighborsABDisconnected[*q] ++; + } + } + // Order AB Disconnected vertices, the less connected first. + for (int i = nb; i > 1; i --) { + int someSwap = 0; + for (int j = nb-1; j > 0; j --) { + if (nbNeighborsABDisconnected[C->val[j]] < nbNeighborsABDisconnected[C->val[j - 1]]) { + swap(C->val, j, j - 1); + someSwap = 1; + } + } + if (someSwap == 0) break; + } + // Select independent AB Disconnected vertices (mark dateABDisconnected[*p] = -nbCallsSepare when selected) + dateABDisconnected[C->val[0]] = -date; + int nbS = 1; + int i = 1; + while (i < nb) { + // the ith AB Disconnected vertex is chosen if independent with previous selected vertices + int v = C->val[i]; + int *q = g->lists[v]; + for ( ; q < g->lists[v]+nbNeighborsInS[v]; q ++) + if (dateABDisconnected[*q] == -date) + break; + if (q == g->lists[v]+nbNeighborsInS[v]) { + swap(C->val, i, nbS); + dateABDisconnected[v] = -date; + nbS ++; + i ++; + } + } + printf("nbS=%d\n", nbS); + + // verif + if (0) { + for (int i = 0; i < nbS - 1; i++) + for (int j = i + 1; j < nbS; j++) + if (areNeighbours(C->val[i], C->val[j], g)) + printf("OUYE\n"); + } + sep->nbABDV = nbS; +} + + + + + + + + + + +// +// Improvement: search moves from A/B to C that generate moves from C to A/B +// Seems useless. + + +void improveSeparation(Separator s, Graph g, int nSteps) { + int moves[s->C->n]; + int nbmoves; + + START: + nbmoves = 0; + // Moves A->C (neighbors C->B) + for (int i = 0; i < nSteps; i ++) { + int u; + int nbMoves = searchMoveAC(s, g, moves, &u); + if (u == NONE) + return; + makeMove(u, s->A, s->C); + for (int j = 0; j < nbMoves; j ++) { + makeMove(moves[j], s->C, s->B); + } + nbMoves ++; + } + + // Moves B->C (neighbors C->A) + for (int i = 0; i < nSteps; i ++) { + int u; + int nbMoves = searchMoveBC(s, g, moves, &u); + if (u == NONE) + return; + makeMove(u, s->B, s->C); + for (int j = 0; j < nbMoves; j ++) { + makeMove(moves[j], s->C, s->A); + } + nbMoves ++; + } + + if ((nbmoves > 0) && (nSteps -- > 0)) + goto START; +} + + +// There could be a problem with nbNeighborsInHeap(neighbor) since the flag for presence in +// A, B and C has not been necessarily initialized +int searchMoveAC(Separator s, Graph g, int movesCB[], int *the) { + Heap A = s->A; + + for (int i = A->n-1; i >= 0; i --) { + // evaluate transfer of u from A to C. + // Good transfer if some neighbors of u are in C and can be moved to B + LIST p = g->adj[A->val[i]]; + int nb = 0; + while (p != NULL) { + if ( (s->C->ind[p->val] != NONE) && (nbVerticeInHeap(g->lists[p->val], nbNeighborsInS[p->val], s->A, g) == 1) ) // (nbNeighborsInHeap(p->val, s->A, g) == 1) + // p->val could be moved to B + movesCB[nb ++] = p->val; + p = p->suiv; + } + if ((nb > 1) || ((nb == 1) && (rand()%2))) { + *the = A->val[i]; + return nb; + } + } + return NONE; +} + + +int searchMoveBC(Separator s, Graph g, int movesCA[], int *the) { + Heap B = s->B; + + for (int i = B->n-1; i >= 0; i --) { + // evaluate transfer of u from A to C. + // Good transfer if some neighbors of u are in C and can be moved to A + LIST p = g->adj[B->val[i]]; + int nb = 0; + while (p != NULL) { + if ( (s->C->ind[p->val] != NONE) && (nbNeighborsInB[p->val] == 1) ) + // p->val could be moved to A + movesCA[nb ++] = p->val; + p = p->suiv; + } + if ((nb > 1) || ((nb == 1) && (rand()%2))) { + *the = B->val[i]; + return nb; + } + } + return NONE; +} + + + +void makeMove(int v, Heap source, Heap dest) { + heapRemove(v, source); + heapInsert(v, dest); +} + + + + + +// +// Strcture separator +// + + +Separator newSeparator(int size, Graph g) { + Separator s = malloc(sizeof(struct separator)); + s->A = allocHeap(size, isSmallerNeighborsInA); + s->B = allocHeap(size, isSmallerNeighborsInB); + s->C = allocHeap(size, compareCVerticesFlushBtoA); + s->graph = g; + return s; +} + + + +void allocSeparation(Graph g) { + + nbNeighborsInB = malloc(g->n * sizeof(int)); + nbNeighborsInA = malloc(g->n * sizeof(int)); + + nbNInDestCopy = malloc(g->n * sizeof(int)); + nbNInABCopy = malloc(g->n * sizeof(int)); + nbNeighborsInS = malloc(g->n * sizeof(int)); + + nbNeighborsABDisconnected = malloc(g->n * sizeof(int)); + dateABDisconnected = calloc(g->n, sizeof(int)); + + priorities = malloc(g->n * sizeof(int)); + + verticesToThrow = malloc(g->n * sizeof(int)); +} + + +int isABetterSeparator(Separator best, Separator s) { + return (best->C->n <= s->C->n); +} + + +void copySeparator(Separator src, Separator dest) { + dest->A->n = src->A->n; + dest->B->n = src->B->n; + dest->C->n = src->C->n; + memcpy(dest->A->val, src->A->val, src->A->n * sizeof(int)); + memcpy(dest->B->val, src->B->val, src->B->n * sizeof(int)); + memcpy(dest->C->val, src->C->val, src->C->n * sizeof(int)); +} + + + +void recoverNbNeighbors(int S[], int n) { + nbEdgesInA = 0; + nbEdgesInB = nbEdgesInS; + for (int i = 0; i < n; i++) { + nbNeighborsInA[S[i]] = 0; + nbNeighborsInB[S[i]] = nbNeighborsInS[S[i]]; + } +} + + + +int initializeNbNeighbors(SET V, int S[], int n, int pos[], Graph g) { + nbEdgesInS = 0; + minDegree = n+1; + maxDegree = -1; + + for (int i = 0; i < n; i++) { + // count the number of neighbors of S[i] in S and place them at the beginning of the list + int nb = 0; + int *p = g->lists[S[i]]; + while (*p != NONE) { + if (pos[*p] != NONE) { + if (p - g->lists[S[i]] != nb) { int tmp=*p; *p=g->lists[S[i]][nb]; g->lists[S[i]][nb] = tmp; } + nb ++; + } + p++; + } + nbNeighborsInS[S[i]] = nb; + if (nb < minDegree) { nbMinD = 1; minDegree = nb; } + else if (nb == minDegree) nbMinD ++; + if (nb > maxDegree) { maxDegree = nb; nbMaxD = 1; } + else if (nb == maxDegree) nbMaxD ++; + nbEdgesInS += nb; + } + nbEdgesInS = nbEdgesInS/2; + return nbEdgesInS; +} + + + +void initSeparator(SET V, int *S, int n, Graph g, Separator s) { + + resetHeap(s->A); + resetHeap(s->B); + resetHeap(s->C); + + // mark nodes that are not concerned in this run, just considering the nodes of S and their neighbors + // (when n is small, it is better to consider just the vertices that could interest us) + for (int i = 0; i < n; i++) { + s->A->ind[S[i]] = s->B->ind[S[i]] = s->C->ind[S[i]] = NONE; + } + + // Insert all vertices in B + for (int i = 0; i < n; i ++) { + heapJustAdd(S[i], s->B); + } + + recoverNbNeighbors(S, n); +} + + + + +int verifySeparator(int *S, int n, Separator s) { + + if ((s->A->n == s->graph->n) || (s->B->n == s->graph->n)) { + printf("verifySeparator : %d --> %d %d %d\n", n, s->A->n, s->B->n, s->C->n); + return 0; + } + + + for (int i = 0; i < n; i ++) { + int nb = 0; + nb += nbOccs(S[i], s->A->val, s->A->n); + nb += nbOccs(S[i], s->B->val, s->B->n); + nb += nbOccs(S[i], s->C->val, s->C->n); + if (nb == 0) { + printf("verifySeparator : %d is not in A,B,C\n", S[i]); + return 0; + } + if (nb > 1) { + printf("verifySeparator : %d is in ", S[i]); + if (nbOccs(S[i], s->A->val, s->A->n) > 0) printf("A "); + if (nbOccs(S[i], s->B->val, s->B->n) > 0) printf("B "); + if (nbOccs(S[i], s->C->val, s->C->n) > 0) printf("C "); + printf("\n"); + return 0; + } + } + return 1; +} + + + +void printSeparator(Separator s) { + printf("separation: "); + for (int i = 0; i < s->A->n; i ++) printf("%d,", s->A->val[i]); + printf(" -- "); + for (int i = 0; i < s->B->n; i ++) printf("%d,", s->B->val[i]); + printf(" -- "); + for (int i = 0; i < s->C->n; i ++) printf("%d,", s->C->val[i]); + printf("\n"); + //printf("%d + %d + %d\n", s->B->n, s->C->n, s->A->n); +} + + +int nbCallsdecreaseNbNeighborsInB = 0; +// Only for flushBtoA stage. u has been removed from B => decrease the number of neighbors in B for all B neighbors, +// Neighbors have been ordered so that those in S[] occur first in the list +void decreaseNbNeighborsInB(int u, Heap B, Heap C, SET V, int S[], int n, Graph g) { + int nb = 0; + + for (int * p = g->lists[u]; *p != NONE; p ++) { + + nbNeighborsInB[*p] --; + if (B->ind[*p] != NONE) { + if (useMinPartitions) + minheapDecreaseValue(*p, B, nbNeighborsInB); + else + heapBubbleUp(B->ind[*p], B); + } + else if (C->ind[*p] != NONE) + heapBubbleUp(C->ind[*p], C); + if ( ++ nb == nbNeighborsInS[u]) break; + } +} + + +// Only for flushAtoB(). u has been inserted in B (for flushAtoB) +void increaseNbNeighborsInB(int u, Heap C, SET V, int S[], int n, Graph g) { + int nb = 0; + for (int *pp = g->lists[u]; *pp != NONE; pp ++) { + nbNeighborsInB[*pp] ++; + if (C->ind[*pp] != NONE) + heapBubbleUp(C->ind[*pp], C); + if ( ++ nb == nbNeighborsInS[u]) break; + } +} + + + +// for flushAtoB +void decreaseNbNeighborsInA(int u, Heap A, Heap C, SET V, int S[], int n, Graph g) { + int nb = 0; + for (int *p = g->lists[u]; *p != NONE; p ++) { + nbNeighborsInA[*p] --; + if (A->ind[*p] != NONE) { + if (useMinPartitions) + minheapDecreaseValue(*p, A, nbNeighborsInA); + else + heapBubbleUp(A->ind[*p], A); + } + else if (C->ind[*p] != NONE) + heapBubbleUp(C->ind[*p], C); + if ( ++ nb == nbNeighborsInS[u]) break; + } + return; +} + + + +// for flushBtoA +void increaseNbNeighborsInA(int u, Heap C, SET V, int S[], int n, Graph g) { + int nb = 0; + for (int *pp = g->lists[u]; *pp != NONE; pp ++) { + nbNeighborsInA[*pp] ++; + if (C->ind[*pp] != NONE) + heapBubbleUp(C->ind[*pp], C); + // It is useless to consider u neighbors which are in B, there is none + if ( ++ nb == nbNeighborsInS[u]) break; // first neighbors are those in S[] + } + return; +} + + +// Supposes that the numbers of neighbors in S[] are OK, and neighbors occur first in the lists. +int verifyNbNeighbors(Heap A, Heap B, Heap C, SET V, int S[], int n, Graph g) { + int nbEIA = 0, nbEIB = 0; + for (int i = 0; i < n; i ++) { + int nbNA = nbVerticeInHeap(g->lists[S[i]], nbNeighborsInS[S[i]], A, g); + if (nbNA != nbNeighborsInA[S[i]]) { printf("bad nbNeighborsInA %d :: %d in place of %d\n", S[i], nbNeighborsInA[S[i]], nbNA); return 0; } + int nbNB = nbVerticeInHeap(g->lists[S[i]], nbNeighborsInS[S[i]], B, g); + if (nbNB != nbNeighborsInB[S[i]]) { printf("bad nbNeighborsInB %d :: %d in place of %d\n", S[i], nbNeighborsInB[S[i]], nbNB); return 0; } + if (isInHeap(S[i], A)) nbEIA += nbNA; + if (isInHeap(S[i], B)) nbEIB += nbNB; + } + nbEIA = nbEIA/2; + nbEIB = nbEIB/2; + if (nbEIA != nbEdgesInA) { printf("bad nbEdgesInA :: %d it should be %d\n", nbEdgesInA, nbEIA); return 0; } + if (nbEIB != nbEdgesInB) { printf("bad nbEdgesInB :: %d it should be %d\n", nbEdgesInB, nbEIB); return 0; } + //printf("nb neighbors is OK \n"); + return 1; +} + + + +void initializePriorities(Graph g) { + for (int i = 0; i < g->n; i ++) + priorities[i] = rand()%(10*g->n); +} + +void randomizePriorities(int S[], int n, Graph g) { + for (int i = 0; i < n; i ++) + priorities[S[i]] = rand()%(10*g->n); +} + + + + + diff --git a/pace-2020/separator.h b/pace-2020/separator.h new file mode 100644 index 0000000000000000000000000000000000000000..4127677d016d9dbffc920136b9a332fbf2c955ec --- /dev/null +++ b/pace-2020/separator.h @@ -0,0 +1,110 @@ +// +// Created by Stephane on 10/03/2020. +// + +#ifndef SRC_SEPARATOR_H +#define SRC_SEPARATOR_H + +#include "graph.h" +#include "heap.h" +#include "sets.h" + + +#define EVAL_0 0 +#define EVAL_TREE_HEIGHT_COMPLETE_GRAPH 1 +#define EVAL_CARD 2 +#define EVAL_SQRT_CARD 3 + +#define EVAL_MINIMIZE_C 4 +#define EVAL_MAX_SOURCE_DENSITY 5 + +#define EVAL_MIN_A_B 6 + +#define EVAL_MAX_CDENS_MIN_AB_SIZES 7 +#define EVAL_MAX_C_DENSITY 8 +#define EVAL_MAX_AB_SIZES_MIN_AB_EDGES 9 + +#define EVAL_LEVEL_DENSITY 11 +#define EVAL_ESSAI 33 + + +#define FLUSH_A_B 0 +#define FLUSH_B_A 1 + + + +typedef struct separator * Separator; + +struct separator { + Heap A; + Heap B; + Heap C; + int nbABDV; // nb vertices in C that are disconnected from A, B and from themselves + Graph graph; +}; + + + +extern int *nbNeighborsInA; +extern int *nbNeighborsInB; +extern int nbEdgesInA, nbEdgesInB; + +extern int * nbNInABCopy; + +extern int *priorities; + +extern int nbCallsSepare; + + +double evalSep(int nA, int nB, int nC, int mA, int mB, int mode, int direction); + +int searchSeparator(int *S, int n, SET V, Graph g, Separator theSeparator, int nTries, int nFlushes, int depth); +int separe(int *S, int n, SET V, Graph g, Separator s, int nbFlushs, int mode); +void flushBtoA(Heap A, Heap B, Heap C, SET V, int S[], int n, int mode, int seed, Graph g); +void flushAtoB(Heap A, Heap B, Heap C, SET V, int S[], int n, int mode, Graph g); + +void builtBestSeparator(Heap dest, Heap src, Heap C, int nbNdest[], int nbNsrc[], int size, Graph g); + +void removeNeighborsFromA(int e, Heap A, Heap B, Heap C, SET V, int *S, int n, Graph g); +void removeNeighborsFromB(int e, Heap A, Heap B, Heap C, SET V, int *S, int n, Graph g); + +int isSmallerNeighborsInB(int a, int b); +int isSmallerNeighborsInA(int a, int b); +int compareCVerticesFlushBtoA(int a, int b); +int compareCVerticesFlushAtoB(int a, int b); + +void pourCintoA(Heap A, int nbNFrom[], int nbNTo[], int *nbEdges, Heap C, Graph g, int justAdd); + +void allocSeparation(Graph g); +int isABetterSeparator(Separator best, Separator s); +void copySeparator(Separator from, Separator to); + +void selectABDisconnectedVertices(Separator sep, SET V, int *S, int n, int date, Graph g); + + +void improveSeparation(Separator s, Graph g, int nSteps); +int searchMoveAC(Separator s, Graph g, int movesCB[], int *the); +int searchMoveBC(Separator s, Graph g, int movesCA[], int *the); +void makeMove(int v, Heap source, Heap dest); + +Separator newSeparator(int size, Graph g); +int initializeNbNeighbors(SET V, int S[], int n, int pos[], Graph g); +void recoverNbNeighbors(int S[], int n); +void initSeparator(SET V, int *S, int n, Graph g, Separator s); +//void removeFromB(int v, Separator s); +//void removeFromC(int v, Separator s); +//void addInC(int v, Separator s); +void printSeparator(Separator s); +int verifySeparator(int *S, int n, Separator s); + +void decreaseNbNeighborsInB(int u, Heap B, Heap C, SET V, int S[], int n, Graph g); +void decreaseNbNeighborsInA(int u, Heap A, Heap C, SET V, int S[], int n, Graph g); +void increaseNbNeighborsInA(int u, Heap C, SET V, int S[], int n, Graph g); +void increaseNbNeighborsInB(int u, Heap C, SET V, int S[], int n, Graph g); +int verifyNbNeighbors(Heap A, Heap B, Heap C, SET V, int S[], int n, Graph g); + +void initializePriorities(Graph g); +void randomizePriorities(int S[], int n, Graph g); + + +#endif //SRC_SEPARATOR_H diff --git a/pace-2020/sets.c b/pace-2020/sets.c new file mode 100644 index 0000000000000000000000000000000000000000..6e12703d53ac9ff34289386f12e95b5c3e35f3db --- /dev/null +++ b/pace-2020/sets.c @@ -0,0 +1,173 @@ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> + +#include "sets.h" + +TYPESEG fullPartialSegment [] = { + 0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, + 65535, 131071, 262143, 524287, 1048575, 2097151, 4194303, + 8388607, 16777215, 33554431, 67108863, 134217727, 268435455, + 536870911, 1073741823, 2147483647}; +/* 4294967295 */ + +int Cardinal[256] = { + 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5, + 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, + 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, + 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, + 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, + 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, + 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, + 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8}; + + + +SET allocSet(int n) { + SET s; + + s = calloc((size_t) (n-1) / SIZESEG + 3, sizeof(TYPESEG)); + assert(s != NULL); + TAILLE(s) = (TYPESEG) ((n-1) / SIZESEG + 1); + CARD(s) = 0; + return s; +} + + +void freeSet(SET s) { + free(s); +} + + +void clearSet(SET s) { + unsigned int * p = s+TAILLE(s)+1; + + while (p > s+1) + *p -- = (TYPESEG) 0; + /* int i; */ + + /* for (i = 2; i < TAILLE(s)+2; i++) */ + /* *(s+i) = (TYPESEG) 0; */ + CARD(s) = 0; +} + + +void FillSet(SET s, int n) { + int i; + + for (i = 2; i < 2+n/SIZESEG; i++) + *(s+i) = ~((TYPESEG) 0); + + if (n%SIZESEG != 0) + *(s+i) = (TYPESEG) fullPartialSegment [n%SIZESEG]; + + CARD(s) = (TYPESEG) n; +} + + +void copySet(SET s, SET d) { + int i; + + TAILLE(d) = TAILLE(s); + CARD(d) = CARD(s); + for (i = 2; i < TAILLE(s)+2; i++) + *(d+i) = *(s+i); +} + + +SET makeSet(int *S, int nb, SET E) { + clearSet(E); + for (int i = 0; i < nb; i ++) + ADDe(S[i], E); + return E; +} + + +int nCommuns(SET s1, SET s2) { + int i, n = 0; + TYPESEG S; + unsigned char *c; + + for (i = 2; i < TAILLE(s1)+2; i++) { + S = *(s1+i)&*(s2+i); + c = (unsigned char *) (&S); + n += Cardinal[*c]+Cardinal[*(c+1)]+Cardinal[*(c+2)]+Cardinal[*(c+3)]; + } + return n; +} + +int nFaitsCommunsInSet(SET s1, SET s2) { + int i, n = 0; + TYPESEG S1, S2; + + for (i = 2; i < TAILLE(s1)+2; i++) { + S1 = *(s1+i); + S2 = *(s2+i); + while (S1 || S2) { + if ((S1%4 == S2%4) && (S1%4 != 3)) + n ++; + S1 = (S1 >> (TYPESEG) 2); + S2 = (S2 >> (TYPESEG) 2); + } + } + return n; +} + + +int isSubSet(SET u, SET s) { + int i; + + for (i = 2; i < TAILLE(u)+2; i++) + if ((*(u+i)&*(s+i)) != *(u+i)) + return 0; + return 1; +} + + +int isSupSet(SET u, SET s) { + int i; + + for (i = 2; i < TAILLE(u)+2; i++) + if ((*(u+i)&*(s+i)) != *(s+i)) + return 0; + return 1; +} + +char setsIntersect(SET s1, SET s2) { + int i; + + for (i = 2; i < TAILLE(s1)+2; i++) + if ((*(s1+i)&*(s2+i)) != (TYPESEG) 0) + return 1; + return 0; +} + +// add elements of s1 to s2 +void addSet(SET s1, SET s2) { + int i; + + for (i = 2; i < TAILLE(s1)+2; i++) + *(s2+i) = (*(s2+i))|(*(s1+i)); + CALCARD(s2); +} + + +void FactsLevelToSet(int * F, int nf, SET S) { + int i; + TYPESEG * p = S+SEGMARGIN; + + for (i = 0, *p = (TYPESEG) 0; i < nf; i ++) { + if ( F[2*i] ) { + if ( ! F[2*i+1] ) + *p = (*p)|(((TYPESEG) 1) << (TYPESEG) ((2*i)%SIZESEG)); + } + else if ( F[2*i+1] ) + *p = (*p)|(((TYPESEG) 1) << (TYPESEG) ((2*i+1)%SIZESEG)); + if ((2*i+2)%SIZESEG == 0) { + p ++; + *p = (TYPESEG) 0; + } + } + CALCARD(S); +} diff --git a/pace-2020/sets.h b/pace-2020/sets.h new file mode 100644 index 0000000000000000000000000000000000000000..b129871dfb5aea66b426286aecb440838c4e271e --- /dev/null +++ b/pace-2020/sets.h @@ -0,0 +1,84 @@ +#ifndef _H_sets +#define _H_sets + +#include <stdio.h> +#include <stdlib.h> + +/* Les deux segmets initiaux pour stocker le cardinal et la taille. */ +#define SEGMARGIN 2 + + +typedef unsigned int TYPESEG; /* Type d'un segment. */ +typedef TYPESEG *SET; /* Un ensemble. */ + +extern int Cardinal[]; + +/* + * Prototypes. + */ + +SET allocSet(int); +void copySet(SET, SET); +SET makeSet(int *S, int nb, SET E); +int nCommuns(SET , SET ); +int nFaitsCommunsInSet(SET s1, SET s2); +void freeSet(SET); +char setsIntersect(SET, SET); +void addSet(SET, SET); +int isSubSet(SET, SET); +int isSupSet(SET, SET); +void clearSet(SET); +void FillSet(SET s, int n); +void FactsLevelToSet(int * F, int nf, SET S); + + +/* + * Macros. + */ + +#define SIZESEG 32 + +#define CARD(s) *(s) +#define TAILLE(s) *((s)+1) /* Nombre de segments. */ + +#define IS_EMPTY(s) (*(s) == 0) + +#define IN(e,s) ((*((s)+(e)/SIZESEG+SEGMARGIN)&((TYPESEG) 1)<<((e)%SIZESEG)) != ((TYPESEG) 0)) +#define ADDe(e,s) if (!IN((e),(s))) {*((s)+(e)/SIZESEG+SEGMARGIN) |= (TYPESEG) (((TYPESEG) 1)<<((e)%SIZESEG)); (CARD(s))++;} +#define RETe(e,s) if (IN((e),(s))) {*((s)+(e)/SIZESEG+SEGMARGIN) ^= ((TYPESEG) 1)<<((e)%SIZESEG); (CARD(s))--;} +#define CALCARD(s) {\ + int iCALCARD,nCALCARD;\ + unsigned char *pCALCARD;\ + for (iCALCARD=0, pCALCARD=(unsigned char *) ((s)+SEGMARGIN), nCALCARD=0; iCALCARD < TAILLE(s); pCALCARD+=4, iCALCARD++)\ + nCALCARD+=Cardinal[*pCALCARD]+Cardinal[*(pCALCARD+1)]+Cardinal[*(pCALCARD+2)]+Cardinal[*(pCALCARD+3)];\ + CARD(s) = nCALCARD;\ +} + +#define ADDs(s1,s2) {\ + int iADDs;\ + for (iADDs=SEGMARGIN; iADDs < TAILLE(s2)+SEGMARGIN; iADDs++)\ + *((s2)+iADDs) |= *((s1)+iADDs);\ + CALCARD(s2)\ + } +#define RETs(s1,s2) {\ + int iRETs;\ + for (iRETs=SEGMARGIN; iRETs < TAILLE(s2)+SEGMARGIN; iRETs++)\ + *((s2)+iRETs) &= ~*((s1)+iRETs);\ + CALCARD(s2)\ + } +#define INTERs(s1,s2) {\ + int iINTERs; \ + for (iINTERs=SEGMARGIN; iINTERs < TAILLE(s2)+SEGMARGIN; iINTERs++) \ + *((s2)+iINTERs) &= *((s1)+iINTERs); \ + CALCARD(s2) \ + } + +#define AFFSET(s) {\ + int iAFFSET;\ + printf("[%ld/%ld] ",CARD(s),TAILLE(s));\ + for (iAFFSET=0; iAFFSET<TAILLE(s)*SIZESEG; iAFFSET++)\ + if IN(iAFFSET,s)\ + printf("%5ld",iAFFSET);\ + printf("\n");\ + } +#endif diff --git a/pace-2020/swaps.c b/pace-2020/swaps.c new file mode 100644 index 0000000000000000000000000000000000000000..7cd3fd703140dddef3b5d95941c3119bc19341b1 --- /dev/null +++ b/pace-2020/swaps.c @@ -0,0 +1,749 @@ +// +// Created by Stephane on 08/04/2020. +// + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> + +#include "swaps.h" +#include "decompose.h" +#include "graph.h" +#include "main.h" +#include "tree.h" +#include "sets.h" +#include "utils.h" + + + +// Parameters +int maxSwaps = 5; // max number of good swaps to find each time +int maxSwapsSearches = 11111; // max number of searches to perform each time +int justSwapBestSwap = 1; // the best swap is the one with the greatest gain + +int nbCallsSwapNode = 0; + + +int depthCC; +Node bestNode; // best node and its correspondent for swapping +int *swapsVertices = NULL, *correspondent; +Node * dependentSubtrees; + + +Node * criticalBranch = NULL; +Node criticalNode; +int lengthCB; +int changeCriticalNode; +Node * lastAncestor; // the last critical ancestor that was calculated for the node +int * dateLastAncestor; // and at what date +int * neighborsAreSorted; +int * dateNodesSet; // last time the set of nodes in subtree has been updated +int * datePulledUp; // last time the subtree has been pulled up + + +// Two swaps may be incompatible, in paticular if their interval (node,correspondent) are not stricly disjoint. +// It can be detected when the number of subtrees has decreased since the evaluation of the swap. +// To have less conflicts it is better to perform first swaps of small lengths. +int *swapGain = NULL; +int *nbSubtrees = NULL; // Number of dependent subtrees on the critical branch for the nodes of the critical branch +int *swapLength = NULL; // the length of the branch between the node and its correspondent +int *swapDepth = NULL; // depth of the correspondent + +Heap swapsHeap = NULL; + +int lenMin; +int gainMax; + +int *nbDeeperN = NULL; // Number of deeper neighbors in the tree, for each vertex of the graph +int limitNbDeepestNeighbors = 6; // Unused ignore swap if there are more neighbors under + + + +int with_assertions = 0; + +int nbCallsPrune = 0; + +int date = 0; + + +void exploreAndUpdateSetOfNodes(Node p, SET V, int date, int dates[]) { + if (dates[p->vertex] == date) { + addSet(p->nodes, V); + return; + } + ADDe(p->vertex, V); + Node q = p->fbs; + while (q != NULL) { + exploreAndBuildSetOfNodes(q, V); + q = q->next; + } +} + + +int pullUpIndependentSubtreesInTheBranch(Node root, Node from, int date, Graph g) { + Node p; + int nbMoves = 0; + + int trace = 0; + nbCallsPrune ++; + + if (from == root) return 0; + + if (trace) printf("from node : %d @ %d h=%d root heigh=%d\n", criticalNode->vertex, criticalNode->depth, criticalNode->height, root->height); + + p = from; + while (p->father != root) { + // search p critical subtrees that contain no neighbor of p, to pull them up + int nbNUnder = g->nadj[p->vertex] - nbNeighborsAbove(p, g); + int nbPU = 0; + Node q = p->fbs; + Node prev = NULL; + + if ((clock()-startTime)/CLOCKS_PER_SEC >= time_limit) stopSearch = 1; + if (stopSearch) break; + + while (q != NULL) { + + if (stopSearch) break; + + Node next = q->next; + if ((datePulledUp[q->vertex] == date) || (q->height+1 < p->height)) { prev = q; q = next; continue; } // Can jump some neighbors here (not counted in nbNUnder) + + if ((q->nodes == NULL) || (dateNodesSet[q->vertex] != date)) { + if (q->nodes == NULL) q->nodes = allocSet(g->n); + else clearSet(q->nodes); + exploreAndUpdateSetOfNodes(q, q->nodes, date, dateNodesSet); + dateNodesSet[q->vertex] = date; + } + + int nb = hasNeighborsInSubtree(p->vertex, q->nodes, g); + + if ((nb == 0) || (nbNUnder == 0)) { + // pull up subtree q independent with p + nbPU ++; + datePulledUp[q->vertex] = date; + + if (trace) printf("pull up %d node %d @ %d h=%d\n", nbPU, q->vertex, q->depth, q->height); + + // 1. detach q + if (prev == NULL) p->fbs = q->next; + else prev->next = q->next; + q->next = NULL; + dateNodesSet[p->vertex] = NONE; + //if (p->height == q->height+1) { p->nbhmax --; if (p->nbhmax == 0) initializeHeight(p); } + + + // 2. search destination (do not consider to put q as the new root => loops) + Node dest = p->father; + int up = 1; + while (dest != root) { + if ( ! hasNoNeighborInSet(dest->vertex, q->nodes, g)) break; + dateNodesSet[dest->vertex] = NONE; + dest = dest->father; + up ++; + } + if (trace && (dest != NULL)) printf("dest +%d attach %d under %d @ %d h=%d\n", up, q->vertex, dest->vertex, dest->depth, dest->height); + + + // 3. reattach to the tree + if (dest == NULL) { + // q becomes the new root => loops, should consider heights (not updated) to put one under the other + root->next = q->fbs; + root->father = q; + q->fbs = root; + q->father = q->next = NULL; + root = q; + } + else { + q->next = dest->fbs; + dest->fbs = q; + q->father = dest; + } + } + else + prev = q; + + nbNUnder -= nb; + q = next; + } + if (nbPU > 0) { + initializeHeight(p); + dateNodesSet[p->vertex] = NONE; + } + nbMoves += nbPU; + p = p->father; + } + + return nbMoves; +} + + +Node pullUpIndependentSubtreesInTree(Node root, Graph g) { + date ++; + + while (1) { + int prevHeight = root->height; + // criticalNode = markCriticalBranch(root, date, 1, g); + Node deepest = leftmostDeepestNode(root); + int nbPullUp = pullUpIndependentSubtreesInTheBranch(root, deepest, date, g); + if ((clock()-startTime)/CLOCKS_PER_SEC >= time_limit) stopSearch = 1; + if (stopSearch) break; + if (nbPullUp <= 0) break; + updateDepthsAndHeights(root, 0, 0); // Useless ? + if (0) printf("nbPU=%d %d --> %d\n", nbPullUp, prevHeight, root->height); + } + return root; +} + + + + +int compareSwaps(int i, int j) { + if (swapDepth[i] < swapDepth[j]) return 1; + return 0; + if (swapGain[i] == 0) return 0; + if (swapGain[j] == 0) return 1; + if (swapLength[i] < swapLength[j]) return 1; + if (swapLength[i] > swapLength[j]) return 0; + return (swapGain[i] > swapGain[j]); +} + + +void allocForSwaps (Graph g) { + criticalBranch = malloc(g->n * sizeof(Node)); + swapGain = malloc(g->n * sizeof(int)); + nbSubtrees = malloc(g->n * sizeof(int)); + swapLength = malloc(g->n * sizeof(int)); + swapDepth = malloc(g->n * sizeof(int)); + nbDeeperN = malloc(g->n * sizeof(int)); + swapsVertices = malloc(g->n * sizeof(int)); + correspondent = malloc(g->n * sizeof(int)); + dependentSubtrees = malloc(g->n * sizeof(Node)); + lastAncestor = malloc(g->n * sizeof(Node)); + dateLastAncestor = calloc(g->n, sizeof(int)); + neighborsAreSorted = calloc(g->n, sizeof(int)); + dateNodesSet = calloc(g->n, sizeof(int)); + datePulledUp = calloc(g->n, sizeof(int)); + swapsHeap = allocHeap(g->n, compareSwaps); +} + + + +int newVersionSearchingAboveFirstCriticalNode = 1; + + +Node makeSwapsInCriticalBranch(Node root, Graph g) { + int nbPUpRestarts = 0; + + if (criticalBranch == NULL) allocForSwaps(g); + + int trace = 0; + + // updateNbDeeperNeighbors(nbDeeperN, g); + //freeSetsOfNodes(theNodes, g->n); + updateDepthsAndHeights(root, 0, 0); + + if (pullUpIndependentSubtrees) { + PULL_UP: + + root = pullUpIndependentSubtreesInTree(root, g); + +#ifdef NOTDEF + date ++; + + while (1) { + int prevHeight = root->height; + // criticalNode = markCriticalBranch(root, date, 1, g); + Node deepest = leftmostDeepestNode(root); + int nbPullUp = pullUpIndependentSubtreesInTheBranch(root, deepest, date, g); + if ((clock()-startTime)/CLOCKS_PER_SEC >= time_limit) stopSearch = 1; + if (stopSearch) break; + if (nbPullUp <= 0) break; + updateDepthsAndHeights(root, 0, 0); // Useless ? + if (trace) printf("nbPU=%d %d --> %d\n", nbPullUp, prevHeight, root->height); + } +#endif + + updateBestDecomposition(root, g); + } + + if (stopSearch) return root; + + if ( ! searchSwapsInCriticalBranch) + goto TERMINATE; + + int nbSwapsCompleted = 0; + int height = root->height; + while (1) { + date ++; + + criticalNode = markCriticalBranch(root, date, 0, g); // sort neighbors on critical branch, built set of nodes for criticalNode + + if (stopSearch) break; + + //updateDepthsAndHeights(root, 0, 0); + + int nbSwaps = listSwaps(root, date, maxSwaps, maxSwapsSearches, g); + + if (nbSwaps == 0) break; + + if (stopSearch) break; + + if (nbSwaps > 0) { + nbSwapsCompleted ++; + if (justSwapBestSwap) { + root = swapCriticalNode(root, bestNode, theNodes[correspondent[bestNode->vertex]], g); + } + else { + nbSwaps = selectSwaps(swapsVertices, correspondent, nbSwaps, lenMin + 120 * root->height / 100); + if (0) + root = swapCriticalNode(root, theNodes[swapsVertices[0]], theNodes[correspondent[swapsVertices[0]]], g); + else + root = makeSwaps(root, nbSwaps, g); + } + } + + updateDepthsAndHeights(root, 0, 0); + + updateBestDecomposition(root, g); + + if (stopSearch) break; + // if (root->height == height) break; // stop loop modified 2/05/2020 + } + + if (root->height < height) nbPUpRestarts = 0; + + if (nbSwapsCompleted > 0) { if (nbPUpRestarts ++ < maxMakeSwapsRestarts) goto PULL_UP; } + + if (trace) printf("terminate swaps %.1fs\n", (float) (clock()-startTime)/CLOCKS_PER_SEC); + + //printf("nbPUpRestarts = %d\n", nbPUpRestarts); + TERMINATE: + //verifyDecomposition(root, g); + //printf("swaps : %d --> %d\n", height0, root->height); + freeSetsOfNodes(theNodes, g->n); + + return root; +} + + + + + + + + + +// Select swaps so as there is no overlappings +int selectSwaps(int *nodes, int *corr, int nb, int maxLen) { + resetHeap(swapsHeap); + for (int i = 0; i < nb; i ++) + heapJustAdd(swapsVertices[i], swapsHeap); + makeHeap(swapsHeap); + + // Select swaps that are independent, that is the node of the second is deeper than the destination of the first one + swapsVertices[0] = swapsHeap->val[0]; + int n = 1; + int maxDepth = swapDepth[swapsVertices[0]]; + for (int i = 1; i < nb; i ++) + //if (theNodes[swapsVertices[i]]->depth >= maxDepth) + if (swapDepth[swapsHeap->val[i]] - swapLength[swapsHeap->val[i]] >= maxDepth) { + //int v = swapsHeap->val[i]; + //if (theNodes[v]->depth != swapDepth[v] - swapLength[v]) printf("node depth=%d swap depth=%d\n", theNodes[v]->depth, swapDepth[v] - swapLength[v]); + swapsVertices[n] = swapsHeap->val[i]; + maxDepth = swapDepth[swapsVertices[n]]; + n ++; + } + return n; +} + + + +#define SEARCH_FROM_ROOT + +int listSwaps(Node root, int date, int maxSwaps, int maxSearches, Graph g) { + + gainMax = 0; + lenMin = g->n+1; + int nbSwaps = 0; + int maxHeight; + +#ifdef SEARCH_FROM_ROOT + int depth = 0; + for (Node node = root; node != criticalNode; node = node->fbs, depth++) +#else + int depth = criticalNode->depth-1; + for (Node node = criticalNode->father; node != NULL; node = node->father, depth--) +#endif + { + if (maxSearches -- == 0) break; + + Node cc = searchCriticalCorrespondant(node, &maxHeight, date, 0, g); + + int gain; + + if (cc != NULL) { + gain = root->height - (maxHeight + 1 + cc->depth); + + if (gain <= 0) continue; + + if (gain > gainMax) { + gainMax = gain; + bestNode = node; + } + + swapGain[node->vertex] = gain; + swapLength[node->vertex] = cc->depth - node->depth; + swapDepth[node->vertex] = cc->depth; + if (swapLength[node->vertex] < lenMin) lenMin = swapLength[node->vertex]; + swapsVertices[nbSwaps] = node->vertex; + correspondent[node->vertex] = cc->vertex; + nbSwaps ++; + if (nbSwaps == maxSwaps) break; + } + + if ((clock()-startTime)/CLOCKS_PER_SEC >= time_limit) stopSearch = 1; + if (stopSearch) return 0; + } + return nbSwaps; +} + + + + +int nbIgnoredSwaps; + +Node makeSwaps(Node root, int nbSwaps, Graph g) { + + int moved[g->n]; // mark moved nodes, in case the node to move had get new children + + for (int i = 0; i < nbSwaps; i ++) + moved[swapsVertices[i]] = 0; + + nbIgnoredSwaps = 0; + for (int i = 0; i < nbSwaps; i ++) { + if (moved[swapsVertices[i]]) continue; + moved[correspondent[swapsVertices[i]]] = 1; + + root = swapCriticalNode(root, theNodes[swapsVertices[i]], theNodes[correspondent[swapsVertices[i]]], g); + + if ((clock()-startTime)/CLOCKS_PER_SEC >= time_limit) { + stopSearch = 1; + return root; + } + if (changeCriticalNode) break; + break; + } + //printf("nbSwaps=%d ignored=%d\n", nbSwaps, nbIgnoredSwaps); + return root; +} + + + +// Depths and heights are ok for critical nodes, not for the other nodes + + +Node swapCriticalNode(Node root, Node node, Node cc, Graph g) { + //int vertex = node->vertex; + Node father = node->father; + Node substitute = node->fbs; + Node p; + + nbCallsSwapNode ++; + + int trace = 0; + + if (with_assertions) assert(cc != node); + if (cc == node) return root; + + if (trace) printf("swap %d@%d h%d -- %d@%d h%d (h=%d)\n", + node->vertex, node->depth, node->height, cc->vertex, cc->depth, cc->height, root->height); + + // 1. list dependent subtrees of node and remove them + int bidon; + searchCriticalCorrespondant(node, &bidon, date, 1, g); // with store=1, to build dependentSubtrees[] + // dependentSubtrees contains all the subtrees to move, snatch them from the tree (also the children of node) + for (Node *p = dependentSubtrees; *p != NULL; p ++) + justRemoveChild(*p); + + // 2. remove node and substitute to node its critical child + if (node != root) { + father->fbs = substitute; + Node last = substitute; + while (last->next != NULL) { //last->depth --; + last->father = father; last = last->next; } + last->father = father; + //last->depth --; + if (node->next != NULL) { + last->next = node->next; + last = last->next; + while (last != NULL) { last->father = father; last = last->next; } + node->next = NULL; + } + } else { // substitute becomes the root, its siblings are new children + root = substitute; + substitute->father = NULL; + Node last = substitute->fbs; + while (last->next != NULL) { //last->depth --; + last = last->next; } + //last->depth --; + if (substitute->next != NULL) { + last->next = substitute->next; + last = last->next; + while (last != NULL) { last->father = substitute; last = last->next; } + substitute->next = NULL; + } + } + + // 3. Add subtrees as children of node. Update node height + resetNode(node); + for (Node *p = dependentSubtrees; *p != NULL; p ++) + addChild(*p, node); + + // 4. Attach node to the tree under its critical correspondent + if (with_assertions) assert(cc->fbs != NULL); + node->next = cc->fbs->next; + cc->fbs->next = node; + node->father = cc; + node->depth = cc->depth+1; + + + + + // 4. update heights, depths and sets of nodes + + // heights :: normally only the height of p and the heights from father to root can change. + // depths :: on the critical branch the depths loose one for all the nodes under father (correspondent comprised), + // and the depth of node becomes depth(corresp)+1, and its subtrees can also be updated (what is the usefulness of depth ?) + + changeCriticalNode = (node->height + 1 >= cc->height); + + // update depth on portion of critical branch criticalNode-cc + p = criticalNode; + while (p != cc) { + p->depth --; + p = p->father; + } + + // p=cc, cc update + if (p->height < node->height+1) p->height = node->height+1; + p->depth --; + p = p->father; + + // update depth and heights for nodes between cc and father + while (p != father) { + p->depth --; + if (p->height < p->fbs->height+1) initializeHeight(p); + p = p->father; + } + + // nodes from father to root have smaller heights + while (p != NULL) { + p->height --; + if ( ! changeCriticalNode) { + // verify that there is not another child with max height, in which case the critical node changes + Node q = p->fbs->next; + while (q != NULL) { + if (q->height + 1 == p->height) changeCriticalNode = 1; + q = q->next; + } + } + p = p->father; + } + + if (with_assertions) { + if (father == NULL) assert(root->depth == 0); + else assert(substitute->depth == father->depth+1); + } + + if (trace) { + //printTree(father); + printf("AFTER swap %d@%d h%d -- %d@%d h%d father %d@%d h%d\n", node->vertex, node->depth, node->height, + cc->vertex, cc->depth, cc->height, father->vertex, father->depth, father->height); + } + return root; +} + + + + + + + +// search the bottom node of the critical path (path from root such that each node has a uniq critical child) +// Mark the nodes of the critical branch with the given date +Node markCriticalBranch(Node root, int date, int single, Graph g) { + Node p = root; + Node the = NULL; + int height = root->height; + int depth = 0; // the number of levels is depth+1 + int nbCritical; + + lengthCB = 0; + + while (1) { + Node q = p->fbs; + Node pred, thePred; + nbCritical = 0; + + p->depth = depth; + p->date = date; + if (with_assertions) assert(p->height == height); + + free (p->nodes); + p->nodes = NULL; + + criticalBranch[lengthCB++] = p; + + if ( ! neighborsAreSorted[p->vertex]) { + int *list = g->slists[p->vertex]; + Introsort(list, list, list + g->nadj[p->vertex] - 1); + neighborsAreSorted[p->vertex] = 1; + } + + the = NULL; + while (q != NULL) { + if (q->height == height - 1) { + nbCritical++; + the = q; + thePred = pred; + } + pred = q; + q = q->next; + } + + if ((single && (nbCritical != 1)) || (the == NULL)) + break; + + if (the != p->fbs) { + // the is positionned as first child + thePred->next = the->next; + the->next = p->fbs; + p->fbs = the; + } + + p = the; + height--; + depth++; + } + + depthCC = depth; + + if (0) if ( ! newVersionSearchingAboveFirstCriticalNode) { + if (p->nodes == NULL) p->nodes = allocSet(g->n); + else clearSet(p->nodes); + exploreAndBuildSetOfNodes(p, p->nodes); + } + + if ( ! neighborsAreSorted[p->vertex]) { + int *list = g->slists[p->vertex]; + Introsort(list, list, list + g->nadj[p->vertex] - 1); + neighborsAreSorted[p->vertex] = 1; + } + + return p; // p is the deepest node of the critical branch +} + + +int verifyCriticalBranch(Node root, Node cc, int date, Graph g) { + Node p = root; + Node the = NULL; + int height = root->height; + int depth = 0; // the number of levels is depth+1 + int nbCritical; + + while (1) { + Node q; + nbCritical = 0; + + if (p->height != height) printf("critical branch : height not good : %d (%d)\n", p->height, height); + if (p->depth != depth) printf("critical branch : depth not good : %d (%d)\n", p->depth, depth); + p->depth = depth; + p->date = date; + + q = p->fbs; + while (q != NULL) { + if (q->height == height - 1) { + nbCritical++; + the = q; + } + q = q->next; + } + + if (nbCritical != 1) { + if (p != cc) printf("critical branch : %d@%d is not critical (%d@%d is)\n", cc->vertex, cc->depth, p->vertex, p->depth); + break; + } + + if (the != p->fbs) { + printf("critical branch : critical node %d@%d is not first child\n", the->vertex, the->depth); + } + + p = the; + height--; + depth++; + } + height = p->height; + updateHeights(p); + if (p->height != height) printf("critical branch : critical node %d@%d h%d had wrong height %d\n", p->vertex, p->depth, p->height, height); + + return 1; // p is the deepest node of the critical branch +} + + + + + +// Calculate the lowest node of the critical path such that under this node there is no neighbors of node +Node searchCriticalCorrespondant(Node node, int *maxHeight, int date, int store, Graph g) { +// Node searchCriticalCorrespondant(Node node, int treeHeight, int gainMin, int *maxHeight, int date, int store, Graph g) { + int vertex = node->vertex; + int maxHeightDepSubtree = 0; // the maximal height of the subtrees that are dependent with vertex + + Node *ccc = dependentSubtrees; + Node cc = NULL; + for (int *p = g->lists[vertex]; *p != NONE; p ++) { + Node ngb = theNodes[*p], the; + + if (stopSearch) return NULL; + + if ((ngb->date == date) && (ngb->depth < node->depth)) continue; + + if (ngb->date == date) {// on the critical branch, deeper than node + if ((cc == NULL) || (ngb->depth > cc->depth)) + cc = ngb; + } + else { + // discover a subtree containing a neighbor of node. + if (dateLastAncestor[*p] != date) { + lastAncestor[*p] = criticalAncestor(ngb, date); // highest non critical ancestor (his father is on the critical branch) + dateLastAncestor[*p] = date; + } + the = lastAncestor[*p]; + if ((store) && (the->date != -date)) { // Must store the. -date helps not adding the same node twice + *ccc ++ = the; + the->date = -date; + } + if ((cc == NULL) || (the->father->depth > cc->depth)) + cc = the->father; + + if (the->height > maxHeightDepSubtree) + maxHeightDepSubtree = the->height; + } + // if (cc->depth + maxHeightDepSubtree + gainMin >= treeHeight) return NULL; + } + *ccc = NULL; + *maxHeight = maxHeightDepSubtree; + return cc; +} + + + + + + + + + + + diff --git a/pace-2020/swaps.h b/pace-2020/swaps.h new file mode 100644 index 0000000000000000000000000000000000000000..44e78a22a87855f6baa6f75fa106e9e6730a659c --- /dev/null +++ b/pace-2020/swaps.h @@ -0,0 +1,27 @@ +// +// Created by Stephane on 08/04/2020. +// + +#ifndef SGA_CRITICAL_PATH_H +#define SGA_CRITICAL_PATH_H + +#include "graph.h" +#include "tree.h" +#include "sets.h" + + + + +extern int nbCallsSwapNode; + +Node makeSwapsInCriticalBranch(Node root, Graph g); +int listSwaps(Node root, int date, int maxSwaps, int maxSearches, Graph g); +Node makeSwaps(Node root, int nbSwaps, Graph g); +int selectSwaps(int *nodes, int *corr, int nb, int maxLen); +Node swapCriticalNode(Node root, Node node, Node cc, Graph g); +int evaluateSwap(Node node, Node cc, Graph g); +Node markCriticalBranch(Node root, int date, int single, Graph g); +int verifyCriticalBranch(Node root, Node cc, int date, Graph g); +Node searchCriticalCorrespondant(Node node, int *maxHeight, int date, int store, Graph g); + +#endif //SGA_CRITICAL_PATH_H diff --git a/pace-2020/tree.c b/pace-2020/tree.c new file mode 100644 index 0000000000000000000000000000000000000000..0e5752ac703746d232f5f38b4f7a6d9f4a4dd14d --- /dev/null +++ b/pace-2020/tree.c @@ -0,0 +1,906 @@ +// +// Created by Stephane on 10/03/2020. +// + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> + +#include "decompose.h" +#include "graph.h" +#include "tree.h" +#include "sets.h" +#include "utils.h" + + + + +Node newNode(int vertex, Graph g) { + Node v = malloc(sizeof(struct node)); + v->vertex = vertex; + v->height = 0; + v->nbhmax = 0; + v->next = v->prev = v->fbs = v->lbs = NULL; + v->father = NULL; + v->nodes = NULL; //allocSet(g->n); + v->depth = 0; + v->date = 0; + return v; +} + + +void resetNode(Node p) { + p->fbs = p->lbs = p->next = p->prev = p->father = NULL; + p->height = 1; + p->nbhmax = 0; + //VideSet(p->nodes); +} + + +// Calculate the height for this node, returns true if height has been modified +int initializeHeight(Node p) { + int h = p->height; + p->height = 1; + Node q = p->fbs; + p->nbhmax = 0; + while (q != NULL) { + if (p->height < q->height+1) { p->height = q->height+1; p->nbhmax = 1; } + else if (p->height == q->height+1) p->nbhmax ++; + q = q->next; + } + return (p->height != h); +} + + +// Update heights and number of children with max height for all the nodes +void updateHeights(Node root) { + Node q = root->fbs; + while (q != NULL) { + updateHeights(q); + q = q->next; + } + initializeHeight(root); +} + +// Update depths +void updateDepths(Node p, int depth) { + p->depth = depth; + Node q = p->fbs; + while (q != NULL) { + updateDepths(q, depth + 1); + q = q->next; + } +} + +// prepare improvement: set depths and heights and free nodes sets for all nodes of the subtree +void updateDepthsAndHeights(Node p, int depth, int verbose) { + int height = 1; + + if (verbose && (p->depth != depth)) printf("depth node %d : %d -> %d\n", p->vertex, p->depth, depth); + p->depth = depth; + + Node q = p->fbs; + while (q != NULL) { + updateDepthsAndHeights(q, depth + 1, verbose); + if (q->height+1 > height) height = q->height+1; + q = q->next; + } + + if (verbose && (p->height != height)) printf("height node %d : %d -> %d\n", p->vertex, p->height, height); + p->height = height; + +} + + +void updateDepthsInCriticalBranch(Node p, int depth, Node end) { + while (1) { + p->depth = depth; + if (p == end) + break; + p = p->fbs; + depth ++; + } +} + + +void sortNeighborsInBranch(Node p, Graph g) { + while (p != NULL) { + int *list = g->lists[p->vertex]; + Introsort(list, list, list+g->nadj[p->vertex]-1); + p = p->father; + } +} + + + +int nbNeighborsAbove(Node node, Graph g) { + int *N = g->slists[node->vertex]; + int nN = g->nadj[node->vertex]; + int nb = 0; + + Node p = node->father; + while (p != NULL) { + if (isInSet(p->vertex, NULL, N, nN)) + nb ++; + p = p->father; + } + return nb; +} + +// Returns the leftmost deepest node +Node leftmostDeepestNode(Node root) { + Node p = root; + while (1) { + Node q = p->fbs; + while (q != NULL) { + if (q->height+1 == p->height) + break; + q = q->next; + } + if (q == NULL) return p; + p = q; + } +} + + +// the first ancestor whose father is marked with date (that is which is a node of the critical branch) +Node criticalAncestor(Node p, int date) { + while (p != NULL) { + if (p->father->date == date) break; + p = p->father; + } + return p; +} + + +void updateNbDeeperNeighbors(int nbDeeperN[], Graph g) { + for (int i = 0; i < g->n; i ++) { + nbDeeperN[i] = 0; + for (int *p = g->lists[i]; *p != NONE; p ++) + if (theNodes[*p]->depth > theNodes[i]->depth) + nbDeeperN[i] ++; + } +} + + + +// Count at each level the number of critical nodes +void exploreMakeStats(Node node, int depth, int nbCritical[], int *max) { + Node q = node->fbs; + while (q != NULL) { + if (q->height+1 == node->height) + exploreMakeStats(q, depth+1, nbCritical, max); + q = q->next; + } + nbCritical[depth] ++; + if (*max < depth) *max = depth; +} + +int makeStatsCriticalNodes(Node node, int nbCritical[]) { + int max = 0; + for (int i = 0; i < node->height; i ++) + nbCritical[i] = 0; + exploreMakeStats(node, 0, nbCritical, &max); + return max; +} + + + +// update height after insertion of a new child or increase of the height of a child +int incHeightNodeUpdate(Node node, int height) { // node gets height among its children + if (node->height < height+1) { + node->height = height+1; + node->nbhmax = 1; + return 1; + } + if (node->height == height+1) node->nbhmax ++; + return 0; +} + +// update height after removal of a child or decrease of the height of a child +int decHeightNodeUpdate(Node node, int height) { // node looses height among its children + if (node->height == height+1) { + if (node->nbhmax-- == 1) + if (initializeHeight(node)) + return 1; + } + return 0; +} + + + +// p looses a child of height height (removal or height decrease). +// Update p and propagate above if necessary. +void updateDecHeightOnBranch(Node p, int height) { + while (p != NULL) { + if ( ! decHeightNodeUpdate(p, height)) + break; + p = p->father; + height ++; + } +} + +void forceUpdateDecHeightOnBranch(Node p, int height) { + while (p != NULL) { + decHeightNodeUpdate(p, height); + p = p->father; + height ++; + } +} + + +// New child or child height increase +void updateIncHeightOnBranch(Node p, int height) { + while (p != NULL) { + if ( ! incHeightNodeUpdate(p, height)) + break; + p = p->father; + height ++; + } +} + + +// insert node at last position in the list of children +void addChild(Node p, Node father) { + + p->next = NULL; + p->father = father; + + if (father->fbs == NULL) { + father->fbs = father->lbs = p; + p->prev = NULL; + } + else { + father->lbs->next = p; + p->prev = father->lbs; + father->lbs = p; + } + // updateIncHeightOnBranch(father, p->height); abandoned, it is better to update only once + incHeightNodeUpdate(father, p->height); +} + + + +void addChildOLD(Node p, Node father) { + p->next = father->fbs; + if (father->fbs != NULL) father->fbs->prev = p; + p->prev = NULL; + father->fbs = p; + p->father = father; + // updateIncHeightOnBranch(father, p->height); abandoned, it is better to update only once + incHeightNodeUpdate(father, p->height); +} + + +int removeChild(Node p, Node father) { + if (father->fbs == p) { + father->fbs = p->next; + if (p->next != NULL) p->next->prev = NULL; + else father->lbs = NULL; + } + else { + p->prev->next = p->next; + if (p->next != NULL) p->next->prev = p->prev; + else father->lbs = p->prev; + } + //updateDecHeightOnBranch(father, p->height); abandoned, it is better to update only once + return decHeightNodeUpdate(father, p->height); +} + +// Suppose father exists !! +void justRemoveChild(Node node) { + Node father = node->father; + if (node == father->fbs) + father->fbs = node->next; + else { + Node p = father->fbs; + while (p->next != node) + p = p->next; + p->next = node->next; + } +} + + +void addSibling(Node p, Node sibling) { + assert(sibling != NULL); + Node next = sibling->next; + + p->next = next; + if (next != NULL) next->prev = p; + sibling->next = p; + p->prev = sibling; + + p->father = sibling->father; + if (p->father != NULL) + incHeightNodeUpdate(p->father, p->height); +} + +void connectSiblings(Node u, Node v) { + u->next = v; + v->next = NULL; + u->prev = NULL; + v->prev = u; +} + +void connect3Siblings(Node u, Node v, Node w) { + u->next = v; + v->next = w; + w->next = NULL; + u->prev = NULL; + v->prev = u; + w->prev = v; +} + + +Node bottomNode; + +Node makeSingleBranch(int S[], int n, int nbNInAB[], Graph g) { + // put at bottom those which have the fewer neighbors in A and B + + if (1 && nbNInAB != NULL) + QSort1(S, nbNInAB, 0, n-1); + + if (n == 0) + return NULL; + + Node node, father; + + bottomNode = node = theNodes[S[0]]; + resetNode(bottomNode); + + for (int i = 1; i < n; i ++) { + father = theNodes[S[i]]; + resetNode(father); + addChild(node, father); + node = father; + } + + return node; +} + +// Make a single branch with nodes S[nbDV],...,S[n-1] with independent children S[0],...,S[nbDV-1] +Node makeSingleBranchWithDisconnectedVertices(int *S, int n, int nbDV, Graph g) { + + if (n == 0) + return NULL; + + Node node, father; + + if (n == nbDV) nbDV --; + + bottomNode = node = theNodes[S[nbDV]]; + resetNode(bottomNode); + + for (int i = 0; i < nbDV; i ++) { + Node child = theNodes[S[i]]; + resetNode(child); + addChild(child, node); + } + + for (int i = nbDV+1; i < n; i ++) { + father = theNodes[S[i]]; + resetNode(father); + addChild(node, father); + node = father; + } + + return node; +} + + + + +// +// Modifications +// + + +void printChildren(Node node) { + Node p = node->fbs; + printf("(%d) :: ", node->vertex); + while (p != NULL) { + printf("%d(%d),", p->vertex, p->father->vertex); + p = p->next; + } + printf("\n"); +} + + + +// pull up the node p. Then p becomes a child of its grandfather +int pullUp(Node p) { + Node father = p->father; + assert(father != NULL); + Node gfather = father->father; + assert(gfather != NULL); + int hbefore = gfather->height; + int trace = 0; + + if (trace) { printf("\npull up %d:h=%d father=%d gfather=%d \n", p->vertex, p->height, father->vertex, gfather->vertex);printTree(gfather); } + + int prevHeight = father->height; + if (removeChild(p, father)) + decHeightNodeUpdate(gfather, prevHeight); // indeed gfather height is perhaps not good here + + if (trace) { printf("pull up :: after remove %d :: father=%d gfather=%d\n", p->vertex, father->vertex, gfather->vertex);printTree(gfather);} + + addChild(p, gfather); + + if (trace) { printf("pull up :: after addChild :: father=%d gfather=%d \n", father->vertex, gfather->vertex);printTree(gfather); } + //printf(" ---> %d:h=%d father=%d gfather=%d\n", p->vertex, p->height, father->vertex, gfather->vertex); + + return (gfather->height != hbefore); +} + + + +// +// Forks: from a node u, the longest branch such that each node has a uniq child dependent with u +// +// Goal: the fork is not a critical node, but there are critical nodes on the path. +// Then, pushing down the source node as a child of the fork has as effect to pull up all subtrees +// connected on the path, in particular those that were critical. +Node theFork; // the fork +int forkIsCritical; // if the fork is a critical node, that is some leaves are at the maximal depth +Node theFirstSon; // the first dependent son in the branch +Node *dependentChildren = NULL; // The children of the fork that are dependent with the source node +int delta = 0; // Depth difference between nodes under the fork and the other nodes of the subtree +// If delta=1 the swap has no effect on the height of the subtree. If delta>1 the height decreases of 1. +int maxDepthForkSwaps = 33; // under this depth abandon +Node theRoot; +int searchSomeSwapsAtRandom = 1; + +void searchForksSwaps(Node root, Graph g, int maxdepth) { + theRoot = root; + maxDepthForkSwaps = maxdepth; + //while (exploreAndSearchForks(root, 0, g)) + exploreAndSearchForks(root, 0, g); + { + if (!verifyTree(root, 0)) {printf("swap fork error 00: node u\n"); exit(0); } + } +} + +// NOTE:: it is not necessary to search the fork, it is sufficient to swap whenever delta > 1 + +int exploreAndSearchForks(Node node, int depth, Graph g) { + int len; + + if (dependentChildren == NULL) dependentChildren = malloc(g->n* sizeof(Node)); + + if (node->fbs == NULL) return 0; + + if (node->father != NULL) { + //printf("[%d] search fork for %d h=%d :\n", depth, node->vertex, node->height); + len = searchFork(node, g); + if ( (delta > 1) || ((delta == 1) && (rand()%2)) ) { + printf("[%d] fork swap h_u=%d h_fork=%d len=%d* delta=%d\n", depth, node->height, theFork->height, len, delta); + swapFork(node, theFork, g); + return 1; + } + //else printf("[%d] %d l=%d\n", depth, node->vertex, len); + } + + if (depth > maxDepthForkSwaps) + return 0; + + Node p = node->fbs; + while (p != NULL) { + if (p->height == node->height-1) { // ignore non critical nodes + exploreAndSearchForks(p, depth + 1, g); + //if ( ! exploreAndSearchForks(p, depth + 1, g)) return 0; + } + p = p->next; + } + return 1; +} + +// Search the fork. delta is the difference of maximal depth considering just the nodes of +// the fork or all the nodes of the subtree u +int searchFork(Node u, Graph g) { + int len = 0, nbdep; + Node the; + int trace = 0; + + theFork = u; + forkIsCritical = 1; // u is a critical node + theFirstSon = NULL; + delta = 0; + + while (1) { + Node q = theFork->fbs; + nbdep = 0; + + while (q != NULL) { + if ( ! independent(u->vertex, q, g)) { + dependentChildren[nbdep] = q; + nbdep++; + the = q; + if (q->height+1 < theFork->height) forkIsCritical = 0; + } + q = q->next; + } + dependentChildren[nbdep] = NULL; + + if (nbdep == 0) return -len; + + if (nbdep > 1) return len; + + if (trace) printf("the=%d h_the=%d\n", the->vertex, the->height); + + // A uniq dependent child, its height is the->height, delta is the difference + // between its height and the height of its father +1. If 0 this means that the is a + // critical node. + delta += (theFork->height-1-the->height); + if (theFirstSon == NULL) theFirstSon = the; + theFork = the; + len ++; + } + return 0; +} + + + +// Push down the source node as a child of the fork. Children of the fork that are dependent with the +// source node are pushed down as children of the source. Suppose that u is not fork and not root. +int nbSwaps = 0; + +Node swapFork(Node u, Node fork, Graph g) { + assert(u != fork); + assert(u->father != NULL); // this particular case should be considered a part (u must have a uniq son) + Node father = u->father; + int heightFather = father->height; + + nbSwaps ++; + + // remove u from father children + removeChild(u, father); + +// updateHeights(father); +// printf("father height 1 : %d --> %d\n", heightFather, father->height); + + // pull up u children (even theFirstSon) + Node q = u->fbs; + while (q != NULL) { + Node next = q->next; + removeChild(q, u); + addChild(q, father); + q = next; + } + // here u has no child + +// updateHeights(father); +// printf("father height 2 : %d \n", father->height); + int forkHeight = fork->height; + + // transfer fork children that are dependent with u, as new children of u + //resetNode(u); + //u->fbs = NULL; //p->lbs = p->next = p->prev = p->father = NULL; + //u->height = 1; + //u->nbhmax = 0; + + if (1) for (Node *pp = dependentChildren; *pp != NULL; pp++) { + removeChild(*pp, fork); + addChild(*pp, u); + } + + if (0) { + q = fork->fbs; + resetNode(u); + while (q != NULL) { + Node next = q->next; + if (!independent(u->vertex, q, g)) { + removeChild(q, fork); + addChild(q, u); + } + q = next; + } + } + + + //updateHeights(father); + //printf("father height 3 : %d \n", father->height); + + // Add u as a child of fork + addChild(u, fork); + + //updateHeights(father); + //printf("father height 4 : %d \n", father->height); + + Node root; + while (u != NULL) { + root = u; + initializeHeight(u); + u = u->father; + } + if (!verifyTree(root, 0)) {printf("swap fork error 1: node u\n"); exit(0); } + + //printf("father height :: %d --> %d\n", heightFather, father->height); + + if (heightFather < father->height) { + printTree(father); + exit(0); + } + + if (0) { + // Update... + printf("updating: \n"); + printf(" u:%d h=%d\n", u->vertex, u->height); + printf(" fork:%d h=%d\n", fork->vertex, fork->height); + printf(" father:%d h=%d\n", father->vertex, father->height); + if (father->father != NULL) + printf(" father->father:%d h=%d\n", father->father->vertex, father->father->height); + + initializeHeight(u); + initializeHeight(fork); + if (fork->height != forkHeight) { + updateIncHeightOnBranch(fork->father, fork->height); + } + if (!verifyTree(u, 0)) printf("swap fork verify 1: node u\n"); + + initializeHeight(father); + if (father->height < heightFather) + updateDecHeightOnBranch(father->father, heightFather); + + printf(" u:%d h=%d\n", u->vertex, u->height); + printf(" fork:%d h=%d\n", fork->vertex, fork->height); + printf(" father:%d h=%d\n", father->vertex, father->height); + if (father->father != NULL) + printf(" father->father:%d h=%d\n", father->father->vertex, father->father->height); + + if (!verifyTree(u->father, 0)) printf("swap fork verify 2: u->father\n"); + if (!verifyTree(father, 0)) printf("swap fork verify 3: root\n"); + if ((father->father != NULL) && (!verifyTree(father->father, 0))) printf("swap fork verify 4: root->father\n"); + } + + return father; +} + + + +// +// Independent subtrees: computation +// + +int indpdNbCalls = 0; + +SET nodesInSubtrees = NULL; + +void makeNodesInSubtrees(Node node) { + Node p = node->fbs; + while (p != NULL) { + makeNodesInSubtrees(p); + p = p->next; + } + ADDe(node->vertex, nodesInSubtrees); +} + + +int independent(int v, Node tree, Graph g) { + + indpdNbCalls++; + + if (nodesInSubtrees == NULL) nodesInSubtrees = allocSet(g->n); + + clearSet(nodesInSubtrees); + makeNodesInSubtrees(tree); + + LIST p = g->adj[v]; + while (p != NULL) { + if (IN(p->val, nodesInSubtrees)) + return 0; + p = p->suiv; + } + return 1; +} + + +// +// Sets of nodes (for swap in critical branches) +// + + +void makeAllSetsOfNodes(Node node, Graph g) { + Node q = node->fbs; + while (q != NULL) { + makeAllSetsOfNodes(q, g); + q = q->next; + } + if (node->nodes == NULL) node->nodes = allocSet(g->n); + else clearSet(node->nodes); + q = node->fbs; + while (q != NULL) { + addSet(q->nodes, node->nodes); + q = q->next; + } +} + + +// Construct sets of nodes for a given node, and for its children, suppose children sets do not exist +void exploreAndBuildSetOfNodes(Node p, SET V) { + ADDe(p->vertex, V); + Node q = p->fbs; + while (q != NULL) { + exploreAndBuildSetOfNodes(q, V); + q = q->next; + } +} + +void buildSetOfNodes(Node p, Graph g) { + + if (p->nodes != NULL) return; + + p->nodes = allocSet(g->n); + + SET V = p->nodes; + + //clearSet(V); + ADDe(p->vertex, V); + + Node q = p->fbs; + while (q != NULL) { + if (q->nodes == NULL) { + q->nodes = allocSet(g->n); + exploreAndBuildSetOfNodes(q, q->nodes); + } + addSet(q->nodes, V); + q = q->next; + } +} + +void updateSetOfNodes(Node p, Graph g) { + + if (p->nodes == NULL) p->nodes = allocSet(g->n); + + SET V = p->nodes; + + clearSet(V); + ADDe(p->vertex, V); + + Node q = p->fbs; + while (q != NULL) { + assert (q->nodes != NULL); + addSet(q->nodes, V); + q = q->next; + } +} + + + +void freeSetsOfNodes(Node nodes[], int nb) { + + for (int i = 0; i < nb; i ++) { + free(nodes[i]->nodes); + nodes[i]->nodes = NULL; + } +} + + + +// +// Verifications +// + + +int verifyNode(Node root) { + + if (root == NULL) + return NONE; + + int height = 1; + Node p = root->fbs; + + while (p != NULL) { + if (p->height+1 > height) + height = p->height+1; + p = p->next; + } + + if (root->height != height) + return height; + return NONE; +} + +// Verify heights in nodes +int verifyTree(Node root, int depth) { + int height; + + if (root == NULL) + return 1; + + Node p = root->fbs; + int vertex; + if (p != NULL) + vertex = p->vertex; + + while (p != NULL) { + if ( ! verifyTree(p, depth+1)) + return 0; + p = p->next; + if ((p != NULL) && (p->vertex == vertex)) { + printf("children list loops !!\n"); + exit(0); + } + } + + height = verifyNode(root); + if (height != NONE) { + printf("bad height node %d at depth %d : height is %d should be %d\n", root->vertex, depth, root->height, height); + return 0; + } + + return 1; +} + + +void exploreAndPrint(Node node, int depth) { + for (int i = 0; i < depth; i ++) printf(" -"); + printf("[%d:%dx%d]\n", node->vertex, node->height, node->nbhmax); + Node p = node->fbs; + if (p == NULL) + return; + //printf("("); + while (p != NULL) { + exploreAndPrint(p, depth+1); + p = p->next; + if (p != NULL) printf(","); + } + //printf(")"); +} + +void printTree(Node node) { + exploreAndPrint(node, 0); + printf("\n"); +} + + +int sizeForest(Node node) { + int nb = 0; + while (node != NULL) { + nb += 1+ sizeForest(node->fbs); + node = node->next; + } + return nb; +} + + +int sizeTree(Node node) { + if (node == NULL) return 0; + int nb = 1; + Node p = node->fbs; + while (p != NULL) { + nb += sizeTree(p); + p = p->next; + } + return nb; +} + + + +int treeContains(int e, Node p) { + if (p == NULL) return 0; + if (p->vertex == e) return 1; + for (Node q = p->fbs; q != NULL; q = q->next) + if (treeContains(e, q)) + return 1; + return 0; +} + +int treeContainsNeighbors(int v, Node tree, Graph g) { + int nb = 0; + for (int *p = g->lists[v]; *p != NONE; p ++) + if (treeContains(*p, tree)) + nb ++; + return nb; +} + + + + + + + + + + + + diff --git a/pace-2020/tree.h b/pace-2020/tree.h new file mode 100644 index 0000000000000000000000000000000000000000..8c590009a081f21817a403bdb9ad50781c04cfbb --- /dev/null +++ b/pace-2020/tree.h @@ -0,0 +1,88 @@ +// +// Created by Stephane on 10/03/2020. +// + +#ifndef SRC_TREE_H +#define SRC_TREE_H + +#include "graph.h" +#include "sets.h" + +typedef struct node * Node; +struct node { + int vertex; + Node fbs; // first child + Node lbs; // last child + Node next; + Node prev; + Node father; + //int size; + int height; + int nbhmax; // the number of children with max height + SET nodes; + int depth; + int date; // for swaps, to mark nodes of the critical branch at this moment +}; + + + +extern Node bottomNode; + + +Node newNode(int vertex, Graph g); +void resetNode(Node p); + +int initializeHeight(Node p); +void updateHeights(Node root); +void updateDepths(Node p, int depth); +void updateDepthsAndHeights(Node p, int depth, int verbose); +void updateDepthsInCriticalBranch(Node p, int depth, Node end); +void sortNeighborsInBranch(Node p, Graph g); +int nbNeighborsAbove(Node p, Graph g); +Node leftmostDeepestNode(Node root); +Node criticalAncestor(Node p, int date); +void updateNbDeeperNeighbors(int nbDeeperN[], Graph g); +int makeStatsCriticalNodes(Node node, int nbCritical[]); + +void updateDecHeightOnBranch(Node p, int height); +void updateIncHeightOnBranch(Node p, int height); +int decHeightNodeUpdate(Node node, int height); +int incHeightNodeUpdate(Node node, int height); +void forceUpdateDecHeightOnBranch(Node p, int height); + +void addChild(Node p, Node father); +int removeChild(Node p, Node father); +void justRemoveChild(Node node); +void addSibling(Node p, Node sibling); +void connectSiblings(Node u, Node v); +void connect3Siblings(Node u, Node v, Node w); + +Node makeSingleBranch(int S[], int n, int nbNInAB[], Graph g); +Node makeSingleBranchWithDisconnectedVertices(int *S, int n, int nbDV, Graph g); + +int pullUp(Node p); + +void searchForksSwaps(Node root, Graph g, int maxdepth); +int exploreAndSearchForks(Node node, int depth, Graph g); +int searchFork(Node u, Graph g); +Node swapFork(Node u, Node fork, Graph g); + +void makeAllSetsOfNodes(Node node, Graph g); +void exploreAndBuildSetOfNodes(Node p, SET V); +void buildSetOfNodes(Node p, Graph g); +void updateSetOfNodes(Node p, Graph g); + +void freeSetsOfNodes(Node nodes[], int nb); + +int independent(int v, Node tree, Graph g); + +int verifyTree(Node root, int depth); + +void printTree(Node node); +int sizeForest(Node node); +int sizeTree(Node node); + +int treeContains(int e, Node p); +int treeContainsNeighbors(int v, Node tree, Graph g); + +#endif //SRC_TREE_H diff --git a/pace-2020/utils.c b/pace-2020/utils.c new file mode 100644 index 0000000000000000000000000000000000000000..d1af18499a29c153e57f1b21ad205034bd3e1a94 --- /dev/null +++ b/pace-2020/utils.c @@ -0,0 +1,364 @@ +// +// Created by Stephane on 10/03/2020. +// + +#include <assert.h> +#include <string.h> +#include <stdio.h> + +#include "utils.h" +#include "sets.h" + + +// choose at random a vertex from S[], with preference for those that have a big weight +int chooseWeightedRandom(int weights[], int S[], int n, int total) { + assert(total > 0); + int t = rand()%total; + int i = 0; + while (t >= weights[S[i]]) { + t -= weights[S[i]]; + i ++; + } + return S[i]; +} + + + +void copyList(int *dest, int *src, int n) { + memcpy(dest, src, n * sizeof(int)); +} + + +void printList(int S[], int n) { + for (int i = 0; i < n; i ++) printf("%d ", S[i]); + printf("\n"); +} + +void shakeList(int S[], int pos[], int n, int nSteps) { + while (nSteps -- > 0) { + int i = rand()%n; + int j = rand()%n; + swap(S, i, j); + pos[S[i]] = i; + pos[S[j]] = j; + } +} + + +int nbOccs(int x, int S[], int n) { + int nb = 0; + for (int i = 0; i < n; i ++) + if (S[i] == x) + nb ++; + return nb; +} + + +int indexMaxInList(int S[], int n) { + int imax = 0; + for (int i = 1; i < n; i ++) + if (S[i] > S[imax]) + imax = i; + return imax; +} + + +int maxInList(int S[], int n) { + int max = S[0]; + for (int i = 1; i < n; i ++) + if (S[i] > max) + max = S[i]; + return max; +} + + +// make list with elements of S[],n with value num in I[] +int extractList(int num, int S[], int n, int C[], int T[]) { + int size = 0; + for (int i = 0; i < n; i ++) { + if (C[i] == num) + T[size ++] = S[i]; + } + return size; +} + +// the vertices in S[] with num num are placed at the beginning of S +int packListLeft(int num, int S[], int n, int C[]) { + int nb = 0; + for (int i = 0; i < n; i ++) { + if (C[S[i]] == num) { + swap(S, i, nb); + nb ++; + } + } + return nb; +} + + +// move a portion of the array at the left +void copyListLeft(int S[], int start, int size) { + for (int i = 0; i < size; i ++) + S[i] = S[i+start]; +} + + + +int nbInListWithThisValue(int val, int *S, int n, int *values) { + int nb = 0; + for (int i = 0; i < n; i ++) { + if (values[S[i]] == val) nb ++; + } + return nb; +} + + + +// search in set, either a SET of a sorted list +int isInSet(int v, SET S, int T[], int n) { + + if (S != NULL) { + return IN(v, S); + } + + if (n == 0) return 0; + + int l = 0; + int r = n; + // l <= pos < r + while (l+1 < r) { + int m = (l+r)/2; + if (v >= T[m]) + l = m; + else + r = m; + } + // l+1=r and l <= pos < r + return (v == T[l]); +} + + + +// search v in the list, +int isInList(int v, int T[], int n) { + int l = 0; + int r = n; + while (l+1 < r) { + int m = (l+r)/2; + if (v >= T[m]) + l = m; + else + r = m; + } + // l+1=r and l <= pos < r + return (v == T[l]); +} + + + + + +// +// +// + + +// Introsort: the sort function of C++ STL. + + +void swap(int T[], int i, int j) { + int tmp = T[i]; + T[i] = T[j]; + T[j] = tmp; +} + +void swapValues(int *p, int *q) { + int tmp = *p; + *p = *q; + *q = tmp; +} + + +// heapify heap T[i],...,T[b-1] +void heapify(int i, int T[], int n) { + while (2*i+1 < n) { + int imin = i; + if (T[2*i+1] < T[imin]) imin = 2*i+1; + if ((2*i+2 < n) && (T[2*i+2] < T[imin])) imin = 2*i+2; + if (imin == i) break; + swap(T, i, imin); + i = imin; + } +} + +// Make a heap with elements T[a],...,T[n-1] +void make_heap(int T[], int n) { + for (int i = (n+1)/2; i >= 0; i --) { + heapify(i, T, n); + } +} + +// Sort T[a],...,T[n-1] +void sort_heap(int T[], int n) { + for (int i = n-1; i >= 1; i --) { + swap(T, 0, i); + heapify(0, T, i); + } + for (int i = 0; i < n/2; i ++) swap(T, i, n-1-i); +} + +// Sort arr[a],...,arr[b] +void InsertionSort(int S[], int a, int b) { + for (int i = a+1; i <= b; i++) { + + int key = S[i]; + int j = i-1; + while (j >= a && S[j] > key) { + S[j+1] = S[j]; + j = j-1; + } + S[j+1] = key; + } +} + + +// A function to partition the array and return the partition point +int* Partition(int arr[], int low, int high) +{ + int pivot = arr[high]; // pivot + int i = (low - 1); // Index of smaller element + + for (int j = low; j <= high-1; j++) { + // If current element is smaller than or equal to pivot + + if (arr[j] <= pivot) { + // increment index of smaller element + i++; + + swapValues(arr+i, arr+j); + } + } + swapValues(arr+i+1, arr+high); + return (arr + i + 1); +} + + +// A function that find the middle of the values pointed by the pointers a, b, c and return that pointer +int * MedianOfThree(int * a, int * b, int * c) +{ + if (*a < *b && *b < *c) + return (b); + + if (*a < *c && *c <= *b) + return (c); + + if (*b <= *a && *a < *c) + return (a); + + if (*b < *c && *c <= *a) + return (c); + + if (*c <= *a && *a < *b) + return (a); + + //if (*c <= *b && *b <= *c) + return (b); +} + +// A Utility function to perform intro sort +void IntrosortUtil(int arr[], int * begin, int * end, int depthLimit) +{ + // Count the number of elements + int size = end - begin + 1; + + // If partition size is low then do insertion sort + if (size < 16) { + InsertionSort(arr, begin-arr, end-arr); + return; + } + + // If the depth is zero use heapsort + if (depthLimit == 0) { + int n = (end-arr)+1; + make_heap(arr, n); + sort_heap(arr, n); + return; + } + + // Else use a median-of-three concept to + // find a good pivot + int * pivot = MedianOfThree(begin, begin+size/2, end); + + // Swap the values + //swap(arr, pivot-arr, end-arr); + swapValues(pivot, end); + + // Perform Quick Sort + int * partitionPoint = Partition(arr, begin-arr, end-arr); + IntrosortUtil(arr, begin, partitionPoint-1, depthLimit - 1); + IntrosortUtil(arr, partitionPoint + 1, end, depthLimit - 1); + + return; +} + + +#include <math.h> + +// Implementation of introsort: sort elements *begin,...,*end +void Introsort(int arr[], int *begin, int *end) { + + int depthLimit = (int) (2 * log(end-begin)); + + // Perform a recursive Introsort + IntrosortUtil(arr, begin, end, depthLimit); + + return; +} + + +void QSort1(int *T, int *V, int Deb, int Fin) +{ + int a, b; + + while (1) + { + a = Deb, b = Fin; + int v = V[T[(Deb+Fin)/2]]; + do + { + while (V[T[a]] < v) + a++; + while (V[T[b]] > v) + b--; + if (a <= b) { + int tmp = T[a]; + T[a] = T[b]; + T[b] = tmp; + a++, b--; + } + } + while (a <= b); + + if (b-Deb > Fin-a) { + if (Fin > a) + QSort1(T, V, a, Fin); + if (Deb < b) + Fin = b; + else + break; + } + else { + if (Deb < b) + QSort1(T, V, Deb, b); + if (Fin > a) + Deb = a; + else + break; + } + } +} + + + + + + diff --git a/pace-2020/utils.h b/pace-2020/utils.h new file mode 100644 index 0000000000000000000000000000000000000000..ce264fced94fc1fed6081fd00cacc0023ac32a61 --- /dev/null +++ b/pace-2020/utils.h @@ -0,0 +1,34 @@ +// +// Created by Stephane on 10/03/2020. +// + +#ifndef SRC_UTILS_H +#define SRC_UTILS_H + +#include "sets.h" + +#define NONE (-1) + +int chooseWeightedRandom(int weights[], int S[], int n, int total); +void copyList(int *dest, int *src, int n); +void printList(int S[], int n); +void shakeList(int S[], int pos[], int n, int nSteps); +int nbOccs(int x, int S[], int n); +int maxInList(int S[], int n); +int indexMaxInList(int S[], int n); +int extractList(int num, int S[], int n, int I[], int T[]); +int packListLeft(int num, int S[], int n, int C[]); +void copyListLeft(int S[], int start, int size); +int nbInListWithThisValue(int num, int *S, int n, int *values); + +int isInSet(int v, SET S, int T[], int n); +int isInList(int v, int T[], int n); + +void swap(int arr[], int i, int j); +void swapValues(int *p, int *q); +void Introsort(int arr[], int *begin, int *end); +void InsertionSort(int S[], int a, int b); +void QSort1(int *T, int *V, int Deb, int Fin); + + +#endif //SRC_UTILS_H