def buildSolverModel(self, lp): """ Takes the pulp lp model and translates it into a glpk model """ log.debug("create the glpk model") prob = glpk.glp_create_prob() glpk.glp_set_prob_name(prob, lp.name) log.debug("set the sense of the problem") if lp.sense == constants.LpMaximize: glpk.glp_set_obj_dir(prob, glpk.GLP_MAX) log.debug("add the constraints to the problem") glpk.glp_add_rows(prob, len(list(lp.constraints.keys()))) for i, v in enumerate(lp.constraints.items(), start=1): name, constraint = v glpk.glp_set_row_name(prob, i, name) if constraint.sense == constants.LpConstraintLE: glpk.glp_set_row_bnds(prob, i, glpk.GLP_UP, 0.0, -constraint.constant) elif constraint.sense == constants.LpConstraintGE: glpk.glp_set_row_bnds(prob, i, glpk.GLP_LO, -constraint.constant, 0.0) elif constraint.sense == constants.LpConstraintEQ: glpk.glp_set_row_bnds(prob, i, glpk.GLP_FX, -constraint.constant, -constraint.constant) else: raise PulpSolverError( 'Detected an invalid constraint type') constraint.glpk_index = i log.debug("add the variables to the problem") glpk.glp_add_cols(prob, len(lp.variables())) for j, var in enumerate(lp.variables(), start=1): glpk.glp_set_col_name(prob, j, var.name) lb = 0.0 ub = 0.0 t = glpk.GLP_FR if not var.lowBound is None: lb = var.lowBound t = glpk.GLP_LO if not var.upBound is None: ub = var.upBound t = glpk.GLP_UP if not var.upBound is None and not var.lowBound is None: if ub == lb: t = glpk.GLP_FX else: t = glpk.GLP_DB glpk.glp_set_col_bnds(prob, j, t, lb, ub) if var.cat == constants.LpInteger: glpk.glp_set_col_kind(prob, j, glpk.GLP_IV) assert glpk.glp_get_col_kind(prob, j) == glpk.GLP_IV var.glpk_index = j log.debug("set the objective function") for var in lp.variables(): value = lp.objective.get(var) if value: glpk.glp_set_obj_coef(prob, var.glpk_index, value) log.debug("set the problem matrix") for constraint in lp.constraints.values(): l = len(list(constraint.items())) ind = glpk.intArray(l + 1) val = glpk.doubleArray(l + 1) for j, v in enumerate(constraint.items(), start=1): var, value = v ind[j] = var.glpk_index val[j] = value glpk.glp_set_mat_row(prob, constraint.glpk_index, l, ind, val) lp.solverModel = prob
def create_problem(self, data): hosts_attacked = data["attacked"] hosts_executing = data["executing"] metrics = data["metric"] damage = data["damage"] responses = data["response"] logging.info("CSR Optimizer creating problem...") glpki.glp_init_env() problem = glpki.glp_create_prob() glpki.glp_set_prob_name(problem, "CSR") # Set optimization direction to minimize glpki.glp_set_obj_dir(problem, glpki.GLP_MIN) # Column C_m_i :Create a column for every property logging.debug("Adding %s columns for metrics", len(metrics)) first = glpki.glp_add_cols(problem, len(metrics)) for m in metrics: logging.debug("Adding column [%s] for metric '%s'", first, m.name) m.column = first glpki.glp_set_col_name(problem, m.column, "C_m_" + str(m.name)) glpki.glp_set_col_bnds(problem, m.column, glpki.GLP_LO, 0, 0) glpki.glp_set_col_kind(problem, m.column, glpki.GLP_CV) glpki.glp_set_obj_coef(problem, m.column, 1.0) first += 1 # Column C_m_i : Create a column for every response first = glpki.glp_add_cols(problem, len(responses)) for r in responses: logging.debug("Adding column [%s] for response '%s'", first, r.name) r.column = first glpki.glp_set_col_name(problem, r.column, "C_n_" + str(r.name)) glpki.glp_set_col_bnds(problem, r.column, glpki.GLP_DB, 0, 1) glpki.glp_set_col_kind(problem, r.column, glpki.GLP_IV) glpki.glp_set_obj_coef(problem, r.column, 0) first += 1 # Row: C1) Every victim is freed: Create a constrain row for every attacked host logging.debug("Adding %s row for attacked hosts", len(hosts_attacked)) first = glpki.glp_add_rows(problem, len(hosts_attacked)) for a in hosts_attacked: logging.debug("Adding constraint [%s] for attacked host '%s'", first, a.name) a.row_freed = first # set row name glpki.glp_set_row_name(problem, a.row_freed, a.name + "_freed") # set row bounds: glpki.glp_set_row_bnds(problem, a.row_freed, glpki.GLP_LO, 1, 0) first += 1 # Row: C2) Sum of costs is lower than damage: Create a constrain row for every property if (None != damage): logging.debug("Adding damage row %s row for metrics", len(metrics)) first = glpki.glp_add_rows(problem, len(metrics)) for m in metrics: logging.debug("Adding damage constraint [%s] for metric '%s'", first, m.name) m.row_damage = first # set row name glpki.glp_set_row_name(problem, m.row_damage, m.name + "_damage") # set row bounds: cur_damage = -1 for d in damage: if (d.name == m.name): cur_damage = d.value assert (-1 != cur_damage) glpki.glp_set_row_bnds(problem, m.row_damage, glpki.GLP_UP, 0, cur_damage) first += 1 # Row C3) Cost of each metric: Create a row for every property logging.debug("Adding %s row for metrics", len(metrics)) first = glpki.glp_add_rows(problem, len(metrics)) for m in metrics: logging.debug("Adding constraint [%s] for metric '%s'", first, m.name) m.row_cost = first # set row name glpki.glp_set_row_name(problem, m.row_cost, m.name + "_cost") # set row bounds: glpki.glp_set_row_bnds(problem, m.row_cost, glpki.GLP_FX, 0, 0) first += 1 # Set problem matrix content c_conflicts = 0 for r in responses: for c in r.conflicting_responses: if (c == ""): continue c_conflicts += 1 c_freed = 0 for a in hosts_attacked: for r in responses: if (a.name == r.dest or r.dest.count(a.name) != 0): c_freed += 1 array_size = 1 + c_freed + 2 * len(metrics) * len(responses) + len( metrics) + 2 * c_conflicts ia = glpki.intArray(array_size) ja = glpki.intArray(array_size) ar = glpki.doubleArray(array_size) index = 1 count = 0 # Conflicting responses ConflictingContraints = 0 for r in responses: for c in r.conflicting_responses: if (c == ""): continue r2 = None for r_tmp in responses: if (c == r_tmp.name): r2 = r_tmp if (None == r2) or (r.name == r2.name): continue # Add a constraint for every conflict ConflictingContraints = ConflictingContraints + 1 logging.debug( "Adding constraint [%s] for conflict '%s' <-> '%s'", first, r.name, c) first = glpki.glp_add_rows(problem, 1) glpki.glp_set_row_name(problem, first, "conflict_" + r.name + "-" + r2.name) glpki.glp_set_row_bnds(problem, first, glpki.GLP_DB, 0, 1) ia[index] = first ja[index] = r.column ar[index] = 1 logging.debug("%s: [%s][%s] = %s", count, ia[index], ja[index], ar[index]) index += 1 count += 1 ia[index] = first ja[index] = r2.column ar[index] = 1 logging.debug("%s: [%s][%s] = %s", count, ia[index], ja[index], ar[index]) index += 1 count += 1 # Constraint 1) Every attacked not has to be freed for a in hosts_attacked: logging.debug("1) Free %s", a.name) for r in responses: if (a.name == r.dest or r.dest.count(a.name) != 0): ia[index] = a.row_freed ja[index] = r.column ar[index] = 1.0 logging.debug("%s: [%s][%s] = %s", count, ia[index], ja[index], ar[index]) index += 1 count += 1 # Constraint 2) damage if (None != damage): for m in metrics: logging.debug("2) Damage for metric %s", m.name) for r in responses: ia[index] = m.row_damage ja[index] = r.column ar[index] = r.get_cost(m.name) logging.debug("%s: [%s][%s] = %s", count, ia[index], ja[index], ar[index]) index += 1 count += 1 # Constraint 3) cost for m in metrics: logging.debug("3) Cost for metric %s", m.name) ia[index] = m.row_cost ja[index] = m.column ar[index] = 1 logging.debug("H: %s [%s][%s] = %s", count, ia[index], ja[index], ar[index]) index += 1 count += 1 for r in responses: ia[index] = m.row_cost ja[index] = r.column ar[index] = -r.get_cost(m.name) logging.debug("%s: [%s][%s] = %s", count, ia[index], ja[index], ar[index]) index += 1 count += 1 glpki.glp_load_matrix(problem, count, ia, ja, ar) return problem