def add_input_star(self, a_matrix_t, b_vec, input_basis_matrix): '''minkowski add an input star into the lp (creates 1 new variable for each input)''' assert len(a_matrix_t.shape) == 2 assert len(b_vec.shape) == 1 assert a_matrix_t.shape[1] == b_vec.shape[ 0], "number of rows in constraints must match" assert a_matrix_t.shape[0] == input_basis_matrix.shape[0], \ "number of columns in constraint matix / rows in input basis matrix must match" assert input_basis_matrix.shape[ 1] == self.num_standard_vars, "input basis matrix cols must match standard vars" if self.num_inputs is None: self.num_inputs = input_basis_matrix.shape[0] else: assert input_basis_matrix.shape[ 0] == self.num_inputs, "num_inputs changed between calls to add_input_star" Timers.tic("lp add_input_star") LpInstance._add_input_star(self.lp_data, a_matrix_t, a_matrix_t.shape[1], a_matrix_t.shape[0], b_vec, \ b_vec.shape[0], input_basis_matrix, input_basis_matrix.shape[1], input_basis_matrix.shape[0]) Timers.toc("lp add_input_star")
def do_step_reach(self): 'do a single reach step of the computation' Timers.tic('do_step') if not self.is_finished(): if self.aggdag.get_cur_state(): self.do_step_continuous_post() self.continuous_steps += 1 elif self.aggdag.deagg_man.doing_replay(): # in the middle of a deaggregation replay self.aggdag.deagg_man.do_step_replay() else: # begin a deaggregation replay or pop a state off the waiting list deagg_node = self.settings.aggstrat.get_deagg_node(self.aggdag) if deagg_node: self.aggdag.deagg_man.begin_replay(deagg_node) self.aggdag.deagg_man.do_step_replay() else: #print(".core popping, calling aggdag.save_viz()") #self.aggdag.save_viz() # pop state off waiting list self.do_step_pop() if self.settings.process_urgent_guards and self.aggdag.get_cur_state( ) is not None: self.check_guards() Timers.toc('do_step')
def get_box_center(lpi): '''get the center of the box overapproximation of the passed-in lpi may return None if lp solving fails (numerical issues) ''' Timers.tic('get_box_center') dims = lpi.dims pt = [] for dim in range(dims): col = lpi.cur_vars_offset + dim min_dir = [1 if i == dim else 0 for i in range(dims)] max_dir = [-1 if i == dim else 0 for i in range(dims)] min_val = lpi.minimize(direction_vec=min_dir, columns=[col], fail_on_unsat=False) max_val = lpi.minimize(direction_vec=max_dir, columns=[col], fail_on_unsat=False) if min_val is None or max_val is None: pt = None break min_val = min_val[0] max_val = max_val[0] pt.append((min_val + max_val) / 2.0) Timers.toc('get_box_center') return pt
def check_intersection(lpi, lc, tol=1e-13): '''check if there is an intersection between the LP constriants and the LinearConstraint object lc This solves an LP optimizing in the given direction... without adding the constraint to the LP This returns True/False if an intersection is possible it also can return None if the lp is infeasible ''' Timers.tic("check_intersection") lpi.set_minimize_direction(lc.csr, is_csr=True) columns = lc.csr.indices[0:lc.csr.indptr[1]] lp_columns = [lpi.cur_vars_offset + c for c in columns] lp_res = lpi.minimize(columns=lp_columns, fail_on_unsat=False) if lp_res is None: # sometimes, changing optimization direction makes lp infeasible (up to numerical accuracy) # this happens in gearbox with small time steps. In this case, return no intersection rv = None else: dot_res = np.dot(lc.csr.data, lp_res) rv = dot_res + tol <= lc.rhs Timers.toc("check_intersection") return rv
def vector_to_star_basis(self, standard_vec): ''' convert a vector in the standard basis to a point in the star's basis. This solves basis_matrix * rv = input, which is essentially computing the inverse of basis_matrix, which can become ill-conditioned. ''' Timers.tic("vector_to_star_basis()") rv = np.linalg.solve(self.basis_matrix.T, standard_vec) #rv = lstsq(self.basis_matrix.T, np.array(standard_vec, dtype=float))[0] # double-check that we've found the solution within some tolerance if not np.allclose(np.dot(self.basis_matrix.T, rv), standard_vec): raise RuntimeError( "basis matrix was ill-conditioned, vector_to_star_basis() failed" ) Timers.toc("vector_to_star_basis()") assert isinstance(rv, np.ndarray) return rv
def replay_op(self, op_list, i): ''' replay a single operation in the current node this is used when nodes are split, to leverage parent information ''' Timers.tic('replay_op') assert not self.node_left_invariant() op = op_list[i] cur_state = self.get_cur_state() assert cur_state is not None self.aggdag.core.print_verbose(f"replaying {i}: {op}") if isinstance(op, OpLeftInvariant): self.op_list.append(op) elif isinstance(op, OpTransition): self.replay_op_transition(cur_state, op) elif isinstance(op, OpInvIntersect): # if there is a later invariant intersection with the same hyperplane and it's stronger, skip this one skip = False for future_i in range(i + 1, len(op_list)): future_op = op_list[future_i] if not isinstance(future_op, OpInvIntersect): # another op (such as a transition, can't skip current one) break if future_op.i_index == op.i_index: if future_op.is_stronger: skip = True break #print(".aggdag %%%% debug never skipping invariant intersection") # hmm, skipping invariant intersections is only valid if deaggregation is a subset of aggregated set... # for our krylov aggregation, this isn't really the case though... so in general you need to invaraint # intersect at every step... plus this is really an optimization rather than the main algorithm if True or not skip: self.aggdag.core.print_verbose( f"doing invariant intersection in replay at step {cur_state.cur_step_in_mode}" ) is_feasible = self.replay_op_intersect_invariant(cur_state, op) if not is_feasible: op = OpLeftInvariant(op.step, self, False) self.op_list.append(op) else: self.aggdag.core.print_verbose( "skipping invariant intersection because stronger one is coming up" ) Timers.toc('replay_op')
def compute_robust_ce(self): Timers.tic('Robust counter-example generation time') lce_object = self.compute_longest_ce() longest_ce_lpi = lce_object.usafe_lpi # longest_ce_lpi = self.create_lpi(lce_object) directions = np.identity(self.num_dims, dtype=float) robust_point = np.zeros(self.num_dims) for index in range(self.num_dims): direction = directions[index] result = np.zeros(self.num_dims) is_feasible = longest_ce_lpi.minimize(-1 * direction, result, error_if_infeasible=False) basis_matrix = self.init_star.basis_matrix if is_feasible: point1 = np.dot(basis_matrix, result) print("Depth {}".format(sum(direction * result))) result = np.zeros(self.num_dims) is_feasible = longest_ce_lpi.minimize(direction, result, error_if_infeasible=False) if is_feasible: point2 = np.dot(basis_matrix, result) print("Depth {}".format(sum(direction * result))) # print ("Points for the direction {} are {} and {}".format(direction, point1, point2)) current_point = (point1 + point2) / 2 robust_point[index] = np.dot(current_point, direction) print("Robust point is '{}'".format(robust_point)) Timers.toc('Robust counter-example generation time') return robust_point
def check_guards(self): '''check for discrete successors with the guards''' Timers.tic("check_guards") cur_state = self.aggdag.get_cur_state() for t in cur_state.mode.transitions: t_lpi = t.get_guard_intersection(cur_state.lpi) if t_lpi: if t.to_mode.is_error(): self.error_reached(cur_state, t, t_lpi) if self.settings.stop_on_aggregated_error: break if cur_state.is_concrete and self.settings.stop_on_concrete_error: break self.aggdag.add_transition_successor(t, t_lpi) self.print_verbose(f"Took transition {t} at steps {cur_state.cur_steps_since_start}") # if it's a time-triggered transition, we may remove cur_state immediately if self.settings.optimize_tt_transitions and t.time_triggered: if was_tt_taken(cur_state.lpi, t, self.settings.step_size, self.settings.num_steps): self.print_verbose("Transition was time-triggered, finished with current state analysis") self.took_tt_transition = True else: self.print_verbose("Transition was NOT taken as time-triggered, due to runtime checks") Timers.toc("check_guards")
def presimulate(self, desired_step): ''' as an optimization, run simulations up to some bound in preperation for many consecutive calls to get_vecs_origin_at_step(). This may get truncated due to memory limits. ''' Timers.tic("sim + overhead") # if there are currently no simulations, or if the offset != 0 if self.settings.sim_mode == SimulationSettings.SIMULATION and self.step_offset != 0: self.step_offset = 0 # try to ensure step [0, desired_step] is in memory if desired_step >= self.max_steps_in_mem: desired_step = self.max_steps_in_mem - 1 # presimulate origin start = np.zeros((self.num_dims)) self.origin_sim = self.simulate_origin(start, desired_step, include_step_zero=True) assert len(self.origin_sim) == 1 + desired_step # presimulate vec_values start_list = np.identity(self.num_dims) self.vec_values = self.simulate_vecs(start_list, desired_step, include_step_zero=True) assert len(self.vec_values) == 1 + desired_step assert len(self.vec_values) == len(self.origin_sim) Timers.toc("sim + overhead")
def do_step_pop(self): 'do a step where we pop from the waiting list' Timers.tic('do_step_pop') self.plotman.state_popped() # reset certain per-mode plot variables self.aggdag.print_waiting_list() self.result.last_cur_state = cur_state = self.aggdag.pop_waiting_list() self.print_normal("Removed state in mode '{}' at step {} ({} in mode) (Waiting list has {} left)".format( \ cur_state.mode.name, cur_state.cur_steps_since_start, cur_state.cur_step_in_mode, \ len(self.aggdag.waiting_list))) # if a_matrix is None, it's an error mode if cur_state.mode.a_csr is None: self.print_normal("Mode '{}' was an error mode; skipping.".format(cur_state.mode.name)) self.aggdag.cur_state_left_invariant() else: self.max_steps_remaining = self.settings.num_steps - cur_state.cur_steps_since_start[0] still_feasible = self.intersect_invariant(cur_state) if not still_feasible: self.print_normal("Continuous state was outside of the mode's invariant; skipping.") self.aggdag.cur_state_left_invariant() else: cur_state.apply_approx_model(self.settings.approx_model) # pause plot self.print_verbose("Pausing due to step_pop()") self.plotman.pause() Timers.toc('do_step_pop')
def init_matrices(self): 'initialize the one-step basis and input effects matrices' dims = self.dims Timers.tic('expm') self.one_step_matrix_exp = expm(self.a_csc * self.time_elapser.step_size) Timers.toc('expm') Timers.tic('toarray') self.one_step_matrix_exp = self.one_step_matrix_exp.toarray() Timers.toc('toarray') if self.b_csc is not None: self.one_step_input_effects_matrix = np.zeros(self.b_csc.shape, dtype=float) for c in range(self.time_elapser.inputs): # create the a_matrix augmented with a column of the b_matrix as an affine term indptr = self.b_csc.indptr data = np.concatenate((self.a_csc.data, self. b_csc.data[indptr[c]:indptr[c+1]])) indices = np.concatenate((self.a_csc.indices, self.b_csc.indices[indptr[c]:indptr[c+1]])) indptr = np.concatenate((self.a_csc.indptr, [len(data)])) aug_a_csc = csc_matrix((data, indices, indptr), shape=(dims + 1, dims + 1)) mat = aug_a_csc * self.time_elapser.step_size # the last column of matrix_exp is the same as multiplying it by the initial state [0, 0, ..., 1] init_state = np.zeros(dims + 1, dtype=float) init_state[dims] = 1.0 col = expm_multiply(mat, init_state) self.one_step_input_effects_matrix[:, c] = col[:dims]
def simulate_vecs_disc(self, start_list, steps, cur_step): Timers.tic("simulation") sim_start_time = time.time() result = [] prev_val = start_list for idx in range(cur_step, cur_step + steps, 1): new_val = np.matmul(self.dy_data.dense_a_matrix.transpose(), prev_val) # print(new_val.shape) single_step_result = np.empty((self.num_dims, self.num_dims)) for dim in range(self.num_dims): single_step_result[dim] = np.array(new_val.tolist()[dim]) result.append(single_step_result) prev_val = new_val if self.settings.stdout: SHARED_NEXT_PRINT.value = sim_start_time + self.settings.print_interval_secs SHARED_COMPLETED_SIMS.value = 0 mb_per_step = np.dtype( float ).itemsize * self.num_dims * self.num_dims / 1024.0 / 1024.0 print("Simulating {} steps (~{:.2f} GB in memory)...".format( steps, steps * mb_per_step / 1024.0)) if self.settings.stdout: print("Total Simulation Time: {:.2f} secs".format(time.time() - sim_start_time)) Timers.toc("simulation") return result
def minimize(self, direction, result, error_if_infeasible=False): ''' minimize a constraint in the standard basis. this returns True of False, depending on whether the LP was feasible. If it was feasible, the passed-in 'result' vector is assigned ''' assert len(direction) == self.num_standard_vars, \ "minimize objective length({}) should match number of standard variables({})".format( len(direction), self.num_standard_vars) dir_len, = direction.shape res_len, = result.shape Timers.tic("lp minimize") res = LpInstance._minimize(self.lp_data, direction, dir_len, result, res_len) Timers.toc("lp minimize") is_feasible = (res == 0) if not is_feasible and error_if_infeasible: raise RuntimeError( 'minimize LP was infeasible when error_if_infeasible=True') return is_feasible
def compute_counterexample(self, benchmark, regex=None): start_node = self.pv_object.reach_tree.nodes[0] current_path = [] paths = [] Timers.tic("Time taken by MILP") self.pv_object.explore_tree_for_error_stars(start_node, current_path, paths) for path in paths: prev_node_state = start_node.state print("No of nodes in the path is: '{}'".format(len(path))) milp_instance = ReachabilityInstance(benchmark, self.num_dims, len(path)) if regex is not None: milp_instance = RegexInstance(benchmark, self.num_dims, len(path)) basis_centers = [] for node in path: if prev_node_state.mode.name != node.state.mode.name: if isinstance(node.state.parent.star.parent, DiscretePostParent): basis_centers.append( node.state.parent.star.parent.prestar_basis_center) prev_node_state = node.state usafe_basis_preds = self.pv_object.compute_usafe_set_pred_in_star_basis( node.state) for index in range(len(usafe_basis_preds)): pred = usafe_basis_preds[index] for basis_center in basis_centers[::-1]: pred = self.pv_object.convert_usafe_basis_pred_in_basis_center( pred, basis_center) usafe_basis_preds[index] = pred no_of_constraints = len(usafe_basis_preds) con_matrix = np.zeros((no_of_constraints, self.num_dims), dtype=float) rhs = np.zeros(no_of_constraints, dtype=float) for idx in range(len(usafe_basis_preds)): pred = usafe_basis_preds[idx] pred_list = pred.vector.tolist() for idy in range(len(pred_list)): if pred_list[idy] != 0: con_matrix[idx][idy] = pred_list[idy] rhs[idx] = pred.value # print(con_matrix) polytope = Polytope(con_matrix, rhs) milp_instance.addPolytope(polytope) if regex is None: milp_instance.solve() else: milp_instance.solve(regex) Timers.toc("Time taken by MILP")
def generate_expressions(self): Timers.tic('BDD Traversal Time') current_node = self.root current_regex = '' valid_exps = [] invalid_exps = [] valid_exps, invalid_exps = self.traverse_subtree(current_node, current_regex, valid_exps, invalid_exps) Timers.toc('BDD Traversal Time') return valid_exps, invalid_exps
def set_last_input_statuses(self, row_statuses, col_statuses): 'set the statuses for the last-added input star' row_size = row_statuses.shape[0] col_size = col_statuses.shape[0] Timers.tic("lp set_statuses") LpInstance._set_last_input_statuses(self.lp_data, row_statuses, row_size, col_statuses, col_size) Timers.toc("lp set_statuses")
def simulate_vecs(self, start_list, steps, include_step_zero=False): '''simulate from each of the vector points, from the last state in self.vec_values''' Timers.tic("simulation") # create the linear (nonaffine) dynamics linear_dy = DyData(self.dy_data.sparse_a_matrix, None, self.settings.sparse) sim_start_time = time.time() args = [] for dim in range(self.num_dims): args.append([ sim_start_time, start_list[dim], steps, include_step_zero, linear_dy, self.settings ]) if self.settings.stdout: SHARED_NEXT_PRINT.value = sim_start_time + self.settings.print_interval_secs SHARED_COMPLETED_SIMS.value = 0 mb_per_step = np.dtype( float ).itemsize * self.num_dims * self.num_dims / 1024.0 / 1024.0 print("Simulating {} steps (~{:.2f} GB in memory)...".format( steps, steps * mb_per_step / 1024.0)) result = self.parallel_sim(args) if self.settings.stdout: print("Total Simulation Time: {:.2f} secs".format(time.time() - sim_start_time)) Timers.toc("simulation") # need to convert the results to a list at each time step before returning transpose_start = time.time() rv = [] for step in range(result[0].shape[0]): single_step_result = np.empty((self.num_dims, self.num_dims)) for dim in range(self.num_dims): single_step_result[dim] = result[dim][step] rv.append(single_step_result) # was like 11.5 seconds for PDE transpose time if self.settings.stdout: print("Transpose time: {:.2f} secs".format(time.time() - transpose_start)) return rv
def get_col_statuses(self, store): 'get the col statuses of the current lp solution, and store then in the passed-in variable' size = store.shape[0] Timers.tic("lp get_statuses") rv = LpInstance._get_col_statuses(self.lp_data, store, size) Timers.toc("lp get_statuses") if rv != 0: raise RuntimeError("get_col_statuses failed")
def set_standard_basis_statuses(self, row_statuses, col_statuses): 'set the statuses for the standard variables / constraints and basis variables / constraints' row_size = row_statuses.shape[0] col_size = col_statuses.shape[0] Timers.tic("lp set_statuses") LpInstance._set_standard_basis_statuses(self.lp_data, row_statuses, row_size, col_statuses, col_size) Timers.toc("lp set_statuses")
def set_minimize_direction(self, direction_vec, is_csr=False, offset=None): '''set the direction for the optimization if offset is None, will use cur_vars_offset (direction is in terms of current-time variables) ''' Timers.tic("set_minimize_direction") if offset is None: offset = self.cur_vars_offset size = direction_vec.shape[1] if is_csr else len(direction_vec) assert size <= self.dims, "len(direction_vec) ({}) > number of cur_vars({})".format( size, self.dims) else: assert direction_vec.shape[1] + offset <= self.get_num_cols() # set the previous objective columns to zero for i in self.obj_cols: glpk.glp_set_obj_coef(self.lp, i, 0) self.obj_cols = [] if is_csr: assert isinstance(direction_vec, csr_matrix) assert direction_vec.shape[0] == 1 data, inds, indptr = direction_vec.data, direction_vec.indices, direction_vec.indptr for n in range(indptr[1]): col = int(1 + offset + inds[n]) self.obj_cols.append(col) if col > len(self.names): print(self) assert col <= len(self.names) glpk.glp_set_obj_coef(self.lp, col, data[n]) else: # non-csr if not isinstance(direction_vec, np.ndarray): direction_vec = np.array(direction_vec, dtype=float) assert len(direction_vec.shape) == 1 assert len(direction_vec) <= self.dims, "dirLen({}) > dims({})".format(len(direction_vec), self.dims) for i, direction in enumerate(direction_vec): col = int(1 + offset + i) self.obj_cols.append(col) glpk.glp_set_obj_coef(self.lp, col, float(direction)) Timers.toc("set_minimize_direction")
def begin_replay(self, node): 'begin a deaggregation replay with the passed-in node' Timers.tic('begin deagg replay') # remove all states in the waiting list that come from this node self.aggdag.remove_node_decendants_from_waiting_list(node) # start to populate waiting_nodes self.waiting_nodes.append((node, node.split())) Timers.toc('begin deagg replay')
def simulate_origin(self, start, steps, include_step_zero=False): '''simulate the origin, from the last point in self.origin_sim, for a certain number of steps''' Timers.tic("simulation") result = raw_sim_one(start, steps, self.dy_data, self.settings, include_step_zero=include_step_zero) Timers.toc("simulation") return result
def _find_init_simplex(dims, supp_point_func): ''' find an n-dimensional initial simplex ''' Timers.tic('init_simplex') # first, construct the initial simplex and determine a basis for the convex set (it may be degenerate) init_simplex = _find_two_points(dims, supp_point_func) if len(init_simplex ) == 2: # S may be a degenerate shape consisting of a single point init_vec = init_simplex[1] - init_simplex[0] spanning_dirs = [init_vec] degenerate_dirs = [] vecs = [init_vec] for _ in range(dims - 1): new_dir, rank = _get_orthonormal_rank(vecs) # min/max in direction v, checking if it increases the rank of vecs pt = supp_point_func(new_dir) vecs.append(pt - init_simplex[0]) if _get_rank(vecs) > rank: init_simplex.append(pt) spanning_dirs.append(vecs[-1]) continue # rank did not increase with maximize, try minimize vecs = vecs[0:-1] # pop vec pt = supp_point_func(-1 * new_dir) vecs.append(pt - init_simplex[0]) if _get_rank(vecs) > rank: init_simplex.append(pt) spanning_dirs.append(vecs[-1]) continue # rank still didn't increase, new_dir is orthogonal to shape S vecs = vecs[0:-1] # pop vec vecs.append( new_dir ) # forces a new orthonormal direction during the next iteration degenerate_dirs.append(new_dir) Timers.toc('init_simplex') return init_simplex
def run(self, init_state_list): ''' Run the computation (main entry point) init_star is the initial state fixed_dim_list, if used, is a list of dimensions with fixed initial values ''' Timers.reset() Timers.tic("total") self.setup(init_state_list) if self.settings.plot.plot_mode == PlotSettings.PLOT_INTERACTIVE: # make sure to store plot result for on_click listener to report on self.print_verbose( f"Setting store_plot_result to true since PLOT_INTERACTIVE has click listener" ) self.settings.plot.store_plot_result = True if self.settings.plot.store_plot_result: self.result.plot_data = PlotData(self.plotman.num_subplots) if self.settings.plot.plot_mode == PlotSettings.PLOT_NONE: self.run_to_completion() else: self.plotman.compute_and_animate() Timers.toc("total") if self.settings.stdout >= HylaaSettings.STDOUT_VERBOSE: Timers.print_stats() if self.result.has_concrete_error: self.print_normal( "Result: Error modes are reachable (found counter-example).\n") elif self.result.has_aggregated_error: self.print_normal("Result: System is safe, although error modes were reachable when aggregation " + \ "(overapproximation) was used.\n") else: self.print_normal( "Result: System is safe. Error modes are NOT reachable.\n") self.print_normal("Total Runtime: {:.2f} sec".format( Timers.top_level_timer.total_secs)) # assign results self.result.top_level_timer = Timers.top_level_timer Timers.reset() return self.result
def simulate_origin_disc(self, start, steps, cur_step): Timers.tic("simulation") result = [] prev_val = start for idx in range(cur_step, cur_step + steps, 1): a_exp = mat_pow(self.dy_data.dense_a_matrix, idx - 1) new_val = np.array( np.matmul(a_exp, self.dy_data.dense_b_vector).flatten().tolist( )[0]) + np.array(prev_val) prev_val = new_val result.append(new_val) Timers.toc("simulation") return result
def set_constraints_swigvec_rows(self, data_vec_list, indices_vec_list, count_list, row_offset): '''An optimized / lower level way to set row constraints compared with set_constraints_csr The passed in fields are a list of swig data vector and indices vectors (one for each row), as well as a row offset. ''' Timers.tic('set_constraints_swigvec_rows') for row, (data, indices, count) in enumerate(zip(data_vec_list, indices_vec_list, count_list)): glpk.glp_set_mat_row(self.lp, 1 + row_offset + row, count, indices, data) Timers.toc('set_constraints_swigvec_rows')
def add_standard_constraint(self, a_vec, b_val): '''add a constraint in the standard basis''' if len(a_vec.shape) == 1: w = a_vec.shape[0] else: h, w = a_vec.shape assert h == 1, "expected 1-d vector in add_standard_constaint()" Timers.tic("lp add_standard_constraint") LpInstance._add_standard_constraint(self.lp_data, a_vec, w, b_val) Timers.toc("lp add_standard_constraint") self.added_standard_constraint = True
def step(self, step_in_mode=None): '''update the star based on values from a new simulation time instant the default is to advance by one step, otherwise step_in_mode can force going to a specific step number ''' Timers.tic("step") # self.basis_matrix, input_effects_matrix = self.mode.time_elapse.get_basis_matrix(0) # print(self.basis_matrix, input_effects_matrix, self.lpi) if step_in_mode is None: step_in_mode = self.cur_step_in_mode + 1 num_steps = step_in_mode - self.cur_step_in_mode # we can't do negative steps because we add input effects in the lpi for each step assert num_steps >= 0, "step() called with negative num steps (mode: " + \ f"{self.mode.name}, cur_step_in_mode: {self.cur_step_in_mode}, requested_step: {step_in_mode})" if num_steps > 0: Timers.tic('get_bm') self.basis_matrix, input_effects_matrix = self.mode.time_elapse.get_basis_matrix(step_in_mode) Timers.toc('get_bm') Timers.tic('set_bm') lputil.set_basis_matrix(self.lpi, self.basis_matrix) Timers.toc('set_bm') if input_effects_matrix is not None: Timers.tic('input effects matrix') # if we're doing multiple steps here we need to get each step's input effects matrix for step in range(self.cur_step_in_mode + 1, step_in_mode): _, ie_mat = self.mode.time_elapse.get_basis_matrix(step) self.input_effects_list.append(ie_mat) lputil.add_input_effects_matrix(self.lpi, ie_mat, self.mode, self.lgg_beta) # add the input effects matrix for the final step (computed before with basis matrix) self.input_effects_list.append(input_effects_matrix) lputil.add_input_effects_matrix(self.lpi, input_effects_matrix, self.mode, self.lgg_beta) Timers.toc('input effects matrix') # print(f".ss lp columns = {self.lpi.get_num_cols()}") self.cur_step_in_mode += num_steps self.cur_steps_since_start[0] += num_steps self.cur_steps_since_start[1] += num_steps self._verts = None # cached vertices no longer valid # print(self.basis_matrix, input_effects_matrix, self.lpi) # if P1_lpi is not None: # if isinstance(P1_lpi, LpInstance): # check_poly_contain_efficient_w_proj(P1_lpi=P1_lpi, P2_lpi=self.lpi) # elif isinstance(P1_lpi, list): # P1_box = P1_lpi # check_poly_contain_brute_force(P1_box=P1_box, P2_lpi=self.lpi) # else: # print("Provide a correct type for P1") Timers.toc("step")
def run_to_completion(self): 'run the computation until it finishes (without plotting)' Timers.tic("total") while not self.is_finished(): self.do_step() Timers.toc("total") if self.settings.print_output: LpInstance.print_stats() Timers.print_stats() self.result.time = Timers.timers["total"].total_secs
def anim_iterator(): 'generator for the computation iterator' Timers.tic("total") # do the computation until its done while not is_finished_func(): yield False # redraw one more (will clear cur_state) # yield False Timers.toc("total") LpInstance.print_stats() Timers.print_stats()