Exemple #1
0
def test_bg_foi():
    bristol = Ward("Bristol")
    london = Ward("London")
    oxford = Ward("Oxford")

    bristol.set_num_players(100)
    london.set_num_players(100)
    oxford.set_num_players(100)

    bristol.set_bg_foi(10)
    london.set_bg_foi(1)

    wards = bristol + london + oxford

    lurgy = Disease("lurgy")

    lurgy.add("E", beta=0.0, progress=1.0)
    lurgy.add("I", beta=0.0, progress=1.0)
    lurgy.add("R")

    params = Parameters()
    params.set_disease(lurgy)

    network = Network.from_wards(wards, params=params)

    outdir = os.path.join(script_dir, "test_bg_foi")

    with OutputFiles(outdir, force_empty=True, prompt=None) as output_dir:
        trajectory = network.run(population=Population(),
                                 output_dir=output_dir,
                                 extractor=_check_infections)

    OutputFiles.remove(outdir, prompt=None)

    # the only source of infection should be the bg. Should have
    # no infections in oxford, some in london and most in bristol
    print(trajectory[-1])

    assert trajectory[-1].recovereds <= 200
    assert trajectory[-1].susceptibles >= 100
Exemple #2
0
def test_go_ward():
    bristol = Ward("bristol")
    london = Ward("london")
    oxford = Ward("oxford")

    bristol.set_num_players(100)
    london.set_num_players(100)
    oxford.set_num_players(100)

    bristol.add_workers(0, destination=london)
    bristol.add_workers(0, destination=oxford)
    oxford.add_workers(0, destination=bristol)
    oxford.add_workers(0, destination=london)
    london.add_workers(0, destination=bristol)
    london.add_workers(0, destination=oxford)

    disease = Disease(name="lurgy")
    disease.add(name="E", beta=0.5, progress=0.5)
    disease.add(name="I", beta=0.8, progress=0.25)
    disease.add(name="R")
    disease.assert_sane()

    params = Parameters()
    params.set_disease(disease)
    params.add_seeds("1 20 bristol")

    outdir = os.path.join(script_dir, "test_go_ward_output")

    network = Network.from_wards(bristol + london + oxford, params=params)

    with OutputFiles(outdir, force_empty=True, prompt=None) as output_dir:
        trajectory = network.copy().run(population=Population(),
                                        output_dir=output_dir,
                                        nthreads=1)

    print(trajectory[-1])

    # there are no workers, so can only infect the 100 Bristolians
    assert trajectory[-1].recovereds <= 100

    # Repeat with a different number of threads to test parallel code
    outdir = os.path.join(script_dir, "test_go_ward_output")

    with OutputFiles(outdir, force_empty=True, prompt=None) as output_dir:
        trajectory = network.copy().run(population=Population(),
                                        output_dir=output_dir,
                                        nthreads=4)

    print(trajectory[-1])

    # there are no workers, so can only infect the 100 Bristolians
    assert trajectory[-1].recovereds <= 100

    # now do a cyclic move, from "R" to "S"
    with OutputFiles(outdir, force_empty=True, prompt=None) as output_dir:
        trajectory = network.copy().run(population=Population(),
                                        output_dir=output_dir,
                                        mover=move_cycle,
                                        nsteps=200)

    print(trajectory[-1])

    # we should have completed all 200 steps as this will never end
    assert trajectory[-1].day == 200
    assert trajectory[-1].recovereds <= 100

    # move everyone to Bristol
    with OutputFiles(outdir, force_empty=True, prompt=None) as output_dir:
        trajectory = network.copy().run(population=Population(),
                                        output_dir=output_dir,
                                        mover=move_bristol)

    print(trajectory[-1])
    assert trajectory[-1].recovereds > 100

    # now move through all of bristol, london, oxford
    with OutputFiles(outdir, force_empty=True, prompt=None) as output_dir:
        trajectory = network.copy().run(population=Population(),
                                        output_dir=output_dir,
                                        mover=move_travel)

    print(trajectory[-1])
    assert trajectory[-1].recovereds > 100

    OutputFiles.remove(outdir, prompt=None)
