def _check_inputs(self, b_csr, u_constraints_csr, u_constraints_rhs, allow_constants): 'Run assersion checks on input matrices' assert u_constraints_csr.shape[0] == u_constraints_rhs.shape[ 0], "u_constraints rows shoud match rhs len" assert u_constraints_csr.shape[1] == b_csr.shape[ 1], "u_constraints cols should match b.width" assert b_csr.shape[0] == self.a_csr.shape[0], \ "B-mat shape {} incompatible with A-mat shape {}".format(b_csr.shape, self.a_csr.shape) # make sure the input constraints are feasible assert lputil.is_feasible( u_constraints_csr, u_constraints_rhs), "input constraints were infeasible" #make sure there are not inputs that are fixed to a constant. This is for efficiency reasons. It is better #to add an affine variable to the a matrix and including this as part of A. num_inputs = b_csr.shape[1] for i in range(num_inputs): # does this input only affect a single variable? --> does b_col have a single nonzero? b_col = b_csr[:, i].toarray() nonzeros = sum([1 if x != 0 else 0 for x in b_col]) if nonzeros != 1: continue # check if is there a fixed lower and upper bound for this input lb_row = np.array([0 if n != i else 1 for n in range(num_inputs)], dtype=float) ub_row = np.array([0 if n != i else -1 for n in range(num_inputs)], dtype=float) lb = ub = None for row, rhs in zip(u_constraints_csr, u_constraints_rhs): row = row.toarray() if np.array_equiv(lb_row, row): lb = rhs elif np.array_equiv(ub_row, row): ub = -rhs if ub is None or lb is None: continue if abs(ub - lb) < 1e-9: msg = ("Time-varying input #{} is fixed to {}. This is a (very) inefficient " + \ "way encode affine terms. Instead, introduce a fixed affine variable in the A matrix with a' = 0" + \ " and a(0) = 1, and refer to that variable in any differential equations that use affine " + \ "terms. This can be made a warning by using 'allow_constants=True' in set_inputs().").format(i, lb) if not allow_constants: raise RuntimeError(msg) else: print("Warning: " + msg)
def set_invariant(self, constraints_csr, constraints_rhs): 'sets the invariant' assert self.a_csr is not None, "A matrix must be set first" if not isinstance(constraints_csr, csr_matrix): constraints_csr = csr_matrix(constraints_csr, dtype=float) if not isinstance(constraints_rhs, np.ndarray): constraints_rhs = np.array(constraints_rhs, dtype=float) constraints_rhs.shape = (len(constraints_rhs), ) # flatten rhs into a 1-d array assert constraints_csr.shape[1] == self.a_csr.shape[0], \ "width of invaraiant constraints({}) must equal A matrix size({})".format( \ constraints_csr.shape[1], self.a_csr.shape[0]) assert constraints_csr.shape[0] == len(constraints_rhs) assert lputil.is_feasible( constraints_csr, constraints_rhs), "invariant constraints were infeasible" # for efficiency in checking, the invariant is split into a list of individual constraints for row, rhs in enumerate(constraints_rhs): inds = [] data = [] indptr = [0] for i in range(constraints_csr.indptr[row], constraints_csr.indptr[row + 1]): column = constraints_csr.indices[i] d = constraints_csr.data[i] inds.append(column) data.append(d) indptr.append(len(data)) constraint_vec = csr_matrix((data, inds, indptr), dtype=float, shape=(1, constraints_csr.shape[1])) self.inv_list.append(LinearConstraint(constraint_vec, rhs))
def set_guard(self, guard_csr, guard_rhs): '''set the guard''' if not isinstance(guard_csr, csr_matrix): guard_csr = csr_matrix(guard_csr, dtype=float) if not isinstance(guard_rhs, np.ndarray): guard_rhs = np.array(guard_rhs, dtype=float) assert self.from_mode.a_csr is not None, "A-matrix not assigned in predecessor mode {}".format(self.from_mode) if guard_csr.shape[0] > 0: assert guard_csr.shape[1] == self.from_mode.a_csr.shape[0], "guard matrix expected {} columns, got {}" \ .format(self.from_mode.a_csr.shape[0], guard_csr.shape[1]) assert lputil.is_feasible(guard_csr, guard_rhs), "guard constraints were infeasible" guard_rhs.shape = (len(guard_rhs), ) # flatten into a 1-d array assert guard_rhs.shape[0] == guard_csr.shape[0] self.guard_csr = guard_csr self.guard_rhs = guard_rhs
def set_reset(self, reset_csr=None, reset_minkowski_csr=None, reset_minkowski_constraints_csr=None, reset_minkowski_constraints_rhs=None): '''resets are of the form x' = Rx + My, Cy <= rhs, where y are fresh variables the reset_minowski variables can be None if no new variables are needed. If unassigned, the identity reset is assumed x' are the new variables x are the old variables reset_csr is R reset_minkowski_csr is M reset_minkowski_constraints_csr is C reset_minkowski_constraints_rhs is rhs ''' assert self.from_mode.a_csr is not None, "A matrix not assigned in predecessor mode {}".format( self.from_mode) to_mode_csr = self.to_mode.a_csr # reset to an error mode if to_mode_csr is None: to_mode_csr = self.from_mode.a_csr if reset_csr is None: assert self.from_mode.a_csr.shape[0] == to_mode_csr.shape[ 0], "identity reset but num dims changes" reset_csr = sp.sparse.identity(self.from_mode.a_csr.shape[0], dtype=float, format='csr') if not isinstance(reset_csr, csr_matrix): reset_csr = csr_matrix(reset_csr, dtype=float) if reset_minkowski_csr is not None and not isinstance( reset_minkowski_csr, csr_matrix): reset_minkowski_csr = csr_matrix(reset_minkowski_csr, dtype=float) if reset_minkowski_constraints_csr is not None and not isinstance( reset_minkowski_constraints_csr, csr_matrix): reset_minkowski_constraints_csr = csr_matrix( reset_minkowski_constraints_csr, dtype=float) if reset_minkowski_constraints_rhs is not None and not isinstance( reset_minkowski_constraints_rhs, np.ndarray): reset_minkowski_constraints_rhs = np.array( reset_minkowski_constraints_rhs, dtype=float) assert reset_csr.shape[1] == self.from_mode.a_csr.shape[ 0], "reset matrix expected {} columns, got {}".format( self.from_mode.a_csr.shape[0], reset_csr.shape[1]) assert reset_csr.shape[0] == to_mode_csr.shape[ 0], "reset matrix expected {} rows, got {}".format( to_mode_csr.shape[0], reset_csr.shape[0]) if reset_minkowski_constraints_rhs is not None: assert len(reset_minkowski_constraints_rhs.shape) == 1 assert reset_minkowski_constraints_csr is not None assert reset_minkowski_constraints_csr.shape[0] == len( reset_minkowski_constraints_rhs) new_vars = reset_minkowski_constraints_csr.shape[1] if reset_minkowski_csr is None: reset_minkowski_csr = sp.sparse.identity(new_vars, dtype=float, format='csr') assert isinstance(reset_minkowski_csr, csr_matrix) assert reset_minkowski_csr.shape[0] == to_mode_csr.shape[0] assert reset_minkowski_csr.shape[1] == new_vars, \ "expected num reset_minkowski columns({}) to match reset_minkowski_constraints columns({})".format( \ reset_minkowski_csr.shape[1], new_vars) assert lputil.is_feasible(reset_minkowski_constraints_csr, reset_minkowski_constraints_rhs), \ "reset minkowski variable constraints were infeasible" self.reset_csr = reset_csr self.reset_minkowski_csr = reset_minkowski_csr self.reset_minkowski_constraints_csr = reset_minkowski_constraints_csr self.reset_minkowski_constraints_rhs = reset_minkowski_constraints_rhs