def viz_tree(self): self.graph_num += 1 if self.debug > 0: err.log("Generating DOT for tree diagram number " + str(self.graph_num)) graph = Digraph() graph.format = 'eps' graph.body.extend(['size="10,10"', 'fontpath="/home/M/.fonts/"']) graph.attr('node', shape='circle') graph.attr('node', style='filled') graph.attr('node', color='black') graph.attr('node', fixedsize='true') graph.attr('node', height='0.75') graph.attr('node', width='0.75') graph.attr('node', fontcolor='white') graph.attr('node', fontname='InputMono-Bold') graph.attr('edge', arrowhead='none') graph.attr('edge', style='filled') stack = [self.root] nodes = set() while len(stack) > 0: self.add_node(stack.pop(), stack, graph, nodes) return graph
def verify_tree_ref(self): node = self.root # The parent of the root node should always be root if node.p is not node: err.warn("Root's (" + str(node) + ") parent isn't root") return False # Verify the parent and children pointers are valid for each subtree left = self.verify_tree_ref_helper(node, node.l, True) right = self.verify_tree_ref_helper(node, node.r, False) err.log("Left of Root: " + str(left)) err.log("Left of Root: " + str(right)) return left and right
def verify_red_has_black_children_helper(self, node, red_parent): if node.v is None: return True if "color" not in node.cl: return True if red_parent and node.cl["color"] is not "BLACK": err.log("Red Node \w red parent: " + str(node.v)) return False red_parent = node.cl["color"] is "RED" left = self.verify_red_has_black_children_helper(node.l, red_parent) right = self.verify_red_has_black_children_helper(node.r, red_parent) return left and right
def verify_rb(self): black_or_red = self.verify_black_or_red() black_children = self.verify_red_has_black_children() black_height = self.verify_black_height() is not -1 err.log("Each node is Black or Red: " + str(black_or_red)) err.log("Each Red node has black children: " + str(black_children)) err.log("Black Heights Match: " + str(black_height)) return black_height and black_children and black_or_red
def verify(self, rb=False): ref = self.verify_tree_ref() val = self.verify_tree_val() rbl = self.verify_rb() err.log("Pointers: " + str(ref)) err.log("Value: " + str(val)) if rbl: err.log("RedBlack: " + str(rbl)) return ref and val and (rbl or not rb)
def add_plot(fname, cwd, fig, logn, logt, opsn, opst, t_counts, n_counts, t_pairs, n_pairs, log_marker, xloc, yloc, ax_main, ax_count, ax_vcount, ax_none, ax_small, xmax, xmin, ymax, ymin, xrng, yrng, xlist, ylist, roots, graphs, graph_i, debug): plot_fname = cwd + '/../tmp/' + fname + '_' + str(graph_i) + '.eps' if graph_i == 0: pad_xlim = [xmin - 0.05 * xrng, xmax + 0.05 * xrng] pad_ylim = [ymin - 0.05 * yrng, ymax + 0.05 * yrng] ylim = [0, ymax] yloc.view_limits(ymin, ymax) xloc.view_limits(xmin, xmax) if debug > 1: err.log("Created axes") ax_main.set_xlabel('Element in BST') ax_main.set_ylabel('Time') ax_main.spines['top'].set_visible(False) ax_main.spines['right'].set_visible(False) ax_main.set_axisbelow(True) ax_main.set_aspect('auto', adjustable="box-forced") ax_main.set_xlim(pad_xlim) ax_main.set_ylim(pad_ylim) ax_main.yaxis.set_minor_locator(yloc) ax_main.yaxis.grid(True, which='minor', color=colors.h_light_gray) ax_main.xaxis.set_minor_locator(xloc) ax_main.xaxis.grid(True, which='minor', color=colors.h_light_gray) if debug > 1: err.log("Set up main plot") log = ax_main.scatter([-1] + logn, [-1] + logt, s=1000 / 2 / max(xrng, yrng), c=[colors.h_light_blue] + [ colors.h_light_blue if roots[logt[i]] != logn[i] else colors.h_dark_blue for i in range(0, len(logt)) ], marker=log_marker, label='Intermediate accesses') root_log = ax_main.scatter([-1], [-1], s=1000 / 2 / max(xrng, yrng), c=colors.h_dark_blue, marker=log_marker, label='Root value at this time') if debug > 1: err.log("Plotted Xs") ops = ax_main.scatter(opsn, opst, s=1000 / max(xrng, yrng), c=colors.h_red, marker="o", label='Operation arguments') if debug > 1: err.log("Plotted Os") for i, t in enumerate(logt): if (t, logn[i]) not in t_pairs: t_pairs.add((t, logn[i])) t_counts[t - ymin] += 1 if debug > 1: err.log("Generated y-axis histogram data") if graph_i == 0: xlim = [0, xmax] ax_count.set_xlabel('# Accesses At This Time') ax_count.spines['top'].set_visible(False) ax_count.spines['right'].set_visible(False) ax_count.set_axisbelow(True) ax_count.set_aspect('auto', adjustable="box-forced") ax_count.yaxis.set_minor_locator(yloc) ax_count.yaxis.grid(True, which='minor', color=colors.h_light_gray) ax_count.set_xlim(xlim) ax_count.set_ylim(pad_ylim) ax_count.tick_params(axis='y', which='both', left='off') ax_count.set_yticklabels([]) ax_count.xaxis.get_major_ticks()[0].label1.set_visible(False) if debug > 1: err.log("Set up y-axis histogram axis") hbar = ax_count.barh(ylist, t_counts, min(yrng, 128) / 128, align='center', color=colors.h_dark_blue) if debug > 1: err.log("Created y-axis histogram bar chart") for i, n in enumerate(logn): if (n, logt[i]) not in n_pairs: n_pairs.add((n, logt[i])) n_counts[int(n) - xmin] += 1 if debug > 1: err.log("Generated x-axis histogram data") if graph_i == 0: ax_vcount.set_ylabel('# Accesses of This Element') ax_vcount.spines['right'].set_visible(False) ax_vcount.spines['top'].set_visible(False) ax_vcount.set_axisbelow(True) ax_vcount.set_aspect('auto', adjustable="box-forced") ax_vcount.xaxis.set_minor_locator(xloc) ax_vcount.xaxis.grid(True, which='minor', color=colors.h_light_gray) ax_vcount.set_xlim(pad_xlim) ax_vcount.set_ylim(ylim) ax_vcount.yaxis.set_label_position('left') ax_vcount.yaxis.tick_left() ax_vcount.tick_params(axis='x', which='both', bottom='off') ax_vcount.set_xticklabels([]) ax_vcount.yaxis.get_major_ticks()[0].label1.set_visible(False) sbar = ax_small.barh(ylist, t_counts, 1, align='center', color=colors.h_dark_blue) if debug > 1: err.log("Set up x-axis histogram axis") vbar = ax_vcount.bar(xlist, n_counts, min(xrng, 128) / 128, align='center', color=colors.h_dark_blue) if debug > 1: err.log("Generated y-axis histogram data") if graph_i == 0: ax_none.spines['top'].set_visible(False) ax_none.spines['bottom'].set_visible(False) ax_none.spines['right'].set_visible(False) ax_none.spines['left'].set_visible(False) ax_none.set_xticklabels([]) ax_none.set_yticklabels([]) ax_none.axis('off') ax_main.legend(loc='lower center', bbox_to_anchor=(1, -0.25), ncol=3) if debug > 1: err.log("Set up tree image axis") if len(graphs) > 0: graph = graphs[0] graph.render(cwd + '/../tmp/' + fname + '_' + str(graph_i) + '.gv') if debug > 0: err.log("Saving intermediary graphviz EPS file #" + str(graph_i)) if debug > 0: err.log("Saving intermediary matplotlib EPS file #" + str(graph_i)) plt.savefig(plot_fname, bbox_inches='tight', pad_inches=0.5, format='eps') ax_small.patches = [] ax_count.patches = [] ax_vcount.patches = []
def plot(logn, logt, opsn, opst, pages, graphs, no_clean, debug): fname = str(datetime.now()).replace(' ', '_') plt.rc('font', family='Input Mono') cwd = sys.path[0] try: os.mkdir(cwd + '/../tmp') if debug > 0: err.log('../tmp/ directory created for temporary storage.') except FileExistsError: if debug > 0: err.log( '../tmp/ directory exists; using it for temporary storage.') new_logn = [] new_logt = [] new_pairs = set() for i, t in enumerate(logt): p = (t, logn[i]) if p not in new_pairs: new_logn.append(logn[i]) new_logt.append(t) logn = new_logn logt = new_logt xmax = int(max(logn)) xmin = int(min(logn)) ymax = int(max(logt)) ymin = int(min(logt)) xrng = max(xmax - xmin, 0) yrng = max(ymax - ymin, 0) roots = {} t_counts = np.zeros(yrng + 1) n_counts = np.zeros(xrng + 1) t_pairs = set() n_pairs = set() ylist = range(ymin, ymax + 1) xlist = range(xmin, xmax + 1) xticker_base = 1.0 if xrng > ticker.MultipleLocator.MAXTICKS - 50: xticker_base = xrng / ticker.MultipleLocator.MAXTICKS * 1.5 yticker_base = 1.0 if yrng > ticker.MultipleLocator.MAXTICKS - 50: yticker_base = yrng / ticker.MultipleLocator.MAXTICKS * 1.5 yloc = ticker.MultipleLocator(base=yticker_base) xloc = ticker.MultipleLocator(base=xticker_base) fig = plt.figure(figsize=(10, 10)) fontP = FontProperties() fontP.set_size('small') gs = gridspec.GridSpec(2, 2) kx = dict(aspect='auto') ax_main = plt.subplot(gs[1, 0], **kx) ax_count = plt.subplot(gs[1, 1], **kx) ax_vcount = plt.subplot(gs[0, 0], **kx) ax_none = plt.subplot(gs[0, 1], **kx) ax_small = plt.axes([0.73, 0.11, 0.17, 0.17]) ax_main.yaxis.set_major_locator(ticker.MaxNLocator(integer=True)) ax_main.xaxis.set_major_locator(ticker.MaxNLocator(integer=True)) ax_count.yaxis.set_major_locator(ticker.MaxNLocator(integer=True)) ax_count.xaxis.set_major_locator(ticker.MaxNLocator(integer=True)) ax_vcount.yaxis.set_major_locator(ticker.MaxNLocator(integer=True)) ax_vcount.xaxis.set_major_locator(ticker.MaxNLocator(integer=True)) plt.xticks([]) plt.yticks([]) ax_small.yaxis.set_minor_locator(yloc) ax_small.yaxis.grid(True, which='minor', color=colors.h_light_gray) ax_small.set_axisbelow(True) gs.update(wspace=0.00, hspace=-0.00) log_marker = 'x' if len(opst) > 50: if debug > 1: err.log('Input size is ' + str(len(opst)) + ', using marker \'o\'') log_marker = 'o' elif debug > 1: err.log('Input size is ' + str(len(opst)) + ', using marker \'x\'') if pages: partial_logn = [] partial_logt = [] partial_opst = [] partial_opsn = [] last_logt_i = 0 logt_i = 0 for i in range(0, len(opst)): if debug > 1: err.log("Generating data plot number " + str(i)) partial_opst = [opst[i]] partial_opsn = [opsn[i]] op_t = opst[i] last_logt_i = logt_i + 1 roots = {} while logt_i + 1 < len(logt) and logt[logt_i + 1] <= op_t: logt_i += 1 roots[logt[last_logt_i]] = logn[last_logt_i] partial_logn = [] partial_logt = [] for j in range(last_logt_i, logt_i + 1): partial_logt.append(logt[j]) partial_logn.append(logn[j]) if debug > 1: err.log("Starting plot generation") add_plot(fname, cwd, fig, partial_logn, partial_logt, partial_opsn, partial_opst, t_counts, n_counts, t_pairs, n_pairs, log_marker, xloc, yloc, ax_main, ax_count, ax_vcount, ax_none, ax_small, xmax, xmin, ymax, ymin, xrng, yrng, xlist, ylist, roots, graphs, i, debug) if len(graphs) > 0: del graphs[0] else: for i, t in enumerate(logt): if t not in roots.keys(): roots[t] = logn[i] add_plot(fname, cwd, fig, logn, logt, opsn, opst, t_counts, n_counts, t_pairs, n_pairs, log_marker, xloc, yloc, ax_main, ax_count, ax_vcount, ax_none, ax_small, xmax, xmin, ymax, ymin, xrng, yrng, xlist, ylist, roots, graphs, 0, debug) plt.close() page_list = [] page_size = document.paperformat(200, 200) num_plots = 1 if pages: num_plots = len(opsn) for i in range(0, num_plots): if debug > 0: err.log("Concatenating PS pages for plot #" + str(i)) plots_name = cwd + '/../tmp/' + fname + '_' + str(i) + '.eps' tree_name = cwd + '/../tmp/' + fname + '_' + str(i) + '.gv.eps' got_tree = True try: tree_file = open(tree_name, 'r') tree_w = 0 tree_h = 0 for line in tree_file: if line.startswith("%%BoundingBox:"): bbline = line.split() tree_w = bbline[3] tree_h = bbline[4] if debug > 1: err.log( "In EPS #{} got height: {} and width {} from line {}" .format(i, tree_h, tree_w, line.replace('\n', ''))) break else: err.err( "BoundingBox line not found in EPS file for tree diagram.") tree_file.close() except: got_tree = False c = canvas.canvas() plots_file = epsfile.epsfile(0, 0, plots_name, height=160, width=160) c.insert(plots_file) if got_tree: if tree_w > tree_h: tree_file = epsfile.epsfile(120, 120, tree_name, align='cc', width=70) else: tree_file = epsfile.epsfile(120, 120, tree_name, align='cc', height=70) c.insert(tree_file) p = document.page(c, fittosize=True, centered=True, paperformat=page_size) if no_clean: c.writeEPSfile(cwd + '/../tmp/' + fname + '_' + str(i) + '.zipped.eps') page_list.append(p) d = document.document(page_list) out_name = cwd + '/../outputs/' + fname + '.ps' if debug > 0: err.log("Saving final output " + out_name) d.writePSfile(out_name) if not no_clean: for tmpf in os.listdir(cwd + '/../tmp/'): os.remove(cwd + '/../tmp/' + tmpf) os.rmdir(cwd + '/../tmp/')
def exec_ops(self, algo, pages, gen_graphs, no_clean, debug): logt = [] logn = [] opst = [] opsn = [] graphs = [] api = API(logn, logt, gen_graphs, graphs, debug) if algo == 'simple': tree = SimpleBST(api) elif algo == 'rb': tree = RedBlackBST(api) elif algo == 'splay': tree = SplayBST(api) elif algo == 'avl': err.err("Algorithm not yet implemented") elif algo == 'wavl': err.err("Algorithm not yet implemented") elif algo == 'tango': err.err("Algorithm not yet implemented") elif algo == 'static': err.err("Algorithm not yet implemented") time = 1 for op in self.ops: if debug > 2: tree_str = str(tree) if debug > 1: err.log("operation #" + str(time) + ": " + str(op)) api.reset() if op.op == 'ins': opst.append(time) opsn.append(op.arg) api.set_time(time) api.set_log_on() tree.insert(op.arg) api.set_log_off() time += 1 elif op.op == 'sea': opst.append(time) opsn.append(op.arg) api.set_time(time) api.set_log_on() tree.search(op.arg) api.set_log_off() time += 1 elif op.op == 'del': opst.append(time) opsn.append(op.arg) api.set_time(time) api.set_log_on() tree.delete(op.arg) api.set_log_off() time += 1 if debug == 2: err.warn(tree) if debug > 2: err.log("Before op, tree was:") err.warn(tree_str) err.log("After op, tree is:") err.warn(tree) err.warn("Beginning tree verification:") if tree.verify_tree(): err.warn("Verified") else: err.err("Issue found when verifying tree!") if gen_graphs and pages: api.viz() if gen_graphs and not pages: api.viz() if debug == 1 and len(self.ops) < 50: err.warn(tree) plot.plot(logn, logt, opsn, opst, pages, graphs, no_clean, debug)