Exemple #3
0
def test_go_record():
    bristol = Ward("bristol")
    london = Ward("london")
    oxford = Ward("oxford")

    bristol.set_num_players(100)
    london.set_num_players(100)
    oxford.set_num_players(100)

    bristol.add_workers(0, destination=london)
    bristol.add_workers(0, destination=oxford)
    oxford.add_workers(0, destination=bristol)
    oxford.add_workers(0, destination=london)
    london.add_workers(0, destination=bristol)
    london.add_workers(0, destination=oxford)

    disease = Disease(name="lurgy")
    disease.add(name="E", beta=0.5, progress=0.5)
    disease.add(name="I", beta=0.8, progress=0.25)
    disease.add(name="R")
    disease.assert_sane()

    params = Parameters()
    params.set_disease(disease)
    params.add_seeds("1 20 bristol")

    outdir = os.path.join(script_dir, "test_go_ward_output")

    network = Network.from_wards(bristol + london + oxford, params=params)

    with OutputFiles(outdir, force_empty=True, prompt=None) as output_dir:
        trajectory = network.copy().run(population=Population(),
                                        output_dir=output_dir,
                                        mover=move_bristol)

    OutputFiles.remove(outdir, prompt=None)

    # despite the moves, only Bristolians can be infected as there
    # are no work movements
    assert trajectory[-1].recovereds <= 100
Exemple #4
0
def test_ward_params():
    bristol = Ward("Bristol")
    london = Ward("London")
    oxford = Ward("Oxford")

    bristol.set_num_players(1000)
    london.set_num_players(5000)
    oxford.set_num_players(800)

    bristol.add_workers(500, destination=bristol)
    bristol.add_workers(200, destination=oxford)
    bristol.add_workers(900, destination=london)

    oxford.add_workers(100, destination=bristol)
    oxford.add_workers(1000, destination=oxford)
    oxford.add_workers(2000, destination=london)

    london.add_workers(100, destination=bristol)
    london.add_workers(400, destination=oxford)
    london.add_workers(10000, destination=london)

    bristol.add_player_weight(0.1, destination=oxford)
    oxford.add_player_weight(0.2, destination=bristol)
    oxford.add_player_weight(0.15, destination=london)
    london.add_player_weight(0.3, destination=oxford)

    bristol.set_scale_uv(0.5)
    bristol.set_cutoff(5.0)
    london.set_scale_uv(1.5)
    oxford.set_cutoff(15.4)

    bristol.set_bg_foi(10.8)
    london.set_bg_foi(-5.2)

    bristol.set_custom("something", 9.9)
    oxford.set_custom("else", 22.1)

    assert bristol.scale_uv() == 0.5
    assert bristol.cutoff() == 5.0
    assert bristol.bg_foi() == 10.8
    assert bristol.custom("something") == 9.9
    assert bristol.custom("else") == 0.0
    assert bristol.custom("else", 1.0) == 1.0

    assert london.scale_uv() == 1.5
    assert london.bg_foi() == -5.2

    assert oxford.cutoff() == 15.4
    assert oxford.bg_foi() == 0.0
    assert oxford.custom("else") == 22.1

    wards = bristol + london + oxford

    assert wards[bristol].scale_uv() == 0.5
    assert wards[oxford].custom("else") == 22.1
    assert wards[bristol].bg_foi() == 10.8
    assert wards[oxford].bg_foi() == 0.0

    s = wards.to_json()
    print(s)
    assert wards == Wards.from_json(s)

    network = Network.from_wards(wards)

    assert network.nodes.scale_uv[1] == 0.5
    assert network.nodes.scale_uv[2] == 1.5
    assert network.nodes.scale_uv[3] == 1.0

    assert network.nodes.cutoff[1] == 5.0
    assert network.nodes.cutoff[2] == 99999.99
    assert network.nodes.cutoff[3] == 15.4

    assert network.nodes.bg_foi[1] == 10.8
    assert network.nodes.bg_foi[2] == -5.2
    assert network.nodes.bg_foi[3] == 0.0

    something = network.nodes.get_custom("something")
    els = network.nodes.get_custom("else")
    miss = network.nodes.get_custom("missing", 99.9)

    assert something[1] == 9.9
    assert something[2] == 0.0
    assert something[3] == 0.0

    assert els[1] == 0.0
    assert els[2] == 0.0
    assert els[3] == 22.1

    assert miss[1] == 99.9
    assert miss[2] == 99.9
    assert miss[3] == 99.9

    network2 = Network.from_wards(network.to_wards())

    for i in range(0, len(network.info)):
        assert network.info[i] == network2.info[i]

    for i in range(1, network.nnodes + 1):
        assert network.nodes.scale_uv[i] == network2.nodes.scale_uv[i]
        assert network.nodes.cutoff[i] == network2.nodes.cutoff[i]
        assert network.nodes.bg_foi[i] == network2.nodes.bg_foi[i]
        assert network.nodes.get_custom("something")[i] == \
            network2.nodes.get_custom("something")[i]
        assert network.nodes.get_custom("else")[i] == \
            network2.nodes.get_custom("else")[i]
