Пример #1
0
def test_weighted_instance():
    """Checks that the capped formulations agree on the optimal
    result for an instance with weighted edges.
    """
    EPS = 0.000001
    d, ndds = read_with_ndds("test-fixtures/100-random-weights")
    fns = [
        k_ip.optimise_hpief_prime, k_ip.optimise_hpief_2prime,
        k_ip.optimise_hpief_prime_full_red,
        k_ip.optimise_hpief_2prime_full_red, k_ip.optimise_picef,
        k_ip.optimise_ccf, k_ip.optimise_eef, k_ip.optimise_eef_full_red
    ]
    for max_cycle in [0, 1, 2, 3, 4]:
        for max_chain in [0, 1, 2, 3]:
            opt_result_0 = fns[0](k_ip.OptConfig(d, ndds, max_cycle,
                                                 max_chain))
            k_utils.check_validity(opt_result_0, d, ndds, max_cycle, max_chain)
            for fn in fns[1:]:
                opt_result = fn(k_ip.OptConfig(d, ndds, max_cycle, max_chain))
                k_utils.check_validity(opt_result, d, ndds, max_cycle,
                                       max_chain)
                print(max_cycle, max_chain, opt_result.total_score, \
                        opt_result.ip_model.obj_val, opt_result_0.total_score, fn)
                assert abs(opt_result.total_score -
                           opt_result_0.total_score) < EPS
Пример #2
0
def test_relabelled_solve():
    """Checks whether the vertex-ordering heuristic affects the
    result for a weighted instance
    """
    EPS = 0.000001
    d, ndds = read_with_ndds("test-fixtures/100-random-weights")
    for max_cycle in [0, 3]:
        for max_chain in [0, 5]:
            opt_result_0 = k_ip.optimise_picef(
                k_ip.OptConfig(d, ndds, max_cycle, max_chain))
            print(opt_result_0.total_score)
            opt_result = k_ip.optimise_relabelled(
                k_ip.optimise_picef,
                k_ip.OptConfig(d, ndds, max_cycle, max_chain))
            print("   ", opt_result.total_score)
            assert abs(opt_result.total_score - opt_result_0.total_score) < EPS
Пример #3
0
def test_weighted_instance_failure_aware():
    """Checks that the CF and PICEF formulations agree on the optimal
    result for an instance with weighted edges, using failure-aware solving.
    """
    EPS = 0.000001
    d, ndds = read_with_ndds("test-fixtures/100-random-weights")
    fns = [k_ip.optimise_picef, k_ip.optimise_ccf]
    for max_cycle in [0, 1, 2, 3, 4]:
        for max_chain in [0, 1, 2, 3]:
            cfg = k_ip.OptConfig(d,
                                 ndds,
                                 max_cycle,
                                 max_chain,
                                 edge_success_prob=0.7)
            opt_result_cf = k_ip.optimise_ccf(cfg)
            opt_result_picef = k_ip.optimise_picef(cfg)
            opt_result_cf_relabelled = k_ip.optimise_relabelled(
                k_ip.optimise_ccf, cfg)
            opt_result_picef_relabelled = k_ip.optimise_relabelled(
                k_ip.optimise_picef, cfg)
            assert abs(opt_result_cf.total_score -
                       opt_result_picef.total_score) < EPS
            assert abs(opt_result_cf.total_score -
                       opt_result_cf_relabelled.total_score) < EPS
            assert abs(opt_result_cf.total_score -
                       opt_result_picef_relabelled.total_score) < EPS
Пример #4
0
def test_instance_with_chain_with_option():
    graph, altruists = read_digraph_file("test-fixtures/test-alt2.json")
    cfg = k_ip.OptConfig(graph, ndds=altruists, max_cycle=3, max_chain=2)
    opt_result = k_ip.optimise_picef_nhs(cfg)
    eq_(len(opt_result.cycles), 0)
    eq_(len(opt_result.chains), 1)
    assert_almost_equal(opt_result.total_score, 9.098)
Пример #5
0
def test_instance_with_threeway_with_backarc_max_matchable():
    graph, altruists = read_digraph_file("test-fixtures/test3.json")
    cfg = k_ip.OptConfig(graph, ndds=altruists, max_cycle=3, max_chain=2)
    cfg._constrain_maximal = True
    opt_result = k_ip.optimise_picef_nhs(cfg)
    eq_(len(opt_result.cycles), 1)
    assert_almost_equal(opt_result.total_score, 12.147)
Пример #6
0
def test_instance_with_twocycle_and_threecycle_max_matchable():
    graph, altruists = read_digraph_file("test-fixtures/test1.json")
    cfg = k_ip.OptConfig(graph, ndds=altruists, max_cycle=3, max_chain=2)
    cfg._constrain_maximal = True
    opt_result = k_ip.optimise_picef_nhs(cfg)
    eq_(len(opt_result.cycles), 1)
    eq_(opt_result.total_score, 8.098)
