def test_equality(self): # type: (LatticeTestCase) -> None p1 = (0.0, 0.75) p2 = (1.0, 1.75) r1 = Rectangle(p1, p2) print('Rectangle 1: {0}'.format(r1)) p3 = (0.5, 0.0) p4 = (1.5, 1.0) r2 = Rectangle(p3, p4) print('Rectangle 2: {0}'.format(r2)) p5 = (1.0, 1.0) p6 = (2.0, 2.0) r3 = Rectangle(p5, p6) print('Rectangle 3: {0}'.format(r3)) l1 = Lattice(dim=r1.dim(), key=lambda x: x.min_corner) l2 = Lattice(dim=r1.dim(), key=lambda x: x.max_corner) l1.add_list([r1, r2]) l2.add_list([r1, r2]) # Equality self.assertSetEqual({r1, r2}, l1.less_equal(r3)) self.assertSetEqual(set(), l1.greater_equal(r3)) self.assertSetEqual({r1, r2}, l2.less_equal(r3)) self.assertSetEqual(set(), l2.greater_equal(r3))
def test_equality(self): # type: (RectangleTestCase) -> None p1 = (0.0, 0.75) p2 = (1.0, 1.75) r1 = Rectangle(p1, p2) print('Rectangle 1: {0}'.format(r1)) p3 = (0.5, 0.0) p4 = (1.5, 1.0) r2 = Rectangle(p3, p4) print('Rectangle 2: {0}'.format(r2)) p5 = (1.0, 1.0) p6 = (2.0, 2.0) r3 = Rectangle(p5, p6) print('Rectangle 3: {0}'.format(r3)) r4 = Rectangle() r5 = Rectangle() # Equality self.assertNotEqual(r1, r2) self.assertNotEqual(r1, r3) self.assertNotEqual(r2, r3) self.assertEqual(r4, r5) self.assertGreater(r3, r1) self.assertGreaterEqual(r3, r1) self.assertGreaterEqual(r1, r1) self.assertLess(r1, r3) self.assertLessEqual(r1, r3) self.assertLessEqual(r1, r1)
def test_distance_to_center(self): # type: (RectangleTestCase) -> None p5 = (1.0, 1.0) p6 = (2.0, 2.0) r3 = Rectangle(p5, p6) dist_p5 = r3.distance_to_center(p5) dist_p6 = r3.distance_to_center(p6) # Distance to center self.assertEqual(dist_p5, dist_p6)
def test_vertices(self): # type: (RectangleTestCase) -> None p1 = (0.0, 0.0) p2 = (1.0, 1.0) rect = Rectangle(p1, p2) vertices = rect.vertices() expected_vertices = [(0.0, 0.0), (0.0, 1.0), (1.0, 0.0), (1.0, 1.0)] # Vertices self.assertEqual(vertices, expected_vertices), num_vertices = rect.num_vertices() num_vertices_expected = len(expected_vertices) self.assertEqual(num_vertices, num_vertices_expected)
def __init__(self, border=list(), ylow=list(), yup=list(), xspace=Rectangle()): # type: (ResultSet, iter, iter, iter, Rectangle) -> None assert xspace is not None, 'xspace is None, it must be defined' # self.border = list(border) is required for forcing the creation of a local list. # If two ResultSets are created by making an empty call to ResultSet() (i.e., rs1, rs2), # then rs1.border and rs2.border will point to the same list. Modifications in rs1.border # will change rs2.border self.xspace = xspace self.border = list(border) self.ylow = list(ylow) self.yup = list(yup) # self.ylow = [Rectangle(xspace.min_corner, r.max_corner) for r in ylow] # self.yup = [Rectangle(r.min_corner, xspace.max_corner) for r in yup] # self.border = Rectangle.difference_rectangles(self.xspace, self.ylow + self.yup) # self.yup = Rectangle.difference_rectangles(self.xspace, self.ylow + self.border) # self.ylow = Rectangle.difference_rectangles(self.xspace, self.border + self.yup) self.filename_yup = 'up' self.filename_ylow = 'low' self.filename_border = 'border' self.filename_space = 'space' self.ylow_pareto = NDTree() self.yup_pareto = NDTree()
def SearchND(ora, min_corner=0.0, max_corner=1.0, epsilon=EPS, delta=DELTA, max_step=STEPS, blocking=False, sleep=0.0, opt_level=2, parallel=False, logging=True, simplify=True): # type: (Oracle, float, float, float, float, int, bool, float, int, bool, bool, bool) -> ResultSet d = ora.dim() minc = (min_corner,) * d maxc = (max_corner,) * d xyspace = Rectangle(minc, maxc) if parallel: rs = ParSearch.multidim_search(xyspace, ora, epsilon, delta, max_step, blocking, sleep, opt_level, logging) else: rs = SeqSearch.multidim_search(xyspace, ora, epsilon, delta, max_step, blocking, sleep, opt_level, logging) if simplify: rs.simplify() rs.fusion() return rs
def create_3D_space(minx, miny, minz, maxx, maxy, maxz): # type: (float, float, float, float, float, float) -> Rectangle RootSearch.logger.debug('Creating Space') start = time.time() minc = (minx, miny, minz) maxc = (maxx, maxy, maxz) xyspace = Rectangle(minc, maxc) end = time.time() time0 = end - start RootSearch.logger.debug('Time creating Space: {0}'.format(str(time0))) return xyspace
def create_ND_space(args): # type: (iter) -> Rectangle # args = [(minx, maxx), (miny, maxy),..., (minz, maxz)] RootSearch.logger.debug('Creating Space') start = time.time() minc = tuple(minx for minx, _ in args) maxc = tuple(maxx for _, maxx in args) xyspace = Rectangle(minc, maxc) end = time.time() time0 = end - start RootSearch.logger.debug('Time creating Space: {0}'.format(str(time0))) return xyspace
def simplify(self): # type: (ResultSet) -> None # Remove single points from the yup and ylow closures, i.e., rectangles rect with: # rect.min_corner == rect.max_corner # These kind of rectangles appear when the dicothomic search cannot find an intersection of the diagonal # with the Pareto front self.ylow = [li for li in self.ylow if li.norm() != 0.0] self.yup = [li for li in self.yup if li.norm() != 0.0] # Single points may appear in the boundary, so we don't remove them # self.border = [li for li in self.border if li.norm() != 0] # Get the highest (upper right) values of self.ylow; i.e., those points that are closer to self.yup extended_ylow = [Rectangle(self.xspace.min_corner, r.max_corner) for r in self.ylow] # extended_yup = [Rectangle(r.min_corner, self.xspace.max_corner) for r in self.yup] # Get the lowest (lower left) values of self.yup; i.e., those points that are closer to self.ylow # extended_ylow = [Rectangle(self.xspace.min_corner, ylow_point) for ylow_point in self.get_points_pareto_ylow()] extended_yup = [Rectangle(yup_point, self.xspace.max_corner) for yup_point in self.get_points_pareto_yup()] self.border = Rectangle.difference_rectangles(self.xspace, extended_ylow + extended_yup) self.yup = Rectangle.difference_rectangles(self.xspace, extended_ylow + self.border) self.ylow = Rectangle.difference_rectangles(self.xspace, extended_yup + self.border)
def test_inclusion(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) # Inclusion self.assertTrue(r1.inside(p1)) self.assertTrue(r1.inside(p2)) self.assertTrue(r2.inside(p3)) self.assertTrue(r2.inside(p4)) self.assertTrue(r3.inside(p5)) self.assertTrue(r3.inside(p6)) self.assertFalse(p1 in r1) self.assertFalse(p2 in r1) self.assertFalse(p3 in r2) self.assertFalse(p4 in r2) self.assertFalse(p5 in r3) self.assertFalse(p6 in r3) # p5 is in the edge of r1, so no strictly inside r1 self.assertFalse(p5 in r1) self.assertFalse(p6 in r1) self.assertFalse(p1 in r3)
def multidim_search_opt_3(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) lattice_border_ylow = Lattice(dim=xspace.dim(), key=lambda x: x.min_corner) lattice_border_yup = Lattice(dim=xspace.dim(), key=lambda x: x.max_corner) lattice_border_ylow.add(xspace) lattice_border_yup.add(xspace) ylow = [] yup = [] # x_minimal = points from 'x' that are strictly incomparable (Pareto optimal) ylow_minimal = [] yup_minimal = [] # 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() lattice_border_ylow.remove(xrectangle) lattice_border_yup.remove(xrectangle) 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() ################################ # Every Border rectangle that dominates B0 is included in Ylow b0_extended = Rectangle(xspace.min_corner, y.low) # border_overlapping_b0 = [rect for rect in border if rect.overlaps(b0_extended)] # border_overlapping_b0 = [rect for rect in border_overlapping_b0 if rect.overlaps(b0_extended)] ylow_rectangle = Rectangle(y.low, y.low) border_overlapping_b0 = lattice_border_ylow.less_equal(ylow_rectangle) # border_intersecting_b0 = [b0_extended.intersection(rect) for rect in border_overlapping_b0] ## 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) list_idwc = (idwc(b0_extended, rect) for rect in border_overlapping_b0) border_nondominatedby_b0 = set(itertools.chain.from_iterable(list_idwc)) # border_nondominatedby_b0 = Rectangle.fusion_rectangles(border_nondominatedby_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_nondominatedby_b0 border -= border_overlapping_b0 lattice_border_ylow.add_list(border_nondominatedby_b0) lattice_border_ylow.remove_list(border_overlapping_b0) lattice_border_yup.add_list(border_nondominatedby_b0) lattice_border_yup.remove_list(border_overlapping_b0) # Every Border rectangle that is dominated by B1 is included in Yup b1_extended = Rectangle(y.high, xspace.max_corner) # border_overlapping_b1 = [rect for rect in border if rect.overlaps(b1_extended)] # border_overlapping_b1 = [rect for rect in border_overlapping_b1 if rect.overlaps(b1_extended)] yup_rectangle = Rectangle(y.high, y.high) border_overlapping_b1 = lattice_border_yup.greater_equal(yup_rectangle) # border_intersecting_b1 = [b1_extended.intersection(rect) for rect in border_overlapping_b1] ## 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) list_iuwc = (iuwc(b1_extended, rect) for rect in border_overlapping_b1) border_nondominatedby_b1 = set(itertools.chain.from_iterable(list_iuwc)) # border_nondominatedby_b1 = Rectangle.fusion_rectangles(border_nondominatedby_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_nondominatedby_b1 border -= border_overlapping_b1 lattice_border_ylow.add_list(border_nondominatedby_b1) lattice_border_ylow.remove_list(border_overlapping_b1) lattice_border_yup.add_list(border_nondominatedby_b1) lattice_border_yup.remove_list(border_overlapping_b1) db0 = Rectangle.difference_rectangles(b0_extended, ylow_minimal) db1 = Rectangle.difference_rectangles(b1_extended, yup_minimal) vol_db0 = sum(b0.volume() for b0 in db0) vol_db1 = sum(b1.volume() for b1 in db1) # rs = ResultSet([], border_intersecting_b0 + [b0], border_intersecting_b1 + [b1], Rectangle()) # vol_db0 = rs.volume_ylow() - rs.overlapping_volume_ylow() # vol_db1 = rs.volume_yup() - rs.overlapping_volume_yup() vol_ylow += vol_db0 vol_yup += vol_db1 ylow.extend(db0) yup.extend(db1) ylow_minimal.append(b0_extended) yup_minimal.append(b1_extended) RootSearch.logger.debug('b0: {0}'.format(db0)) RootSearch.logger.debug('b1: {0}'.format(db1)) RootSearch.logger.debug('ylow: {0}'.format(ylow)) RootSearch.logger.debug('yup: {0}'.format(yup)) ################################ # 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)) lattice_border_ylow.add_list(i) lattice_border_yup.add_list(i) # Remove boxes in the boundary with volume 0 boxes_null_vol = border[:border.bisect_key_left(0.0)] border -= boxes_null_vol lattice_border_ylow.remove_list(boxes_null_vol) lattice_border_yup.remove_list(boxes_null_vol) 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)
def fusion(self): # type: (ResultSet) -> None # Concatenate rectangles in each closure self.border = Rectangle.fusion_rectangles(self.border) self.ylow = Rectangle.fusion_rectangles(self.ylow) self.yup = Rectangle.fusion_rectangles(self.yup)
def from_file_space(self, f): # type: (ResultSet, str) -> None self.xspace = Rectangle() with open(f, 'rb') as inputfile: self.xspace = pickle.load(inputfile)
def __init__(self, border=list(), ylow=list(), yup=list(), xspace=Rectangle()): # type: (ParResultSet, iter, iter, iter, Rectangle) -> None # super(ParResultSet, self).__init__(border, ylow, yup, xspace) ResultSet.__init__(self, border, ylow, yup, xspace) self.p = Pool(cpu_count())
def test_concatenation(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) p7 = (1.5, 0.0) p8 = (2.0, 1.0) r4 = Rectangle(p7, p8) p9 = (0.5, 1.0) r5 = Rectangle(p9, p2) p10 = (0.5, 1.75) r6 = Rectangle(p1, p10) r_intersect = r1.intersection(r2) # Concatenation of Rectangles self.assertTrue(not r1.is_concatenable(r2)) self.assertTrue(not r1.is_concatenable(r3)) self.assertTrue(not r1.is_concatenable(r4)) self.assertTrue(not r1.is_concatenable(r5)) self.assertTrue(not r1.is_concatenable(r6)) self.assertTrue(not r2.is_concatenable(r1)) self.assertTrue(not r2.is_concatenable(r3)) self.assertTrue(r2.is_concatenable(r4)) self.assertTrue(not r2.is_concatenable(r5)) self.assertTrue(not r2.is_concatenable(r6)) self.assertTrue(not r3.is_concatenable(r1)) self.assertTrue(not r3.is_concatenable(r2)) self.assertTrue(not r4.is_concatenable(r1)) self.assertTrue(r4.is_concatenable(r2)) self.assertTrue(not r5.is_concatenable(r1)) self.assertTrue(not r5.is_concatenable(r2)) self.assertTrue(not r5.is_concatenable(r6)) self.assertTrue(not r6.is_concatenable(r1)) self.assertTrue(not r6.is_concatenable(r2)) self.assertTrue(not r6.is_concatenable(r5)) self.assertEqual(r1, r_intersect.concatenate(r5).concatenate(r6)) self.assertEqual(r4, r2.concatenate(r4).intersection(r4))
def test_intersection(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) p7 = (1.5, 0.0) p8 = (2.0, 1.0) r4 = Rectangle(p7, p8) p9 = (0.5, 1.0) r5 = Rectangle(p9, p2) p10 = (0.5, 1.75) r6 = Rectangle(p1, p10) p1_intersect = (0.5, 0.75) p2_intersect = (1.0, 1.0) r_intersect_expected = Rectangle(p1_intersect, p2_intersect) r_intersect = r1.intersection(r2) # Intersection of Rectangles self.assertTrue(r1.overlaps(r2)) self.assertTrue(not r1.overlaps(r3)) self.assertTrue(not r1.overlaps(r4)) self.assertTrue(r1.overlaps(r5)) self.assertTrue(r1.overlaps(r6)) self.assertTrue(r2.overlaps(r1)) self.assertTrue(not r2.overlaps(r3)) self.assertTrue(not r2.overlaps(r4)) self.assertTrue(not r3.overlaps(r1)) self.assertTrue(not r3.overlaps(r2)) self.assertTrue(not r3.overlaps(r4)) self.assertTrue(not r4.overlaps(r1)) self.assertTrue(not r4.overlaps(r2)) self.assertTrue(not r4.overlaps(r3)) ##### self.assertEqual(r_intersect, r_intersect_expected) self.assertEqual(r1.intersection(r5), r5) self.assertEqual(r1.intersection(r6), r6) self.assertEqual(r5.intersection(r1), r5) self.assertEqual(r6.intersection(r1), r6)
def set_points_pareto(self, l): # type: (ResultSet, iter) -> None self.yup = [Rectangle(p, self.xspace.max_corner) for p in l] self.ylow = [Rectangle(self.xspace.min_corner, p) for p in l] self.border = [Rectangle(p, p) for p in l]
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)
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 test_difference(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 = (0.5, 1.0) r3 = Rectangle(p1, p5) r4 = Rectangle(p5, p2) p6 = (0.0, 1.0) p7 = (0.5, 1.75) r5 = Rectangle(p6, p7) r6 = Rectangle(p1, p7) diff_result = set(r1.difference(r2)) # Difference self.assertTrue(r6 in diff_result) # self.assertTrue(r3 in diff_result) self.assertTrue(r4 in diff_result) # self.assertTrue(r5 in diff_result) # self.assertTrue(len(diff_result) == 3) self.assertTrue(len(diff_result) == 2) diff_result21 = set(r3.difference(r4)) diff_result22 = set(r4.difference(r3)) diff_result31 = set(r4.difference(r5)) diff_result32 = set(r5.difference(r4)) # r1.difference(r2) returns r1 in the # case that r1 and r2 do not intersect self.assertTrue(len(diff_result21) == 1) self.assertTrue(len(diff_result22) == 1) self.assertTrue(len(diff_result31) == 1) self.assertTrue(len(diff_result32) == 1) self.assertTrue(r3 in diff_result21) self.assertTrue(r4 in diff_result22) self.assertTrue(r4 in diff_result31) self.assertTrue(r5 in diff_result32) # r1 - r2 is a synonym for r1.difference(r2) # '-' tries to minimize the number of cubes generated by # self.difference(other) by concatenating adjacent boxes self.assertLessEqual(len(r1 - r2), len(diff_result)) self.assertLessEqual(len(r3 - r4), len(diff_result21)) self.assertLessEqual(len(r4 - r3), len(diff_result22)) self.assertLessEqual(len(r4 - r5), len(diff_result31)) self.assertLessEqual(len(r5 - r4), len(diff_result32))
def test_idwc_iuwc(self): # type: (RectangleTestCase) -> None p1 = (0.0,)*4 p2 = (0.5,)*4 p3 = (0.2, 0.6, 0.2, 0.2) z = Rectangle(p1, p2) y = Rectangle(p1, p3) r = [Rectangle((0.2, 0.0, 0.0, 0.0), p2), Rectangle((0.0, 0.0, 0.2, 0.0), (0.2, 0.5, 0.5, 0.5)), Rectangle((0.0, 0.0, 0.0, 0.2), (0.2, 0.5, 0.2, 0.5))] self.assertSetEqual(set(r), set(idwc(y, z))) p1 = (0.0,) * 3 p2 = (0.5,) * 3 p3 = (0.2, 0.6, 0.2) p4 = (0.2, ) * 3 p5 = (1.0,) * 3 z = Rectangle(p1, p2) y1 = Rectangle(p1, p3) y2 = Rectangle(p4, p5) # y_interval = Rectangle p6 = (0.2, 0.0, 0.0) p7 = (0.2, 0.5, 0.5) r1 = [Rectangle(p6, p2), Rectangle((0.0, 0.0, 0.2), p7)] r2 = [Rectangle(p1, p7), Rectangle(p6, (0.5, 0.2, 0.5)), Rectangle((0.2, 0.2, 0.0), (0.5, 0.5, 0.2))] self.assertSetEqual(set(r1), set(idwc(y1, z))) self.assertSetEqual(set(r2), set(iuwc(y2, z))) self.assertSetEqual(set(), set(idwc(y1, z)) & set(y1 - z)) self.assertSetEqual(set(), set(iuwc(y2, z)) & set(y2 - z))
def setUp(self): # type: (ResultSetTestCase) -> None self.files_to_clean = set() # Set of rectangles calculated by doc/example/example2d.py # Search2D stopped after 5 steps self.border_2D = [Rectangle((0.624992370605469, 0.249996185186319), (0.75, 0.375001907290425)), Rectangle((0.125001907348633, 0.749992370605469), (0.250003814697266, 0.875003814930096)), Rectangle((0.749992370605469, 0.125001907348633), (0.875003814930096, 0.250003814697266)), Rectangle((0.5, 0.374994277546644), (0.625, 0.500007629394531)), Rectangle((0.0, 0.874996185302734), (0.12500953685958, 1.0)), Rectangle((0.874996185302734, 0.0), (1.0, 0.12500953685958)), Rectangle((0.249996185186319, 0.5), (0.500007629394531, 0.75))] self.ylow_2D = [Rectangle((0.0, 0.0), (0.5, 0.5)), Rectangle((0.5, 0.0), (0.749992370605469, 0.249996185186319)), Rectangle((0.0, 0.5), (0.249996185186319, 0.749992370605469)), Rectangle((0.749992370605469, 0.0), (0.874996185302734, 0.125001907348633)), Rectangle((0.0, 0.749992370605469), (0.125001907348633, 0.874996185302734)), Rectangle((0.5, 0.249996185186319), (0.624992370605469, 0.374994277546644))] self.yup_2D = [Rectangle((0.500007629394531, 0.500007629394531), (1.0, 1.0)), Rectangle((0.75, 0.250003814697266), (1.0, 0.500007629394531)), Rectangle((0.250003814697266, 0.75), (0.500007629394531, 1.0)), Rectangle((0.875003814930096, 0.12500953685958), (1.0, 0.250003814697266)), Rectangle((0.12500953685958, 0.875003814930096), (0.250003814697266, 1.0)), Rectangle((0.625, 0.375001907290425), (0.75, 0.500007629394531))] self.xspace_2D = create_2D_space(0.0, 0.0, 1.0, 1.0) self.rs_2D = ResultSet(self.border_2D, self.ylow_2D, self.yup_2D, self.xspace_2D) self.rs2 = ResultSet() # Set of rectangles calculated by doc/example/example3d.py # Search3D stopped after 5 steps self.border_3D = [Rectangle((0.5, 0.5, 0.0), (0.500007629394531, 0.500007629394531, 0.500007629394531)), Rectangle((0.5, 0.5, 0.0), (1.0, 0.500007629394531, 7.629510947e-06)), Rectangle((0.5, 0.5, 0.0), (0.500007629394531, 1.0, 7.629510947e-06)), Rectangle((0.0, 0.499999999883584, 0.999992370605469), (0.500007629394531, 0.500007629394531, 1.0)), Rectangle((0.499999999883584, 0.0, 0.999992370605469), (0.500007629394531, 0.500007629394531, 1.0)), Rectangle((0.499999999883584, 0.499999999883584, 0.5), (0.500007629394531, 0.500007629394531, 1.0)), Rectangle((0.5, 0.5, 0.0), (0.500007629394531, 1.0, 0.500007629394531)), Rectangle((0.5, 0.5, 0.0), (1.0, 0.500007629394531, 0.500007629394531)), Rectangle((0.5, 0.5, 0.0), (1.0, 1.0, 7.629510947e-06)), Rectangle((0.0, 0.0, 0.999992370605469), (0.500007629394531, 0.500007629394531, 1.0)), Rectangle((0.499999999883584, 0.0, 0.5), (0.500007629394531, 0.500007629394531, 1.0)), Rectangle((0.0, 0.499999999883584, 0.5), (0.500007629394531, 0.500007629394531, 1.0)), Rectangle((0.5, 0.249996185186319, 0.5), (0.75, 0.500007629394531, 0.75)), Rectangle((0.749992370605469, 0.0, 0.5), (1.0, 0.250003814697266, 0.75)), Rectangle((0.5, 0.0, 0.749992370605469), (0.75, 0.250003814697266, 1.0)), Rectangle((0.5, 0.0, 0.249996185186319), (0.75, 0.250003814697266, 0.500007629394531)), Rectangle((0.5, 0.249996185186319, 0.0), (0.75, 0.500007629394531, 0.250003814697266)), Rectangle((0.249996185186319, 0.5, 0.0), (0.500007629394531, 0.75, 0.250003814697266)), Rectangle((0.0, 0.5, 0.249996185186319), (0.250003814697266, 0.75, 0.500007629394531)), Rectangle((0.749992370605469, 0.0, 0.0), (1.0, 0.250003814697266, 0.250003814697266)), Rectangle((0.0, 0.749992370605469, 0.0), (0.250003814697266, 1.0, 0.250003814697266)), Rectangle((0.5, 0.249996185186319, 0.749992370605469), (0.75, 0.500007629394531, 1.0)), Rectangle((0.749992370605469, 0.249996185186319, 0.5), (1.0, 0.500007629394531, 0.75)), Rectangle((0.749992370605469, 0.0, 0.749992370605469), (1.0, 0.250003814697266, 1.0)), Rectangle((0.5, 0.249996185186319, 0.249996185186319), (0.75, 0.500007629394531, 0.500007629394531)), Rectangle((0.249996185186319, 0.5, 0.249996185186319), (0.500007629394531, 0.75, 0.500007629394531)), Rectangle((0.749992370605469, 0.249996185186319, 0.0), (1.0, 0.500007629394531, 0.250003814697266)), Rectangle((0.749992370605469, 0.0, 0.249996185186319), (1.0, 0.250003814697266, 0.500007629394531)), Rectangle((0.0, 0.749992370605469, 0.249996185186319), (0.250003814697266, 1.0, 0.500007629394531)), Rectangle((0.249996185186319, 0.749992370605469, 0.0), (0.500007629394531, 1.0, 0.250003814697266)), Rectangle((0.0, 0.5, 0.5), (0.500007629394531, 1.0, 1.0))] self.ylow_3D = [Rectangle((0.0, 0.0, 0.0), (0.5, 0.5, 0.5)), Rectangle((0.0, 0.5, 0.0), (0.249996185186319, 0.749992370605469, 0.249996185186319)), Rectangle((0.0, 0.0, 0.5), (0.499999999883584, 0.499999999883584, 0.999992370605469)), Rectangle((0.5, 0.0, 0.0), (0.749992370605469, 0.249996185186319, 0.249996185186319)), Rectangle((0.5, 0.0, 0.5), (0.749992370605469, 0.249996185186319, 0.749992370605469)), Rectangle((0.5, 0.5, 0.0), (0.5, 0.5, 0.0))] self.yup_3D = [Rectangle((0.500007629394531, 0.500007629394531, 7.629510947e-06), (1.0, 1.0, 1.0)), Rectangle((0.250003814697266, 0.75, 0.250003814697266), (0.500007629394531, 1.0, 0.500007629394531)), Rectangle((0.500007629394531, 0.500007629394531, 1.0), (0.500007629394531, 0.500007629394531, 1.0)), Rectangle((0.75, 0.250003814697266, 0.250003814697266), (1.0, 0.500007629394531, 0.500007629394531)), Rectangle((0.75, 0.250003814697266, 0.75), (1.0, 0.500007629394531, 1.0))] self.xspace_3D = create_3D_space(0.0, 0.0, 0.0, 1.0, 1.0, 1.0) self.rs_3D = ResultSet(self.border_3D, self.ylow_3D, self.yup_3D, self.xspace_3D)
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)