Example #1
0
def test_folded_torus(w, h, transformation, uncrinkle_direction, folds,
                      mock_rhombus_to_rect, mock_fold):
    hex_boards, folded_boards = utils.folded_torus(w, h, transformation,
                                                   uncrinkle_direction, folds)

    # Right number of boards produced
    assert len(hex_boards) == len(folded_boards) == 3 * w * h

    # Same board should be present in hexagonal layout as in folded layout
    assert set(b for (b, c) in hex_boards) == set(b
                                                  for (b, c) in folded_boards)

    # Positions allocated should be unique
    assert len(set(c for (b, c) in hex_boards)) == len(hex_boards)
    assert len(set(c for (b, c) in folded_boards)) == len(folded_boards)

    # Should only use rhombus-to-rect when slicing
    if transformation == "slice":
        assert mock_rhombus_to_rect.called
    else:
        assert not mock_rhombus_to_rect.called

    min_x = min(c[0] for (b, c) in folded_boards)
    min_y = min(c[1] for (b, c) in folded_boards)

    # Should be based from 0,0
    assert min_x == 0
    assert min_y == 0

    max_x = max(c[0] for (b, c) in folded_boards)
    max_y = max(c[1] for (b, c) in folded_boards)

    # Should be folded the required number of times
    assert mock_fold.call_args[0][1] == folds

    # Folded boards should fit within expected bounds (note that the 'or's here
    # are to allow for folding odd numbers of boards in each dimension).
    if transformation == "slice":
        if uncrinkle_direction == "rows":
            assert max_x == 2 * w or max_x + 1 == 2 * w
            assert max_y == int(1.5 * h) or max_y + 1 == int(1.5 * h)
        else:  # if uncrinkle_direction == "columns":
            assert max_x == w or max_x + 1 == w
            assert max_y == 3 * h or max_y + 1 == 3 * h
    else:  # if transformation == "shear"
        if uncrinkle_direction == "rows":
            assert max_x == 3 * w or max_x + 1 == 3 * w
            assert max_y == h or max_y + 1 == h
        else:  # if uncrinkle_direction == "columns":
            assert max_x == w or max_x + 1 == w
            assert max_y == 3 * h or max_y + 1 == 3 * h
def test_folded_torus(w, h, transformation, uncrinkle_direction, folds,
                      mock_rhombus_to_rect,
                      mock_fold):
	hex_boards, folded_boards = utils.folded_torus(w, h, transformation,
	                                               uncrinkle_direction, folds)
	
	# Right number of boards produced
	assert len(hex_boards) == len(folded_boards) == 3 * w * h
	
	# Same board should be present in hexagonal layout as in folded layout
	assert set(b for (b, c) in hex_boards) == set(b for (b, c) in folded_boards)
	
	# Positions allocated should be unique
	assert len(set(c for (b, c) in hex_boards)) == len(hex_boards)
	assert len(set(c for (b, c) in folded_boards)) == len(folded_boards)
	
	# Should only use rhombus-to-rect when slicing
	if transformation == "slice":
		assert mock_rhombus_to_rect.called
	else:
		assert not mock_rhombus_to_rect.called
	
	min_x = min(c[0] for (b, c) in folded_boards)
	min_y = min(c[1] for (b, c) in folded_boards)
	
	# Should be based from 0,0
	assert min_x == 0
	assert min_y == 0
	
	max_x = max(c[0] for (b, c) in folded_boards)
	max_y = max(c[1] for (b, c) in folded_boards)
	
	# Should be folded the required number of times
	assert mock_fold.call_args[0][1] == folds
	
	# Folded boards should fit within expected bounds (note that the 'or's here
	# are to allow for folding odd numbers of boards in each dimension).
	if transformation == "slice":
		if uncrinkle_direction == "rows":
			assert max_x == 2*w or max_x + 1 == 2*w
			assert max_y == int(1.5*h) or max_y + 1 == int(1.5 * h)
		else:  # if uncrinkle_direction == "columns":
			assert max_x == w or max_x + 1 == w
			assert max_y == 3 * h or max_y + 1 == 3 * h
	else:  # if transformation == "shear"
		if uncrinkle_direction == "rows":
			assert max_x == 3*w or max_x + 1 == 3*w
			assert max_y == h or max_y + 1 == h
		else:  # if uncrinkle_direction == "columns":
			assert max_x == w or max_x + 1 == w
			assert max_y == 3*h or max_y + 1 == 3*h
def cabinetised_boards(cabinet):
	from spinner import transforms
	from spinner import utils
	
	# Generate folded system
	hex_boards, folded_boards = utils.folded_torus(10, 8, "shear", "rows", (2, 2))
	
	# Divide into cabinets
	cabinetised_boards = transforms.cabinetise(folded_boards,
	                                           cabinet.num_cabinets,
	                                           cabinet.frames_per_cabinet,
	                                           cabinet.boards_per_frame)
	cabinetised_boards = transforms.remove_gaps(cabinetised_boards)
	
	return cabinetised_boards
def cabinetised_boards(cabinet):
    from spinner import transforms
    from spinner import utils

    # Generate folded system
    hex_boards, folded_boards = utils.folded_torus(10, 8, "shear", "rows",
                                                   (2, 2))

    # Divide into cabinets
    cabinetised_boards = transforms.cabinetise(folded_boards,
                                               cabinet.num_cabinets,
                                               cabinet.frames_per_cabinet,
                                               cabinet.boards_per_frame)
    cabinetised_boards = transforms.remove_gaps(cabinetised_boards)

    return cabinetised_boards
