def find_edge_existence_matchings(matchings_dir, d, a, name, verbose=0, cycle_cap=3, chain_cap_list=[3], edge_success_prob_list = [0.4], gamma_list=[], protection_levels=[0.01], N_trials=10, subtour_dir = None, remove_subtours=False, cycle_file=None, run_experiment=False, outfile=None): timelimit = None if len(edge_success_prob_list) > 0: prob = True use_gamma = False par_list = edge_success_prob_list elif len(gamma_list) > 0: use_gamma = True prob = False par_list = gamma_list if ( len(edge_success_prob_list) > 0 and len(gamma_list) > 0): raise Warning("cannot specify both edge success prob list and gamma list") for chain_cap in chain_cap_list: for par in par_list: if prob: edge_fail_func = lambda e: np.random.rand() > par elif use_gamma: gamma = par type = 'nr' nr_file = os.path.join(matchings_dir,build_filename(name, type, chain_cap)) cfg = kidney_ip.OptConfig(d, a, cycle_cap, chain_cap, verbose=(verbose >= 2), timelimit=timelimit, edge_success_prob=1, cycle_file=cycle_file) if os.path.exists(nr_file): if run_experiment: sol = kidney_ip.OptSolution.from_file(cfg, nr_file) nonrob_score = sum(e.score for e in sol.matching_edges) else: sol = kidney_ip.optimise_picef(cfg) sol.save_to_file(nr_file) nonrob_score = sum(e.score for e in sol.matching_edges) if verbose >= 1: print "protection level epsilon = %f" % p print "non-robust solution:" print sol.display() if prob: type = 'fa' fa_file = os.path.join(matchings_dir,build_filename(name, type, chain_cap,edge_success_prob=par)) cfg_failaware = kidney_ip.OptConfig(d, a, cycle_cap, chain_cap, verbose=(verbose>=2), timelimit=timelimit, edge_success_prob=par,cycle_file=cycle_file) if os.path.exists(fa_file): if run_experiment: sol_failaware = kidney_ip.OptSolution.from_file(cfg_failaware, fa_file) failaware_score = sum(e.score for e in sol_failaware.matching_edges) else: pass else: sol_failaware = kidney_ip.optimise_picef(cfg_failaware) sol_failaware.save_to_file(fa_file) failaware_score = sol_failaware.get_total_score() if verbose >= 1: print "failure-aware solution:" print sol_failaware.display() if run_experiment and (sol.total_score == 0): if verbose: print "optimal matching has zero weight for exchange: %s" % name with open(outfile, 'a') as csvfile: csvfile.write("{},{},{},{},{},{},{},{},{},{},{},{},{}\n".format( name, 0, # i cycle_cap, chain_cap, par, p, 0, # sol_rob.gamma, 0, # sol_rob.optimistic_score, 0, # failaware_nominal_score, 0, # sol.total_score, 0, # realized_robust_score, 0, # realized_failaware_score, 0 ))# realized_nonrob_score)) else: max_num_cycles = 0 for p in protection_levels: type = 'ex' ex_file = os.path.join(matchings_dir, build_filename(name, type, chain_cap, edge_success_prob=par, protection_level=p)) cfg_rob = kidney_ip.OptConfig(d, a, cycle_cap, chain_cap, verbose=(verbose >= 2), timelimit=timelimit, edge_success_prob=par, protection_level=p, name=name, subtour_dir=subtour_dir, cycle_file=cycle_file, remove_subtours=remove_subtours) if os.path.exists(ex_file): if run_experiment: sol_rob = kidney_ip.OptSolution.from_file(cfg_rob, ex_file) rob_optimistic_score = sum(e.score for e in sol_rob.matching_edges) gamma = sol_rob.gamma else: pass else: sol_rob = kidney_ip.solve_edge_existence_uncertainty(cfg_rob, max_num_cycles=max_num_cycles) sol_rob.save_to_file(ex_file) rob_optimistic_score = sum(e.score for e in sol_rob.matching_edges) gamma = sol_rob.gamma max_num_cycles = sol_rob.max_num_cycles # don't recalculate the maximum number of cycles... if verbose: print "robust solution:" print sol_rob.display() if run_experiment: # get the robust and non-robust scores for N_trials realizations with open(outfile, 'a') as csvfile: for i in range(N_trials): # add edge failures (these don't need to be replicated, they are Bernouli random) for e in d.es: e.fail = edge_fail_func(e) for n in a: for e in n.edges: e.fail = edge_fail_func(e) if verbose >= 2: print "MATCHINGS AFTER FAILURE" print "non-robust solution:" print sol.display() print "failure-aware solution:" print sol_failaware.display() print "robust solution:" print sol_rob.display() realized_failaware_score = sol_failaware.score_after_edge_failure(a) realized_robust_score = sol_rob.score_after_edge_failure(a) realized_nonrob_score = sol.score_after_edge_failure(a) csvfile.write("{},{},{},{},{},{},{},{},{},{},{},{},{}\n".format( name, i, cycle_cap, chain_cap, par, p, gamma, rob_optimistic_score, failaware_score, nonrob_score, realized_robust_score, realized_failaware_score, realized_nonrob_score))
def find_edge_existence_matchings_const_gamma(matchings_dir, d, a, name,verbose=0, cycle_cap=3, chain_cap_list=[3], gamma_list=[1], N_trials=10, run_experiment=False, outfile=None): timelimit = None for chain_cap in chain_cap_list: empty_matching = False for gamma in sorted(gamma_list): type = 'nr' nr_file = os.path.join(matchings_dir, build_filename(name, type, chain_cap)) cfg = kidney_ip.OptConfig(d, a, cycle_cap, chain_cap, verbose=(verbose >= 2), timelimit=timelimit, edge_success_prob=1,gamma=0) if os.path.exists(nr_file): if run_experiment: sol = kidney_ip.OptSolution.from_file(cfg, nr_file) nonrob_score = sum(e.score for e in sol.matching_edges) else: sol = kidney_ip.optimise_pctsp(cfg) # THIS USED TO USE PICEF sol.save_to_file(nr_file) nonrob_score = sum(e.score for e in sol.matching_edges) if verbose >= 1: print "non-robust solution:" print sol.display() type = 'gamma' gam_file = os.path.join(matchings_dir, build_filename(name, type, chain_cap,gamma=gamma)) cfg_rob = kidney_ip.OptConfig(d, a, cycle_cap, chain_cap, verbose=(verbose >= 2), timelimit=timelimit, name=name, gamma=gamma) if os.path.exists(gam_file): if run_experiment: sol_rob = kidney_ip.OptSolution.from_file(cfg_rob, gam_file) rob_optimistic_score = sum(e.score for e in sol_rob.matching_edges) else: pass elif empty_matching: sol_rob.gamma = gamma # use the previous matching, but change gamma... else: sol_rob = kidney_ip.optimize_robust_pctsp(cfg_rob) sol_rob.save_to_file(gam_file) rob_optimistic_score = sum(e.score for e in sol_rob.matching_edges) if rob_optimistic_score == 0: empty_matching = True if verbose: print "robust solution (gamma = %d):" % gamma print sol_rob.display() if run_experiment: # get the robust and non-robust scores for N_trials realizations with open(outfile, 'a') as csvfile: for i in range(N_trials): # scores after a set number of failures realized_robust_score = sol_rob.score_after_num_failures(a,gamma,seed=i) realized_nonrob_score = sol.score_after_num_failures(a,gamma,seed=i) csvfile.write("{},{},{},{},{},{},{},{},{}\n".format( name, i, cycle_cap, chain_cap, gamma, rob_optimistic_score, nonrob_score, realized_robust_score, realized_nonrob_score))
def find_edge_weight_matchings(matchings_dir, d, a, name, verbose=0, cycle_cap=3, chain_cap_list=[3], dist='uniform', protection_levels=[0.01], alpha_list=[0.5], cycle_file=None, run_experiment=False, N_trials=None, outfile=None): timelimit = None edge_success_prob = 1 for alpha in alpha_list: # weight distribution: wt_string = dist + re.sub('\\.', '', '{:g}'.format(alpha)) if dist == 'uniform': # edge weights are uniformly distributed on [w(1-a),w(1+a)], where a is between 0 and 1 low_frac = 1.0 - alpha high_frac = 1.0 + alpha discount_func = lambda edge: edge.score * alpha realized_weight_func = lambda edge: np.random.uniform(low=edge.score*low_frac, high=edge.score*high_frac) elif dist == 'bimodal': # edge weights are either low or high low_frac = 1.0 - alpha high_frac = 1.0 + alpha discount_func = lambda edge: edge.score * alpha realized_weight_func = lambda edge: np.random.choice([edge.score * low_frac, edge.score * high_frac]) elif dist == 'flat': # save state for re-generating edge states edge_assign_seed = random.randint(0, 2**31) # assign some edges to be constant (0.5), and others to be either 0 or 1 # sets edge discount and weight_type assign_flat_edges(edge_assign_seed,alpha,d,a) # weight_type 0 = constant # weight_type 1 = bimodal # realized edge weights will be added later realized_weight_func = lambda edge: 0.5 if edge.weight_type==0 else np.random.choice([0.0,1.0]) for chain_cap in chain_cap_list: type = 'nr' nr_file = os.path.join(matchings_dir,build_filename(name, type, chain_cap)) cfg = kidney_ip.OptConfig(d, a, cycle_cap, chain_cap, verbose=(verbose >= 2), timelimit=timelimit, edge_success_prob=edge_success_prob, cycle_file=cycle_file) # # if os.path.exists(nr_file): # # if run_experiment: # # sol = kidney_ip.OptSolution.from_file(cfg, nr_file) # # nonrob_score = sum(e.score for e in sol.matching_edges) # # else: # # pass # else: sol = kidney_ip.optimise_picef(cfg) sol.save_to_file(nr_file) nonrob_score = sum(e.score for e in sol.matching_edges) max_card = 0 for p in protection_levels: type = 'wt' wt_file = os.path.join(matchings_dir, build_filename(name, type, chain_cap, wt_string=wt_string, edge_success_prob=None, protection_level=p)) cfg_rob = kidney_ip.OptConfig(d, a, cycle_cap, chain_cap, verbose=(verbose>=2), timelimit=timelimit, edge_success_prob=edge_success_prob, protection_level=p,cycle_file=cycle_file, edge_assign_seed=edge_assign_seed) if os.path.exists(wt_file): if run_experiment: sol_rob = kidney_ip.OptSolution.from_file(cfg_rob, wt_file) rob_optimistic_score = sum(e.score for e in sol_rob.matching_edges) else: pass else: sol_rob = kidney_ip.solve_edge_weight_uncertainty(cfg_rob, max_card=max_card) sol_rob.save_to_file(wt_file) rob_optimistic_score = sum(e.score for e in sol_rob.matching_edges) max_card = sol_rob.max_card # don't recalculate the maximum cardinality... if verbose >= 1: print "protection level epsilon = %f" % p print "non-robust solution:" print sol.display() print "robust solution:" print sol_rob.display() if run_experiment: # assign edges their original weight_type using the seed assign_flat_edges(sol_rob.edge_assign_seed, alpha, d, a) with open(outfile, 'a') as csvfile: for i in range(N_trials): realized_robust_score = sol_rob.score_with_edge_weight_func(realized_weight_func) realized_nonrob_score = sol.score_with_edge_weight_func(realized_weight_func) csvfile.write("{},{},{},{},{},{},{},{},{},{},{}\n".format( name, i, cycle_cap, chain_cap, alpha, p, sol_rob.gamma, rob_optimistic_score, nonrob_score, realized_robust_score, realized_nonrob_score))
def weighted_fairness_experiment(beta_list, digraph, altruists, dirname, outfile, chain_cap_list, edge_prob_list, frac_edges): beta_list.sort() cycle_cap = 3 # chain_cap = 3 verbose = False timelimit = None #edge_success_prob = edge_prob eef_alt_constraints = None lp_file = None relax = None formulation = 'picef' use_relabelled = False multi = 1 gap = 0 alpha = 0 min_sensitized = 0 total_score = numpy.zeros(len(beta_list)) fair_score = numpy.zeros(len(beta_list)) num_matched = numpy.zeros(len(beta_list)) sens_matched = numpy.zeros(len(beta_list)) total_num_sensitized = digraph.get_num_sensitized() total_num_pairs = digraph.get_num_pairs() num_ndds = len(altruists) # find maximum number of sensitized patients possible # copy KPD graph with nonzero weights only for highly sensitized patientss d_fair = digraph.fair_copy() a_fair = [a.fair_copy() for a in altruists] # print("maximum possible fairness: {} (total matched = {})".format(max_sens, fair_sol.num_matched())) for chain_cap in chain_cap_list: for edge_success_prob in edge_prob_list: fair_cfg = kidney_ip.OptConfig(d_fair, a_fair, cycle_cap, chain_cap, verbose, timelimit, edge_success_prob, eef_alt_constraints, lp_file, relax, multi, gap, min_sensitized) fair_sol = solve_kep(fair_cfg, formulation, use_relabelled) max_fair_score = fair_sol.total_score max_sens_matched = fair_sol.num_sensitized() # these values should never be used current_total_score = -1 current_fair_score = -1 current_num_matched = -1 current_sens_matched = -1 for i, beta in enumerate(beta_list): # if we've already hit the maximum score... if current_fair_score == max_fair_score: total_score[i] = current_total_score fair_score[i] = current_fair_score num_matched[i] = current_num_matched sens_matched[i] = current_sens_matched else: digraph.augment_weights(beta) for a in altruists: a.augment_weights(beta) cfg = kidney_ip.OptConfig(digraph, altruists, cycle_cap, chain_cap, verbose, timelimit, edge_success_prob, eef_alt_constraints, lp_file, relax, multi, gap, min_sensitized) sol = solve_kep(cfg, formulation, use_relabelled) digraph.unaugment_weights(beta) for a in altruists: a.unaugment_weights(beta) # get the total scores (unaugment the weights first, and recalculate the score...) current_total_score = sol.get_score( digraph, altruists, edge_success_prob) current_fair_score = sol.get_score(d_fair, a_fair, edge_success_prob) current_num_matched = sol.num_matched() current_sens_matched = sol.num_sensitized() total_score[i] = current_total_score fair_score[i] = current_fair_score num_matched[i] = current_num_matched sens_matched[i] = current_sens_matched with open(outfile, 'a') as csvfile: for i, beta in enumerate( beta_list): # enumerate(beta_list[0:max_i+1]): csvfile.write( "{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}\n". format(dirname, cycle_cap, chain_cap, total_num_pairs, num_ndds, total_num_sensitized, max_fair_score, max_sens_matched, beta, alpha, total_score[i], fair_score[i], num_matched[i], sens_matched[i], edge_success_prob, frac_edges))
def alpha_lex_experiment(digraph, altruists, dirname, outfile, alpha_list, chain_cap_list, edge_prob_list, frac_edges): alpha_list.sort() cycle_cap = 3 # chain_cap = 4 verbose = False timelimit = None #edge_success_prob = edge_prob eef_alt_constraints = None lp_file = None relax = None formulation = 'picef' use_relabelled = False multi = 1 gap = 0 min_sensitized = 0 beta = 0 # find maximum number of sensitized patients possible # copy KPD graph with nonzero weights only for highly sensitized patientss d_fair = digraph.fair_copy() a_fair = [a.fair_copy() for a in altruists] # graph parameters total_num_sensitized = digraph.get_num_sensitized() total_num_pairs = digraph.get_num_pairs() num_ndds = len(altruists) with open(outfile, 'a') as csvfile: for chain_cap in chain_cap_list: for edge_success_prob in edge_prob_list: fair_cfg = kidney_ip.OptConfig(d_fair, a_fair, cycle_cap, chain_cap, verbose, timelimit, edge_success_prob, eef_alt_constraints, lp_file, relax, multi, gap, min_sensitized) fair_sol = solve_kep(fair_cfg, formulation, use_relabelled) max_fair_score = fair_sol.total_score max_sens_matched = fair_sol.num_sensitized() # first solve original problem (alpha = 0) min_fair_score = 0 cfg = kidney_ip.OptConfig(digraph, altruists, cycle_cap, chain_cap, verbose, timelimit, edge_success_prob, eef_alt_constraints, lp_file, relax, multi, gap, min_fair_score) sol = solve_kep(cfg, formulation, use_relabelled) fair_score = sol.get_fair_score(altruists) num_matched = sol.num_matched() num_sensitized = sol.num_sensitized() for alpha in alpha_list: min_fair_score = alpha * max_fair_score # numpy.linspace(0,1,11) * max_fair_score # if the previous solution already satisfies this minimum score, just write it again if fair_score >= min_fair_score: csvfile.write( "{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}\n" .format(dirname, cycle_cap, chain_cap, total_num_pairs, num_ndds, total_num_sensitized, max_fair_score, max_sens_matched, beta, alpha, sol.total_score, fair_score, num_matched, num_sensitized, edge_success_prob, frac_edges)) # if the previous solution doesn't meet the alpha criteria, solve again with the new min fair score else: cfg = kidney_ip.OptConfig( digraph, altruists, cycle_cap, chain_cap, verbose, timelimit, edge_success_prob, eef_alt_constraints, lp_file, relax, multi, gap, min_fair_score) sol = solve_kep(cfg, formulation, use_relabelled) fair_score = sol.get_fair_score(altruists) num_matched = sol.num_matched() num_sensitized = sol.num_sensitized() csvfile.write( "{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}\n" .format(dirname, cycle_cap, chain_cap, total_num_pairs, num_ndds, total_num_sensitized, max_fair_score, max_sens_matched, beta, alpha, sol.total_score, fair_score, num_matched, num_sensitized, edge_success_prob, frac_edges))
def start(): parser = argparse.ArgumentParser("Solve a kidney-exchange instance") parser.add_argument("cycle_cap", type=int, help="The maximum permitted cycle length") parser.add_argument("chain_cap", type=int, help="The maximum permitted number of edges in a chain") parser.add_argument("formulation", help="The IP formulation (uef, eef, eef_full_red, hpief_prime, hpief_2prime, hpief_prime_full_red, hpief_2prime_full_red, picef, cf)") parser.add_argument("--use-relabelled", "-r", required=False, action="store_true", help="Relabel vertices in descending order of in-deg + out-deg") parser.add_argument("--eef-alt-constraints", "-e", required=False, action="store_true", help="Use slightly-modified EEF constraints (ignored for other formulations)") parser.add_argument("--timelimit", "-t", required=False, default=None, type=float, help="IP solver time limit in seconds (default: no time limit)") parser.add_argument("--verbose", "-v", required=False, action="store_true", help="Log Gurobi output to screen and log file") parser.add_argument("--edge-success-prob", "-p", required=False, type=float, default=1.0, help="Edge success probability, for failure-aware matching. " + "This can only be used with PICEF and cycle formulation. (default: 1)") parser.add_argument("--lp-file", "-l", required=False, default=None, metavar='FILE', help="Write the IP model to FILE, then exit.") parser.add_argument("--relax", "-x", required=False, action='store_true', help="Solve the LP relaxation.") parser.add_argument("--multi", "-m", required=False, # added by Duncan type=int, default=1, help="Search for multiple solutions. (Specify the maximum number of solutions to search for, default = 1)") parser.add_argument("--experiment", "-z", required=False, # added by Duncan action='store_true', default=None, help="Run experiment") parser.add_argument("--highly_sensitized", "-H", type=percent, default=0, required=False, # added by Duncan help="Fraction of highly sensitized patients (on [0-1], default = 0)") parser.add_argument("--seed", "-s", type=str, default=1, required=False, # added by Duncan help="Random seed for choosing sensitized vertices") parser.add_argument("--fairness", "-f", type=str, default=1, required=False, # added by Duncan help="Output file of fairness data") parser.add_argument("--all_solutions", "-a", type=str, default=1, required=False, # added by Duncan help="Output file of all solutionss") parser.add_argument("--add_weight_type", "-w", type=int, default=0, required=False, # added by Duncan help="Add random edge weights (0 = constant, 1 = floating point, >1 = number of weight levels") parser.add_argument("--pool_gap", "-g", type=int, default=0, required=False, # added by Duncan help="Pool gap (if >0, find suboptimal solutions)") parser.add_argument("--pareto", "-P", required=False, # added by Duncan action='store_true', default=None, help="Calculate Pareto curve") args = parser.parse_args() args.formulation = args.formulation.lower() input_lines = [line for line in sys.stdin if len(line.strip()) > 0] n_digraph_edges = int(input_lines[0].split()[1]) digraph_lines = input_lines[:n_digraph_edges + 2] d = kidney_digraph.read_digraph(digraph_lines) if len(input_lines) > len(digraph_lines): ndd_lines = input_lines[n_digraph_edges + 2:] altruists = kidney_ndds.read_ndds(ndd_lines, d) else: altruists = [] # add random weights # args.add_weight_type = 0 # 0 is default, read weights from file (constant, uniform for each edge) if args.add_weight_type == 1: # random floating point weight between 1 and 2 for each edge for edge in d.es: edge.score = random.random() + 1.0 elif args.add_weight_type > 1: # random integer, either 1 or 2 for edge in d.es: edge.score = random.randint(1, args.add_weight_type) if args.highly_sensitized > 0: num_sensitized = int( round(d.n * args.highly_sensitized) ) random.seed(args.seed) sensitized_pairs = random.sample(range(d.n),num_sensitized) for i in sensitized_pairs: d.vs[i].sensitized = True else: num_sensitized = 0 sensitized_pairs = [] if args.pareto: print "formulation : {}".format(args.formulation) print "using_relabelled : {}".format(args.use_relabelled) print "cycle_cap : {}".format(args.cycle_cap) print "chain_cap : {}".format(args.chain_cap) print "num_pairs : {}".format(d.n) print "num_ndds : {}".format(len(altruists)) print "max_core_size : {}".format(args.multi) print "num_sensitized : {}".format(num_sensitized) print "sensitized_pairs : {}".format(' '.join([str(i) for i in sensitized_pairs])) # 1) calculate optimal core, and all fairness values within core min_sens = 0 gap = 0 min_sens = 0 cfg = kidney_ip.OptConfig(d, altruists, args.cycle_cap, args.chain_cap, args.verbose, args.timelimit, args.edge_success_prob, args.eef_alt_constraints, args.lp_file, args.relax, args.multi, gap, min_sens) core = solve_kep(cfg, args.formulation, args.use_relabelled) print "optimal_score : {}".format(core.total_score) core_fairness = [s.num_sensitized() for s in core.solutions] print "{:10s} {:10s} {:10s}".format('min_sens','num_sens','score') #for s in core.solutions: # print "{:10d} {:10d} {:10.3f}".format(0,s.num_sensitized(),s.total_score) # 2) start with a 0 fairness bound, and increase, solving KEP for optimal solution # ONLY SEARCH FOR ONE SOLUTION PER FAIRNESS for min_sensitized in range(num_sensitized): cfg2 = kidney_ip.OptConfig(d, altruists, args.cycle_cap, args.chain_cap, args.verbose, args.timelimit, args.edge_success_prob, args.eef_alt_constraints, args.lp_file, args.relax, 1, 0, min_sensitized) sol = solve_kep(cfg2, args.formulation, args.use_relabelled) if sol.total_score > 0: print "{:10d} {:10d} {:10.3f}".format(int(min_sensitized), sol.num_sensitized(),sol.total_score) elif args.experiment: experiment_num = 1 # run experiment: # randomly assign a percentage of pairs to be highly sensitized # use the filename as a seed for python.random if experiment_num == 1: # 1) find optimal solution min_sens=0 cfg = kidney_ip.OptConfig(d, altruists, args.cycle_cap, args.chain_cap, args.verbose, args.timelimit, args.edge_success_prob, args.eef_alt_constraints, args.lp_file, args.relax, args.multi, args.pool_gap, min_sens) opt_solution = solve_kep(cfg, args.formulation, args.use_relabelled) # 2) find all solutions within 90% of optimal solution opt_score = opt_solution.total_score print "inital opt finished. OPT score = {} (max={})".format(opt_score,args.multi) pct = 90 low_score = max( opt_score * pct / 100, 1) gap = opt_score - low_score print "Now finding all solutions within {}% of OPT. low score = {}".format(pct,low_score) cfg_2 = kidney_ip.OptConfig(d, altruists, args.cycle_cap, args.chain_cap, args.verbose, args.timelimit, args.edge_success_prob, args.eef_alt_constraints, args.lp_file, args.relax, args.multi, gap) opt_solution_2 = solve_kep(cfg_2, args.formulation, args.use_relabelled) opt_solution_2.write_fairness( args.fairness, args.cycle_cap, args.chain_cap, len(altruists) ) #opt_solution_2.write_all_scores(args.all_solutions, args.cycle_cap, args.chain_cap, len(altruists)) # print "new core size : {} (max={})".format(opt_solution.size,args.multi) # print "score counts ; min_fairness max_fairness" # fair_by_score = opt_solution.pct_sensitized_by_score() # for score, counts in opt_solution.score_counter().most_common(): # max_fair = max(fair_by_score[score]) # min_fair = min(fair_by_score[score]) # print"{:5} {:10} ; {:6.2f} {:6.2f}".format(score,counts,min_fair,max_fair) # # fairness = opt_solution.pct_sensitized_counter() # print "--- fairness ---" # print "max percent sens: {}".format(max(fairness.keys())) # print "min percent sens: {}".format(min(fairness.keys())) elif experiment_num == 2: # 1) find optimal solution without constraining fairness min_sensitized = 0 cfg = kidney_ip.OptConfig(d, altruists, args.cycle_cap, args.chain_cap, args.verbose, args.timelimit, args.edge_success_prob, args.eef_alt_constraints, args.lp_file, args.relax, args.multi, args.pool_gap, min_sensitized) opt_solution = solve_kep(cfg, args.formulation, args.use_relabelled) print "No constraint on fairness. OPT = {}".format(opt_solution.total_score) print "# sensitized pairs used (total) = {} ({})".format(opt_solution.num_sensitized(),num_sensitized) print "----------- sensitized verts -----------" print ' '.join([str(i) for i in sorted(sensitized_pairs)]) print "----------- solution -----------" print opt_solution.display() # now force 3 sensitized pairs to be used min_sensitized = 1 cfg2 = kidney_ip.OptConfig(d, altruists, args.cycle_cap, args.chain_cap, args.verbose, args.timelimit, args.edge_success_prob, args.eef_alt_constraints, args.lp_file, args.relax, args.multi, args.pool_gap, min_sensitized) opt_solution2 = solve_kep(cfg2, args.formulation, args.use_relabelled) print "Fairness constrined to {}. OPT = {}".format(min_sensitized, opt_solution2.total_score) print "# sensitized pairs used (total) = {} ({})".format(opt_solution2.num_sensitized(),num_sensitized) print "----------- sensitized verts -----------" print ' '.join([str(i) for i in sorted(sensitized_pairs)]) print "----------- solution -----------" print opt_solution2.display() # now force 10 sensitized pairs to be used min_sensitized = 13 cfg3 = kidney_ip.OptConfig(d, altruists, args.cycle_cap, args.chain_cap, args.verbose, args.timelimit, args.edge_success_prob, args.eef_alt_constraints, args.lp_file, args.relax, args.multi, args.pool_gap, min_sensitized) opt_solution3 = solve_kep(cfg3, args.formulation, args.use_relabelled) print "Fairness constrined to {}. OPT = {}".format(min_sensitized, opt_solution3.total_score) print "# sensitized pairs used (total) = {} ({})".format(opt_solution3.num_sensitized(),num_sensitized) print "----------- sensitized verts -----------" print ' '.join([str(i) for i in sorted(sensitized_pairs)]) print "----------- solution -----------" print opt_solution3.display() elif experiment_num == 3: # 1) calculate core (optimal), and fairness values within core min_sens = 0 cfg = kidney_ip.OptConfig(d, altruists, args.cycle_cap, args.chain_cap, args.verbose, args.timelimit, args.edge_success_prob, args.eef_alt_constraints, args.lp_file, args.relax, args.multi, 0, 0) core = solve_kep(cfg, args.formulation, args.use_relabelled) core_fairness = [s.num_sensitized() for s in core.solutions] print "optimal score: {}".format(core.total_score) print "fairness values (num sensitized = {}):".format(num_sensitized) print core_fairness # 2) start with a 0% fairness bound, and increase as long as KEP is feasible. for each increase in fairness, # solve KEP and record optimal solution # ONLY SEARCH FOR ONE SOLUTION for min_sensitized in range(num_sensitized): cfg2 = kidney_ip.OptConfig(d, altruists, args.cycle_cap, args.chain_cap, args.verbose, args.timelimit, args.edge_success_prob, args.eef_alt_constraints, args.lp_file, args.relax, 1, 0, min_sensitized) sol = solve_kep(cfg2, args.formulation, args.use_relabelled) print "min_sensitized : {} score : {}".format(min_sensitized, sol.total_score) else: start_time = time.time() cfg = kidney_ip.OptConfig(d, altruists, args.cycle_cap, args.chain_cap, args.verbose, args.timelimit, args.edge_success_prob, args.eef_alt_constraints, args.lp_file, args.relax, args.multi) # added multi -- Duncan opt_solution = solve_kep(cfg, args.formulation, args.use_relabelled) time_taken = time.time() - start_time if args.multi > 1: # added by Duncan print "formulation: {}".format(args.formulation) print "formulation_name: {}".format(opt_solution.formulation_name) print "using_relabelled: {}".format(args.use_relabelled) print "cycle_cap: {}".format(args.cycle_cap) print "chain_cap: {}".format(args.chain_cap) print "total_time: {}".format(time_taken) print "ip_solve_time: {}".format(opt_solution.ip_model.runtime) print "# pairs : {}".format(cfg.digraph.n) print "# NDDs : {}".format(len(cfg.ndds)) print "total_score: {}".format(opt_solution.total_score) print "max core size: {}".format(args.multi) print "core size : {}".format(opt_solution.size) if args.output_core: opt_solution.write_vertex_participation(args.output_core, args.cycle_cap, args.chain_cap, len(altruists) ) else: print "formulation: {}".format(args.formulation) print "formulation_name: {}".format(opt_solution.formulation_name) print "using_relabelled: {}".format(args.use_relabelled) print "cycle_cap: {}".format(args.cycle_cap) print "chain_cap: {}".format(args.chain_cap) print "edge_success_prob: {}".format(args.edge_success_prob) print "ip_time_limit: {}".format(args.timelimit) print "ip_vars: {}".format(opt_solution.ip_model.numVars) print "ip_constrs: {}".format(opt_solution.ip_model.numConstrs) print "total_time: {}".format(time_taken) print "ip_solve_time: {}".format(opt_solution.ip_model.runtime) print "solver_status: {}".format(opt_solution.ip_model.status) print "total_score: {}".format(opt_solution.total_score) opt_solution.display()
def start(): parser = argparse.ArgumentParser("Solve a kidney-exchange instance") parser.add_argument("cycle_cap", type=int, help="The maximum permitted cycle length") parser.add_argument( "chain_cap", type=int, help="The maximum permitted number of edges in a chain") parser.add_argument( "formulation", help= "The IP formulation (uef, eef, eef_full_red, hpief_prime, hpief_2prime, hpief_prime_full_red, hpief_2prime_full_red, picef, cf)" ) parser.add_argument( "--use-relabelled", "-r", required=False, action="store_true", help="Relabel vertices in descending order of in-deg + out-deg") parser.add_argument( "--eef-alt-constraints", "-e", required=False, action="store_true", help= "Use slightly-modified EEF constraints (ignored for other formulations)" ) parser.add_argument( "--timelimit", "-t", required=False, default=None, type=float, help="IP solver time limit in seconds (default: no time limit)") parser.add_argument("--verbose", "-v", required=False, action="store_true", help="Log Gurobi output to screen and log file") parser.add_argument( "--edge-success-prob", "-p", required=False, type=float, default=1.0, help="Edge success probability, for failure-aware matching. " + "This can only be used with PICEF and cycle formulation. (default: 1)") parser.add_argument("--lp-file", "-l", required=False, default=None, metavar='FILE', help="Write the IP model to FILE, then exit.") parser.add_argument("--relax", "-x", required=False, action='store_true', help="Solve the LP relaxation.") args = parser.parse_args() args.formulation = args.formulation.lower() input_lines = [line for line in sys.stdin if len(line.strip()) > 0] n_digraph_edges = int(input_lines[0].split()[1]) digraph_lines = input_lines[:n_digraph_edges + 2] d = kidney_digraph.read_digraph(digraph_lines) if len(input_lines) > len(digraph_lines): ndd_lines = input_lines[n_digraph_edges + 2:] altruists = kidney_ndds.read_ndds(ndd_lines, d) else: altruists = [] start_time = time.time() cfg = kidney_ip.OptConfig(d, altruists, args.cycle_cap, args.chain_cap, args.verbose, args.timelimit, args.edge_success_prob, args.eef_alt_constraints, args.lp_file, args.relax) opt_solution = solve_kep(cfg, args.formulation, args.use_relabelled) time_taken = time.time() - start_time print "formulation: {}".format(args.formulation) print "formulation_name: {}".format(opt_solution.formulation_name) print "using_relabelled: {}".format(args.use_relabelled) print "cycle_cap: {}".format(args.cycle_cap) print "chain_cap: {}".format(args.chain_cap) print "edge_success_prob: {}".format(args.edge_success_prob) print "ip_time_limit: {}".format(args.timelimit) print "ip_vars: {}".format(opt_solution.ip_model.numVars) print "ip_constrs: {}".format(opt_solution.ip_model.numConstrs) print "total_time: {}".format(time_taken) print "ip_solve_time: {}".format(opt_solution.ip_model.runtime) print "solver_status: {}".format(opt_solution.ip_model.status) print "total_score: {}".format(opt_solution.total_score) opt_solution.display()