Exemple #5
0
def test_ward_json():
    w = WardInfo(name="something",
                 alternate_names=["one", "two"],
                 code="123",
                 alternate_codes=["1", "2", "cat"],
                 authority="somewhere",
                 authority_code="s123",
                 region="place name",
                 region_code="r789")

    s = json.dumps(w.to_data())
    print(s)

    w2 = WardInfo.from_data(json.loads(s))

    assert w == w2

    ward = Ward(id=10, info=w)

    ward.set_position(x=1500, y=2500, units="m")
    ward.set_num_players(1200)
    ward.set_num_workers(500)

    ward.add_workers(number=30, destination=1)
    ward.add_workers(number=20, destination=30)

    ward.add_player_weight(weight=0.2, destination=30)
    ward.add_player_weight(weight=0.5, destination=1)

    print(ward)

    s = json.dumps(ward.to_data())

    print(s)

    ward2 = Ward.from_data(json.loads(s))

    assert json.dumps(ward.to_data()) == json.dumps(ward2.to_data())
    assert ward == ward2

    ward2 = Ward(id=1, name="something else")

    ward3 = Ward(id=30, name="another name")

    wards = Wards([ward, ward2, ward3])

    print(wards)

    _assert_equal(wards[ward.id()], ward)
    _assert_equal(wards[ward2.id()], ward2)
    _assert_equal(wards[ward3.id()], ward3)

    s = json.dumps(wards.to_data())

    print(s)

    wards2 = Wards.from_data(json.loads(s))

    assert wards == wards2

    ward3 = Ward(id=50, name="another ward")
    wards2.insert(ward3)

    assert wards != wards2
Exemple #6
0
def test_harmonise_wards():
    bristol = Ward("Bristol")
    london = Ward("London")
    oxford = Ward("Oxford")

    bristol.set_num_players(1000)
    london.set_num_players(5000)
    oxford.set_num_players(800)

    bristol.add_workers(500, destination=bristol)
    bristol.add_workers(200, destination=oxford)
    bristol.add_workers(900, destination=london)

    oxford.add_workers(100, destination=bristol)
    oxford.add_workers(1000, destination=oxford)
    oxford.add_workers(2000, destination=london)

    london.add_workers(100, destination=bristol)
    london.add_workers(400, destination=oxford)
    london.add_workers(10000, destination=london)

    bristol.add_player_weight(0.1, destination=oxford)
    oxford.add_player_weight(0.2, destination=bristol)
    oxford.add_player_weight(0.15, destination=london)
    london.add_player_weight(0.3, destination=oxford)

    home_wards = bristol + london + oxford
    print(home_wards)

    holiday = Ward("holiday")
    bristol = Ward("Bristol")
    oxford = Ward("Oxford")
    holiday.add_player_weight(0.5, destination=bristol)
    holiday.add_player_weight(0.5, destination=oxford)

    holiday_wards = bristol + oxford + holiday
    print(holiday_wards)

    hospital = Ward("hospital")
    london = Ward("London")
    london.add_workers(50, destination=hospital)
    hospital.set_num_players(150)

    hospital_wards = london + hospital
    print(hospital_wards)

    overall, harmonised = Wards.harmonise(
        [home_wards, holiday_wards, hospital_wards])

    print(overall)
    print(harmonised)

    assert overall.num_workers() == home_wards.num_workers() + \
        holiday_wards.num_workers() + \
        hospital_wards.num_workers()

    assert overall.num_players() == home_wards.num_players() + \
        holiday_wards.num_players() + \
        hospital_wards.num_players()

    assert harmonised[0].num_workers() == home_wards.num_workers()
    assert harmonised[0].num_players() == home_wards.num_players()
    assert harmonised[1].num_workers() == holiday_wards.num_workers()
    assert harmonised[1].num_players() == holiday_wards.num_players()
    assert harmonised[2].num_workers() == hospital_wards.num_workers()
    assert harmonised[2].num_players() == hospital_wards.num_players()

    print(overall.to_json())