Example #5
0
def test_assign_wires():
    # Simply check the appropriateness of each point provided in an example system.
    hex_boards, folded_boards = utils.folded_torus(4, 2, "shear", "rows",
                                                   (2, 2))
    cabinetised_boards = transforms.cabinetise(folded_boards, 1, 1, 24)
    wires = plan.enumerate_wires(cabinetised_boards)

    # Map each board to a point along a line.
    physical_boards = [(board, coordinates.Cartesian3D(float(b), 0.0, 0.0))
                       for board, (c, f, b) in cabinetised_boards]
    b2c = dict(physical_boards)

    # Given in no particular order
    available_wire_lengths = [8.0, 3.0, 24.0]

    board_wire_offset = {
        Direction.north: coordinates.Cartesian3D(0.0, 0.0, 0.0),
        Direction.south: coordinates.Cartesian3D(1.0, 0.0, 0.0),
        Direction.east: coordinates.Cartesian3D(0.0, 1.0, 0.0),
        Direction.west: coordinates.Cartesian3D(0.0, 0.0, 1.0),
        Direction.north_east: coordinates.Cartesian3D(1.0, 1.0, 1.0),
        Direction.south_west: coordinates.Cartesian3D(-1.0, -1.0, -1.0),
    }

    last_wire = None
    last_arc_height = None
    for src, dst, wire in plan.assign_wires(wires, physical_boards,
                                            board_wire_offset,
                                            available_wire_lengths, 0.0):
        # Check the wire was chosen correctly
        distance = ((b2c[src[0]] + board_wire_offset[src[1]]) -
                    (b2c[dst[0]] + board_wire_offset[dst[1]])).magnitude()
        shortest_possible_wire, arc_height = metrics.physical_wire_length(
            distance, available_wire_lengths, 0.0)
        assert wire == shortest_possible_wire

        # Make sure wires are given in ascending order of arc height unless the
        # wire length changes
        if last_wire == wire and last_arc_height is not None:
            assert arc_height >= last_arc_height
        last_arc_height = arc_height

        last_wire = wire
Example #6
0
def test_assign_wires():
	# Simply check the appropriateness of each point provided in an example system.
	hex_boards, folded_boards = utils.folded_torus(4, 2, "shear", "rows", (2,2))
	cabinetised_boards = transforms.cabinetise(folded_boards, 1, 1, 24)
	wires = plan.enumerate_wires(cabinetised_boards)
	
	# Map each board to a point along a line.
	physical_boards = [(board, coordinates.Cartesian3D(float(b), 0.0, 0.0))
	                   for board, (c, f, b) in cabinetised_boards]
	b2c = dict(physical_boards)
	
	# Given in no particular order
	available_wire_lengths = [8.0, 3.0, 24.0]
	
	board_wire_offset = {
		Direction.north: coordinates.Cartesian3D(0.0, 0.0, 0.0),
		Direction.south: coordinates.Cartesian3D(1.0, 0.0, 0.0),
		Direction.east: coordinates.Cartesian3D(0.0, 1.0, 0.0),
		Direction.west: coordinates.Cartesian3D(0.0, 0.0, 1.0),
		Direction.north_east: coordinates.Cartesian3D(1.0, 1.0, 1.0),
		Direction.south_west: coordinates.Cartesian3D(-1.0, -1.0, -1.0),
	}
	
	last_wire = None
	last_arc_height = None
	for src, dst, wire in plan.assign_wires(wires, physical_boards,
	                                        board_wire_offset,
	                                        available_wire_lengths, 0.0):
		# Check the wire was chosen correctly
		distance = ((b2c[src[0]] + board_wire_offset[src[1]]) -
		            (b2c[dst[0]] + board_wire_offset[dst[1]])).magnitude()
		shortest_possible_wire, arc_height = metrics.physical_wire_length(
			distance, available_wire_lengths, 0.0)
		assert wire == shortest_possible_wire
		
		# Make sure wires are given in ascending order of arc height unless the
		# wire length changes
		if last_wire == wire and last_arc_height is not None:
			assert arc_height >= last_arc_height
		last_arc_height = arc_height
		
		last_wire = wire
def main(args=None):
	parser = argparse.ArgumentParser(
		description="Generate visual maps from the SpiNNaker network topology to "
		            "board locations.")
	arguments.add_version_args(parser)
	arguments.add_image_args(parser)
	arguments.add_topology_args(parser)
	arguments.add_cabinet_args(parser)
	
	# Process command-line arguments
	args = parser.parse_args(args)
	(w, h), transformation, uncrinkle_direction, folds =\
		arguments.get_topology_from_args(parser, args)
	
	cabinet, num_frames = arguments.get_cabinets_from_args(parser, args)
	
	aspect_ratio = get_machine_map_aspect_ratio(w, h)
	
	output_filename, file_type, image_width, image_height =\
		arguments.get_image_from_args(parser, args, aspect_ratio)
	
	# Generate folded system
	hex_boards, folded_boards = folded_torus(w, h,
	                                         transformation,
	                                         uncrinkle_direction,
	                                         folds)
	
	# Divide into cabinets
	cabinetised_boards = transforms.cabinetise(folded_boards,
	                                           cabinet.num_cabinets,
	                                           num_frames,
	                                           cabinet.boards_per_frame)
	cabinetised_boards = transforms.remove_gaps(cabinetised_boards)
	
	# Render the image
	Context = {"png": PNGContextManager, "pdf": PDFContextManager}[file_type]
	with Context(output_filename, image_width, image_height) as ctx:
		draw_machine_map(ctx, image_width, image_height,
		                 w, h, hex_boards, cabinetised_boards)
	
	return 0
def main(args=None):
	parser = argparse.ArgumentParser(
		description="Produce CSV listings of Ethernet connected chip physical and "
		            "network positions.")
	arguments.add_version_args(parser)
	arguments.add_topology_args(parser)
	arguments.add_cabinet_args(parser)
	
	# Process command-line arguments
	args = parser.parse_args(args)
	(w, h), transformation, uncrinkle_direction, folds =\
		arguments.get_topology_from_args(parser, args)
	
	cabinet, num_frames = arguments.get_cabinets_from_args(parser, args)
	
	# Generate folded system
	hex_boards, folded_boards = folded_torus(w, h,
	                                         transformation,
	                                         uncrinkle_direction,
	                                         folds)
	
	# Divide into cabinets
	cabinetised_boards = transforms.cabinetise(folded_boards,
	                                           cabinet.num_cabinets,
	                                           num_frames,
	                                           cabinet.boards_per_frame)
	cabinetised_boards = transforms.remove_gaps(cabinetised_boards)
	
	# Generate the output
	print("cabinet,frame,board,x,y")
	b2c = dict(cabinetised_boards)
	for board, hex_coord in sorted(hex_boards, key=(lambda v: topology.to_xy(v[1]))):
		x, y = topology.to_xy(topology.board_to_chip(hex_coord))
		c, f, b = b2c[board]
		print(",".join(map(str, [c,f,b, x,y])))
	
	
	return 0
