def get_problem_matrix(constrs, id_to_col=None, constr_offsets=None): """ Builds a sparse representation of the problem data by calling CVXCanon's C++ build_matrix function. Parameters ---------- constrs: A list of python linOp trees id_to_col: A map from variable id to offset withoun our matrix Returns ---------- V, I, J: numpy arrays encoding a sparse representation of our problem const_vec: a numpy column vector representing the constant_data in our problem """ linOps = [constr.expr for constr in constrs] lin_vec = cvxcore.LinOpVector() id_to_col_C = cvxcore.IntIntMap() if id_to_col is None: id_to_col = {} # Loading the variable offsets from our # Python map into a C++ map for id, col in list(id_to_col.items()): id_to_col_C[int(id)] = int(col) # This array keeps variables data in scope # after build_lin_op_tree returns tmp = [] for lin in linOps: tree = build_lin_op_tree(lin, tmp) tmp.append(tree) lin_vec.push_back(tree) if constr_offsets is None: problemData = cvxcore.build_matrix(lin_vec, id_to_col_C) else: # Load constraint offsets into a C++ vector constr_offsets_C = cvxcore.IntVector() for offset in constr_offsets: constr_offsets_C.push_back(int(offset)) problemData = cvxcore.build_matrix(lin_vec, id_to_col_C, constr_offsets_C) # Unpacking V = problemData.getV(len(problemData.V)) I = problemData.getI(len(problemData.I)) J = problemData.getJ(len(problemData.J)) const_vec = problemData.getConstVec(len(problemData.const_vec)) return V, I, J, const_vec.reshape(-1, 1)
def get_problem_matrix(linOps, var_length, id_to_col, param_to_size, param_to_col, constr_length): """ Builds a sparse representation of the problem data. Parameters ---------- linOps: A list of python linOp trees representing an affine expression var_length: The total length of the variables. id_to_col: A map from variable id to column offset. param_to_size: A map from parameter id to parameter size. param_to_col: A map from parameter id to column in tensor. constr_length: Summed sizes of constraints input. Returns ------- A sparse (CSC) matrix with constr_length * (var_length + 1) rows and param_size + 1 columns (where param_size is the length of the parameter vector). """ lin_vec = cvxcore.ConstLinOpVector() id_to_col_C = cvxcore.IntIntMap() for id, col in id_to_col.items(): id_to_col_C[int(id)] = int(col) param_to_size_C = cvxcore.IntIntMap() for id, size in param_to_size.items(): param_to_size_C[int(id)] = int(size) # dict to memoize construction of C++ linOps, and to keep Python references # to them to prevent their deletion linPy_to_linC = {} for lin in linOps: build_lin_op_tree(lin, linPy_to_linC) tree = linPy_to_linC[lin] lin_vec.push_back(tree) problemData = cvxcore.build_matrix(lin_vec, int(var_length), id_to_col_C, param_to_size_C, s.get_num_threads()) # Populate tensors with info from problemData. tensor_V = {} tensor_I = {} tensor_J = {} for param_id, size in param_to_size.items(): tensor_V[param_id] = [] tensor_I[param_id] = [] tensor_J[param_id] = [] problemData.param_id = param_id for i in range(size): problemData.vec_idx = i prob_len = problemData.getLen() tensor_V[param_id].append(problemData.getV(prob_len)) tensor_I[param_id].append(problemData.getI(prob_len)) tensor_J[param_id].append(problemData.getJ(prob_len)) # Reduce tensors to a single sparse CSR matrix. V = [] I = [] J = [] # one of the 'parameters' in param_to_col is a constant scalar offset, # hence 'plus_one' param_size_plus_one = 0 for param_id, col in param_to_col.items(): size = param_to_size[param_id] param_size_plus_one += size for i in range(size): V.append(tensor_V[param_id][i]) I.append(tensor_I[param_id][i] + tensor_J[param_id][i] * constr_length) J.append(tensor_J[param_id][i] * 0 + (i + col)) V = np.concatenate(V) I = np.concatenate(I) J = np.concatenate(J) A = scipy.sparse.csc_matrix( (V, (I, J)), shape=(np.int64(constr_length) * np.int64(var_length + 1), param_size_plus_one)) return A