Exemple #7
0
def test_duplicate_wards():
    bristol = Ward("Bristol")
    bristol.set_num_players(100)

    london = Ward("London")
    london.set_num_players(200)

    bristol.add_workers(50, london)
    bristol.add_player_weight(0.5, london)

    wards = bristol + london

    print(wards)

    assert bristol in wards
    assert london in wards

    assert wards.num_workers() == bristol.num_workers() + london.num_workers()
    assert wards.num_players() == bristol.num_players() + london.num_players()

    print(wards.to_json())

    wlist1 = wards[bristol].get_worker_lists()
    plist1 = wards[bristol].get_player_lists()

    wards += bristol

    print(wards)

    print(wards.to_json())

    assert wards[bristol].num_players() == 2 * bristol.num_players()
    assert wards[bristol].num_workers() == 2 * bristol.num_workers()

    wlist2 = wards[bristol].get_worker_lists()
    plist2 = wards[bristol].get_player_lists()

    print(wlist1)
    print(wlist2)

    assert wlist1[0][0] == wlist2[0][0]
    assert 2 * wlist1[1][0] == wlist2[1][0]

    print(plist1)
    print(plist2)

    assert plist1 == plist2
Exemple #8
0
def test_add_wards():

    bristol = Ward("Bristol")
    london = Ward("London")
    glasgow = Ward("Glasgow")

    wards = Wards()

    assert bristol not in wards
    assert london not in wards
    assert glasgow not in wards

    bristol.add_workers(5, london)
    bristol.add_workers(10, bristol)
    bristol.add_workers(15, glasgow)

    assert not bristol.is_resolved()

    print(bristol._workers, bristol._players)

    bristol.add_player_weight(0.2, london)
    bristol.add_player_weight(0.5, glasgow)

    wards.add(bristol)

    assert bristol in wards
    assert london not in wards
    assert glasgow not in wards

    wards.add(london)

    assert london in wards
    assert glasgow not in wards

    assert bristol + london == wards

    wards2 = wards + glasgow

    assert glasgow in wards2

    wards += glasgow

    assert wards == wards2

    assert bristol + london + glasgow == wards

    print(wards)

    print(bristol._workers, bristol._players)

    assert not bristol.is_resolved()

    bristol2 = bristol.resolve(wards)

    print(bristol2)
    print(bristol2._workers, bristol2._players)

    assert bristol2.is_resolved()
    assert bristol != bristol2

    bristol2 = bristol2.dereference(wards)

    assert not bristol2.is_resolved()
    assert bristol == bristol2

    assert wards == wards2

    sheffield = Ward("Sheffield")
    norwich = Ward("Norwich")

    wards2 = sheffield + norwich

    print(wards)
    print(wards2)

    wards3 = wards + wards2

    print(wards3)

    assert bristol in wards3
    assert london in wards3
    assert glasgow in wards3
    assert sheffield in wards3
    assert norwich in wards3

    wards3 = wards2 + wards

    bristol2 = wards3["Bristol"]

    assert bristol2.is_resolved()

    print(bristol2._workers, bristol2._players)

    bristol2 = bristol2.dereference(wards3)

    assert not bristol2.is_resolved()

    print(bristol2._workers, bristol2._players)

    assert bristol == bristol2
