UNPKG

aureooms-js-algo

Version:

playground for algorithmic code bricks in JavaScript

352 lines (263 loc) 10.5 kB
/** * Bichromatic dominating pairs using the divide and conquer chainsaw. * * see F. P. Preparata and M. I. Shamos, Computational Geometry, NY, 1985, p. 366. * * Here the algorithm handles non-strict ( >= ) dominance. * * select( f, a, i, j, k ) where * f is a comparator * a the array of points * [i, j[ the range to search in the array * k the index to select * * select(...) partitions the array in tree regions * ----------------------------- * | <= h | h | >= h | * ----------------------------- * i .... k k+1 .... j-1 * * __eq__( d, v ) template for a function eq( a ) * returns true iff coordinate d of a equals v * * __ne__( d, v ) template for a function ne( y ) * returns true iff coordinate d of a is not equal to v * * color( point ) * = 0 if point is blue * = 1 if point is red * * p = split( predicate, a, i, j ) * rearranges an array so that all elements for which predicate is false * are in interval [i, p[ and all other elements are in interval [p, j[ * * swap( a, ai, aj, b, bi ) * swap elements from a in interval [ai, aj[ with elements from b in interval * [bi, bi + aj - ai[ * */ let __bdpdc__ = function ( select, __eq__, __ne__, color, split, swap ) { /** * a is an array of points * * note that we only consider points starting * at index i and ending at index j-1 in a * * points are arrays of coordinates * * d = dj - di is the number of coordinates of each point * * * __f__ is a template for a function {coordinates^2} -> {<0, =0, >0} named f * * i.e. for coordinates a and b * * f( a, b ) < 0 means a < b; * f( a, b ) = 0 means a = b; * f( a, b ) > 0 means a > b. * * out is the output array * */ let bdpdc = function* ( __f__, a, i, j, di, dj ) { let k, h, x, y, p, q, m, n, _m, _n; // empty or one element array case if ( i >= j - 1 ) return ; // base case : dj - di = d = 0 // enumerate all red / blue pairs // [i, p[ contains only blue points // [p, j[ contains only red points // p = index of first red point if ( di === dj ) { // move all blue points left and all red points right // (arbitrary choice) p = split( color, a, i, j ); // for each red point for ( x = p ; x < j ; ++x ) { // for each blue point for ( y = i ; y < p ; ++y ) { yield [ a[x], a[y] ] ; } } } /** * recursion fairy * * we compute m such that h is the median of * the ith coordinate of all points * */ else { // ------------------------------------------------------- // | b&r scrambled | // ------------------------------------------------------- // i j k = ( i + j ) / 2 | 0; // ------------------------------------------------------- // | b&r scrambled | // ------------------------------------------------------- // i k j // select median element // O(n) select( __f__( di ), a, i, j, k ); h = a[k][di]; // ------------------------------------------------------- // | b&r <= h | h | b&r >= h | // ------------------------------------------------------- // i k j // we do 3 recursive calls // // first: for red and blue points with di < h in R^d // we do not consider points with di = h because either // // 1. red = h, blue < h --> handled by last call // 2. red < h, blue = h --> red cannot dominate blue // 3. red = h, blue = h --> handled by last call // (would be "red cannot dominate blue" for strict dominance // in this 3rd case) // // second: for red and blue points with di > h in R^d // we do not consider points with di = h for similar reasons as above // // last: for red points with di >= h and blue points with di <= h in R^{d-1} // (would be > and < for strict dominance) // // note that we do not need to handle the case where red < h and blue >= h // or red <= h and blue > h since red cannot dominate blue in those cases // first recursive call // we only consider points that have di < h // since all points that have di = h will be handled later // move median elements from [ i, k [ in the [ x, k [ interval, x >= i // O(n) x = split( __eq__( di, h ), a, i, k ); // ------------------------------------------------------- // | b&r < h | b&r = h | h | b&r > h | // ------------------------------------------------------- // i x k j yield* bdpdc( __f__, a, i, x, di, dj ); // move median elements from [ k + 1, j [ in the [ y, j [ interval, y <= j // O(n) y = split( __ne__( di, h ), a, k + 1, j ); // ------------------------------------------------------- // | b&r < h | b&r = h | h | b&r = h | b&r > h | // ------------------------------------------------------- // i x k y j yield* bdpdc( __f__, a, y, j, di, dj ); // since we do not touch median elements in the first two // recursive calls they are still at the correct place // Now we want to // - move red points such that di < h to the right // - move red points such that di >= h to the left // // /!\ Note that we also might think that we should // - move blue points such that di > h to the right // - move blue points such that di <= h to the left // but after the selection algorithm this is already the case // ------------------------------------------------------- // | b&r < h | b&r = h | h | b&r = h | b&r > h | // ------------------------------------------------------- // i x k y j p = split( color, a, i, x ); // ------------------------------------------------------- // | b < h | r < h | b&r = h | h | b&r = h | b&r > h | // ------------------------------------------------------- // i p x k y j q = split( color, a, y, j ); // ------------------------------------------------------- // | b < h | r < h | b&r = h | h | b&r = h | b > h | r > h | // ------------------------------------------------------- // i p x k y q j // we now want to swap r < h elements with r > h elements // we have 3 cases // 1. x - p = j - q // 2. x - p < j - q // 3. x - p > j - q m = x - p; n = j - q; // 1. x - p = j - q if ( m === n ) { swap( a, q, j, a, p ); // ------------------------------------------------------- // | b < h | r > h | b&r = h | h | b&r = h | b > h | r < h | // ------------------------------------------------------- // i p x k y q j j = y; // ------------------------------------------------------- // | b < h | r > h | b&r = h | h | b&r = h | b > h | r < h | // ------------------------------------------------------- // i p x k j ... } // 2. x - p < j - q else if ( m < n ) { swap( a, p, x, a, q ); // --------------------------------------------------------------- // | b < h | r > h | b&r = h | h | b&r = h | b > h | r < h | r > h | // --------------------------------------------------------------- // i p x k y q q+m j // we now want to swap b > h and r < h elements with r > h elements // [y,q[ [q,q+m[ [q+m,j[ // we have 2 cases // 1. (q + m) - y >= j - (q + m) [OR >] // 2. (q + m) - y < j - (q + m) [OR <=] _m = (q + m) - y; _n = j - (q + m); // 1. (q + m) - y >= j - (q + m) if ( _m >= _n ) { swap( a, q + m, j, a, y ); } // 2. (q + m) - y < j - (q + m) else { swap( a, j - _m, j, a, y ); } // --------------------------------------------------------------- // | b < h | r > h | b&r = h | h | b&r = h | r > h | b>h & r<h | // --------------------------------------------------------------- // i p x k y y+_n j j = y + _n; // --------------------------------------------------------------- // | b < h | r > h | b&r = h | h | b&r = h | r > h | b>h & r<h | // --------------------------------------------------------------- // i p x k y j ... } // 3. x - p > j - q else { swap( a, q, j, a, p ); // --------------------------------------------------------------- // | b < h | r > h | r < h | b&r = h | h | b&r = h | b > h | r < h | // --------------------------------------------------------------- // i p p+n x k y q j // we now want to swap r < h with b&r = h elements // we have 2 cases // 1. x - (p + n) >= y - x // 2. x - (p + n) < y - x _m = x - (p + n); _n = y - x; // 1. x - (p + n) >= y - x if ( _m >= _n ) { swap( a, x, y, a, p + n ); } // 2. x - (p + n) < y - x else { swap( a, y - _m, y, a, p + n ); } // ----------------------------------------------------------- // | b < h | r > h | b&r = h | h | b&r = h | b>h & r<h | // ----------------------------------------------------------- // i p p+n k y-_m j j = y - _m; // ----------------------------------------------------------- // | b < h | r > h | b&r = h | h | b&r = h | b>h & r<h | // ----------------------------------------------------------- // i p p+n k j ... } // [i, j[ now contains only b <= h and r >= h points // in this new interval, all r points dominate b points // for the ith coordinate // we can thus ask the recursion fairy to take care of the other // dj - di - 1 dimensions left yield* bdpdc( __f__, a, i, j, di + 1, dj ); } }; return bdpdc; }; exports.__bdpdc__ = __bdpdc__;