def __init__(self, budget_membership_mat, rhs_vec): """ BudgetSet constructor Args: budget_membership_mat: A matrix with 0-1 entries to designate which uncertain parameters participate in each budget constraint. Here, each row is associated with a separate budget constraint. rhs_vec: Vector (``list``) of right-hand side values for the budget constraints. """ # === Non-zero number of columns mat = np.asarray(budget_membership_mat) rhs = np.asarray(rhs_vec) if len(mat.shape) == 1: cols = mat.shape else: cols = mat.shape[1] if cols == 0: raise AttributeError( "Budget membership matrix must have non-zero number of columns." ) # === Assert is valid matrix (same number of columns across all rows if not all(len(row) == cols for row in budget_membership_mat): raise AttributeError( "Budget membership matrix must be a valid matrix, " "e.g. same number of column entries across rows.") # === Matrix dimension compatibility if mat.shape[0] != rhs.shape[0]: raise AttributeError( "Rows of lhs_coefficients_mat matrix must equal rows of rhs_vec lists." ) # === Ensure a 0-1 matrix if any(not np.isclose(elem, 0) and not np.isclose(elem, 1) for row in budget_membership_mat for elem in row): raise AttributeError( "Budget membership matrix must be a matrix of 0's and 1's.") # === No all zero rows if all(elem == 0 for row in budget_membership_mat for elem in row): raise AttributeError( "All zero rows are not permitted in the budget membership matrix." ) # === Ensure 0 <= rhs_i for all i if any(rhs_vec[i] < 0 for i in range(len(rhs_vec))): raise AttributeError("RHS vector entries must be >= 0.") # === Non-emptiness is implied by the set # === Add constraints such that uncertain params are >= 0 # === This adds >=0 bound on all parameters in the set cols = mat.shape[1] identity = np.identity(cols) * -1 for row in identity: budget_membership_mat.append(row.tolist()) for i in range(identity.shape[0]): rhs_vec.append(0) self.coefficients_mat = budget_membership_mat self.rhs_vec = rhs_vec self.type = "budget"
def __init__(self, lhs_coefficients_mat, rhs_vec): """ PolyhedralSet constructor Args: lhs_coefficients_mat: Matrix of left-hand side coefficients for the linear inequality constraints defining the polyhedral set. rhs_vec: Vector (``list``) of right-hand side values for the linear inequality constraints defining the polyhedral set. """ # === Real valued data mat = np.asarray(lhs_coefficients_mat) if not all( isinstance(elem, (int, float)) for row in lhs_coefficients_mat for elem in row): raise AttributeError( "Matrix lhs_coefficients_mat must be real-valued and numeric.") if not all(isinstance(elem, (int, float)) for elem in rhs_vec): raise AttributeError( "Vector rhs_vec must be real-valued and numeric.") # === Check columns of A must be same length as rhs if mat.shape[0] != len(rhs_vec): raise AttributeError( "Rows of lhs_coefficients_mat matrix must equal length of rhs_vec list." ) # === Columns are non-zero if mat.shape[1] == 0: raise AttributeError( "Columns of lhs_coefficients_mat must be non-zero.") # === Matrix is not all zeros if all( np.isclose(elem, 0) for row in lhs_coefficients_mat for elem in row): raise AttributeError( "Matrix lhs_coefficients_mat cannot be all zeroes.") # === Non-emptiness res = sp.optimize.linprog(c=np.zeros(mat.shape[1]), A_ub=mat, b_ub=rhs_vec, method="simplex") if not res.success: raise AttributeError( "User-defined PolyhedralSet was determined to be empty. " "Please check the set of constraints supplied during set construction." ) # === Boundedness if res.status == 3: # scipy linprog status == 3 indicates unboundedness raise AttributeError( "User-defined PolyhedralSet was determined to be unbounded. " "Please augment the set of constraints supplied during set construction." ) self.coefficients_mat = lhs_coefficients_mat self.rhs_vec = rhs_vec self.type = "polyhedral"
def __init__(self, origin, number_of_factors, psi_mat, beta): """ FactorModelSet constructor Args: origin: Vector (``list``) of uncertain parameter values around which deviations are restrained. number_of_factors: Natural number representing the dimensionality of the space to which the set projects. psi: Matrix with non-negative entries designating each uncertain parameter's contribution to each factor. Here, each row is associated with a separate uncertain parameter and each column with a separate factor. beta: Number in [0,1] representing the fraction of the independent factors that can simultaneously attain their extreme values. Setting 'beta = 0' will enforce that as many factors will be above 0 as there will be below 0 (i.e., "zero-net-alpha" model). Setting 'beta = 1' produces the hyper-rectangle [origin - psi e, origin + psi e], where 'e' is the vector of ones. """ mat = np.asarray(psi_mat) # === Numeric valued arrays if not all(isinstance(elem, (int, float)) for elem in origin): raise AttributeError( "All elements of origin vector must be numeric.") if not all( isinstance(elem, (int, float)) for row in psi_mat for elem in row): raise AttributeError( "All elements of psi_mat vector must be numeric.") if not isinstance(beta, (int, float)): raise AttributeError("Beta parameter must be numeric.") if not isinstance(number_of_factors, (int)): raise AttributeError("number_of_factors must be integer.") # === Ensure dimensions of psi are n x F if mat.shape != (len(origin), number_of_factors): raise AttributeError( "Psi matrix must be of dimensions n x F where n is dim(uncertain_params)" "and F is number_of_factors.") # === Ensure beta in [0,1] if beta > 1 or beta < 0: raise AttributeError("Beta parameter must be in [0,1].") # === No all zero columns of psi_mat for idx in range(mat.shape[1]): if all(np.isclose(elem, 0) for elem in mat[:, idx]): raise AttributeError( "Psi matrix cannot have all zero columns.") # === Psi must be strictly positive entries for idx in range(mat.shape[1]): if any(elem < 0 for elem in mat[:, idx]): raise AttributeError( "Psi matrix cannot have any negative entries. All factors must be non-negative." ) self.origin = origin self.number_of_factors = number_of_factors self.psi_mat = psi_mat self.beta = beta self.type = "factor_model"