Пример #7
0
def test_instance_with_threeway_with_backarc_or_threeway_without():
    graph, altruists = read_digraph_file("test-fixtures/test4.json")
    opt_result = k_ip.optimise_picef_nhs(
        k_ip.OptConfig(graph, ndds=altruists, max_cycle=3, max_chain=2))
    eq_(len(opt_result.cycles), 1)
    assert_almost_equal(opt_result.total_score, 12.147)
    cycle = [v.patient_id() for v in opt_result.cycles[0]]
    eq_(cycle, [1, 2, 4])
Пример #8
0
def test_instance_with_two_2cycles():
    d, ndds = read_with_ndds("test-fixtures/two_2cycles")
    fns = [
        k_ip.optimise_uuef, k_ip.optimise_eef, k_ip.optimise_eef_full_red,
        k_ip.optimise_hpief_prime_full_red,
        k_ip.optimise_hpief_2prime_full_red, k_ip.optimise_hpief_prime,
        k_ip.optimise_hpief_2prime, k_ip.optimise_picef, k_ip.optimise_ccf
    ]
    for fn in fns:
        opt_result = fn(k_ip.OptConfig(d, ndds, 3, 0))
        assert len(opt_result.cycles) == 1
        assert opt_result.total_score == 40
Пример #9
0
def test_preflib_instance_with_zero_chain_cap():
    d, ndds = read_with_ndds("test-fixtures/MD-00001-00000100")
    fns = [
        k_ip.optimise_eef, k_ip.optimise_eef_full_red,
        k_ip.optimise_hpief_prime_full_red,
        k_ip.optimise_hpief_2prime_full_red, k_ip.optimise_hpief_prime,
        k_ip.optimise_hpief_2prime, k_ip.optimise_eef,
        k_ip.optimise_eef_full_red, k_ip.optimise_picef, k_ip.optimise_ccf
    ]
    for fn in fns:
        max_cycle = 4
        max_chain = 0
        opt_result = fn(k_ip.OptConfig(d, ndds, max_cycle, max_chain))
        k_utils.check_validity(opt_result, d, ndds, max_cycle, max_chain)
        print(fn)
        assert opt_result.total_score == 39
Пример #10
0
def test_single_cycle_instance():
    d, ndds = read_with_ndds("test-fixtures/one-cycle")
    fns = [
        k_ip.optimise_uuef, k_ip.optimise_hpief_prime,
        k_ip.optimise_hpief_2prime, k_ip.optimise_hpief_prime_full_red,
        k_ip.optimise_hpief_2prime_full_red, k_ip.optimise_eef,
        k_ip.optimise_eef_full_red, k_ip.optimise_picef, k_ip.optimise_ccf
    ]
    for max_chain in [0, 1, 2]:
        for fn in fns:
            opt_result = fn(k_ip.OptConfig(d, ndds, 3, max_chain))
            assert len(opt_result.cycles) == 1
            if fn == k_ip.optimise_uuef or max_chain > 0:
                assert len(opt_result.chains) == 1
            else:
                assert len(opt_result.chains) == 0
Пример #11
0
def test_chains_only_instance():
    d, ndds = read_with_ndds("test-fixtures/no-cycles")
    fns = [
        k_ip.optimise_uuef, k_ip.optimise_hpief_prime,
        k_ip.optimise_hpief_2prime, k_ip.optimise_hpief_prime_full_red,
        k_ip.optimise_hpief_2prime_full_red, k_ip.optimise_eef,
        k_ip.optimise_eef_full_red, k_ip.optimise_picef, k_ip.optimise_ccf
    ]
    for max_chain in [0, 1, 2]:
        for fn in fns:
            opt_result = fn(k_ip.OptConfig(d, ndds, 3, max_chain, None))
            eq_(len(opt_result.cycles), 0)
            if fn == k_ip.optimise_uuef or max_chain > 0:
                eq_(len(opt_result.chains), 2)
            else:
                eq_(len(opt_result.chains), 0)
Пример #12
0
def test_failure_aware():
    # Use instance with a 3-cycle and a 3-chain
    d, ndds = read_with_ndds("test-fixtures/3cycle_and_3chain")
    fns = [k_ip.optimise_picef, k_ip.optimise_ccf]
    for fn in fns:
        for max_cycle, max_chain, expected_score in [(3, 2, 3 * .125 + .75),
                                                     (3, 3, 3 * .125 + .875),
                                                     (0, 3, .875),
                                                     (3, 0, 3 * .125)]:

            opt_result = fn(
                k_ip.OptConfig(d,
                               ndds,
                               max_cycle,
                               max_chain,
                               edge_success_prob=.5))
            # 3 edges * .5**3 for the cycle; .5 + .5**2 for the chain
            assert opt_result.total_score == expected_score
            k_utils.check_validity(opt_result, d, ndds, max_cycle, max_chain)