Exemple #9
0
def test_wards():
    wards = Wards()
    bristol = Ward(name="Bristol")
    london = Ward(name="London")
    bristol.add_workers(500, destination=bristol)
    bristol.add_workers(500, destination=london)
    bristol.set_num_players(750)
    london.add_workers(8500, destination=london)
    london.add_workers(100, destination=bristol)
    london.set_num_players(10000)
    print(bristol)
    print(london)

    wards.add(bristol)
    wards.add(london)

    print(wards)

    assert wards.num_workers() == 9600
    assert wards.num_players() == 10750
    assert wards.population() == 10750 + 9600

    data = wards.to_data()

    print(data)

    wards2 = Wards.from_data(data)

    print(wards2)

    assert wards == wards2

    try:
        filename = "_test_wards.json"

        with open(filename, "w") as FILE:
            json.dump(data, FILE, indent=2)

        print("".join(open(filename).readlines()))

        with open(filename) as FILE:
            data2 = json.load(FILE)

        wards2 = Wards.from_data(data2)
        print(wards2)
        assert wards == wards2

    finally:
        import os
        os.unlink(filename)

    network = Network.from_wards(wards, disease="lurgy")

    assert network.work_population == wards.num_workers()
    assert network.play_population == wards.num_players()
    assert network.population == wards.population()

    wards2 = network.to_wards()

    assert len(wards) == len(wards2)

    for w1, w2 in zip(wards, wards2):
        if w1 is None:
            assert w2 is None
            continue

        assert w1.id() == w2.id()
        assert w1.name() == w2.name()
        assert w1.info() == w2.info()
        assert w1.num_workers() == w2.num_workers()
        assert w1.num_players() == w2.num_players()
        assert w1.get_player_lists() == w2.get_player_lists()
        assert w1.get_worker_lists() == w2.get_worker_lists()
        assert w1.position() == w2.position()

    s = wards.to_json()
    wards2 = Wards.from_json(s)

    assert wards2 == wards

    filename = wards.to_json("_test_wards_data.json", indent=4)

    print(filename)

    try:
        wards2 = Wards.from_json(filename)
    finally:
        import os
        os.unlink(filename)

    assert wards2 == wards
