def optimise_eef(cfg, full_red=False): """Optimise using the reduced extended edge formulation (Constantino et al., EJOR, 2013). Note that this implementation does not yet include chains, and throws an exception if a chain cap greater than zero is used. Args: cfg: an OptConfig object full_red: True if cycles should be generated in order to reduce number of variables further Returns: an OptSolution object """ if cfg.edge_success_prob != 1: raise ValueError( "This formulation does not support failure-aware matching.") m = create_ip_model(cfg.timelimit, cfg.verbose) m.params.method = 2 m.params.presolve = 0 # For each vertex v, a list of variables corresponding to in-edges to v vtx_to_in_edges = [[] for __ in cfg.digraph.vs] add_chain_vars_and_constraints(cfg.digraph, cfg.ndds, cfg.max_chain, m, vtx_to_in_edges) vars_and_edges = add_eef_vars_and_constraints(cfg.max_cycle, cfg.digraph, m, full_red, cfg.eef_alt_constraints, vtx_to_in_edges) obj_expr = quicksum(edge.score * var for var, edge, low_v_id in vars_and_edges) if cfg.max_chain > 0: obj_expr += quicksum(e.score * e.edge_var for ndd in cfg.ndds for e in ndd.edges) obj_expr += quicksum(e.score * var for e in cfg.digraph.es for var in e.grb_vars) m.setObjective(obj_expr, GRB.MAXIMIZE) optimise(m, cfg) cycle_start_vv = [] cycle_next_vv = {} for var, edge, low_v_id in vars_and_edges: if var.x > 0.1: cycle_next_vv[edge.src.id] = edge.tgt.id cycle_start_vv.append(edge.src.id) return OptSolution(ip_model=m, cycles=kidney_utils.selected_edges_to_cycles( cfg.digraph, cycle_start_vv, cycle_next_vv), chains=[] if cfg.max_chain == 0 else kidney_utils.get_optimal_chains(cfg.digraph, cfg.ndds), digraph=cfg.digraph)
def optimise_eef(cfg, full_red=False): """Optimise using the reduced extended edge formulation (Constantino et al., EJOR, 2013). Note that this implementation does not yet include chains, and throws an exception if a chain cap greater than zero is used. Args: cfg: an OptConfig object full_red: True if cycles should be generated in order to reduce number of variables further Returns: an OptSolution object """ if cfg.edge_success_prob != 1: raise ValueError("This formulation does not support failure-aware matching.") m = create_ip_model(cfg.timelimit, cfg.verbose) m.params.method = 2 m.params.presolve = 0 # For each vertex v, a list of variables corresponding to in-edges to v vtx_to_in_edges = [[] for __ in cfg.digraph.vs] add_chain_vars_and_constraints(cfg.digraph, cfg.ndds, cfg.max_chain, m, vtx_to_in_edges) vars_and_edges = add_eef_vars_and_constraints( cfg.max_cycle, cfg.digraph, m, full_red, cfg.eef_alt_constraints, vtx_to_in_edges ) obj_expr = quicksum(edge.score * var for var, edge, low_v_id in vars_and_edges) if cfg.max_chain > 0: obj_expr += quicksum(e.score * e.edge_var for ndd in cfg.ndds for e in ndd.edges) obj_expr += quicksum(e.score * var for e in cfg.digraph.es for var in e.grb_vars) m.setObjective(obj_expr, GRB.MAXIMIZE) optimise(m, cfg) cycle_start_vv = [] cycle_next_vv = {} for var, edge, low_v_id in vars_and_edges: if var.x > 0.1: cycle_next_vv[edge.src.id] = edge.tgt.id cycle_start_vv.append(edge.src.id) return OptSolution( ip_model=m, cycles=kidney_utils.selected_edges_to_cycles(cfg.digraph, cycle_start_vv, cycle_next_vv), chains=[] if cfg.max_chain == 0 else kidney_utils.get_optimal_chains(cfg.digraph, cfg.ndds), digraph=cfg.digraph, )
def optimise_uuef(cfg): """Optimise using the uncapped edge formulation. Args: cfg: an OptConfig object Returns: an OptSolution object """ if cfg.edge_success_prob != 1: raise ValueError( "This formulation does not support failure-aware matching.") m = create_ip_model(cfg.timelimit, cfg.verbose) add_unlimited_vars_and_constraints(cfg.digraph, cfg.ndds, m) obj_expr = (quicksum(e.score * e.edge_var for ndd in cfg.ndds for e in ndd.edges) + quicksum(e.score * var for e in cfg.digraph.es for var in e.grb_vars)) m.setObjective(obj_expr, GRB.MAXIMIZE) optimise(m, cfg) # Try all possible cycle start positions cycle_start_vv = range(cfg.digraph.n) cycle_next_vv = {} for e in cfg.digraph.es: for var in e.grb_vars: if var.x > 0.1: cycle_next_vv[e.src.id] = e.tgt.id return OptSolution( ip_model=m, cycles=kidney_utils.selected_edges_to_cycles(cfg.digraph, cycle_start_vv, cycle_next_vv), chains=kidney_utils.get_optimal_chains(cfg.digraph, cfg.ndds), digraph=cfg.digraph)
def optimise_uuef(cfg): """Optimise using the uncapped edge formulation. Args: cfg: an OptConfig object Returns: an OptSolution object """ if cfg.edge_success_prob != 1: raise ValueError("This formulation does not support failure-aware matching.") m = create_ip_model(cfg.timelimit, cfg.verbose) add_unlimited_vars_and_constraints(cfg.digraph, cfg.ndds, m) obj_expr = quicksum(e.score * e.edge_var for ndd in cfg.ndds for e in ndd.edges) + quicksum( e.score * var for e in cfg.digraph.es for var in e.grb_vars ) m.setObjective(obj_expr, GRB.MAXIMIZE) optimise(m, cfg) # Try all possible cycle start positions cycle_start_vv = range(cfg.digraph.n) cycle_next_vv = {} for e in cfg.digraph.es: for var in e.grb_vars: if var.x > 0.1: cycle_next_vv[e.src.id] = e.tgt.id return OptSolution( ip_model=m, cycles=kidney_utils.selected_edges_to_cycles(cfg.digraph, cycle_start_vv, cycle_next_vv), chains=kidney_utils.get_optimal_chains(cfg.digraph, cfg.ndds), digraph=cfg.digraph, )
def optimise_hpief_prime(cfg, full_red=False, hpief_2_prime=False): """Optimise using the HPIEF' or HPIEF'' formulation. The HPIEF' model is based on HPIEF, but does not include cycle-edge variables at position zero. HPIEF'' also removes variables corresponding to edges at the last possible position of a cycle. Args: cfg: an OptConfig object full_red: True if cycles should be generated in order to reduce number of variables further hpief_2_prime: Use HPIEF''? Default: HPIEF' Returns: an OptSolution object """ if cfg.edge_success_prob != 1: raise ValueError( "This formulation does not support failure-aware matching.") if cfg.max_cycle < 3: hpief_2_prime = False m = create_ip_model(cfg.timelimit, cfg.verbose) m.params.method = 2 m.params.presolve = 0 # For each vertex v, a list of variables corresponding to in-edges to v vtx_to_in_edges = [[] for __ in cfg.digraph.vs] add_chain_vars_and_constraints(cfg.digraph, cfg.ndds, cfg.max_chain, m, vtx_to_in_edges) vars_and_edges = add_hpief_prime_vars_and_constraints( cfg.max_cycle, cfg.digraph, vtx_to_in_edges, m, full_red, hpief_2_prime) obj_terms = [] for var, pos, edge, low_v_id in vars_and_edges: score = edge.score if pos == 1: score += cfg.digraph.adj_mat[low_v_id][edge.src.id].score if hpief_2_prime and pos == cfg.max_cycle - 2 and edge.tgt.id != low_v_id: score += cfg.digraph.adj_mat[edge.tgt.id][low_v_id].score obj_terms.append(score * var) obj_expr = quicksum(obj_terms) if cfg.max_chain > 0: obj_expr += quicksum(e.score * e.edge_var for ndd in cfg.ndds for e in ndd.edges) obj_expr += quicksum(e.score * var for e in cfg.digraph.es for var in e.grb_vars) m.setObjective(obj_expr, GRB.MAXIMIZE) optimise(m, cfg) cycle_start_vv = [] cycle_next_vv = {} for var, pos, edge, low_v_id in vars_and_edges: if var.x > 0.1: cycle_next_vv[edge.src.id] = edge.tgt.id if pos == 1: cycle_start_vv.append(low_v_id) cycle_next_vv[low_v_id] = edge.src.id if hpief_2_prime and pos == cfg.max_cycle - 2 and edge.tgt.id != low_v_id: cycle_next_vv[edge.tgt.id] = low_v_id return OptSolution(ip_model=m, cycles=kidney_utils.selected_edges_to_cycles( cfg.digraph, cycle_start_vv, cycle_next_vv), chains=[] if cfg.max_chain == 0 else kidney_utils.get_optimal_chains(cfg.digraph, cfg.ndds), digraph=cfg.digraph)
def optimise_hpief_prime(cfg, full_red=False, hpief_2_prime=False): """Optimise using the HPIEF' or HPIEF'' formulation. The HPIEF' model is based on HPIEF, but does not include cycle-edge variables at position zero. HPIEF'' also removes variables corresponding to edges at the last possible position of a cycle. Args: cfg: an OptConfig object full_red: True if cycles should be generated in order to reduce number of variables further hpief_2_prime: Use HPIEF''? Default: HPIEF' Returns: an OptSolution object """ if cfg.edge_success_prob != 1: raise ValueError("This formulation does not support failure-aware matching.") if cfg.max_cycle < 3: hpief_2_prime = False m = create_ip_model(cfg.timelimit, cfg.verbose) m.params.method = 2 m.params.presolve = 0 # For each vertex v, a list of variables corresponding to in-edges to v vtx_to_in_edges = [[] for __ in cfg.digraph.vs] add_chain_vars_and_constraints(cfg.digraph, cfg.ndds, cfg.max_chain, m, vtx_to_in_edges) vars_and_edges = add_hpief_prime_vars_and_constraints( cfg.max_cycle, cfg.digraph, vtx_to_in_edges, m, full_red, hpief_2_prime ) obj_terms = [] for var, pos, edge, low_v_id in vars_and_edges: score = edge.score if pos == 1: score += cfg.digraph.adj_mat[low_v_id][edge.src.id].score if hpief_2_prime and pos == cfg.max_cycle - 2 and edge.tgt.id != low_v_id: score += cfg.digraph.adj_mat[edge.tgt.id][low_v_id].score obj_terms.append(score * var) obj_expr = quicksum(obj_terms) if cfg.max_chain > 0: obj_expr += quicksum(e.score * e.edge_var for ndd in cfg.ndds for e in ndd.edges) obj_expr += quicksum(e.score * var for e in cfg.digraph.es for var in e.grb_vars) m.setObjective(obj_expr, GRB.MAXIMIZE) optimise(m, cfg) cycle_start_vv = [] cycle_next_vv = {} for var, pos, edge, low_v_id in vars_and_edges: if var.x > 0.1: cycle_next_vv[edge.src.id] = edge.tgt.id if pos == 1: cycle_start_vv.append(low_v_id) cycle_next_vv[low_v_id] = edge.src.id if hpief_2_prime and pos == cfg.max_cycle - 2 and edge.tgt.id != low_v_id: cycle_next_vv[edge.tgt.id] = low_v_id return OptSolution( ip_model=m, cycles=kidney_utils.selected_edges_to_cycles(cfg.digraph, cycle_start_vv, cycle_next_vv), chains=[] if cfg.max_chain == 0 else kidney_utils.get_optimal_chains(cfg.digraph, cfg.ndds), digraph=cfg.digraph, )