Example #9
0
def main(args=None):
    parser = argparse.ArgumentParser(
        description=
        "Produce CSV listings of Ethernet connected chip physical and "
        "network positions.")
    arguments.add_version_args(parser)
    arguments.add_topology_args(parser)
    arguments.add_cabinet_args(parser)

    # Process command-line arguments
    args = parser.parse_args(args)
    (w, h), transformation, uncrinkle_direction, folds =\
     arguments.get_topology_from_args(parser, args)

    cabinet, num_frames = arguments.get_cabinets_from_args(parser, args)

    # Generate folded system
    hex_boards, folded_boards = folded_torus(w, h, transformation,
                                             uncrinkle_direction, folds)

    # Divide into cabinets
    cabinetised_boards = transforms.cabinetise(folded_boards,
                                               cabinet.num_cabinets,
                                               num_frames,
                                               cabinet.boards_per_frame)
    cabinetised_boards = transforms.remove_gaps(cabinetised_boards)

    # Generate the output
    print("cabinet,frame,board,x,y")
    b2c = dict(cabinetised_boards)
    for board, hex_coord in sorted(hex_boards,
                                   key=(lambda v: topology.to_xy(v[1]))):
        x, y = topology.to_xy(topology.board_to_chip(hex_coord))
        c, f, b = b2c[board]
        print(",".join(map(str, [c, f, b, x, y])))

    return 0
Example #10
0
def main(args=None):
    parser = argparse.ArgumentParser(
        description=
        "Interactively guide the user through the process of wiring up a "
        "SpiNNaker machine.")
    arguments.add_version_args(parser)

    parser.add_argument("--no-tts",
                        action="store_true",
                        default=False,
                        help="disable text-to-speech announcements of wiring "
                        "steps")

    parser.add_argument("--no-auto-advance",
                        action="store_true",
                        default=False,
                        help="disable auto-advancing through wiring steps")

    parser.add_argument("--fix",
                        action="store_true",
                        default=False,
                        help="detect errors in existing wiring and just show "
                        "corrective steps")

    parser.add_argument(
        "--log",
        type=str,
        metavar="LOGFILE",
        help="record the times at which each cable is installed")

    arguments.add_topology_args(parser)
    arguments.add_cabinet_args(parser)
    arguments.add_wire_length_args(parser)
    arguments.add_bmp_args(parser)
    arguments.add_proxy_args(parser)
    arguments.add_subset_args(parser)

    # Process command-line arguments
    args = parser.parse_args(args)
    (w, h), transformation, uncrinkle_direction, folds =\
     arguments.get_topology_from_args(parser, args)

    cabinet, num_frames = arguments.get_cabinets_from_args(parser, args)

    wire_lengths, min_slack = arguments.get_wire_lengths_from_args(
        parser, args, mandatory=True)

    bmp_ips = arguments.get_bmps_from_args(parser, args, cabinet.num_cabinets,
                                           num_frames)

    proxy_host_port = arguments.get_proxy_from_args(parser, args)

    wire_filter = arguments.get_subset_from_args(parser, args)

    if cabinet.num_cabinets == num_frames == 1:
        num_boards = 3 * w * h
    else:
        num_boards = cabinet.boards_per_frame

    # Generate folded system
    hex_boards, folded_boards = folded_torus(w, h, transformation,
                                             uncrinkle_direction, folds)

    # Divide into cabinets
    cabinetised_boards = transforms.cabinetise(folded_boards,
                                               cabinet.num_cabinets,
                                               num_frames,
                                               cabinet.boards_per_frame)
    cabinetised_boards = transforms.remove_gaps(cabinetised_boards)
    physical_boards = transforms.cabinet_to_physical(cabinetised_boards,
                                                     cabinet)

    # Focus on only the boards which are part of the system
    if cabinet.num_cabinets > 1:
        focus = [slice(0, cabinet.num_cabinets)]
    elif num_frames > 1:
        focus = [0, slice(0, num_frames)]
    else:
        focus = [0, 0, slice(0, w * h * 3)]

    # Generate wiring plan
    wires_between_boards, wires_between_frames, wires_between_cabinets =\
     generate_wiring_plan(cabinetised_boards, physical_boards,
                          cabinet.board_wire_offset, wire_lengths, min_slack)
    flat_wiring_plan = flatten_wiring_plan(wires_between_boards,
                                           wires_between_frames,
                                           wires_between_cabinets,
                                           cabinet.board_wire_offset)

    # Create a BMP connection/wiring probe or connect to a proxy
    if proxy_host_port is None:
        if len(bmp_ips) == 0:
            if args.fix:
                parser.error(
                    "--fix requires that all BMPs be listed with --bmp")
            bmp_controller = None
            wiring_probe = None
        else:
            bmp_controller = BMPController(bmp_ips)

        # Create a wiring probe
        if bmp_controller is not None and (not args.no_auto_advance
                                           or args.fix):
            wiring_probe = WiringProbe(bmp_controller, cabinet.num_cabinets,
                                       num_frames, num_boards)
    else:
        # Fix is not supported since the proxy client does not recreate the
        # discover_wires method of WiringProbe.
        if args.fix:
            parser.error("--fix cannot be used with --proxy")

        # The proxy object provides a get_link_target and set_led method compatible
        # with those provided by bmp_controller and wiring_probe. Since these are
        # the only methods used, we use the proxy client object in place of
        # bmp_controller and wiring_probe.
        bmp_controller = wiring_probe = ProxyClient(*proxy_host_port)

    # Create a TimingLogger if required
    if args.log:
        if os.path.isfile(args.log):
            logfile = open(args.log, "a")
            add_header = False
        else:
            logfile = open(args.log, "w")
            add_header = True
        timing_logger = TimingLogger(logfile, add_header)
    else:
        logfile = None
        timing_logger = None

    # Convert wiring plan into cabinet coordinates
    b2c = dict(cabinetised_boards)
    wires = []
    for ((src_board, src_direction), (dst_board, dst_direction), wire_length) \
        in flat_wiring_plan:

        sc, sf, sb = b2c[src_board]
        dc, df, db = b2c[dst_board]
        wires.append(((sc, sf, sb, src_direction), (dc, df, db, dst_direction),
                      wire_length))

    # Filter wires according to user-specified rules
    wires = list(filter(wire_filter, wires))
    if len(wires) == 0:
        parser.error("--subset selects no wires")

    if not args.fix:
        # If running normally, just run through the full set of wires
        wiring_plan = wires
    else:
        # If running in fix mode, generate a list of fixes to make
        correct_wires = set((src, dst) for src, dst, length in wires)
        actual_wires = set(wiring_probe.discover_wires())

        to_remove = actual_wires - correct_wires
        to_add = correct_wires - actual_wires

        # Remove all bad wires first, then re-add good ones (note ordering now is
        # just reset to cabinets right-to-left, frames top-to-bottom and boards
        # left-to-right).
        wiring_plan = [(src, dst, None) for src, dst in sorted(to_remove)]
        for src, dst, length in wires:
            if (src, dst) in to_add:
                wiring_plan.append((src, dst, length))

        if len(wiring_plan) == 0:
            print("No corrections required.")
            return 0

    # Intialise the GUI and launch the mainloop
    ui = InteractiveWiringGuide(cabinet=cabinet,
                                wire_lengths=wire_lengths,
                                wires=wiring_plan,
                                bmp_controller=bmp_controller,
                                use_tts=not args.no_tts,
                                focus=focus,
                                wiring_probe=wiring_probe,
                                auto_advance=not args.no_auto_advance,
                                timing_logger=timing_logger)
    ui.mainloop()

    if logfile is not None:
        logfile.close()

    return 0
