def get_kernel(shifts, shift_vals): """ Get all kernels describing the path of the edges in a discrete raster :param shifts: possible circle points :returns kernel: all possible kernels shape: (number of circle points x upper x upper) :returns posneg: a list indicating whether it is a path to the left =1 or to the right =0 """ upper = np.amax(np.absolute(shifts)) + 1 posneg = [] kernel = np.zeros((len(shifts), upper, upper)) max_val = np.max(shift_vals) for i, shift in enumerate(shifts): if shift[1] < 0: posneg.append(1) line = bresenham_line(0, upper - 1, shift[0], upper - 1 + shift[1]) else: posneg.append(0) line = bresenham_line(0, 0, shift[0], shift[1]) # add points of line to the kernel normed_val = shift_vals[i] / (len(line) * max_val) for (j, k) in line: kernel[i, j, k] = normed_val return kernel, posneg
def set_shift( self, start, dest, pylon_dist_min=3, pylon_dist_max=5, max_angle=np.pi / 2, max_angle_lg=np.pi / 2, **kwargs ): """ Initialize shift variable by getting the donut values :param pylon_dist_min, pylon_dist_max: min and max distance of pylons :param vec: vector of diretion of edges :param max_angle: Maximum angle of edges to vec """ self.start_inds = np.asarray(start) self.dest_inds = np.asarray(dest) self.angle_norm_factor = max_angle_lg vec = self.dest_inds - self.start_inds shifts = get_half_donut( pylon_dist_min, pylon_dist_max, vec, angle_max=max_angle ) shift_angles = [angle_360(s, vec) for s in shifts] # sort the shifts self.shifts = np.asarray(shifts)[np.argsort(shift_angles)] self.shift_tuples = self.shifts # construct bresenham lines shift_lines = List() for shift in self.shifts: line = bresenham_line(0, 0, shift[0], shift[1]) shift_lines.append(np.array(line[1:-1])) self.shift_lines = shift_lines
def cells_crossed_plot( folders, disp_inst, out_path=None, buffer=4, line_buffer=2 ): """ Plotting function to visualize how often each cell is crossed Arguments: folders: List of directory paths that contain the paths to analyze disp_inst: 2D array, instance to display and plot the paths on out_path: saving fp for plot """ # e.g. path_dir ["sensitivity_tuples", "weight_sensitivity_0905", # "optimal_paths", "weight_sensitivity_0905", "layer_sensitivity"] path_list = [] for path in folders: for fn in os.listdir( os.path.join("../../outputs/de_presentation", path) ): if fn[-3:] == "csv": path_table = pd.read_csv( os.path.join("../../outputs/de_presentation", path, fn) ) path_list.append((np.asarray(path_table[["X_raw", "Y_raw"]]))) x_len, y_len = disp_inst.shape mark_array = np.zeros((y_len, x_len)) for path in path_list: # path_tuple_list path = np.asarray(path).astype(int) for p in range(len(path)): (i, j) = path[p] mark_array[i:i + buffer + 1, j:j + buffer + 1] = mark_array[i:i + buffer + 1, j:j + buffer + 1] + 1 if p < len(path) - 1: (k, l) = path[p + 1] line_points = bresenham_line(i, j, k, l) for (x, y) in line_points[1:-1]: mark_array[x:x + line_buffer, y:y + line_buffer] = mark_array[x:x + line_buffer, y:y + line_buffer] + 1 grey_disp_inst = np.tile(np.expand_dims(disp_inst, 2), 3) x_nonzero, y_nonzero = np.where(mark_array > 0) max_val = np.max(mark_array) for (x, y) in zip(x_nonzero, y_nonzero): normed = mark_array[x, y] / (max_val - 200) grey_disp_inst[y, x] = [ np.clip(1 - normed, 0, 1), np.clip(normed + 0.3, 0, 1), 0.2 ] plt.figure(figsize=(20, 20)) plt.imshow(grey_disp_inst) if out_path is not None: plt.savefig(out_path + ".png") else: plt.show()
def compute_edge_costs(path, instance): e_costs = [] for p in range(len(path) - 1): point_list = bresenham_line(path[p][0], path[p][1], path[p + 1][0], path[p + 1][1]) e_costs.append( np.mean([instance[i, j] for (i, j) in point_list[1:-1]])) # to make it the same size as other costs e_costs.append(0) return e_costs
def test_edge_costs(self) -> None: graph = graphs.ImplicitLG(np.array([self.example_inst]), self.working_expl_corr, n_iters=10, verbose=0) self.cfg.angle_weight = 0 self.cfg.edge_weight = 0.5 path, path_costs, cost_sum = graph.single_sp(**vars(self.cfg)) self.cfg.angle_weight = 0.25 self.cfg.edge_weight = 0 dest_ind = graph.pos2node[tuple(self.dest_inds)] dest_costs = np.min(graph.dists[dest_ind]) dest_costs_gt = len(path) # everywhere 1 a = [] path = np.array(path) for p in range(len(path) - 1): line = bresenham_line(path[p, 0], path[p, 1], path[p + 1, 0], path[p + 1, 1])[1:-1] line_costs = [self.example_inst[i, j] for (i, j) in line] line_costs = [l for l in line_costs if l < np.inf] a.append(np.mean(line_costs) * 0.5) dest_costs_gt += np.sum(a) self.assertEqual(dest_costs, dest_costs_gt) self.assertEqual(dest_costs, cost_sum)
class TestImplicitLG(unittest.TestCase): expl_shape = (50, 50) # create configuration cfg = SimpleNamespace() cfg.pylon_dist_min = 3 cfg.pylon_dist_max = 5 start_inds = np.array([6, 6]) dest_inds = np.array([41, 43]) cfg.start_inds = start_inds cfg.dest_inds = dest_inds cfg.angle_weight = 0.25 cfg.edge_weight = 0 cfg.max_angle = np.pi / 2 cfg.max_angle_lg = np.pi / 4 cfg.layer_classes = ["dummy_class"] cfg.class_weights = [1] # construct simple line instance example_inst = np.ones(expl_shape) # construct corresponding corridor working_expl_corr = np.zeros(expl_shape) line = bresenham_line(start_inds[0], start_inds[1], dest_inds[0], dest_inds[1]) for (i, j) in line: working_expl_corr[i - 1:i + 1, j - 1:j + 1] = 1 # construct instance that required 90 degree angle high_angle_corr = np.zeros(expl_shape) high_angle_corr[start_inds[0], start_inds[1]:dest_inds[1] - 3] = 1 high_angle_corr[start_inds[0], dest_inds[1]] = 1 high_angle_corr[start_inds[0] + 3:dest_inds[0] + 1, dest_inds[1]] = 1 def test_correct_shortest_path(self) -> None: """ Test the implicit line graph construction """ graph = graphs.ImplicitLG(np.array([self.example_inst]), self.working_expl_corr, n_iters=10, verbose=0) path, path_costs, cost_sum = graph.single_sp(**vars(self.cfg)) self.assertListEqual(graph.cost_weights.tolist(), [0.2, 0.8]) self.assertTupleEqual(graph.instance.shape, self.expl_shape) self.assertEqual(np.sum(graph.cost_weights), 1) self.assertNotEqual(len(graph.shifts), 0) # all initialized to infinity # self.assertTrue(not np.any([graph.dists[graph.dists < np.inf]])) # start point was set to normalized value start_ind = graph.pos2node[tuple(self.start_inds)] self.assertEqual(0.8, graph.dists[start_ind, 0]) # all start dists have same value self.assertEqual(len(np.unique(graph.dists[start_ind])), 1) # not all values still inf self.assertLess(np.min(graph.dists[start_ind]), np.inf) # get actual best path # path, path_costs, cost_sum = graph.get_shortest_path( # self.start_inds, self.dest_inds # ) self.assertNotEqual(len(path), 0) self.assertEqual(len(path), len(path_costs)) self.assertGreaterEqual(cost_sum, 5) weighted_costs = np.sum(path_costs, axis=0) * graph.cost_weights self.assertEqual(np.sum(weighted_costs), cost_sum) for (i, j) in path: self.assertEqual(self.example_inst[i, j], 1) def test_edge_costs(self) -> None: graph = graphs.ImplicitLG(np.array([self.example_inst]), self.working_expl_corr, n_iters=10, verbose=0) self.cfg.angle_weight = 0 self.cfg.edge_weight = 0.5 path, path_costs, cost_sum = graph.single_sp(**vars(self.cfg)) self.cfg.angle_weight = 0.25 self.cfg.edge_weight = 0 dest_ind = graph.pos2node[tuple(self.dest_inds)] dest_costs = np.min(graph.dists[dest_ind]) dest_costs_gt = len(path) # everywhere 1 a = [] path = np.array(path) for p in range(len(path) - 1): line = bresenham_line(path[p, 0], path[p, 1], path[p + 1, 0], path[p + 1, 1])[1:-1] line_costs = [self.example_inst[i, j] for (i, j) in line] line_costs = [l for l in line_costs if l < np.inf] a.append(np.mean(line_costs) * 0.5) dest_costs_gt += np.sum(a) self.assertEqual(dest_costs, dest_costs_gt) self.assertEqual(dest_costs, cost_sum) def test_angle_sp(self) -> None: graph = graphs.ImplicitLG(np.array([self.example_inst]), self.high_angle_corr, n_iters=10, verbose=0) path, path_costs, cost_sum = graph.single_sp(**vars(self.cfg)) # assert that destination can NOT be reached dest_ind = graph.pos2node[tuple(self.dest_inds)] self.assertFalse(np.min(graph.dists[dest_ind]) < np.inf) # NEXT TRY: more angles allowed self.cfg.max_angle_lg = np.pi graph = graphs.ImplicitLG(np.array([self.example_inst]), self.high_angle_corr, n_iters=10, verbose=0) path, path_costs, cost_sum = graph.single_sp(**vars(self.cfg)) # assert that dest CAN be reached dest_ind = graph.pos2node[tuple(self.dest_inds)] self.assertTrue(np.min(graph.dists[dest_ind]) < np.inf) # same with linegraph: lg_graph = graphs.LineGraph(np.array([self.example_inst]), self.high_angle_corr, verbose=0) path_lg, path_costs_lg, cost_sum_lg = lg_graph.single_sp( **vars(self.cfg)) self.cfg.max_angle_lg = np.pi / 4 # assert that path is non-empty self.assertTrue(len(path_lg) > 0) self.assertEqual(len(path_lg), len(path_costs_lg)) self.assertGreaterEqual(cost_sum_lg, 5) weighted_costs = np.sum(path_costs_lg, axis=0) * lg_graph.cost_weights self.assertEqual(np.sum(weighted_costs), cost_sum_lg) # assert that all points are equal to 1 for (i, j) in path_lg: self.assertEqual(self.example_inst[i, j], 1) lg_graph = graphs.LineGraph(np.array([self.example_inst]), self.high_angle_corr, verbose=0) path_lg, path_costs_lg, cost_sum_lg = lg_graph.single_sp( **vars(self.cfg)) self.assertTrue(len(path_lg) == 0)