def is_undetermined(x): num_samples, ndim = x.shape if num_samples <= ndim: err.warn('regression is underdetermined: {}'.format( x.shape)) #: {}'.format(x)) return True else: return False
def overapprox_x0(num_dims, prop, pwa_trace, solver=gopts.opt_engine): cons, Vars, vars_grouped_by_state = pwatrace2cons(pwa_trace, num_dims, prop) cons = list(cons) num_opt_vars = len(Vars) nvars = num_dims.x + num_dims.pi #directions = [(1, 0), (-1, 0), (0, 1), (0, -1)] I = np.eye(nvars) directions = np.vstack((I, -I)) left_over_vars = num_opt_vars - nvars directions_ext = np.pad(directions, [(0, 0), (0, left_over_vars)], 'constant') var_array = np.array(Vars) for direction in directions_ext: print(np.dot(direction, var_array)) #lambdafied = tuple( # sym.lambdify(Vars, np.dot(direction, var_array), str('numpy')) for direction in directions_ext) #obj_f = tuple(lambda x, l=l: l(*x) for l in lambdafied) objs = tuple(np.dot(direction, var_array) for direction in directions_ext) x_arr = np.array(sym.symbols(['x{}'.format(i) for i in range(nvars)])) res = solve_mult_opt(nlpfun(solver), objs, cons, Vars) l = len(res) assert (l % 2 == 0) min_res, max_res = res[:l // 2], res[l // 2:] ranges = [] for di, rmin, rmax in zip(directions, min_res, max_res): if (rmin.success and rmax.success): print('{} \in [{}, {}]'.format(np.dot(di, x_arr), rmin.fun, -rmax.fun)) ranges.append([rmin.fun, -rmax.fun]) else: if settings.debug: print('LP failed') print('rmin status:', rmin.status) print('rmax status:', rmax.status) return None r = np.asarray(ranges) # due to numerical errors, the interval can be malformed try: ret_val = IntervalCons(r[:, 0], r[:, 1]) except ValueError: err.warn('linprog fp failure: Malformed Interval! Please fix.') return None print(ret_val) U.pause() return ret_val
def plot_rect(self, r, edgecolor="k"): if len(r[0]) > 2: err.warn("dim>2, projecting before plottting the rectangle on the first 2 dims.") c = r[0][0:2] rng = r[1][0:2] else: c = r[0] rng = r[1] self.ax.add_patch( patches.Rectangle(c, *rng, fill=False, edgecolor=edgecolor) # patches.Rectangle((0.1, 0.1), 0.5, 0.5, fill=False) )
def cell_affine_models(cell, step_sim, ntrain, ntest, tol, include_err): """cell_affine_models Parameters ---------- cell : cell step_sim : 1 time step (delta_t) simulator tol : each abs state is split further into num_splits cells in order to meet: modeling error < tol (module ntests samples) Returns ------- pwa.SubModel() Notes ------ """ # XXX: Generate different samples for each time step or reuse? # Not clear! sub_models = [] X, Y = getxy_ignoramous(cell, ntrain, step_sim) rm = RegressionModel(X, Y) X, Y = getxy_ignoramous(cell, ntest, step_sim) e_pc = rm.error_pc(X, Y) # error % if __debug__: print('error%:', e_pc) #error = np.linalg.norm(e_pc, 2) # error exceeds tol in error_dims error_dims = np.arange(len(e_pc))[np.where(e_pc >= tol)] if len(error_dims) > 0: err.warn('splitting on e%:{}, |e%|:{}'.format( e_pc, np.linalg.norm(e_pc, 2))) for split_cell in cell.split(axes=error_dims): sub_models_ = cell_affine_models( split_cell, step_sim, ntrain, ntest, tol, include_err) sub_models.extend(sub_models_) return sub_models else: #print('error%:', rm.error_pc(X, Y)) A, b = rm.Ab C, d = cell.ival_constraints.poly() e = rm.error(X, Y) if include_err else None dmap = pwa.DiscreteAffineMap(A, b, e) part = pwa.Partition(C, d, cell) sub_model = pwa.SubModel(part, dmap) if __debug__: print('----------------Finalized------------------') return [sub_model]
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 plot_rect(self, r, edgecolor='k'): if len(r[0]) > 2: err.warn( 'dim>2, projecting before plottting the rectangle on the first 2 dims.' ) c = r[0][0:2] rng = r[1][0:2] else: c = r[0] rng = r[1] self.ax().add_patch( patches.Rectangle(c, *rng, fill=False, edgecolor=edgecolor, linewidth=2) #patches.Rectangle((0.1, 0.1), 0.5, 0.5, fill=False) )
def wraped_call(tcd): err.warn('wraped_call being used!') tcd.input_array = np.array( [int(round(i * cf)) for i in tcd.input_array]) tcd.state_array = np.array( [int(round(i * cf)) for i in tcd.state_array]) tcd.x_array = np.array([int(round(i * cf)) for i in tcd.x_array]) # tcd.state_array = (tcd.state_array * cf).astype(int) # tcd.x_array = (tcd.x_array * cf).astype(int) fcd = controller_call_fun(tcd) # WHY ROUND here??? # fcd.state_array = list((np.round(fcd.state_array / cf).astype(float))) # fcd.output_array = list((np.round(fcd.output_array / cf).astype(float))) fcd.state_array = list(fcd.state_array.astype(float) / cf) fcd.output_array = list(fcd.output_array.astype(float) / cf) return fcd
def trace_generator(self, depth): # TODO: make the graph search depth bounded? err.warn('ignoring depth') path_gen = self.pwa_model.get_all_path_generator( self.sources, self.targets) path_ctr = 0 for path in path_gen: path_ctr += 1 ptrace = [self.pwa_model.node_p(qi) for qi in path] mtrace = [ self.pwa_model.edge_m((qi, qj)) for qi, qj in U.pairwise(path) ] pwa_trace = PWATRACE(partitions=ptrace, models=mtrace) x_array = azp.feasible(self.num_dims, self.prop, pwa_trace) if x_array is not None: concrete_trace = ConcreteTrace(x_array, pwa_trace) print('Model Found') yield concrete_trace, pwa_trace print('Total paths checked: {}'.format(path_ctr)) return
def build_pwa_dt_model(AA, abs_states, sp, sys_sim): """build_pwa_dt_model Parameters ---------- AA : AA is abs_states : abs_states is sp : sp is sys_sim : sys_sim is Returns ------- Notes ------ Builds a model with time as a discrete variable. i.e., models the behaviors resulting from several chosen time steps and not only the one specified in .tst as delta_t. """ dt_steps = [0.01, 0.1, AA.plant_abs.delta_t] err.warn('using time steps: {}'.format(dt_steps)) step_sims = [simsys.get_step_simulator(sp.controller_sim, sp.plant_sim, dt) for dt in dt_steps] pwa_models = {} for dt, step_sim in zip(dt_steps, step_sims): pwa_model = pwa.PWA() for abs_state in abs_states: sub_model = affine_model(abs_state, AA, sp, step_sim) pwa_model.add(sub_model) pwa_models[dt] = pwa_model return pwa_models
def getxy_rel_ignoramous(cell1, cell2, force, N, sim, t0=0): """getxy_rel_ignoramous Parameters ---------- force : force to return non-zero samples. Will loop for infinitiy if none exists. """ xl = [] yl = [] sat_count = 0 iter_count = itertools.count() print(cell1.ival_constraints) print(cell2.ival_constraints) if __debug__: obs_cells = set() while next(iter_count) <= MAX_ITER: x_array, y_array = getxy_ignoramous(cell1, N, sim, t0=0) if __debug__: for i in y_array: obs_cells.add(CM.cell_from_concrete(i, cell1.eps)) print('reachable cells:', obs_cells) # satisfying indexes sat_array = cell2.ival_constraints.sat(y_array) sat_count += np.sum(sat_array) xl.append(x_array[sat_array]) yl.append(y_array[sat_array]) if sat_count >= MIN_TRAIN: break # If no sample is found and force is True, must keep sampling till # satisfying samples are found if __debug__: if sat_count < MIN_TRAIN: err.warn('Fewer than MIN_TRAIN samples found!') print('found samples: ', sat_count) return np.vstack(xl), np.vstack(yl)
elif algarg in {'avl', 'avltree'}: algo = algs[3] elif algarg in {'wavl', 'wavltree', 'weakavl', 'weakavltree'}: algo = algs[4] elif algarg in {'tango', 'tangotree'}: algo = algs[5] elif algarg in { 'static', 'osbst', 'optimalstatic', 'opt', 'optbst', 'optimalstaticbst' }: algo = algs[6] else: err.err("Algorithm not recognized.") debug = args.debug_level if args.debug and debug == 0: debug = 1 if debug == 1: err.warn("Debug mode is set to: SIMPLE") elif debug == 2: err.warn("Debug mode is set to: VERBOSE") elif debug == 3: err.warn("Debug mode is set to: VERIFY") ops.exec_ops(algo, args.pages, args.graphs, args.clean_off, debug)
def plot(self, X, Y, tol, title='unknown'): from matplotlib import pyplot as plt from mpl_toolkits.mplot3d import Axes3D dimX = X.shape[1] assert (dimX == 2) # if 1 or less rows if X.shape[0] <= 1: err.warn('cant plot, only 1 value!!') return div = 50 X_min, X_max = np.min(X, axis=0), np.max(X, axis=0) step0 = (X_max[0] - X_min[0]) / div step1 = (X_max[1] - X_min[1]) / div step = min(step0, step1) #print('x0 range:', X_min[0], X_max[0]) #print('x1 range:', X_min[1], X_max[1]) # Predict data of estimated models xx1, xx2 = np.mgrid[X_min[0]:X_max[0]:step, X_min[1]:X_max[1]:step] xx = np.vstack([xx1.ravel(), xx2.ravel()]).T yy = self.predict(xx) yy0 = yy[:, 0] yy1 = yy[:, 1] Y0 = Y[:, 0] Y1 = Y[:, 1] error_pc = self.error_pc(X, Y) outlier0_idx = error_pc[:, 0] > tol outlier1_idx = error_pc[:, 1] > tol if any(outlier0_idx): #print('X:\n', X[outlier0_idx, :]) #print('Y0_pred:', self.predict(X[outlier0_idx, :])[:, 0]) #print('Y0_true', Y0[outlier0_idx]) Y0_pred_ = self.predict(X[outlier0_idx, :])[:, 0] Y0_pred = np.reshape(Y0_pred_, (Y0_pred_.size, 1)) # make it 2-dim to match dim of X and Y0_pred Y0_true_ = Y0[outlier0_idx] Y0_true = np.reshape(Y0_true_, (Y0_true_.size, 1)) epc0_ = error_pc[outlier0_idx, 0] epc0 = np.reshape(epc0_, (epc0_.size, 1)) logger.debug('X - Y0_pred - Y0_true - error_pc') logger.debug( np.hstack((X[outlier0_idx, :], Y0_pred, Y0_true, epc0))) if any(outlier1_idx): Y1_pred_ = self.predict(X[outlier1_idx, :])[:, 1] Y1_pred = np.reshape(Y1_pred_, (Y1_pred_.size, 1)) # make it 2-dim to match dim of X and Y1_pred Y1_true_ = Y1[outlier1_idx] Y1_true = np.reshape(Y1_true_, (Y1_true_.size, 1)) epc1_ = error_pc[outlier1_idx, 1] epc1 = np.reshape(epc1_, (epc1_.size, 1)) logger.debug('X - Y1_pred - Y1_true - error_pc') logger.debug( np.hstack((X[outlier1_idx, :], Y1_pred, Y1_true, epc1))) # plot the surface #print(xx) #print(xx2) #print(yy[:, 0]) #embed() ################ # First subplot ################ fig = plt.figure() #figsize=plt.figaspect(2.)) fig.suptitle(title) ax = fig.add_subplot(2, 1, 1, projection='3d') ax.plot_surface(xx1, xx2, np.reshape(yy0, (xx1.shape))) ax.plot(X[:, 0], X[:, 1], Y0, 'y.') ax.plot(X[outlier0_idx, 0], X[outlier0_idx, 1], Y0[outlier0_idx], 'r.') ax.set_title('y0 vs x') ax.set_xlabel('x0') ax.set_ylabel('x1') ax.set_zlabel('y0') ################# # Second subplot ################# ax = fig.add_subplot(2, 1, 2, projection='3d') ax.plot_surface(xx1, xx2, np.reshape(yy1, (xx1.shape))) ax.plot(X[:, 0], X[:, 1], Y1, 'y.') ax.plot(X[outlier1_idx, 0], X[outlier1_idx, 1], Y1[outlier1_idx], 'r.') ax.set_title('y1 vs x') ax.set_xlabel('x0') ax.set_ylabel('x1') ax.set_zlabel('y1')
def cell_rel_affine_models(cell1, cell2, force, step_sim, ntrain, ntest, tol, include_err): """cell_affine_models Parameters ---------- cell1 : source cell cell2 : target cell step_sim : 1 time step (delta_t) simulator tol : each abs state is split further into num_splits cells in order to meet: modeling error < tol (module ntests samples) Returns ------- pwa.SubModel() Notes ------ """ # XXX: Generate different samples for each time step or reuse? # Not clear! sub_models = [] X, Y = getxy_rel_ignoramous(cell1, cell2, force, ntrain, step_sim) # No samples found => no model training_samples_found = len(X) != 0 if not training_samples_found: return [None] rm = RegressionModel(X, Y) X, Y = getxy_rel_ignoramous(cell1, cell2, True, ntest, step_sim) testing_samples_found = len(X) != 0 # If valid samples are found, compute e_pc (error %) and dims # where error % >= given tol if testing_samples_found: e_pc = rm.error_pc(X, Y) error_dims = np.arange(len(e_pc))[np.where(e_pc >= tol)] # Otherwise, forget it! else: e_pc = None error_dims = [] if __debug__: print('error%:', e_pc) if len(error_dims) > 0: err.warn('splitting on e%:{}, |e%|:{}'.format( e_pc, np.linalg.norm(e_pc, 2))) for split_cell1 in cell1.split(axes=error_dims): sub_models_ = cell_rel_affine_models( split_cell1, cell2, False, step_sim, ntrain, ntest, tol, include_err) sub_models.extend(sub_models_) return sub_models else: A, b = rm.Ab C1, d1 = cell1.ival_constraints.poly() C2, d2 = cell2.ival_constraints.poly() e = rm.error(X, Y) if (include_err and testing_samples_found) else None dmap = rel.DiscreteAffineMap(A, b, e) part1 = rel.Partition(C1, d1, cell1) part2 = rel.Partition(C2, d2, cell2) sub_model = rel.Relation(part1, part2, dmap) if __debug__: print('----------------Finalized------------------') return [sub_model]
def warn_if_small_data_set(x): if len(x) <= 2: err.warn_severe('Less than 2 training samples!: {}'.format(x)) elif len(x) <= 10: err.warn('Less than 10 training samples!: {}'.format(x))
def get_all_path_generator( G, source_list, sink_list, max_depth, max_paths ): # Define super source and sink nodes # A Super source node has a directed edge to each source node in the # source_list # Similarily, a Super sink node has a directed edge from each sink node # in the sink_list dummy_super_source_node = 'source' dummy_super_sink_node = 'sink' num_source_nodes = len(source_list) num_sink_nodes = len(sink_list) # increment max_depth by 2 to accommodate edges from 'super source' and # to 'super sink' max_depth += 2 # Add edges: # \forall source \in source_list. super source node -> source edge_list = list(zip([dummy_super_source_node] * num_source_nodes, source_list)) G.add_edges_from(edge_list) if settings.debug: U.eprint('source -> list') for e in edge_list: U.eprint(e) # Add edges: # \forall sink \in sink_list. sink -> super sink node edge_list = list(zip(sink_list, [dummy_super_sink_node] * num_sink_nodes)) G.add_edges_from(edge_list) if settings.debug: U.eprint('sink -> list') for e in edge_list: U.eprint(e) if settings.debug: #print(the graph first) U.eprint('Printing graph...') for e in G.G.edges(): s, t = e U.eprint('{}, {}'.format(G.v_attr[s], G.v_attr[t])) U.eprint('Printing graph...done') path_it = G.all_shortest_paths(dummy_super_source_node, dummy_super_sink_node, ) if settings.debug: U.eprint('path list') paths = list(path_it) for path in paths[0:max_paths]: p = [G.v_attr[v] for v in path] U.eprint(p) path_it = (i for i in paths) ############################################################# # TODO: Remove the extra step to count paths # It is there just as a debug print paths = list(U.bounded_iter(path_it, max_paths)) num_paths = len(paths) err.warn('counting paths...found: {}'.format(num_paths)) def path_gen(): for path in paths: p = [G.v_attr[v] for v in path] yield p[1:-1] # END: CODE TO BE REMOVED # CORRECT CODE BELOW # def path_gen(): # for path in U.bounded_iter(path_it, max_paths): # p = [G.v_attr[v] for v in path] # yield p[1:-1] ############################################################# return path_gen()
def init( A, init_cons_list_plant, final_cons, init_d, controller_init_state, ): PA = A.plant_abs d, pvt, n = init_d, (0, ), 0 plant_initial_state_set = set() def f(init_cons_): return PA.get_abs_state_set_from_ival_constraints(init_cons_, n, d, pvt) for init_cons in init_cons_list_plant: init_abs_states = f(init_cons) # filters away zero measure sets def fnzm(as_): intsec = PA.get_ival_cons_abs_state(as_) & init_cons return (intsec is not None) and not intsec.zero_measure err.warn('what is going on?') #filt_init_abs_states = filter(fnzm, init_abs_states) filt_init_abs_states = init_abs_states plant_initial_state_set.update(filt_init_abs_states) # Old code to compute plant_initial_state_set # plant_initial_state_list = [] # for init_cons in init_cons_list_plant: # plant_initial_state_list += \ # PA.get_abs_state_set_from_ival_constraints(init_cons, n, d, pvt) # plant_initial_state_set = set(plant_initial_state_list) # The below can be very very expensive in time and memory for large final # sets! # plant_final_state_set = \ # set(PA.get_abs_state_set_from_ival_constraints(final_cons, 0, 0, 0)) # ##!!##logger.debug('{0}initial plant states{0}\n{1}'.format('=' * 10, plant_initial_state_set)) # set control states for initial states # TODO: ideally the initial control states should be supplied by the # user and the below initialization should be agnostic to the type initial_state_list = [] for plant_init_state in plant_initial_state_set: initial_state_list.append(AA.TopLevelAbs.get_abs_state(plant_state=plant_init_state)) #final_state_list = [] # for plant_final_state in plant_final_state_set: # final_state_list.append(AA.TopLevelAbs.get_abs_state( # plant_state=plant_final_state, # controller_state=controller_init_abs_state)) # print('='*80) # print('all final states') # for ps in plant_final_state_set: # print(ps) # print('='*80) def is_final(_A, abs_state): #print('----------isfinal-----------') #print(abs_state.plant_state.cell_id == ps.cell_id) #print(abs_state.plant_state in plant_final_state_set) #print(hash(abs_state.plant_state), hash(ps)) #print(abs_state.plant_state == ps) #if abs_state.plant_state.cell_id == ps.cell_id: #exit() # return abs_state.plant_state in plant_final_state_set #print('---------------------------------------------') #print(_A.plant_abs.get_ival_constraints(abs_state.ps)) #print('---------------------------------------------') pabs_ic = _A.plant_abs.get_ival_cons_abs_state(abs_state.plant_state) intersection = pabs_ic & final_cons return not(intersection is None or intersection.zero_measure) # ##!!##logger.debug('{0}initial{0}\n{1}'.format('=' * 10, plant_initial_state_set)) return (set(initial_state_list), is_final)
def overapprox_x0(num_dims, prop, pwa_trace, solver=gopts.opt_engine): A_ub, b_ub = pwatrace2lincons(pwa_trace, num_dims, prop) num_opt_vars = A_ub.shape[1] nvars = num_dims.x + num_dims.pi #directions = [(1, 0), (-1, 0), (0, 1), (0, -1)] I = np.eye(nvars) directions = np.vstack((I, -I)) left_over_vars = num_opt_vars - nvars directions_ext = np.pad(directions, [(0, 0), (0, left_over_vars)], 'constant') # LP structure: A_ub [x x'] <= b_ub x_arr = np.array(sym.symbols(['x{}'.format(i) for i in range(nvars)])) A_ub, b_ub = truncate(A_ub, b_ub) res = solve_mult_lp(lpfun(solver), directions_ext, A_ub, b_ub) l = len(res) assert (l % 2 == 0) #min_directions, max_directions = np.split(directions, l/2, axis=1) min_res, max_res = res[:l // 2], res[l // 2:] ranges = [] for di, rmin, rmax in zip(directions, min_res, max_res): if (rmin.success and rmax.success): print('{} \in [{}, {}]'.format(np.dot(di, x_arr), rmin.fun, -rmax.fun)) ranges.append([rmin.fun, -rmax.fun]) else: if settings.debug: print('LP failed') print('rmin status:', rmin.status) print('rmax status:', rmax.status) return None #raise e # For python2/3 compatibility # try: # input = raw_input # except NameError: # pass # prompt = input('load the prompt? (y/Y)') # if prompt.lower() == 'y': # import IPython # IPython.embed() #ranges = [[0.00416187, 0.00416187],[3.47047152,3.47047152],[9.98626028,9.98626028],[4.98715449,4.98715449]] r = np.asarray(ranges) # due to numerical errors, the interval can be malformed try: ret_val = cons.IntervalCons(r[:, 0], r[:, 1]) except: #from IPython import embed err.warn('linprog fp failure: Malformed Interval! Please fix.') #embed() return None return ret_val
def get_all_path_generator( G, source_list, sink_list, max_depth, max_paths ): # Define super source and sink nodes # A Super source node has a directed edge to each source node in the # source_list # Similarily, a Super sink node has a directed edge from each sink node # in the sink_list dummy_super_source_node = 'source' dummy_super_sink_node = 'sink' num_source_nodes = len(source_list) num_sink_nodes = len(sink_list) # increment max_depth by 2 to accommodate edges from 'super source' and # to 'super sink' max_depth += 2 # Add edges: # \forall source \in source_list. super source node -> source edge_list = zip([dummy_super_source_node] * num_source_nodes, source_list) G.add_edges_from(edge_list) if __debug__: print >> sys.stderr, 'source -> list' for e in edge_list: print >> sys.stderr, e # Add edges: # \forall sink \in sink_list. sink -> super sink node edge_list = zip(sink_list, [dummy_super_sink_node] * num_sink_nodes) G.add_edges_from(edge_list) if __debug__: print >> sys.stderr, 'sink -> list' for e in edge_list: print >> sys.stderr, e if __debug__: #print the graph first print >>sys.stderr, 'Printing graph...' for e in G.G.edges(): s, t = e print >>sys.stderr, '{}, {}'.format(G.v_attr[s], G.v_attr[t]) print >>sys.stderr, 'Printing graph...done' path_it = G.all_shortest_paths(dummy_super_source_node, dummy_super_sink_node, ) if __debug__: print >> sys.stderr, 'path list' paths = list(path_it) for path in paths[0:max_paths]: p = [G.v_attr[v] for v in path] print >> sys.stderr, p path_it = (i for i in paths) ############################################################# # TODO: Remove the extra step to count paths # It is there just as a debug print paths = list(U.bounded_iter(path_it, max_paths)) num_paths = len(paths) err.warn('counting paths...found: {}'.format(num_paths)) def path_gen(): for path in paths: p = [G.v_attr[v] for v in path] yield p[1:-1] # END: CODE TO BE REMOVED # CORRECT CODE BELOW # def path_gen(): # for path in U.bounded_iter(path_it, max_paths): # p = [G.v_attr[v] for v in path] # yield p[1:-1] ############################################################# return path_gen()
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)