def main(args=None):
	parser = argparse.ArgumentParser(
		description="Generate illustrations of SpiNNaker machine wiring.")
	arguments.add_version_args(parser)
	arguments.add_image_args(parser)
	add_diagram_arguments(parser)
	arguments.add_topology_args(parser)
	arguments.add_cabinet_args(parser)
	arguments.add_subset_args(parser)
	
	# Process command-line arguments
	args = parser.parse_args(args)
	(w, h), transformation, uncrinkle_direction, folds =\
		arguments.get_topology_from_args(parser, args)
	
	cabinet, num_frames =\
		arguments.get_cabinets_from_args(parser, args)
	
	aspect_ratio, focus, wire_thickness, highlights, hide_labels =\
		get_diagram_arguments(parser, args, w, h, cabinet, num_frames)
	
	output_filename, file_type, image_width, image_height =\
		arguments.get_image_from_args(parser, args, aspect_ratio)
	
	wire_filter = arguments.get_subset_from_args(parser, args)
	
	# Generate folded system
	hex_boards, folded_boards = folded_torus(w, h,
	                                         transformation,
	                                         uncrinkle_direction,
	                                         folds)
	
	# Divide into cabinets
	cabinetised_boards = transforms.cabinetise(folded_boards,
	                                           cabinet.num_cabinets,
	                                           num_frames,
	                                           cabinet.boards_per_frame)
	cabinetised_boards = transforms.remove_gaps(cabinetised_boards)
	
	# Set up diagram
	md = MachineDiagram(cabinet)
	
	# Create lookup from cabinet coord to chip x/y to enable labelling of boards
	b2cab = dict(cabinetised_boards)
	b2chip = dict((b, topology.to_xy(topology.board_to_chip(c)))
	              for b, c in hex_boards)
	cab2chip = dict((b2cab[b], b2chip[b]) for b, c in cabinetised_boards)
	
	# Add labels
	if not hide_labels:
		for cabinet_num in range(cabinet.num_cabinets):
			md.add_label(cabinet_num, cabinet_num)
			for frame_num in range(cabinet.frames_per_cabinet):
				md.add_label(frame_num, cabinet_num, frame_num)
				for board_num in range(cabinet.boards_per_frame):
					# Only label boards which are actually part of the system
					xy = cab2chip.get((cabinet_num, frame_num, board_num), None)
					if xy is not None:
						md.add_label("{} ({},{})".format(board_num, xy.x, xy.y),
						             cabinet_num, frame_num, board_num)
						for socket in Direction:
							name = "".join(w[0] for w in socket.name.split("_")).upper()
							md.add_label(name, cabinet_num, frame_num, board_num, socket,
							             rgba=(1.0, 1.0, 1.0, 0.7))
	
	# Add highlights
	for highlight in highlights:
		md.add_highlight(*highlight, width=cabinet.board_dimensions.x/3.0)
	
	# Add wires
	wire_thickness_m = {
		"thick" : cabinet.board_dimensions.x / 5.0,
		"normal" : cabinet.board_dimensions.x / 10.0,
		"thin" : cabinet.board_dimensions.x / 20.0,
	}[wire_thickness]
	b2c = dict(cabinetised_boards)
	for direction in [Direction.north, Direction.west, Direction.north_east]:
		for b, c in cabinetised_boards:
			ob = b.follow_wire(direction)
			oc = b2c[ob]
			
			src = (c.cabinet, c.frame, c.board, direction)
			dst = (oc.cabinet, oc.frame, oc.board, direction.opposite)
			if wire_filter((src, dst)):
				md.add_wire(src, dst, width=wire_thickness_m)
	
	# Render the image
	Context = {"png": PNGContextManager,
	           "pdf": PDFContextManager}[file_type]
	with Context(output_filename, image_width, image_height) as ctx:
		md.draw(ctx, image_width, image_height, *(((list(focus) + [None]*3)[:3])*2))
	
	return 0
Example #12
0
def test_partition_wires():
    # Verify the correctness with a two-cabinet system.
    hex_boards, folded_boards = utils.folded_torus(10, 8, "shear", "rows",
                                                   (2, 2))
    cabinetised_boards = transforms.cabinetise(folded_boards, 2, 5, 24)
    all_wires = plan.enumerate_wires(cabinetised_boards)

    between_boards, between_frames, between_cabinets =\
     plan.partition_wires(all_wires, cabinetised_boards)

    # Should have the correct set of categories
    assert len(between_boards) == 5 * 2
    assert len(between_frames) == 2

    seen_wires = set()
    b2c = dict(cabinetised_boards)

    for (cabinet, frame), wires in iteritems(between_boards):
        assert 0 <= cabinet < 2
        assert 0 <= frame < 5
        for ((src_board, src_direction), (dst_board, dst_direction)) in wires:
            # Check it really does stay in the same frame
            sc, sf, sb = b2c[src_board]
            dc, df, db = b2c[dst_board]
            assert sc == cabinet
            assert dc == cabinet
            assert sf == frame
            assert df == frame
            assert (sc, sf) == (dc, df)
            assert src_direction.opposite == dst_direction

            # Check we've not seen it before
            wire = ((src_board, src_direction), (dst_board, dst_direction))
            assert wire not in seen_wires
            seen_wires.add(wire)

    for cabinet, wires in iteritems(between_frames):
        assert 0 <= cabinet < 2
        for ((src_board, src_direction), (dst_board, dst_direction)) in wires:
            # Check it really does stay in the same cabinet
            sc, sf, sb = b2c[src_board]
            dc, df, db = b2c[dst_board]
            assert sc == cabinet
            assert dc == cabinet
            assert sc == dc
            assert sf != df
            assert src_direction.opposite == dst_direction

            # Check we've not seen it before
            wire = ((src_board, src_direction), (dst_board, dst_direction))
            assert wire not in seen_wires
            seen_wires.add(wire)

    from pprint import pprint
    for ((src_board, src_direction), (dst_board,
                                      dst_direction)) in between_cabinets:
        # Check it really doesn't stay within a cabinet
        sc, sf, sb = b2c[src_board]
        dc, df, db = b2c[dst_board]
        assert sc != dc
        assert src_direction.opposite == dst_direction

        # Check we've not seen it before
        wire = ((src_board, src_direction), (dst_board, dst_direction))
        assert wire not in seen_wires
        seen_wires.add(wire)

    # Should have seen all wires too!
    assert seen_wires == set(all_wires)
