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