Exemple #10
0
def test_move_generator():
    m = MoveGenerator(fraction=0.3)
    assert m.fraction() == 0.3

    m = MoveGenerator(number=1000)
    assert m.number() == 1000

    params = Parameters()
    params.set_disease("lurgy")

    network = Network.single(params, Population(initial=1000))

    m = MoveGenerator(from_stage="E")
    assert m.generate(network) == [[0, 1, 0, 1]]
    assert m.should_move_all()
    assert m.fraction() == 1.0
    assert m.number() >= 1000000000

    m = MoveGenerator(from_stage="E", to_stage="R")
    assert m.generate(network) == [[0, 1, 0, 4]]
    assert m.should_move_all()

    m = MoveGenerator(to_stage="R")
    assert m.generate(network) == [[0, -1, 0, 4], [0, 0, 0, 4], [0, 1, 0, 4],
                                   [0, 2, 0, 4], [0, 3, 0, 4], [0, 4, 0, 4]]
    assert m.should_move_all()

    m = MoveGenerator(from_stage=["E", "I1"])
    assert m.generate(network) == [[0, 1, 0, 1], [0, 2, 0, 2]]
    assert m.should_move_all()

    m = MoveGenerator(from_stage=["E", "I1"], to_stage=["I1", "I2"])
    assert m.generate(network) == [[0, 1, 0, 2], [0, 2, 0, 3]]
    assert m.should_move_all()

    m = MoveGenerator(from_stage=["E", "I1"], to_stage="R")
    assert m.generate(network) == [[0, 1, 0, 4], [0, 2, 0, 4]]
    assert m.should_move_all()

    m = MoveGenerator()
    assert m.generate(network) == [[0, -1, 0, -1], [0, 0, 0, 0], [0, 1, 0, 1],
                                   [0, 2, 0, 2], [0, 3, 0, 3], [0, 4, 0, 4]]
    assert m.should_move_all()

    demographics = Demographics.load(demography_json)

    networks = demographics.specialise(network)

    m = MoveGenerator()
    assert m.generate(networks) == [[0, -1, 0, -1], [0, 0, 0, 0], [0, 1, 0, 1],
                                    [0, 2, 0, 2], [0, 3, 0, 3], [0, 4, 0, 4],
                                    [1, -1, 1, -1], [1, 0, 1, 0], [1, 1, 1, 1],
                                    [1, 2, 1, 2], [1, 3, 1, 3], [1, 4, 1, 4],
                                    [2, -1, 2, -1], [2, 0, 2, 0], [2, 1, 2, 1],
                                    [2, 2, 2, 2], [2, 3, 2, 3], [2, 4, 2, 4]]

    m = MoveGenerator(from_stage="E")
    assert m.generate(networks) == [[0, 1, 0, 1], [1, 1, 1, 1], [2, 1, 2, 1]]

    m = MoveGenerator(to_stage="R")
    assert m.generate(networks) == [[0, -1, 0, 4], [0, 0, 0, 4], [0, 1, 0, 4],
                                    [0, 2, 0, 4], [0, 3, 0, 4], [0, 4, 0, 4],
                                    [1, -1, 1, 4], [1, 0, 1, 4], [1, 1, 1, 4],
                                    [1, 2, 1, 4], [1, 3, 1, 4], [1, 4, 1, 4],
                                    [2, -1, 2, 4], [2, 0, 2, 4], [2, 1, 2, 4],
                                    [2, 2, 2, 4], [2, 3, 2, 4], [2, 4, 2, 4]]

    m = MoveGenerator(from_demographic="red")
    assert m.generate(networks) == [[0, -1, 0, -1], [0, 0, 0, 0], [0, 1, 0, 1],
                                    [0, 2, 0, 2], [0, 3, 0, 3], [0, 4, 0, 4]]

    m = MoveGenerator(to_demographic="blue")
    assert m.generate(networks) == [[0, -1, 2, -1], [0, 0, 2, 0], [0, 1, 2, 1],
                                    [0, 2, 2, 2], [0, 3, 2, 3], [0, 4, 2, 4],
                                    [1, -1, 2, -1], [1, 0, 2, 0], [1, 1, 2, 1],
                                    [1, 2, 2, 2], [1, 3, 2, 3], [1, 4, 2, 4],
                                    [2, -1, 2, -1], [2, 0, 2, 0], [2, 1, 2, 1],
                                    [2, 2, 2, 2], [2, 3, 2, 3], [2, 4, 2, 4]]

    m = MoveGenerator(to_demographic="blue", to_stage="R")
    assert m.generate(networks) == [[0, -1, 2, 4], [0, 0, 2, 4], [0, 1, 2, 4],
                                    [0, 2, 2, 4], [0, 3, 2, 4], [0, 4, 2, 4],
                                    [1, -1, 2, 4], [1, 0, 2, 4], [1, 1, 2, 4],
                                    [1, 2, 2, 4], [1, 3, 2, 4], [1, 4, 2, 4],
                                    [2, -1, 2, 4], [2, 0, 2, 4], [2, 1, 2, 4],
                                    [2, 2, 2, 4], [2, 3, 2, 4], [2, 4, 2, 4]]

    m = MoveGenerator(from_demographic="red",
                      to_demographic="blue",
                      from_stage=["I1", "I2"],
                      to_stage="S")

    assert m.generate(networks) == [[0, 2, 2, -1], [0, 3, 2, -1]]

    m = MoveGenerator(from_demographic="blue", from_stage="E", to_stage="I1")

    print(m.generate(networks))
    assert m.generate(networks) == [[2, 1, 2, 2]]

    m = MoveGenerator(to_ward=1)

    player = PersonType.PLAYER
    worker = PersonType.WORKER

    assert m.generate_wards(network) == [[None, (player, 1, 2)]]
    assert m.generate_wards(networks) == [[None, (player, 1, 2)]]
    assert not m.should_move_all()
    assert m.fraction() == 1.0
    assert m.number() >= 1000000000

    bristol = Ward("bristol")
    london = Ward("london")
    oxford = Ward("oxford")

    bristol.add_workers(0, destination=london)
    bristol.add_workers(0, destination=oxford)
    london.add_workers(0, destination=bristol)
    london.add_workers(0, destination=oxford)

    network = Network.from_wards(bristol + london + oxford)

    assert len(network.nodes) == network.nnodes + 1
    assert len(network.links) == network.nlinks + 1

    assert network.nnodes == 3
    assert network.nlinks == 4

    m = MoveGenerator(from_ward=["bristol",
                                 WardID("bristol", "london")],
                      to_ward="oxford",
                      fraction=0.3,
                      number=100)
    assert not m.should_move_all()
    assert m.fraction() == 0.3
    assert m.number() == 100

    print(m.generate_wards(network))

    assert m.generate_wards(network) == [[(player, 1, 2), (player, 3, 4)],
                                         [(worker, 1, 2), (player, 3, 4)]]

    m = MoveGenerator(from_ward=WardID("oxford", "bristol"), to_ward=1)

    assert m.generate_wards(network) == [[(worker, -1, -1), (player, 1, 2)]]

    oxford.add_workers(0, destination=bristol)

    network = Network.from_wards(bristol + london + oxford)

    print(m.generate_wards(network))
    assert m.generate_wards(network) == [[(worker, 5, 6), (player, 1, 2)]]

    m = MoveGenerator(from_ward=WardID("bristol", "bristol"), to_ward="oxford")

    print(m.generate_wards(network))
    assert m.generate_wards(network) == [[(worker, -1, -1), (player, 3, 4)]]

    bristol.add_workers(0, destination=bristol)

    network = Network.from_wards(bristol + london + oxford)

    print(m.generate_wards(network))
    assert m.generate_wards(network) == [[(worker, 1, 2), (player, 3, 4)]]

    assert network.links.ifrom[1] == network.links.ito[1]
    assert network.links.ifrom[1] == network.get_node_index("bristol")

    m = MoveGenerator(to_ward=WardID("london", "bristol"))

    print(m.generate_wards(network))
    assert m.generate_wards(network) == [[None, (worker, 4, 5)]]

    assert network.links.ifrom[4] == network.get_node_index("london")
    assert network.links.ito[4] == network.get_node_index("bristol")

    m = MoveGenerator(
        from_stage="S",
        to_stage="R",
        from_ward=[WardID("bristol", all_commute=True),
                   WardID("bristol")],
        to_ward="oxford",
        number=42,
        fraction=0.5)

    print(m.generate(network))
    print(m.generate_wards(network))

    assert m.generate(network) == [[0, -1, 0, 4]]
    assert m.generate_wards(network) == [[(worker, 1, 4), (player, 3, 4)],
                                         [(player, 1, 2), (player, 3, 4)]]

    record = MoveRecord()

    for stage in m.generate(network):
        for ward in m.generate_wards(network):
            from_type = ward[0][0]
            ifrom_begin = ward[0][1]
            ifrom_end = ward[0][2]

            to_type = ward[1][0]
            ito_begin = ward[1][1]
            ito_end = ward[1][2]

            n = ifrom_end - ifrom_begin

            print(ifrom_begin, ifrom_end, ito_begin, ito_end)

            if ito_end - ito_begin == 0:
                raise ValueError("Cannot move individuals to a non-existent "
                                 "ward or ward-link")
            elif ito_end - ito_begin == 1:
                # this is a single to-ward (or link)
                ito_delta = 0
            elif ito_end - ito_begin != ifrom_end - ifrom_begin:
                # different number of links
                raise ValueError(
                    "Cannot move individuals as the number of from "
                    "and to links are not the same: "
                    f"{ifrom_begin}:{ifrom_end} versus "
                    f"{ito_begin}:{ito_end}")
            else:
                ito_delta = 1

            for i in range(0, n):
                ifrom = ifrom_begin + i
                ito = ito_begin + (i * ito_delta)
                record.add(from_demographic=stage[0],
                           from_stage=stage[1],
                           to_demographic=stage[2],
                           to_stage=stage[3],
                           from_type=from_type,
                           from_ward=ifrom,
                           to_type=to_type,
                           to_ward=ito,
                           number=m.number() * m.fraction())

    from array import array

    records = [
        array("i", (0, -1, 1, 1, 0, 4, 2, 3, 21)),
        array("i", (0, -1, 1, 2, 0, 4, 2, 3, 21)),
        array("i", (0, -1, 1, 3, 0, 4, 2, 3, 21)),
        array("i", (0, -1, 2, 1, 0, 4, 2, 3, 21))
    ]

    print(record._record)
    for i, move in enumerate(record):
        print(f"{move} == {records[i]}")
        assert move == records[i]