Example #13
0
def test_folded_torus_bad_args():
	with pytest.raises(TypeError):
		utils.folded_torus(1, 1, "foo", "rows", (1, 1))
	with pytest.raises(TypeError):
		utils.folded_torus(1, 1, "slice", "foo", (1, 1))
Example #14
0
def main(args=None):
	parser = argparse.ArgumentParser(
		description="Print basic wiring statistics for a specified "
		            " configuration of boards.")
	arguments.add_version_args(parser)
	arguments.add_topology_args(parser)
	arguments.add_histogram_args(parser)
	arguments.add_wire_length_args(parser)
	arguments.add_cabinet_args(parser)
	
	# Process and display command-line arguments
	args = parser.parse_args(args)
	(w, h), transformation, uncrinkle_direction, folds =\
		arguments.get_topology_from_args(parser, args)
	histogram_bins = arguments.get_histogram_from_args(parser, args)
	wire_lengths, min_slack =\
		arguments.get_wire_lengths_from_args(parser, args)
	cabinet, num_frames = arguments.get_cabinets_from_args(parser, args)
	
	print(heading("Wiring Statistics", 1))
	print(heading("Folding Parameters", 2))
	print(table([["Parameter", "Value", "Unit"],
	             ["Number of boards", 3 * w * h, ""],
	             ["System dimensions", "{}x{}".format(w, h), "triads"],
	             ["Transformation", transformation, ""],
	             ["Uncrinkle Direction", uncrinkle_direction, ""],
	             ["Folds", "{}x{}".format(*folds), "pieces"],
	             ["Number of cabinets", cabinet.num_cabinets, ""],
	             ["Number of frames-per-cabinet", num_frames, ""],
	             ["Number of boards-per-frame", cabinet.boards_per_frame, ""],
	            ]))
	
	# Generate folded system and report wire-lengths after folding
	hex_boards, folded_boards = folded_torus(w, h,
	                                         transformation,
	                                         uncrinkle_direction,
	                                         folds)
	print(heading("Non-cabinetised measurements", 2))
	print(avg_wire_length_table(folded_boards, "boards"))
	
	# Divide into cabinets and report crossings
	cabinetised_boards = transforms.cabinetise(folded_boards,
	                                           cabinet.num_cabinets,
	                                           num_frames,
	                                           cabinet.boards_per_frame)
	cabinetised_boards = transforms.remove_gaps(cabinetised_boards)
	
	print(heading("Inter-cabinet/Inter-frame wiring", 2))
	print(wire_counts_table(cabinetised_boards))
	
	# Map to real, physical cabinets and measure wire lengths
	physical_boards = transforms.cabinet_to_physical(cabinetised_boards, cabinet)
	
	print(heading("Cabinetised measurements", 2))
	print("All wire lengths described in this section do not include any slack.\n")
	print(avg_wire_length_table(physical_boards, "meters",
	                            cabinet.board_wire_offset))
	
	# Generate a histogram of wire lengths
	print(heading("Wire length histogram", 2))
	print("Wire lengths are selected which include at least {} meters "
	      "of slack.\n".format(min_slack))
	print(wire_length_table(physical_boards,
	                        wire_lengths if wire_lengths else histogram_bins,
	                        min_slack,
	                        cabinet.board_wire_offset))
	
	return 0
def main(args=None):
	parser = argparse.ArgumentParser(
		description="Validate the wiring of a SpiNNaker system.")
	arguments.add_version_args(parser)
	
	parser.add_argument("--verbose", "-v", action="store_true", default=False,
	                    help="list all incorrect and missing wires")
	
	arguments.add_topology_args(parser)
	arguments.add_cabinet_args(parser)
	arguments.add_bmp_args(parser)
	
	# Process command-line arguments
	args = parser.parse_args(args)
	(w, h), transformation, uncrinkle_direction, folds =\
		arguments.get_topology_from_args(parser, args)
	
	cabinet, num_frames = arguments.get_cabinets_from_args(parser, args)
	
	bmp_ips = arguments.get_bmps_from_args(parser, args,
	                                       cabinet.num_cabinets,
	                                       num_frames)
	
	if len(bmp_ips) == 0:
		parser.error("BMP host names must be provided for every frame.")
	
	# Generate folded system
	hex_boards, folded_boards = folded_torus(w, h,
	                                         transformation,
	                                         uncrinkle_direction,
	                                         folds)
	
	# Divide into cabinets
	cabinetised_boards = transforms.cabinetise(folded_boards,
	                                           cabinet.num_cabinets,
	                                           num_frames,
	                                           cabinet.boards_per_frame)
	cabinetised_boards = transforms.remove_gaps(cabinetised_boards)
	
	# Generate list of wires
	wires = plan.enumerate_wires(cabinetised_boards)
	
	# Set up the wiring probe
	bmp_controller = BMPController(bmp_ips)
	if cabinet.num_cabinets == 1 and num_frames == 1:
		num_boards = 3 * w * h
	else:
		num_boards = cabinet.boards_per_frame
	wiring_probe = probe.WiringProbe(bmp_controller,
	                                 cabinet.num_cabinets,
	                                 num_frames,
	                                 num_boards)
	
	
	# Check for the presence of every wire
	missing = []
	b2c = dict(cabinetised_boards)
	for ((src_board, src_direction), (dst_board, dst_direction)) in wires:
		src = tuple(list(b2c[src_board]) + [src_direction])
		dst = tuple(list(b2c[dst_board]) + [dst_direction])
		actual_dst = wiring_probe.get_link_target(*src)
		actual_src = wiring_probe.get_link_target(*dst)
		
		if actual_dst != dst or actual_src != src:
			missing.append((src, dst))
	
	if missing:
		sys.stderr.write("{} wires missing or erroneously connected.\n".format(
			len(missing), len(wires)))
		
		if args.verbose:
			for src, dst in missing:
				print("C:{} F:{} B:{} {} <--> C:{} F:{} B:{} {}".format(
					src[0], src[1], src[2], src[3].name.replace("_", " "),
					dst[0], dst[1], dst[2], dst[3].name.replace("_", " ")))
		else:
			print("Add --verbose for a complete list.")
		
		return -1
	else:
		sys.stderr.write("All {} wires correctly connected.\n".format(len(wires)))
		return 0
