def create_lpi(self, ce_object): longest_ce_lpi = LpInstance(self.num_dims, self.num_dims) longest_ce_lpi.update_basis_matrix(self.init_star.basis_matrix) prev_node_state = ce_object.patch[ce_object.start_index].state basis_centers = [] while True: if isinstance(prev_node_state.parent, InitParent) or isinstance( prev_node_state.parent.star.parent, InitParent): break elif isinstance(prev_node_state.parent.star.parent, DiscretePostParent): basis_centers.append( prev_node_state.parent.star.parent.prestar_basis_center) prev_node_state = prev_node_state.parent.star.parent.prestar for idx in range(ce_object.start_index, ce_object.end_index + 1, 1): node = ce_object.patch[idx] if node.state.mode.name != prev_node_state.mode.name: basis_centers.append( node.state.parent.star.parent.prestar_basis_center) prev_node_state = node.state usafe_basis_preds = self.compute_usafe_set_pred_in_star_basis( node.state) for pred in usafe_basis_preds: for basis_center in basis_centers[::-1]: pred = self.convert_usafe_basis_pred_in_basis_center( pred, basis_center) longest_ce_lpi.add_basis_constraint(pred.vector, pred.value) for pred in self.init_star.constraint_list: longest_ce_lpi.add_basis_constraint(pred.vector, pred.value) return longest_ce_lpi
def test_underconstrained(self): 'test an underconstrained case (fails for cvxopt)' a_ub = [[1.0, 0.0], [-1.0, 0.0]] b_ub = [1.0, 1.0] c = [1.0, 0.0] num_vars = 2 lp = LpInstance(num_vars, num_vars) orthonormal_basis = [[ 1.0 if d == index else 0.0 for d in xrange(num_vars) ] for index in xrange(num_vars)] lp.update_basis_matrix(np.array(orthonormal_basis, dtype=float)) # add each constraint for row in xrange(len(b_ub)): vec = np.matrix(a_ub[row], dtype=float) val = b_ub[row] lp.add_basis_constraint(vec, val) res_glpk = np.zeros(num_vars) lp.minimize(np.array(c, dtype=float), res_glpk) self.assertAlmostEqual(res_glpk[0], -1)
def compute_ce_vector(self, simulation, usafe_set_constraint_list, direction=None, sim_start_time=0, current_mode_idx=0): usafe_points = [] ce_vector = [] for time in self.error_time_steps[current_mode_idx]: point = simulation[int(time) - sim_start_time] usafe_lpi = LpInstance(self.num_dims, self.num_dims) identity_matrix = np.identity(self.num_dims) usafe_lpi.update_basis_matrix(np.identity(self.num_dims)) for dim in range(identity_matrix.ndim): lc = LinearConstraint(identity_matrix[dim], point[dim]) usafe_lpi.add_basis_constraint(lc.vector, lc.value) lc = LinearConstraint(-1 * identity_matrix[dim], -point[dim]) usafe_lpi.add_basis_constraint(lc.vector, lc.value) for constraints in usafe_set_constraint_list: usafe_lpi.add_basis_constraint(constraints.vector, constraints.value) direction = np.zeros(self.num_dims) usafe_point = np.zeros(self.num_dims) is_feasible = usafe_lpi.minimize(direction, usafe_point, error_if_infeasible=False) usafe_points.append(usafe_point) if is_feasible: ce_vector.append(1) else: ce_vector.append(0) return ce_vector
def test_ha(self): 'test based on harmonic oscillator dynamics' lp = LpInstance(2, 2) basis = np.array([[0, -1], [1, 0]], dtype=float) lp.update_basis_matrix(basis) # x == 1 lp.add_basis_constraint(np.array([1, 0], dtype=float), 1.0) lp.add_basis_constraint(np.array([-1, 0], dtype=float), -1.0) # y == 0 lp.add_basis_constraint(np.array([0, 1], dtype=float), 0) lp.add_basis_constraint(np.array([0, -1], dtype=float), -0) res = -np.ones(4) lp.minimize(np.array([0, 0], dtype=float), res) # result should be [0, -1] (standard basis) and [1, 0] (star basis) self.assertAlmostEqual(res[0], 0.0) self.assertAlmostEqual(res[1], -1.0) # star constraints self.assertAlmostEqual(res[2], 1.0) self.assertAlmostEqual(res[3], 0.0)
def compute_longest_sequence(self, ce_vector, init_star, direction, current_mode_idx=0): usafe_lpi = LpInstance(init_star.num_dims, init_star.num_dims) length = 0 # First value is the length of the subsequence # Second and third values are the indices of the subsequence in the ce_vector time_step_indices = [0, 0, 0] start_index = 0 end_index = 0 index = [0, 0] max_len = 0 current_index = 0 while (current_index < len(ce_vector)): if ce_vector[current_index] == 1: if length == 0: usafe_lpi = LpInstance(init_star.num_dims, init_star.num_dims) usafe_lpi.update_basis_matrix(init_star.basis_matrix) for lc in init_star.constraint_list: usafe_lpi.add_basis_constraint(lc.vector, lc.value) start_index = current_index usafe_basis_predicates = self.usafe_basis_predicates[ current_mode_idx][current_index] result = np.zeros(init_star.num_dims) for usafe_basis_predicate in usafe_basis_predicates: usafe_lpi.add_basis_constraint( usafe_basis_predicate.vector, usafe_basis_predicate.value) is_feasible = usafe_lpi.minimize(direction, result, error_if_infeasible=False) if is_feasible: length = length + 1 end_index = current_index else: current_index = start_index + 1 length = 0 if max_len < length: max_len = length index[0] = start_index index[1] = end_index else: length = 0 current_index = current_index + 1 time_step_indices[1] = self.error_time_steps[current_mode_idx][ index[0]] time_step_indices[2] = self.error_time_steps[current_mode_idx][ index[1]] time_step_indices[0] = time_step_indices[2] - time_step_indices[1] + 1 return time_step_indices
def make_no_input_lpi(self, basis_matrix=None): '''make the lpi object for the input-free star, using the current star's basis matrix''' if basis_matrix is None: basis_matrix = np.zeros((self.star.num_dims, self.star.num_dims)) rv = LpInstance(self.star.num_dims, self.star.num_dims) rv.update_basis_matrix(basis_matrix) for lc in self.star.constraint_list: rv.add_basis_constraint(lc.vector, lc.value) return rv
def compare_opt(self, a_ub, b_ub, c): 'compare cvx opt versus our glpk interface' # make sure we're using floats not ints a_ub = [[float(x) for x in row] for row in a_ub] b_ub = [float(x) for x in b_ub] c = [float(x) for x in c] num_vars = len(a_ub[0]) # solve it with cvxopt options = {'show_progress': False} sol = cvxopt.solvers.lp(cvxopt.matrix(c), cvxopt.matrix(a_ub).T, cvxopt.matrix(b_ub), options=options) #if sol['status'] == 'primal infeasible': # res_cvxopt = None if sol['status'] != 'optimal': raise RuntimeError("cvxopt LP failed: {}".format(sol['status'])) res_cvxopt = [float(n) for n in sol['x']] #print "cvxopt value = {}, result = {}".format(np.dot(res_cvxopt, c), repr(res_cvxopt)) # solve it with the glpk <-> hylaa interface lp = LpInstance(num_vars, num_vars) orthonormal_basis = [[ 1.0 if d == index else 0.0 for d in xrange(num_vars) ] for index in xrange(num_vars)] lp.update_basis_matrix(np.array(orthonormal_basis, dtype=float)) # add each constraint for row in xrange(len(b_ub)): vec = np.matrix(a_ub[row], dtype=float) val = b_ub[row] lp.add_basis_constraint(vec, val) res_glpk = np.zeros(num_vars) lp.minimize(np.array(c, dtype=float), res_glpk) #print "glpk interface value = {}, result = {}".format(np.dot(res_glpk, c), repr(res_glpk)) self.assertEqual(num_vars, len(res_cvxopt)) self.assertAlmostEqual(np.dot(res_glpk, c), np.dot(res_cvxopt, c), places=5)
def test_damping(self): 'test based on damping dynamics' lp = LpInstance(1, 1) basis = np.array([[0.5]], dtype=float) lp.update_basis_matrix(basis) lp.add_basis_constraint(np.array([1.0], dtype=float), 1.0) lp.add_basis_constraint(np.array([-1.0], dtype=float), -1.0) res = np.zeros(2) lp.minimize(np.array([0], dtype=float), res) self.assertLess(res[0], 1.0)
def make_input_lpi(self, basis_matrix=None): 'make the lpi object for the input star' rv = None if self.star.mode.num_inputs > 0: rv = LpInstance(self.star.num_dims, self.star.mode.num_inputs) if basis_matrix is None: basis_matrix = np.zeros( (self.star.mode.num_inputs, self.star.num_dims)) rv.update_basis_matrix(basis_matrix) for i in range(self.star.mode.u_constraints_b.shape[0]): rv.add_basis_constraint(self.star.mode.u_constraints_a[i, :], self.star.mode.u_constraints_b[i]) return rv
def get_lpi(self): 'get (maybe create) the LpInstance object for this star + inputs, and return it' rv = self._star_lpi if rv is None: rv = LpInstance(self.num_dims, self.num_dims) rv.update_basis_matrix(self.basis_matrix) for lc in self.constraint_list: rv.add_basis_constraint(lc.vector, lc.value) # add the influence of the inputs if self.input_stars is not None: for input_star in self.input_stars: rv.add_input_star(input_star.a_matrix_t, input_star.b_vector, input_star.input_basis_matrix) self._star_lpi = rv return rv
def compute_sequence_in_a_mode(self, error_star_list, direction, compute_intersection): usafe_basis_preds_list = self.compute_usafe_basis_pred_in_star_basis_in_star_list(error_star_list, compute_intersection) valid_ids_for_all_indices = [] feasible_points = [] for idx_i in range(len(error_star_list)): valid_ids_for_current_index = [] ## Create an LP instance usafe_lpi = LpInstance(self.num_dims, self.num_dims) usafe_lpi.update_basis_matrix(error_star_list[0].parent.star.basis_matrix) all_preds = [] for pred in usafe_basis_preds_list[idx_i]: all_preds.append(pred.clone()) for pred in error_star_list[0].parent.star.constraint_list: all_preds.append(pred.clone()) for pred in all_preds: usafe_lpi.add_basis_constraint(pred.vector, pred.value) result = np.zeros(self.num_dims) usafe_lpi.minimize(direction, result, error_if_infeasible=False) feasible_point = np.dot(error_star_list[0].parent.star.basis_matrix, result) valid_ids_for_current_index.append(idx_i) for idx_j in range(idx_i-1, -1, -1): for pred in usafe_basis_preds_list[idx_j]: usafe_lpi.add_basis_constraint(pred.vector, pred.value) result = np.zeros(self.num_dims) is_feasible = usafe_lpi.minimize(direction, result, error_if_infeasible=False) if not is_feasible: break valid_ids_for_current_index.append(idx_j) feasible_point = np.dot(self.init_star.basis_matrix, result) valid_ids_for_all_indices.append(valid_ids_for_current_index) feasible_points.append(feasible_point) return valid_ids_for_all_indices, feasible_points
def check_if_feasible(self, usafe_basis_preds, usafe_basis_preds_list_in_first_mode, start_index, end_index, direction): ## Create an LP instance usafe_lpi = LpInstance(self.num_dims, self.num_dims) usafe_lpi.update_basis_matrix(self.init_star.basis_matrix) for pred in usafe_basis_preds: usafe_lpi.add_basis_constraint(pred.vector, pred.value) for idx in range(len(usafe_basis_preds_list_in_first_mode)): if idx >= start_index and idx <= end_index: for pred in usafe_basis_preds_list_in_first_mode[idx]: usafe_lpi.add_basis_constraint(pred.vector, pred.value) for pred in self.init_star.constraint_list: usafe_lpi.add_basis_constraint(pred.vector, pred.value) result = np.zeros(self.num_dims) is_feasible = usafe_lpi.minimize(direction, result, error_if_infeasible=False) return is_feasible
def make_combined_lpi(self, automaton_transition=None, skip_inputs=False): 'create one lpi per guard, which will have both the star and input effects, as well as the guard condition' lpi = LpInstance(self.star.num_dims, self.star.num_dims) lpi.update_basis_matrix(self.star.basis_matrix) for lc in self.star.constraint_list: lpi.add_basis_constraint(lc.vector, lc.value) # add standard basis guard constraints if automaton_transition is not None: for lc in automaton_transition.condition_list: lpi.add_standard_constraint(lc.vector, lc.value) # add any input star constraints mode = self.star.mode if not skip_inputs and self.star.input_stars is not None: for input_star in self.star.input_stars: lpi.add_input_star(mode.u_constraints_a_t, mode.u_constraints_b, input_star.input_basis_matrix) return lpi
def check_path_feasibility(self, node, direction, basis_centers, constraints_list): current_constraints_list = [] current_basis_centers = [] for constraint in constraints_list: current_constraints_list.append(constraint) for basis_center in basis_centers: current_basis_centers.append(basis_center) if node.error is False: print("Non-error node at '{}' in location '{}'".format( node.state.total_steps, node.state.mode.name)) if node.cont_transition is not None: print( " -- has a continuous transition at '{}' to location '{}'". format(node.cont_transition.succ_node.state.total_steps, node.cont_transition.succ_node.state.mode.name)) self.check_path_feasibility(node.cont_transition.succ_node, direction, current_basis_centers, current_constraints_list) if len(node.disc_transitions) > 0 and node.disc_transitions[ 0].succ_node.cont_transition is not None: print(" -- has a discrete transition at '{}' to location '{}'". format( node.disc_transitions[0].succ_node.state.total_steps, node.disc_transitions[0].succ_node.state.mode.name)) basis_centers.append(node.state.center) self.check_path_feasibility(node.disc_transitions[0].succ_node, direction, current_basis_centers, current_constraints_list) if node.cont_transition is None and len( node.disc_transitions) == 0: print(" -- has no transition. Returning to previous node") else: print("Error node at '{}' in location '{}'".format( node.state.total_steps, node.state.mode.name)) # print "basis centers '{}'".format(basis_centers) usafe_lpi = LpInstance(self.num_dims, self.num_dims) usafe_lpi.update_basis_matrix(self.init_star.basis_matrix) for constraint in current_constraints_list: usafe_lpi.add_basis_constraint(constraint.vector, constraint.value) usafe_basis_preds = self.compute_usafe_set_pred_in_star_basis( node.state) for pred in usafe_basis_preds: for basis_center in current_basis_centers[::-1]: pred = self.convert_usafe_basis_pred_in_basis_center( pred, basis_center) usafe_lpi.add_basis_constraint(pred.vector, pred.value) current_constraints_list.append(pred) if isinstance(node.state.parent.star.parent, DiscretePostParent): for pred in node.state.parent.star.constraint_list: for basis_center in current_basis_centers[::-1]: pred = self.convert_usafe_basis_pred_in_basis_center( pred, basis_center) usafe_lpi.add_basis_constraint(pred.vector, pred.value) current_constraints_list.append(pred) result = np.zeros(self.num_dims) is_feasible = usafe_lpi.minimize(direction, result, error_if_infeasible=False) if is_feasible: feasible_point = np.dot(self.init_star.basis_matrix, result) print("feasible point is '{}' at the time step '{}'".format( feasible_point, node.state.total_steps)) if node.cont_transition is None and len( node.disc_transitions) is 0: print("-- has no transition. Returning to previous node") if node.cont_transition is not None: print( " -- has a continuous transition at '{}' to location '{}'". format(node.cont_transition.succ_node.state.total_steps, node.cont_transition.succ_node.state.mode.name)) self.check_path_feasibility(node.cont_transition.succ_node, direction, current_basis_centers, current_constraints_list) if len(node.disc_transitions) > 0 and node.disc_transitions[ 0].succ_node.cont_transition is not None: print( " -- '{}' in location '{}' has a discrete transition at '{}' to location '{}'" .format( node.state.total_steps, node.state.mode.name, node.disc_transitions[0].succ_node.state.total_steps, node.disc_transitions[0].succ_node.state.mode.name)) current_basis_centers.append( node.disc_transitions[0].succ_node.state.parent. prestar_basis_center) self.check_path_feasibility( node.disc_transitions[0].succ_node.cont_transition. succ_node, direction, current_basis_centers, current_constraints_list)
def compute_robust_ce_old(self): Timers.tic('Robust counter-example generation time') ce_object = self.compute_longest_ce() robust_points_in_initial_star = [] patch = ce_object.patch[1:len(ce_object.patch) - 1] for node in patch: usafe_lpi = LpInstance(self.num_dims, self.num_dims) usafe_lpi.update_basis_matrix(node.state.basis_matrix) error_std_preds = self.convert_star_pred_in_standard_pred( node.state) for pred in error_std_preds: usafe_lpi.add_standard_constraint(pred.vector, pred.value) for pred in self.usafe_set_constraint_list: usafe_lpi.add_standard_constraint(pred.vector, pred.value) directions = np.identity(self.num_dims, dtype=float) avg_points = [] for index in range(self.num_dims): direction = directions[index] result = np.ones(self.num_dims) is_feasible = usafe_lpi.minimize(direction, result, error_if_infeasible=False) if is_feasible: basis_matrix = np.identity(self.num_dims, dtype=float) point1 = np.dot(basis_matrix, result) result = np.ones(self.num_dims) is_feasible = usafe_lpi.minimize(-1 * direction, result, error_if_infeasible=False) if is_feasible: basis_matrix = np.identity(self.num_dims, dtype=float) point2 = np.dot(basis_matrix, result) avg_point = (point1 + point2) / 2 avg_points.append(avg_point) robust_point_in_star = np.zeros(self.num_dims, dtype=float) for point in avg_points: robust_point_in_star += point robust_point_in_star = robust_point_in_star / len(avg_points) # print "robust point in star {}".format(robust_point_in_star) basis_centers = [] prev_node_state = node.state while True: if isinstance( prev_node_state.parent, InitParent) or isinstance( prev_node_state.parent.star.parent, InitParent): break elif isinstance(prev_node_state.parent.star.parent, DiscretePostParent): basis_centers.append(prev_node_state.parent.star.parent. prestar_basis_center) prev_node_state = prev_node_state.parent.star.parent.prestar error_star_state = node.state.point_to_star_basis( robust_point_in_star) for basis_center in basis_centers[::-1]: error_star_state = error_star_state - basis_center robust_points_in_initial_star.append( np.dot(self.init_star.basis_matrix.T, error_star_state)) robust_point = 0.0 for point in robust_points_in_initial_star: robust_point += point robust_point = robust_point / len(robust_points_in_initial_star) print("Robust point: '{}'".format(robust_point)) Timers.toc('Robust counter-example generation time') return robust_point
def compute_deepest_ce(self, direction): start_node = self.reach_tree.nodes[0] node_queue = [start_node] depth = None deepest_node = None deepest_point = None Timers.tic("Deepest counter-example generation time") while len(node_queue) is not 0: node = node_queue[0] node_queue = node_queue[1:] if node.error is True: usafe_lpi = LpInstance(self.num_dims, self.num_dims) # usafe_lpi.update_basis_matrix(np.identity(self.num_dims)) usafe_lpi.update_basis_matrix(node.state.basis_matrix) error_std_preds = self.convert_star_pred_in_standard_pred( node.state) for pred in error_std_preds: usafe_lpi.add_standard_constraint(pred.vector, pred.value) for pred in self.usafe_set_constraint_list: usafe_lpi.add_standard_constraint(pred.vector, pred.value) # usafe_basis_preds = self.compute_usafe_set_pred_in_star_basis(node.state) # for pred in node.state.constraint_list: # usafe_lpi.add_basis_constraint(pred.vector, pred.value) # for pred in usafe_basis_preds: # usafe_lpi.add_basis_constraint(pred.vector, pred.value) result = np.ones(self.num_dims) is_feasible = usafe_lpi.minimize(-1 * direction, result, error_if_infeasible=False) if is_feasible: # basis_matrix = node.state.basis_matrix basis_matrix = np.identity(self.num_dims, dtype=float) point = np.dot(basis_matrix, result) current_depth = np.dot(direction, point) # print("Current depth {}".format(current_depth)) # print ("depth for the point {} at time {} in loc {} is : {}".format(point, node.state.total_steps, # node.state.mode.name, current_depth)) if depth is None or current_depth >= depth: depth = current_depth deepest_node = node deepest_point = point if node.cont_transition is not None: node_queue.append(node.cont_transition.succ_node) if len(node.disc_transitions) > 0 and node.disc_transitions[ 0].succ_node.cont_transition is not None: node_queue.append(node.disc_transitions[0].succ_node. cont_transition.succ_node) print("deepest point is '{}' in location '{}' with depth '{}'".format( deepest_point, deepest_node.state.mode.name, np.dot(abs(direction), deepest_point))) basis_centers = [] # basis_matrices = [] prev_node_state = deepest_node.state while True: if isinstance(prev_node_state.parent, InitParent) or isinstance( prev_node_state.parent.star.parent, InitParent): break elif isinstance(prev_node_state.parent.star.parent, DiscretePostParent): basis_centers.append( prev_node_state.parent.star.parent.prestar_basis_center) # basis_matrices.append(prev_node_state.parent.star.parent.prestar.basis_matrix) prev_node_state = prev_node_state.parent.star.parent.prestar print("Basis centers: {}".format(basis_centers)) # usafe_lpi = LpInstance(self.num_dims, self.num_dims) # usafe_lpi.update_basis_matrix(self.init_star.basis_matrix) # error_star_state = self.convert_std_state_in_star_state(deepest_point, deepest_node.state) error_star_state = deepest_node.state.point_to_star_basis( deepest_point) # for index in range(len(basis_centers)-1, -1, -1): # print "Index is {}".format(index) # basis_center = basis_centers[index] # basis_matrix = basis_matrices[index] # basis_center_coeffs = np.dot(inv(basis_matrix.T),basis_center) # error_star_state = error_star_state - basis_center_coeffs for basis_center in basis_centers[::-1]: error_star_state = error_star_state - basis_center deepest_ce = np.dot(self.init_star.basis_matrix.T, error_star_state) ce_depth = float(np.dot(abs(direction), deepest_point)) ce_object = CeObject(ce=deepest_ce, ce_depth=ce_depth) print("The deepest ce is '{}' with depth '{}'".format( deepest_ce, ce_depth)) Timers.toc("Deepest counter-example generation time") return ce_object
def compute_longest_ce_in_a_path(self, path): # longest_ce_lpi = None direction = np.ones(self.num_dims) prev_time_step = path[0].state.total_steps - 1 continuous_patches = [] current_patch = [] for node in path: if node.state.total_steps == prev_time_step + 1: current_patch.append(node) # print(node.state.mode.name, node.state.total_steps) else: continuous_patches.append(current_patch) current_patch = [node] prev_time_step = node.state.total_steps # print('Loc {} time step {}\n'.format(node.state.mode.name, node.state.total_steps)) if len(current_patch) is not 0: continuous_patches.append(current_patch) # ce_length = 0 # ce = None ce_object = None for patch in continuous_patches: # current_ce_length = 0 # ce = None for idx_i in range(len(patch)): usafe_lpi = LpInstance(self.num_dims, self.num_dims) usafe_lpi.update_basis_matrix(self.init_star.basis_matrix) prev_node_state = patch[idx_i].state basis_centers = [] current_ce_length = 0 while True: if isinstance(prev_node_state.parent, InitParent) or isinstance( prev_node_state.parent.star.parent, InitParent): break elif isinstance(prev_node_state.parent.star.parent, DiscretePostParent): basis_centers.append(prev_node_state.parent.star. parent.prestar_basis_center) prev_node_state = prev_node_state.parent.star.parent.prestar # TO CHECK Reverse the basis_centers list here? prev_node_state = patch[idx_i].state for idx_j in range(idx_i, len(patch), 1): node = patch[idx_j] if node.state.mode.name != prev_node_state.mode.name: basis_centers.append( node.state.parent.star.parent.prestar_basis_center) prev_node_state = node.state usafe_basis_preds = self.compute_usafe_set_pred_in_star_basis( node.state) for pred in usafe_basis_preds: for basis_center in basis_centers[::-1]: pred = self.convert_usafe_basis_pred_in_basis_center( pred, basis_center) usafe_lpi.add_basis_constraint(pred.vector, pred.value) for pred in self.init_star.constraint_list: usafe_lpi.add_basis_constraint(pred.vector, pred.value) # TO CHECK is this a redundant step? # if isinstance(node.state.parent.star.parent, DiscretePostParent): # for pred in node.state.parent.star.constraint_list: # for basis_center in basis_centers[::-1]: # pred = self.convert_usafe_basis_pred_in_basis_center(pred, basis_center) # usafe_lpi.add_basis_constraint(pred.vector, pred.value) result = np.zeros(self.num_dims) is_feasible = usafe_lpi.minimize(direction, result, error_if_infeasible=False) if is_feasible: feasible_point = np.dot(self.init_star.basis_matrix, result) current_ce_length = current_ce_length + 1 current_ce = feasible_point # print "Counterexample is '{}' of length '{}' for node '{}' at time '{}'".format(current_ce, # current_ce_length, node.state.mode.name, node.state.total_steps) else: # print "Node '{}' at time '{}' is not feasible with existing states".format( # node.state.mode.name, node.state.total_steps) break if ce_object is None or current_ce_length >= ce_object.ce_length: ce_object = CeObject(current_ce, current_ce_length, usafe_lpi, 0, patch, patch[idx_i].state.total_steps, patch[idx_j].state.total_steps) # longest_ce_lpi = usafe_lpi # print "This counterexample starts from index '{}' in location '{}'".format( # patch[idx_i].state.total_steps, patch[idx_i].state.mode.name) # print "This counterexample ends at index '{}' in location '{}'".format( # node.state.total_steps, node.state.mode.name) return ce_object
class GuardOptData(Freezable): 'Guard optimization data' def __init__(self, star, mode, transition_index): assert isinstance(mode, LinearAutomatonMode) self.settings = star.settings self.mode = mode self.inputs = star.inputs self.star = star self.transition = mode.transitions[transition_index] self.num_output_vars = self.transition.guard_matrix_csr.shape[1] self.key_dir_offset = 0 if self.settings.plot.plot_mode != PlotSettings.PLOT_NONE: if self.settings.plot.xdim_dir is not None: self.key_dir_offset += 1 if self.settings.plot.ydim_dir is not None: self.key_dir_offset += 1 self.lpi = LpInstance(self.num_output_vars, star.num_init_vars, self.inputs) self.lpi.set_init_constraints(star.init_mat, star.init_rhs) self.lpi.set_output_constraints(self.transition.guard_matrix_csr, self.transition.guard_rhs) if star.inputs > 0: self.lpi.set_input_constraints_csc( csc_matrix(star.mode.u_constraints_csr), star.mode.u_constraints_rhs) self.optimized_lp_solution = None self.freeze_attrs() def update_full_lp(self): '''update the LP solution and, if it's feasible, get its solution, for GUARD_FULL_LP''' cur_basis_mat = self.star.time_elapse.cur_basis_mat # start and end rows of key-dir matrices start = self.key_dir_offset end = self.key_dir_offset + self.num_output_vars self.lpi.update_basis_matrix(cur_basis_mat[start:end]) # add input effects for the current step (if it exists) if self.star.time_elapse.cur_input_effects_matrix is not None: input_effects_mat = self.star.time_elapse.cur_input_effects_matrix self.lpi.add_input_effects_matrix(input_effects_mat[start:end]) result_len = self.num_output_vars + self.star.num_init_vars result_len += self.num_output_vars # total input effect result_len += self.inputs * (self.star.time_elapse.next_step - 1 ) # inputs at each step result = np.zeros((result_len), dtype=float) direction = np.zeros((self.num_output_vars, ), dtype=float) is_feasible = self.lpi.minimize(direction, result, error_if_infeasible=False) return result if is_feasible else None def get_guard_lpi(self): '''get the current full lp instance for this guard''' return self.lpi def get_optimized_lp_solution(self): '''gets the lp solution without calling an lp solver this is only possible if the initial set has only range conditions for each initial dimension, and the output-space has only a single condition This returns either an lp solution (np.ndarray) or None if infeasible ''' Timers.tic('get_optimized_lp_solution') init_ranges = self.star.init_range_tuples basis_mat = self.star.time_elapse.cur_basis_mat input_effects_mat = self.star.time_elapse.cur_input_effects_matrix assert len(init_ranges) == basis_mat.shape[1] assert len(self.transition.guard_rhs) == 1 assert self.num_output_vars == 1 assert self.transition.guard_matrix_csr.shape == (1, 1) guard_multiplier = self.transition.guard_matrix_csr[0, 0] if self.optimized_lp_solution is None: # +1 for output +1 for total input effects self.optimized_lp_solution = [0.0] * (len(init_ranges) + 1 + 1) result = self.optimized_lp_solution total_output_index = len(init_ranges) total_input_index = len(init_ranges) + 1 guard_threshold = self.transition.guard_rhs[0] noinput_effect = 0 Timers.tic("noinput_effects") for init_index in xrange(len(init_ranges)): basis_val = basis_mat[0, init_index] min_init = init_ranges[init_index][0] max_init = init_ranges[init_index][1] mult = basis_val * guard_multiplier val1 = min_init * mult val2 = max_init * mult # take the minimum of val1 and val2, since guard is CONDITION <= RHS if val1 < val2: noinput_effect += val1 result[init_index] = min_init else: noinput_effect += val2 result[init_index] = max_init Timers.toc("noinput_effects") # add input effects if they exist if input_effects_mat is not None: Timers.tic("input_effects") input_ranges = self.star.mode.u_range_tuples for input_index in xrange(len(input_ranges)): basis_val = input_effects_mat[0][input_index] min_input = input_ranges[input_index][0] max_input = input_ranges[input_index][1] val1 = min_input * basis_val * guard_multiplier val2 = max_input * basis_val * guard_multiplier # take the minimum of val1 and val2, since guard is CONDITION <= RHS if val1 < val2: result[total_input_index] += val1 result.append(min_input) else: result[total_input_index] += val2 result.append(max_input) Timers.toc("input_effects") result[total_output_index] = noinput_effect + result[total_input_index] rv = np.array( result, dtype=float ) if result[total_output_index] <= guard_threshold else None Timers.toc('get_optimized_lp_solution') return rv def get_updated_lp_solution(self): '''update the LP solution and, if it's feasible, get its solution''' if self.star.settings.interval_guard_optimization and self.star.init_range_tuples is not None and \ (self.star.inputs == 0 or self.star.mode.u_range_tuples is not None) and self.num_output_vars == 1: # LP can be decomposed column-by-column (optimization) rv = self.get_optimized_lp_solution() else: rv = self.update_full_lp() return rv
def compute_sequence_in_a_mode_wrt_init_mode(self, error_star_list, direction, compute_intersection): basis_center = error_star_list[0].parent.star.parent.prestar_basis_center usafe_basis_preds_list = self.compute_usafe_basis_pred_in_star_basis_in_star_list(error_star_list, compute_intersection) valid_ids_for_all_indices = [] feasible_points = [] basis_matrix = error_star_list[0].parent.star.parent.prestar.parent.star.basis_matrix for idx_i in range(len(error_star_list)): valid_ids_for_current_index = [] ## Create an LP instance usafe_lpi = LpInstance(self.num_dims, self.num_dims) usafe_lpi.update_basis_matrix(basis_matrix) #if idx_i == 0: # with open("constraints_before", 'w+') as f: # f.write('uasfe_basis_preds\n') # for pred in usafe_basis_preds_list[idx_i]: # f.write('{},{};\n'.format(pred.vector, pred.value)) # f.write('parent.star.constraint_list\n') # for pred in error_star_list[0].parent.star.constraint_list: # f.write('{},{};\n'.format(pred.vector, pred.value)) # f.write('Initial mode predicates\n') # for pred in error_star_list[0].parent.star.parent.prestar.parent.star.constraint_list: # f.write('{},{};\n'.format(pred.vector, pred.value)) all_preds = [] for pred in usafe_basis_preds_list[idx_i]: all_preds.append(self.convert_usafe_basis_pred_in_basis_center(pred, basis_center)) for pred in error_star_list[0].parent.star.constraint_list: all_preds.append(self.convert_usafe_basis_pred_in_basis_center(pred, basis_center)) ## adding constraints from the previous mode initial star (P) for pred in error_star_list[0].parent.star.parent.prestar.parent.star.constraint_list: all_preds.append(pred.clone()) for pred in all_preds: usafe_lpi.add_basis_constraint(pred.vector, pred.value) #if idx_i == 0: # with open("constraints_after", 'w+') as f: # for pred in all_preds: # f.write('{},{};\n'.format(pred.vector, pred.value)) result = np.zeros(self.num_dims) usafe_lpi.minimize(direction, result, error_if_infeasible=False) feasible_point = np.dot(basis_matrix, result) valid_ids_for_current_index.append(idx_i) for idx_j in range(idx_i - 1, -1, -1): for pred in usafe_basis_preds_list[idx_j]: new_pred = self.convert_usafe_basis_pred_in_basis_center(pred, basis_center) usafe_lpi.add_basis_constraint(new_pred.vector, new_pred.value) result = np.zeros(self.num_dims) is_feasible = usafe_lpi.minimize(direction, result, error_if_infeasible=False) if not is_feasible: break valid_ids_for_current_index.append(idx_j) feasible_point = np.dot(basis_matrix, result) valid_ids_for_all_indices.append(valid_ids_for_current_index) feasible_points.append(feasible_point) #print "valid ids for current mode: '{}'".format(valid_ids_for_all_indices) #print "feasible points: '{}'".format(feasible_points) return valid_ids_for_all_indices, feasible_points
def compute_sequences_in_two_modes(self, error_star_list_per_mode, direction, compute_intersection=False): error_star_list_second_mode = error_star_list_per_mode[1] error_star_list_first_mode = [] for index in range(len(error_star_list_per_mode[0])): if (error_star_list_per_mode[0][index].total_steps < error_star_list_second_mode[0].total_steps): error_star_list_first_mode.append(error_star_list_per_mode[0][index].clone()) else: break usafe_basis_preds_list_first_mode = self.compute_usafe_basis_pred_in_star_basis_in_star_list(error_star_list_first_mode, compute_intersection) usafe_basis_preds_list_second_mode = self.compute_usafe_basis_pred_in_star_basis_in_star_list(error_star_list_second_mode, compute_intersection) ## compute_sequence_in_a_mode() returns the indices of the feasible stars for each star scanning from left to right sequences_in_second_mode, feasible_pts_in_second_mode = self.compute_sequence_in_a_mode_wrt_init_mode(error_star_list_second_mode, direction, compute_intersection) sequences_in_first_mode, feasible_pts_in_first_mode = self.compute_sequence_in_a_mode(error_star_list_first_mode, direction, compute_intersection) len_of_longest_seq_in_first_mode = 0 longest_ce_in_first_mode = None longest_seq_in_first_mode = [0, 0] ce_length_in_first_mode = 0 for index in range(len(sequences_in_first_mode)): valid_ids = sequences_in_first_mode[index] cur_seq_len = (valid_ids[0]-valid_ids[len(valid_ids)-1]) if len_of_longest_seq_in_first_mode < cur_seq_len: len_of_longest_seq_in_first_mode = cur_seq_len longest_seq_in_first_mode[1] = valid_ids[0] longest_seq_in_first_mode[0] = valid_ids[len(valid_ids)-1] ce_length_in_first_mode = longest_seq_in_first_mode[1] - longest_seq_in_first_mode[0] + 1 longest_ce_in_first_mode = feasible_pts_in_first_mode[index] len_of_longest_seq_in_second_mode = 0 longest_seq_in_second_mode = [0, 0] longest_ce_in_second_mode = None ce_length_in_second_mode = 0 for index in range(len(sequences_in_second_mode)): valid_ids = sequences_in_second_mode[index] cur_seq_len = (valid_ids[0] - valid_ids[len(valid_ids)-1]) if len_of_longest_seq_in_second_mode < cur_seq_len: len_of_longest_seq_in_second_mode = cur_seq_len longest_seq_in_second_mode[1] = valid_ids[0] longest_seq_in_second_mode[0] = valid_ids[len(valid_ids) - 1] ce_length_in_second_mode = longest_seq_in_second_mode[1] - longest_seq_in_second_mode[0] + 1 longest_ce_in_second_mode = feasible_pts_in_second_mode[index] ## Compute indices - Compute longest sequence in first mode for each star in the next mode ## The sequence is represented as start and end index. If there is none, both start and end indices are -1 first_mode_seq_for_each_second_mode_stars = [] #usafe_basis_preds_list_in_first_mode = self.compute_usafe_basis_pred_in_star_basis_in_star_list( # error_star_list_per_mode[0], compute_intersection) for index in range(len(error_star_list_second_mode)): usafe_basis_preds_for_current_star_in_current_mode = self.compute_usafe_basis_pred_in_star_basis( error_star_list_second_mode[index], compute_intersection) basis_center = error_star_list_second_mode[0].parent.star.parent.prestar_basis_center new_usafe_basis_preds = [] for pred in usafe_basis_preds_for_current_star_in_current_mode: new_usafe_basis_preds.append(self.convert_usafe_basis_pred_in_basis_center(pred, basis_center)) indices = self.compute_indices(new_usafe_basis_preds, usafe_basis_preds_list_first_mode, 0, len(usafe_basis_preds_list_first_mode) - 1, direction) first_mode_seq_for_each_second_mode_stars.append(self.perform_pruning(indices)) final_seqs_for_first_mode = [] final_seqs_for_second_mode = [] feasible_ces = [] basis_center = error_star_list_second_mode[0].parent.star.parent.prestar_basis_center for valid_ids_for_current_index in sequences_in_second_mode: start = 0 end = len(valid_ids_for_current_index) - 1 feasible_point = None while True: ## Create an LP instance usafe_lpi = LpInstance(self.num_dims, self.num_dims) usafe_lpi.update_basis_matrix(self.init_star.basis_matrix) for pred in self.init_star.constraint_list: usafe_lpi.add_basis_constraint(pred.vector, pred.value) sequence_1 = first_mode_seq_for_each_second_mode_stars[valid_ids_for_current_index[start]] ## Merging it with same sequence gives the same seq for idx in range(start, end, 1 ): sequence_1 = self.compute_sequences_intersection(sequence_1, first_mode_seq_for_each_second_mode_stars[valid_ids_for_current_index[idx]]) if sequence_1[1] != -1: for pred in usafe_basis_preds_list_second_mode[valid_ids_for_current_index[idx]]: lc = self.convert_usafe_basis_pred_in_basis_center(pred, basis_center) usafe_lpi.add_basis_constraint(lc.vector, lc.value) #sequence_1 = self.compute_sequences_intersection(sequence_1, first_mode_seq_for_each_second_mode_stars[valid_ids_for_current_index[idx]]) if sequence_1[1] == -1: break for idx in range(len(sequence_1)): for pred in usafe_basis_preds_list_first_mode[idx]: usafe_lpi.add_basis_constraint(pred.vector, pred.value) result = np.zeros(self.num_dims) is_feasible = usafe_lpi.minimize(direction, result, error_if_infeasible=False) feasible_point = np.dot(self.init_star.basis_matrix, result) if is_feasible: break else: end = end - 1 valid_ids = valid_ids_for_current_index[start:end+1] #end+1 for including the last value sequence_2 = [-1,-1] sequence_2[1] = valid_ids[0] sequence_2[0] = valid_ids[len(valid_ids) - 1] if sequence_1[1] != -1: final_seqs_for_second_mode.append(sequence_2) final_seqs_for_first_mode.append(sequence_1) feasible_ces.append(feasible_point) combined_max_ce_length = 0 start_idx_first_mode = -1 start_idx_sec_mode = -1 end_idx_first_mode = -1 end_idx_sec_mode = -1 longest_ce = None for index in range(len(final_seqs_for_second_mode)): current_ce_length = final_seqs_for_first_mode[index][1] - final_seqs_for_first_mode[index][0] + 1 current_ce_length = current_ce_length + (final_seqs_for_second_mode[index][1] - final_seqs_for_second_mode[index][0] + 1) if current_ce_length > combined_max_ce_length: start_idx_first_mode = final_seqs_for_first_mode[index][0] end_idx_first_mode = final_seqs_for_first_mode[index][1] start_idx_sec_mode = final_seqs_for_second_mode[index][0] end_idx_sec_mode = final_seqs_for_second_mode[index][1] combined_max_ce_length = current_ce_length longest_ce = feasible_ces[index] if combined_max_ce_length < ce_length_in_first_mode: combined_max_ce_length = ce_length_in_first_mode longest_ce = longest_ce_in_first_mode start_idx_first_mode = longest_ce_in_first_mode[0] end_idx_first_mode = longest_ce_in_first_mode[1] start_idx_sec_mode = end_idx_sec_mode = -1 if combined_max_ce_length < ce_length_in_second_mode: combined_max_ce_length = ce_length_in_second_mode longest_ce = longest_ce_in_second_mode start_idx_sec_mode = longest_seq_in_second_mode[0] end_idx_sec_mode = longest_seq_in_second_mode[1] start_idx_first_mode = end_idx_first_mode = -1 final_indices = [] final_indices.append(combined_max_ce_length) final_indices.append(start_idx_first_mode) final_indices.append(end_idx_first_mode) final_indices.append(start_idx_sec_mode) final_indices.append(end_idx_sec_mode) return final_indices, longest_ce
def compute_deepest_ce(self, depth_direction): compute_intersection = True Timers.tic('Deepest counter-example') points = [] for error_star in self.error_stars: usafe_lpi = LpInstance(self.num_dims, self.num_dims) usafe_lpi.update_basis_matrix(error_star.basis_matrix) for pred in self.usafe_set_constraint_list: usafe_lpi.add_standard_constraint(pred.vector, pred.value) for pred in error_star.constraint_list: usafe_lpi.add_basis_constraint(pred.vector, pred.value) result = np.zeros(self.num_dims) is_feasible = usafe_lpi.minimize(-1 * depth_direction, result, error_if_infeasible=False) if is_feasible: usafe_set_basis_matrix = np.identity(self.num_dims, dtype=float) points.append(np.dot(usafe_set_basis_matrix, result)) if len(points) is 0: print("Result (Deepest counter-example): No solution exists in this direction.") Timers.toc('Deepest counter-example') return # Find the index of the error_star corresponding to the max_depth max_depth = np.dot(depth_direction, points[0]) max_depth_error_star = self.error_stars[0].clone() max_point = points[0] for index in range(len(points)): point = points[index] depth = np.dot(depth_direction, point) if depth > max_depth: max_depth = depth max_depth_error_star = self.error_stars[index].clone() max_point = point print("The deepest point is: '{}' with max_depth '{}'".format(max_point, max_depth)) #print "Max error star: '{}'".format(max_depth_error_star) #max_depth_error_star = self.error_stars[max_depth_index].clone() feasible_point = None if max_depth_error_star.mode.name == self.init_star.mode.name: basis_matrix = max_depth_error_star.parent.star.basis_matrix usafe_lpi = LpInstance(self.num_dims, self.num_dims) usafe_lpi.update_basis_matrix(basis_matrix) usafe_basis_preds = self.compute_point_as_star_basis(max_point, max_depth_error_star) #usafe_basis_preds = self.compute_usafe_basis_pred_in_star_basis(max_depth_error_star, False) for pred in usafe_basis_preds: usafe_lpi.add_basis_constraint(pred.vector, pred.value) for pred in max_depth_error_star.parent.star.constraint_list: usafe_lpi.add_basis_constraint(pred.vector, pred.value) result = np.zeros(self.num_dims) is_feasible = usafe_lpi.minimize(-1 * depth_direction, result, error_if_infeasible=False) if is_feasible: feasible_point = np.dot(basis_matrix, result) print("CounterExample: '{}' with depth '{}' in the given direction".format(feasible_point, max_depth)) Timers.toc('Deepest counter-example') else: basis_center = max_depth_error_star.parent.star.parent.prestar_basis_center usafe_basis_preds = self.compute_usafe_basis_pred_in_star_basis(max_depth_error_star, compute_intersection) #print "Usafe Basis predicates: {}".format(usafe_basis_preds) #usafe_basis_preds = self.compute_point_as_star_basis(max_point, max_depth_error_star) basis_matrix = max_depth_error_star.parent.star.parent.prestar.parent.star.basis_matrix usafe_lpi = LpInstance(self.num_dims, self.num_dims) usafe_lpi.update_basis_matrix(basis_matrix) all_preds = [] for pred in usafe_basis_preds: all_preds.append(self.convert_usafe_basis_pred_in_basis_center(pred, basis_center)) #for pred in max_depth_error_star.parent.star.constraint_list: # all_preds.append(self.convert_usafe_basis_pred_in_basis_center(pred, basis_center)) ## adding constraints from the previous mode initial star (P) for pred in max_depth_error_star.parent.star.parent.prestar.parent.star.constraint_list: all_preds.append(pred.clone()) for pred in all_preds: usafe_lpi.add_basis_constraint(pred.vector, pred.value) result = np.zeros(self.num_dims) is_feasible = usafe_lpi.minimize(-1 * depth_direction, result, error_if_infeasible=False) if is_feasible: feasible_point = np.dot(basis_matrix, result) print("CounterExample: '{}' with depth '{}' in the given direction".format(feasible_point, max_depth)) Timers.toc('Deepest counter-example') return feasible_point
def compute_counter_examples(self, direction): ## Populate error stars info error_star_steps = [] error_star_modes = [] for error_star in self.error_stars: error_star_steps.append(error_star.total_steps) error_star_modes.append(error_star.mode) # List of feasible solutions/initial points initial_points = [] usafe_basis_predicates_list = [] ## Iterate over the stars which intersect with the unsafe set ## Eventually there is going to be just one star at a particular ## time step that user is interested in. for index in range(len(self.error_stars)): #basis_matrix = error_star_basis_matrices[index] #basis_center = error_star_centers[index] error_star = self.error_stars[index] usafe_basis_predicates = self.compute_usafe_basis_pred_in_star_basis(error_star) ## List of predicates for each time step where our standard star intersects with the unsafe set ## To be used while computing the longest subsequence. usafe_basis_predicates_list.append(usafe_basis_predicates) ## Create an LP instance usafe_lpi = LpInstance(self.num_dims, self.num_dims) ## Update the basis matrix usafe_lpi.update_basis_matrix(self.init_star.basis_matrix) for predicate in usafe_basis_predicates: usafe_lpi.add_basis_constraint(predicate.vector, predicate.value) ## Add init star basis constraints to the usafe linear constraints list for lc in self.init_star.constraint_list: usafe_lpi.add_basis_constraint(lc.vector, lc.value) result = np.zeros(self.num_dims) is_feasible = usafe_lpi.minimize(direction, result, error_if_infeasible=False) ## This gives us a point, if any, in the initial set which leads to an unsafe point at a given time step. if is_feasible: initial_points.append(np.dot(self.init_star.basis_matrix, result)) counterExamples = [] unique_initial_points = [] for index_i in range(len(initial_points)): not_unique = False for index_u in range(len(unique_initial_points)): out = np.zeros(self.num_dims) if (np.subtract(unique_initial_points[index_u], initial_points[index_i]) == out).all(): not_unique = True break if not not_unique: counterExample = CounterExample(initial_points[index_i], usafe_basis_predicates_list, error_star_steps, error_star_modes, self.num_dims) counterExamples.append(counterExample) unique_initial_points.append(initial_points[index_i]) return counterExamples