Пример #13
0
def test_failure_aware():
    # Use instance with a 3-cycle and a 3-chain
    d, ndds = read_with_ndds("test-fixtures/3cycle_and_3chain")
    fns = [k_ip.optimise_picef, k_ip.optimise_ccf]
    edge_weight = 1 * 0.5
    for fn in fns:
        for max_cycle, max_chain, expected_score in [
            (3, 0, 1.5), (3, 2, 1.5 + 0.5 + 0.25),
            (3, 3, 1.5 + 0.5 + 0.25 + 0.125), (0, 3, 0.5 + 0.25 + 0.125)
        ]:
            opt_result = fn(
                k_ip.OptConfig(d,
                               ndds,
                               max_cycle,
                               max_chain,
                               edge_success_prob=.5))
            assert_almost_equal(opt_result.total_score, expected_score)
            LOGGER.debug("%s got %s, expected %s", fn, opt_result.total_score,
                         expected_score)
            k_utils.check_validity(opt_result, d, ndds, max_cycle, max_chain)
Пример #14
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, nhs, nhs_chains)"
    )
    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(
        "--details",
        required=False,
        default=None,
        metavar='FILE',
        help="Write a summary of the problem to FILE, then exit.")
    parser.add_argument("--size",
                        "-s",
                        required=False,
                        action='store_true',
                        help="Only maximise number of transplants")
    parser.add_argument("--relax",
                        "-x",
                        required=False,
                        action='store_true',
                        help="Solve the LP relaxation.")
    parser.add_argument("--output",
                        "-o",
                        required=False,
                        metavar='FILE',
                        help="Write solution to FILE")
    parser.add_argument("--std-output",
                        required=False,
                        action='store_true',
                        help="Write solution to stdout")
    parser.add_argument("--xml",
                        required=False,
                        metavar='FILE',
                        help="Write solution as XML to FILE")
    parser.add_argument(
        "--matchable",
        required=False,
        action="store_true",
        help="Find and use maximally matchable edges (For NHS option only)")
    parser.add_argument("--debug",
                        "-d",
                        required=False,
                        action="store_true",
                        help="Enable debugging output")

    args = parser.parse_args()

    if args.debug:
        logging.basicConfig(level=logging.DEBUG,
                            format='%(asctime)s %(levelname)s:%(name)s '
                            '%(message)s')
    else:
        logging.basicConfig(level=logging.INFO,
                            format='%(asctime)s %(levelname)s:%(name)s '
                            '%(message)s')
    args.formulation = args.formulation.lower()

    input_lines = [line for line in sys.stdin if len(line.strip()) > 0]
    if input_lines[0].strip() == "{":  # JSON input
        digraph, altruists = readers.read_digraph_json(input_lines)
    elif "xml" in input_lines[0] or "<data>" in input_lines[0]:
        digraph, altruists = readers.read_digraph_xml(input_lines)
    else:
        n_digraph_edges = int(input_lines[0].split()[1])
        digraph_lines = input_lines[:n_digraph_edges + 2]

        digraph = readers.read_digraph(digraph_lines)

        if len(input_lines) > len(digraph_lines):
            ndd_lines = input_lines[n_digraph_edges + 2:]
            altruists = readers.read_ndds(ndd_lines, digraph)
        else:
            altruists = []

    start_time = time.time()
    cfg = kidney_ip.OptConfig(digraph, 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.size,
                              args.details)
    if args.matchable:
        cfg._constrain_maximal = True
    opt_solution = solve_kep(cfg, args.formulation, args.use_relabelled)
    time_taken = time.time() - start_time
    if args.std_output:
        print("formulation: {}".format(args.formulation))
        if opt_solution:
            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))
        if opt_solution:
            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))
        if opt_solution:
            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))
    if args.xml and opt_solution:
        opt_solution.as_xml(args.xml)
    if opt_solution:
        if args.output:
            with open(args.output, 'w') as outfile:
                outfile.write(str(opt_solution))
        elif args.std_output:
            opt_solution.display()
Пример #15
0
def test_instance_with_two_threeway_or_three_twoway():
    graph, altruists = read_digraph_file("test-fixtures/test2.json")
    opt_result = k_ip.optimise_picef_nhs(
        k_ip.OptConfig(graph, ndds=altruists, max_cycle=3, max_chain=2))
    eq_(len(opt_result.cycles), 3)
    assert_almost_equal(opt_result.total_score, 24.294)