Example #16
0
def test_folded_torus_bad_args():
    with pytest.raises(TypeError):
        utils.folded_torus(1, 1, "foo", "rows", (1, 1))
    with pytest.raises(TypeError):
        utils.folded_torus(1, 1, "slice", "foo", (1, 1))
Example #17
0
def main(args=None):
    parser = argparse.ArgumentParser(
        description=
        "Textually enumerate every connection required in a machine.")

    parser.add_argument("--sort-by",
                        "-s",
                        choices=["installation-order", "board", "wire-length"],
                        default="board",
                        help="Specifies the order the connections should be "
                        "listed in the file: installation-order sorts in "
                        "the most sensible order for installation, "
                        "board lists wires on a board-by-board basis, "
                        "wire-length lists in order of wire length.")

    arguments.add_version_args(parser)

    arguments.add_topology_args(parser)
    arguments.add_cabinet_args(parser)
    arguments.add_wire_length_args(parser)

    # Process command-line arguments
    args = parser.parse_args(args)
    (w, h), transformation, uncrinkle_direction, folds =\
     arguments.get_topology_from_args(parser, args)

    cabinet, num_frames = arguments.get_cabinets_from_args(parser, args)

    wire_lengths, min_slack = arguments.get_wire_lengths_from_args(
        parser, args, mandatory=True)

    # Generate folded system
    hex_boards, folded_boards = folded_torus(w, h, transformation,
                                             uncrinkle_direction, folds)

    # Divide into cabinets
    cabinetised_boards = transforms.cabinetise(folded_boards,
                                               cabinet.num_cabinets,
                                               num_frames,
                                               cabinet.boards_per_frame)
    cabinetised_boards = transforms.remove_gaps(cabinetised_boards)
    physical_boards = transforms.cabinet_to_physical(cabinetised_boards,
                                                     cabinet)

    # Generate wiring plan
    wires_between_boards, wires_between_frames, wires_between_cabinets =\
     generate_wiring_plan(cabinetised_boards, physical_boards,
                          cabinet.board_wire_offset, wire_lengths, min_slack)
    flat_wiring_plan = flatten_wiring_plan(wires_between_boards,
                                           wires_between_frames,
                                           wires_between_cabinets,
                                           cabinet.board_wire_offset)

    # Convert wiring plan into cabinet coordinates
    b2c = dict(cabinetised_boards)
    wires = []
    for ((src_board, src_direction), (dst_board, dst_direction), wire_length) \
        in flat_wiring_plan:

        sc, sf, sb = b2c[src_board]
        dc, df, db = b2c[dst_board]
        wires.append(((sc, sf, sb, src_direction), (dc, df, db, dst_direction),
                      wire_length, src_board, dst_board))

    b2p = dict(physical_boards)

    # Order as requested on the command-line
    if args.sort_by == "board":
        wires = sorted(wires)
    elif args.sort_by == "wire-length":
        wires = sorted(wires, key=(lambda w: (w[2], w[:2])))
    elif args.sort_by == "installation-order":  # pragma: no branch
        pass  # List is initially in assembly order

    print("C  F  B  Socket      C  F  B  Socket      Length")
    print("-- -- -- ----------  -- -- -- ----------  ------")
    for ((sc, sf, sb, src_direction), (dc, df, db, dst_direction), wire_length,
         src_board, dst_board) in wires:
        print("{:2d} {:2d} {:2d} {:10s}  {:2d} {:2d} {:2d} {:10s}  {:0.2f}".
              format(sc, sf, sb, src_direction.name.replace("_", " "), dc, df,
                     db, dst_direction.name.replace("_", " "), wire_length))

    return 0
Example #18
0
def test_generate_wiring_plan():
    # Since generate_wiring_plan is largely a wrapper around the functions tested
    # above, this simply tests that the output is not insane...
    hex_boards, folded_boards = utils.folded_torus(10, 8, "shear", "rows",
                                                   (2, 2))
    cabinetised_boards = transforms.cabinetise(folded_boards, 2, 5, 24)
    cab = cabinet.Cabinet(**real)
    physical_boards = transforms.cabinet_to_physical(cabinetised_boards, cab)
    all_wires = plan.enumerate_wires(cabinetised_boards)
    available_wire_lengths = [0.3, 0.5, 1.0]

    b2c = dict(cabinetised_boards)

    between_boards, between_frames, between_cabinets =\
     plan.generate_wiring_plan(cabinetised_boards, physical_boards,
                               cab.board_wire_offset,
                               available_wire_lengths,
                               0.0)

    seen_wires = set()

    assert set(between_boards) == set(
        (c, f, d) for c in range(cab.num_cabinets)
        for f in range(cab.frames_per_cabinet)
        for d in [Direction.north, Direction.south_west, Direction.east])
    for (cabinet_num, frame_num,
         direction), wires in iteritems(between_boards):
        for ((src_board, src_direction), (dst_board, dst_direction),
             wire_length) in wires:
            # The board does stay in the frame_num and goes in the specified direction
            c, f, b = b2c[src_board]
            assert c == cabinet_num
            assert f == frame_num
            assert src_direction == direction

            c, f, b = b2c[dst_board]
            assert c == cabinet_num
            assert f == frame_num
            assert dst_direction == direction.opposite

            # The wire length chosen should exist
            assert wire_length in available_wire_lengths

            # Check we've not seen it before
            wire = ((src_board, src_direction), (dst_board, dst_direction))
            assert wire not in seen_wires
            seen_wires.add(wire)

    assert set(between_frames) == set(
        (c, d) for c in range(cab.num_cabinets)
        for d in [Direction.north, Direction.south_west, Direction.east])
    for (cabinet_num, direction), wires in iteritems(between_frames):
        for ((src_board, src_direction), (dst_board, dst_direction),
             wire_length) in wires:
            # The board does stay in the cabinet and goes in the specified direction
            c, f, b = b2c[src_board]
            assert c == cabinet_num
            assert src_direction == direction

            c, f, b = b2c[dst_board]
            assert c == cabinet_num
            assert dst_direction == direction.opposite

            assert wire_length in available_wire_lengths

            # Check we've not seen it before
            wire = ((src_board, src_direction), (dst_board, dst_direction))
            assert wire not in seen_wires
            seen_wires.add(wire)

    assert set(between_cabinets) == set(
        [Direction.north, Direction.south_west, Direction.east])
    for direction, wires in iteritems(between_cabinets):
        for ((src_board, src_direction), (dst_board, dst_direction),
             wire_length) in wires:
            # The board does stay in the cabinet and goes in the specified direction
            assert src_direction == direction
            assert dst_direction == direction.opposite

            assert wire_length in available_wire_lengths

            # Check we've not seen it before
            wire = ((src_board, src_direction), (dst_board, dst_direction))
            assert wire not in seen_wires
            seen_wires.add(wire)

    # All wires should have been seen
    assert seen_wires == set(all_wires)
