// // 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; }