/// \brief Return the second dimensions size of a test matrix
			///
			/// \pre Matrix cannot be empty (ie first dimension size must be > 0) else an invalid_argument_exception will be thrown
			///
			/// \pre Matrix must have a consistent size of the second dimension else an invalid_argument_exception will be thrown
			///
			/// \returns The size of the second dimension
			static size_t get_second_dimension_size(const bool_deq_vec &arg_test_matrix ///< The test matrix to query
			                                              ) {
				if (arg_test_matrix.empty()) {
					BOOST_THROW_EXCEPTION(invalid_argument_exception("Cannot get second dimension size for empty test matrix"));
				}
				const bool_deq::size_type second_dimension_size = arg_test_matrix.front().size();
				for (const bool_deq &entry : arg_test_matrix) {
					if (second_dimension_size != entry.size()) {
						BOOST_THROW_EXCEPTION(invalid_argument_exception("Test matrix does not have a consistent second dimension size"));
					}
				}
				return second_dimension_size;
			}
			/// \brief Check that get_window_start_a_for_b() and get_window_stop_a_for_b() recreate the values in the matrix for the specified window size
			void check_windowed_matrix(const bool_deq_vec &arg_test_matrix, ///< The test matrix to check
			                           const size_t       &arg_window_size  ///< The window size to use
			                           ) const {
				const size_t first_dimension_size  = arg_test_matrix.size();
				const size_t second_dimension_size = get_second_dimension_size(arg_test_matrix);

				for (size_t entry_ctr = 0; entry_ctr < first_dimension_size; ++entry_ctr) {
					const bool_deq       &entry            = arg_test_matrix[entry_ctr];
					const size_size_pair  first_and_last   = get_indices_of_first_and_last_trues(entry);
					const size_t         &first_true_index = first_and_last.first;
					const size_t         &last_true_index  = first_and_last.second;

					BOOST_CHECK_EQUAL(
						first_true_index + 1,
						get_window_start_a_for_b__offset_1(
							second_dimension_size,
							first_dimension_size,
							arg_window_size,
							entry_ctr + 1
						)
					);
					BOOST_CHECK_EQUAL(
						last_true_index + 1,
						get_window_stop_a_for_b__offset_1(
							second_dimension_size,
							first_dimension_size,
							arg_window_size,
							entry_ctr + 1
						)
					);
					if (first_true_index > 0 && last_true_index + 1 < second_dimension_size) {
						if (first_dimension_size != second_dimension_size) {
							BOOST_CHECK_EQUAL(
								arg_window_size,
								last_true_index - first_true_index + 1
							);
						}
					}
				}
			}
			/// \brief Checks that residue_name_aligner::residue_name_align() does the correct thing for all permutations of the residue lists.
			///
			/// This should be accessed via check_residue_name_aligner_results() or check_residue_name_aligner_throws()
			///
			/// This subroutine is mostly ready to handle more than two lists.
			///
			/// \todo modify the actual call to residue_name_aligner::residue_name_align() to handle multiple lists
			///       (after that subroutine has been altered to handle multiple lists)
			void do_check_residue_name_aligner(const residue_name_vec_vec  &arg_residue_lists,
			                                   const bool_deq_vec          &arg_correct_presence_lists,
			                                   const size_vec_vec          &arg_correct_answer_lists,
			                                   const bool                  &arg_should_throw
			                                   ) {
				const size_t num_lists = arg_residue_lists.size();
				BOOST_REQUIRE_EQUAL(num_lists, 2_z); /// This code isn't yet able to process more than two at a time
				if (!arg_should_throw) {
					BOOST_REQUIRE_EQUAL(num_lists, arg_correct_presence_lists.size());
					BOOST_REQUIRE_EQUAL(num_lists, arg_correct_answer_lists.size());
				}

				// Construct a vector containing the indices of the lists
				size_vec permutation_indices(num_lists, 0);
				for (size_t index_ctr = 0; index_ctr < num_lists; ++index_ctr) {
					permutation_indices[index_ctr] = index_ctr;
				}

				// Loop over the permutations of the indices
				do {
					// If these residue lists should cause residue_name_aligner::residue_name_align() to throw then check they do
					if (arg_should_throw) {
						BOOST_CHECK_THROW(
							residue_name_aligner::residue_name_align(
								{ arg_residue_lists[ permutation_indices[ 0 ] ],
								  arg_residue_lists[ permutation_indices[ 1 ] ] }
							),
							invalid_argument_exception
						);
					}
					// Otherwise check the results from residue_name_aligner::residue_name_align()
					else {
						// Construct an alignment from this permutation of residue lists
						const alignment my_alignment = residue_name_aligner::residue_name_align(
							{ arg_residue_lists[permutation_indices[ 0 ]],
							  arg_residue_lists[permutation_indices[ 1 ]] }
						);
						const alignment::size_type num_positions = my_alignment.length();

						// Check each of the alignment entries in turn
						for (size_t index_ctr = 0; index_ctr < num_lists; ++index_ctr) {
							// Grab the correct answer list under the current permutation
							const size_t permutation_index           = permutation_indices[index_ctr];
							const bool_deq &correct_presence_list = arg_correct_presence_lists[permutation_index];
							const size_vec &correct_answer_list      = arg_correct_answer_lists[permutation_index];

							const size_t correct_answer_size         = correct_answer_list.size();

							// Check that the number of positions match
							BOOST_CHECK_EQUAL(correct_answer_size, num_positions);

							// Check that each of the positions in the alignment match what is expected
							for (size_t position_ctr  = 0; position_ctr < min(correct_answer_size, num_positions); ++position_ctr) {
								const aln_posn_opt position     = my_alignment.position_of_entry_of_index( index_ctr, position_ctr );
								const bool         has_position = static_cast<bool>( position );
								BOOST_CHECK_EQUAL( correct_presence_list[position_ctr], has_position );

								if ( position ) {
									BOOST_CHECK_EQUAL(correct_answer_list[position_ctr], *position );
								}
							}
						}
					}
				} while ( next_permutation( permutation_indices ) );
			}