def main(args=None):
	parser = argparse.ArgumentParser(
		description="Interactively guide the user through the process of wiring up a "
		            "SpiNNaker machine.")
	arguments.add_version_args(parser)
	
	parser.add_argument("--no-tts", action="store_true", default=False,
	                    help="disable text-to-speech announcements of wiring "
	                         "steps")
	
	parser.add_argument("--no-auto-advance", action="store_true", default=False,
	                    help="disable auto-advancing through wiring steps")
	
	parser.add_argument("--fix", action="store_true", default=False,
	                    help="detect errors in existing wiring and just show "
	                         "corrective steps")
	
	parser.add_argument("--log", type=str, metavar="LOGFILE",
	                    help="record the times at which each cable is installed")
	
	arguments.add_topology_args(parser)
	arguments.add_cabinet_args(parser)
	arguments.add_wire_length_args(parser)
	arguments.add_bmp_args(parser)
	arguments.add_proxy_args(parser)
	arguments.add_subset_args(parser)
	
	# Process command-line arguments
	args = parser.parse_args(args)
	(w, h), transformation, uncrinkle_direction, folds =\
		arguments.get_topology_from_args(parser, args)
	
	cabinet, num_frames = arguments.get_cabinets_from_args(parser, args)
	
	wire_lengths, min_slack = arguments.get_wire_lengths_from_args(
		parser, args, mandatory=True)
	
	bmp_ips = arguments.get_bmps_from_args(parser, args,
	                                       cabinet.num_cabinets,
	                                       num_frames)
	
	proxy_host_port = arguments.get_proxy_from_args(parser, args)
	
	wire_filter = arguments.get_subset_from_args(parser, args)
	
	if cabinet.num_cabinets == num_frames == 1:
		num_boards = 3 * w * h
	else:
		num_boards = cabinet.boards_per_frame
	
	# Generate folded system
	hex_boards, folded_boards = folded_torus(w, h,
	                                         transformation,
	                                         uncrinkle_direction,
	                                         folds)
	
	# Divide into cabinets
	cabinetised_boards = transforms.cabinetise(folded_boards,
	                                           cabinet.num_cabinets,
	                                           num_frames,
	                                           cabinet.boards_per_frame)
	cabinetised_boards = transforms.remove_gaps(cabinetised_boards)
	physical_boards = transforms.cabinet_to_physical(cabinetised_boards, cabinet)
	
	# Focus on only the boards which are part of the system
	if cabinet.num_cabinets > 1:
		focus = [slice(0, cabinet.num_cabinets)]
	elif num_frames > 1:
		focus = [0, slice(0, num_frames)]
	else:
		focus = [0, 0, slice(0, w*h*3)]
	
	
	# Generate wiring plan
	wires_between_boards, wires_between_frames, wires_between_cabinets =\
		generate_wiring_plan(cabinetised_boards, physical_boards,
		                     cabinet.board_wire_offset, wire_lengths, min_slack)
	flat_wiring_plan = flatten_wiring_plan(wires_between_boards,
	                                       wires_between_frames,
	                                       wires_between_cabinets,
	                                       cabinet.board_wire_offset)
	
	# Create a BMP connection/wiring probe or connect to a proxy
	if proxy_host_port is None:
		if len(bmp_ips) == 0:
			if args.fix:
				parser.error("--fix requires that all BMPs be listed with --bmp")
			bmp_controller = None
			wiring_probe = None
		else:
			bmp_controller = BMPController(bmp_ips)
		
		# Create a wiring probe
		if bmp_controller is not None and (not args.no_auto_advance or args.fix):
			wiring_probe = WiringProbe(bmp_controller,
			                           cabinet.num_cabinets,
			                           num_frames,
			                           num_boards)
	else:
		# Fix is not supported since the proxy client does not recreate the
		# discover_wires method of WiringProbe.
		if args.fix:
			parser.error("--fix cannot be used with --proxy")
		
		# The proxy object provides a get_link_target and set_led method compatible
		# with those provided by bmp_controller and wiring_probe. Since these are
		# the only methods used, we use the proxy client object in place of
		# bmp_controller and wiring_probe.
		bmp_controller = wiring_probe = ProxyClient(*proxy_host_port)
	
	# Create a TimingLogger if required
	if args.log:
		if os.path.isfile(args.log):
			logfile = open(args.log, "a")
			add_header = False
		else:
			logfile = open(args.log, "w")
			add_header = True
		timing_logger = TimingLogger(logfile, add_header)
	else:
		logfile = None
		timing_logger = None
	
	# Convert wiring plan into cabinet coordinates
	b2c = dict(cabinetised_boards)
	wires = []
	for ((src_board, src_direction), (dst_board, dst_direction), wire_length) \
	    in flat_wiring_plan:
		
		sc, sf, sb = b2c[src_board]
		dc, df, db = b2c[dst_board]
		wires.append(((sc, sf, sb, src_direction),
		              (dc, df, db, dst_direction),
		              wire_length))
	
	# Filter wires according to user-specified rules
	wires = list(filter(wire_filter, wires))
	if len(wires) == 0:
		parser.error("--subset selects no wires")
	
	if not args.fix:
		# If running normally, just run through the full set of wires
		wiring_plan = wires
	else:
		# If running in fix mode, generate a list of fixes to make
		correct_wires = set((src, dst) for src, dst, length in wires)
		actual_wires = set(wiring_probe.discover_wires())
		
		to_remove = actual_wires - correct_wires
		to_add = correct_wires - actual_wires
		
		# Remove all bad wires first, then re-add good ones (note ordering now is
		# just reset to cabinets right-to-left, frames top-to-bottom and boards
		# left-to-right).
		wiring_plan = [(src, dst, None) for src, dst in sorted(to_remove)]
		for src, dst, length in wires:
			if (src, dst) in to_add:
				wiring_plan.append((src, dst, length))
		
		if len(wiring_plan) == 0:
			print("No corrections required.")
			return 0

	
	# Intialise the GUI and launch the mainloop
	ui = InteractiveWiringGuide(cabinet=cabinet,
	                            wire_lengths=wire_lengths,
	                            wires=wiring_plan,
	                            bmp_controller=bmp_controller,
	                            use_tts=not args.no_tts,
	                            focus=focus,
	                            wiring_probe=wiring_probe,
	                            auto_advance=not args.no_auto_advance,
	                            timing_logger=timing_logger)
	ui.mainloop()
	
	if logfile is not None:
		logfile.close()
	
	return 0
