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))
Esempio n. 6
0
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()
Esempio n. 7
0
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()