def test_volumes(self): # type: (RectangleTestCase) -> None p1 = (0.0, 0.75) p2 = (1.0, 1.75) r1 = Rectangle(p1, p2) p3 = (0.5, 0.0) p4 = (1.5, 1.0) r2 = Rectangle(p3, p4) p5 = (1.0, 1.0) p6 = (2.0, 2.0) r3 = Rectangle(p5, p6) r_intersect = r1.intersection(r2) # Volumes self.assertEqual(r1.volume(), r2.volume()) self.assertEqual(r3.volume(), r1.volume()) self.assertEqual(r3.volume(), r2.volume()) self.assertGreater(r1.volume(), r_intersect.volume()) self.assertGreater(r2.volume(), r_intersect.volume())
def multidim_search_opt_0(xspace, oracle, epsilon=EPS, delta=DELTA, max_step=STEPS, blocking=False, sleep=0.0, logging=True): # type: (Rectangle, Oracle, float, float, float, bool, float, bool) -> ResultSet # Xspace is a particular case of maximal rectangle # Xspace = [min_corner, max_corner]^n = [0, 1]^n # xspace.min_corner = (0,) * n # xspace.max_corner = (1,) * n # Dimension n = xspace.dim() # Set of comparable and incomparable rectangles, represented by 'alpha' indices comparable = comp(n) incomparable = incomp(n) # comparable = [zero, one] # incomparable = list(set(alpha) - set(comparable)) # with: # zero = (0_1,...,0_n) # one = (1_1,...,1_n) # List of incomparable rectangles # border = [xspace] border = SortedListWithKey(key=Rectangle.volume) # border = SortedSet(key=Rectangle.volume) border.add(xspace) ylow = [] yup = [] # oracle function f = oracle.membership() error = (epsilon,) * n vol_total = xspace.volume() vol_yup = 0 vol_ylow = 0 vol_border = vol_total step = 0 RootSearch.logger.debug('xspace: {0}'.format(xspace)) RootSearch.logger.debug('vol_border: {0}'.format(vol_border)) RootSearch.logger.debug('delta: {0}'.format(delta)) RootSearch.logger.debug('step: {0}'.format(step)) RootSearch.logger.debug('incomparable: {0}'.format(incomparable)) RootSearch.logger.debug('comparable: {0}'.format(comparable)) # Create temporary directory for storing the result of each step tempdir = tempfile.mkdtemp() RootSearch.logger.info('Report\nStep, Ylow, Yup, Border, Total, nYlow, nYup, nBorder, BinSearch') while (vol_border >= delta) and (step <= max_step) and (len(border) > 0): step = step + 1 # if RootSearch.logger.isEnabledFor(RootSearch.logger.DEBUG): # RootSearch.logger.debug('border: {0}'.format(border)) # l.sort(key=Rectangle.volume) xrectangle = border.pop() RootSearch.logger.debug('xrectangle: {0}'.format(xrectangle)) RootSearch.logger.debug('xrectangle.volume: {0}'.format(xrectangle.volume())) RootSearch.logger.debug('xrectangle.norm: {0}'.format(xrectangle.norm())) # y, segment # y = search(xrectangle.diag(), f, epsilon) y, steps_binsearch = binary_search(xrectangle.diag(), f, error) RootSearch.logger.debug('y: {0}'.format(y)) # b0 = Rectangle(xspace.min_corner, y.low) b0 = Rectangle(xrectangle.min_corner, y.low) ylow.append(b0) vol_ylow += b0.volume() RootSearch.logger.debug('b0: {0}'.format(b0)) RootSearch.logger.debug('ylow: {0}'.format(ylow)) # b1 = Rectangle(y.high, xspace.max_corner) b1 = Rectangle(y.high, xrectangle.max_corner) yup.append(b1) vol_yup += b1.volume() RootSearch.logger.debug('b1: {0}'.format(b1)) RootSearch.logger.debug('yup: {0}'.format(yup)) yrectangle = Rectangle(y.low, y.high) i = irect(incomparable, yrectangle, xrectangle) # i = pirect(incomparable, yrectangle, xrectangle) # l.extend(i) border += i RootSearch.logger.debug('irect: {0}'.format(i)) # Remove boxes in the boundary with volume 0 # border = border[border.bisect_key_right(0.0):] del border[:border.bisect_key_left(0.0)] vol_border = vol_total - vol_yup - vol_ylow RootSearch.logger.info( '{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}'.format(step, vol_ylow, vol_yup, vol_border, vol_total, len(ylow), len(yup), len(border), steps_binsearch)) if sleep > 0.0: rs = ResultSet(border, ylow, yup, xspace) if n == 2: rs.plot_2D_light(blocking=blocking, sec=sleep, opacity=0.7) elif n == 3: rs.plot_3D_light(blocking=blocking, sec=sleep, opacity=0.7) if logging: rs = ResultSet(border, ylow, yup, xspace) name = os.path.join(tempdir, str(step)) rs.to_file(name) return ResultSet(border, ylow, yup, xspace)
def multidim_search_opt_1(xspace, oracle, epsilon=EPS, delta=DELTA, max_step=STEPS, blocking=False, sleep=0.0, logging=True): # type: (Rectangle, Oracle, float, float, float, bool, float, bool) -> ResultSet # Xspace is a particular case of maximal rectangle # Xspace = [min_corner, max_corner]^n = [0, 1]^n # xspace.min_corner = (0,) * n # xspace.max_corner = (1,) * n # Dimension n = xspace.dim() # Set of comparable and incomparable rectangles, represented by 'alpha' indices comparable = comp(n) incomparable = incomp(n) # comparable = [zero, one] # incomparable = list(set(alpha) - set(comparable)) # with: # zero = (0_1,...,0_n) # one = (1_1,...,1_n) # List of incomparable rectangles # border = [xspace] # border = SortedListWithKey(key=Rectangle.volume) border = SortedSet([], key=Rectangle.volume) border.add(xspace) ylow = [] yup = [] # oracle function f = oracle.membership() error = (epsilon,) * n vol_total = xspace.volume() vol_yup = 0 vol_ylow = 0 vol_border = vol_total step = 0 RootSearch.logger.debug('xspace: {0}'.format(xspace)) RootSearch.logger.debug('vol_border: {0}'.format(vol_border)) RootSearch.logger.debug('delta: {0}'.format(delta)) RootSearch.logger.debug('step: {0}'.format(step)) RootSearch.logger.debug('incomparable: {0}'.format(incomparable)) RootSearch.logger.debug('comparable: {0}'.format(comparable)) # Create temporary directory for storing the result of each step tempdir = tempfile.mkdtemp() RootSearch.logger.info( 'Report\nStep, Ylow, Yup, Border, Total, nYlow, nYup, nBorder, BinSearch, nBorder dominated by Ylow, nBorder dominated by Yup') while (vol_border >= delta) and (step <= max_step) and (len(border) > 0): step = step + 1 # if RootSearch.logger.isEnabledFor(RootSearch.logger.DEBUG): # RootSearch.logger.debug('border: {0}'.format(border)) # l.sort(key=Rectangle.volume) xrectangle = border.pop() RootSearch.logger.debug('xrectangle: {0}'.format(xrectangle)) RootSearch.logger.debug('xrectangle.volume: {0}'.format(xrectangle.volume())) RootSearch.logger.debug('xrectangle.norm: {0}'.format(xrectangle.norm())) # y, segment # y = search(xrectangle.diag(), f, epsilon) y, steps_binsearch = binary_search(xrectangle.diag(), f, error) RootSearch.logger.debug('y: {0}'.format(y)) # discovered_segments.append(y) b0 = Rectangle(xrectangle.min_corner, y.low) b1 = Rectangle(y.high, xrectangle.max_corner) ylow.append(b0) yup.append(b1) vol_ylow += b0.volume() vol_yup += b1.volume() RootSearch.logger.debug('b0: {0}'.format(b0)) RootSearch.logger.debug('b1: {0}'.format(b1)) RootSearch.logger.debug('ylow: {0}'.format(ylow)) RootSearch.logger.debug('yup: {0}'.format(yup)) ################################ # Every Border rectangle that dominates B0 is included in Ylow # Every Border rectangle that is dominated by B1 is included in Yup b0_extended = Rectangle(xspace.min_corner, y.low) b1_extended = Rectangle(y.high, xspace.max_corner) # Every cube in the boundary overlaps another cube in the boundary # When cubes from the boundary are moved to ylow or yup, they may still have a complementary cube # remaining in the boundary with a non-empty intersection. border_overlapping_ylow = [r for r in ylow if r.overlaps(b0_extended)] border_overlapping_yup = [r for r in yup if r.overlaps(b1_extended)] border_overlapping_b0 = [rect for rect in border if rect.overlaps(b0_extended)] # Warning: Be aware of the overlapping areas of the cubes in the border. # If we calculate the intersection of b0_extended with all the cubes in the frontier, and two cubes # 'a' and 'b' partially overlaps, then the volume of this overlapping portion will be counted twice # border_dominatedby_b0 = [rect.intersection(b0_extended) for rect in border_overlapping_b0] # Solution: Project the 'shadow' of the cubes in the border over b0_extended. border_dominatedby_b0_shadow = Rectangle.difference_rectangles(b0_extended, border_overlapping_b0) # The negative of this image returns a set of cubes in the boundary without overlapping. # border_dominatedby_b0 will be appended to ylow. # Remove the portion of the negative that overlaps any cube that is already appended to ylow border_dominatedby_b0 = Rectangle.difference_rectangles(b0_extended, border_dominatedby_b0_shadow + border_overlapping_ylow) # border_nondominatedby_b0 = [rect - b0_extended for rect in border_overlapping_b0] border_nondominatedby_b0 = [] for rect in border_overlapping_b0: border_nondominatedby_b0 += list(rect - b0_extended) # border_nondominatedby_b0 = set() # for rect in border_overlapping_b0: # border_nondominatedby_b0 |= set(rect - b0_extended) # border_nondominatedby_b0 -= set(border_overlapping_b0) # if 'rect' is completely dominated by b0_extended (i.e., rect is strictly inside b0_extended), then # set(rect - b0_extended) == {rect} # Therefore, 'rect' must be removed from 'non dominated' borders # border -= border_overlapping_b0 border |= border_nondominatedby_b0 border -= border_overlapping_b0 border_overlapping_b1 = [rect for rect in border if rect.overlaps(b1_extended)] # Warning: Be aware of the overlapping areas of the cubes in the border. # If we calculate the intersection of b1_extended with all the cubes in the frontier, and two cubes # 'a' and 'b' partially overlaps, then the volume of this overlapping portion will be considered twice # border_dominatedby_b1 = [rect.intersection(b1_extended) for rect in border_overlapping_b1] # Solution: Project the 'shadow' of the cubes in the border over b1_extended. border_dominatedby_b1_shadow = Rectangle.difference_rectangles(b1_extended, border_overlapping_b1) # The negative of this image returns a set of cubes in the boundary without overlapping. # border_dominatedby_b1 will be appended to yup. # Remove the portion of the negative that overlaps any cube that is already appended to yup border_dominatedby_b1 = Rectangle.difference_rectangles(b1_extended, border_dominatedby_b1_shadow + border_overlapping_yup) # border_nondominatedby_b1 = [rect - b1_extended for rect in border_overlapping_b1] border_nondominatedby_b1 = [] for rect in border_overlapping_b1: border_nondominatedby_b1 += list(rect - b1_extended) # border_nondominatedby_b1 = set() # for rect in border_overlapping_b1: # border_nondominatedby_b1 |= set(rect - b1_extended) # border_nondominatedby_b1 -= set(border_overlapping_b1) # if 'rect' is completely dominated by b1_extended (i.e., rect is strictly inside b1_extended), then # set(rect - b1_extended) == {rect} # Therefore, 'rect' must be removed from 'non dominated' borders # border -= border_overlapping_b1 border |= border_nondominatedby_b1 border -= border_overlapping_b1 ylow.extend(border_dominatedby_b0) yup.extend(border_dominatedby_b1) vol_ylow += sum(b0.volume() for b0 in border_dominatedby_b0) vol_yup += sum(b1.volume() for b1 in border_dominatedby_b1) ################################ # Every rectangle in 'i' is incomparable for current B0 and for all B0 included in Ylow # Every rectangle in 'i' is incomparable for current B1 and for all B1 included in Yup ################################ yrectangle = Rectangle(y.low, y.high) i = irect(incomparable, yrectangle, xrectangle) # i = pirect(incomparable, yrectangle, xrectangle) # l.extend(i) border |= i RootSearch.logger.debug('irect: {0}'.format(i)) # Remove boxes in the boundary with volume 0 border -= border[:border.bisect_key_left(0.0)] vol_border = vol_total - vol_yup - vol_ylow RootSearch.logger.info('{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10}' .format(step, vol_ylow, vol_yup, vol_border, vol_total, len(ylow), len(yup), len(border), steps_binsearch, len(border_overlapping_b0), len(border_overlapping_b1))) if sleep > 0.0: rs = ResultSet(border, ylow, yup, xspace) if n == 2: rs.plot_2D_light(blocking=blocking, sec=sleep, opacity=0.7) elif n == 3: rs.plot_3D_light(blocking=blocking, sec=sleep, opacity=0.7) if logging: rs = ResultSet(border, ylow, yup, xspace) name = os.path.join(tempdir, str(step)) rs.to_file(name) return ResultSet(border, ylow, yup, xspace)