Example #20
0
def test_partition_wires():
	# Verify the correctness with a two-cabinet system.
	hex_boards, folded_boards = utils.folded_torus(10, 8, "shear", "rows", (2,2))
	cabinetised_boards = transforms.cabinetise(folded_boards, 2, 5, 24)
	all_wires = plan.enumerate_wires(cabinetised_boards)
	
	between_boards, between_frames, between_cabinets =\
		plan.partition_wires(all_wires, cabinetised_boards)
	
	# Should have the correct set of categories
	assert len(between_boards) == 5 * 2
	assert len(between_frames) == 2
	
	seen_wires = set()
	b2c = dict(cabinetised_boards)
	
	for (cabinet, frame), wires in iteritems(between_boards):
		assert 0 <= cabinet < 2
		assert 0 <= frame < 5
		for ((src_board, src_direction), (dst_board, dst_direction)) in wires:
			# Check it really does stay in the same frame
			sc, sf, sb = b2c[src_board]
			dc, df, db = b2c[dst_board]
			assert sc == cabinet
			assert dc == cabinet
			assert sf == frame
			assert df == frame
			assert (sc, sf) == (dc, df)
			assert src_direction.opposite == dst_direction
			
			# Check we've not seen it before
			wire = ((src_board, src_direction), (dst_board, dst_direction))
			assert wire not in seen_wires
			seen_wires.add(wire)
	
	for cabinet, wires in iteritems(between_frames):
		assert 0 <= cabinet < 2
		for ((src_board, src_direction), (dst_board, dst_direction)) in wires:
			# Check it really does stay in the same cabinet
			sc, sf, sb = b2c[src_board]
			dc, df, db = b2c[dst_board]
			assert sc == cabinet
			assert dc == cabinet
			assert sc == dc
			assert sf != df
			assert src_direction.opposite == dst_direction
			
			# Check we've not seen it before
			wire = ((src_board, src_direction), (dst_board, dst_direction))
			assert wire not in seen_wires
			seen_wires.add(wire)
	
	from pprint import pprint
	for ((src_board, src_direction), (dst_board, dst_direction)) in between_cabinets:
		# Check it really doesn't stay within a cabinet
		sc, sf, sb = b2c[src_board]
		dc, df, db = b2c[dst_board]
		assert sc != dc
		assert src_direction.opposite == dst_direction
		
		# Check we've not seen it before
		wire = ((src_board, src_direction), (dst_board, dst_direction))
		assert wire not in seen_wires
		seen_wires.add(wire)
	
	# Should have seen all wires too!
	assert seen_wires == set(all_wires)
Example #21
0
def test_generate_wiring_plan():
	# Since generate_wiring_plan is largely a wrapper around the functions tested
	# above, this simply tests that the output is not insane...
	hex_boards, folded_boards = utils.folded_torus(10, 8, "shear", "rows", (2,2))
	cabinetised_boards = transforms.cabinetise(folded_boards, 2, 5, 24)
	cab = cabinet.Cabinet(**real)
	physical_boards = transforms.cabinet_to_physical(cabinetised_boards, cab)
	all_wires = plan.enumerate_wires(cabinetised_boards)
	available_wire_lengths = [0.3, 0.5, 1.0]
	
	b2c = dict(cabinetised_boards)
	
	between_boards, between_frames, between_cabinets =\
		plan.generate_wiring_plan(cabinetised_boards, physical_boards,
		                          cab.board_wire_offset,
		                          available_wire_lengths,
		                          0.0)
	
	seen_wires = set()
	
	assert set(between_boards) == set((c, f, d)
	                                  for c in range(cab.num_cabinets)
	                                  for f in range(cab.frames_per_cabinet)
	                                  for d in [Direction.north,
	                                            Direction.south_west,
	                                            Direction.east])
	for (cabinet_num, frame_num, direction), wires in iteritems(between_boards):
		for ((src_board, src_direction), (dst_board, dst_direction),
		     wire_length) in wires:
			# The board does stay in the frame_num and goes in the specified direction
			c, f, b = b2c[src_board]
			assert c == cabinet_num
			assert f == frame_num
			assert src_direction == direction
			
			c, f, b = b2c[dst_board]
			assert c == cabinet_num
			assert f == frame_num
			assert dst_direction == direction.opposite
			
			# The wire length chosen should exist
			assert wire_length in available_wire_lengths
			
			# Check we've not seen it before
			wire = ((src_board, src_direction), (dst_board, dst_direction))
			assert wire not in seen_wires
			seen_wires.add(wire)
	
	assert set(between_frames) == set((c, d)
	                                  for c in range(cab.num_cabinets)
	                                  for d in [Direction.north,
	                                            Direction.south_west,
	                                            Direction.east])
	for (cabinet_num, direction), wires in iteritems(between_frames):
		for ((src_board, src_direction), (dst_board, dst_direction),
		     wire_length) in wires:
			# The board does stay in the cabinet and goes in the specified direction
			c, f, b = b2c[src_board]
			assert c == cabinet_num
			assert src_direction == direction
			
			c, f, b = b2c[dst_board]
			assert c == cabinet_num
			assert dst_direction == direction.opposite
			
			assert wire_length in available_wire_lengths
			
			# Check we've not seen it before
			wire = ((src_board, src_direction), (dst_board, dst_direction))
			assert wire not in seen_wires
			seen_wires.add(wire)
	
	assert set(between_cabinets) == set([Direction.north,
	                                     Direction.south_west,
	                                     Direction.east])
	for direction, wires in iteritems(between_cabinets):
		for ((src_board, src_direction), (dst_board, dst_direction),
		     wire_length) in wires:
			# The board does stay in the cabinet and goes in the specified direction
			assert src_direction == direction
			assert dst_direction == direction.opposite
			
			assert wire_length in available_wire_lengths
			
			# Check we've not seen it before
			wire = ((src_board, src_direction), (dst_board, dst_direction))
			assert wire not in seen_wires
			seen_wires.add(wire)
	
	# All wires should have been seen
	assert seen_wires == set(all_wires)