def solve_problem(self, target_variable, maximize=False): """ Solve the linear programming problem """ target_column = self.var_corr[target_variable] c = [0.0] * self.variable_count if maximize: c[target_column] = -1.0 else: c[target_column] = 1.0 sol = lp_solver.apply(c, self.Aub, self.bub, self.Aeq, self.beq, variant=DEFAULT_LP_SOLVER_VARIANT) parameters_points = { "maximize": maximize, "return_when_none": True, "var_corr": self.var_corr } return lp_solver.get_points_from_sol(sol, parameters=parameters_points, variant=DEFAULT_LP_SOLVER_VARIANT)
def __compute_exact_heuristic_new_version(sync_net, a_matrix, h_cvx, g_matrix, cost_vec, incidence_matrix, marking, fin_vec, variant, use_cvxopt=False, strict=True): m_vec = incidence_matrix.encode_marking(marking) b_term = [i - j for i, j in zip(fin_vec, m_vec)] b_term = np.matrix([x * 1.0 for x in b_term]).transpose() if not strict: g_matrix = np.vstack([g_matrix, a_matrix]) h_cvx = np.vstack([h_cvx, b_term]) a_matrix = np.zeros((0, a_matrix.shape[1])) b_term = np.zeros((0, b_term.shape[1])) if use_cvxopt: # not available in the latest version of PM4Py from cvxopt import matrix b_term = matrix(b_term) parameters_solving = {"solver": "glpk"} sol = lp_solver.apply(cost_vec, g_matrix, h_cvx, a_matrix, b_term, parameters=parameters_solving, variant=variant) prim_obj = lp_solver.get_prim_obj_from_sol(sol, variant=variant) points = lp_solver.get_points_from_sol(sol, variant=variant) prim_obj = prim_obj if prim_obj is not None else sys.maxsize points = points if points is not None else [0.0] * len(sync_net.transitions) return prim_obj, points
def solve(self, variant=None) -> Tuple[int, List[int]]: """ Solves the extended marking equation, returning the heuristics and the x vector Parameters ------------- variant Variant of the ILP solver to use Returns ------------- h Heuristics value x X vector """ if variant is None: variant = solver.DEFAULT_LP_SOLVER_VARIANT # use ILP solver if variant is solver.CVXOPT_SOLVER_CUSTOM_ALIGN: variant = solver.CVXOPT_SOLVER_CUSTOM_ALIGN_ILP c, Aub, bub, Aeq, beq = self.get_components() parameters_solver = {} parameters_solver["use_ilp"] = True sol = solver.apply(c, Aub, bub, Aeq, beq, variant=variant, parameters=parameters_solver) sol_points = solver.get_points_from_sol(sol, variant=variant) if sol_points is not None: x = self.get_x_vector(sol_points) x = [int(y) for y in x] h = self.get_h(sol_points) return h, x return None, None
def __ilp_solve(c, Aub, bub, Aeq, beq): Aeq = np.asmatrix(Aeq).astype(np.float64) beq = np.asmatrix(beq).transpose().astype(np.float64) Aub = np.asmatrix(Aub).astype(np.float64) bub = np.asmatrix(bub).transpose().astype(np.float64) if "cvxopt" in solver.DEFAULT_LP_SOLVER_VARIANT: # does this part only if cvxopt is imported from cvxopt import matrix c = matrix([x * 1.0 for x in c]) Aeq = matrix(Aeq) beq = matrix(beq) Aub = matrix(Aub) bub = matrix(bub) # tries to solve the problem with LP solving # (faster) # if it produces a vector which elements are different from 0 or 1 # then use the ILP solver sol = solver.apply(c, Aub, bub, Aeq, beq, variant="cvxopt_solver_custom_align") points = solver.get_points_from_sol(sol, variant="cvxopt_solver_custom_align") condition_points = True for x in points: if x > TOL or x < 1 - TOL: continue condition_points = False break # there is at least one point in the solution that is not integer. # in that case, it is better to apply the ILP solver instead of just rounding the points if condition_points is False: sol = solver.apply(c, Aub, bub, Aeq, beq, variant="cvxopt_solver_custom_align_ilp") points = solver.get_points_from_sol(sol, variant="cvxopt_solver_custom_align_ilp") # round the points to the nearest integer (0 or 1). # if the ILP solver is called, these are already integer points = [round(x) for x in points] else: # calls other linear solvers (pulp, ortools) with REQUIRE_ILP set to True sol = solver.apply(c, Aub, bub, Aeq, beq, variant=solver.DEFAULT_LP_SOLVER_VARIANT, parameters={solver.Parameters.REQUIRE_ILP: True}) points = solver.get_points_from_sol(sol, variant=solver.DEFAULT_LP_SOLVER_VARIANT) return points
def solve_given_components(self, c, Aub, bub, Aeq, beq): """ Solves the linear problem given the components Parameters -------------- c Objective vector Aub Inequalities matrix bub Inequalities vector Aeq Equalities matrix beq Equalities vector Returns ------------- h Heuristics value x X vector """ if solver.DEFAULT_LP_SOLVER_VARIANT == solver.CVXOPT_SOLVER_CUSTOM_ALIGN and type( c) is list: from cvxopt import matrix Aub = matrix(Aub.astype(np.float64)) bub = matrix(bub.astype(np.float64)) Aeq = matrix(Aeq.astype(np.float64)) beq = matrix(beq.astype(np.float64)) c = matrix([1.0 * x for x in c]) sol = solver.apply(c, Aub, bub, Aeq, beq, variant=solver.DEFAULT_LP_SOLVER_VARIANT) sol_points = solver.get_points_from_sol( sol, variant=solver.DEFAULT_LP_SOLVER_VARIANT) if sol_points is not None: x = self.get_x_vector(sol_points) x = [int(y) for y in x] h = self.get_h(sol_points) return h, x return None, None
def resolve_LP(C_matrix, duration_matrix, activities, activities_counter): """ Formulates and solve the LP problem Parameters -------------- C_matrix C_matrix duration_matrix Duration matrix activities Ordered list of activities of the log activities_counter Counter of activities Returns ------------- dfg Directly-Follows Graph performance_dfg Performance DFG (containing the estimated performance for the arcs) """ edges = [(i, j) for i in range(len(activities)) for j in range(len(activities))] c = [ C_matrix[i, j] for i in range(len(activities)) for j in range(len(activities)) ] edges_sources = { i: [z for z in range(len(edges)) if edges[z][0] == i] for i in range(len(activities)) } edges_targets = { j: [z for z in range(len(edges)) if edges[z][1] == j] for j in range(len(activities)) } activities_occurrences = { i: activities_counter[activities[i]] for i in range(len(activities)) } Aeq = [] beq = [] for i in range(len(activities)): rec = [0] * len(edges) for e in edges_sources[i]: rec[e] = 1 Aeq.append(rec) beq.append(activities_occurrences[i]) for j in range(len(activities)): rec = [0] * len(edges) for e in edges_targets[j]: rec[e] = 1 Aeq.append(rec) beq.append(activities_occurrences[j]) Aeq = np.asmatrix(Aeq).astype(np.float64) beq = np.asmatrix(beq).transpose().astype(np.float64) Aub = [] bub = [] for i in range(len(activities)): for e in edges_sources[i]: rec = [0] * len(edges) rec[e] = 1 Aub.append(rec) bub.append(activities_occurrences[i]) rec = [-x for x in rec] Aub.append(rec) bub.append(0) for j in range(len(activities)): for e in edges_targets[j]: rec = [0] * len(edges) rec[e] = 1 Aub.append(rec) bub.append(activities_occurrences[j]) rec = [-x for x in rec] Aub.append(rec) bub.append(0) Aub = np.asmatrix(Aub).astype(np.float64) bub = np.asmatrix(bub).transpose().astype(np.float64) use_cvxopt = False if solver.DEFAULT_LP_SOLVER_VARIANT == solver.CVXOPT_SOLVER_CUSTOM_ALIGN or solver.DEFAULT_LP_SOLVER_VARIANT == solver.CVXOPT_SOLVER_CUSTOM_ALIGN_ILP: use_cvxopt = True if use_cvxopt: from cvxopt import matrix c = matrix(c) Aub = matrix(Aub) bub = matrix(bub) Aeq = matrix(Aeq) beq = matrix(beq) res = solver.apply(c, Aub, bub, Aeq, beq, variant=solver.DEFAULT_LP_SOLVER_VARIANT) points = solver.get_points_from_sol( res, variant=solver.DEFAULT_LP_SOLVER_VARIANT) points = [round(p) for p in points] dfg = {} performance_dfg = {} for idx, p in enumerate(points): if p > 0: dfg[(activities[edges[idx][0]], activities[edges[idx][1]])] = p performance_dfg[( activities[edges[idx][0]], activities[edges[idx][1]])] = duration_matrix[edges[idx][0], edges[idx][1]] return dfg, performance_dfg
def transform_basis(basis, style=None): """ We construct a (I)LP to transform our basis into a set of vectors by using linear combination to fit certain styles/ properties :param basis: list of p-invariants. Commonly computed by the method 'compute_place_invariants' in place_invariants.py :param style: String that is used to construct certain constraints At the moment, 'uniform' (all weights have value 0 or 1), and 'weighted' (all weights are >=0) are supported :return: List of p-invariants that fits the style """ if style == None: style = 'weighted' # First, we want to check if a vector of a basis only contains non-positve entries. If so, then we multiply the # vector -1. modified_base = [] for vector in basis: all_non_positiv = True for entry in vector: if entry > 0: all_non_positiv = False if all_non_positiv: modified_base.append(-1 * vector) else: modified_base.append(vector) #For uniform variants, it is necessary that the weight for a place is either 0 or 1. We collect the variants for #which this condition does not hold. We also collect the variants for the weighted invariants the entry is <0. to_modify = [] for vector in modified_base: for entry in vector: if ((entry < 0 or entry > 1) and style == 'uniform') or (entry < 0 and style == 'weighted'): to_modify.append(vector) break # if we have nothing to modify, we are done if len(to_modify) > 0: for vector in to_modify: removearray(modified_base, vector) set_B = range(0, len(modified_base)) # start of the problem """prob = pulp.LpProblem("linear_combination", pulp.LpMinimize) X = pulp.LpVariable.dicts("x", set_B, cat='Integer') y = pulp.LpVariable("y", cat='Integer', lowBound=1) # add objective prob += pulp.lpSum(X[i] for i in set_B) if style=='uniform': # variables for uniform. Therefore, the resulting weight can either be 0 or 1 z = pulp.LpVariable.dicts("z", range(0, len(vector)), lowBound=0, upBound=1, cat='Integer') # add constraints for i in range(len(vector)): prob += pulp.lpSum(X[j]*modified_base[j][i] for j in range(len(modified_base)))+y*vector[i]== z[i] elif style=='weighted': for i in range(len(vector)): prob += pulp.lpSum(X[j]*modified_base[j][i] for j in range(len(modified_base)))+y*vector[i] >= 0 prob.solve()""" # problem is solved c = [1] * len(set_B) + [0] * (len(vector) + 1) zeros = [0] * (len(set_B) + len(vector) + 1) Aub = [] bub = [] Aeq = [] beq = [] first_constraint = copy(zeros) first_constraint[len(set_B)] = -1 Aub.append(first_constraint) bub.append(-1) for i in range(len(vector)): this_row = copy(zeros) this_row[len(set_B)] = list(vector[i])[0] for j in range(len(modified_base)): if type(modified_base[j][i]) is np.float64: this_row[j] = float(modified_base[j][i]) else: this_row[j] = list(modified_base[j][i])[0] if style == "uniform": this_row[len(set_B) + 1 + i] = -1 Aeq.append(this_row) beq.append(0) elif style == "weighted": Aub.append([-x for x in this_row]) bub.append(0) for i in range(len(vector)): last_constraint_1 = copy(zeros) last_constraint_1[len(set_B) + 1 + i] = 1 Aub.append(last_constraint_1) bub.append(1) last_constraint_2 = copy(zeros) last_constraint_2[len(set_B) + 1 + i] = -1 Aub.append(last_constraint_2) bub.append(0) Aeq = np.asmatrix(Aeq).astype(np.float64) beq = np.asmatrix(beq).transpose().astype(np.float64) Aub = np.asmatrix(Aub).astype(np.float64) bub = np.asmatrix(bub).transpose().astype(np.float64) if Aeq.shape[1] == 0: Aeq = np.zeros((1, len(c))).astype(np.float64) beq = np.zeros(1).transpose().astype(np.float64) if Aub.shape[1] == 0: Aub = np.zeros((1, len(c))).astype(np.float64) bub = np.zeros(1).transpose().astype(np.float64) if "cvxopt" in solver.DEFAULT_LP_SOLVER_VARIANT: from cvxopt import matrix c = matrix([x * 1.0 for x in c]) Aeq = matrix(Aeq) beq = matrix(beq) Aub = matrix(Aub) bub = matrix(bub) sol = solver.apply(c, Aub, bub, Aeq, beq, variant=solver.DEFAULT_LP_SOLVER_VARIANT) points = solver.get_points_from_sol( sol, variant=solver.DEFAULT_LP_SOLVER_VARIANT) new_vector = np.zeros(len(vector)) if style == "weighted": for i in range(len(new_vector)): new_vector[i] = points[len(set_B)] * vector[i] for j in range(len(modified_base)): new_vector[i] = new_vector[ i] + modified_base[j][i] * points[j] elif style == "uniform": for i in range(len(new_vector)): new_vector[i] = points[len(set_B) + 1 + i] modified_base.append(new_vector) return modified_base