Repository: vgteam/libbdsg (language: python)

Issue:
Distance index
Update the distance index to be more efficient. This changes the format of the index so distance indexes (version 2) will have to be rebuilt
This only affects the distance index

Add some error checking to serialization/deserialization
This adds some error checking to the serialization and deserialization functions that the new distance index ends up using. This would have let us catch the failed writes that were causing the output to be truncated in some cases.


Discussion / hints:

Fix patch:
diff --git a/bdsg/.readthedocs.yml b/.readthedocs.yml
similarity index 82%
rename from bdsg/.readthedocs.yml
rename to .readthedocs.yml
index a017f72a..15f8abdc 100644
--- a/bdsg/.readthedocs.yml
+++ b/.readthedocs.yml
@@ -14,3 +14,11 @@ python:
   version: 3.7
   install:
     - requirements: bdsg/docs/requirements.txt
+
+build:
+  apt_packages:
+    - libjansson-dev
+
+submodules:
+  include: all
+  recursive: true
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2c5f6b24..c08a8825 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,6 +2,8 @@
 cmake_minimum_required(VERSION 3.10)
 # We can't use CMake 3.11 until we no longer have to run on Ubuntu 18.04.
 
+include(FindPkgConfig)
+
 # Make MACOSX_RPATH on explicitly, so non-installed libraries use @rpath in install name
 set(CMAKE_MACOSX_RPATH ON)
 
@@ -35,6 +37,7 @@ endif ()
 set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g")
 set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g")
 
+# Find OMP system depenency and configure for OS
 if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
 
   # assumes clang build
@@ -80,6 +83,19 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
   set (OMP_INCLUDE_FLAGS "-I${OMP_INCLUDE_PATH}")
   set (OMP_LIB_FLAGS "-L${OMP_LIB_PATH}")
   
+  # We also need manual libdl for some reason, so find it properly
+  find_path(DL_LIB_PATH libdl.dylib
+            PATHS "${HOMEBREW_PREFIX}/lib" /opt/local/lib /usr/local/lib /usr/lib /lib
+            REQUIRED)
+  if ("${DL_LIB_PATH}" STREQUAL "")
+    # REQUIRED is a new CMake feature
+    message(FATAL_ERROR "Could not find libdl.dylib")
+  else()
+    message("Found libdl libraries in ${DL_LIB_PATH}")
+  endif()
+  
+  set (DL_LIB_FLAGS "-L${DL_LIB_PATH}")
+  
   set (OpenMP_C "${CMAKE_C_COMPILER}")
   set (OpenMP_C_FLAGS " -Xpreprocessor -fopenmp ${OMP_INCLUDE_FLAGS} ${OMP_LIB_FLAGS}")
   set (OpenMP_C_LIB_NAMES "libomp" "libgomp" "libiomp5")
@@ -97,7 +113,7 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
   
   # Mac needs libdl and libomp when linking the library and a hint on where to look for them
   # Mac doesn't have $ORIGIN for RPaths. We might not be able to produce a working Mac wheel for Python bindings.
-  set(PLATFORM_EXTRA_LIB_FLAGS -ldl -lomp -L/opt/local/lib/libomp -L/usr/local/lib)
+  set(PLATFORM_EXTRA_LIB_FLAGS -ldl -lomp ${DL_LIB_FLAGS} ${OMP_LIB_FLAGS})
   
   # Mac needs install names set after installation
   SET(CMAKE_INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
@@ -117,6 +133,9 @@ elseif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
   
 endif()
 
+# Find other system dependencies
+pkg_check_modules(Jansson REQUIRED IMPORTED_TARGET jansson)
+
 # Find our bdsg package directory where input sources and dependencies are
 set(bdsg_DIR "${CMAKE_CURRENT_SOURCE_DIR}/bdsg")
 
@@ -268,6 +287,7 @@ add_library(bdsg_objs OBJECT
   ${bdsg_DIR}/src/snarl_distance_index.cpp
   )
 
+# Add includes for ourselves
 set(bdsg_INCLUDES
   "${bdsg_DIR}/include"
 )
@@ -281,7 +301,8 @@ set(bdsg_TARGET_DEPS
   handlegraph_shared
   bbhash
   sparsepp
-  mio::mio)
+  mio::mio
+  PkgConfig::Jansson)
 
 set(bdsg_LIBS
   ${bdsg_TARGET_DEPS}
diff --git a/Makefile b/Makefile
index 33322b71..a0f5cc5b 100644
--- a/Makefile
+++ b/Makefile
@@ -9,7 +9,7 @@ INSTALL_PREFIX?=/usr/local
 INSTALL_LIB_DIR=$(INSTALL_PREFIX)/lib
 INSTALL_INC_DIR=$(INSTALL_PREFIX)/include
 
-LIB_FLAGS:=-lbdsg -lsdsl -lhandlegraph -lomp
+LIB_FLAGS:=-lbdsg -lsdsl -lhandlegraph
 
 OBJS = $(OBJ_DIR)/eades_algorithm.o 
 OBJS += $(OBJ_DIR)/hash_graph.o 
@@ -33,6 +33,7 @@ CXXFLAGS :=-MMD -MP -O3 -Werror=return-type -std=c++14 -ggdb -g -I$(INC_DIR) $(C
 
 ifeq ($(shell uname -s),Darwin)
 	CXXFLAGS := $(CXXFLAGS) -Xpreprocessor -fopenmp
+	LIB_FLAGS := $(LIB_FLAGS) -lomp
 else
 	CXXFLAGS := $(CXXFLAGS) -fopenmp
 endif
@@ -50,7 +51,7 @@ docs:
 .pre-build:
 	@if [ ! -d $(LIB_DIR) ]; then mkdir -p $(LIB_DIR); fi
 	@if [ ! -d $(OBJ_DIR) ]; then mkdir -p $(OBJ_DIR); fi
-	@if [ ! -d $(BIN_DIR) ]; then mkdir -p $(BIN_DIR); fiq
+	@if [ ! -d $(BIN_DIR) ]; then mkdir -p $(BIN_DIR); fi
 
 # run .pre-build before we make anything at all.
 -include .pre-build
diff --git a/README.md b/README.md
index 4f43aa48..164e8e9e 100644
--- a/README.md
+++ b/README.md
@@ -72,7 +72,7 @@ The documentation for `libbdsg` is built using Sphinx, and will invoke the CMake
 # Install Sphinx
 virtualenv --python python3 venv
 . venv/bin/activate
-pip3 install -r docs/requirements.txt
+pip3 install -r bdsg/docs/requirements.txt
 
 # Build the documentation
 make docs
@@ -91,6 +91,7 @@ The documentation can then be found at `docs/_build/html/index.html`.
 - [`sparsepp`](https://github.com/greg7mdp/sparsepp)
 - [`DYNAMIC`](https://github.com/xxsds/DYNAMIC)
 - [`BBHash/alltypes`](https://github.com/rizkg/BBHash/tree/alltypes) 
+- [`jansson`](https://github.com/akheron/jansson)
 
 The build process with `make` assumes that these libraries and their headers have been installed in a place on the system where the compiler can find them (e.g. in `CPLUS_INCLUDE_PATH`).
 
diff --git a/bdsg/cmake_bindings/bdsg/snarl_distance_index.cpp b/bdsg/cmake_bindings/bdsg/snarl_distance_index.cpp
index 71d9fb70..456f0abe 100644
--- a/bdsg/cmake_bindings/bdsg/snarl_distance_index.cpp
+++ b/bdsg/cmake_bindings/bdsg/snarl_distance_index.cpp
@@ -33,7 +33,7 @@
 	PYBIND11_MAKE_OPAQUE(std::shared_ptr<void>);
 #endif
 
-// bdsg::SnarlDistanceIndex file:bdsg/snarl_distance_index.hpp line:99
+// bdsg::SnarlDistanceIndex file:bdsg/snarl_distance_index.hpp line:156
 struct PyCallBack_bdsg_SnarlDistanceIndex : public bdsg::SnarlDistanceIndex {
 	using bdsg::SnarlDistanceIndex::SnarlDistanceIndex;
 
@@ -405,12 +405,12 @@ struct PyCallBack_bdsg_SnarlDistanceIndex : public bdsg::SnarlDistanceIndex {
 
 void bind_bdsg_snarl_distance_index(std::function< pybind11::module &(std::string const &namespace_) > &M)
 {
-	{ // bdsg::SnarlDistanceIndex file:bdsg/snarl_distance_index.hpp line:99
-		pybind11::class_<bdsg::SnarlDistanceIndex, std::shared_ptr<bdsg::SnarlDistanceIndex>, PyCallBack_bdsg_SnarlDistanceIndex, handlegraph::SnarlDecomposition, handlegraph::TriviallySerializable> cl(M("bdsg"), "SnarlDistanceIndex", "The distance index. Stores minimum distances among nodes in each \n snarl's netgraph and each chain.\n Also used to store the snarl tree");
-		{ // bdsg::SnarlDistanceIndex::TemporaryDistanceIndex file:bdsg/snarl_distance_index.hpp line:1610
+	{ // bdsg::SnarlDistanceIndex file:bdsg/snarl_distance_index.hpp line:156
+		pybind11::class_<bdsg::SnarlDistanceIndex, std::shared_ptr<bdsg::SnarlDistanceIndex>, PyCallBack_bdsg_SnarlDistanceIndex, handlegraph::SnarlDecomposition, handlegraph::TriviallySerializable> cl(M("bdsg"), "SnarlDistanceIndex", "This defines the distance index, which also serves as a snarl tree that implements libhandlegraph's \n SnarlDecomposition interface\n\n The distance index is used to find the minimum distance between two positions on the graph\n The structure of the distance index is based on the snarl tree. \n Variation graphs can be decomposed into nested substructures called \"snarls\" and \"chains, and the \n decomposition is described by the snarl tree\n The distance index provides an interface to traverse the snarl tree and to find minimum distances\n between two sibling nodes in the snarl tree (eg between two chains that are children of the same snarl)\n The distance index can also be built without distances and used just to traverse the snarl tree\n\n A chain is comprised of at least one node and may also contain snarls. \n Each snarl is comprised of child chains and is bounded by two boundary nodes. \n The boundary nodes are not part of the snarl, but are represented in the snarl as sentinels\n Trivial snarls (with only one edge between the boundary nodes) are not represented, but a snarl may \n have no nodes if it has other edges\n\n The root of a snarl tree is contains child chains. The children of the root are not necessarily connected\n components in the graph- there may be connectivity between chains that are children of the root\n\n All structures in the snarl tree have two sides that can define the orientation of a traversal \n A forward traversal of a node is always based on the node's orientation \n A forward traversal of a snarl or chain goes from its start boundary node to its end boundary node\n Nodes and snarls can also be oriented backwards relative to the orientation of the parent chain- \n if a traversal of a chain going start to end traverses a child end to start. Then the child would \n be considered to be reversed in its parent\n\n  ");
+		{ // bdsg::SnarlDistanceIndex::TemporaryDistanceIndex file:bdsg/snarl_distance_index.hpp line:1512
 			auto & enclosing_class = cl;
 			pybind11::class_<bdsg::SnarlDistanceIndex::TemporaryDistanceIndex, std::shared_ptr<bdsg::SnarlDistanceIndex::TemporaryDistanceIndex>> cl(enclosing_class, "TemporaryDistanceIndex", "");
-			{ // bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryRecord file:bdsg/snarl_distance_index.hpp line:1628
+			{ // bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryRecord file:bdsg/snarl_distance_index.hpp line:1530
 				auto & enclosing_class = cl;
 				pybind11::class_<bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryRecord, std::shared_ptr<bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryRecord>> cl(enclosing_class, "TemporaryRecord", "");
 				cl.def( pybind11::init( [](bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryRecord const &o){ return new bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryRecord(o); } ) );
@@ -418,7 +418,7 @@ void bind_bdsg_snarl_distance_index(std::function< pybind11::module &(std::strin
 				cl.def("assign", (struct bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryRecord & (bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryRecord::*)(const struct bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryRecord &)) &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryRecord::operator=, "C++: bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryRecord::operator=(const struct bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryRecord &) --> struct bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryRecord &", pybind11::return_value_policy::automatic, pybind11::arg(""));
 			}
 
-			{ // bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryChainRecord file:bdsg/snarl_distance_index.hpp line:1630
+			{ // bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryChainRecord file:bdsg/snarl_distance_index.hpp line:1532
 				auto & enclosing_class = cl;
 				pybind11::class_<bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryChainRecord, std::shared_ptr<bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryChainRecord>, bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryRecord> cl(enclosing_class, "TemporaryChainRecord", "");
 				cl.def( pybind11::init( [](){ return new bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryChainRecord(); } ) );
@@ -434,9 +434,14 @@ void bind_bdsg_snarl_distance_index(std::function< pybind11::module &(std::strin
 				cl.def_readwrite("max_length", &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryChainRecord::max_length);
 				cl.def_readwrite("children", &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryChainRecord::children);
 				cl.def_readwrite("prefix_sum", &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryChainRecord::prefix_sum);
+				cl.def_readwrite("max_prefix_sum", &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryChainRecord::max_prefix_sum);
 				cl.def_readwrite("forward_loops", &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryChainRecord::forward_loops);
 				cl.def_readwrite("backward_loops", &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryChainRecord::backward_loops);
 				cl.def_readwrite("chain_components", &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryChainRecord::chain_components);
+				cl.def_readwrite("distance_left_start", &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryChainRecord::distance_left_start);
+				cl.def_readwrite("distance_right_start", &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryChainRecord::distance_right_start);
+				cl.def_readwrite("distance_left_end", &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryChainRecord::distance_left_end);
+				cl.def_readwrite("distance_right_end", &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryChainRecord::distance_right_end);
 				cl.def_readwrite("rank_in_parent", &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryChainRecord::rank_in_parent);
 				cl.def_readwrite("reversed_in_parent", &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryChainRecord::reversed_in_parent);
 				cl.def_readwrite("is_trivial", &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryChainRecord::is_trivial);
@@ -446,7 +451,7 @@ void bind_bdsg_snarl_distance_index(std::function< pybind11::module &(std::strin
 				cl.def("get_max_record_length", (unsigned long (bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryChainRecord::*)() const) &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryChainRecord::get_max_record_length, "C++: bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryChainRecord::get_max_record_length() const --> unsigned long");
 			}
 
-			{ // bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporarySnarlRecord file:bdsg/snarl_distance_index.hpp line:1657
+			{ // bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporarySnarlRecord file:bdsg/snarl_distance_index.hpp line:1567
 				auto & enclosing_class = cl;
 				pybind11::class_<bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporarySnarlRecord, std::shared_ptr<bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporarySnarlRecord>, bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryRecord> cl(enclosing_class, "TemporarySnarlRecord", "");
 				cl.def( pybind11::init( [](){ return new bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporarySnarlRecord(); } ) );
@@ -466,19 +471,20 @@ void bind_bdsg_snarl_distance_index(std::function< pybind11::module &(std::strin
 				cl.def_readwrite("children", &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporarySnarlRecord::children);
 				cl.def_readwrite("tippy_child_ranks", &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporarySnarlRecord::tippy_child_ranks);
 				cl.def_readwrite("distances", &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporarySnarlRecord::distances);
+				cl.def_readwrite("distance_start_start", &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporarySnarlRecord::distance_start_start);
+				cl.def_readwrite("distance_end_end", &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporarySnarlRecord::distance_end_end);
 				cl.def_readwrite("rank_in_parent", &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporarySnarlRecord::rank_in_parent);
 				cl.def_readwrite("reversed_in_parent", &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporarySnarlRecord::reversed_in_parent);
-				cl.def_readwrite("loop_start", &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporarySnarlRecord::loop_start);
-				cl.def_readwrite("loop_end", &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporarySnarlRecord::loop_end);
 				cl.def_readwrite("is_trivial", &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporarySnarlRecord::is_trivial);
 				cl.def_readwrite("is_simple", &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporarySnarlRecord::is_simple);
 				cl.def_readwrite("is_tip", &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporarySnarlRecord::is_tip);
 				cl.def_readwrite("is_root_snarl", &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporarySnarlRecord::is_root_snarl);
+				cl.def_readwrite("skipped_distances", &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporarySnarlRecord::skipped_distances);
 				cl.def("get_max_record_length", (unsigned long (bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporarySnarlRecord::*)() const) &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporarySnarlRecord::get_max_record_length, "C++: bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporarySnarlRecord::get_max_record_length() const --> unsigned long");
 				cl.def("assign", (struct bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporarySnarlRecord & (bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporarySnarlRecord::*)(const struct bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporarySnarlRecord &)) &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporarySnarlRecord::operator=, "C++: bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporarySnarlRecord::operator=(const struct bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporarySnarlRecord &) --> struct bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporarySnarlRecord &", pybind11::return_value_policy::automatic, pybind11::arg(""));
 			}
 
-			{ // bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryNodeRecord file:bdsg/snarl_distance_index.hpp line:1685
+			{ // bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryNodeRecord file:bdsg/snarl_distance_index.hpp line:1599
 				auto & enclosing_class = cl;
 				pybind11::class_<bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryNodeRecord, std::shared_ptr<bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryNodeRecord>, bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryRecord> cl(enclosing_class, "TemporaryNodeRecord", "");
 				cl.def( pybind11::init( [](){ return new bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryNodeRecord(); } ) );
@@ -490,6 +496,10 @@ void bind_bdsg_snarl_distance_index(std::function< pybind11::module &(std::strin
 				cl.def_readwrite("reversed_in_parent", &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryNodeRecord::reversed_in_parent);
 				cl.def_readwrite("is_tip", &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryNodeRecord::is_tip);
 				cl.def_readwrite("root_snarl_index", &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryNodeRecord::root_snarl_index);
+				cl.def_readwrite("distance_left_start", &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryNodeRecord::distance_left_start);
+				cl.def_readwrite("distance_right_start", &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryNodeRecord::distance_right_start);
+				cl.def_readwrite("distance_left_end", &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryNodeRecord::distance_left_end);
+				cl.def_readwrite("distance_right_end", &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryNodeRecord::distance_right_end);
 				cl.def_static("get_max_record_length", (const unsigned long (*)()) &bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryNodeRecord::get_max_record_length, "C++: bdsg::SnarlDistanceIndex::TemporaryDistanceIndex::TemporaryNodeRecord::get_max_record_length() --> const unsigned long");
 			}
 
@@ -512,27 +522,7 @@ void bind_bdsg_snarl_distance_index(std::function< pybind11::module &(std::strin
 
 		cl.def( pybind11::init( [](){ return new bdsg::SnarlDistanceIndex(); }, [](){ return new PyCallBack_bdsg_SnarlDistanceIndex(); } ) );
 
-		pybind11::enum_<bdsg::SnarlDistanceIndex::record_t>(cl, "record_t", pybind11::arithmetic(), "/////////////////////////////////  How we define different properties of the distance index")
-			.value("ROOT", bdsg::SnarlDistanceIndex::ROOT)
-			.value("NODE", bdsg::SnarlDistanceIndex::NODE)
-			.value("DISTANCED_NODE", bdsg::SnarlDistanceIndex::DISTANCED_NODE)
-			.value("TRIVIAL_SNARL", bdsg::SnarlDistanceIndex::TRIVIAL_SNARL)
-			.value("DISTANCED_TRIVIAL_SNARL", bdsg::SnarlDistanceIndex::DISTANCED_TRIVIAL_SNARL)
-			.value("SIMPLE_SNARL", bdsg::SnarlDistanceIndex::SIMPLE_SNARL)
-			.value("DISTANCED_SIMPLE_SNARL", bdsg::SnarlDistanceIndex::DISTANCED_SIMPLE_SNARL)
-			.value("SNARL", bdsg::SnarlDistanceIndex::SNARL)
-			.value("DISTANCED_SNARL", bdsg::SnarlDistanceIndex::DISTANCED_SNARL)
-			.value("OVERSIZED_SNARL", bdsg::SnarlDistanceIndex::OVERSIZED_SNARL)
-			.value("ROOT_SNARL", bdsg::SnarlDistanceIndex::ROOT_SNARL)
-			.value("DISTANCED_ROOT_SNARL", bdsg::SnarlDistanceIndex::DISTANCED_ROOT_SNARL)
-			.value("CHAIN", bdsg::SnarlDistanceIndex::CHAIN)
-			.value("DISTANCED_CHAIN", bdsg::SnarlDistanceIndex::DISTANCED_CHAIN)
-			.value("MULTICOMPONENT_CHAIN", bdsg::SnarlDistanceIndex::MULTICOMPONENT_CHAIN)
-			.value("CHILDREN", bdsg::SnarlDistanceIndex::CHILDREN)
-			.export_values();
-
-
-		pybind11::enum_<bdsg::SnarlDistanceIndex::connectivity_t>(cl, "connectivity_t", pybind11::arithmetic(), "")
+		pybind11::enum_<bdsg::SnarlDistanceIndex::connectivity_t>(cl, "connectivity_t", pybind11::arithmetic(), "The connectivity of a net_handle- this defines the direction that the net_handle is traversed")
 			.value("START_START", bdsg::SnarlDistanceIndex::START_START)
 			.value("START_END", bdsg::SnarlDistanceIndex::START_END)
 			.value("START_TIP", bdsg::SnarlDistanceIndex::START_TIP)
@@ -545,7 +535,7 @@ void bind_bdsg_snarl_distance_index(std::function< pybind11::module &(std::strin
 			.export_values();
 
 
-		pybind11::enum_<bdsg::SnarlDistanceIndex::net_handle_record_t>(cl, "net_handle_record_t", pybind11::arithmetic(), "")
+		pybind11::enum_<bdsg::SnarlDistanceIndex::net_handle_record_t>(cl, "net_handle_record_t", pybind11::arithmetic(), "Type of a net_handle_t. This is to allow a node record to be seen as a chain from the \n perspective of a handle")
 			.value("ROOT_HANDLE", bdsg::SnarlDistanceIndex::ROOT_HANDLE)
 			.value("NODE_HANDLE", bdsg::SnarlDistanceIndex::NODE_HANDLE)
 			.value("SNARL_HANDLE", bdsg::SnarlDistanceIndex::SNARL_HANDLE)
@@ -554,6 +544,26 @@ void bind_bdsg_snarl_distance_index(std::function< pybind11::module &(std::strin
 			.export_values();
 
 
+		pybind11::enum_<bdsg::SnarlDistanceIndex::record_t>(cl, "record_t", pybind11::arithmetic(), "A record_t is the type of structure that a record can be\n\n NODE, SNARL, and CHAIN indicate that they don't store distances.\n SIMPLE_SNARL is a snarl with all children connecting only to the boundary nodes in one direction\n OVERSIZED_SNARL only stores distances to the boundaries\n ROOT_SNARL represents a connected component of the root. It has no start or end node so \n    its children technically belong to the root\n MULTICOMPONENT_CHAIN can represent a chain with snarls that are not start-end connected\n     The chain is split up into components between these snarls, each node is tagged with\n     which component it belongs to")
+			.value("ROOT", bdsg::SnarlDistanceIndex::ROOT)
+			.value("NODE", bdsg::SnarlDistanceIndex::NODE)
+			.value("DISTANCED_NODE", bdsg::SnarlDistanceIndex::DISTANCED_NODE)
+			.value("TRIVIAL_SNARL", bdsg::SnarlDistanceIndex::TRIVIAL_SNARL)
+			.value("DISTANCED_TRIVIAL_SNARL", bdsg::SnarlDistanceIndex::DISTANCED_TRIVIAL_SNARL)
+			.value("SIMPLE_SNARL", bdsg::SnarlDistanceIndex::SIMPLE_SNARL)
+			.value("DISTANCED_SIMPLE_SNARL", bdsg::SnarlDistanceIndex::DISTANCED_SIMPLE_SNARL)
+			.value("SNARL", bdsg::SnarlDistanceIndex::SNARL)
+			.value("DISTANCED_SNARL", bdsg::SnarlDistanceIndex::DISTANCED_SNARL)
+			.value("OVERSIZED_SNARL", bdsg::SnarlDistanceIndex::OVERSIZED_SNARL)
+			.value("ROOT_SNARL", bdsg::SnarlDistanceIndex::ROOT_SNARL)
+			.value("DISTANCED_ROOT_SNARL", bdsg::SnarlDistanceIndex::DISTANCED_ROOT_SNARL)
+			.value("CHAIN", bdsg::SnarlDistanceIndex::CHAIN)
+			.value("DISTANCED_CHAIN", bdsg::SnarlDistanceIndex::DISTANCED_CHAIN)
+			.value("MULTICOMPONENT_CHAIN", bdsg::SnarlDistanceIndex::MULTICOMPONENT_CHAIN)
+			.value("CHILDREN", bdsg::SnarlDistanceIndex::CHILDREN)
+			.export_values();
+
+
 		pybind11::enum_<bdsg::SnarlDistanceIndex::temp_record_t>(cl, "temp_record_t", pybind11::arithmetic(), "")
 			.value("TEMP_CHAIN", bdsg::SnarlDistanceIndex::TEMP_CHAIN)
 			.value("TEMP_SNARL", bdsg::SnarlDistanceIndex::TEMP_SNARL)
@@ -569,35 +579,19 @@ void bind_bdsg_snarl_distance_index(std::function< pybind11::module &(std::strin
 		cl.def("deserialize", (void (bdsg::SnarlDistanceIndex::*)(int)) &bdsg::SnarlDistanceIndex::deserialize, "C++: bdsg::SnarlDistanceIndex::deserialize(int) --> void", pybind11::arg("fd"));
 		cl.def("get_magic_number", (unsigned int (bdsg::SnarlDistanceIndex::*)() const) &bdsg::SnarlDistanceIndex::get_magic_number, "C++: bdsg::SnarlDistanceIndex::get_magic_number() const --> unsigned int");
 		cl.def("get_prefix", (std::string (bdsg::SnarlDistanceIndex::*)() const) &bdsg::SnarlDistanceIndex::get_prefix, "C++: bdsg::SnarlDistanceIndex::get_prefix() const --> std::string");
-		cl.def("get_root", (struct handlegraph::net_handle_t (bdsg::SnarlDistanceIndex::*)() const) &bdsg::SnarlDistanceIndex::get_root, "Get a net handle referring to a tip-to-tip traversal of the contents of the root snarl.\n TODO: Special handling for circular things in the root snarl? Circular traversal type?\n\nC++: bdsg::SnarlDistanceIndex::get_root() const --> struct handlegraph::net_handle_t");
-		cl.def("is_root", (bool (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::is_root, "Return true if the given handle refers to (a traversal of) the root\n snarl, and false otherwise.\n\nC++: bdsg::SnarlDistanceIndex::is_root(const struct handlegraph::net_handle_t &) const --> bool", pybind11::arg("net"));
-		cl.def("is_root_snarl", (bool (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::is_root_snarl, "Return true if the given handle refers to (a traversal of) a snarl of the root,\n which is considered to be the root but actually refers to a subset of the children \n of the root that are connected\n\nC++: bdsg::SnarlDistanceIndex::is_root_snarl(const struct handlegraph::net_handle_t &) const --> bool", pybind11::arg("net"));
-		cl.def("is_snarl", (bool (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::is_snarl, "Returns true if the given net handle refers to (a traversal of) a snarl.\n\nC++: bdsg::SnarlDistanceIndex::is_snarl(const struct handlegraph::net_handle_t &) const --> bool", pybind11::arg("net"));
-		cl.def("is_simple_snarl", (bool (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::is_simple_snarl, "C++: bdsg::SnarlDistanceIndex::is_simple_snarl(const struct handlegraph::net_handle_t &) const --> bool", pybind11::arg("net"));
-		cl.def("is_chain", (bool (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::is_chain, "Returns true if the given net handle refers to (a traversal of) a chain.\n\nC++: bdsg::SnarlDistanceIndex::is_chain(const struct handlegraph::net_handle_t &) const --> bool", pybind11::arg("net"));
-		cl.def("is_multicomponent_chain", (bool (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::is_multicomponent_chain, "C++: bdsg::SnarlDistanceIndex::is_multicomponent_chain(const struct handlegraph::net_handle_t &) const --> bool", pybind11::arg("net"));
-		cl.def("is_looping_chain", (bool (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::is_looping_chain, "Returns true if the given net handle refers to (a traversal of) a chain that loops (a chain where the first and last node are the same).\n\nC++: bdsg::SnarlDistanceIndex::is_looping_chain(const struct handlegraph::net_handle_t &) const --> bool", pybind11::arg("net"));
-		cl.def("is_trivial_chain", (bool (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::is_trivial_chain, "Returns true if the given net handle refers to (a traversal of) a trivial chain that represents a single node.\n\nC++: bdsg::SnarlDistanceIndex::is_trivial_chain(const struct handlegraph::net_handle_t &) const --> bool", pybind11::arg("net"));
-		cl.def("is_node", (bool (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::is_node, "Returns true if the given net handle refers to (a traversal of) a single node, and thus has a corresponding handle_t.\n\nC++: bdsg::SnarlDistanceIndex::is_node(const struct handlegraph::net_handle_t &) const --> bool", pybind11::arg("net"));
-		cl.def("is_sentinel", (bool (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::is_sentinel, "Return true if the given net handle is a snarl bound sentinel (in either\n inward or outward orientation), and false otherwise.\n\nC++: bdsg::SnarlDistanceIndex::is_sentinel(const struct handlegraph::net_handle_t &) const --> bool", pybind11::arg("net"));
-		cl.def("get_net", (struct handlegraph::net_handle_t (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::handle_t &, const class handlegraph::HandleGraph *) const) &bdsg::SnarlDistanceIndex::get_net, "Turn a handle to an oriented node into a net handle for a start-to-end or end-to-start traversal of the node, as appropriate.\n\nC++: bdsg::SnarlDistanceIndex::get_net(const struct handlegraph::handle_t &, const class handlegraph::HandleGraph *) const --> struct handlegraph::net_handle_t", pybind11::arg("handle"), pybind11::arg("graph"));
-		cl.def("get_handle", (struct handlegraph::handle_t (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &, const class handlegraph::HandleGraph *) const) &bdsg::SnarlDistanceIndex::get_handle, "For a net handle to a traversal of a single node, get the handle for that node in the orientation it is traversed.\n May not be called for other net handles.\n\nC++: bdsg::SnarlDistanceIndex::get_handle(const struct handlegraph::net_handle_t &, const class handlegraph::HandleGraph *) const --> struct handlegraph::handle_t", pybind11::arg("net"), pybind11::arg("graph"));
-		cl.def("get_parent", (struct handlegraph::net_handle_t (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::get_parent, "Get the parent snarl of a chain, or the parent chain of a snarl or node.\n If the child is start-to-end or end-to-start, and the parent is a chain,\n the chain comes out facing the same way, accounting for the relative\n orientation of the child snarl or node in the chain. Otherwise,\n everything is produced as start-to-end, even if that is not actually a\n realizable traversal of a snarl or chain. May not be called on the root\n snarl.\n\n Also works on snarl boundary sentinels.\n\nC++: bdsg::SnarlDistanceIndex::get_parent(const struct handlegraph::net_handle_t &) const --> struct handlegraph::net_handle_t", pybind11::arg("child"));
-		cl.def("get_bound", (struct handlegraph::net_handle_t (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &, bool, bool) const) &bdsg::SnarlDistanceIndex::get_bound, "Get the bounding handle for the snarl or chain referenced by the given\n net handle, getting the start or end facing in or out as appropriate.\n\n For snarls, returns the bounding sentinel net handles. For chains,\n returns net handles for traversals of the bounding nodes of the chain.\n\n Ignores traversal type.\n\n May not be called on traversals of individual nodes.\n\nC++: bdsg::SnarlDistanceIndex::get_bound(const struct handlegraph::net_handle_t &, bool, bool) const --> struct handlegraph::net_handle_t", pybind11::arg("snarl"), pybind11::arg("get_end"), pybind11::arg("face_in"));
-		cl.def("get_node_from_sentinel", (struct handlegraph::net_handle_t (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::get_node_from_sentinel, "Given the sentinel of a snarl, return a handle to the node representing it\n\nC++: bdsg::SnarlDistanceIndex::get_node_from_sentinel(const struct handlegraph::net_handle_t &) const --> struct handlegraph::net_handle_t", pybind11::arg("sentinel"));
-		cl.def("flip", (struct handlegraph::net_handle_t (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::flip, "Return a net handle to the same snarl/chain/node in the opposite orientation.\n No effect on tip-to-tip, start-to-start, or end-to-end net handles. Flips all the others.\n\nC++: bdsg::SnarlDistanceIndex::flip(const struct handlegraph::net_handle_t &) const --> struct handlegraph::net_handle_t", pybind11::arg("net"));
-		cl.def("canonical", (struct handlegraph::net_handle_t (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::canonical, "Get a canonical traversal handle from any net handle. All handles to the\n same net graph element have the same canonical traversal. That canonical\n traversal must be realizable, and might not always be start-to-end or\n even consistently be the same kind of traversal for different snarls,\n chains, or nodes. Mostly useful to normalize for equality comparisons.\n\nC++: bdsg::SnarlDistanceIndex::canonical(const struct handlegraph::net_handle_t &) const --> struct handlegraph::net_handle_t", pybind11::arg("net"));
-		cl.def("starts_at", (enum handlegraph::SnarlDecomposition::endpoint_t (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::starts_at, "Return the kind of location at which the given traversal starts.\n\nC++: bdsg::SnarlDistanceIndex::starts_at(const struct handlegraph::net_handle_t &) const --> enum handlegraph::SnarlDecomposition::endpoint_t", pybind11::arg("traversal"));
-		cl.def("ends_at", (enum handlegraph::SnarlDecomposition::endpoint_t (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::ends_at, "Return the kind of location at which the given traversal ends.\n\nC++: bdsg::SnarlDistanceIndex::ends_at(const struct handlegraph::net_handle_t &) const --> enum handlegraph::SnarlDecomposition::endpoint_t", pybind11::arg("traversal"));
-		cl.def("get_rank_in_parent", (unsigned long (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::get_rank_in_parent, "C++: bdsg::SnarlDistanceIndex::get_rank_in_parent(const struct handlegraph::net_handle_t &) const --> unsigned long", pybind11::arg("net"));
-		cl.def("connected_component_count", (unsigned long (bdsg::SnarlDistanceIndex::*)() const) &bdsg::SnarlDistanceIndex::connected_component_count, "How many connected components are in this graph?\n This returns the number of topological connected components, not necessarily the \n number of nodes in the top-level snarl \n\nC++: bdsg::SnarlDistanceIndex::connected_component_count() const --> unsigned long");
-		cl.def("get_parent_traversal", (struct handlegraph::net_handle_t (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &, const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::get_parent_traversal, "Get a net handle for traversals of a snarl or chain that contains\n the given oriented bounding node traversals or sentinels. Given two\n sentinels for a snarl, produces a net handle to a start-to-end,\n end-to-end, end-to-start, or start-to-start traversal of that snarl.\n Given handles to traversals of the bounding nodes of a chain, similarly\n produces a net handle to a traversal of the chain.\n\n For a chain, either or both handles can also be a snarl containing tips,\n for a tip-to-start, tip-to-end, start-to-tip, end-to-tip, or tip-to-tip\n traversal. Similarly, for a snarl, either or both handles can be a chain\n in the snarl that contains internal tips, or that has no edges on the\n appropriate end.\n\n May only be called if a path actually exists between the given start\n and end.\n\nC++: bdsg::SnarlDistanceIndex::get_parent_traversal(const struct handlegraph::net_handle_t &, const struct handlegraph::net_handle_t &) const --> struct handlegraph::net_handle_t", pybind11::arg("traversal_start"), pybind11::arg("traversal_end"));
+		cl.def("maximum_distance", [](bdsg::SnarlDistanceIndex const &o, const long long & a0, const bool & a1, const unsigned long & a2, const long long & a3, const bool & a4, const unsigned long & a5) -> unsigned long { return o.maximum_distance(a0, a1, a2, a3, a4, a5); }, "", pybind11::arg("id1"), pybind11::arg("rev1"), pybind11::arg("offset1"), pybind11::arg("id2"), pybind11::arg("rev2"), pybind11::arg("offset2"));
+		cl.def("maximum_distance", [](bdsg::SnarlDistanceIndex const &o, const long long & a0, const bool & a1, const unsigned long & a2, const long long & a3, const bool & a4, const unsigned long & a5, bool const & a6) -> unsigned long { return o.maximum_distance(a0, a1, a2, a3, a4, a5, a6); }, "", pybind11::arg("id1"), pybind11::arg("rev1"), pybind11::arg("offset1"), pybind11::arg("id2"), pybind11::arg("rev2"), pybind11::arg("offset2"), pybind11::arg("unoriented_distance"));
+		cl.def("maximum_distance", (unsigned long (bdsg::SnarlDistanceIndex::*)(const long long, const bool, const unsigned long, const long long, const bool, const unsigned long, bool, const class handlegraph::HandleGraph *) const) &bdsg::SnarlDistanceIndex::maximum_distance, "Find an approximation of the maximum distance between two positions. \n This isn't a true maximum- the only guarantee is that it's greater than or equal to the minimum distance\n\nC++: bdsg::SnarlDistanceIndex::maximum_distance(const long long, const bool, const unsigned long, const long long, const bool, const unsigned long, bool, const class handlegraph::HandleGraph *) const --> unsigned long", pybind11::arg("id1"), pybind11::arg("rev1"), pybind11::arg("offset1"), pybind11::arg("id2"), pybind11::arg("rev2"), pybind11::arg("offset2"), pybind11::arg("unoriented_distance"), pybind11::arg("graph"));
 		cl.def("distance_in_parent", [](bdsg::SnarlDistanceIndex const &o, const struct handlegraph::net_handle_t & a0, const struct handlegraph::net_handle_t & a1, const struct handlegraph::net_handle_t & a2) -> unsigned long { return o.distance_in_parent(a0, a1, a2); }, "", pybind11::arg("parent"), pybind11::arg("child1"), pybind11::arg("child2"));
 		cl.def("distance_in_parent", [](bdsg::SnarlDistanceIndex const &o, const struct handlegraph::net_handle_t & a0, const struct handlegraph::net_handle_t & a1, const struct handlegraph::net_handle_t & a2, const class handlegraph::HandleGraph * a3) -> unsigned long { return o.distance_in_parent(a0, a1, a2, a3); }, "", pybind11::arg("parent"), pybind11::arg("child1"), pybind11::arg("child2"), pybind11::arg("graph"));
 		cl.def("distance_in_parent", (unsigned long (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &, const struct handlegraph::net_handle_t &, const struct handlegraph::net_handle_t &, const class handlegraph::HandleGraph *, unsigned long) const) &bdsg::SnarlDistanceIndex::distance_in_parent, "Find the distance between the two child node sides in the parent, facing each other, not \n including the lengths of the nodes\n This only takes into account the endpoint of the net_handle_t traversal, it does not care if the traversal\n was possible. Doesn't allow you to find the distance from a traversal ending/starting in a tip\n requires that the children are children of the parent\n For chains, the distance to/from a snarl is really the distance from the outer node of the snarl\n Returns std::numeric_limits<size_t>::max() if there is not path between them in the parent \n or if they are not children of the parent\n\n Distance limit is the distance after which we give up if we're doing a traversal\n\nC++: bdsg::SnarlDistanceIndex::distance_in_parent(const struct handlegraph::net_handle_t &, const struct handlegraph::net_handle_t &, const struct handlegraph::net_handle_t &, const class handlegraph::HandleGraph *, unsigned long) const --> unsigned long", pybind11::arg("parent"), pybind11::arg("child1"), pybind11::arg("child2"), pybind11::arg("graph"), pybind11::arg("distance_limit"));
-		cl.def("distance_to_parent_bound", (unsigned long (bdsg::SnarlDistanceIndex::*)(struct handlegraph::net_handle_t &, bool, struct handlegraph::net_handle_t &, bool) const) &bdsg::SnarlDistanceIndex::distance_to_parent_bound, "C++: bdsg::SnarlDistanceIndex::distance_to_parent_bound(struct handlegraph::net_handle_t &, bool, struct handlegraph::net_handle_t &, bool) const --> unsigned long", pybind11::arg("parent"), pybind11::arg("to_start"), pybind11::arg("child"), pybind11::arg("go_left"));
+		cl.def("max_distance_in_parent", [](bdsg::SnarlDistanceIndex const &o, const struct handlegraph::net_handle_t & a0, const struct handlegraph::net_handle_t & a1, const struct handlegraph::net_handle_t & a2) -> unsigned long { return o.max_distance_in_parent(a0, a1, a2); }, "", pybind11::arg("parent"), pybind11::arg("child1"), pybind11::arg("child2"));
+		cl.def("max_distance_in_parent", [](bdsg::SnarlDistanceIndex const &o, const struct handlegraph::net_handle_t & a0, const struct handlegraph::net_handle_t & a1, const struct handlegraph::net_handle_t & a2, const class handlegraph::HandleGraph * a3) -> unsigned long { return o.max_distance_in_parent(a0, a1, a2, a3); }, "", pybind11::arg("parent"), pybind11::arg("child1"), pybind11::arg("child2"), pybind11::arg("graph"));
+		cl.def("max_distance_in_parent", (unsigned long (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &, const struct handlegraph::net_handle_t &, const struct handlegraph::net_handle_t &, const class handlegraph::HandleGraph *, unsigned long) const) &bdsg::SnarlDistanceIndex::max_distance_in_parent, "Find the maximum distance between two children in the parent. \n This is the same as distance_in_parent for everything except children of chains\n\nC++: bdsg::SnarlDistanceIndex::max_distance_in_parent(const struct handlegraph::net_handle_t &, const struct handlegraph::net_handle_t &, const struct handlegraph::net_handle_t &, const class handlegraph::HandleGraph *, unsigned long) const --> unsigned long", pybind11::arg("parent"), pybind11::arg("child1"), pybind11::arg("child2"), pybind11::arg("graph"), pybind11::arg("distance_limit"));
+		cl.def("distance_to_parent_bound", [](bdsg::SnarlDistanceIndex const &o, const struct handlegraph::net_handle_t & a0, bool const & a1, struct handlegraph::net_handle_t const & a2) -> unsigned long { return o.distance_to_parent_bound(a0, a1, a2); }, "", pybind11::arg("parent"), pybind11::arg("to_start"), pybind11::arg("child"));
+		cl.def("distance_to_parent_bound", (unsigned long (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &, bool, struct handlegraph::net_handle_t, class std::tuple<enum bdsg::SnarlDistanceIndex::net_handle_record_t, enum bdsg::SnarlDistanceIndex::net_handle_record_t, enum bdsg::SnarlDistanceIndex::net_handle_record_t, enum bdsg::SnarlDistanceIndex::net_handle_record_t>) const) &bdsg::SnarlDistanceIndex::distance_to_parent_bound, "Get the distance from the child to the start or end bound of the parent\n parent_and_child_types are hints to figure out the type of snarl/chain records the parent and child are\n tuple of parent record type, parent handle type, child record type, child handle type\n This is really just used to see if the parent and child are trivial chains, so it might not be exactly what the actual record is\n\nC++: bdsg::SnarlDistanceIndex::distance_to_parent_bound(const struct handlegraph::net_handle_t &, bool, struct handlegraph::net_handle_t, class std::tuple<enum bdsg::SnarlDistanceIndex::net_handle_record_t, enum bdsg::SnarlDistanceIndex::net_handle_record_t, enum bdsg::SnarlDistanceIndex::net_handle_record_t, enum bdsg::SnarlDistanceIndex::net_handle_record_t>) const --> unsigned long", pybind11::arg("parent"), pybind11::arg("to_start"), pybind11::arg("child"), pybind11::arg("parent_and_child_types"));
+		cl.def("into_which_snarl", (class std::tuple<long long, bool, bool> (bdsg::SnarlDistanceIndex::*)(const long long &, const bool &) const) &bdsg::SnarlDistanceIndex::into_which_snarl, "If this node id and orientation is pointing into a snarl, then return the start\n node id and orientation pointing into the snarl, and if the snarl is trivial\n Returns <0, false, false> if it doesn't point into a snarl\n\nC++: bdsg::SnarlDistanceIndex::into_which_snarl(const long long &, const bool &) const --> class std::tuple<long long, bool, bool>", pybind11::arg("id"), pybind11::arg("reverse"));
 		cl.def("is_ordered_in_chain", (bool (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &, const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::is_ordered_in_chain, "C++: bdsg::SnarlDistanceIndex::is_ordered_in_chain(const struct handlegraph::net_handle_t &, const struct handlegraph::net_handle_t &) const --> bool", pybind11::arg("child1"), pybind11::arg("child2"));
-		cl.def("get_record_offset_in_chain", (unsigned long (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::get_record_offset_in_chain, "C++: bdsg::SnarlDistanceIndex::get_record_offset_in_chain(const struct handlegraph::net_handle_t &) const --> unsigned long", pybind11::arg("child"));
 		cl.def("is_externally_start_end_connected", (bool (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t) const) &bdsg::SnarlDistanceIndex::is_externally_start_end_connected, "C++: bdsg::SnarlDistanceIndex::is_externally_start_end_connected(const struct handlegraph::net_handle_t) const --> bool", pybind11::arg("net"));
 		cl.def("is_externally_start_start_connected", (bool (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t) const) &bdsg::SnarlDistanceIndex::is_externally_start_start_connected, "C++: bdsg::SnarlDistanceIndex::is_externally_start_start_connected(const struct handlegraph::net_handle_t) const --> bool", pybind11::arg("net"));
 		cl.def("is_externally_end_end_connected", (bool (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t) const) &bdsg::SnarlDistanceIndex::is_externally_end_end_connected, "C++: bdsg::SnarlDistanceIndex::is_externally_end_end_connected(const struct handlegraph::net_handle_t) const --> bool", pybind11::arg("net"));
@@ -609,22 +603,43 @@ void bind_bdsg_snarl_distance_index(std::function< pybind11::module &(std::strin
 		cl.def("node_id", (long long (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::node_id, "What is the node id of the node represented by this net handle\n net must be a node or a sentinel\n\nC++: bdsg::SnarlDistanceIndex::node_id(const struct handlegraph::net_handle_t &) const --> long long", pybind11::arg("net"));
 		cl.def("has_node", (bool (bdsg::SnarlDistanceIndex::*)(const long long) const) &bdsg::SnarlDistanceIndex::has_node, "Does the graph have this node?\n\nC++: bdsg::SnarlDistanceIndex::has_node(const long long) const --> bool", pybind11::arg("id"));
 		cl.def("is_reversed_in_parent", (bool (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::is_reversed_in_parent, "Only really relevant for nodes in chains, is the node\n traversed backwards relative to the orientation of the chain\n\nC++: bdsg::SnarlDistanceIndex::is_reversed_in_parent(const struct handlegraph::net_handle_t &) const --> bool", pybind11::arg("net"));
-		cl.def("get_node_net_handle", (struct handlegraph::net_handle_t (bdsg::SnarlDistanceIndex::*)(const long long) const) &bdsg::SnarlDistanceIndex::get_node_net_handle, "Get a net handle from a node\n\nC++: bdsg::SnarlDistanceIndex::get_node_net_handle(const long long) const --> struct handlegraph::net_handle_t", pybind11::arg("id"));
+		cl.def("get_node_net_handle", [](bdsg::SnarlDistanceIndex const &o, const long long & a0) -> handlegraph::net_handle_t { return o.get_node_net_handle(a0); }, "", pybind11::arg("id"));
+		cl.def("get_node_net_handle", (struct handlegraph::net_handle_t (bdsg::SnarlDistanceIndex::*)(const long long, bool) const) &bdsg::SnarlDistanceIndex::get_node_net_handle, "Get a net handle from a node and, optionally, an orientation\n\nC++: bdsg::SnarlDistanceIndex::get_node_net_handle(const long long, bool) const --> struct handlegraph::net_handle_t", pybind11::arg("id"), pybind11::arg("rev"));
 		cl.def("get_max_tree_depth", (unsigned long (bdsg::SnarlDistanceIndex::*)() const) &bdsg::SnarlDistanceIndex::get_max_tree_depth, "How deep is the snarl tree? The root is 0, top-level chain is 1, etc\n Only counts chains\n\nC++: bdsg::SnarlDistanceIndex::get_max_tree_depth() const --> unsigned long");
-		cl.def("get_depth", (unsigned long (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::get_depth, "What is the depth of this net handle. Nodes and snarls get the depth of their parent, the epth of the root is 0\n\nC++: bdsg::SnarlDistanceIndex::get_depth(const struct handlegraph::net_handle_t &) const --> unsigned long", pybind11::arg("net"));
+		cl.def("get_depth", (unsigned long (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::get_depth, "What is the depth of this net handle? Nodes and snarls get the depth of their parent\n The depth of the root is 0, the depth of its child chains is 1, the depth of the nodes and snarls that are \n children of those chains is also 1, and the chains that are children of those snarls have depth 2\n\n     \n\nC++: bdsg::SnarlDistanceIndex::get_depth(const struct handlegraph::net_handle_t &) const --> unsigned long", pybind11::arg("net"));
 		cl.def("get_connected_component_number", (unsigned long (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::get_connected_component_number, "Given a handle, return a unique identifier for the connected component that it's on\n Connected components are based on the connectivity of the graph, so there may be fewer\n connected components than there are root-level structures. For example, if two root-level\n chains are connected to each other in the root, then they will be considered one connected\n component but two separate root-level chains\n\nC++: bdsg::SnarlDistanceIndex::get_connected_component_number(const struct handlegraph::net_handle_t &) const --> unsigned long", pybind11::arg("net"));
 		cl.def("get_handle_from_connected_component", (struct handlegraph::net_handle_t (bdsg::SnarlDistanceIndex::*)(unsigned long) const) &bdsg::SnarlDistanceIndex::get_handle_from_connected_component, "Given the connected component number (from get_connected_component_number), get the\n root-level handle pointing to it.\n If the connected component is a root-level snarl, then this may return a \"root\" handle,\n but it will actually point to the snarl\n\nC++: bdsg::SnarlDistanceIndex::get_handle_from_connected_component(unsigned long) const --> struct handlegraph::net_handle_t", pybind11::arg("num"));
-		cl.def("has_connectivity", (bool (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &, enum handlegraph::SnarlDecomposition::endpoint_t, enum handlegraph::SnarlDecomposition::endpoint_t) const) &bdsg::SnarlDistanceIndex::has_connectivity, "C++: bdsg::SnarlDistanceIndex::has_connectivity(const struct handlegraph::net_handle_t &, enum handlegraph::SnarlDecomposition::endpoint_t, enum handlegraph::SnarlDecomposition::endpoint_t) const --> bool", pybind11::arg("net"), pybind11::arg("start"), pybind11::arg("end"));
-		cl.def("has_external_connectivity", (bool (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &, enum handlegraph::SnarlDecomposition::endpoint_t, enum handlegraph::SnarlDecomposition::endpoint_t) const) &bdsg::SnarlDistanceIndex::has_external_connectivity, "C++: bdsg::SnarlDistanceIndex::has_external_connectivity(const struct handlegraph::net_handle_t &, enum handlegraph::SnarlDecomposition::endpoint_t, enum handlegraph::SnarlDecomposition::endpoint_t) const --> bool", pybind11::arg("net"), pybind11::arg("start"), pybind11::arg("end"));
-		cl.def("minimum_distance", [](bdsg::SnarlDistanceIndex const &o, const long long & a0, const bool & a1, const unsigned long & a2, const long long & a3, const bool & a4, const unsigned long & a5) -> unsigned long { return o.minimum_distance(a0, a1, a2, a3, a4, a5); }, "", pybind11::arg("id1"), pybind11::arg("rev1"), pybind11::arg("offset1"), pybind11::arg("id2"), pybind11::arg("rev2"), pybind11::arg("offset2"));
-		cl.def("minimum_distance", [](bdsg::SnarlDistanceIndex const &o, const long long & a0, const bool & a1, const unsigned long & a2, const long long & a3, const bool & a4, const unsigned long & a5, bool const & a6) -> unsigned long { return o.minimum_distance(a0, a1, a2, a3, a4, a5, a6); }, "", pybind11::arg("id1"), pybind11::arg("rev1"), pybind11::arg("offset1"), pybind11::arg("id2"), pybind11::arg("rev2"), pybind11::arg("offset2"), pybind11::arg("unoriented_distance"));
-		cl.def("minimum_distance", (unsigned long (bdsg::SnarlDistanceIndex::*)(const long long, const bool, const unsigned long, const long long, const bool, const unsigned long, bool, const class handlegraph::HandleGraph *) const) &bdsg::SnarlDistanceIndex::minimum_distance, "Get the minimum distance between two positions in the graph\n If unoriented_distance is true, then ignore the orientations of the positions\n Otherwise, distance is calculated from the first position going forward to the second position going forward\n The distance includes one of the positions; the distance from one position to itself is 0\n Returns std::numeric_limits<size_t>::max() if there is no path between the two positions\n\nC++: bdsg::SnarlDistanceIndex::minimum_distance(const long long, const bool, const unsigned long, const long long, const bool, const unsigned long, bool, const class handlegraph::HandleGraph *) const --> unsigned long", pybind11::arg("id1"), pybind11::arg("rev1"), pybind11::arg("offset1"), pybind11::arg("id2"), pybind11::arg("rev2"), pybind11::arg("offset2"), pybind11::arg("unoriented_distance"), pybind11::arg("graph"));
+		cl.def("has_connectivity", (bool (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &, enum handlegraph::SnarlDecomposition::endpoint_t, enum handlegraph::SnarlDecomposition::endpoint_t) const) &bdsg::SnarlDistanceIndex::has_connectivity, "Is there a path between the start and end endpoints within the net handle?\n\nC++: bdsg::SnarlDistanceIndex::has_connectivity(const struct handlegraph::net_handle_t &, enum handlegraph::SnarlDecomposition::endpoint_t, enum handlegraph::SnarlDecomposition::endpoint_t) const --> bool", pybind11::arg("net"), pybind11::arg("start"), pybind11::arg("end"));
+		cl.def("has_external_connectivity", (bool (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &, enum handlegraph::SnarlDecomposition::endpoint_t, enum handlegraph::SnarlDecomposition::endpoint_t) const) &bdsg::SnarlDistanceIndex::has_external_connectivity, "Is there a path between the start and end endpoints outside the net handle?\n This is used for children of the root\n\nC++: bdsg::SnarlDistanceIndex::has_external_connectivity(const struct handlegraph::net_handle_t &, enum handlegraph::SnarlDecomposition::endpoint_t, enum handlegraph::SnarlDecomposition::endpoint_t) const --> bool", pybind11::arg("net"), pybind11::arg("start"), pybind11::arg("end"));
 		cl.def("get_prefix_sum_value", (unsigned long (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t) const) &bdsg::SnarlDistanceIndex::get_prefix_sum_value, "Get the distance index values for nodes in a chain\n These will all fail if the parent of net is not a chain\n\nC++: bdsg::SnarlDistanceIndex::get_prefix_sum_value(const struct handlegraph::net_handle_t) const --> unsigned long", pybind11::arg("net"));
 		cl.def("get_forward_loop_value", (unsigned long (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t) const) &bdsg::SnarlDistanceIndex::get_forward_loop_value, "C++: bdsg::SnarlDistanceIndex::get_forward_loop_value(const struct handlegraph::net_handle_t) const --> unsigned long", pybind11::arg("net"));
 		cl.def("get_reverse_loop_value", (unsigned long (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t) const) &bdsg::SnarlDistanceIndex::get_reverse_loop_value, "C++: bdsg::SnarlDistanceIndex::get_reverse_loop_value(const struct handlegraph::net_handle_t) const --> unsigned long", pybind11::arg("net"));
 		cl.def("get_chain_component", [](bdsg::SnarlDistanceIndex const &o, const struct handlegraph::net_handle_t & a0) -> unsigned long { return o.get_chain_component(a0); }, "", pybind11::arg("net"));
 		cl.def("get_chain_component", (unsigned long (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t, bool) const) &bdsg::SnarlDistanceIndex::get_chain_component, "C++: bdsg::SnarlDistanceIndex::get_chain_component(const struct handlegraph::net_handle_t, bool) const --> unsigned long", pybind11::arg("net"), pybind11::arg("get_end"));
-		cl.def("set_snarl_size_limit", (void (bdsg::SnarlDistanceIndex::*)(unsigned long)) &bdsg::SnarlDistanceIndex::set_snarl_size_limit, "//////////////  Construction methods\n\nC++: bdsg::SnarlDistanceIndex::set_snarl_size_limit(unsigned long) --> void", pybind11::arg("size"));
+		cl.def("get_root", (struct handlegraph::net_handle_t (bdsg::SnarlDistanceIndex::*)() const) &bdsg::SnarlDistanceIndex::get_root, "Get a net handle referring to a tip-to-tip traversal of the contents of the root snarl.\n\nC++: bdsg::SnarlDistanceIndex::get_root() const --> struct handlegraph::net_handle_t");
+		cl.def("is_root", (bool (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::is_root, "Return true if the given handle refers to (a traversal of) the root\n snarl, and false otherwise.\n\nC++: bdsg::SnarlDistanceIndex::is_root(const struct handlegraph::net_handle_t &) const --> bool", pybind11::arg("net"));
+		cl.def("is_root_snarl", (bool (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::is_root_snarl, "Return true if the given handle refers to (a traversal of) a snarl of the root,\n which is considered to be the root but actually refers to a subset of the children \n of the root that are connected\n\nC++: bdsg::SnarlDistanceIndex::is_root_snarl(const struct handlegraph::net_handle_t &) const --> bool", pybind11::arg("net"));
+		cl.def("is_snarl", (bool (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::is_snarl, "Returns true if the given net handle refers to (a traversal of) a snarl.\n\nC++: bdsg::SnarlDistanceIndex::is_snarl(const struct handlegraph::net_handle_t &) const --> bool", pybind11::arg("net"));
+		cl.def("is_simple_snarl", (bool (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::is_simple_snarl, "C++: bdsg::SnarlDistanceIndex::is_simple_snarl(const struct handlegraph::net_handle_t &) const --> bool", pybind11::arg("net"));
+		cl.def("is_chain", (bool (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::is_chain, "Returns true if the given net handle refers to (a traversal of) a chain.\n\nC++: bdsg::SnarlDistanceIndex::is_chain(const struct handlegraph::net_handle_t &) const --> bool", pybind11::arg("net"));
+		cl.def("is_multicomponent_chain", (bool (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::is_multicomponent_chain, "C++: bdsg::SnarlDistanceIndex::is_multicomponent_chain(const struct handlegraph::net_handle_t &) const --> bool", pybind11::arg("net"));
+		cl.def("is_looping_chain", (bool (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::is_looping_chain, "Returns true if the given net handle refers to (a traversal of) a chain that loops (a chain where the first and last node are the same).\n\nC++: bdsg::SnarlDistanceIndex::is_looping_chain(const struct handlegraph::net_handle_t &) const --> bool", pybind11::arg("net"));
+		cl.def("is_trivial_chain", (bool (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::is_trivial_chain, "Returns true if the given net handle refers to (a traversal of) a trivial chain that represents a single node.\n\nC++: bdsg::SnarlDistanceIndex::is_trivial_chain(const struct handlegraph::net_handle_t &) const --> bool", pybind11::arg("net"));
+		cl.def("is_node", (bool (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::is_node, "Returns true if the given net handle refers to (a traversal of) a single node, and thus has a corresponding handle_t.\n\nC++: bdsg::SnarlDistanceIndex::is_node(const struct handlegraph::net_handle_t &) const --> bool", pybind11::arg("net"));
+		cl.def("is_sentinel", (bool (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::is_sentinel, "Return true if the given net handle is a snarl bound sentinel (in either\n inward or outward orientation), and false otherwise.\n\nC++: bdsg::SnarlDistanceIndex::is_sentinel(const struct handlegraph::net_handle_t &) const --> bool", pybind11::arg("net"));
+		cl.def("get_net", (struct handlegraph::net_handle_t (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::handle_t &, const class handlegraph::HandleGraph *) const) &bdsg::SnarlDistanceIndex::get_net, "Turn a handle to an oriented node into a net handle for a start-to-end or end-to-start traversal of the node, as appropriate.\n\nC++: bdsg::SnarlDistanceIndex::get_net(const struct handlegraph::handle_t &, const class handlegraph::HandleGraph *) const --> struct handlegraph::net_handle_t", pybind11::arg("handle"), pybind11::arg("graph"));
+		cl.def("get_handle", (struct handlegraph::handle_t (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &, const class handlegraph::HandleGraph *) const) &bdsg::SnarlDistanceIndex::get_handle, "For a net handle to a traversal of a single node, get the handle for that node in the orientation it is traversed.\n May not be called for other net handles.\n\nC++: bdsg::SnarlDistanceIndex::get_handle(const struct handlegraph::net_handle_t &, const class handlegraph::HandleGraph *) const --> struct handlegraph::handle_t", pybind11::arg("net"), pybind11::arg("graph"));
+		cl.def("get_parent", (struct handlegraph::net_handle_t (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::get_parent, "Get the parent snarl of a chain, or the parent chain of a snarl or node.\n If the child is start-to-end or end-to-start, and the parent is a chain,\n the chain comes out facing the same way, accounting for the relative\n orientation of the child snarl or node in the chain. Otherwise,\n everything is produced as start-to-end, even if that is not actually a\n realizable traversal of a snarl or chain. May not be called on the root\n snarl.\n\n Also works on snarl boundary sentinels.\n\nC++: bdsg::SnarlDistanceIndex::get_parent(const struct handlegraph::net_handle_t &) const --> struct handlegraph::net_handle_t", pybind11::arg("child"));
+		cl.def("get_bound", (struct handlegraph::net_handle_t (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &, bool, bool) const) &bdsg::SnarlDistanceIndex::get_bound, "Get the bounding handle for the snarl or chain referenced by the given\n net handle, getting the start or end facing in or out as appropriate.\n\n For snarls, returns the bounding sentinel net handles. For chains,\n returns net handles for traversals of the bounding nodes of the chain.\n If the chain is a looping chain, then the start and end of the chain\n are the same, so the connectivity of the bound indicates which we're\n looking at; the connectivity will be start-start if it is going \n backwards in the node, and end-end if it is going forwards \n\n Ignores traversal type.\n\n May not be called on traversals of individual nodes.\n\nC++: bdsg::SnarlDistanceIndex::get_bound(const struct handlegraph::net_handle_t &, bool, bool) const --> struct handlegraph::net_handle_t", pybind11::arg("snarl"), pybind11::arg("get_end"), pybind11::arg("face_in"));
+		cl.def("get_node_from_sentinel", (struct handlegraph::net_handle_t (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::get_node_from_sentinel, "Given the sentinel of a snarl, return a handle to the node representing it\n\nC++: bdsg::SnarlDistanceIndex::get_node_from_sentinel(const struct handlegraph::net_handle_t &) const --> struct handlegraph::net_handle_t", pybind11::arg("sentinel"));
+		cl.def("flip", (struct handlegraph::net_handle_t (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::flip, "Return a net handle to the same snarl/chain/node in the opposite orientation.\n No effect on tip-to-tip, start-to-start, or end-to-end net handles. Flips all the others.\n\nC++: bdsg::SnarlDistanceIndex::flip(const struct handlegraph::net_handle_t &) const --> struct handlegraph::net_handle_t", pybind11::arg("net"));
+		cl.def("canonical", (struct handlegraph::net_handle_t (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::canonical, "Get a canonical traversal handle from any net handle. All handles to the\n same net graph element have the same canonical traversal. That canonical\n traversal must be realizable, and might not always be start-to-end or\n even consistently be the same kind of traversal for different snarls,\n chains, or nodes. Mostly useful to normalize for equality comparisons.\n\n Any root snarl will become just the root\n Anything without connectivity will get START_END\n\nC++: bdsg::SnarlDistanceIndex::canonical(const struct handlegraph::net_handle_t &) const --> struct handlegraph::net_handle_t", pybind11::arg("net"));
+		cl.def("start_end_traversal_of", (struct handlegraph::net_handle_t (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::start_end_traversal_of, "C++: bdsg::SnarlDistanceIndex::start_end_traversal_of(const struct handlegraph::net_handle_t &) const --> struct handlegraph::net_handle_t", pybind11::arg("net"));
+		cl.def("starts_at", (enum handlegraph::SnarlDecomposition::endpoint_t (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::starts_at, "Return the kind of location at which the given traversal starts.\n\nC++: bdsg::SnarlDistanceIndex::starts_at(const struct handlegraph::net_handle_t &) const --> enum handlegraph::SnarlDecomposition::endpoint_t", pybind11::arg("traversal"));
+		cl.def("ends_at", (enum handlegraph::SnarlDecomposition::endpoint_t (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::ends_at, "Return the kind of location at which the given traversal ends.\n\nC++: bdsg::SnarlDistanceIndex::ends_at(const struct handlegraph::net_handle_t &) const --> enum handlegraph::SnarlDecomposition::endpoint_t", pybind11::arg("traversal"));
+		cl.def("get_rank_in_parent", (unsigned long (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::get_rank_in_parent, "C++: bdsg::SnarlDistanceIndex::get_rank_in_parent(const struct handlegraph::net_handle_t &) const --> unsigned long", pybind11::arg("net"));
+		cl.def("connected_component_count", (unsigned long (bdsg::SnarlDistanceIndex::*)() const) &bdsg::SnarlDistanceIndex::connected_component_count, "How many connected components are in this graph?\n This returns the number of topological connected components, not necessarily the \n number of nodes in the top-level snarl \n\nC++: bdsg::SnarlDistanceIndex::connected_component_count() const --> unsigned long");
+		cl.def("get_parent_traversal", (struct handlegraph::net_handle_t (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &, const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::get_parent_traversal, "Get a net handle for traversals of a snarl or chain that contains\n the given oriented bounding node traversals or sentinels. Given two\n sentinels for a snarl, produces a net handle to a start-to-end,\n end-to-end, end-to-start, or start-to-start traversal of that snarl.\n Given handles to traversals of the bounding nodes of a chain, similarly\n produces a net handle to a traversal of the chain.\n\n For a chain, either or both handles can also be a snarl containing tips,\n for a tip-to-start, tip-to-end, start-to-tip, end-to-tip, or tip-to-tip\n traversal. Similarly, for a snarl, either or both handles can be a chain\n in the snarl that contains internal tips, or that has no edges on the\n appropriate end.\n\n May only be called if a path actually exists between the given start\n and end.\n\nC++: bdsg::SnarlDistanceIndex::get_parent_traversal(const struct handlegraph::net_handle_t &, const struct handlegraph::net_handle_t &) const --> struct handlegraph::net_handle_t", pybind11::arg("traversal_start"), pybind11::arg("traversal_end"));
 		cl.def_static("get_record_handle_type", (const enum bdsg::SnarlDistanceIndex::net_handle_record_t (*)(enum bdsg::SnarlDistanceIndex::record_t)) &bdsg::SnarlDistanceIndex::get_record_handle_type, "C++: bdsg::SnarlDistanceIndex::get_record_handle_type(enum bdsg::SnarlDistanceIndex::record_t) --> const enum bdsg::SnarlDistanceIndex::net_handle_record_t", pybind11::arg("type"));
 		cl.def_static("get_record_offset", (const unsigned long (*)(const struct handlegraph::net_handle_t &)) &bdsg::SnarlDistanceIndex::get_record_offset, "The offset into records that this handle points to\n\nC++: bdsg::SnarlDistanceIndex::get_record_offset(const struct handlegraph::net_handle_t &) --> const unsigned long", pybind11::arg("net_handle"));
 		cl.def_static("get_node_record_offset", (const unsigned long (*)(const struct handlegraph::net_handle_t &)) &bdsg::SnarlDistanceIndex::get_node_record_offset, "C++: bdsg::SnarlDistanceIndex::get_node_record_offset(const struct handlegraph::net_handle_t &) --> const unsigned long", pybind11::arg("net_handle"));
@@ -641,15 +656,22 @@ void bind_bdsg_snarl_distance_index(std::function< pybind11::module &(std::strin
 		cl.def_static("get_end_endpoint", (const enum handlegraph::SnarlDecomposition::endpoint_t (*)(enum bdsg::SnarlDistanceIndex::connectivity_t)) &bdsg::SnarlDistanceIndex::get_end_endpoint, "C++: bdsg::SnarlDistanceIndex::get_end_endpoint(enum bdsg::SnarlDistanceIndex::connectivity_t) --> const enum handlegraph::SnarlDecomposition::endpoint_t", pybind11::arg("connectivity"));
 		cl.def_static("get_end_endpoint", (const enum handlegraph::SnarlDecomposition::endpoint_t (*)(const struct handlegraph::net_handle_t &)) &bdsg::SnarlDistanceIndex::get_end_endpoint, "C++: bdsg::SnarlDistanceIndex::get_end_endpoint(const struct handlegraph::net_handle_t &) --> const enum handlegraph::SnarlDecomposition::endpoint_t", pybind11::arg("net"));
 		cl.def_static("connectivity_to_endpoints", (const struct std::pair<enum handlegraph::SnarlDecomposition::endpoint_t, enum handlegraph::SnarlDecomposition::endpoint_t> (*)(const enum bdsg::SnarlDistanceIndex::connectivity_t &)) &bdsg::SnarlDistanceIndex::connectivity_to_endpoints, "C++: bdsg::SnarlDistanceIndex::connectivity_to_endpoints(const enum bdsg::SnarlDistanceIndex::connectivity_t &) --> const struct std::pair<enum handlegraph::SnarlDecomposition::endpoint_t, enum handlegraph::SnarlDecomposition::endpoint_t>", pybind11::arg("connectivity"));
+		cl.def("set_snarl_size_limit", (void (bdsg::SnarlDistanceIndex::*)(unsigned long)) &bdsg::SnarlDistanceIndex::set_snarl_size_limit, "C++: bdsg::SnarlDistanceIndex::set_snarl_size_limit(unsigned long) --> void", pybind11::arg("size"));
 		cl.def("net_handle_as_string", (std::string (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &) const) &bdsg::SnarlDistanceIndex::net_handle_as_string, "C++: bdsg::SnarlDistanceIndex::net_handle_as_string(const struct handlegraph::net_handle_t &) const --> std::string", pybind11::arg("net"));
+		cl.def("traverse_decomposition", (bool (bdsg::SnarlDistanceIndex::*)(const class std::function<bool (const struct handlegraph::net_handle_t &)> &, const class std::function<bool (const struct handlegraph::net_handle_t &)> &, const class std::function<bool (const struct handlegraph::net_handle_t &)> &) const) &bdsg::SnarlDistanceIndex::traverse_decomposition, "C++: bdsg::SnarlDistanceIndex::traverse_decomposition(const class std::function<bool (const struct handlegraph::net_handle_t &)> &, const class std::function<bool (const struct handlegraph::net_handle_t &)> &, const class std::function<bool (const struct handlegraph::net_handle_t &)> &) const --> bool", pybind11::arg("snarl_iteratee"), pybind11::arg("chain_iteratee"), pybind11::arg("node_iteratee"));
+		cl.def("traverse_decomposition_helper", (bool (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t &, const class std::function<bool (const struct handlegraph::net_handle_t &)> &, const class std::function<bool (const struct handlegraph::net_handle_t &)> &, const class std::function<bool (const struct handlegraph::net_handle_t &)> &) const) &bdsg::SnarlDistanceIndex::traverse_decomposition_helper, "C++: bdsg::SnarlDistanceIndex::traverse_decomposition_helper(const struct handlegraph::net_handle_t &, const class std::function<bool (const struct handlegraph::net_handle_t &)> &, const class std::function<bool (const struct handlegraph::net_handle_t &)> &, const class std::function<bool (const struct handlegraph::net_handle_t &)> &) const --> bool", pybind11::arg("net"), pybind11::arg("snarl_iteratee"), pybind11::arg("chain_iteratee"), pybind11::arg("node_iteratee"));
 		cl.def("print_self", (void (bdsg::SnarlDistanceIndex::*)() const) &bdsg::SnarlDistanceIndex::print_self, "C++: bdsg::SnarlDistanceIndex::print_self() const --> void");
 		cl.def("print_descendants_of", (void (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t) const) &bdsg::SnarlDistanceIndex::print_descendants_of, "C++: bdsg::SnarlDistanceIndex::print_descendants_of(const struct handlegraph::net_handle_t) const --> void", pybind11::arg("net"));
+		cl.def("print_snarl_stats", (void (bdsg::SnarlDistanceIndex::*)() const) &bdsg::SnarlDistanceIndex::print_snarl_stats, "C++: bdsg::SnarlDistanceIndex::print_snarl_stats() const --> void");
+		cl.def("write_snarls_to_json", (void (bdsg::SnarlDistanceIndex::*)() const) &bdsg::SnarlDistanceIndex::write_snarls_to_json, "C++: bdsg::SnarlDistanceIndex::write_snarls_to_json() const --> void");
 		cl.def("validate_index", (void (bdsg::SnarlDistanceIndex::*)() const) &bdsg::SnarlDistanceIndex::validate_index, "C++: bdsg::SnarlDistanceIndex::validate_index() const --> void");
 		cl.def("validate_descendants_of", (void (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t) const) &bdsg::SnarlDistanceIndex::validate_descendants_of, "C++: bdsg::SnarlDistanceIndex::validate_descendants_of(const struct handlegraph::net_handle_t) const --> void", pybind11::arg("net"));
 		cl.def("validate_ancestors_of", (void (bdsg::SnarlDistanceIndex::*)(const struct handlegraph::net_handle_t) const) &bdsg::SnarlDistanceIndex::validate_ancestors_of, "C++: bdsg::SnarlDistanceIndex::validate_ancestors_of(const struct handlegraph::net_handle_t) const --> void", pybind11::arg("net"));
 		cl.def("get_usage", (class std::tuple<unsigned long, unsigned long, unsigned long> (bdsg::SnarlDistanceIndex::*)()) &bdsg::SnarlDistanceIndex::get_usage, "C++: bdsg::SnarlDistanceIndex::get_usage() --> class std::tuple<unsigned long, unsigned long, unsigned long>");
-		cl.def_static("sum", (unsigned long (*)(const class std::vector<unsigned long>)) &bdsg::SnarlDistanceIndex::sum, "Add integers, returning max() if any of them are max()\n\nC++: bdsg::SnarlDistanceIndex::sum(const class std::vector<unsigned long>) --> unsigned long", pybind11::arg("vals"));
+		cl.def_static("sum", (unsigned long (*)(const unsigned long &, const unsigned long &)) &bdsg::SnarlDistanceIndex::sum, "Add integers, returning max() if any of them are max()\n\nC++: bdsg::SnarlDistanceIndex::sum(const unsigned long &, const unsigned long &) --> unsigned long", pybind11::arg("val1"), pybind11::arg("val2"));
+		cl.def_static("sum", (unsigned long (*)(const class std::vector<unsigned long> &)) &bdsg::SnarlDistanceIndex::sum, "C++: bdsg::SnarlDistanceIndex::sum(const class std::vector<unsigned long> &) --> unsigned long", pybind11::arg("vals"));
 		cl.def_static("minus", (unsigned long (*)(unsigned long, unsigned long)) &bdsg::SnarlDistanceIndex::minus, "C++: bdsg::SnarlDistanceIndex::minus(unsigned long, unsigned long) --> unsigned long", pybind11::arg("x"), pybind11::arg("y"));
+		cl.def_static("maximum", (unsigned long (*)(unsigned long, unsigned long)) &bdsg::SnarlDistanceIndex::maximum, "C++: bdsg::SnarlDistanceIndex::maximum(unsigned long, unsigned long) --> unsigned long", pybind11::arg("x"), pybind11::arg("y"));
 		cl.def_static("bit_width", (unsigned long (*)(unsigned long)) &bdsg::SnarlDistanceIndex::bit_width, "C++: bdsg::SnarlDistanceIndex::bit_width(unsigned long) --> unsigned long", pybind11::arg("value"));
 		cl.def("time_accesses", (void (bdsg::SnarlDistanceIndex::*)()) &bdsg::SnarlDistanceIndex::time_accesses, "C++: bdsg::SnarlDistanceIndex::time_accesses() --> void");
 	}
diff --git a/bdsg/deps/libhandlegraph b/bdsg/deps/libhandlegraph
index f2ccd4ce..a9e33664 160000
--- a/bdsg/deps/libhandlegraph
+++ b/bdsg/deps/libhandlegraph
@@ -1,1 +1,1 @@
-Subproject commit f2ccd4ce02e4c92cf011bedb62db1f86aa2489da
+Subproject commit a9e33664ab73a3751f139bc4a7d07098de9e8515
diff --git a/bdsg/docs/conf.py b/bdsg/docs/conf.py
index 24d63ce0..36d9812d 100644
--- a/bdsg/docs/conf.py
+++ b/bdsg/docs/conf.py
@@ -57,7 +57,7 @@
 
 # -- Breathe Configuration ---------------------------------------------------
 
-breathe_projects = { "bdsg": "../build/doxygen/xml" }
+breathe_projects = { "bdsg": "../../build/doxygen/xml" }
 breathe_default_project = "bdsg"
 
 # -- General configuration ---------------------------------------------------
diff --git a/bdsg/docs/requirements.txt b/bdsg/docs/requirements.txt
index a0721438..1986c992 100644
--- a/bdsg/docs/requirements.txt
+++ b/bdsg/docs/requirements.txt
@@ -1,6 +1,6 @@
 alabaster==0.7.12
 Babel==2.8.0
-breathe==4.13.0
+breathe==4.34.0
 certifi==2020.6.20
 chardet==3.0.4
 docutils==0.16
@@ -15,14 +15,14 @@ pytz==2020.1
 requests==2.24.0
 six==1.15.0
 snowballstemmer==2.0.0
-Sphinx==1.8.5
+Sphinx==5.1.1
 sphinx-rtd-theme==0.5.0
 sphinxcontrib-applehelp==1.0.2
 sphinxcontrib-devhelp==1.0.2
-sphinxcontrib-htmlhelp==1.0.3
+sphinxcontrib-htmlhelp==2.0.0
 sphinxcontrib-jsmath==1.0.1
 sphinxcontrib-qthelp==1.0.3
-sphinxcontrib-serializinghtml==1.1.4
+sphinxcontrib-serializinghtml==1.1.5
 sphinxcontrib-websupport==1.2.4
 urllib3==1.25.11
 
diff --git a/bdsg/docs/rst/api.rst b/bdsg/docs/rst/api.rst
index 525277f8..8f629d94 100644
--- a/bdsg/docs/rst/api.rst
+++ b/bdsg/docs/rst/api.rst
@@ -33,6 +33,11 @@ The module contains definitions for different types of handles. THese are refere
    :members:
    :inherited-members:
    
+.. autoclass:: bdsg.handlegraph.net_handle_t
+   :show-inheritance:
+   :members:
+   :inherited-members:
+
 ----------------
 Graph Interfaces
 ----------------
@@ -117,7 +122,18 @@ Orthogonal to the mutability and paths hierarchy, there is a :class:`bdsg.handle
    :show-inheritance:
    :members:
    :inherited-members:
-   
+ 
+~~~~~~~~~~~~~~~~~~
+SnarlDecomposition
+~~~~~~~~~~~~~~~~~~
+
+A "snarl decomposition" describes the decomposition of the graph into nested substructures known as snarls and chains. The :class:`bdsg.handlegraph.SnarlDecomposition` interface defines methods for traversing the snarl decomposition of a graph using :class:`bdsg.handelgraph.net_handle_t`.
+
+.. autoclass:: bdsg.handlegraph.SnarlDecomposition
+   :show-inheritance:
+   :members:
+   :inherited-members:
+     
 ====================================
 libbdsg Handle Graph Implementations
 ====================================
@@ -159,7 +175,21 @@ ODGI
 .. autoclass:: bdsg.bdsg.ODGI
    :show-inheritance:
    :members:
-   
+
+----------------------------------
+SnarlDecomposition Implementations
+----------------------------------
+
+There is one implementation for a snarl decomposition
+
+~~~~~~~~~~~~~~~~~~
+SnarlDistanceIndex
+~~~~~~~~~~~~~~~~~~
+
+.. autoclass:: bdsg.bdsg.SnarlDistanceIndex
+   :show-inheritance:
+   :members:
+
 --------------
 Graph Overlays
 --------------
@@ -221,5 +251,3 @@ Here is an example of how to use these typed collections:
     
 .. autoclass:: vector_unsigned_long
     :members:
-
-
diff --git a/bdsg/docs/rst/cppapi.rst b/bdsg/docs/rst/cppapi.rst
index 5ad83aaf..ceaeec10 100644
--- a/bdsg/docs/rst/cppapi.rst
+++ b/bdsg/docs/rst/cppapi.rst
@@ -24,6 +24,8 @@ The namespace contains definitions for different types of handles. THese are ref
 
 .. doxygenstruct:: handlegraph::step_handle_t
 
+.. doxygenstruct:: handlegraph::net_handle_t
+
 ----------------
 Graph Interfaces
 ----------------
@@ -97,6 +99,15 @@ Orthogonal to the mutability and paths hierarchy, there is a :cpp:class:`handleg
 .. doxygenclass:: handlegraph::SerializableHandleGraph
    :members:
 
+~~~~~~~~~~~~~~~~~~~~~~~
+SnarlDecomposition
+~~~~~~~~~~~~~~~~~~~~~~~
+
+A "snarl decomposition" describes the decomposition of the graph into nested substructures known as snarls and chains. The :cpp:class:`handlegraph::SnarlDecomposition` interface defines methods for traversing the snarl decomposition of a graph using :cpp:class:`handlegraph::net_handle_t`.
+
+.. doxygenclass:: handlegraph::SnarlDecomposition
+   :members:
+
 ====================================
 libbdsg Handle Graph Implementations
 ====================================
@@ -129,6 +140,19 @@ ODGI
    
 .. doxygenclass:: bdsg::ODGI
    :members:
+
+-----------------------------------
+Snarl Decomposition Implementations
+-----------------------------------
+
+There is one implementation for a snarl decomposition
+
+~~~~~~~~~~~~~~~~~~
+SnarlDistanceIndex
+~~~~~~~~~~~~~~~~~~
+
+.. doxygenclass:: bdsg::SnarlDistanceIndex
+   :members:
    
 --------------
 Graph Overlays
@@ -183,7 +207,3 @@ All these overlay helpers are really instantiations of a couple of templates:
    :undoc-members:
 
 
-
-
-
-
diff --git a/bdsg/include/bdsg/internal/mapped_structs.hpp b/bdsg/include/bdsg/internal/mapped_structs.hpp
index ce21978e..8b073b7d 100644
--- a/bdsg/include/bdsg/internal/mapped_structs.hpp
+++ b/bdsg/include/bdsg/internal/mapped_structs.hpp
@@ -2147,6 +2147,11 @@ void UniqueMappedPointer<T>::load_after_prefix(std::istream& in, const std::stri
     // Drop any existing chain.
     reset();
     
+    if (!in) {
+        // Notice if something goes wrong
+        throw std::runtime_error("Stream is in a bad state and cannot be used for input!");
+    }
+    
     const size_t MAX_CHUNK_SIZE = 4096;
     
     // Fill up this buffer with chunks of a certian size
@@ -2155,17 +2160,28 @@ void UniqueMappedPointer<T>::load_after_prefix(std::istream& in, const std::stri
     // Make the chain through the Manager
     chain = Manager::create_chain([&]() {
         if (buffer.empty() && !prefix.empty()) {
-            // Inject the prefix on the first call
+            // Inject the prefix on the first call.
+            // (Or on any call after hitting EOF and returning "", so don't keep calling us)
             buffer = prefix;
+        } else if (in.eof()) {
+            // Show an empty buffer for EOF
+            buffer.clear();
         } else {
             // Other calls read data, until the last call shows an empty buffer
             // for EOF.
             buffer.resize(MAX_CHUNK_SIZE);
             // Grab a chunk
-            in.read(&buffer.at(0), MAX_CHUNK_SIZE);
             if (!in) {
+                // Notice if something goes wrong
+                throw std::runtime_error("Error before reading chunk from stream!");
+            }
+            in.read(&buffer.at(0), MAX_CHUNK_SIZE);
+            if (in.eof()) {
                 // Didn't read all the characters, so shrink down (maybe to 0)
                 buffer.resize(in.gcount());
+            } else if (!in) {
+                // Input error not co-occuirring with EOF
+                throw std::runtime_error("Error reading chunk from stream!");
             }
         }
         // Copy the buffer over to the caller.
@@ -2223,6 +2239,11 @@ void UniqueMappedPointer<T>::save(const std::function<void(const void*, size_t)>
 
 template<typename T>
 void UniqueMappedPointer<T>::save_after_prefix(std::ostream& out, const std::string& prefix) const {
+    if (!out) {
+        // Notice if something goes wrong
+        throw std::runtime_error("Stream is in a bad state and cannot be used for output!");
+    }
+    
     // We need to drop as many characters from the chain as are in the prefix.
     size_t dropped = 0;
      
@@ -2237,7 +2258,11 @@ void UniqueMappedPointer<T>::save_after_prefix(std::ostream& out, const std::str
         dropped += to_drop;
         
         // And save it to the stream.
-        out.write(start_char, length); 
+        out.write(start_char, length);
+        if (!out) {
+            // Notice if something goes wrong
+            throw std::runtime_error("Error writing chunk to stream!");
+        }
     });
 }
 
diff --git a/bdsg/include/bdsg/snarl_distance_index.hpp b/bdsg/include/bdsg/snarl_distance_index.hpp
index 3637edf0..125d9554 100644
--- a/bdsg/include/bdsg/snarl_distance_index.hpp
+++ b/bdsg/include/bdsg/snarl_distance_index.hpp
@@ -10,9 +10,41 @@
 #include <handlegraph/trivially_serializable.hpp>
 #include <bdsg/internal/mapped_structs.hpp>
 #include <string>
+#include <numeric>
 #include <arpa/inet.h>
+ /**
+  * This defines the distance index, which also serves as a snarl tree that implements libhandlegraph's 
+  * SnarlDecomposition interface
+  *
+  * The distance index is used to find the minimum distance between two positions on the graph
+  * The structure of the distance index is based on the snarl tree. 
+  * Variation graphs can be decomposed into nested substructures called "snarls" and "chains, and the 
+  * decomposition is described by the snarl tree
+  * The distance index provides an interface to traverse the snarl tree and to find minimum distances
+  * between two sibling nodes in the snarl tree (eg between two chains that are children of the same snarl)
+  * The distance index can also be built without distances and used just to traverse the snarl tree
+  *
+  * A chain is comprised of at least one node and may also contain snarls. 
+  * Each snarl is comprised of child chains and is bounded by two boundary nodes. 
+  * The boundary nodes are not part of the snarl, but are represented in the snarl as sentinels
+  * Trivial snarls (with only one edge between the boundary nodes) are not represented, but a snarl may 
+  * have no nodes if it has other edges
+  *
+  * The root of a snarl tree contains child chains. The children of the root are not necessarily connected
+  * components in the graph- there may be connectivity between chains that are children of the root
+  * The depth of the root is 0, the depth of its child chains is 1, the depth of the nodes and snarls that are 
+  * children of those chains is also 1, and the chains that are children of those snarls have depth 2
+  *
+  * All structures in the snarl tree have two sides that can define the orientation of a traversal 
+  * A forward traversal of a node is always based on the node's orientation 
+  * A forward traversal of a snarl or chain goes from its start boundary node to its end boundary node
+  * Nodes and snarls can also be oriented backwards relative to the orientation of the parent chain- 
+  * if a traversal of a chain going start to end traverses a child end to start. Then the child would 
+  * be considered to be reversed in its parent
+  *
+  */
+
 
-//TODO: get_record_handle_type isn't going to be accurate for simple snarls since they can represent nodes too
 
 //How to hash pairs, copied from vg
 // http://stackoverflow.com/questions/4870437/pairint-int-pair-as-key-of-unordered-map-issue#comment5439557_4870467
@@ -89,13 +121,16 @@ namespace bdsg {
 using namespace sdsl;
 using namespace std;
 using namespace handlegraph;
-/**
- * The distance index. Stores minimum distances among nodes in each 
- * snarl's netgraph and each chain.
- * Also used to store the snarl tree
- */
-
 
+/**
+  * The distance index, which also acts as a snarl decomposition.
+  *
+  * The distance index provides an interface to traverse the snarl tree and to find minimum distances
+  * between two sibling nodes in the snarl tree (eg between two chains that are children of the same snarl).
+  *
+  * It also provides a method for quickly calculating the minimum distance between two positions on the graph.
+  *
+  */
 class SnarlDistanceIndex : public SnarlDecomposition, public TriviallySerializable {
 
 public:
@@ -105,7 +140,7 @@ class SnarlDistanceIndex : public SnarlDecomposition, public TriviallySerializab
 public:
 
     //Serialize and deserialize from TriviallySerializable
-    //
+
     using TriviallySerializable::serialize;
     using TriviallySerializable::deserialize;
     void dissociate();
@@ -122,499 +157,374 @@ class SnarlDistanceIndex : public SnarlDecomposition, public TriviallySerializab
     std::string get_prefix() const;
 
 
-public:
-
-
-////////////////// SnarlDecomposition methods
-
-    /**
-     * Get a net handle referring to a tip-to-tip traversal of the contents of the root snarl.
-     * TODO: Special handling for circular things in the root snarl? Circular traversal type?
-     */
-    net_handle_t get_root() const ;
-    
-    /**
-     * Return true if the given handle refers to (a traversal of) the root
-     * snarl, and false otherwise.
-     */
-    bool is_root(const net_handle_t& net) const;
-    /**
-     * Return true if the given handle refers to (a traversal of) a snarl of the root,
-     * which is considered to be the root but actually refers to a subset of the children 
-     * of the root that are connected
-     */
-    bool is_root_snarl(const net_handle_t& net) const;
-    
-    /**
-     * Returns true if the given net handle refers to (a traversal of) a snarl.
-     */
-    bool is_snarl(const net_handle_t& net) const;
-    bool is_simple_snarl(const net_handle_t& net) const;
-    /**
-     * Returns true if the given net handle refers to (a traversal of) a chain.
-     */
-    bool is_chain(const net_handle_t& net) const;
-    bool is_multicomponent_chain(const net_handle_t& net) const;
-    /**
-     * Returns true if the given net handle refers to (a traversal of) a chain that loops (a chain where the first and last node are the same).
-     */
-    bool is_looping_chain(const net_handle_t& net) const;
-    /**
-     * Returns true if the given net handle refers to (a traversal of) a trivial chain that represents a single node.
-     */
-    bool is_trivial_chain(const net_handle_t& net) const;
-    /**
-     * Returns true if the given net handle refers to (a traversal of) a single node, and thus has a corresponding handle_t.
-     */
-    bool is_node(const net_handle_t& net) const;
-    /**
-     * Return true if the given net handle is a snarl bound sentinel (in either
-     * inward or outward orientation), and false otherwise.
-     */
-    bool is_sentinel(const net_handle_t& net) const;
-    
-    /**
-     * Turn a handle to an oriented node into a net handle for a start-to-end or end-to-start traversal of the node, as appropriate.
-     */
-    net_handle_t get_net(const handle_t& handle, const handlegraph::HandleGraph* graph) const;
-    
-    /**
-     * For a net handle to a traversal of a single node, get the handle for that node in the orientation it is traversed.
-     * May not be called for other net handles.
-     */
-    handle_t get_handle(const net_handle_t& net, const handlegraph::HandleGraph* graph) const;
-    
-    /**
-     * Get the parent snarl of a chain, or the parent chain of a snarl or node.
-     * If the child is start-to-end or end-to-start, and the parent is a chain,
-     * the chain comes out facing the same way, accounting for the relative
-     * orientation of the child snarl or node in the chain. Otherwise,
-     * everything is produced as start-to-end, even if that is not actually a
-     * realizable traversal of a snarl or chain. May not be called on the root
-     * snarl.
-     *
-     * Also works on snarl boundary sentinels.
-     */
-    net_handle_t get_parent(const net_handle_t& child) const;
-    
-    
-    // We have sentinel net_handle_t values for the start/end of each snarl, so
-    // that we can tell which last edge a traversal of the contents of a snarl
-    // takes when we represent it as a list of net_handle_t items. We also use
-    // these to query what's attached to the snarl start/end when traversing,
-    // and to see self loops immediately inside the snarl. These may actually
-    // just be the handles for the nodes at the start'end of the snarl with
-    // special flags set.
-    //
-    // For chains, we use the net handles to the appropriate first/last nodes
-    // in the appropriate orientation.
-    // The chain bound of a looping chain will have connectivity with the same
-    // start/end point when it is for the end of the chain; the connectivity
-    // will be start-start if it is going backwards in the node, and end-end
-    // if it is going forwards
-    
-    /**
-     * Get the bounding handle for the snarl or chain referenced by the given
-     * net handle, getting the start or end facing in or out as appropriate.
-     *
-     * For snarls, returns the bounding sentinel net handles. For chains,
-     * returns net handles for traversals of the bounding nodes of the chain.
-     *
-     * Ignores traversal type.
-     *
-     * May not be called on traversals of individual nodes.
-     */
-    net_handle_t get_bound(const net_handle_t& snarl, bool get_end, bool face_in) const;
-
-    /** 
-     * Given the sentinel of a snarl, return a handle to the node representing it
-     */
-    net_handle_t get_node_from_sentinel(const net_handle_t& sentinel) const;
+////////////////////////////////////  How we define different properties of a net handle
 
-    
-    /**
-     * Return a net handle to the same snarl/chain/node in the opposite orientation.
-     * No effect on tip-to-tip, start-to-start, or end-to-end net handles. Flips all the others.
-     */
-    net_handle_t flip(const net_handle_t& net) const;
-    
-    /**
-     * Get a canonical traversal handle from any net handle. All handles to the
-     * same net graph element have the same canonical traversal. That canonical
-     * traversal must be realizable, and might not always be start-to-end or
-     * even consistently be the same kind of traversal for different snarls,
-     * chains, or nodes. Mostly useful to normalize for equality comparisons.
-     */
-    net_handle_t canonical(const net_handle_t& net) const;
-
-    /**
-     * Return the kind of location at which the given traversal starts.
-     */
-    endpoint_t starts_at(const net_handle_t& traversal) const;
-    
-    /**
-     * Return the kind of location at which the given traversal ends.
-     */
-    endpoint_t ends_at(const net_handle_t& traversal) const;
-
-    /**
-     *
-     */
-    size_t get_rank_in_parent(const net_handle_t& net) const;
-
-    /**
-     * How many connected components are in this graph?
-     * This returns the number of topological connected components, not necessarily the 
-     * number of nodes in the top-level snarl 
-     */
-    size_t connected_component_count() const;
+    public:
 
-protected:
-    /**
-     * Internal implementation for for_each_child.
-     */
-    bool for_each_child_impl(const net_handle_t& traversal, const std::function<bool(const net_handle_t&)>& iteratee) const;
+    ///The connectivity of a net_handle- this defines the direction that the net_handle is traversed
+    enum connectivity_t { START_START=1, START_END, START_TIP, 
+                            END_START, END_END, END_TIP, 
+                            TIP_START, TIP_END, TIP_TIP};
 
-    /**
-     * Internal implementation for for_each_traversal.
-     */
-    bool for_each_traversal_impl(const net_handle_t& item, const std::function<bool(const net_handle_t&)>& iteratee) const;
+    ///Type of a net_handle_t, which may not be the type of the record
+    ///This is to allow a node record to be seen as a chain from the perspective of a handle
+    enum net_handle_record_t {ROOT_HANDLE=0, NODE_HANDLE, SNARL_HANDLE, CHAIN_HANDLE, SENTINEL_HANDLE};
 
-    /**
-     * Internal implementation for follow_net_edges.
-     */
-    bool follow_net_edges_impl(const net_handle_t& here, const handlegraph::HandleGraph* graph, bool go_left, const std::function<bool(const net_handle_t&)>& iteratee) const;
+/////////////////////////////  functions for distance calculations using net_handle_t's 
 
 public:
 
 
-        /**
-     * Get a net handle for traversals of a snarl or chain that contains
-     * the given oriented bounding node traversals or sentinels. Given two
-     * sentinels for a snarl, produces a net handle to a start-to-end,
-     * end-to-end, end-to-start, or start-to-start traversal of that snarl.
-     * Given handles to traversals of the bounding nodes of a chain, similarly
-     * produces a net handle to a traversal of the chain.
-     *
-     * For a chain, either or both handles can also be a snarl containing tips,
-     * for a tip-to-start, tip-to-end, start-to-tip, end-to-tip, or tip-to-tip
-     * traversal. Similarly, for a snarl, either or both handles can be a chain
-     * in the snarl that contains internal tips, or that has no edges on the
-     * appropriate end.
-     *
-     * May only be called if a path actually exists between the given start
-     * and end.
-     */
-    net_handle_t get_parent_traversal(const net_handle_t& traversal_start, const net_handle_t& traversal_end) const;
-///////////////////////////// More public functions for distance calculations using net_handle_t's 
-
-public:
-    /**
-     * Find the distance between the two child node sides in the parent, facing each other, not 
-     * including the lengths of the nodes
-     * This only takes into account the endpoint of the net_handle_t traversal, it does not care if the traversal
-     * was possible. Doesn't allow you to find the distance from a traversal ending/starting in a tip
-     * requires that the children are children of the parent
-     * For chains, the distance to/from a snarl is really the distance from the outer node of the snarl
-     * Returns std::numeric_limits<size_t>::max() if there is not path between them in the parent 
-     * or if they are not children of the parent
-     *
-     * Distance limit is the distance after which we give up if we're doing a traversal
-     */
+    ///Get the minimum distance between two positions in the graph.
+    ///If unoriented_distance is true, then ignore the orientations of the positions.
+    ///Otherwise, distance is calculated from the first position going forward to the second position going forward.
+    ///The distance includes one of the positions; the distance from one position to itself is 0.
+    ///Returns std::numeric_limits<size_t>::max() if there is no path between the two positions.
+    ///
+    ///distance_traceback are is helping to find actual distance path. For each of the nodes, keep a vector of the ancestors of the node
+    ///and the distance and direction (as + or - values of the distance) taken in the minimum distance path to get to the start and end of the parent.
+    ///
+    ///For example, if the first node is traversed forward and only reaches the end node of its parent chain, then the values stored will be <inf, +distance>.
+    ///If it were traversed backwards to reach the start node and couldn't reach the end node, then the values stored would be <-distance, inf>.
+    ///The distance value is the distance to the end of the node to the and of the chain/snarl, and distances stored are distances within the net_handle associated with it.
+    ///So the first value in the vector will always be node itself and the offset in the node, and the second value will be the parent chain and the distance from the.
+    ///ends of the node to the ends of the parent ( or the distance between nodes in the chain).
+    ///The last value of the two nodes should match (in the absolute value at least). It will be the common ancestor node and the distances will be the distance to the 
+    ///start/end of the other node with the same meaning for the sign of the distance.
+    ///The hints will go up to the lowest common ancestor needed for finding the shortest distance, which may or may not be the LCA or the root.
+    size_t minimum_distance(const handlegraph::nid_t id1, const bool rev1, const size_t offset1, const handlegraph::nid_t id2, 
+                            const bool rev2, const size_t offset2, bool unoriented_distance = false, const HandleGraph* graph=nullptr, 
+                            pair<vector<tuple<net_handle_t, int32_t, int32_t>>, vector<tuple<net_handle_t, int32_t, int32_t>>>* distance_traceback=nullptr) const ;
+
+    ///Find an approximation of the maximum distance between two positions. 
+    ///This isn't a true maximum- the only guarantee is that it's greater than or equal to the minimum distance.
+    size_t maximum_distance(const handlegraph::nid_t id1, const bool rev1, const size_t offset1, const handlegraph::nid_t id2, 
+                            const bool rev2, const size_t offset2, bool unoriented_distance = false, const HandleGraph* graph=nullptr) const ;
+
+    //Find the distance between the two child node sides in the parent, facing each other, not 
+    //including the lengths of the nodes.
+    //This only takes into account the endpoint of the net_handle_t traversal, it does not care if the traversal
+    //was possible. Doesn't allow you to find the distance from a traversal ending/starting in a tip.
+    //requires that the children are children of the parent.
+    //For chains, the distance to/from a snarl is really the distance from the outer node of the snarl.
+    //Returns std::numeric_limits<size_t>::max() if there is not path between them in the parent 
+    //or if they are not children of the parent.
+    //Distance limit is the distance after which we give up if we're doing a traversal.
     size_t distance_in_parent(const net_handle_t& parent, const net_handle_t& child1, const net_handle_t& child2, const HandleGraph* graph=nullptr, size_t distance_limit = std::numeric_limits<size_t>::max()) const;
 
-    size_t distance_to_parent_bound(net_handle_t& parent, bool to_start, net_handle_t& child, bool go_left) const;
+    ///Find the maximum distance between two children in the parent. 
+    ///This is the same as distance_in_parent for everything except children of chains
+    size_t max_distance_in_parent(const net_handle_t& parent, const net_handle_t& child1, const net_handle_t& child2, const HandleGraph* graph=nullptr, size_t distance_limit = std::numeric_limits<size_t>::max()) const;
+
+    ///Get the distance from the child to the start or end bound of the parent.
+    ///parent_and_child_types are hints to figure out the type of snarl/chain records the parent and child are.
+    ///tuple of parent record type, parent handle type, child record type, child handle type.
+    ///This is really just used to see if the parent and child are trivial chains, so it might not be exactly what the actual record is.
+    size_t distance_to_parent_bound(const net_handle_t& parent, bool to_start, net_handle_t child,
+                                    tuple<net_handle_record_t, net_handle_record_t, net_handle_record_t, net_handle_record_t> parent_and_child_types = make_tuple(ROOT_HANDLE, ROOT_HANDLE, ROOT_HANDLE, ROOT_HANDLE)) const;
+
+    ///If this node id and orientation is pointing into a snarl, then return the start.
+    ///node id and orientation pointing into the snarl, and if the snarl is trivial.
+    ///Returns <0, false, false> if it doesn't point into a snarl.
+    tuple<nid_t, bool, bool> into_which_snarl(const nid_t& id, const bool& reverse) const;
 
     
-    //Return true if child1 comes before child2 in the chain. 
+    ///Return true if child1 comes before child2 in the chain. 
     bool is_ordered_in_chain(const net_handle_t& child1, const net_handle_t& child2) const;
-    //Return the offset of the child in the chain
-    //TODO: I don't like exposing this because it doesn't really 
-    //mean anything but I need it
-    size_t get_record_offset_in_chain(const net_handle_t& child) const;
+
 
     bool is_externally_start_end_connected(const net_handle_t net) const {return is_externally_start_end_connected(snarl_tree_records->at(get_record_offset(net)));}
     bool is_externally_start_start_connected(const net_handle_t net) const {return is_externally_start_start_connected(snarl_tree_records->at(get_record_offset(net)));}
     bool is_externally_end_end_connected(const net_handle_t net) const {return is_externally_end_end_connected(snarl_tree_records->at(get_record_offset(net)));}
 
-    /** 
-     * For two net handles, get a net handle lowest common ancestor
-     * If the lowest common ancestor is the root, then the two handles may be in 
-     * different connected components. In this case, return false
-     */
+    ///For two net handles, get a net handle lowest common ancestor.
+    ///If the lowest common ancestor is the root, then the two handles may be in
+    ///different connected components. In this case, return false.
     pair<net_handle_t, bool> lowest_common_ancestor(const net_handle_t& net1, const net_handle_t& net2) const;
 
 
-    /**
-     * Return the length of the net, which must represent a node (or sentinel of a snarl)
-     */
+    ///Return the length of the net, which must represent a node (or sentinel of a snarl)
     size_t node_length(const net_handle_t& net) const ;
 
 
-    /**
-     * This is also the length of a net, but it can also be a snarl or chain. 
-     * The length of a chain includes the boundary nodes, a snarl does not
-     * A looping chain only includes the start/end node once
-     */
+    ///This is also the length of a net, but it can also be a snarl or chain. 
+    ///The length of a chain includes the boundary nodes, a snarl does not.
+    ///A looping chain only includes the start/end node once
     size_t minimum_length(const net_handle_t& net) const;
     size_t maximum_length(const net_handle_t& net) const;
 
-    /**
-    The length of a chain. If it is a multicomponent chain, then the length of 
-     the last component, which is used for calculating distance, instead of inf 
-    */
+    ///The length of a chain. If it is a multicomponent chain, then the length of 
+    ///the last component, which is used for calculating distance, instead of inf 
     size_t chain_minimum_length(const net_handle_t& net) const;
 
-    /**
-     * What is the node id of the node represented by this net handle
-     * net must be a node or a sentinel
-     */
+    ///What is the node id of the node represented by this net handle.
+    ///net must be a node or a sentinel
     nid_t node_id(const net_handle_t& net) const ;
 
-    /**
-     * Does the graph have this node?
-     */
+    ///Does the graph have this node?
     bool has_node(const nid_t id) const;
 
-    /**
-     * Only really relevant for nodes in chains, is the node
-     * traversed backwards relative to the orientation of the chain
-     */
-
+    ///Only really relevant for nodes in chains, is the node
+    ///traversed backwards relative to the orientation of the chain
     bool is_reversed_in_parent(const net_handle_t& net) const;
 
-    /**
-     * Get a net handle from a node
-     */
-    net_handle_t get_node_net_handle(const nid_t id) const;
+    ///Get a net handle from a node and, optionally, an orientation
+    net_handle_t get_node_net_handle(const nid_t id, bool rev = false) const;
 
-    /**
-     * How deep is the snarl tree? The root is 0, top-level chain is 1, etc
-     * Only counts chains
-     */
+    ///How deep is the snarl tree? The root is 0, top-level chain is 1, etc
+    ///Only counts chains
     size_t get_max_tree_depth() const;
 
-    /**
-     * What is the depth of this net handle. Nodes and snarls get the depth of their parent, the epth of the root is 0
-     */
+    ///What is the depth of this net handle? Nodes and snarls get the depth of their parent.
+    ///The depth of the root is 0, the depth of its child chains is 1, the depth of the nodes and snarls that are 
+    ///children of those chains is also 1, and the chains that are children of those snarls have depth 2
     size_t get_depth(const net_handle_t& net) const;
 
 
-    /**
-     * Given a handle, return a unique identifier for the connected component that it's on
-     * Connected components are based on the connectivity of the graph, so there may be fewer
-     * connected components than there are root-level structures. For example, if two root-level
-     * chains are connected to each other in the root, then they will be considered one connected
-     * component but two separate root-level chains
-     */
+    //Given a handle, return a unique identifier for the connected component that it's on.
+    //Connected components are based on the connectivity of the graph, so there may be fewer
+    //connected components than there are root-level structures. For example, if two root-level
+    //chains are connected to each other in the root, then they will be considered one connected
+    //component but two separate root-level chains.
     size_t get_connected_component_number(const net_handle_t& net) const;
 
-    /**
-     * Given the connected component number (from get_connected_component_number), get the
-     * root-level handle pointing to it.
-     * If the connected component is a root-level snarl, then this may return a "root" handle,
-     * but it will actually point to the snarl
-     */
+    ///Given the connected component number (from get_connected_component_number), get the
+    ///root-level handle pointing to it.
+    ///If the connected component is a root-level snarl, then this may return a "root" handle,
+    ///but it will actually point to the snarl
     net_handle_t get_handle_from_connected_component(size_t num) const;
 
 
+    ///Is there a path between the start and end endpoints within the net handle?
     bool has_connectivity(const net_handle_t& net, endpoint_t start, endpoint_t end) const ;
-    //TODO: bool has_external_connectivity(const net_handle_t& net, endpoint_t start, endpoint_t end) const {return has_external_connectivity((*records)->at(get_record_offset(net)));} 
-    bool has_external_connectivity(const net_handle_t& net, endpoint_t start, endpoint_t end) const ; 
 
+    ///Is there a path between the start and end endpoints outside the net handle?
+    ///This is used for children of the root
+    bool has_external_connectivity(const net_handle_t& net, endpoint_t start, endpoint_t end) const ; 
 
-    /**
-     * Get the minimum distance between two positions in the graph
-     * If unoriented_distance is true, then ignore the orientations of the positions
-     * Otherwise, distance is calculated from the first position going forward to the second position going forward
-     * The distance includes one of the positions; the distance from one position to itself is 0
-     * Returns std::numeric_limits<size_t>::max() if there is no path between the two positions
-     */
-    //TODO: The positions can't be const?
-    size_t minimum_distance(const handlegraph::nid_t id1, const bool rev1, const size_t offset1, const handlegraph::nid_t id2, const bool rev2, const size_t offset2, bool unoriented_distance = false, const HandleGraph* graph=nullptr) const ;
 
-    /**
-     * Get the distance index values for nodes in a chain
-     * These will all fail if the parent of net is not a chain
-     */
+    ///Get the prefix sum value for a node in a chain.
+    ///Fails if the parent of net is not a chain
     size_t get_prefix_sum_value(const net_handle_t net) const;
+
+    ///Get the prefix sum value for a node in a chain.
+    ///Fails if the parent of net is not a chain
     size_t get_forward_loop_value(const net_handle_t net) const;
+
+    ///Get the prefix sum value for a node in a chain.
+    ///Fails if the parent of net is not a chain
     size_t get_reverse_loop_value(const net_handle_t net) const;
-    //If get_end is true, then get the second component of the last node in a looping chain
-    //If the chain loops, then the first and last node are the same
-    //If it is also a multicomponent, chain, then it is in two different components
-    //If get_end is true, then get the larger of the two components
+
+    //If get_end is true, then get the second component of the last node in a looping chain.
+    //If the chain loops, then the first and last node are the same.
+    //If it is also a multicomponent, chain, then it is in two different components.
+    //If get_end is true, then get the larger of the two components.
     size_t get_chain_component(const net_handle_t net, bool get_end = false) const;
 
+
+
+public:
+
+
+////////////////// SnarlDecomposition methods
+
+    ///Get a net handle referring to a tip-to-tip traversal of the contents of the root snarl.
+    net_handle_t get_root() const ;
     
-//////////////////////////////////////////  The actual distance index
-private:
-    
-    /**
-     *
-     * This stores all records for the root, nodes, chains/snarls, and snarls' children
-     * 
-     * It's really made up of five types of vectors: 
-     * 
-     * - The (single) root vector has the format:
-     *   [root tag, # connected components, # nodes, min_node_id, [pointer to node/snarl/chain record] x N], [pointer to node] x M]
-     *   The root vector stores the root of every connected component, which can be a 
-     *   node, snarl, or chain
-     *
-     * - A chain record for each chain, which is interspersed node and snarl records:
-     *   [chain tag, #nodes, pointer to parent, min length, max length, rank in parent, start, end, pointer to last child
-     *       [ (node record), snarl record size, (snarl record), snarl record size] x N] 
-     *          (plus an extra node id, prefix sum, fd loop, rev loop at the end for the last node), 0, 0
-     *    The two 0's at the end indicates that it's the end of the chain
-     *    snarl_record_size is the number of things in the snarl record (so 0 if there is no snarl there)
-     *    start/end include the orientations
-     * 
-     * - A snarl record for each snarl, which are stuck in chains
-     *   [snarl tag, # nodes, pointer to parent, min length, max length, rank in parent, 
-     *      pointer to children (in child vector), start, end, distance vector]
-     *   Trivial snarls will still be contained within a chain
-     *   Single nodes will technically be contained in a chain, but not stored as a chain
-     *   The rank of the start node will always be 0 and the end node rank will be 1
-     *   start/end are the start and end nodes, include the orientations
-     *   For the first and last nodes, we only care about the node sides pointing in
-     *   Each node side in the actual distance matrix will be 2*(rank-1) for the left side, and 
-     *   2rank+1 for the right side, and 0 for the start, 1 for the end, where we only keep the 
-     *   inner node side of the start and end
-     *   Node count is the number of nodes, not including boundary nodes
-     *   
-     * - A node record for nodes in chains
-     *   TODO: make the pointer to the parent how far backwards to go to get to the beginning of the chain and
-     *   the last bit will be true if the node is reversed in the parent
-     *   [node tag, node id, pointer to parent, node length, prefix sum, fd loop, rev loop]
-     *
-     * - A node record for nodes in snarls/roots
-     *   These will be interspersed between chains more or less based on where they are in the snarl tree
-     *   [node tag, node id, pointer to parent, node length, rank in parent]
-     * 
-     * - The (single) child vector, listing children in snarls
-     *   [child vector tag, (pointer to records) x N
-     *   Each snarl will have a pointer into here, and will also know how many children it has
-     * 
-     * 
-     *   For each of the "rank_in_parent" fields, the last bit is 1 if it is reversed in the parent
-     *
-     */
+    ///Return true if the given handle refers to (a traversal of) the root
+    ///snarl, and false otherwise.
+    bool is_root(const net_handle_t& net) const;
+
+    ///Return true if the given handle refers to (a traversal of) a snarl of the root,
+    ///which is considered to be the root but actually refers to a subset of the children 
+    ///of the root that are connected
+    bool is_root_snarl(const net_handle_t& net) const;
     
-private:
-//TODO: This should definitely not be public
-    bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector> snarl_tree_records;
+    ///Returns true if the given net handle refers to (a traversal of) a snarl.
+    bool is_snarl(const net_handle_t& net) const;
 
-    /* If this is 0, then don't store distances
-     * Otherwise, for snarls with more children than snarl_size_limit, only store the distances
-     * that include boundary nodes (OVERSIZED_SNARL)
-     */
-    size_t snarl_size_limit = 1000;
+    ///Returns true if the given net handle refers to (a traversal of) a simple snarl
+    ///A simple snarl is a bubble where each child node can only reach the boundary nodes,
+    ///and each side of a node reaches a different boundary node
+    bool is_simple_snarl(const net_handle_t& net) const;
 
-/////////////////  Construction methods
-public:
+    ///Returns true if the given net handle refers to (a traversal of) a chain.
+    bool is_chain(const net_handle_t& net) const;
+    ///Returns true if the given net handle refers to (a traversal of) a chain that is not start-end connected
+    bool is_multicomponent_chain(const net_handle_t& net) const;
 
-    void set_snarl_size_limit (size_t size) {snarl_size_limit=size;}
+    ///Returns true if the given net handle refers to (a traversal of) a chain that loops (a chain where the first and last node are the same).
+    bool is_looping_chain(const net_handle_t& net) const;
 
+    ///Returns true if the given net handle refers to (a traversal of) a trivial chain that represents a single node.
+    bool is_trivial_chain(const net_handle_t& net) const;
 
+    ///Returns true if the given net handle refers to (a traversal of) a single node, and thus has a corresponding handle_t.
+    bool is_node(const net_handle_t& net) const;
 
+    ///Return true if the given net handle is a snarl bound sentinel (in either
+    ///inward or outward orientation), and false otherwise.
+    bool is_sentinel(const net_handle_t& net) const;
+    
+    ///Turn a handle to an oriented node into a net handle for a start-to-end or end-to-start traversal of the node, as appropriate.
+    net_handle_t get_net(const handle_t& handle, const handlegraph::HandleGraph* graph) const;
+    
+    ///For a net handle to a traversal of a single node, get the handle for that node in the orientation it is traversed.
+    ///May not be called for other net handles.
+    handle_t get_handle(const net_handle_t& net, const handlegraph::HandleGraph* graph) const;
+    
+    ///Get the parent snarl of a chain, or the parent chain of a snarl or node.
+    ///If the child is start-to-end or end-to-start, and the parent is a chain,
+    ///the chain comes out facing the same way, accounting for the relative
+    ///orientation of the child snarl or node in the chain. Otherwise,
+    ///everything is produced as start-to-end, even if that is not actually a
+    ///realizable traversal of a snarl or chain. May not be called on the root
+    ///snarl.
+    ///
+    ///Also works on snarl boundary sentinels.
+    net_handle_t get_parent(const net_handle_t& child) const;
+    
+    
+    // We have sentinel net_handle_t values for the start/end of each snarl, so
+    // that we can tell which last edge a traversal of the contents of a snarl
+    // takes when we represent it as a list of net_handle_t items. We also use
+    // these to query what's attached to the snarl start/end when traversing,
+    // and to see self loops immediately inside the snarl. These may actually
+    // just be the handles for the nodes at the start'end of the snarl with
+    // special flags set.
+    //
+    // For chains, we use the net handles to the appropriate first/last nodes
+    // in the appropriate orientation.
+    // The chain bound of a looping chain will have connectivity with the same
+    // start/end point when it is for the end of the chain; the connectivity
+    // will be start-start if it is going backwards in the node, and end-end
+    // if it is going forwards
+    
+    ///Get the bounding handle for the snarl or chain referenced by the given
+    ///net handle, getting the start or end facing in or out as appropriate.
+    ///
+    ///For snarls, returns the bounding sentinel net handles. For chains,
+    ///returns net handles for traversals of the bounding nodes of the chain.
+    ///If the chain is a looping chain, then the start and end of the chain
+    ///are the same, so the connectivity of the bound indicates which we're
+    ///looking at; the connectivity will be start-start if it is going 
+    ///backwards in the node, and end-end if it is going forwards.
+    ///
+    ///Ignores traversal type.
+    ///
+    ///May not be called on traversals of individual nodes.
+    net_handle_t get_bound(const net_handle_t& snarl, bool get_end, bool face_in) const;
 
-private:
+    ///Given the sentinel of a snarl, return a handle to the node representing it
+    net_handle_t get_node_from_sentinel(const net_handle_t& sentinel) const;
 
-    uint32_t magic_number = 1738636486;
+    
+    ///Return a net handle to the same snarl/chain/node in the opposite orientation.
+    ///No effect on tip-to-tip, start-to-start, or end-to-end net handles. Flips all the others.
+    net_handle_t flip(const net_handle_t& net) const;
+    
+    ///Get a canonical traversal handle from any net handle. All handles to the
+    ///same net graph element have the same canonical traversal. That canonical
+    ///traversal must be realizable, and might not always be start-to-end or
+    ///even consistently be the same kind of traversal for different snarls,
+    ///chains, or nodes. Mostly useful to normalize for equality comparisons.
+    ///
+    ///Any root snarl will become just the root
+    ///Anything without connectivity will get START_END
+    net_handle_t canonical(const net_handle_t& net) const;
 
+    ///Makes a start-end traversal of the net.
+    ///Faster than canonical because it doesn't check the index for anything 
+    net_handle_t start_end_traversal_of(const net_handle_t& net) const;
 
-/////// These are used to interpret the distance index, which is just a vector of ints
-/////// Uses a SnarlTreeRecord as the main class for defining and interpreting the records
-/////// SnarlTreeRecords are given a base pointer, which points to the start of the record
-/////// These tell the record how big it is and the offsets of each of its values
+    ///Return the kind of location at which the given traversal starts.
+    endpoint_t starts_at(const net_handle_t& traversal) const;
     
-    //Root record
-    const static size_t ROOT_RECORD_SIZE = 5;
-    const static size_t COMPONENT_COUNT_OFFSET = 1;
-    const static size_t NODE_COUNT_OFFSET = 2;
-    const static size_t MIN_NODE_ID_OFFSET = 3;
-    const static size_t MAX_TREE_DEPTH_OFFSET = 4;
+    ///Return the kind of location at which the given traversal ends.
+    endpoint_t ends_at(const net_handle_t& traversal) const;
 
-    //Node record
-    const static size_t NODE_RECORD_SIZE = 5;
-    const static size_t NODE_ID_OFFSET = 1;
-    const static size_t NODE_PARENT_OFFSET = 2;
-    const static size_t NODE_LENGTH_OFFSET = 3;
-    const static size_t NODE_RANK_OFFSET = 4;
- 
-    //Chain record
-    const static size_t CHAIN_RECORD_SIZE = 10;
-    const static size_t CHAIN_NODE_COUNT_OFFSET = 1;
-    const static size_t CHAIN_PARENT_OFFSET = 2;
-    const static size_t CHAIN_MIN_LENGTH_OFFSET = 3; //If this is a multicomponent chain, then the actual min length is 0, but this will be the length of the last component since it is the only length that matters when looping around the outside of the chain
-    const static size_t CHAIN_MAX_LENGTH_OFFSET = 4;
-    const static size_t CHAIN_RANK_OFFSET = 5;
-    const static size_t CHAIN_START_NODE_OFFSET = 6;
-    const static size_t CHAIN_END_NODE_OFFSET = 7; //TODO Don't really need this , could get it from start node or last child
-    const static size_t CHAIN_LAST_CHILD_OFFSET = 8; //The offset of the last thing in the chain - node or (if looping chain) snarl
-    const static size_t CHAIN_DEPTH_OFFSET = 9;
+    ///For a child of a snarl, the rank is used to calculate the distance
+    size_t get_rank_in_parent(const net_handle_t& net) const;
 
-    //Trivial snarl record (which occurs within a chain)
-    //These contain up to 128 nodes with nothing between them
-    //The record is followed by [node id+orientation, right prefix sum] for each node in the trivial snarl
-    //So the total length of the trivial snarl is 8+2*#nodes
-    //The right prefix sum is the sum from the start of the trivial chain to the right side of the node (relative to the chain)
-    const static size_t BITS_FOR_TRIVIAL_NODE_OFFSET = 8;
-    const static size_t MAX_TRIVIAL_SNARL_NODE_COUNT =  (1 << BITS_FOR_TRIVIAL_NODE_OFFSET) -1;
-    const static size_t TRIVIAL_SNARL_RECORD_SIZE = 7;
-    const static size_t TRIVIAL_SNARL_PARENT_OFFSET = 1;
-    const static size_t TRIVIAL_SNARL_NODE_COUNT_OFFSET = 2;
-    const static size_t TRIVIAL_SNARL_PREFIX_SUM_OFFSET = 3;
-    const static size_t TRIVIAL_SNARL_FORWARD_LOOP_OFFSET = 4;
-    const static size_t TRIVIAL_SNARL_REVERSE_LOOP_OFFSET = 5;
-    const static size_t TRIVIAL_SNARL_COMPONENT_OFFSET = 6;
-   
-    //Snarl record (which occurs within a chain)
-    const static size_t SNARL_RECORD_SIZE = 6;
-    const static size_t SNARL_NODE_COUNT_OFFSET = 1;
-    const static size_t SNARL_PARENT_OFFSET = 2;
-    const static size_t SNARL_MIN_LENGTH_OFFSET = 3;
-    const static size_t SNARL_MAX_LENGTH_OFFSET = 4;
-    const static size_t SNARL_CHILD_RECORD_OFFSET = 5;
+    ///How many connected components are in this graph?
+    ///This returns the number of topological connected components, not necessarily the 
+    ///number of nodes in the top-level snarl 
+    size_t connected_component_count() const;
 
-    //A simple snarl 
-    const static size_t SIMPLE_SNARL_RECORD_SIZE = 3;
-    //This one stores the node count and min and max lengths of the snarl
-    //It'll take 26 bits: 11 for each length
-    const static size_t SIMPLE_SNARL_NODE_COUNT_AND_LENGTHS_OFFSET = 1;
-    const static size_t SIMPLE_SNARL_PARENT_OFFSET = 2;
+protected:
+    ///Internal implementation for for_each_child.
+    bool for_each_child_impl(const net_handle_t& traversal, const std::function<bool(const net_handle_t&)>& iteratee) const;
 
+    ///Internal implementation for for_each_traversal.
+    bool for_each_traversal_impl(const net_handle_t& item, const std::function<bool(const net_handle_t&)>& iteratee) const;
 
+    ///Internal implementation for follow_net_edges.
+    ///if go_left is true, then go out  from the start of the traversal of here, otherwise go out from
+    ///the end of the traversal 
+    bool follow_net_edges_impl(const net_handle_t& here, const handlegraph::HandleGraph* graph, bool go_left, const std::function<bool(const net_handle_t&)>& iteratee) const;
 
+public:
 
-    //The snarl size is repeated immediately after a chain node record (so the offset is CHAIN_NODE(_MULTICOMPONENT)_RECORD_SIZE -1)
-    //If there is a snarl, the snarl size is repeated after the snarl record
 
-////////////////////////////////////  How we define different properties of the distance index
+    ///Get a net handle for traversals of a snarl or chain that contains
+    ///the given oriented bounding node traversals or sentinels. Given two
+    ///sentinels for a snarl, produces a net handle to a start-to-end,
+    ///end-to-end, end-to-start, or start-to-start traversal of that snarl.
+    ///Given handles to traversals of the bounding nodes of a chain, similarly
+    ///produces a net handle to a traversal of the chain.
+    ///
+    ///For a chain, either or both handles can also be a snarl containing tips,
+    ///for a tip-to-start, tip-to-end, start-to-tip, end-to-tip, or tip-to-tip
+    ///traversal. Similarly, for a snarl, either or both handles can be a chain
+    ///in the snarl that contains internal tips, or that has no edges on the
+    ///appropriate end.
+    ///
+    ///May only be called if a path actually exists between the given start
+    ///and end.
+    net_handle_t get_parent_traversal(const net_handle_t& traversal_start, const net_handle_t& traversal_end) const;
 
-    public:
 
-    /*
-     *
-     * The "tags" for defining what kind of record we're looking at will be a record_t and a 
-     * bit vector indicating connectivity. The bit vector will be the last 6 bits of the tag
-     * 
-     * Each bit represents one type of connectivity:
-     * start-start, start-end, start-tip, end-end, end-tip, tip-tip
-     * 
-     * The remainder of the tag will be the record_t of the record
-     * NODE, SNARL, and CHAIN indicate that they don't store distances.
-     * SIMPLE_SNARL is a snarl with all children connecting only to the boundary nodes
-     * OVERSIZED_SNARL only stores distances to the boundaries
-     * ROOT_SNARL represents a connected component of the root. It has no start or end node so 
-     *    its children actually belong to the root
-     * MULTICOMPONENT_CHAIN can represent a chain with snarls that are not start-end connected
-     *     The chain is split up into components between these snarls, each node is tagged with
-     *     which component it belongs to
-     */
-    //TODO: Make simple snarls work
-    //TODO: Maybe also add a tag for trivial snarls/chains
-    //TODO: Unary snarls? Looping chains?
+private:
+
+    ///Function to walk through the shortest path between the two nodes+orientations. Orientation is the same as for minimum_distance - 
+    ///traverses from the first node going forward to the second node going forward.
+    ///Calls iteratee on each node of the shortest path between the nodes and the distance to the start of that node
+    void for_each_handle_in_shortest_path(const handlegraph::nid_t id1, const bool rev1, const handlegraph::nid_t id2, const bool rev2, 
+                                          const HandleGraph* graph, const std::function<bool(const handlegraph::handle_t, size_t)>& iteratee) const;
+
+    ///Helper function for recursively traversing the shortest path in a snarl.
+    ///start and end must be children (or sentinels) of the snarl.
+    ///The distance found will traverse start going forward and reach end going forward.
+    ///doesn't call iteratee on start or end.
+    ///If to_duplicate isn't the nullptr, then keep a list of everything traversed (flipped) and its length
+    void for_each_handle_in_shortest_path_in_snarl(const net_handle_t& snarl_handle, net_handle_t start, net_handle_t end,
+                                          size_t distance_to_traverse, size_t& distance_traversed, const HandleGraph* graph, 
+                                          const std::function<bool(const handlegraph::handle_t, size_t)>& iteratee,
+                                          vector<pair<net_handle_t, size_t>>* to_duplicate) const;
+    ///Helper function for recursively traversing the shortest path in a chain.
+    ///start and end must be children of the chain.
+    ///iteratee is not run on start or end.
+    void for_each_handle_in_shortest_path_in_chain(const net_handle_t& chain_handle, net_handle_t start, net_handle_t end,
+                                          size_t distance_to_traverse, size_t& distance_traversed, const HandleGraph* graph, 
+                                          const std::function<bool(const handlegraph::handle_t, size_t)>& iteratee,
+                                          vector<pair<net_handle_t, size_t>>* to_duplicate) const;
+
+
+////////////////////////////// How to interpret net_handle_ts
+//
+public:
+
+    ///A record_t is the type of structure that a record can be.
+    ///
+    ///NODE, SNARL, and CHAIN indicate that they don't store distances.
+    ///SIMPLE_SNARL is a snarl with all children connecting only to the boundary nodes in one direction.
+    ///OVERSIZED_SNARL only stores distances to the boundaries.
+    ///ROOT_SNARL represents a connected component of the root. It has no start or end node so 
+    ///   its children technically belong to the root.
+    ///MULTICOMPONENT_CHAIN can represent a chain with snarls that are not start-end connected.
+    ///    The chain is split up into components between these snarls, each node is tagged with
+    ///    which component it belongs to.
+    ///
     enum record_t {ROOT=1, 
                    NODE, DISTANCED_NODE, 
                    TRIVIAL_SNARL, DISTANCED_TRIVIAL_SNARL,
@@ -624,21 +534,19 @@ class SnarlDistanceIndex : public SnarlDecomposition, public TriviallySerializab
                    CHAIN, DISTANCED_CHAIN, MULTICOMPONENT_CHAIN,
                    CHILDREN};
 
-    enum connectivity_t { START_START=1, START_END, START_TIP, 
-                            END_START, END_END, END_TIP, 
-                            TIP_START, TIP_END, TIP_TIP};
-    //Type of a net_handle_t. This is to allow a node record to be seen as a chain from the 
-    //perspective of a handle
-    enum net_handle_record_t {ROOT_HANDLE=0, NODE_HANDLE, SNARL_HANDLE, CHAIN_HANDLE, SENTINEL_HANDLE};
+
+    
+    ///Given the type of the record, return the handle type. Some record types can represent multiple things,
+    ///for example a simple snarl record is used to represent a snarl, and the nodes/trivial chains in it.
+    ///This will return whatever is higher on the snarl tree. A simple snarl will be considered a snarl,
+    ///a root snarl will be considered a root, etc
     const static net_handle_record_t get_record_handle_type(record_t type) {
-        //TODO: I"m not sure if a root snarl should be a root or a snarl
         if (type == ROOT || type == ROOT_SNARL || type == DISTANCED_ROOT_SNARL) {
             return ROOT_HANDLE;
         } else if (type == NODE || type == DISTANCED_NODE || type == TRIVIAL_SNARL || type == DISTANCED_TRIVIAL_SNARL) {
             return NODE_HANDLE;
         } else if (type == SNARL || type == DISTANCED_SNARL || type ==  SIMPLE_SNARL ||type ==  OVERSIZED_SNARL 
                  || type == SIMPLE_SNARL || type == DISTANCED_SIMPLE_SNARL){
-            //TODO: Simple snarls can be snarls or nodes
             return SNARL_HANDLE;
         } else if (type == CHAIN || type == DISTANCED_CHAIN || type == MULTICOMPONENT_CHAIN) {
             return CHAIN_HANDLE;
@@ -646,39 +554,24 @@ class SnarlDistanceIndex : public SnarlDecomposition, public TriviallySerializab
             throw runtime_error("error: trying to get the handle type of a list of children");
         }
     }
-private:
-    /*Give each of the enum types a name for debugging */
-    vector<std::string> record_t_as_string = {"ROOT", "NODE", "DISTANCED_NODE", 
-                     "TRIVIAL_SNARL", "DISTANCED_TRIVIAL_SNARL",
-                     "SNARL", "DISTANCED_SNARL", "SIMPLE_SNARL", "OVERSIZED_SNARL", 
-                     "ROOT_SNARL", "DISTANCED_ROOT_SNARL",
-                     "CHAIN", "DISTANCED_CHAIN", "MULTICOMPONENT_CHAIN",
-                     "CHILDREN"};
-    vector<std::string> connectivity_t_as_string = { "START_START", "START_END", "START_TIP", 
-                            "END_START", "END_END", "END_TIP", 
-                            "TIP_START", "TIP_END", "TIP_TIP"};
-    vector<std::string> net_handle_record_t_string = {"ROOT_HANDLE", "NODE_HANDLE", "SNARL_HANDLE", 
-                                                "CHAIN_HANDLE", "SENTINEL_HANDLE"};
-
-
-
-////////////////////////////// How to interpret net_handle_ts
-//TODO: Does this depend on endianness???
-//Last 3 bits are the net_handle_record_t, next 4 are the connectivity_t, next 8 are th enode offset, 
-//last are the offset into snarl_tree_records
-//
-//For sentinel net_handle_t's, which represent the boundaries of snarls (just inside of the boundary nodes),
-//The record points to the snarl containing them, and the connectivity indicates which bound 
-//we're looking at (START_END for start in, START_START for start out, etc)
 
 public:
-//TODO: This should not be public
+/*
+ * These are used to actually get values from a net_handle_t, which is just an int.
+ * Last 3 bits are the net_handle_record_t, next 4 are the connectivity_t, next 8 are the node offset, 
+ * last are the offset into snarl_tree_records.
+ * 
+ * For sentinel net_handle_t's, which represent the boundaries of snarls (just inside of the boundary nodes),
+ * The record points to the snarl containing them, and the connectivity indicates which bound 
+ * we're looking at (START_END for start in, START_START for start out, etc)
+ */
+
 
     ///The offset into records that this handle points to
     const static size_t get_record_offset (const handlegraph::net_handle_t& net_handle) {
         return handlegraph::as_integer(net_handle) >> 15;
     }
-    //The offset of a node in a trivial snarl (0 if it isn't a node in a trivial snarl)
+    ///The offset of a node in a trivial snarl (0 if it isn't a node in a trivial snarl)
     const static size_t get_node_record_offset (const handlegraph::net_handle_t& net_handle) {
         return (handlegraph::as_integer(net_handle) >> 7 ) & MAX_TRIVIAL_SNARL_NODE_COUNT; //Get 8 bits after last 7
     }
@@ -693,11 +586,13 @@ class SnarlDistanceIndex : public SnarlDecomposition, public TriviallySerializab
         return static_cast<net_handle_record_t>(record_type);
     }
 
-    const static handlegraph::net_handle_t get_net_handle_from_values(size_t pointer, connectivity_t connectivity, net_handle_record_t type, size_t node_offset=0) {
+    const static handlegraph::net_handle_t get_net_handle_from_values(size_t pointer, connectivity_t connectivity, 
+                                                                      net_handle_record_t type, size_t node_offset=0) {
         if (pointer > ((size_t)1 << (64-BITS_FOR_TRIVIAL_NODE_OFFSET-3-4))-1) {
             throw runtime_error("error: don't have space in net handle for record offset");
         }
-        net_handle_t handle =  as_net_handle((((((pointer << BITS_FOR_TRIVIAL_NODE_OFFSET) | node_offset) << 4) | connectivity)<<3) | type); 
+        net_handle_t handle =  as_net_handle((((((pointer << BITS_FOR_TRIVIAL_NODE_OFFSET) | node_offset) << 4) 
+                                                  | connectivity)<<3) | type); 
         return handle;
     
     }
@@ -715,7 +610,7 @@ class SnarlDistanceIndex : public SnarlDecomposition, public TriviallySerializab
     }
 
 
-    //Get the offset into snarl_tree_records for the pointer to a node record
+    ///Get the offset into snarl_tree_records for the pointer to a node record.
     const static size_t get_node_pointer_offset (const handlegraph::nid_t& id, const handlegraph::nid_t& min_node_id, size_t component_count) {
         size_t node_records_offset = component_count + ROOT_RECORD_SIZE; 
         size_t offset = (id-min_node_id)*2;
@@ -787,10 +682,183 @@ class SnarlDistanceIndex : public SnarlDecomposition, public TriviallySerializab
     }
 
 
+
+
+    
+//////////////////////////////////////////  The actual distance index
+    
+private:
+
+    ///This vector is the entire distance index. It is split up into "records" that are defined below
+    bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector> snarl_tree_records;
+
+/*
+ * These are used to interpret snarl_tree_records, which is just a vector of ints.
+ * Uses a SnarlTreeRecord as the main class for defining and interpreting the records.
+ * SnarlTreeRecords are given a base pointer, which points to the start of the record
+ * Each record starts with a "tag", which defines which type of record it is. The 
+ * contents of the record are defined below: 
+*/
+    
+    /*Root record
+    
+     * - The (single) root vector has the format:
+     *   [root tag, # connected components (N), # nodes (M), min_node_id, max depth [pointer to node/snarl/chain record] x N], [pointer to node+ node offset] x M]
+     *   The root vector stores the root of every connected component, which can be a 
+     *   node, snarl, or chain
+     */
+    const static size_t ROOT_RECORD_SIZE = 5;
+    const static size_t COMPONENT_COUNT_OFFSET = 1;
+    const static size_t NODE_COUNT_OFFSET = 2;
+    const static size_t MIN_NODE_ID_OFFSET = 3;
+    const static size_t MAX_TREE_DEPTH_OFFSET = 4;
+
+    /*Node record
+     * - A node record for nodes in snarls/roots
+     *   These will be interspersed between chains more or less based on where they are in the snarl tree
+     *   [node tag, node id, pointer to parent, node length, rank in parent]
+     */
+    const static size_t NODE_RECORD_SIZE = 9;
+    const static size_t NODE_ID_OFFSET = 1;
+    const static size_t NODE_PARENT_OFFSET = 2;
+    const static size_t NODE_LENGTH_OFFSET = 3;
+    const static size_t NODE_RANK_OFFSET = 4;
+    //The distances from the left or right of the node to the left or right of its parent snarl (or 0 if its parent is a root)
+    //As with other distances, store 0 for inf, value +1 for everything else
+    const static size_t NODE_DISTANCE_LEFT_START_OFFSET = 5;
+    const static size_t NODE_DISTANCE_RIGHT_START_OFFSET = 6;
+    const static size_t NODE_DISTANCE_LEFT_END_OFFSET = 7;
+    const static size_t NODE_DISTANCE_RIGHT_END_OFFSET = 8;
+ 
+    /*Chain record
+
+     * - A chain record for each chain, which is interspersed node and snarl records:
+     *   The nodes are all stored in a "TrivialSnarl", which is a bunch of nodes with no snarls between them
+     *   [chain tag, #nodes, pointer to parent, min length, max length, rank in parent, start, end, pointer to last child
+     *       [ (trivial nodes), (snarl record),] x N] 
+     *    snarl_record_size is the number of things in the snarl record (so 0 if there is no snarl there)
+     *    start/end include the orientations
+     *
+     * If this is a multicomponent chain, then the actual min length is 0, but this will store the length of the last component 
+     * since it is the only length that matters when looping around the outside of the chain
+     */ 
+    const static size_t CHAIN_RECORD_SIZE = 14;
+    const static size_t CHAIN_NODE_COUNT_OFFSET = 1;
+    const static size_t CHAIN_PARENT_OFFSET = 2;
+    const static size_t CHAIN_MIN_LENGTH_OFFSET = 3;     
+    const static size_t CHAIN_MAX_LENGTH_OFFSET = 4;
+    const static size_t CHAIN_RANK_OFFSET = 5;
+    const static size_t CHAIN_START_NODE_OFFSET = 6;
+    const static size_t CHAIN_END_NODE_OFFSET = 7;
+    const static size_t CHAIN_LAST_CHILD_OFFSET = 8; //The offset of the last thing in the chain - node or (if looping chain) snarl
+    const static size_t CHAIN_DEPTH_OFFSET = 9;
+    //DIstances from the left/right of the chain to the left/right of its parent
+    const static size_t CHAIN_DISTANCE_LEFT_START_OFFSET = 10;
+    const static size_t CHAIN_DISTANCE_RIGHT_START_OFFSET = 11;
+    const static size_t CHAIN_DISTANCE_LEFT_END_OFFSET = 12;
+    const static size_t CHAIN_DISTANCE_RIGHT_END_OFFSET = 13;
+
+    /*Trivial snarl record (which occurs within a chain) representing nodes in a chain
+     * These contain up to 128 nodes with nothing between them
+
+     *   [trivial snarl tag, pointer to parent, node count, prefix sum, fd loop, rev loop, component]
+
+     * The record is followed by [node id+orientation, right prefix sum] for each node in the trivial snarl
+     * So the total length of the trivial snarl is 8+2*#nodes
+     * The right prefix sum is the sum from the start of the trivial chain to the right side of the node (relative to the chain)
+     * The node_record_offset in a net_handle_t to a trivial snarl points to a node in the trivial snarl
+ 
+     */
+    const static size_t BITS_FOR_TRIVIAL_NODE_OFFSET = 8;
+    const static size_t MAX_TRIVIAL_SNARL_NODE_COUNT =  (1 << BITS_FOR_TRIVIAL_NODE_OFFSET) -1;
+    const static size_t TRIVIAL_SNARL_RECORD_SIZE = 8;
+    const static size_t TRIVIAL_SNARL_PARENT_OFFSET = 1;
+    const static size_t TRIVIAL_SNARL_NODE_COUNT_OFFSET = 2;
+    const static size_t TRIVIAL_SNARL_PREFIX_SUM_OFFSET = 3;
+    const static size_t TRIVIAL_SNARL_MAX_PREFIX_SUM_OFFSET = 4;
+    const static size_t TRIVIAL_SNARL_FORWARD_LOOP_OFFSET = 5;
+    const static size_t TRIVIAL_SNARL_REVERSE_LOOP_OFFSET = 6;
+    const static size_t TRIVIAL_SNARL_COMPONENT_OFFSET = 7;
+   
+    /*Snarl record (which occurs within a chain)
+     * 
+     * - A snarl record for each snarl, which are stuck in chains
+     *   [snarl tag, # nodes, pointer to parent, min length, max length, rank in parent, 
+     *      pointer to children (in child vector), distance vector]
+     *   The rank of the start node will always be 0 and the end node rank will be 1
+     *   start/end are the start and end nodes, include the orientations
+     *   For the first and last nodes, we only care about the node sides pointing in
+     *   Each node side in the actual distance matrix will be 2*(rank-1) for the left side, and 
+     *   2rank+1 for the right side, and 0 for the start, 1 for the end, where we only keep the 
+     *   inner node side of the start and end
+     *   Node count is the number of nodes, not including boundary nodes
+     */
+    const static size_t SNARL_RECORD_SIZE = 8;
+    const static size_t SNARL_NODE_COUNT_OFFSET = 1;
+    const static size_t SNARL_PARENT_OFFSET = 2;
+    const static size_t SNARL_MIN_LENGTH_OFFSET = 3;
+    const static size_t SNARL_MAX_LENGTH_OFFSET = 4;
+    const static size_t SNARL_DISTANCE_START_START_OFFSET = 5;
+    const static size_t SNARL_DISTANCE_END_END_OFFSET = 6;
+    const static size_t SNARL_CHILD_RECORD_OFFSET = 7;
+
+    /*A simple snarl for bubbles with only nodes with two edges, one to each bound
+     * [simple snarl tag, node count+length, parent, [node id, node length]xN
+    */
+    const static size_t SIMPLE_SNARL_RECORD_SIZE = 3;
+    //This one stores the node count and min and max lengths of the snarl
+    //It'll take 26 bits: 11 for each length
+    const static size_t SIMPLE_SNARL_NODE_COUNT_AND_LENGTHS_OFFSET = 1;
+    const static size_t SIMPLE_SNARL_PARENT_OFFSET = 2;
+
+     /*  At the end is the (single) child vector, listing children in snarls
+     *   [child vector tag, (pointer to records) x N
+     *   Each snarl will have a pointer into here, and will also know how many children it has
+     */ 
+
+private:
+    /*Give each of the enum types a name for printing */
+    vector<std::string> record_t_as_string = {"ROOT", "NODE", "DISTANCED_NODE", 
+                     "TRIVIAL_SNARL", "DISTANCED_TRIVIAL_SNARL",
+                     "SNARL", "DISTANCED_SNARL", "SIMPLE_SNARL", "OVERSIZED_SNARL", 
+                     "ROOT_SNARL", "DISTANCED_ROOT_SNARL",
+                     "CHAIN", "DISTANCED_CHAIN", "MULTICOMPONENT_CHAIN",
+                     "CHILDREN"};
+    vector<std::string> connectivity_t_as_string = { "START_START", "START_END", "START_TIP", 
+                            "END_START", "END_END", "END_TIP", 
+                            "TIP_START", "TIP_END", "TIP_TIP"};
+    vector<std::string> net_handle_record_t_string = {"ROOT_HANDLE", "NODE_HANDLE", "SNARL_HANDLE", 
+                                                "CHAIN_HANDLE", "SENTINEL_HANDLE"};
+
+
+    /* If this is 0, then don't store distances.
+     * Otherwise, for snarls with more children than snarl_size_limit, only store the distances
+     * that include boundary nodes (OVERSIZED_SNARL)
+     */
+    size_t snarl_size_limit = 1000;
+    uint32_t magic_number = 1738636486;
+public:
+    void set_snarl_size_limit (size_t size) {snarl_size_limit=size;}
+
+
+
+
 private:
+    /*
+     *
+     * The "tags" for defining what kind of record we're looking at. These are the first entry in any 
+     * record. They will be a record_t and a bit vector indicating connectivity.
+     * The bit vector will be the last 6 bits of the tag
+     * 
+     * Each bit represents one type of connectivity:
+     * start-start, start-end, start-tip, end-end, end-tip, tip-tip
+     * 
+     * The remainder of the tag will be the record_t of the record
+     */
     /////////// Methods for interpreting the tags for each snarl tree record
 
     const static record_t get_record_type(const size_t tag) {return static_cast<record_t>(tag >> 9);}
+
     const static bool is_start_start_connected(const size_t tag) {return tag & 32;}
     const static bool is_start_end_connected(const size_t tag)   {return tag & 16;}
     const static bool is_start_tip_connected(const size_t tag)   {return tag & 8;}
@@ -805,14 +873,18 @@ class SnarlDistanceIndex : public SnarlDecomposition, public TriviallySerializab
     const static bool is_externally_end_end_connected(const size_t tag) {return tag & 256;}
 
 
-    ////////////////////////////////  SnarlTreeRecord class for interpreting the records in a distance index
-
-    //Define a struct for interpreting each type of snarl tree node record (For node, snarl, chain)
-    //These will be used with net_handle_t's, which store a pointer into snarl_tree_records 
-    //as an offset. The last 4 bits of the net handle will be the connectivity of the handle,
-    //as a connectivity_t
-    //TODO: This might be overkill but I want it to be easy to change what gets stored in the index
-    //
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////  SnarlTreeRecord class for interpreting the records in a distance index
+//
+/* Define a struct for interpreting each type of snarl tree node record (For node, snarl, chain)
+ *
+ * This is meant to be a layer in between snarl_tree_records and the public interface.
+ * Each net_handle_t has a pointer to the start of a record in snarl_tree_records. 
+ * SnarlTreeRecord keeps the pointer and interprets the values stored in the record .
+ *
+ * SnarlTreeRecordWriter does the same thing but for writing values to the index.
+ *
+ */
     struct SnarlTreeRecord {
 
 
@@ -822,465 +894,276 @@ class SnarlDistanceIndex : public SnarlDecomposition, public TriviallySerializab
 
         //Constructors assuming that this record already exists
         SnarlTreeRecord(){};
-        SnarlTreeRecord (size_t pointer, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records){
-            record_offset = pointer;
-            records = tree_records;
+        SnarlTreeRecord (size_t pointer, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records);
+        SnarlTreeRecord (const net_handle_t& net, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records);
 
-#ifdef debug_distance_indexing
-            record_t type = get_record_type();
-            assert(type >= 1 && type <= 17 );
-#endif
-        }
-        SnarlTreeRecord (const net_handle_t& net, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records){
-            record_offset = get_record_offset(net);
-            records = tree_records;
-#ifdef debug_distance_indexing
-            record_t type = get_record_type();
-            assert(type >= 1 && type <= 17 );
-#endif
-        }
-
-        virtual size_t get_offset() { return record_offset; }
+        size_t get_offset() { return record_offset; }
 
         //What type of snarl tree node is this?
         //This will be the first value of any record
-        virtual record_t get_record_type() const {return SnarlDistanceIndex::get_record_type((*records)->at(record_offset));}
+        record_t get_record_type() const {return SnarlDistanceIndex::get_record_type((*records)->at(record_offset));}
 
         //The name is a bit misleading, it is the handle type that the record thinks it is, 
         //not necessarily the record type of the net_handle_t that was used to produce itused to produce it
-        virtual net_handle_record_t get_record_handle_type() const {
-            return SnarlDistanceIndex::get_record_handle_type( get_record_type());
+        net_handle_record_t get_record_handle_type() const {
+            return SnarlDistanceIndex::get_record_handle_type(get_record_type());
         }
 
 
         //Get the internal connectivity of the structure
-        virtual bool is_start_start_connected() const {return SnarlDistanceIndex::is_start_start_connected((*records)->at(record_offset));}
-        virtual bool is_start_end_connected() const {return SnarlDistanceIndex::is_start_end_connected((*records)->at(record_offset));}
-        virtual bool is_start_tip_connected() const {return SnarlDistanceIndex::is_start_tip_connected((*records)->at(record_offset));}
-        virtual bool is_end_end_connected() const {return SnarlDistanceIndex::is_end_end_connected((*records)->at(record_offset));}
-        virtual bool is_end_tip_connected() const {return SnarlDistanceIndex::is_end_tip_connected((*records)->at(record_offset));}
-        virtual bool is_tip_tip_connected() const {return SnarlDistanceIndex::is_tip_tip_connected((*records)->at(record_offset));}
+        bool is_start_start_connected() const {return SnarlDistanceIndex::is_start_start_connected((*records)->at(record_offset));}
+        bool is_start_end_connected() const {return SnarlDistanceIndex::is_start_end_connected((*records)->at(record_offset));}
+        bool is_start_tip_connected() const {return SnarlDistanceIndex::is_start_tip_connected((*records)->at(record_offset));}
+        bool is_end_end_connected() const {return SnarlDistanceIndex::is_end_end_connected((*records)->at(record_offset));}
+        bool is_end_tip_connected() const {return SnarlDistanceIndex::is_end_tip_connected((*records)->at(record_offset));}
+        bool is_tip_tip_connected() const {return SnarlDistanceIndex::is_tip_tip_connected((*records)->at(record_offset));}
 
         //And the external connectivity. This is only relevant for root-level structures
         //since it would otherwise be captured by the containing snarl
-        virtual bool is_externally_start_end_connected() const {return SnarlDistanceIndex::is_externally_start_end_connected((*records)->at(record_offset));}
-        virtual bool is_externally_start_start_connected() const {return SnarlDistanceIndex::is_externally_start_start_connected((*records)->at(record_offset));}
-        virtual bool is_externally_end_end_connected() const {return SnarlDistanceIndex::is_externally_end_end_connected((*records)->at(record_offset));}
+        bool is_externally_start_end_connected() const {return SnarlDistanceIndex::is_externally_start_end_connected((*records)->at(record_offset));}
+        bool is_externally_start_start_connected() const {return SnarlDistanceIndex::is_externally_start_start_connected((*records)->at(record_offset));}
+        bool is_externally_end_end_connected() const {return SnarlDistanceIndex::is_externally_end_end_connected((*records)->at(record_offset));}
 
-        virtual bool has_connectivity(connectivity_t connectivity) const;
-        virtual bool has_connectivity(endpoint_t start, endpoint_t end);
+        bool has_connectivity(connectivity_t connectivity) const;
+        bool has_connectivity(endpoint_t start, endpoint_t end);
 
         //Get and set a pointer to this node's parent, including its orientation
-        //TODO: I don't think it matters if a chain is reversed or not, also it might not matter if a snarl is
-        virtual size_t get_parent_record_offset() const;
+        size_t get_parent_record_offset() const;
 
         //Get and set the minimum length (distance from start to end, including boundaries for 
         // chains but not snarls, just node length for nodes)
-        virtual size_t get_min_length() const;
+        size_t get_min_length() const;
         
-        //Get and set this node's maximum length
+        //Get and set this node's maximum length.
         //This isn't actually a maximum, it's the maximum among minimum distance paths 
         //through each node in the snarl/chain
-        virtual size_t get_max_length() const;
+        size_t get_max_length() const;
 
-        //Get and set this structure's rank in its parent
-        //For children of snarls, this means the actual rank
+        //Get and set this structure's rank in its parent.
+        //For children of snarls, this means the actual rank.
         //For children of chains, it points to the node in the chain
-        virtual size_t get_rank_in_parent() const;
+        size_t get_rank_in_parent() const;
 
         //Is this node reversed in its parent
-        //TODO: I think a node is the only thing that can be reversed in its parent, and only if it is in a chain
-        virtual bool get_is_reversed_in_parent() const;
+        bool get_is_reversed_in_parent() const;
 
         //Get the node id of the start/end of this structure (start node of a snarl/chain)
-        //TODO: Also need to add min node id
-        virtual handlegraph::nid_t get_start_id() const; 
+        handlegraph::nid_t get_start_id() const; 
         //True if the node is traversed backwards to enter the structure
-        virtual bool get_start_orientation() const;
-        virtual handlegraph::nid_t get_end_id() const;
+        bool get_start_orientation() const;
+        handlegraph::nid_t get_end_id() const;
         //Return true if the end node is traversed backwards to leave the snarl
-        virtual handlegraph::nid_t get_end_orientation() const;
+        handlegraph::nid_t get_end_orientation() const;
 
-        //TODO: These are redeclared so that I don't need to pass the SnarlTreeRecord the actual distance index
-        //Get the offset into snarl_tree_records for a node record
-        virtual size_t get_offset_from_id (const handlegraph::nid_t id) const;
     };
 
     //Record interpreter that has a non-const reference to snarl_tree_records, so it can
     //also add things
-    struct SnarlTreeRecordConstructor {
+    struct SnarlTreeRecordWriter {
 
-        //TODO: This might be bad but this has the same members as SnarlTreeRecord
         //and does basically the same thing but doesn't inherit from it
         size_t record_offset;
         bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* records;
 
         //Constructors assuming that this record already exists
-        SnarlTreeRecordConstructor() {};
-        SnarlTreeRecordConstructor (size_t pointer, bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records){
-            record_offset = pointer;
-            records = tree_records;
-
-#ifdef debug_distance_indexing
-            record_t type = get_record_type();
-            assert(type == ROOT || type == NODE || type == DISTANCED_NODE ||
-                    type == SIMPLE_SNARL || type == DISTANCED_SIMPLE_SNARL || 
-                    type == TRIVIAL_SNARL || type == DISTANCED_TRIVIAL_SNARL || 
-                    type == SNARL || type == DISTANCED_SNARL || type == OVERSIZED_SNARL || 
-                    type == ROOT_SNARL || type == DISTANCED_ROOT_SNARL || type == CHAIN || 
-                    type == DISTANCED_CHAIN || type == MULTICOMPONENT_CHAIN);
-#endif
-        }
-        SnarlTreeRecordConstructor (const net_handle_t& net, bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records){
-            record_offset = get_record_offset(net);
-            records = tree_records;
-#ifdef debug_distance_indexing
-            record_t type = get_record_type();
-            assert(type == ROOT || type == NODE || type == DISTANCED_NODE ||  
-                    type == SIMPLE_SNARL || type == DISTANCED_SIMPLE_SNARL || 
-                    type == TRIVIAL_SNARL || type == DISTANCED_TRIVIAL_SNARL || 
-                    type == SNARL || type == DISTANCED_SNARL || type == OVERSIZED_SNARL || 
-                    type == ROOT_SNARL || type == DISTANCED_ROOT_SNARL || type == CHAIN || 
-                    type == DISTANCED_CHAIN || type == MULTICOMPONENT_CHAIN);
-#endif
-        }
+        SnarlTreeRecordWriter() {};
+        SnarlTreeRecordWriter (size_t pointer, bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records);
+        SnarlTreeRecordWriter (const net_handle_t& net, bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records);
         //What type of snarl tree node is this?
         //This will be the first value of any record
-        //TODO: This copies from SnarlTreeRecord
-        virtual record_t get_record_type() const;
-        virtual void set_start_start_connected();
-        virtual void set_start_end_connected();
-        virtual void set_start_tip_connected();
-        virtual void set_end_end_connected();
-        virtual void set_end_tip_connected();
-        virtual void set_tip_tip_connected();
-        virtual void set_externally_start_end_connected();
-        virtual void set_externally_start_start_connected() const;
-        virtual void set_externally_end_end_connected() const;
-        virtual void set_record_type(record_t type);
-        virtual void set_min_length(size_t length);
-        virtual void set_max_length(size_t length);
-        virtual void set_rank_in_parent(size_t rank);
-        virtual void set_is_reversed_in_parent(bool rev);
-        virtual void set_parent_record_offset(size_t pointer);
+        record_t get_record_type() const;
+        void set_start_start_connected();
+        void set_start_end_connected();
+        void set_start_tip_connected();
+        void set_end_end_connected();
+        void set_end_tip_connected();
+        void set_tip_tip_connected();
+        void set_externally_start_end_connected();
+        void set_externally_start_start_connected() const;
+        void set_externally_end_end_connected() const;
+        void set_record_type(record_t type);
+        void set_min_length(size_t length);
+        void set_max_length(size_t length);
+        void set_rank_in_parent(size_t rank);
+        void set_is_reversed_in_parent(bool rev);
+        void set_parent_record_offset(size_t pointer);
         //Rev is true if the node is traversed backwards to enter the snarl
-        virtual void set_start_node(handlegraph::nid_t id, bool rev); 
+        void set_start_node(handlegraph::nid_t id, bool rev); 
         //Rev is true if the node is traversed backwards to leave the snarl
-        virtual void set_end_node(handlegraph::nid_t id, bool rev) const;
+        void set_end_node(handlegraph::nid_t id, bool rev) const;
     };
 
     struct RootRecord : SnarlTreeRecord {
 
         RootRecord (){};
-        RootRecord (size_t pointer, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records){
-            record_offset = pointer;
-            records = tree_records;
-#ifdef debug_distance_indexing
-            assert(get_record_type() == ROOT);
-#endif
-        }
-        RootRecord (net_handle_t net, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records){
-            record_offset = get_record_offset(net);
-            records = tree_records;
-#ifdef debug_distance_indexing
-            assert(get_record_type() == ROOT);
-#endif
-        }
-        virtual size_t get_connected_component_count() const {return (*records)->at(record_offset+COMPONENT_COUNT_OFFSET);}
-        virtual size_t get_node_count() const {return (*records)->at(record_offset+NODE_COUNT_OFFSET);}
-        virtual size_t get_max_tree_depth() const {return (*records)->at(record_offset+MAX_TREE_DEPTH_OFFSET);}
-        virtual size_t get_min_node_id() const {return (*records)->at(record_offset+MIN_NODE_ID_OFFSET);}
-        virtual SnarlTreeRecord get_component_record(size_t component_number) const {return SnarlTreeRecord((*records)->at(record_offset+2+component_number), records);}
-        virtual bool for_each_child(const std::function<bool(const handlegraph::net_handle_t&)>& iteratee) const;
+        RootRecord (size_t pointer, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records);
+        RootRecord (net_handle_t net, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records);
+
+        size_t get_connected_component_count() const {return (*records)->at(record_offset+COMPONENT_COUNT_OFFSET);}
+        size_t get_node_count() const {return (*records)->at(record_offset+NODE_COUNT_OFFSET);}
+        size_t get_max_tree_depth() const {return (*records)->at(record_offset+MAX_TREE_DEPTH_OFFSET);}
+        size_t get_min_node_id() const {return (*records)->at(record_offset+MIN_NODE_ID_OFFSET);}
+        SnarlTreeRecord get_component_record(size_t component_number) const {return SnarlTreeRecord((*records)->at(record_offset+2+component_number), records);}
+        bool for_each_child(const std::function<bool(const handlegraph::net_handle_t&)>& iteratee) const;
 
     };
 
-    struct RootRecordConstructor : RootRecord, SnarlTreeRecordConstructor {
-        using SnarlTreeRecordConstructor::record_offset;
-        using SnarlTreeRecordConstructor::records;
-        using SnarlTreeRecordConstructor::get_record_type;
+    struct RootRecordWriter : RootRecord, SnarlTreeRecordWriter {
+        using SnarlTreeRecordWriter::record_offset;
+        using SnarlTreeRecordWriter::records;
+        using SnarlTreeRecordWriter::get_record_type;
 
         //Constructor meant for creating a new record, at the end of snarl_tree_records
-        //TODO: The way I wrote this pointer should be 0
-        RootRecordConstructor (size_t pointer, size_t connected_component_count, size_t node_count, size_t max_tree_depth, 
-                    handlegraph::nid_t min_node_id, bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* records){
-            record_offset = pointer;
-            records = records;
-            SnarlTreeRecordConstructor::record_offset = pointer;
-            SnarlTreeRecordConstructor::records = records;
-            RootRecord::record_offset = pointer;
-            RootRecord::records = records;
-            //Allocate memory for the root vector and for all of the nodes
-#ifdef debug_distance_indexing
-            cerr << " Resizing array to add root: length " << (*records)->size() << " -> " 
-                 << (*records)->size() + ROOT_RECORD_SIZE + connected_component_count + (node_count*2) << endl;
-#endif
-            (*records)->resize((*records)->size() + ROOT_RECORD_SIZE + connected_component_count + (node_count*2));
-            set_record_type(ROOT);
-            set_min_node_id(min_node_id);
-            set_node_count(node_count);
-            set_max_tree_depth(max_tree_depth);
-            set_connected_component_count(connected_component_count);
-#ifdef count_allocations
-            cerr << "new_root\t" <<  (ROOT_RECORD_SIZE + connected_component_count + (node_count*2)) << "\t" << (*records)->size() << endl;
-#endif
-        }
-        virtual void set_connected_component_count(size_t connected_component_count);
-        virtual void set_node_count(size_t node_count);
-        virtual void set_max_tree_depth(size_t tree_depth);
-        virtual void set_min_node_id(handlegraph::nid_t node_id);
-        virtual void add_component(size_t index, size_t offset);
+        RootRecordWriter (size_t pointer, size_t connected_component_count, size_t node_count, size_t max_tree_depth, 
+                    handlegraph::nid_t min_node_id, bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* records);
+
+        void set_connected_component_count(size_t connected_component_count);
+        void set_node_count(size_t node_count);
+        void set_max_tree_depth(size_t tree_depth);
+        void set_min_node_id(handlegraph::nid_t node_id);
+        void add_component(size_t index, size_t offset);
     };
     struct NodeRecord : SnarlTreeRecord {
 
         NodeRecord() {};
-        NodeRecord (size_t pointer, size_t node_offset, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records){
-            record_offset = pointer;
-            records = tree_records;
+        NodeRecord (size_t pointer, size_t node_offset, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records);
+        NodeRecord (net_handle_t net, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records);
 
-#ifdef debug_distance_indexing
-            assert(get_record_type() == NODE || get_record_type() == DISTANCED_NODE);
-#endif
-        }
-        NodeRecord (net_handle_t net, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records){
-            records = tree_records;
-            record_offset = get_record_offset(net);
-
-#ifdef debug_distance_indexing
-            assert(get_handle_type(net) == NODE_HANDLE || get_handle_type(net) == CHAIN_HANDLE);
-            assert(get_record_type() == NODE || get_record_type() == DISTANCED_NODE);
-            assert(get_connectivity(net) == START_END || get_connectivity(net) == END_START
-                  || get_connectivity(net) == START_START || get_connectivity(net) == END_END);
-#endif
-        }
+        handlegraph::nid_t get_node_id() const;
 
-        virtual handlegraph::nid_t get_node_id() const;
+        size_t get_node_length() const;
 
-        virtual size_t get_node_length() const;
+        //Get the distance from left/right of the node to start/end of the parent
+        size_t get_distance_left_start();
+        size_t get_distance_right_start();
+        size_t get_distance_left_end();
+        size_t get_distance_right_end();
 
     };
 
-    struct NodeRecordConstructor : NodeRecord , SnarlTreeRecordConstructor {
-        using SnarlTreeRecordConstructor::get_record_type;
-        using SnarlTreeRecordConstructor::record_offset;
-        using SnarlTreeRecordConstructor::records;
+    struct NodeRecordWriter : NodeRecord , SnarlTreeRecordWriter {
+        using SnarlTreeRecordWriter::get_record_type;
+        using SnarlTreeRecordWriter::record_offset;
+        using SnarlTreeRecordWriter::records;
 
 
         //Constructor meant for creating a new record, at the end of snarl_tree_records
         //The memory for all nodes has already been allocated by the root
-        NodeRecordConstructor (size_t pointer, size_t node_offset, record_t type, 
-            bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* snarl_records, nid_t node_id){
-            records = snarl_records;
-            record_offset =  pointer;
-            SnarlTreeRecordConstructor::record_offset = pointer;
-            SnarlTreeRecordConstructor::records = records;
-            NodeRecord::record_offset = pointer;
-            NodeRecord::records = records;
-
-            (*records)->resize((*records)->size() + NODE_RECORD_SIZE); 
-#ifdef count_allocations
-            cerr << "new_node\t" <<  NODE_RECORD_SIZE << "\t" << (*records)->size() << endl;
-#endif
-            set_record_type(type);
-            set_start_end_connected();
-
-            //Set the pointer for the node to this record
-#ifdef debug_distance_indexinging
-            assert (type == NODE || type == DISTANCED_NODE);
-
-            cerr << get_node_pointer_offset(node_id, 
-                                                   (*records)->at(MIN_NODE_ID_OFFSET), 
-                                                   (*records)->at(COMPONENT_COUNT_OFFSET))
-                 << " Set pointer to node " << node_id << " record: " << pointer << endl;
-#endif
-            //Tell the root where to find this node, and a 0 for the offset in a trivial snarl
-            (*records)->at(get_node_pointer_offset(node_id, 
-                                                   (*records)->at(MIN_NODE_ID_OFFSET), 
-                                                   (*records)->at(COMPONENT_COUNT_OFFSET))) = pointer;
-            (*records)->at(get_node_pointer_offset(node_id, 
-                                                   (*records)->at(MIN_NODE_ID_OFFSET), 
-                                                   (*records)->at(COMPONENT_COUNT_OFFSET))+1) = 0;
-
-        }
-        virtual void set_node_id(nid_t value);
-        virtual void set_rank_in_parent(size_t value);
-        virtual void set_node_length(size_t value);
+        NodeRecordWriter (size_t pointer, size_t node_offset, record_t type, 
+            bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* snarl_records, nid_t node_id);
+
+        void set_node_id(nid_t value);
+        void set_rank_in_parent(size_t value);
+        void set_node_length(size_t value);
+
+        //Set the distance from left/right of the node to start/end of the parent
+        void set_distance_left_start(size_t distance);
+        void set_distance_right_start(size_t distance);
+        void set_distance_left_end(size_t distance);
+        void set_distance_right_end(size_t distance);
     };
 
     struct TrivialSnarlRecord : SnarlTreeRecord {
 
         TrivialSnarlRecord() {};
 
-        virtual size_t get_node_count() const;
-        //Returns the prefix sum, forward loop, reverse loop, and component
+        size_t get_node_count() const;
+        //Returns the prefix sum, forward loop, reverse loop, and component.
         //The component will be 0 for the first/last node of a looping chain
-        virtual tuple<size_t, size_t, size_t, size_t> get_chain_values(size_t node_rank) const;
-        virtual size_t get_prefix_sum(size_t node_rank) const;
-        virtual size_t get_forward_loop(size_t node_rank) const ;
-        virtual size_t get_reverse_loop(size_t node_rank) const;
-        virtual size_t get_chain_component(size_t node_rank, bool get_end=false) const;
-        virtual nid_t get_node_id(size_t node_rank) const; 
-        virtual size_t get_node_length(size_t node_rank) const; 
-        virtual size_t get_rank_in_parent(size_t node_rank) const; 
-        virtual bool get_is_reversed_in_parent(size_t node_rank) const; //is the node_rank-th node reversed
-
-        virtual size_t get_record_size() { 
+
+        //Node ranks are from get_node_record_offset(net_handle_T)
+        tuple<size_t, size_t, size_t, size_t> get_chain_values(size_t node_rank) const;
+        size_t get_prefix_sum(size_t node_rank) const;
+        size_t get_max_prefix_sum(size_t node_rank) const;
+        size_t get_forward_loop(size_t node_rank) const ;
+        size_t get_reverse_loop(size_t node_rank) const;
+        size_t get_chain_component(size_t node_rank, bool get_end=false) const;
+        nid_t get_node_id(size_t node_rank) const; 
+        size_t get_node_length(size_t node_rank) const; 
+        size_t get_rank_in_parent(size_t node_rank) const; 
+        bool get_is_reversed_in_parent(size_t node_rank) const; //is the node_rank-th node reversed
+
+        size_t get_record_size() { 
             return TRIVIAL_SNARL_RECORD_SIZE + (get_node_count() * 2);
         }
-        TrivialSnarlRecord (size_t offset, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records){
-            records = tree_records;
-            record_offset = offset;
-
-#ifdef debug_distance_indexing
-            assert(get_record_type() == TRIVIAL_SNARL || get_record_type() == DISTANCED_TRIVIAL_SNARL);
-            //assert(get_connectivity(net) == START_END || get_connectivity(net) == END_START
-            //      || get_connectivity(net) == START_START || get_connectivity(net) == END_END);
-#endif
-        }
+        TrivialSnarlRecord (size_t offset, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records);
     };
 
     //For constructing a trivial snarl, we only build the snarl itself, and 
     //we don't initially know how many nodes it contains
     //
    
-    struct TrivialSnarlRecordConstructor : TrivialSnarlRecord, SnarlTreeRecordConstructor {
-        using SnarlTreeRecordConstructor::get_record_type;
-        using SnarlTreeRecordConstructor::record_offset;
-        using SnarlTreeRecordConstructor::records;
+    struct TrivialSnarlRecordWriter : TrivialSnarlRecord, SnarlTreeRecordWriter {
+        using SnarlTreeRecordWriter::get_record_type;
+        using SnarlTreeRecordWriter::record_offset;
+        using SnarlTreeRecordWriter::records;
 
-        virtual void set_prefix_sum(size_t value) const;
-        virtual void set_forward_loop(size_t value) const;
-        virtual void set_reverse_loop(size_t value) const;
-        virtual void set_chain_component(size_t value) const;
-        virtual void set_node_count(size_t value) const;
+        void set_prefix_sum(size_t value) const;
+        void set_max_prefix_sum(size_t value) const;
+        void set_forward_loop(size_t value) const;
+        void set_reverse_loop(size_t value) const;
+        void set_chain_component(size_t value) const;
+        void set_node_count(size_t value) const;
 
 
         //Constructor meant for creating a new record, at the end of snarl_tree_records
         //New record is true if this is the first time we're making this trivial snarl, false if we
         //just need the constructor to add a new node
-        TrivialSnarlRecordConstructor (size_t pointer, record_t type, 
-            bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* snarl_records, bool new_record){
-            records = snarl_records;
-            record_offset =  pointer;
-            SnarlTreeRecordConstructor::record_offset = pointer;
-            SnarlTreeRecordConstructor::records = records;
-            TrivialSnarlRecord::record_offset = pointer;
-            TrivialSnarlRecord::records = records;
-
-            assert (type == TRIVIAL_SNARL || type == DISTANCED_TRIVIAL_SNARL);
-
-#ifdef debug_distance_indexing
-            cerr << " Resizing array to add trivial snarl: length " << (*records)->size() << " -> "  << (*records)->size() + TRIVIAL_SNARL_RECORD_SIZE << endl;
-#endif
-
-            if (new_record) {
-                (*records)->resize(record_offset + TRIVIAL_SNARL_RECORD_SIZE);
-                set_record_type(type);
-                set_start_end_connected();
-#ifdef count_allocations
-            cerr << "new_trivial_snarl\t" << TRIVIAL_SNARL_RECORD_SIZE << "\t" << (*records)->size() << endl;
-#endif
-            }
-
-        }
+        TrivialSnarlRecordWriter (size_t pointer, record_t type, 
+            bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* snarl_records, bool new_record);
     };
 
     struct SnarlRecord : SnarlTreeRecord {
 
 
         SnarlRecord() {};
-        SnarlRecord (size_t pointer, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records){
-            record_offset = pointer;
-            records = tree_records;
-#ifdef debug_distance_indexing
-            record_t type = get_record_type();
-            assert(type == SNARL || type == DISTANCED_SNARL || type == OVERSIZED_SNARL || type == ROOT_SNARL
-                || type == ROOT_SNARL || type == DISTANCED_ROOT_SNARL);
-#endif
-        }
+        SnarlRecord (size_t pointer, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records);
 
-        SnarlRecord (net_handle_t net, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records){
-            record_offset = get_record_offset(net);
-            records = tree_records;
-#ifdef debug_distance_indexing
-            net_handle_record_t type = get_handle_type(net);
-            assert(type == SNARL_HANDLE || type == SENTINEL_HANDLE || type == ROOT_HANDLE);
-#endif
-        }
+        SnarlRecord (net_handle_t net, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records);
 
         //How big is the entire snarl record?
         static size_t distance_vector_size(record_t type, size_t node_count);
         static size_t record_size (record_t type, size_t node_count) ;
-        virtual size_t record_size() ;
+        size_t record_size() ;
 
         //Get the index into the distance vector for the calculating distance between the given node sides
         static size_t get_distance_vector_offset(size_t rank1, bool right_side1, size_t rank2, 
                 bool right_side2, size_t node_count, record_t type); 
 
-        virtual size_t get_distance_vector_offset(size_t rank1, bool right_side1, 
+        size_t get_distance_vector_offset(size_t rank1, bool right_side1, 
                 size_t rank2, bool right_side2) const;
 
-        //TODO: I want to also add a function to do this given a node id or net_handle_t instead of rank
         //Get and set the distances between two node sides in the graph
         //Ranks identify which node, sides indicate node side: false for left, true for right
-        virtual size_t get_distance(size_t rank1, bool right_side1, size_t rank2, bool right_side2) const;
+        size_t get_distance(size_t rank1, bool right_side1, size_t rank2, bool right_side2) const;
 
-        virtual size_t get_node_count() const;
+        size_t get_distance_start_start() const;
+        size_t get_distance_end_end() const;
 
-        virtual size_t get_child_record_pointer() const;
+        size_t get_node_count() const;
 
-        virtual bool for_each_child(const std::function<bool(const net_handle_t&)>& iteratee) const;
+        size_t get_child_record_pointer() const;
+
+        bool for_each_child(const std::function<bool(const net_handle_t&)>& iteratee) const;
 
     };
 
-    struct SnarlRecordConstructor : SnarlRecord , SnarlTreeRecordConstructor {
-        using SnarlTreeRecordConstructor::records;
-        using SnarlTreeRecordConstructor::record_offset;
-        using SnarlTreeRecordConstructor::get_record_type;
-
-
-        SnarlRecordConstructor();
-
-        SnarlRecordConstructor (size_t node_count, bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* records, record_t type){
-            //Constructor for making a new record, including allocating memory.
-            //Assumes that this is the latest record being made, so pointer will be the end of
-            //the array and we need to allocate extra memory past it
-            //TODO:I'm not sure yet how memory will actually be allocated
-            records = records;
-            record_offset = (*records)->size();
-            SnarlTreeRecordConstructor::record_offset = (*records)->size();
-            SnarlTreeRecordConstructor::records = records;
-            SnarlRecord::record_offset = (*records)->size();
-            SnarlRecord::records = records;
-
-            size_t extra_size = record_size(type, node_count);
-            if (type == OVERSIZED_SNARL) {
-                cerr << "oversized" << endl;
-            }
-#ifdef debug_distance_indexing
-            cerr << " Resizing array to add snarl: length " << (*records)->size() << " -> "  << (*records)->size() + extra_size << endl;
-#endif
-            (*records)->resize((*records)->size() + extra_size);
-            set_node_count(node_count);
-            set_record_type(type);
-#ifdef count_allocations
-            cerr << "new_snarl\t" << extra_size << "\t" << (*records)->size() << endl;
-#endif
-        }
-        SnarlRecordConstructor(bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* records, size_t pointer) {
-            //Make a constructor for a snarl record that has already been allocated.
-            //For adding children to an existing snarl record
-            record_offset = pointer;
-            records = records;
-            SnarlTreeRecordConstructor::records = records;
-            SnarlTreeRecordConstructor::record_offset = pointer;
-            SnarlRecord::records = records;
-            SnarlRecord::record_offset = pointer;
-        }
+    struct SnarlRecordWriter : SnarlRecord , SnarlTreeRecordWriter {
+        using SnarlTreeRecordWriter::records;
+        using SnarlTreeRecordWriter::record_offset;
+        using SnarlTreeRecordWriter::get_record_type;
+
+
+        SnarlRecordWriter();
+
+        SnarlRecordWriter (size_t node_count, bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* records, record_t type);
+        SnarlRecordWriter(bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* records, size_t pointer);
 
-        //Set the bit width used for storing distances 
         void set_distance(size_t rank1, bool right_side1, size_t rank2, bool right_side2, size_t distance);
 
+        void set_distance_start_start(size_t value);
+        void set_distance_end_end(size_t value) ;
+
         //Node count is the number of nodes in the snarl, not including boundary nodes
         void set_node_count(size_t node_count);
 
@@ -1299,89 +1182,37 @@ class SnarlDistanceIndex : public SnarlDecomposition, public TriviallySerializab
         size_t node_rank;
 
         SimpleSnarlRecord() {};
-        SimpleSnarlRecord (size_t pointer, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records, size_t node = std::numeric_limits<size_t>::max()){
-            record_offset = pointer;
-            records = tree_records;
-            node_rank = node; 
-#ifdef debug_distance_indexing
-            assert (node_rank >=2);
-            assert(get_record_type() == SIMPLE_SNARL || get_record_type() == DISTANCED_SIMPLE_SNARL);
-#endif
-        }
+        SimpleSnarlRecord (size_t pointer, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records, size_t node = std::numeric_limits<size_t>::max());
 
-        SimpleSnarlRecord (net_handle_t net, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records){
-            record_offset = get_record_offset(net);
-            records = tree_records;
-            node_rank = get_node_record_offset(net) == 1 ? std::numeric_limits<size_t>::max() : get_node_record_offset(net);
-
-#ifdef debug_distance_indexing
-            assert (node_rank >=2);
-            assert(get_record_type() == SIMPLE_SNARL || get_record_type() == DISTANCED_SIMPLE_SNARL);
-#endif
-        }
+        SimpleSnarlRecord (net_handle_t net, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records);
 
         //How big is the entire snarl record?
         const static size_t record_size(size_t node_count) {return SIMPLE_SNARL_RECORD_SIZE + (node_count*2);}
-        virtual size_t record_size() ;
+        size_t record_size() ;
 
         //Get and set the distances between two node sides in the graph
         //Ranks identify which node, sides indicate node side: false for left, true for right
-        virtual size_t get_distance(size_t rank1, bool right_side1, size_t rank2, bool right_side2) const;
+        size_t get_distance(size_t rank1, bool right_side1, size_t rank2, bool right_side2) const;
 
-        virtual size_t get_node_count() const;
+        size_t get_node_count() const;
 
         nid_t get_node_id(size_t rank = std::numeric_limits<size_t>::max()) const;
         size_t get_node_length(size_t rank = std::numeric_limits<size_t>::max()) const;
         bool get_node_is_reversed(size_t rank = std::numeric_limits<size_t>::max()) const;
 
-        virtual bool for_each_child(const std::function<bool(const net_handle_t&)>& iteratee) const;
+        bool for_each_child(const std::function<bool(const net_handle_t&)>& iteratee) const;
 
     };
-    struct SimpleSnarlRecordConstructor : SimpleSnarlRecord , SnarlTreeRecordConstructor {
-        using SnarlTreeRecordConstructor::records;
-        using SnarlTreeRecordConstructor::record_offset;
-        using SnarlTreeRecordConstructor::get_record_type;
-
-
-        SimpleSnarlRecordConstructor();
-
-        SimpleSnarlRecordConstructor (size_t node_count, bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* records, record_t type){
-            //Constructor for making a new record, including allocating memory.
-            //Assumes that this is the latest record being made, so pointer will be the end of
-            //the array and we need to allocate extra memory past it
-            //TODO:I'm not sure yet how memory will actually be allocated
-            records = records;
-            record_offset = (*records)->size();
-            SnarlTreeRecordConstructor::record_offset = (*records)->size();
-            SnarlTreeRecordConstructor::records = records;
-            SimpleSnarlRecord::record_offset = (*records)->size();
-            SimpleSnarlRecord::records = records;
-
-#ifdef debug_distance_indexing
-            cerr << " Resizing array to add simple snarl: length " << (*records)->size() << " -> "  << (*records)->size() + SIMPLE_SNARL_RECORD_SIZE + 2*node_count << endl;
-            cerr << "\t simple snarl has " << node_count << " nodes " << endl;
-#endif
-            (*records)->resize((*records)->size() + SIMPLE_SNARL_RECORD_SIZE + 2*node_count);
-            set_node_count(node_count);
-            set_record_type(type);
-            set_node_count(node_count);
-            set_start_end_connected();
-#ifdef count_allocations
-            cerr << "new_simple_snarl\t" << SIMPLE_SNARL_RECORD_SIZE << "\t" << (*records)->size() << endl;
-            cerr << "simple_snarl_nodes\t" << (node_count*2) << "\t" << (*records)->size() << endl;
-#endif
-        }
-        SimpleSnarlRecordConstructor(bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* records, size_t pointer) {
-            //Make a constructor for a snarl record that has already been allocated.
-            //For adding children to an existing snarl record
-            record_offset = pointer;
-            records = records;
-            SnarlTreeRecordConstructor::record_offset = pointer;
-            SnarlTreeRecordConstructor::records = records;
-            SimpleSnarlRecord::record_offset = pointer;
-            SimpleSnarlRecord::records = records;
+    struct SimpleSnarlRecordWriter : SimpleSnarlRecord , SnarlTreeRecordWriter {
+        using SnarlTreeRecordWriter::records;
+        using SnarlTreeRecordWriter::record_offset;
+        using SnarlTreeRecordWriter::get_record_type;
 
-        }
+
+        SimpleSnarlRecordWriter();
+
+        SimpleSnarlRecordWriter (size_t node_count, bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* records, record_t type);
+        SimpleSnarlRecordWriter(bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* records, size_t pointer);
 
 
         //Node count is the number of nodes in the snarl, not including boundary nodes
@@ -1395,139 +1226,78 @@ class SnarlDistanceIndex : public SnarlDecomposition, public TriviallySerializab
     struct ChainRecord : SnarlTreeRecord {
 
         ChainRecord() {};
-        ChainRecord (size_t pointer, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records){
-            record_offset = pointer;
-            records = tree_records;
-            net_handle_record_t record_type= get_record_handle_type();
-            if (record_type == NODE_HANDLE) {
-                net_handle_record_t parent_type = SnarlTreeRecord(
-                    NodeRecord(pointer, 0, records).get_parent_record_offset(), records
-                ).get_record_handle_type();
-#ifdef debug_distance_indexing
-                assert(parent_type == ROOT_HANDLE || parent_type == SNARL_HANDLE);
-#endif
-            } else {
-#ifdef debug_distance_indexing
-                assert(get_record_handle_type() == CHAIN_HANDLE);
-#endif
-            }
-        }
-        ChainRecord (net_handle_t net, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records){
-            record_offset = get_record_offset(net);
-            records = tree_records;
-
-            net_handle_record_t record_type = get_record_handle_type();
-#ifdef debug_distance_indexing
-            if (record_type == NODE_HANDLE) {
-                net_handle_record_t parent_type = SnarlTreeRecord(
-                    NodeRecord(record_offset, 0, records).get_parent_record_offset(), records
-                ).get_record_handle_type();
-                assert(parent_type == ROOT_HANDLE || parent_type == SNARL_HANDLE);
-            } else {
-                assert(get_record_handle_type() == CHAIN_HANDLE);
-            }
-#endif
-        }
-        ChainRecord (net_handle_t net, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records, size_t tag){
-            record_offset = get_record_offset(net);
-            records = tree_records;
-
-#ifdef debug_distance_indexing
-            net_handle_record_t record_type= SnarlDistanceIndex::get_record_handle_type(SnarlDistanceIndex::get_record_type(tag));
-            if (record_type == NODE_HANDLE) {
-                net_handle_record_t parent_type = SnarlTreeRecord(
-                    NodeRecord(record_offset, 0, records).get_parent_record_offset(), records
-                ).get_record_handle_type();
-                assert(parent_type == ROOT_HANDLE || parent_type == SNARL_HANDLE);
-            } else {
-                assert(get_record_handle_type() == CHAIN_HANDLE);
-            }
-#endif
-        }
+        ChainRecord (size_t pointer, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records);
+        ChainRecord (net_handle_t net, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records);
+        ChainRecord (net_handle_t net, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records, size_t tag);
 
-        virtual size_t get_node_count() const;
+        size_t get_node_count() const;
 
-        ///Returns (offset, is_snarl, node_offset)
+        ///Returns (offset, is_snarl, node_offset).
         //node_offset is 0 if it is a snarl
-        virtual tuple<size_t, bool, size_t> get_last_child_offset() const;
+        tuple<size_t, bool, size_t> get_last_child_offset() const;
 
         ///Returns true if it is a looping chain and the last node is connected to the rest of the chain by going backwards
-        virtual bool get_is_looping_chain_connected_backwards() const;
+        bool get_is_looping_chain_connected_backwards() const;
 
-        virtual size_t get_depth() const;
+        size_t get_depth() const;
 
-        //Get the distance between the given node sides (relative to the orientation of the chain)
-        //The ranks are the offsets of the nodes in the chain (points to the record tag)
+        //Get the distance between the given node sides (relative to the orientation of the chain).
+        //The ranks are the offsets of the nodes in the chain (points to the record tag).
         //This is the distance between the node sides, leaving the first and entering the second,
-        //not including node lengths
+        //not including node lengths.
         //is_looping_chain indicates whether this chain loops 
-        //and last_chain_component is the component of the last thing in the chain
-        //component is the default component of the chain and end_component is the component if it is a looping chain and we want the second component of the first/last node
-        //TODO: Double check finding the distance for the same node
-        virtual size_t get_distance(size_t rank1, bool right_side1, size_t node_length1, 
+        //and last_chain_component is the component of the last thing in the chain.
+        //component is the default component of the chain and end_component is the component if it is a looping chain and we want the second component of the first/last node.
+        size_t get_distance(size_t rank1, bool right_side1, size_t node_length1, 
                                     size_t prefix_sum1, size_t forward_loop1, size_t reverse_loop1, size_t component1, size_t end_component1,
                                     size_t rank2, bool right_side2, size_t node_length2,
                                     size_t prefix_sum2, size_t forward_loop2, size_t reverse_loop2, size_t component2, size_t end_component2) const;
 
         ///For a chain that loops (when the start and end node are the same), find the 
         //distance walking around the back of the loop
-        virtual size_t get_distance_taking_chain_loop(size_t rank1, bool right_side1, size_t node_length1, 
+        size_t get_distance_taking_chain_loop(size_t rank1, bool right_side1, size_t node_length1, 
                                     size_t prefix_sum1, size_t forward_loop1, size_t reverse_loop1, size_t component1,
                                     size_t rank2, bool right_side2, size_t node_length2,
                                     size_t prefix_sum2, size_t forward_loop2, size_t reverse_loop2, size_t component2) const;
 
+        //Get the distance from left/right of the chain to start/end of the parent
+        size_t get_distance_left_start();
+        size_t get_distance_right_start();
+        size_t get_distance_left_end();
+        size_t get_distance_right_end();
+
         ////////////////////////// methods for navigating the snarl tree from this chain
 
         //Get the offset into snarl_tree_records of the first node in the chain
-        virtual size_t get_first_node_offset() const; 
+        size_t get_first_node_offset() const; 
 
-        //Given a net_Handle_t to a child node, return the next child
-        //go_left is true if we are traversing the chain right to left
+        //Given a net_Handle_t to a child node, return the next child.
+        //go_left is true if we are traversing the chain right to left.
         //
-        //return the same net_handle_t if this is trying to walk out the end of the chain
+        //return the same net_handle_t if this is trying to walk out the end of the chain.
         //
-        //For looping chains, this one has to know whether the boundary node is representing the start or end
-        //This means that you only see the boundary node as the start or the end
+        //For looping chains, this one has to know whether the boundary node is representing the start or end.
+        //This means that you only see the boundary node as the start or the end.
         //
-        //The next handle will be pointing in the direction that we just moved
-        virtual net_handle_t get_next_child(const net_handle_t& net_handle, bool go_left) const;
+        //The next handle will be pointing in the direction that we just moved.
+        net_handle_t get_next_child(const net_handle_t& net_handle, bool go_left) const;
+
+        bool for_each_child(const std::function<bool(const net_handle_t&)>& iteratee) const;
 
-        virtual bool for_each_child(const std::function<bool(const net_handle_t&)>& iteratee) const;
     };
 
-    struct ChainRecordConstructor : ChainRecord , SnarlTreeRecordConstructor {
-        //Constructor for a chain record
+    struct ChainRecordWriter : ChainRecord , SnarlTreeRecordWriter {
+        //Constructor for a chain record.
         //Since the size of the vector will be unknown (since we don't know how big the snarls are),
         //Add nodes and snarls as they come up. Assumes that the memory has already been reserved but
-        //not allocated yet
-        using SnarlTreeRecordConstructor::records;
-        using SnarlTreeRecordConstructor::record_offset;
-        using SnarlTreeRecordConstructor::get_record_type;
-
-        //TODO: I don't think I even need node count
-        ChainRecordConstructor() {}
-        ChainRecordConstructor (size_t pointer, record_t type, size_t node_count, bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* records){
-#ifdef debug_distance_indexing
-            assert(type == CHAIN || 
-                   type == DISTANCED_CHAIN ||
-                   type == MULTICOMPONENT_CHAIN);
-#endif
-            record_offset = pointer;
-            records = records;
-            SnarlTreeRecordConstructor::record_offset = pointer;
-            SnarlTreeRecordConstructor::records = records;
-            ChainRecord::record_offset = pointer;
-            ChainRecord::records = records;
-#ifdef debug_distance_indexing
-            cerr << " Resizing array to add chain: length " << (*records)->size() << " -> "  << (*records)->size() + CHAIN_RECORD_SIZE << endl;
-#endif
-            (*records)->resize((*records)->size() + CHAIN_RECORD_SIZE);
-            set_node_count(node_count);
-            set_record_type(type);
-#ifdef count_allocations
-            cerr << "new_chain\t" << CHAIN_RECORD_SIZE << "\t" << (*records)->size() << endl;
-#endif
-        }
+        //not allocated yet.
+        using SnarlTreeRecordWriter::records;
+        using SnarlTreeRecordWriter::record_offset;
+        using SnarlTreeRecordWriter::get_record_type;
+
+        ChainRecordWriter() {}
+        ChainRecordWriter (size_t pointer, record_t type, size_t node_count, bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* records);
+
 
 
         void set_node_count(size_t node_count);
@@ -1536,32 +1306,39 @@ class SnarlDistanceIndex : public SnarlDecomposition, public TriviallySerializab
         //The offset of the last child, if it is a snarl, and if it can loop 
         void set_last_child_offset(size_t offset, bool is_snarl, bool loopable);
 
-        /* Functions to add children to a chain. Assumes that the chain is well formed up to here
+        //Set the distance from left/right of the chain to start/end of the parent
+        void set_distance_left_start(size_t distance);
+        void set_distance_right_start(size_t distance);
+        void set_distance_left_end(size_t distance);
+        void set_distance_right_end(size_t distance);
+
+        /* Functions to add children to a chain. Assumes that the chain is well formed up to here.
          * These will always be called in order going forward in the chain.
          * The chain is actually composed of snarl records and trivial snarl records, but we 
-         * add things by node and snarl
-         * We need to keep a SnarlTreeRecordConstructor to the last thing that we added (snarl or trivial snarl),
+         * add things by node and snarl.
+         * We need to keep a SnarlTreeRecordWriter to the last thing that we added (snarl or trivial snarl),
          * so that when we add nodes we either add them to the end of the last trivial snarl or 
          * (if we have too many nodes in the last trivial snarl or if the last thing on the chain is a snarl) 
-         * create a new trivial snarl 
+         * create a new trivial snarl .
          * Each (trivial/simple) snarl record is flanked by the size of the record, so it will be 
          * [chain info] ts size | ts record | s size | s record | s size | ts size | ts | ts size ....
          *
          */
 
-        //Add a snarl to the end of the chain and return a SnarlRecordConstructor pointing to it
-        SnarlRecordConstructor add_snarl(size_t snarl_size, record_t type, size_t previous_child_offset); 
-        SimpleSnarlRecordConstructor add_simple_snarl(size_t snarl_size, record_t type, size_t previous_child_offset); 
+        //Add a snarl to the end of the chain and return a SnarlRecordWriter pointing to it
+        SnarlRecordWriter add_snarl(size_t snarl_size, record_t type, size_t previous_child_offset); 
+        SimpleSnarlRecordWriter add_simple_snarl(size_t snarl_size, record_t type, size_t previous_child_offset); 
         //Add a node to the end of a chain and return the offset of the record it got added to
+        //If new_record is true, make a new trivial snarl record for the node
         size_t add_node(nid_t node_id, size_t node_length, bool is_reversed_in_parent,
-                size_t prefix_sum, size_t forward_loop, size_t reverse_loop, size_t component, size_t previous_child_offset);
+                size_t prefix_sum, size_t forward_loop, size_t reverse_loop, size_t component, 
+                size_t max_prefix_sum, size_t previous_child_offset, bool new_record);
 
     };
 
 
 private:
     ////////////////////// More methods for dealing with net_handle_ts
-    //TODO these never get used
     SnarlTreeRecord get_snarl_tree_record(const handlegraph::net_handle_t& net_handle) const {
         return SnarlTreeRecord(get_record_offset(net_handle), &snarl_tree_records);
     }
@@ -1580,18 +1357,38 @@ class SnarlDistanceIndex : public SnarlDecomposition, public TriviallySerializab
     //Return a string of what the handle is
     std::string net_handle_as_string(const net_handle_t& net) const;
 
-    //Print the entire index to cout
+    //Traverse the decomposition and run snarl/chain/node iteratee for ever snarl/chain/node.
+    //No guarantees are made about the order of the traversal.
+    //Each iteratee returns false to stop iterating and true to continue.
+    //Returns false if it was stopped early, true if it finished.
+    bool traverse_decomposition(const std::function<bool(const net_handle_t&)>& snarl_iteratee,
+                                const std::function<bool(const net_handle_t&)>& chain_iteratee,
+                                const std::function<bool(const net_handle_t&)>& node_iteratee) const;
+    bool traverse_decomposition_helper(const net_handle_t& net,
+                                const std::function<bool(const net_handle_t&)>& snarl_iteratee,
+                                const std::function<bool(const net_handle_t&)>& chain_iteratee,
+                                const std::function<bool(const net_handle_t&)>& node_iteratee) const;
+        
+
+    //Print the entire index to cout.
     //Prints each snarl, chain, and node in the index, top down, one per line as a csv: 
     // self, parent, # children, depth
     void print_self() const;
     //Helper function for print self that recursively prints a net handle
-    //and all its descendants
+    //and all its descendants.
     void print_descendants_of(const net_handle_t net) const;
 
+    //Print stats about every snarl to stdout.
+    //tab separated file of:
+    //start_id  end_id  node count  depth
+    void print_snarl_stats() const;
+
+    //Write a json file of every snarl, chain, and node to stderr
+    void write_snarls_to_json() const;
+
     //Validate the distance index. Without debug turned on, this will only
     //assert a bunch of stuff and try to write the thing that fails to cerr
-    //With debug turned on, write the whole index the same as print_self
-
+    //With debug turned on, write the whole index the same as print_self.
     void validate_index() const;
     void validate_descendants_of(const net_handle_t net) const;
     void validate_ancestors_of(const net_handle_t net) const;
@@ -1602,7 +1399,7 @@ class SnarlDistanceIndex : public SnarlDecomposition, public TriviallySerializab
 public:
 
     /*
-     * A structure to store everything in the distance index, but not in just one vector to make it easier to construct
+     * A structure to store everything in the distance index, but not in just one vector to make it easier to construct.
      * This can also be used to combine distance indexes
      */
     enum temp_record_t {TEMP_CHAIN=0, TEMP_SNARL, TEMP_NODE, TEMP_ROOT};
@@ -1619,7 +1416,7 @@ class SnarlDistanceIndex : public SnarlDecomposition, public TriviallySerializab
         handlegraph::nid_t max_node_id=0;
         size_t root_structure_count=0; //How many things are in the root
         size_t max_tree_depth = 0;
-        size_t max_index_size= 0;//TODO: This will change depending on how the actual index is represented
+        size_t max_index_size= 0;
         size_t max_distance = 0;
         size_t get_max_record_length() const; 
 
@@ -1642,9 +1439,17 @@ class SnarlDistanceIndex : public SnarlDecomposition, public TriviallySerializab
             vector<pair<temp_record_t, size_t>> children; //All children, both nodes and snarls, in order
             //Distances for the chain, one entry per node
             vector<size_t> prefix_sum;
+            vector<size_t> max_prefix_sum;
             vector<size_t> forward_loops;
             vector<size_t> backward_loops;
             vector<size_t> chain_components;//Which component does each node belong to, usually all 0s
+
+            //Distances from the left/right of the node to the start/end of the parent snarl
+            size_t distance_left_start = std::numeric_limits<size_t>::max();
+            size_t distance_right_start = std::numeric_limits<size_t>::max();
+            size_t distance_left_end = std::numeric_limits<size_t>::max();
+            size_t distance_right_end = std::numeric_limits<size_t>::max();
+
             size_t rank_in_parent;
             bool reversed_in_parent;
             bool is_trivial;
@@ -1662,24 +1467,28 @@ class SnarlDistanceIndex : public SnarlDecomposition, public TriviallySerializab
             bool end_node_rev;
             size_t end_node_length;
             size_t node_count;
-            size_t min_length; //Not including boundary nodes
+            size_t min_length = std::numeric_limits<size_t>::max(); //Not including boundary nodes
             size_t max_length = 0;
             size_t max_distance = 0;
             size_t tree_depth = 0;
             pair<temp_record_t, size_t> parent;
             vector<pair<temp_record_t, size_t>> children; //All children, nodes and chains, in arbitrary order
             unordered_set<size_t> tippy_child_ranks; //The ranks of children that are tips
-            vector<tuple<pair<size_t, bool>, pair<size_t, bool>, size_t>> distances;
-            //unordered_map<pair<pair<size_t, bool>, pair<size_t, bool>>, size_t> distances;
+            //vector<tuple<pair<size_t, bool>, pair<size_t, bool>, size_t>> distances;
+            unordered_map<pair<pair<size_t, bool>, pair<size_t, bool>>, size_t> distances;
+
+            size_t distance_start_start = std::numeric_limits<size_t>::max();
+            size_t distance_end_end = std::numeric_limits<size_t>::max();
+
             size_t rank_in_parent;
             bool reversed_in_parent;
-            //The minimum distances to go into and out of the snarl from the start or end nodes
-            size_t loop_start;
-            size_t loop_end;
             bool is_trivial;
             bool is_simple;
             bool is_tip = false;
             bool is_root_snarl = false;
+
+            //If any distance was too big, then make this an oversized snarl
+            bool skipped_distances=false;
             size_t get_max_record_length() const ;
         };
         struct TemporaryNodeRecord : TemporaryRecord{
@@ -1694,6 +1503,13 @@ class SnarlDistanceIndex : public SnarlDecomposition, public TriviallySerializab
             bool reversed_in_parent;
             bool is_tip = false;
             size_t root_snarl_index = std::numeric_limits<size_t>::max();
+            //Distances from the left/right of the node to the start/end of the parent snarl
+            size_t distance_left_start = std::numeric_limits<size_t>::max();
+            size_t distance_right_start = std::numeric_limits<size_t>::max();
+            size_t distance_left_end = std::numeric_limits<size_t>::max();
+            size_t distance_right_end = std::numeric_limits<size_t>::max();
+
+
             const static size_t get_max_record_length() {
                 return NODE_RECORD_SIZE;} 
         };
@@ -1712,16 +1528,18 @@ class SnarlDistanceIndex : public SnarlDecomposition, public TriviallySerializab
 
 public:
     ///Add integers, returning max() if any of them are max()
-    static size_t sum(const vector<size_t> vals) {
-        size_t sum = 0;
-        for (const size_t& x : vals) {
-            if (x ==  std::numeric_limits<size_t>::max()) {
-                return std::numeric_limits<size_t>::max();
-            } else {
-                sum += x;
-            }
+    static size_t sum(const size_t& val1, const size_t& val2) {
+        if (val1 == std::numeric_limits<size_t>::max() || val2 == std::numeric_limits<size_t>::max()) {
+            return std::numeric_limits<size_t>::max();
+        } else {
+            return val1 + val2;
         }
-        return sum;
+    }
+    static size_t sum(const vector<size_t>& vals) {
+        return std::accumulate(vals.begin(), vals.end(), 0, 
+            [](const size_t& a, const size_t& b) {
+                return sum(a, b);
+            });
     }
     static size_t minus(size_t x, size_t y) {
         if (x == std::numeric_limits<size_t>::max()) {
@@ -1732,15 +1550,25 @@ class SnarlDistanceIndex : public SnarlDecomposition, public TriviallySerializab
             return x - y;
         }
     }
+    //The maximum that isn't infinite
+    static size_t maximum(size_t x, size_t y) {
+        if (x == std::numeric_limits<size_t>::max()) {
+            return y;
+        } else if (y == std::numeric_limits<size_t>::max()) {
+            return x;
+        } else {
+            return std::max(x, y);
+        }
+    }
     //How many bits are needed to represent this value (with some wiggle room)
     static size_t bit_width(size_t value) {
         return log2(value+1) + 3;
-
     }
 public:
     //Given an arbitrary number of temporary indexes, produce the final one
     //Each temporary index must be a separate connected component
-    void get_snarl_tree_records(const vector<const TemporaryDistanceIndex*>& temporary_indexes, const     HandleGraph* graph);
+    void get_snarl_tree_records(const vector<const TemporaryDistanceIndex*>& temporary_indexes, const HandleGraph* graph);
+
     void time_accesses();
 
 };
diff --git a/bdsg/src/snarl_distance_index.cpp b/bdsg/src/snarl_distance_index.cpp
index 6b48c676..a2782255 100644
--- a/bdsg/src/snarl_distance_index.cpp
+++ b/bdsg/src/snarl_distance_index.cpp
@@ -1,8 +1,11 @@
 //#define debug_distance_indexing
 //#define debug_snarl_traversal
 //#define debug_distances
+//#define debug_distance_paths
 
 #include "bdsg/snarl_distance_index.hpp"
+#include <jansson.h>
+#include <arpa/inet.h>
 
 using namespace std;
 using namespace handlegraph;
@@ -113,7 +116,7 @@ size_t SnarlDistanceIndex::TemporaryDistanceIndex::TemporarySnarlRecord::get_max
 
 net_handle_t SnarlDistanceIndex::get_root() const {
     // The root is the first thing in the index, the traversal is tip to tip
-    return get_net_handle_from_values(0, START_END, ROOT_HANDLE);
+    return get_net_handle_from_values(0, TIP_TIP, ROOT_HANDLE);
 }
 
 bool SnarlDistanceIndex::is_root(const net_handle_t& net) const {
@@ -121,9 +124,14 @@ bool SnarlDistanceIndex::is_root(const net_handle_t& net) const {
 }
 
 bool SnarlDistanceIndex::is_root_snarl(const net_handle_t& net) const {
-    return get_handle_type(net) == ROOT_HANDLE &&
-           (SnarlTreeRecord(net, &snarl_tree_records).get_record_type() == ROOT_SNARL ||
-           SnarlTreeRecord(net, &snarl_tree_records).get_record_type() == DISTANCED_ROOT_SNARL);
+#ifdef debug_distances
+    if (get_handle_type(net) == ROOT_HANDLE && get_record_offset(net) != 0) {
+        assert(SnarlTreeRecord(net, &snarl_tree_records).get_record_type() == ROOT_SNARL ||
+               SnarlTreeRecord(net, &snarl_tree_records).get_record_type() == DISTANCED_ROOT_SNARL);
+    }
+#endif
+
+    return get_handle_type(net) == ROOT_HANDLE && get_record_offset(net) != 0;
 }
 
 
@@ -181,10 +189,12 @@ bool SnarlDistanceIndex::is_looping_chain(const net_handle_t& net) const {
 }
 bool SnarlDistanceIndex::is_ordered_in_chain(const net_handle_t& child1, const net_handle_t& child2) const {
 #ifdef debug_distances
-    if (!(is_chain(get_parent(child1)) && get_parent(child1) == get_parent(child2))) {
-        throw runtime_error("error: trying to get a handle from a snarl, chain, or root");
+    cerr << "are children " << net_handle_as_string(child1) << " and " << net_handle_as_string(child2) << " ordered in parent " << net_handle_as_string(get_parent(child1)) << "?" << endl;
+    if (!(is_chain(get_parent(child1)) && canonical(get_parent(child1)) == canonical(get_parent(child2)))) {
+        throw runtime_error("error: Trying to see if two children are ordered in a non-chain parent or different parents");
     }
-    /*TODO: This is the proper way to do it but it takes too long so just double check this if anything changes
+    /*This is the proper way to do it since it doesn't depend on how I'm storing the children of the chain,
+     * but it takes too long so just double check this if anything changes
     size_t rank1 = is_node(child1) ? TrivialSnarlRecord(get_record_offset(child1), &snarl_tree_records).get_rank_in_parent(get_node_record_offset(child1))
                                    : SnarlTreeRecord(child1, &snarl_tree_records).get_rank_in_parent();
     size_t rank2 = is_node(child2) ? TrivialSnarlRecord(get_record_offset(child2), &snarl_tree_records).get_rank_in_parent(get_node_record_offset(child2))
@@ -196,15 +206,7 @@ bool SnarlDistanceIndex::is_ordered_in_chain(const net_handle_t& child1, const n
 
     return  rank1 < rank2;
 }
-size_t SnarlDistanceIndex::get_record_offset_in_chain(const net_handle_t& child) const {
-#ifdef debug_distances
-        throw runtime_error("error: net handle isn't in a chain");
-#endif
 
-     return is_node(child) ? TrivialSnarlRecord(get_record_offset(child), &snarl_tree_records).get_rank_in_parent(get_node_record_offset(child))
-                                    : SnarlTreeRecord(child, &snarl_tree_records).get_rank_in_parent();
-;
-}
 
 bool SnarlDistanceIndex::is_trivial_chain(const net_handle_t& net) const {
     bool handle_is_chain =get_handle_type(net) == CHAIN_HANDLE; 
@@ -266,9 +268,25 @@ handle_t SnarlDistanceIndex::get_handle(const net_handle_t& net, const handlegra
 }
 
 net_handle_t SnarlDistanceIndex::get_parent(const net_handle_t& child) const {
+
+    connectivity_t child_connectivity = get_connectivity(child);
+
     //If the child is the sentinel of a snarl, just return the snarl
     if (get_handle_type(child) == SENTINEL_HANDLE) {
-        return get_net_handle_from_values(get_record_offset(child), START_END, SNARL_HANDLE, get_node_record_offset(child)); 
+        connectivity_t parent_connectivity = START_END;
+        if (child_connectivity == START_END || child_connectivity == END_START) {
+            //If the child sentinel is pointing through the snarl, then the snarl should point
+            //in the same direction
+            parent_connectivity = child_connectivity;
+        } else if (child_connectivity == START_START) {
+            //If the sentinel is the start node pointing out, then the parent should point out the start
+            parent_connectivity = END_START;
+        } else if (child_connectivity == END_END) {
+            //If the sentinel is the end node pointing out, then the parent should point out the end
+            parent_connectivity = START_END;
+        }
+        return get_net_handle_from_values(get_record_offset(child), parent_connectivity, 
+                                          SNARL_HANDLE, get_node_record_offset(child)); 
     } else if (get_handle_type(child) == ROOT_HANDLE) {
         throw runtime_error("error: trying to find the parent of the root");
     } else if (get_record_type(snarl_tree_records->at(get_record_offset(child))) == SIMPLE_SNARL ||
@@ -276,7 +294,8 @@ net_handle_t SnarlDistanceIndex::get_parent(const net_handle_t& child) const {
         //If this is a simple snarl and a node or chain, then the parent offset doesn't change
         if (get_handle_type(child) == NODE_HANDLE) {
             //If this is a node, then return it as a chain
-            return get_net_handle_from_values(get_record_offset(child), START_END, CHAIN_HANDLE, get_node_record_offset(child));
+            return get_net_handle_from_values(get_record_offset(child), child_connectivity, 
+                                              CHAIN_HANDLE, get_node_record_offset(child));
         } else if (get_handle_type(child) == CHAIN_HANDLE) {
             //If this is a chain, then return the same thing as a snarl
             return get_net_handle_from_values(get_record_offset(child), START_END, SNARL_HANDLE, 1);
@@ -285,22 +304,30 @@ net_handle_t SnarlDistanceIndex::get_parent(const net_handle_t& child) const {
 
     //Otherwise, we need to move up one level in the snarl tree
 
-    //Get the pointer to the parent, and keep the connectivity of the current handle
+    //Get the pointer to the parent to find its type
     size_t parent_pointer = SnarlTreeRecord(child, &snarl_tree_records).get_parent_record_offset();
-    connectivity_t child_connectivity = get_connectivity(child);
-
-    //TODO: I"m going into the parent record here, which could be avoided if things knew what their parents were, but I think if you're doing this you'd later go into the parent anyway so it's probably fine
     net_handle_record_t parent_type = SnarlTreeRecord(parent_pointer, &snarl_tree_records).get_record_handle_type();
+
+    
+    //The connectivity of the parent defaults to start-end
     connectivity_t parent_connectivity = START_END;
-    if ((child_connectivity == START_END || child_connectivity == END_START) 
-        && (parent_type == CHAIN_HANDLE)) {
-        //TODO: This also needs to take into account the orientation of the child, which I might be able to get around?
-        parent_connectivity = child_connectivity;
+    //If the parent is going to be a chain, then it has the connectivity of the child, flipped if the child is 
+    //reversed in the parent
+    if ((get_handle_type(child) == NODE_HANDLE || get_handle_type(child) == SNARL_HANDLE) 
+            && (child_connectivity == START_END || child_connectivity == END_START)) {
+        if (is_reversed_in_parent(child)) {
+            parent_connectivity = child_connectivity == START_END ? END_START : START_END;
+
+        } else {
+            parent_connectivity = child_connectivity;
+        }
+    } else if (parent_type == ROOT_HANDLE) {
+        parent_connectivity = TIP_TIP;
     }
     if (get_handle_type(child) == NODE_HANDLE && parent_type != CHAIN_HANDLE) {
         //If this is a node and it's parent is not a chain, we want to pretend that its 
         //parent is a chain
-        return get_net_handle_from_values(get_record_offset(child), parent_connectivity, CHAIN_HANDLE, get_node_record_offset(child));
+        return get_net_handle_from_values(get_record_offset(child), child_connectivity, CHAIN_HANDLE, get_node_record_offset(child));
     } 
 
     return get_net_handle(parent_pointer, parent_connectivity);
@@ -342,7 +369,6 @@ net_handle_t SnarlDistanceIndex::get_bound(const net_handle_t& snarl, bool get_e
         if (is_looping_chain && get_end) {
             //If this is a looping chain and we're getting the end, then the traversal of the node will be the 
             //end endpoint repeated, instead of the actual traversal
-            //TODO: This might cause problems when checking traversals but I think it's fine
             connectivity = endpoints_to_connectivity(get_end_endpoint(connectivity), get_end_endpoint(connectivity));
         }
         return get_net_handle_from_values(offset, connectivity,  NODE_HANDLE, node_offset);
@@ -368,14 +394,8 @@ net_handle_t SnarlDistanceIndex::get_node_from_sentinel(const net_handle_t& sent
     //The snarl must be in a chain, so the boundary nodes will be the next things on the chain 
     ChainRecord chain_record(parent_chain, &snarl_tree_records);
 
-    bool go_left = starts_at(sentinel) == START;
-    if (SnarlRecord(snarl, &snarl_tree_records).get_is_reversed_in_parent()) {
-        //TODO: I think this is always false
-        assert(false);
-        go_left = !go_left;
-    }
+    net_handle_t next_handle = chain_record.get_next_child(snarl, starts_at(sentinel) == START);
 
-    net_handle_t next_handle = chain_record.get_next_child(snarl, go_left);
     //If the sentinel is facing into the snarl, then flip the node after getting it from the chain
     return ends_at(sentinel) != starts_at(sentinel) ? flip(next_handle) : next_handle ;
 
@@ -384,8 +404,16 @@ net_handle_t SnarlDistanceIndex::get_node_from_sentinel(const net_handle_t& sent
 
 net_handle_t SnarlDistanceIndex::flip(const net_handle_t& net) const {
     connectivity_t old_connectivity = get_connectivity(net);
-    connectivity_t new_connectivity =  endpoints_to_connectivity(get_end_endpoint(old_connectivity), 
+    connectivity_t new_connectivity;
+    if (is_sentinel(net)) {
+        //If this is the sentinel of a snarl, then the first endpoint indicates the node
+        // and the second indicates the orientation, so only flip the second
+        new_connectivity = endpoints_to_connectivity(get_start_endpoint(old_connectivity),
+                get_end_endpoint(old_connectivity) == START ? END : START);
+    } else {
+        new_connectivity = endpoints_to_connectivity(get_end_endpoint(old_connectivity), 
                                                                 get_start_endpoint(old_connectivity));
+    }
     return get_net_handle_from_values(get_record_offset(net), new_connectivity, get_handle_type(net), get_node_record_offset(net));
 }
 
@@ -411,11 +439,15 @@ net_handle_t SnarlDistanceIndex::canonical(const net_handle_t& net) const {
     } else if (record.is_tip_tip_connected()) {
         connectivity = TIP_TIP;
     } else {
-        connectivity = START_END; //TODO: put this back throw runtime_error("error: This node has no connectivity");
+        connectivity = START_END; 
     }
     return get_net_handle_from_values(get_record_offset(net), connectivity, get_handle_type(net), get_node_record_offset(net));
 }
 
+net_handle_t SnarlDistanceIndex::start_end_traversal_of(const net_handle_t& net) const {
+    return get_net_handle_from_values(get_record_offset(net), START_END, get_handle_type(net), get_node_record_offset(net));
+}
+
 SnarlDecomposition::endpoint_t SnarlDistanceIndex::starts_at(const net_handle_t& traversal) const {
     return get_start_endpoint(get_connectivity(traversal));
 
@@ -445,7 +477,6 @@ size_t SnarlDistanceIndex::connected_component_count() const {
     return RootRecord (get_root(), &snarl_tree_records).get_connected_component_count();
 }
 
-//TODO: I'm also allowing this for the root
 bool SnarlDistanceIndex::for_each_child_impl(const net_handle_t& traversal, const std::function<bool(const net_handle_t&)>& iteratee) const {
 #ifdef debug_snarl_traversal
     cerr << "Go through children of " << net_handle_as_string(traversal) << endl;
@@ -493,13 +524,13 @@ bool SnarlDistanceIndex::for_each_child_impl(const net_handle_t& traversal, cons
 
 bool SnarlDistanceIndex::for_each_traversal_impl(const net_handle_t& item, const std::function<bool(const net_handle_t&)>& iteratee) const {
     if (get_handle_type(item) == SENTINEL_HANDLE) {
-        //TODO: I'm not sure what to do here?
         if (!iteratee(get_net_handle_from_values(get_record_offset(item), START_END, get_handle_type(item), get_node_record_offset(item)))) {
             return false;
         }
         if (!iteratee(get_net_handle_from_values(get_record_offset(item), END_START, get_handle_type(item), get_node_record_offset(item)))) {
             return false;
         }
+        return true;
     }
     SnarlTreeRecord record(item, &snarl_tree_records);
     for ( size_t type = 1 ; type <= 9 ; type ++ ){
@@ -522,10 +553,14 @@ bool SnarlDistanceIndex::follow_net_edges_impl(const net_handle_t& here, const h
     SnarlTreeRecord this_record(here, &snarl_tree_records);
     SnarlTreeRecord parent_record (get_parent(here), &snarl_tree_records);
 
-    if (parent_record.get_record_handle_type() == ROOT_HANDLE) {
-        //TODO: Double check that this is the right way to handle this
+    if (parent_record.get_record_handle_type() == ROOT_HANDLE &&
+        parent_record.get_record_type() != ROOT_SNARL &&
+        parent_record.get_record_type() != DISTANCED_ROOT_SNARL) {
+#ifdef debug_snarl_traversal
+        cerr << "The parent is a root so just check self connectivity" << endl;
+#endif
         //If this is a root-level chain or node
-        if ((ends_at(here) == END && !go_left) || (ends_at(here) == START && go_left)) {
+        if ((go_left && starts_at(here) == END) || (!go_left && ends_at(here) == END)) {
             //Follow edges leaving the root structure at the end
             if (this_record.is_externally_start_end_connected()) {
                 //Follow edge from end to start
@@ -559,6 +594,7 @@ bool SnarlDistanceIndex::follow_net_edges_impl(const net_handle_t& here, const h
 
     } else if (get_handle_type(here) == CHAIN_HANDLE || get_handle_type(here) == SENTINEL_HANDLE) {
 #ifdef debug_distances
+        cerr << "Parent is a snarl (or root snarl)" << endl;
         assert(parent_record.get_record_handle_type() == SNARL_HANDLE ||
                parent_record.get_record_handle_type() == ROOT_HANDLE);
         //It could also be the root
@@ -566,7 +602,8 @@ bool SnarlDistanceIndex::follow_net_edges_impl(const net_handle_t& here, const h
         //If this is a chain (or a node pretending to be a chain) and it is the child of a snarl
         //Or if it is the sentinel of a snarl, then we walk through edges in the snarl
         //It can either run into another chain (or node) or the boundary node
-        //TODO: What about if it is the root?
+        bool is_root_snarl = parent_record.get_record_type() == ROOT_SNARL
+                           || parent_record.get_record_type() == DISTANCED_ROOT_SNARL;
 
 
         //Get the graph handle for the end node of whatever this is, pointing in the right direction
@@ -574,29 +611,23 @@ bool SnarlDistanceIndex::follow_net_edges_impl(const net_handle_t& here, const h
         if (get_handle_type(here) == SENTINEL_HANDLE) {
             if ((get_connectivity(here) == START_END && !go_left) ||
                 (get_connectivity(here) == START_START && go_left)) {
+                //If it's going into the snarl from the start node
                 graph_handle = graph->get_handle(parent_record.get_start_id(), parent_record.get_start_orientation());
             } else if ((get_connectivity(here) == END_START && !go_left) ||
                        (get_connectivity(here) == END_END && go_left)) {
+                //If it's going into the snarl from the end node
                 graph_handle = graph->get_handle(parent_record.get_end_id(), !parent_record.get_end_orientation());
             } else {
                 //This is facing out, so don't do anything 
                 return true;
             }
         } else if (get_handle_type(here) == NODE_HANDLE ||is_trivial_chain(here)) {
-            nid_t id = is_trivial_chain(here) ? NodeRecord(here, &snarl_tree_records).get_node_id()
-                                                  : node_id(here);
-            graph_handle = graph->get_handle(id, ends_at(here) == END ? go_left : !go_left);
+            nid_t id = node_id(here);
+            graph_handle = graph->get_handle(id, go_left ? starts_at(here) == START : ends_at(here) == START);
         } else {
-            //TODO: This might not be the best way to handle orientation because it's a bit inconsistent with tips
-            //Might be better to just use go_left and pretend the traversal is forward, but that might be 
-            //unintuitive if you have a sentinel of a snarl that you think should be going in or out of the snarl
-            //
-            //If the traversal explicitly goes out the start, then we assume that it is oriented backwards
-            //and go the opposite direction of go_left. Otherwise, assume that it is oriented forwards
-            if (ends_at(here) == START) {
-                go_left = !go_left;
-            } 
-            graph_handle = get_handle(get_bound(here, !go_left, false), graph);
+            //Get the bound of the snarl or chain. If the traversal ends (or, if go_left is true, starts) at the
+            //start, then go left from here, otherwise go right (forwards)
+            graph_handle = get_handle(get_bound(here, go_left ? starts_at(here) != START : ends_at(here) != START, false), graph);
         }
 #ifdef debug_snarl_traversal
         cerr << "        traversing graph from actual node " << graph->get_id(graph_handle) << (graph->get_is_reverse(graph_handle) ? "rev" : "fd") << endl;
@@ -606,14 +637,14 @@ bool SnarlDistanceIndex::follow_net_edges_impl(const net_handle_t& here, const h
             cerr << "  reached actual node " << graph->get_id(h) << (graph->get_is_reverse(h) ? "rev" : "fd") << endl;
 #endif
 
-            if (graph->get_id(h) == parent_record.get_start_id()) {
+            if (!is_root_snarl && graph->get_id(h) == parent_record.get_start_id()) {
                 //If this is the start boundary node of the parent snarl, then do this on the sentinel
 #ifdef debug_snarl_traversal
                 cerr << "    -> start of parent " << endl;
                 assert(graph->get_is_reverse(h) == !parent_record.get_start_orientation());
 #endif
                 return iteratee(get_bound(get_parent(here), false, false));
-            } else if (graph->get_id(h) == parent_record.get_end_id()) {
+            } else if (!is_root_snarl && graph->get_id(h) == parent_record.get_end_id()) {
 #ifdef debug_snarl_traversal
                 assert(graph->get_is_reverse(h) == parent_record.get_end_orientation());
                 cerr << "    -> end of parent " << endl;
@@ -622,6 +653,9 @@ bool SnarlDistanceIndex::follow_net_edges_impl(const net_handle_t& here, const h
             } else {
                 //It is either another chain or a node, but the node needs to pretend to be a chain
                 net_handle_t node_net_handle = get_node_net_handle(graph->get_id(h));
+                if (graph->get_is_reverse(h)) {
+                    node_net_handle = flip(node_net_handle);
+                }
 
                 if (get_record_type(snarl_tree_records->at(get_record_offset(node_net_handle))) == NODE || 
                     get_record_type(snarl_tree_records->at(get_record_offset(node_net_handle))) == DISTANCED_NODE   ) {
@@ -631,12 +665,21 @@ bool SnarlDistanceIndex::follow_net_edges_impl(const net_handle_t& here, const h
                                                            CHAIN_HANDLE);
 #ifdef debug_snarl_traversal
                 cerr << "    -> actual child node " << net_handle_as_string(next_net) << endl;
+#endif
+                   return iteratee(next_net);
+                } else if (get_record_type(snarl_tree_records->at(get_record_offset(node_net_handle))) == DISTANCED_SIMPLE_SNARL ) {
+                    //If the node is a node in a simple snarl
+                    net_handle_t next_net = get_net_handle_from_values(get_record_offset(node_net_handle), 
+                                                           graph->get_is_reverse(h) ? END_START : START_END, 
+                                                           CHAIN_HANDLE,
+                                                           get_node_record_offset(node_net_handle));
+#ifdef debug_snarl_traversal
+                cerr << "    -> actual child node " << net_handle_as_string(next_net) << endl;
 #endif
                    return iteratee(next_net);
                 } else {
                     //next_node_record is also the start of a chain
-                    bool rev = get_record_offset(node_net_handle) != 
-                               ChainRecord(get_parent(node_net_handle), &snarl_tree_records).get_first_node_offset();
+                    bool rev = node_net_handle != get_bound(get_parent(node_net_handle), false, true);
                     net_handle_t next_net = get_net_handle_from_values(get_record_offset(get_parent(node_net_handle)), 
                                                            rev ? END_START : START_END, 
                                                            CHAIN_HANDLE);
@@ -665,15 +708,13 @@ bool SnarlDistanceIndex::follow_net_edges_impl(const net_handle_t& here, const h
         }
         //If this is a snarl or node, then it is the component of a (possibly pretend) chain
         ChainRecord parent_chain(this_record.get_parent_record_offset(), &snarl_tree_records);
-        if (ends_at(here) == START) {
-            go_left = !go_left;
-        }
+        bool go_left_in_chain = go_left ? starts_at(here) == START : ends_at(here) == START;
         bool is_rev = is_node(here) ? TrivialSnarlRecord(get_record_offset(here), &snarl_tree_records).get_is_reversed_in_parent(get_node_record_offset(here))
                                     : false;
         if (is_rev) {
-            go_left = !go_left;
+            go_left_in_chain = !go_left_in_chain;
         }
-        net_handle_t next_net = parent_chain.get_next_child(here, go_left);
+        net_handle_t next_net = parent_chain.get_next_child(here, go_left_in_chain);
         if (next_net == here ) {
             //If this is the end of the chain
             return true;
@@ -692,7 +733,6 @@ net_handle_t SnarlDistanceIndex::get_parent_traversal(const net_handle_t& traver
 
     if (start_handle_type == SENTINEL_HANDLE) {
         //these are the sentinels of a snarl
-        //TODO: Make sure this is handling possible orientations properly
         assert(end_handle_type == SENTINEL_HANDLE);
         endpoint_t start_endpoint = get_start_endpoint(get_connectivity(traversal_start));
         endpoint_t end_endpoint = get_start_endpoint(get_connectivity(traversal_end));
@@ -820,13 +860,18 @@ size_t SnarlDistanceIndex::distance_in_parent(const net_handle_t& parent,
         const net_handle_t& child1, const net_handle_t& child2, const HandleGraph* graph, size_t distance_limit) const {
 
 #ifdef debug_distances
-    assert(canonical(parent) == canonical(get_parent(child1)));
-    assert(canonical(parent) == canonical(get_parent(child2)));
     cerr << "\t\tFind distance between " << net_handle_as_string(child1) 
          << " and " << net_handle_as_string(child2) 
          << "\tin parent " << net_handle_as_string(parent) << endl;
+    assert(canonical(parent) == canonical(get_parent(child1)));
+    assert(canonical(parent) == canonical(get_parent(child2)));
 #endif
 
+    //Get the orientation of the children. This only cares about the end endpoint, and assumes that things that end
+    //in tips are start-end, meaning that they don't end at the start
+    bool child_ends_at_start1 = ends_at(child1) == START;
+    bool child_ends_at_start2 = ends_at(child2) == START;
+
     if (is_root(parent)) {
         //If the parent is the root, then the children must be in the same root snarl for them to be
         //connected
@@ -846,12 +891,12 @@ size_t SnarlDistanceIndex::distance_in_parent(const net_handle_t& parent,
 #endif
             if (get_record_offset(child1) == get_record_offset(child2)) {
                 //If they are the same child of the root but not in a snarl, then check the external connectivity
-                if (ends_at(child1) == START && ends_at(child2) == START) {
+                if (child_ends_at_start1 && child_ends_at_start2) {
                     return has_external_connectivity(child1, START, START) ? 0 : std::numeric_limits<size_t>::max();
-                } else if (ends_at(child1) == END && ends_at(child2) == END) {
+                } else if (!child_ends_at_start1 && !child_ends_at_start2) {
                     return has_external_connectivity(child1, END, END) ? 0 : std::numeric_limits<size_t>::max();
-                } else if ((ends_at(child1) == START && ends_at(child2) == END) ||
-                            (ends_at(child1) == END && ends_at(child2) == START)) {
+                } else if ((child_ends_at_start1 && !child_ends_at_start2) ||
+                            (!child_ends_at_start1 && child_ends_at_start2)) {
                     if (has_external_connectivity(child1, START, END)) {
                         //If we can take an edge around the snarl
                         return 0;
@@ -869,8 +914,8 @@ size_t SnarlDistanceIndex::distance_in_parent(const net_handle_t& parent,
             //They are in the same root snarl, so find the distance between them
             SnarlRecord snarl_record(parent_record_offset1, &snarl_tree_records);
 
-            return snarl_record.get_distance(get_rank_in_parent(child1), ends_at(child1) == END, 
-                                             get_rank_in_parent(child2), ends_at(child2) == END);
+            return snarl_record.get_distance(get_rank_in_parent(child1), !child_ends_at_start1, 
+                                             get_rank_in_parent(child2), !child_ends_at_start2);
         }
 
 
@@ -885,7 +930,6 @@ size_t SnarlDistanceIndex::distance_in_parent(const net_handle_t& parent,
         assert(is_node(child2) || is_snarl(child2));
 #endif
 
-        //TODO: This is awful
         //These are the values needed for calculating the distance in the chain
         //They are:
         //rank in chain, go_left, node_length, prefix_sum, forward_loop, reverse_loop, component
@@ -912,11 +956,12 @@ size_t SnarlDistanceIndex::distance_in_parent(const net_handle_t& parent,
             size_t& reverse_loop = i == 0 ? reverse_loop1 : reverse_loop2;
             size_t& component    = i == 0 ? component1    : component2;
             size_t& end_component    = i == 0 ? end_component1    : end_component2;
+            bool& child_ends_at_start = i == 0 ? child_ends_at_start1 : child_ends_at_start2;
 
             if (is_node(child)) {
 
                 bool go_left = is_reversed_in_parent(child);
-                if (ends_at(child) == START){
+                if (child_ends_at_start){
                     go_left = !go_left;
                 }
                 rank_in_chain=get_rank_in_parent(child);
@@ -930,7 +975,7 @@ size_t SnarlDistanceIndex::distance_in_parent(const net_handle_t& parent,
             } else {
                 //If this is a snarl, then find the appropriate boundary node and fill it in
                 assert(is_snarl(child));
-                if (ends_at(child) == START) {
+                if (child_ends_at_start) {
                     //If we're going backwards in the chain, then we want the start node
                     //And turn it into a node, since it will be a sentinel
                     net_handle_t start_bound = get_node_from_sentinel(get_bound(child, false, false));
@@ -962,6 +1007,7 @@ size_t SnarlDistanceIndex::distance_in_parent(const net_handle_t& parent,
                 }
             }
         }
+
         if (is_node(child1) != is_node(child2) && rank_in_chain1 == rank_in_chain2 &&
                go_left1 != go_left2) {
             //If one child is a node and the other is a snarl, and the node is the boundary of the snarl
@@ -984,20 +1030,21 @@ size_t SnarlDistanceIndex::distance_in_parent(const net_handle_t& parent,
                     node_lengths_to_add});
 
     } else if (is_snarl(parent)) {
+        bool snarl_is_root = is_root_snarl(parent);
         size_t rank1, rank2; bool rev1, rev2;
         if (is_sentinel(child1)) {
             rank1 = starts_at(child1) == START ? 0 : 1;
             rev1 = false;
         } else {
             rank1 = get_rank_in_parent(child1);
-            rev1 = ends_at(child1) == END;
+            rev1 = !child_ends_at_start1;
         }
         if (is_sentinel(child2)) {
             rank2 = starts_at(child2) == START ? 0 : 1;
             rev2 = false;
         } else {
             rank2 = get_rank_in_parent(child2);
-            rev2 = ends_at(child2) == END;
+            rev2 = !child_ends_at_start2;
         }
         if ((is_sentinel(child1) && starts_at(child1) == ends_at(child1)) ||
             (is_sentinel(child2) && starts_at(child2) == ends_at(child2)) ) {
@@ -1012,17 +1059,18 @@ size_t SnarlDistanceIndex::distance_in_parent(const net_handle_t& parent,
             cerr << "             between ranks " << rank1 << " " << rev1 << " " << rank2 << " " << rev2 << endl;
 #endif
 
-        if (get_record_type(snarl_tree_records->at(get_record_offset(parent))) == OVERSIZED_SNARL 
+        if (get_record_type(snarl_tree_records->at(get_record_offset(parent))) == DISTANCED_SIMPLE_SNARL) {
+            return SimpleSnarlRecord(parent, &snarl_tree_records).get_distance(rank1, rev1, rank2, rev2);
+        } else if (get_record_type(snarl_tree_records->at(get_record_offset(parent))) == OVERSIZED_SNARL 
             && !(rank1 == 0 || rank1 == 1 || rank2 == 0 || rank2 == 1) ) {
             //If this is an oversized snarl and we're looking for internal distances, then we didn't store the
             //distance and we have to find it using dijkstra's algorithm
             if (graph == nullptr) {
-                assert(false);
                 cerr << "warning: trying to find the distance in an oversized snarl without a graph. Returning inf" << endl;
                 return std::numeric_limits<size_t>::max();
             }
-            handle_t handle1 = is_node(child1) ? get_handle(child1, graph) : get_handle(get_bound(child1, ends_at(child1) == END, false), graph); 
-            handle_t handle2 = is_node(child2) ? get_handle(child2, graph) : get_handle(get_bound(child2, ends_at(child2) == END, false), graph);
+            handle_t handle1 = is_node(child1) ? get_handle(child1, graph) : get_handle(get_bound(child1, !child_ends_at_start1, false), graph); 
+            handle_t handle2 = is_node(child2) ? get_handle(child2, graph) : get_handle(get_bound(child2, !child_ends_at_start2, false), graph);
             handle2 = graph->flip(handle2);
 
             size_t distance = std::numeric_limits<size_t>::max();
@@ -1039,8 +1087,51 @@ size_t SnarlDistanceIndex::distance_in_parent(const net_handle_t& parent,
             return distance;
 
             
-        } else if (get_record_type(snarl_tree_records->at(get_record_offset(parent))) == DISTANCED_SIMPLE_SNARL) {
-            return SimpleSnarlRecord(parent, &snarl_tree_records).get_distance(rank1, rev1, rank2, rev2);
+        } else if (rank1 == 0 && rank2 == 0 && !snarl_is_root) {
+            //Start to start is stored in the snarl
+            return SnarlRecord(parent, &snarl_tree_records).get_distance_start_start();
+        } else if ((rank1 == 0 && rank2 == 1) || (rank1 == 1 && rank2 == 0) && !snarl_is_root) {
+            //start to end / end to start is stored in the snarl
+            return SnarlRecord(parent, &snarl_tree_records).get_min_length();
+        } else if (rank1 == 1 && rank2 == 1 && !snarl_is_root) {
+            //end to end is stored in the snarl
+            return SnarlRecord(parent, &snarl_tree_records).get_distance_end_end();
+        } else if (rank1 == 0 || rank1 == 1 || rank2 == 0 || rank2 == 1 && !snarl_is_root) {
+            //If one node is a boundary and the other is a child
+            size_t boundary_rank = (rank1 == 0 || rank1 == 1) ? rank1 : rank2;
+            const net_handle_t& internal_child = (rank1 == 0 || rank1 == 1) ? child2 : child1;
+            bool internal_is_reversed = (rank1 == 0 || rank1 == 1) ? rev2 : rev1;
+            if (is_trivial_chain( internal_child) ) {
+                //Child is just a node pretending to be a chain
+                if (boundary_rank == 0 && !internal_is_reversed) {
+                    //Start to left of child
+                    return NodeRecord(internal_child, &snarl_tree_records).get_distance_left_start();
+                } else if (boundary_rank == 0 && internal_is_reversed) {
+                    //Start to right of child
+                    return NodeRecord(internal_child, &snarl_tree_records).get_distance_right_start();
+                } else if (boundary_rank == 1 && !internal_is_reversed) {
+                    //End to left of child
+                    return NodeRecord(internal_child, &snarl_tree_records).get_distance_left_end();
+                } else {
+                    //End to right of child
+                    return NodeRecord(internal_child, &snarl_tree_records).get_distance_right_end();
+                }
+            } else {
+                //Child is an actual chain
+                if (boundary_rank == 0 && !internal_is_reversed) {
+                    //Start to left of child
+                    return ChainRecord(internal_child, &snarl_tree_records).get_distance_left_start();
+                } else if (boundary_rank == 0 && internal_is_reversed) {
+                    //Start to right of child
+                    return ChainRecord(internal_child, &snarl_tree_records).get_distance_right_start();
+                } else if (boundary_rank == 1 && !internal_is_reversed) {
+                    //End to left of child
+                    return ChainRecord(internal_child, &snarl_tree_records).get_distance_left_end();
+                } else {
+                    //End to right of child
+                    return ChainRecord(internal_child, &snarl_tree_records).get_distance_right_end();
+                }
+            }
         } else {
            return SnarlRecord(parent, &snarl_tree_records).get_distance(rank1, rev1, rank2, rev2);
         }
@@ -1048,48 +1139,292 @@ size_t SnarlDistanceIndex::distance_in_parent(const net_handle_t& parent,
         throw runtime_error("error: Trying to find distance in the wrong type of handle");
     }
 }
+size_t SnarlDistanceIndex::max_distance_in_parent(const net_handle_t& parent, 
+        const net_handle_t& child1, const net_handle_t& child2, const HandleGraph* graph, size_t distance_limit) const {
+
+#ifdef debug_distances
+    cerr << "\t\tFind maximum distance between " << net_handle_as_string(child1) 
+         << " and " << net_handle_as_string(child2) 
+         << "\tin parent " << net_handle_as_string(parent) << endl;
+    assert(canonical(parent) == canonical(get_parent(child1)));
+    assert(canonical(parent) == canonical(get_parent(child2)));
+#endif
+
+    if (is_chain(parent)) {
+
+        //Get the orientation of the children. This only cares about the end endpoint, and assumes that things that end
+        //in tips are start-end, meaning that they don't end at the start
+        bool child_ends_at_start1 = ends_at(child1) == START;
+        bool child_ends_at_start2 = ends_at(child2) == START;
+
+        if (get_record_handle_type(get_record_type(snarl_tree_records->at(get_record_offset(parent)))) == NODE_HANDLE ||
+            get_record_handle_type(get_record_type(snarl_tree_records->at(get_record_offset(parent)))) == SNARL_HANDLE) {
+            return std::numeric_limits<size_t>::max();
+        }
+        ChainRecord chain_record(parent, &snarl_tree_records);
+#ifdef debug_distances
+        assert(is_node(child1) || is_snarl(child1));
+        assert(is_node(child2) || is_snarl(child2));
+#endif
+
+        //These are the values needed for calculating the distance in the chain
+        //They are:
+        //rank in chain, go_left, node_length, prefix_sum, forward_loop, reverse_loop, component
+        size_t rank_in_chain1; size_t rank_in_chain2;
+        bool go_left1; bool go_left2;
+        size_t node_length1; size_t node_length2;
+        size_t prefix_sum1; size_t prefix_sum2;
+        size_t forward_loop1 ; size_t forward_loop2;
+        size_t reverse_loop1 ; size_t reverse_loop2;
+        size_t component1; size_t component2;
+        size_t end_component1; size_t end_component2;
+
+        //The node lengths of snarl boundaries, to be added to the total distance
+        size_t node_lengths_to_add = 0;
+
+        //Get all the relevant chain values
+        for (size_t i = 0 ; i <=1 ; i ++ ) {
+            const net_handle_t& child = i == 0 ? child1 : child2;
+            size_t& rank_in_chain= i == 0 ? rank_in_chain1: rank_in_chain2;
+            bool& go_left_in_chain = i == 0 ? go_left1  : go_left2;
+            size_t& node_length  = i == 0 ? node_length1  : node_length2;
+            size_t& prefix_sum   = i == 0 ? prefix_sum1   : prefix_sum2;
+            size_t& forward_loop = i == 0 ? forward_loop1 : forward_loop2;
+            size_t& reverse_loop = i == 0 ? reverse_loop1 : reverse_loop2;
+            size_t& component    = i == 0 ? component1    : component2;
+            size_t& end_component    = i == 0 ? end_component1    : end_component2;
+            bool& child_ends_at_start = i == 0 ? child_ends_at_start1 : child_ends_at_start2;
+
+            if (is_node(child)) {
+
+                bool go_left = is_reversed_in_parent(child);
+                if (child_ends_at_start){
+                    go_left = !go_left;
+                }
+                rank_in_chain=get_rank_in_parent(child);
+                go_left_in_chain = go_left;
+                node_length = minimum_length(child);
+                std::tie(prefix_sum, forward_loop, reverse_loop, component) = 
+                    TrivialSnarlRecord(get_record_offset(child), &snarl_tree_records).get_chain_values(get_node_record_offset(child));
+                prefix_sum = TrivialSnarlRecord(get_record_offset(child), &snarl_tree_records).get_max_prefix_sum(get_node_record_offset(child));
+                end_component = TrivialSnarlRecord(get_record_offset(child), &snarl_tree_records).get_chain_component(get_node_record_offset(child), true);
+
+                
+            } else {
+                //If this is a snarl, then find the appropriate boundary node and fill it in
+                assert(is_snarl(child));
+                if (child_ends_at_start) {
+                    //If we're going backwards in the chain, then we want the start node
+                    //And turn it into a node, since it will be a sentinel
+                    net_handle_t start_bound = get_node_from_sentinel(get_bound(child, false, false));
+
+                    size_t start_length = minimum_length(start_bound);
+
+                        //set values for first
+                    rank_in_chain=get_record_offset(start_bound) + get_node_record_offset(start_bound);
+                    go_left_in_chain = true;
+                    node_length = start_length;
+                    std::tie(prefix_sum, forward_loop, reverse_loop, component) = 
+                        TrivialSnarlRecord (get_record_offset(start_bound), &snarl_tree_records).get_chain_values(get_node_record_offset(start_bound));
+
+                    prefix_sum = TrivialSnarlRecord (get_record_offset(start_bound), &snarl_tree_records).get_max_prefix_sum(get_node_record_offset(start_bound));
+                    node_lengths_to_add += start_length;
+                } else {
+                    //Do the same thing for the snarl end node if we're going forwards
+                    net_handle_t end_bound = get_node_from_sentinel(get_bound(child, true, false));
+                    size_t end_length = minimum_length(end_bound);
+                    size_t end_rank = get_record_offset(end_bound) + get_node_record_offset(end_bound);
+
+                    //set values for first
+                    rank_in_chain=end_rank;
+                    go_left_in_chain = false;
+                    node_length = end_length;
+                    std::tie(prefix_sum, forward_loop, reverse_loop, component) =
+                            TrivialSnarlRecord (get_record_offset(end_bound), &snarl_tree_records).get_chain_values(get_node_record_offset(end_bound));
+
+                    prefix_sum = TrivialSnarlRecord (get_record_offset(end_bound), &snarl_tree_records).get_max_prefix_sum(get_node_record_offset(end_bound));
+
+                    node_lengths_to_add += end_length;
+                }
+            }
+        }
+
+        if (is_node(child1) != is_node(child2) && rank_in_chain1 == rank_in_chain2 &&
+               go_left1 != go_left2) {
+            //If one child is a node and the other is a snarl, and the node is the boundary of the snarl
+            //pointing into the snarl, then the distance is 0
+            return 0;
+        } else if (!is_node(child1) && !is_node(child2) && rank_in_chain1 == rank_in_chain2 &&
+                go_left1 != go_left2) {
+                //If the snarls are adjacent (and not the same snarl)
+            return node_length2;//return the node length
+        }
+
+        return sum({chain_record.get_distance(rank_in_chain1, go_left1,
+                                              node_length1, prefix_sum1,
+                                              forward_loop1, reverse_loop1,
+                                              component1, component1, 
+                                              rank_in_chain2, go_left2,
+                                              node_length2, prefix_sum2,
+                                              forward_loop2, reverse_loop2,
+                                              component2, component2),
+                    node_lengths_to_add});
+
+    } else {
+        //If the parent isn't a chain, then just return the minimum
+        return distance_in_parent(parent, child1, child2, graph, distance_limit);
+    }
+}
 
-size_t SnarlDistanceIndex::distance_to_parent_bound(net_handle_t& parent, bool to_start, net_handle_t& child, bool go_left) const {
-    if (is_trivial_chain(parent)) {
-        //If this is a node pretending to be a chain in a snarl
-        if ((ends_at(child) == START && to_start != go_left) ||
-            (ends_at(child) == END && to_start == go_left)) {
-            //If the child is traversed backwards and we're going start to right or end to left
-            //Or the child is traversed forwards and we're going start to left or end to right
+size_t SnarlDistanceIndex::distance_to_parent_bound(const net_handle_t& parent, bool to_start, net_handle_t child,
+    tuple<net_handle_record_t, net_handle_record_t, net_handle_record_t, net_handle_record_t> parent_and_child_types) const {
+    /* parent_and_child_types is a tuple of parent handle type, parent record type, child handle type, child record type
+      * This is really just used to see if the parent and child are trivial chains, so it might not be exactly what 
+      * the actual record is
+      * */
+
+
+
+    //Get the record and handle types of the parent and child
+    bool has_handle_types = (parent_and_child_types != make_tuple(ROOT_HANDLE, ROOT_HANDLE, ROOT_HANDLE, ROOT_HANDLE));
+    bool parent_is_chain = has_handle_types ? std::get<0>(parent_and_child_types) == CHAIN_HANDLE 
+                                            : is_chain(parent);
+    bool parent_is_trivial_chain = has_handle_types ? (std::get<0>(parent_and_child_types) == NODE_HANDLE && std::get<1>(parent_and_child_types) == CHAIN_HANDLE)
+                                                    : is_trivial_chain(parent);
+    bool child_is_trivial_chain = has_handle_types ? (std::get<2>(parent_and_child_types) == NODE_HANDLE && std::get<3>(parent_and_child_types) == CHAIN_HANDLE)
+                                                    : is_trivial_chain(child);
+    bool parent_is_snarl = has_handle_types ? std::get<0>(parent_and_child_types) == SNARL_HANDLE
+                                            : is_snarl(parent);
+
+    //Get the orientation of the child. This only cares about the end endpoint, and assumes that things that end
+    //in tips are start-end, meaning that they don't end at the start
+    bool child_ends_at_start = ends_at(child) == START;
+    if (parent_is_trivial_chain) {
+        //If this is a node pretending to be a chain and the parent is the trivial chain, 
+        //then the child is always oriented forwards in the parent (because it is the parent) and the distance is 0 or inf
+        if ((child_ends_at_start && to_start) ||
+            (!child_ends_at_start && !to_start)) {
+            //If the child is traversed backwards and we're going to the start
+            //Or the child is traversed forwards and we're going to the end
             return 0;
         } else {
             return std::numeric_limits<size_t>::max();
+        } 
+    } else if (parent_is_snarl) {
+        if (is_simple_snarl(parent)) {
+            if (to_start) {
+                if (child_ends_at_start != is_reversed_in_parent(child)) {
+                    //If the child is going backwards, and it isn't reversed in the parent,
+                    //or if the child is going forwards and it is reversed in the parent,
+                    //then the distances to the start will be 0
+                    return 0;
+                } else {
+                    return std::numeric_limits<size_t>::max();
+                }
+            } else {
+                //to end of snarl
+                if (child_ends_at_start == is_reversed_in_parent(child)) {
+                    //If the child is going backwards and it is reversed in the parent
+                    //or the child is going forwards and it isn't reversed in the parent
+                    return 0;
+                } else {
+                    return std::numeric_limits<size_t>::max();
+                }
+            }
+        } else {
+            //Otherwise, the parent is a normal snarl and the child nodes/chains know the distance
+            //to the ends of the snarl
+    
+            if (child_is_trivial_chain) {
+                NodeRecord child_record (child, &snarl_tree_records);
+                if (child_ends_at_start && to_start) {
+                    return child_record.get_distance_left_start();
+                } else if (!child_ends_at_start && to_start) {
+                    return child_record.get_distance_right_start();
+                } else if (child_ends_at_start && !to_start) { 
+                    return child_record.get_distance_left_end();
+                } else {
+                    return child_record.get_distance_right_end();
+                }
+            } else {
+                ChainRecord child_record (child, &snarl_tree_records);
+                if (child_ends_at_start && to_start) {
+                    return child_record.get_distance_left_start();
+                } else if (!child_ends_at_start && to_start) {
+                    return child_record.get_distance_right_start();
+                } else if (child_ends_at_start && !to_start) { 
+                    return child_record.get_distance_left_end();
+                } else {
+                    return child_record.get_distance_right_end();
+                }
+            }
         }
-    }
-    net_handle_t parent_bound = get_bound(parent, !to_start, true);
 
-    //If we are looking at the left side of the child
-    bool left_of_child = ends_at(child) == START ? !go_left : go_left;
-    if ((left_of_child && to_start && parent_bound == child) || 
-        //If we want the start to the left of the child and the child is the same as the bound 
-        (left_of_child && !to_start && parent_bound == child) ||
-        //If we want the end to the left of the child and the child opposite of the bound
-        (!left_of_child && to_start && parent_bound == flip(child)) ||
-        //If we want the start to the right of the child and the child opposite of the bound
-        (!left_of_child && !to_start && parent_bound == flip(child))) {
-        //If we want the end to the right of the child and they are the same
-        return 0;
-    }
-    //The node length of the boundary node, only set for chains 
-    size_t bound_length = !is_chain(parent) ? 0 : minimum_length(parent_bound);
 
-    if (is_chain(parent) && !to_start){
-        if (is_looping_chain(parent)){
-            //If this is a looping chain and we want the end 
-            bound_length = 0;
+    } else {
+        //Otherwise, the parent is a chain so get the bound and use distance_in_parent
+
+
+        //The parent bound we want, facing in
+        net_handle_t parent_bound = get_bound(parent, !to_start, true);
+
+        if (parent_bound == flip(child)) {
+            //If the child is the bound we want and pointing into it (out of the chain)
+            return 0;
+        }
+        //The node length of the boundary node, only set for chains 
+        size_t bound_length = !parent_is_chain ? 0 : minimum_length(parent_bound);
+
+        if (parent_is_chain && !to_start){
+            if (is_looping_chain(parent)){
+                //If this is a looping chain and we want the end 
+                bound_length = 0;
+            }
         }
+        
+        return sum(bound_length, 
+                    distance_in_parent(parent, parent_bound, child));
     }
-    
-    return sum({bound_length, 
-                distance_in_parent(parent, parent_bound, go_left ? flip(child) : child)});
 
 }
 
+tuple<nid_t, bool, bool> SnarlDistanceIndex::into_which_snarl(const nid_t& id, const bool& reverse) const {
+    net_handle_t node = get_node_net_handle(id, reverse);
+    net_handle_t parent = get_parent(node);
+
+    if (is_trivial_chain(parent) || is_root(parent)) {
+        //If the parent is a trivial chain, then it is a node child of a snarl
+        return {0, false, false};
+    } else {
+        //Otherwise, the parent is an actual chain and this is the boundary node of a (possibly trivial) snarl
+
+        //If the node is traversed forwards in the parent and we are going backwards (or the opposite),
+        //then we are going backwards in the chain
+        bool go_left_in_chain = is_reversed_in_parent(node) != reverse;
+        ChainRecord chain_record (parent, &snarl_tree_records);
+        net_handle_t next_child = chain_record.get_next_child(node, go_left_in_chain);
+        if (is_snarl(next_child)) {
+            //If the node points into a snarl
+            net_handle_t start = get_node_from_sentinel(get_bound(next_child, false, true));
+            return {node_id(start), ends_at(start) == START, false}; 
+        } else if (next_child == node) {
+            //If the node points out of the chain
+            return {0, false, false};
+        } else {
+            //If the node points to another node (trivial snarl)
+            //Assume that the trivial snarl is oriented forwards in the chain, so the start node
+            //is whichever comes first in the chain
+            if (go_left_in_chain) {
+                //If we went left in the chain, then the start node of the snarl is the next node
+                return {node_id(next_child), is_reversed_in_parent(next_child), true};
+            } else {
+                //If we went right in the chain, then the original node is the start node
+                return {id, reverse, true};
+            }
+        }
+    }
+}
+
 
 
 
@@ -1117,10 +1452,24 @@ pair<net_handle_t, bool> SnarlDistanceIndex::lowest_common_ancestor(const net_ha
             is_connected = false;
         }
     }
-    return make_pair(parent2, is_connected);
+    return make_pair(canonical(parent2), is_connected);
 }
 
-size_t SnarlDistanceIndex::minimum_distance(const handlegraph::nid_t id1, const bool rev1, const size_t offset1, const handlegraph::nid_t id2, const bool rev2, const size_t offset2, bool unoriented_distance, const HandleGraph* graph) const {
+size_t SnarlDistanceIndex::minimum_distance(const handlegraph::nid_t id1, const bool rev1, const size_t offset1, 
+                                            const handlegraph::nid_t id2, const bool rev2, const size_t offset2, 
+                                            bool unoriented_distance, const HandleGraph* graph, 
+                                            pair<vector<tuple<net_handle_t, int32_t, int32_t>>, vector<tuple<net_handle_t, int32_t, int32_t>>>* distance_traceback) const {
+    RootRecord root_record (get_root(), &snarl_tree_records);
+    size_t max_node_id = root_record.get_min_node_id() + root_record.get_node_count();
+    if (id1 < root_record.get_min_node_id() || id2 < root_record.get_min_node_id() ||
+        id1 > max_node_id || id2 > max_node_id) {
+        throw runtime_error("error: Looking for the minimum distance of a node that does not exist");
+    }
+    if (distance_traceback != nullptr) {
+        //Clear the traceback
+        distance_traceback->first.clear();
+        distance_traceback->second.clear();
+    }
 
 
 #ifdef debug_distances
@@ -1134,11 +1483,7 @@ size_t SnarlDistanceIndex::minimum_distance(const handlegraph::nid_t id1, const
      * update the distances to reach the ends of the parent and update the handle and its parent
      * If the parent is a chain, then the new distances include the boundary nodes of the chain.
      * If it is a snarl, it does not*/
-    //TODO: This should really be an actual function and it doesn't consider the lengths of the 
-    //boundary nodes. I think chains might need to know the lengths of their boundary nodes,
-    //or it could find it from the snarl. Really, since the snarl is storing it anyway, I should
-    //probaby rearrange things so that either the snarl or the chain can access boundary node lengths
-    auto update_distances = [&](net_handle_t& net, net_handle_t& parent, size_t& dist_start, size_t& dist_end) {
+    auto update_distances = [&](net_handle_t& net, net_handle_t& parent, size_t& dist_start, size_t& dist_end, bool first_node) {
 #ifdef debug_distances
         cerr << "     Updating distance from node " << net_handle_as_string(net) << " at parent " << net_handle_as_string(parent) << endl;
 #endif
@@ -1153,6 +1498,28 @@ size_t SnarlDistanceIndex::minimum_distance(const handlegraph::nid_t id1, const
                 dist_start = dist_end;
                 dist_end = tmp;
             } 
+
+            if (distance_traceback != nullptr) {
+                //Add an entry for this node
+                tuple<net_handle_t, int32_t, int32_t>* current_traceback;
+                if (first_node) {
+                    distance_traceback->first.emplace_back(parent, std::numeric_limits<int32_t>::max(), std::numeric_limits<int32_t>::max());
+                    current_traceback = &distance_traceback->first.back();
+                } else {
+                    distance_traceback->second.emplace_back(parent, std::numeric_limits<int32_t>::max(), std::numeric_limits<int32_t>::max());
+                    current_traceback = &distance_traceback->second.back();
+                }
+
+
+                //If we're keeping track of the traceback, then remember the distance to the start/end of the parent
+                if (is_reversed_in_parent(net)) {
+                    std::get<1>(*current_traceback) = 0; 
+                    std::get<2>(*current_traceback) = std::numeric_limits<int32_t>::min();
+                } else {
+                    std::get<1>(*current_traceback) = std::numeric_limits<int32_t>::min();
+                    std::get<2>(*current_traceback) = 0;
+                }
+            }
             return;
         }
 
@@ -1178,6 +1545,40 @@ size_t SnarlDistanceIndex::minimum_distance(const handlegraph::nid_t id1, const
         size_t distance_start = dist_start;
         size_t distance_end = dist_end; 
 
+        if (distance_traceback != nullptr) {
+            //Add an entry for this node
+            tuple<net_handle_t, int32_t, int32_t>* current_traceback;
+            if (first_node) {
+                distance_traceback->first.emplace_back(parent, std::numeric_limits<int32_t>::max(), std::numeric_limits<int32_t>::max());
+                current_traceback = &distance_traceback->first.back();
+            } else {
+                distance_traceback->second.emplace_back(parent, std::numeric_limits<int32_t>::max(), std::numeric_limits<int32_t>::max());
+                current_traceback = &distance_traceback->second.back();
+            }
+
+
+            //If we're keeping track of the traceback, then remember the distance to the start/end of the parent
+
+            if (sum({distance_start_start, distance_start}) != std::numeric_limits<size_t>::max() &&
+                sum({distance_start_start, distance_start}) < sum({distance_start_end , distance_end}) ) {
+                //If the distance to the start of the parent comes form the start of the node
+                std::get<1>(*current_traceback) = distance_start_start == 0 ? std::numeric_limits<int32_t>::min() : -distance_start_start; 
+            } else if (sum({distance_start_end , distance_end}) != std::numeric_limits<size_t>::max()) {
+                //If the distance to the start of the parent comes from the end of the node
+                std::get<1>(*current_traceback) = distance_start_end; 
+                
+            }
+
+            if (sum({distance_end_start , distance_start}) != std::numeric_limits<size_t>::max() &&
+                sum({distance_end_start , distance_start}) < sum({distance_end_end , distance_end})) {
+                //If the distance to the end of the parent comes from the distance to the start of the node
+                std::get<2>(*current_traceback) = distance_end_start == 0 ? std::numeric_limits<int32_t>::min() : -distance_end_start;
+            } else if (sum({distance_end_end , distance_end})) {
+                //If the distance to the end of the parent comes from the distance to the end of the node
+                std::get<2>(*current_traceback) = distance_end_end;
+            }
+        }
+
 
         dist_start = std::min( sum({distance_start_start, distance_start}), 
                                     sum({distance_start_end , distance_end}));
@@ -1191,8 +1592,6 @@ size_t SnarlDistanceIndex::minimum_distance(const handlegraph::nid_t id1, const
 
     /*
      * Get net handles for the two nodes and the distances from each position to the ends of the handles
-     * TODO: net2 is pointing in the opposite direction of the position. The final 
-     * distance will be between the two nets pointing towards each other
      */
     net_handle_t net1 = get_node_net_handle(id1);
     net_handle_t net2 = get_node_net_handle(id2);
@@ -1206,7 +1605,7 @@ size_t SnarlDistanceIndex::minimum_distance(const handlegraph::nid_t id1, const
     }
 
     //The lowest common ancestor of the two positions
-    net_handle_t common_ancestor = std::move(lowest_ancestor.first);
+    net_handle_t common_ancestor = start_end_traversal_of(lowest_ancestor.first);
 
 #ifdef debug_distances
         cerr << "Found the lowest common ancestor " << net_handle_as_string(common_ancestor) << endl;
@@ -1237,33 +1636,63 @@ size_t SnarlDistanceIndex::minimum_distance(const handlegraph::nid_t id1, const
 
     size_t minimum_distance = std::numeric_limits<size_t>::max();
 
+    //Remember which common ancestor the minimum distance actually comes from
+    //tuple of <the ancestor, distance between the children, connectivity between the two children
+    tuple<net_handle_t, size_t, connectivity_t> common_ancestor_connectivity (get_root(), std::numeric_limits<size_t>::max(), START_END); 
+
 
     /*
      * Walk up the snarl tree until net1 and net2 are children of the lowest common ancestor
      * Keep track of the distances to the ends of the net handles as we go
      */
  
-    if (canonical(net1) == canonical(net2)){
+    if (start_end_traversal_of(net1) == start_end_traversal_of(net2)){
         if (sum({distance_to_end1 , distance_to_start2}) > node_length(net1) && 
             sum({distance_to_end1 , distance_to_start2}) != std::numeric_limits<size_t>::max()) {
             //If the positions are on the same node and are pointing towards each other, then
             //check the distance between them in the node
             minimum_distance = minus(sum({distance_to_end1 , distance_to_start2}), node_length(net1));
+            if (distance_traceback != nullptr) {
+                //If we're recording the traceback, remember the common node as the common ancestor
+                common_ancestor_connectivity = std::make_tuple(net1, minimum_distance-1, END_START); 
+            }
         }
         if (sum({distance_to_start1 , distance_to_end2}) > node_length(net1) && 
             sum({distance_to_start1 , distance_to_end2}) != std::numeric_limits<size_t>::max()) {
             minimum_distance = std::min(minus(sum({distance_to_start1 , distance_to_end2}), node_length(net1)), minimum_distance);
+            if (distance_traceback != nullptr && minimum_distance < std::get<1>(common_ancestor_connectivity)) {
+                //If we're recording the traceback, remember the common node as the common ancestor
+                common_ancestor_connectivity = std::make_tuple(net1, minimum_distance-1, START_END); 
+            }
+        }
+        if (distance_traceback != nullptr) {
+            //If we're recording the traceback, add the nodes
+            distance_traceback->first.emplace_back(net1, 
+                                                   distance_to_start1 == std::numeric_limits<size_t>::max() ? std::numeric_limits<int32_t>::max() : distance_to_start1, 
+                                                   distance_to_end1 == std::numeric_limits<size_t>::max() ? std::numeric_limits<int32_t>::max() : distance_to_end1);
+            distance_traceback->second.emplace_back(net2, 
+                                                   distance_to_start2 == std::numeric_limits<size_t>::max() ? std::numeric_limits<int32_t>::max() : distance_to_start2, 
+                                                   distance_to_end2 == std::numeric_limits<size_t>::max() ? std::numeric_limits<int32_t>::max() : distance_to_end2);        
         }
-        common_ancestor = get_parent(net1);
+        common_ancestor = start_end_traversal_of(get_parent(net1));
     } else {
 
         //Get the distance from position 1 up to the ends of a child of the common ancestor
 #ifdef debug_distances
         cerr << "Reaching the children of the lowest common ancestor for first position..." << endl;
 #endif   
-        while (canonical(get_parent(net1)) != canonical(common_ancestor)) {
-            net_handle_t parent = get_parent(net1);
-            update_distances(net1, parent, distance_to_start1, distance_to_end1);
+        if (distance_traceback != nullptr) {
+            //Start the traceback with the nodes themselves and their offsets
+            distance_traceback->first.emplace_back(net1, 
+                                                   distance_to_start1 == std::numeric_limits<size_t>::max() ? std::numeric_limits<int32_t>::max() : distance_to_start1, 
+                                                   distance_to_end1 == std::numeric_limits<size_t>::max() ? std::numeric_limits<int32_t>::max() : distance_to_end1);
+            distance_traceback->second.emplace_back(net2, 
+                                                   distance_to_start2 == std::numeric_limits<size_t>::max() ? std::numeric_limits<int32_t>::max() : distance_to_start2, 
+                                                   distance_to_end2 == std::numeric_limits<size_t>::max() ? std::numeric_limits<int32_t>::max() : distance_to_end2);        
+        }
+        while (start_end_traversal_of(get_parent(net1)) != common_ancestor && !is_root(get_parent(net1))) {
+            net_handle_t parent = start_end_traversal_of(get_parent(net1));
+            update_distances(net1, parent, distance_to_start1, distance_to_end1, true);
             net1 = parent;
         }
 #ifdef debug_distances
@@ -1272,9 +1701,9 @@ size_t SnarlDistanceIndex::minimum_distance(const handlegraph::nid_t id1, const
         cerr << "Reaching the children of the lowest common ancestor for position 2..." << endl;
 #endif   
         //And the same for position 2
-        while (canonical(get_parent(net2)) != canonical(common_ancestor)) {
-            net_handle_t parent = get_parent(net2);
-            update_distances(net2, parent, distance_to_start2, distance_to_end2);
+        while (start_end_traversal_of(get_parent(net2)) != start_end_traversal_of(common_ancestor) && !is_root(get_parent(net2))) {
+            net_handle_t parent = start_end_traversal_of(get_parent(net2));
+            update_distances(net2, parent, distance_to_start2, distance_to_end2, false);
             net2 = parent;
         }
 #ifdef debug_distances
@@ -1282,11 +1711,6 @@ size_t SnarlDistanceIndex::minimum_distance(const handlegraph::nid_t id1, const
         cerr << "   with distances to ends " << distance_to_start2 << " and " << distance_to_end2 << endl;
 #endif
     }
-    //TODO: I'm taking this out because it should really be start-end connected, but this
-    //won't do this if that traversal isn't possible. Really it should just be setting the 
-    //connectivity instead
-    //net1 = canonical(net1);
-    //net2 = canonical(net2);
 
 
     /* 
@@ -1295,9 +1719,8 @@ size_t SnarlDistanceIndex::minimum_distance(const handlegraph::nid_t id1, const
      * Walk up to the root and check for distances between the positions within each
      * ancestor
      */
+
     while (!is_root(net1)){
-        //TODO: Actually checking distance in a chain is between the nodes, not the snarl
-        //and neither include the lengths of the nodes
 #ifdef debug_distances
             cerr << "At common ancestor " << net_handle_as_string(common_ancestor) <<  endl;
             cerr << "  with distances for child 1 (" << net_handle_as_string(net1) << "): " << distance_to_start1 << " "  << distance_to_end1 << endl;
@@ -1310,6 +1733,8 @@ size_t SnarlDistanceIndex::minimum_distance(const handlegraph::nid_t id1, const
         size_t distance_end_start = distance_in_parent(common_ancestor, net1, flip(net2), graph);
         size_t distance_end_end = distance_in_parent(common_ancestor, net1, net2, graph);
 
+        size_t old_minimum = minimum_distance;
+
         //And add those to the distances we've found to get the minimum distance between the positions
         minimum_distance = std::min(minimum_distance, 
                            std::min(sum({distance_start_start , distance_to_start1 , distance_to_start2}),
@@ -1317,22 +1742,43 @@ size_t SnarlDistanceIndex::minimum_distance(const handlegraph::nid_t id1, const
                            std::min(sum({distance_end_start , distance_to_end1 , distance_to_start2}),
                                     sum({distance_end_end , distance_to_end1 , distance_to_end2})))));
 
+        if (distance_traceback != nullptr && minimum_distance != std::numeric_limits<size_t>::max()
+            && minimum_distance != old_minimum) {
+            //If we want to do traceback and the distance was updated here
+
+            if (minimum_distance == sum({distance_start_start , distance_to_start1 , distance_to_start2})) {
+                //If the distance was the start of 1 to the start of 2
+                common_ancestor_connectivity = std::make_tuple(common_ancestor, distance_start_start, START_START);
+            } else if (minimum_distance == sum({distance_start_end , distance_to_start1 , distance_to_end2})) {
+                common_ancestor_connectivity = std::make_tuple(common_ancestor, distance_start_end, START_END);
+            } else if (minimum_distance == sum({distance_end_start , distance_to_end1 , distance_to_start2})) {
+                common_ancestor_connectivity = std::make_tuple(common_ancestor, distance_end_start, END_START);
+            } else {
+                assert(minimum_distance == sum({distance_end_end , distance_to_end1 , distance_to_end2}));
+                common_ancestor_connectivity = std::make_tuple(common_ancestor, distance_end_end, END_END);
+            } 
+        }
+
 #ifdef debug_distances
             cerr << "    Found distances between nodes: " << distance_start_start << " " << distance_start_end << " " << distance_end_start << " " << distance_end_end << endl;
             cerr << "  best distance is " << minimum_distance << endl;
 #endif
         if (!is_root(common_ancestor)) {
             //Update the distances to reach the ends of the common ancestor
-            update_distances(net1, common_ancestor, distance_to_start1, distance_to_end1);
-            update_distances(net2, common_ancestor, distance_to_start2, distance_to_end2);
+            update_distances(net1, common_ancestor, distance_to_start1, distance_to_end1, true);
+            update_distances(net2, common_ancestor, distance_to_start2, distance_to_end2, false);
 
             //Update which net handles we're looking at
             net1 = common_ancestor;
             net2 = common_ancestor;
-            common_ancestor = get_parent(common_ancestor);
+            common_ancestor = start_end_traversal_of(get_parent(common_ancestor));
         } else {
             //Just update this one to break out of the loop
             net1 = common_ancestor;
+            if (distance_traceback != nullptr) {
+                distance_traceback->first.emplace_back(common_ancestor, std::numeric_limits<int32_t>::max(), std::numeric_limits<int32_t>::max());
+                distance_traceback->second.emplace_back(common_ancestor, std::numeric_limits<int32_t>::max(), std::numeric_limits<int32_t>::max());
+            }
 
         }
 
@@ -1343,12 +1789,1093 @@ size_t SnarlDistanceIndex::minimum_distance(const handlegraph::nid_t id1, const
 #endif
     }
 
+    if (distance_traceback != nullptr) {
+        //If we care about the traceback, then traceback and remove values that aren't used
+        if (minimum_distance == std::numeric_limits<size_t>::max()) {
+            //If there was no minimum distance, clear the traceback
+            distance_traceback->first.clear();
+            distance_traceback->second.clear();
+        } else {
+            //Otherwise, do the traceback
+
+            for ( bool first_node : {true, false}) {
+                vector<tuple<net_handle_t, int32_t, int32_t>>& current_vector = first_node ? distance_traceback->first : distance_traceback->second;
+                //Cut back the traceback to the common ancestor where the children were connected
+                while (std::get<0>(current_vector.back()) != std::get<0>(common_ancestor_connectivity)) {
+                    current_vector.pop_back();
+                } 
+#ifdef debug_distances
+                cerr << "At " << (first_node ? "first " : "second ") << "node, stripped back to " << current_vector.size() << " ancestors" << endl;
+                cerr << "\treplacing last ancestor with common ancestor and distances: " << net_handle_as_string(std::get<0>(common_ancestor_connectivity))
+                     << " " << std::get<1>(common_ancestor_connectivity) << " " << std::get<2>(common_ancestor_connectivity) << endl;
+#endif
+
+                /*Now update the common ancestor in the traceback
+                 */
+
+                //Is the path going out the start of this node?
+                bool from_start = (first_node && get_start_endpoint(std::get<2>(common_ancestor_connectivity)) == START) ||
+                                  (!first_node && get_end_endpoint(std::get<2>(common_ancestor_connectivity)) == START);
+                //Is the path going to the start of the other node?
+                bool to_start = (first_node && get_end_endpoint(std::get<2>(common_ancestor_connectivity)) == START) ||
+                                  (!first_node && get_start_endpoint(std::get<2>(common_ancestor_connectivity)) == START);
+                if (to_start) { 
+                    std::get<1>(current_vector.back()) = from_start ? (std::get<1>(common_ancestor_connectivity) == 0 ? std::numeric_limits<int32_t>::min()
+                                                                                                                      : -std::get<1>(common_ancestor_connectivity))
+                                                                    : std::get<1>(common_ancestor_connectivity);
+                    std::get<2>(current_vector.back()) = std::numeric_limits<int32_t>::max();
+                } else {
+                    std::get<1>(current_vector.back()) = std::numeric_limits<int32_t>::max();
+                    std::get<2>(current_vector.back()) = from_start ? (std::get<1>(common_ancestor_connectivity) == 0 ? std::numeric_limits<int32_t>::min()
+                                                                                                                      : -std::get<1>(common_ancestor_connectivity))
+                                                                    : std::get<1>(common_ancestor_connectivity);
+                }
+
+                /*
+                 * Walk through the traceback and keep only the relevant value
+                 */
+                for (int i = current_vector.size() - 2 ; i > 0 ; i--) {
+                    assert(i >= 0 && i < current_vector.size());
+                    if (from_start) {
+                        //If the parent of the current child has distance out the start, clear the distance to this child's parent's end
+                        std::get<2>(current_vector[i]) = std::numeric_limits<int32_t>::max();
+
+                        //If the current child's distance to it's parent's start is negative, then it's distance went out the start so
+                        //we will want it's child distance to the start
+                        from_start = std::get<1>(current_vector[i]) < 0;
+#ifdef debug_distances
+                        assert(std::get<1>(current_vector[i]) != std::numeric_limits<int32_t>::max());
+#endif
+                    } else {
+                        //If the parent of the current child has distance out the end, clear the distance to this child's parent's start
+                        std::get<1>(current_vector[i]) = std::numeric_limits<int32_t>::max();
+
+                        //If the current child's distance to it's parent's end is negative, then it's distance went out the start so
+                        //we will want it's child distance to the start
+                        from_start = std::get<2>(current_vector[i]) < 0;
+#ifdef debug_distances
+                        assert(std::get<2>(current_vector[i]) != std::numeric_limits<int32_t>::max());
+#endif
+                    }
+                }
+            }
+#ifdef debug_distance_paths
+            cerr << "Traced back to common ancestor " << net_handle_as_string(std::get<0>(common_ancestor_connectivity)) <<  endl;
+            cerr << "Node1: " << endl;
+            for (auto x : distance_traceback->first) {
+                cerr << "\t" << net_handle_as_string(std::get<0>(x)) << " " << std::get<1>(x) << " " << std::get<2>(x) << endl;
+            }
+            cerr << "Node2: " << endl;
+            for (auto x : distance_traceback->second) {
+                cerr << "\t" << net_handle_as_string(std::get<0>(x)) << " " << std::get<1>(x) << " " << std::get<2>(x) << endl;
+            }
+
+#endif
+        }
+    }
+
     //minimum distance currently includes both positions
     return minimum_distance == std::numeric_limits<size_t>::max() ? std::numeric_limits<size_t>::max() : minimum_distance-1;
 
 
 
 }
+size_t SnarlDistanceIndex::maximum_distance(const handlegraph::nid_t id1, const bool rev1, const size_t offset1, 
+                                            const handlegraph::nid_t id2, const bool rev2, const size_t offset2, 
+                                            bool unoriented_distance, const HandleGraph* graph) const {
+    RootRecord root_record (get_root(), &snarl_tree_records);
+    size_t max_node_id = root_record.get_min_node_id() + root_record.get_node_count();
+    if (id1 < root_record.get_min_node_id() || id2 < root_record.get_min_node_id() ||
+        id1 > max_node_id || id2 > max_node_id) {
+        throw runtime_error("error: Looking for the maximum distance of a node that does not exist");
+    }
+
+
+#ifdef debug_distances
+        cerr << endl;
+        cerr << "Find the maximum distance between " << id1 << " " <<rev1 <<" " << offset1 << " and " << id2 << " " << rev2 << " " << offset2 << endl;
+#endif
+
+
+    /*Helper function to walk up the snarl tree
+     * Given a net handle, its parent,  and the distances to the start and end of the handle, 
+     * update the distances to reach the ends of the parent and update the handle and its parent
+     * If the parent is a chain, then the new distances include the boundary nodes of the chain.
+     * If it is a snarl, it does not*/
+    //TODO: This should really be an actual function and it doesn't consider the lengths of the 
+    //boundary nodes. I think chains might need to know the lengths of their boundary nodes,
+    //or it could find it from the snarl. Really, since the snarl is storing it anyway, I should
+    //probaby rearrange things so that either the snarl or the chain can access boundary node lengths
+    auto update_distances = [&](net_handle_t& net, net_handle_t& parent, size_t& dist_start, size_t& dist_end, bool first_node) {
+#ifdef debug_distances
+        cerr << "     Updating distance from node " << net_handle_as_string(net) << " at parent " << net_handle_as_string(parent) << endl;
+#endif
+
+        if (is_trivial_chain(parent)) {
+            //Don't update distances for the trivial chain
+            return;
+        } else if (is_simple_snarl(parent)) {
+            //If it's a simple snarl just check if they should be reversed
+            if (is_reversed_in_parent (net)) {
+                size_t tmp = dist_start;
+                dist_start = dist_end;
+                dist_end = tmp;
+            } 
+
+            return;
+        }
+
+
+        net_handle_t start_bound = get_bound(parent, false, true);
+        net_handle_t end_bound = get_bound(parent, true, true);
+
+        //The lengths of the start and end nodes of net
+        //This is only needed if net is a snarl, since the boundary nodes are not technically part of the snarl
+        size_t start_length = is_chain(parent) ? node_length(start_bound) : 0;
+        size_t end_length = is_chain(parent) ? node_length(end_bound) : 0;
+
+        //Get the distances from the bounds of the parent to the node we're looking at
+        size_t distance_start_start = start_bound == net ? 0 
+                : sum({start_length, max_distance_in_parent(parent, start_bound, flip(net), graph)});
+        size_t distance_start_end = start_bound == flip(net) ? 0 
+                : sum({start_length, max_distance_in_parent(parent, start_bound, net, graph)});
+        size_t distance_end_start = end_bound == net ? 0 
+                : sum({end_length, max_distance_in_parent(parent, end_bound, flip(net), graph)});
+        size_t distance_end_end = end_bound == flip(net) ? 0 
+                : sum({end_length, max_distance_in_parent(parent, end_bound, net, graph)});
+
+        size_t distance_start = dist_start;
+        size_t distance_end = dist_end; 
+
+        dist_start = maximum( sum({distance_start_start, distance_start}), 
+                              sum({distance_start_end , distance_end}));
+        dist_end = maximum(sum({distance_end_start , distance_start}), 
+                           sum({distance_end_end , distance_end}));
+#ifdef debug_distances
+        cerr << "        ...new distances to start and end: " << dist_start << " " << dist_end << endl;
+#endif
+        return;
+    };
+
+    /*
+     * Get net handles for the two nodes and the distances from each position to the ends of the handles
+     * TODO: net2 is pointing in the opposite direction of the position. The final 
+     * distance will be between the two nets pointing towards each other
+     */
+    net_handle_t net1 = get_node_net_handle(id1);
+    net_handle_t net2 = get_node_net_handle(id2);
+    pair<net_handle_t, bool> lowest_ancestor = lowest_common_ancestor(net1, net2);
+    if (!lowest_ancestor.second) {
+        //If these are not in the same connected component
+#ifdef debug_distances
+        cerr << "These are in different connected components" << endl;
+#endif
+        return std::numeric_limits<size_t>::max();
+    }
+
+    //The lowest common ancestor of the two positions
+    net_handle_t common_ancestor = start_end_traversal_of(lowest_ancestor.first);
+
+#ifdef debug_distances
+        cerr << "Found the lowest common ancestor " << net_handle_as_string(common_ancestor) << endl;
+#endif
+    //These are the distances to the ends of the node, including the position
+    size_t distance_to_start1 = rev1 ? node_length(net1) - offset1 : offset1 + 1;
+    size_t distance_to_end1 = rev1 ? offset1 + 1 : node_length(net1) - offset1;
+    size_t distance_to_start2 = rev2 ? node_length(net2) - offset2 : offset2 + 1;
+    size_t distance_to_end2 = rev2 ? offset2 + 1 : node_length(net2) - offset2;
+
+    if (!unoriented_distance) {
+        //If we care about the oriented distance, one of the distances will be infinite
+        if (rev1) {
+            distance_to_end1 = std::numeric_limits<size_t>::max();
+        } else {
+            distance_to_start1 = std::numeric_limits<size_t>::max();
+        }
+        if (rev2) {
+            distance_to_start2 = std::numeric_limits<size_t>::max();
+        } else {
+            distance_to_end2 = std::numeric_limits<size_t>::max();
+        }
+    }
+
+#ifdef debug_distances
+        cerr << "Starting with distances " << distance_to_start1 << " " << distance_to_end1 << " and " << distance_to_start2 << " " << distance_to_end2 << endl;
+#endif
+
+    size_t maximum_distance = std::numeric_limits<size_t>::max();
+
+    //Remember which common ancestor the maximum distance actually comes from
+    //tuple of <the ancestor, distance between the children, connectivity between the two children
+    tuple<net_handle_t, size_t, connectivity_t> common_ancestor_connectivity (get_root(), std::numeric_limits<size_t>::max(), START_END); 
+
+
+    /*
+     * Walk up the snarl tree until net1 and net2 are children of the lowest common ancestor
+     * Keep track of the distances to the ends of the net handles as we go
+     */
+ 
+    if (start_end_traversal_of(net1) == start_end_traversal_of(net2)){
+        if (sum({distance_to_end1 , distance_to_start2}) > node_length(net1) && 
+            sum({distance_to_end1 , distance_to_start2}) != std::numeric_limits<size_t>::max()) {
+            //If the positions are on the same node and are pointing towards each other, then
+            //check the distance between them in the node
+            maximum_distance = minus(sum({distance_to_end1 , distance_to_start2}), node_length(net1));
+        }
+        if (sum({distance_to_start1 , distance_to_end2}) > node_length(net1) && 
+            sum({distance_to_start1 , distance_to_end2}) != std::numeric_limits<size_t>::max()) {
+            size_t new_max = minus(sum({distance_to_start1 , distance_to_end2}), node_length(net1));
+            if (new_max != std::numeric_limits<size_t>::max()) {
+                maximum_distance = maximum_distance == std::numeric_limits<size_t>::max() ? new_max 
+                                 : std::max(new_max, maximum_distance);
+            }
+        }
+        common_ancestor = start_end_traversal_of(get_parent(net1));
+    } else {
+
+        //Get the distance from position 1 up to the ends of a child of the common ancestor
+#ifdef debug_distances
+        cerr << "Reaching the children of the lowest common ancestor for first position..." << endl;
+#endif   
+        while (start_end_traversal_of(get_parent(net1)) != common_ancestor && !is_root(get_parent(net1))) {
+            net_handle_t parent = start_end_traversal_of(get_parent(net1));
+            update_distances(net1, parent, distance_to_start1, distance_to_end1, true);
+            net1 = parent;
+        }
+#ifdef debug_distances
+        cerr << "Reached node " << net_handle_as_string(net1) << " for position 1" << endl;
+        cerr << "   with distances to ends " << distance_to_start1 << " and " << distance_to_end1 << endl;
+        cerr << "Reaching the children of the lowest common ancestor for position 2..." << endl;
+#endif   
+        //And the same for position 2
+        while (start_end_traversal_of(get_parent(net2)) != start_end_traversal_of(common_ancestor) && !is_root(get_parent(net2))) {
+            net_handle_t parent = start_end_traversal_of(get_parent(net2));
+            update_distances(net2, parent, distance_to_start2, distance_to_end2, false);
+            net2 = parent;
+        }
+#ifdef debug_distances
+        cerr << "Reached node " << net_handle_as_string(net2) << " for position 2" << endl;
+        cerr << "   with distances to ends " << distance_to_start2 << " and " << distance_to_end2 << endl;
+#endif
+    }
+    //TODO: I'm taking this out because it should really be start-end connected, but this
+    //won't do this if that traversal isn't possible. Really it should just be setting the 
+    //connectivity instead
+    //net1 = canonical(net1);
+    //net2 = canonical(net2);
+
+
+    /* 
+     * common_ancestor is now the lowest common ancestor of both net handles, and 
+     * net1 and net2 are both children of common_ancestor
+     * Walk up to the root and check for distances between the positions within each
+     * ancestor
+     */
+
+    while (!is_root(net1)){
+        //TODO: Actually checking distance in a chain is between the nodes, not the snarl
+        //and neither include the lengths of the nodes
+#ifdef debug_distances
+            cerr << "At common ancestor " << net_handle_as_string(common_ancestor) <<  endl;
+            cerr << "  with distances for child 1 (" << net_handle_as_string(net1) << "): " << distance_to_start1 << " "  << distance_to_end1 << endl;
+            cerr << "                     child 2 (" << net_handle_as_string(net2) << "): " << distance_to_start2 << " " <<  distance_to_end2 << endl;
+#endif
+
+        //Find the maximum distance between the two children (net1 and net2)
+        size_t distance_start_start = max_distance_in_parent(common_ancestor, flip(net1), flip(net2), graph);
+        size_t distance_start_end = max_distance_in_parent(common_ancestor, flip(net1), net2, graph);
+        size_t distance_end_start = max_distance_in_parent(common_ancestor, net1, flip(net2), graph);
+        size_t distance_end_end = max_distance_in_parent(common_ancestor, net1, net2, graph);
+
+        size_t old_maximum = maximum_distance;
+
+        //And add those to the distances we've found to get the maximum distance between the positions
+        maximum_distance = maximum(maximum_distance, 
+                           maximum(sum({distance_start_start , distance_to_start1 , distance_to_start2}),
+                           maximum(sum({distance_start_end , distance_to_start1 , distance_to_end2}),
+                           maximum(sum({distance_end_start , distance_to_end1 , distance_to_start2}),
+                                    sum({distance_end_end , distance_to_end1 , distance_to_end2})))));
+
+
+#ifdef debug_distances
+            cerr << "    Found distances between nodes: " << distance_start_start << " " << distance_start_end << " " << distance_end_start << " " << distance_end_end << endl;
+            cerr << "  best distance is " << maximum_distance << endl;
+#endif
+        if (!is_root(common_ancestor)) {
+            //Update the distances to reach the ends of the common ancestor
+            update_distances(net1, common_ancestor, distance_to_start1, distance_to_end1, true);
+            update_distances(net2, common_ancestor, distance_to_start2, distance_to_end2, false);
+
+            //Update which net handles we're looking at
+            net1 = common_ancestor;
+            net2 = common_ancestor;
+            common_ancestor = start_end_traversal_of(get_parent(common_ancestor));
+        } else {
+            //Just update this one to break out of the loop
+            net1 = common_ancestor;
+
+        }
+
+#ifdef debug_distances
+            cerr << "  new common ancestor " << net_handle_as_string(common_ancestor) <<  endl;
+            cerr << "  new distances are " << distance_to_start1 << " "  << distance_to_end1 << 
+                    " " << distance_to_start2 << " " <<  distance_to_end2 << endl;
+#endif
+    }
+
+
+    //maximum distance currently includes both positions
+    return maximum_distance == std::numeric_limits<size_t>::max() ? std::numeric_limits<size_t>::max() : maximum_distance-1;
+
+}
+void SnarlDistanceIndex::for_each_handle_in_shortest_path(const handlegraph::nid_t id1, const bool rev1, const handlegraph::nid_t id2, const bool rev2, 
+                                      const HandleGraph* graph, const std::function<bool(const handlegraph::handle_t, size_t)>& iteratee) const {
+    cerr << "This isn't working, use handlegraph::algorithms::for_each_handle_in_shortest_path instead until I fix it" << endl;
+    return;
+
+    /* First, run minimum distance to get the traceback.
+     * The traceback will be a list of ancestors for each node. They will take the format 
+        <net_handle, distance from last child to to start of net, distance to end of net>
+       The distances will be signed, + meaning that the child (the child of the net handle in the tuple) is traversed forward, - for backwards
+       The last entry in both lists will be for the lowest common ancestor that must be traversed to find the minimum distance (not
+       necessarily the actual lowest common ancestor), and the distances will be from either end of the 
+    */
+    pair<vector<tuple<net_handle_t, int32_t, int32_t>>, vector<tuple<net_handle_t, int32_t, int32_t>>> distance_traceback;
+    size_t distance = minimum_distance(id1, rev1, 0, id2, rev2, 0, false,graph, &distance_traceback);
+#ifdef debug_distance_paths
+    cerr << endl << "Find the minimum distance path between " << id1 << (rev1 ? "rev" : "fd") << " and " << id2 << (rev2 ? "rev" : "fd")
+         << " which has distance between them " << distance << endl;
+#endif
+
+
+    /* We can stop now if the minimum_distance was infinite or if the minimum_distance was within one node
+    */
+
+    if (distance_traceback.first.size() == 0 && distance_traceback.second.size() == 0) {
+        //If there was no path between them
+#ifdef debug_distance_paths
+        assert(distance == std::numeric_limits<size_t>::max());
+#endif
+        return;
+    } else if (distance_traceback.first.size() == 1 && distance_traceback.second.size() == 1) {
+        //If there is only one thing in the traceback, then the two positions must be on the same node
+#ifdef debug_distance_paths
+        assert(is_node(std::get<0>(distance_traceback.first.back())));
+        assert(is_node(std::get<0>(distance_traceback.second.back())));
+        assert(std::get<0>(distance_traceback.first.back()) == std::get<0>(distance_traceback.second.back()));
+        assert(id1 == id2);
+        assert(node_id(std::get<0>(distance_traceback.first.back())) == id1);
+#endif
+        return;
+    }
+#ifdef debug_distance_paths
+        assert(distance_traceback.first.size() > 1);
+        assert(distance_traceback.second.size() > 1);
+#endif
+
+
+    /* Otherwise, walk up the snarl tree from the first node (traversing its traceback vector forwards), and at each
+     * ancestor, call for_each_handle_in_shortest_path_in_snarl/chain to get to the boundary nodes, 
+     * then at the common ancestor, traverse between the second to last ancestor in both lists,
+     * then go through the second node's traceback vector backwards, calling for_each_handle_in_shortest_path_in_snarl/chain
+     * to get from the boundary nodes to each child
+    */
+
+    // Start with the first node
+    net_handle_t& current_node = std::get<0>(distance_traceback.first[0]);
+    net_handle_t& current_parent = std::get<0>(distance_traceback.first[1]);
+
+    size_t distance_traversed = 0;
+
+
+    for (size_t i = 1 ; i < distance_traceback.first.size()-1 ; i++) {
+        //Walking up the snarl tree, walk from the current node to the current parent in the given distance
+        //i always points to the current parent that we're finding distances in
+        if (is_trivial_chain(get_parent(current_node))) {
+            current_node = get_parent(current_node);
+        }
+#ifdef debug_distance_paths
+        cerr << "At traceback for first node: " << net_handle_as_string(std::get<0>(distance_traceback.first[i])) << " " << std::get<1>(distance_traceback.first[i]) << " " << std::get<2>(distance_traceback.first[i]) << endl;
+        cerr << "At current node " << net_handle_as_string(current_node) << endl;
+#endif
+
+        //The (signed) distance from the current node to the end of the current parent
+        int32_t distance_to_traverse = std::get<2>(distance_traceback.first[i]) == std::numeric_limits<int32_t>::max() 
+                            ? std::get<1>(distance_traceback.first[i])
+                            :  std::get<2>(distance_traceback.first[i]);
+#ifdef debug_distance_paths
+        assert(distance_to_traverse != std::numeric_limits<int32_t>::max());                                
+#endif
+
+        //The boundary node/sentinel of the parent pointing out of the parent
+        net_handle_t boundary;
+        if (std::get<1>(distance_traceback.first[i]) == std::numeric_limits<int32_t>::max()) {
+            //If we're traversing to the end of the parent
+            boundary = get_bound(current_parent, true, false);
+        } else {
+            //If we're traversing to the beginning of the parent
+            boundary = get_bound(current_parent, false, false);
+        }
+
+        //Make sure the current node is oriented correctly
+        if ((ends_at(current_node) != START && distance_to_traverse < 0) 
+            || (ends_at(current_node) == START && distance_to_traverse >= 0)) {
+            current_node = flip(current_node);
+        }
+        //We don't care about the orientation for the distance anymore so get the actual value
+        distance_to_traverse = distance_to_traverse == std::numeric_limits<int32_t>::min() ? 0 : std::abs(distance_to_traverse);
+
+
+        if (is_chain(current_parent)) {
+            if (current_node != boundary) {
+                //Go from current node to boundary, not including the length of boundary in the distance_to_traverse
+                for_each_handle_in_shortest_path_in_chain(current_parent, current_node, boundary, distance_to_traverse - node_length(boundary), distance_traversed, graph, iteratee, nullptr);
+
+                //Now iteratee() on boundary
+                iteratee(get_handle(boundary, graph), distance_traversed);
+                distance_traversed += minimum_length(boundary);
+                distance_to_traverse -= minimum_length(boundary);
+            }
+        } else {
+            for_each_handle_in_shortest_path_in_snarl(current_parent, current_node, boundary, distance_to_traverse, distance_traversed, graph, iteratee, nullptr);
+        }
+        current_node = current_parent;
+        current_parent = std::get<0>(distance_traceback.first[i+1]);
+    }
+
+    /* Now walk between the two children of the common ancestor */
+
+#ifdef debug_distance_paths
+    assert(current_parent == std::get<0>(distance_traceback.second.back()));
+#endif
+
+    int32_t distance_between = std::get<1>(distance_traceback.first[distance_traceback.first.size()-1]) == std::numeric_limits<int32_t>::max() 
+                             ? std::get<2>(distance_traceback.first[distance_traceback.first.size()-1])
+                             : std::get<1>(distance_traceback.first[distance_traceback.first.size()-1]);
+
+    //Child of the common ancestor for the second node
+    net_handle_t next_node = std::get<0>(distance_traceback.second[distance_traceback.second.size()-2]);
+    if (is_trivial_chain(get_parent(next_node))) {
+        next_node = get_parent(next_node);
+    }
+    if (is_trivial_chain(get_parent(current_node))) {
+        current_node = get_parent(current_node);
+    }
+#ifdef debug_distance_paths
+    cerr << "Finding distance between two children " << net_handle_as_string(current_node) << " and " << net_handle_as_string (next_node) << endl;
+    cerr << "\tdistance should be " << distance_between << endl;
+#endif
+
+    //Make sure the current node is oriented correctly
+    if ((ends_at(current_node) != START && distance_between < 0) 
+        || (ends_at(current_node) == START && distance_between > 0)) {
+        current_node = flip(current_node);
+    } 
+    distance_between = distance_between == std::numeric_limits<int32_t>::min() ? 0 : std::abs(distance_between);
+
+    //And the next node. Based on the last entry in the first node's traceback. The second or third value will 
+    //be inf depending on whether the second node's ancestor is traversed forward or backwards 
+    if ((ends_at(next_node) != START && std::get<1>(distance_traceback.first.back()) == std::numeric_limits<int32_t>::max()) 
+        || (ends_at(next_node) == START && std::get<2>(distance_traceback.first.back()) == std::numeric_limits<int32_t>::max())) {
+#ifdef debug_distance_paths
+        cerr << "Flip next node which is currently: " << net_handle_as_string(next_node) << " because the last traceback for the first node is " 
+             << net_handle_as_string(std::get<0>(distance_traceback.first.back())) << " " 
+             << std::get<1>(distance_traceback.first.back()) << " " << std::get<2>(distance_traceback.first.back()) << endl; 
+#endif
+
+        next_node = flip(next_node);
+    }
+
+    if (is_chain(current_parent)) {
+        for_each_handle_in_shortest_path_in_chain(current_parent, current_node, next_node, distance_between, distance_traversed, graph, iteratee, nullptr);
+    } else {
+        for_each_handle_in_shortest_path_in_snarl(current_parent, current_node, next_node, distance_between, distance_traversed, graph, iteratee, nullptr);
+    }
+
+    /* Now walk down the snarl tree for the second node, finding the distance_to_traverse from the bound of each parent to its child
+     * Start with the parent one below the common ancestor  
+    */
+    current_parent = next_node;
+    if (distance_traceback.second.size() >= 3) {
+        next_node = std::get<0>(distance_traceback.second[distance_traceback.second.size() - 3]);
+    }
+#ifdef debug_distance_paths
+    cerr << "Now walk down node 2 from parent " << net_handle_as_string(current_parent) << " to node " << net_handle_as_string(next_node) << endl;
+#endif
+    for (int i = distance_traceback.second.size() - 2 ; i > 0 ; i--) {
+        assert(i >= 1 && i < distance_traceback.second.size());
+        //Walk down the snarl tree. i points to the current parent, next_node is one below the parent
+        //
+        current_parent = std::get<0>(distance_traceback.second[i]);
+        next_node = std::get<0>(distance_traceback.second[i-1]);
+        if (is_trivial_chain(get_parent(next_node))) {
+            next_node = get_parent(next_node);
+        }
+
+#ifdef debug_distance_paths
+        cerr << "At traceback for second node: " << net_handle_as_string(std::get<0>(distance_traceback.second[i])) << " " << std::get<1>(distance_traceback.second[i]) << " " << std::get<2>(distance_traceback.second[i]) << endl;
+        cerr << "At next node " << net_handle_as_string(next_node) << " with parent " << net_handle_as_string(current_parent) << endl;
+#endif
+
+        //The (signed) distance_to_traverse from the current node to the end of the current parent
+        int32_t distance_to_traverse = std::get<2>(distance_traceback.second[i]) == std::numeric_limits<int32_t>::max() 
+                            ? std::get<1>(distance_traceback.second[i])
+                            :  std::get<2>(distance_traceback.second[i]);
+
+        //The boundary node/sentinel of the parent pointing into the parent
+        net_handle_t boundary;
+        if (std::get<1>(distance_traceback.second[i]) == std::numeric_limits<int32_t>::max()) {
+            //If we're traversing to the end of the parent
+            boundary = get_bound(current_parent, true, true);
+        } else {
+            //If we're traversing to the beginning of the parent
+            boundary = get_bound(current_parent, false, true);
+        }
+
+        //Make sure the current node is oriented correctly
+        if ((ends_at(next_node) == START && distance_to_traverse < 0) 
+            || (ends_at(next_node) != START && distance_to_traverse >= 0)) {
+            next_node = flip(next_node);
+        } 
+
+        //We don't care about the orientation for the distance anymore so get the actual value
+        distance_to_traverse = distance_to_traverse == std::numeric_limits<int32_t>::min() ? 0 : std::abs(distance_to_traverse);
+
+
+        if (is_chain(current_parent)) {
+
+            if (next_node != boundary) {
+                iteratee(get_handle(boundary, graph), distance_traversed);
+                distance_traversed += minimum_length(boundary);
+                distance_to_traverse -= minimum_length(boundary);
+
+                for_each_handle_in_shortest_path_in_chain(current_parent, boundary, next_node, distance_to_traverse, distance_traversed, graph, iteratee, nullptr);
+            }
+        } else {
+            for_each_handle_in_shortest_path_in_snarl(current_parent, boundary, next_node, distance_to_traverse, distance_traversed, graph, iteratee, nullptr);
+        }
+
+    }
+}
+void SnarlDistanceIndex::for_each_handle_in_shortest_path_in_snarl(const net_handle_t& snarl_handle, net_handle_t start, net_handle_t end,
+                                      size_t distance_to_traverse, size_t& distance_traversed, const HandleGraph* graph,
+                                      const std::function<bool(const handlegraph::handle_t, size_t)>& iteratee,
+                                      vector<pair<net_handle_t, size_t>>* to_duplicate) const {
+#ifdef debug_distance_paths
+    size_t target_distance = distance_to_traverse;
+    size_t starting_distance = distance_traversed;
+    cerr << "Find shortest path in " << net_handle_as_string(snarl_handle) << " from " << net_handle_as_string(start) << " to " << net_handle_as_string(end) << " with distance " << distance_to_traverse << endl;
+    if (SnarlRecord(snarl_handle, &snarl_tree_records).get_record_type() != OVERSIZED_SNARL) {
+        cerr << "\tactual distance is " << distance_in_parent(snarl_handle, start, flip(end)) << endl;
+        assert(distance_in_parent(snarl_handle, start, flip(end)) == distance_to_traverse);
+    }
+#endif
+
+    /* Traverse the shortest path from start to end using the A* algorithm
+     * For any child that isn't a trivial chain, recurse with for_each_handle_in_shortest_path_in_chain
+     * Since the heuristic is the exact minimum distance, we don't need to have a priority queue of next nodes,
+     * there will always be only one that is on the minimum distance path.  
+    */
+
+    SnarlRecord snarl_record (snarl_handle, &snarl_tree_records);
+    if (snarl_record.get_record_type() == OVERSIZED_SNARL) {
+        //IF this is an oversized snarl, then we don't have any distance information so use the handlgraph algorithm
+        //for traversing the shortest path
+
+        //Get the start going out of the child chain (or just the node)
+        handlegraph::handle_t start_handle = (is_trivial_chain(start) || is_sentinel(start)) ? get_handle(start, graph) :
+            get_handle((ends_at(start) != START ? get_bound(start, true, false) : get_bound(start, false, false)), graph); 
+        //Get the end going into the child chain (or just the node)
+        handlegraph::handle_t end_handle = (is_trivial_chain(end) || is_sentinel(end)) ? get_handle(end, graph) :
+            get_handle((ends_at(end) != START ?  get_bound(end, false, true) : get_bound(end, true, true) ), graph); 
+#ifdef debug_distance_paths
+        cerr << "Traversing oversized snarl from " << graph->get_id(start_handle) << (graph->get_is_reverse(start_handle) ? "rev" : "fd")
+             << " to " << graph->get_id(end_handle) << (graph->get_is_reverse(end_handle) ? "rev" : "fd") << endl;
+#endif
+
+        //Add distance traversed through the snarl to distance_traversed
+        size_t distance_to_add = 0;
+        handlegraph::algorithms::for_each_handle_in_shortest_path(graph, start_handle, end_handle, [&](handlegraph::handle_t next_handle, size_t distance) {
+            distance_to_add += graph->get_length(next_handle);
+            if (to_duplicate != nullptr) {
+                net_handle_t duplicated_node = get_net(next_handle, graph);
+                to_duplicate->emplace_back(flip(duplicated_node), minimum_length(duplicated_node));
+            }
+            return iteratee(next_handle, distance + distance_traversed);
+        });
+        distance_traversed += distance_to_add;
+#ifdef debug_distance_paths
+        cerr << "Finished traversing oversized snarl, we've now traversed " << distance_traversed << endl;
+#endif
+        return;
+
+    }
+#ifdef debug_distance_paths
+    unordered_set<net_handle_t> seen;
+#endif
+
+    net_handle_t next = start;
+
+    //We need to make sure we actually try to find a path when start == end instead of stopping immediately
+    bool started = start != end;
+    while (next != end || !started) {
+#ifdef debug_distance_paths
+        cerr << "Walk out from " << net_handle_as_string(next) << endl;;
+        if (seen.count(next) > 0) {
+            cerr << "WE've already seen " << net_handle_as_string(next) << endl;
+            throw runtime_error("error: Retraversing node");
+        }
+        seen.emplace(next);
+#endif
+        follow_net_edges(next, graph, false, [&] (const net_handle_t& next_net) {
+#ifdef debug_distance_paths
+            cerr << "Following net edge from " << net_handle_as_string(next) << endl;
+            cerr << "Checking next net " << net_handle_as_string(next_net) << " find distance to " << net_handle_as_string(flip(end)) << endl;
+            cerr << "Traversed " << distance_traversed << " so far, looking for " << distance_to_traverse << endl;
+            bool snarl_is_root = is_root(snarl_handle) || is_root_snarl(snarl_handle) ||
+                           SnarlTreeRecord(snarl_handle, &snarl_tree_records).get_record_type() == ROOT_SNARL ||
+                            SnarlTreeRecord(snarl_handle, &snarl_tree_records).get_record_type() == DISTANCED_ROOT_SNARL;
+            if (!is_root(snarl_handle)) {
+                if( (end != get_bound(snarl_handle, true, false) && next ==  get_bound(snarl_handle, true, false))
+                || (end != get_bound(snarl_handle, false, false) && next ==  get_bound(snarl_handle, false, false))) {
+                    throw runtime_error("error: Trying to leave the snarl without finding the thing we're looking for");
+                }
+            }
+#endif
+            if (next_net == end) {
+                //If we reach the end, stop because we want the minimum distance path and we must be done
+#ifdef debug_distance_paths
+                cerr << "\tFinished traversal" << endl;
+                assert(distance_to_traverse == 0);
+#endif
+                next = next_net;
+                started = true;
+                return false;
+            } else if (is_sentinel(next_net)) { 
+                //If we've reached a sentinel and are trying to leave the snarl but haven't hit the thing we're looking for yet
+#ifdef debug_distance_paths
+                cerr << "\tTrying to leave the snarl so continue looking" << endl;
+#endif
+               started = true;
+                return true; //Continue
+            } else if (sum({distance_in_parent(snarl_handle, next_net, flip(end)), minimum_length(next_net)}) == distance_to_traverse) {
+#ifdef debug_distance_paths
+                cerr << "\tThis can reach the end going across in " << distance_to_traverse << " so iterate on it and continue from " << net_handle_as_string(next_net) << endl;
+#endif
+                //If the next node can reach the end in the correct distances going across the node
+
+                if (is_trivial_chain(next_net) || is_node(next_net)) {
+                    //If this is just a node, run iteratee on it
+                    iteratee(get_handle(next_net, graph), distance_traversed);
+                    distance_traversed += minimum_length(next_net);
+                    distance_to_traverse -= minimum_length(next_net);
+                    if (to_duplicate != nullptr) {
+                        to_duplicate->emplace_back(flip(next_net), minimum_length(next_net));
+                    }
+                    
+                } else if (is_chain(next_net)) {
+#ifdef debug_distance_paths
+                    size_t starting_distance_traversed = distance_traversed;
+#endif
+                    //Recurse on the chain
+                    net_handle_t chain_start_bound = get_bound(next_net, ends_at(next_net) == START, true);
+                    net_handle_t chain_end_bound = get_bound(next_net, ends_at(next_net) != START, false);
+
+                    //iteratee on the start bound
+                    iteratee(get_handle(chain_start_bound, graph), distance_traversed);
+                    distance_traversed += minimum_length(chain_start_bound);
+                    if (to_duplicate != nullptr) {
+                        to_duplicate->emplace_back(flip(chain_start_bound), minimum_length(chain_start_bound));
+                    }
+
+                    //Do the chain
+                    for_each_handle_in_shortest_path_in_chain(next_net, chain_start_bound, 
+                                                              chain_end_bound,
+                                                              minimum_length(next_net) - minimum_length(chain_start_bound) - minimum_length(chain_end_bound), 
+                                                              distance_traversed, graph, iteratee, to_duplicate);
+
+                    //iteratee on the end bound
+                    iteratee(get_handle(chain_end_bound, graph), distance_traversed);
+                    distance_traversed += minimum_length(chain_end_bound);
+#ifdef debug_distance_paths
+                    cerr << "Just traversed " << net_handle_as_string(next_net) << " with length " << minimum_length(next_net) << " started at distance " << starting_distance_traversed << " and now at " << distance_traversed << endl;
+                    assert((distance_traversed - starting_distance_traversed) == minimum_length(next_net));
+#endif
+
+                    //This includes the bounds
+                    distance_to_traverse -= minimum_length(next_net);
+                    if (to_duplicate != nullptr) {
+                        to_duplicate->emplace_back(flip(chain_end_bound), minimum_length(chain_end_bound));
+                    }
+                }
+                next = next_net;
+                started = true;
+
+                return false;//Return false to stop iterating
+            } else if (is_chain(next_net) && sum({distance_in_parent(snarl_handle, flip(next_net), flip(end)), 
+                             distance_in_parent(next_net, get_bound(next_net, ends_at(next_net) == START, true),
+                                                          get_bound(next_net, ends_at(next_net) == START, true)),
+                            2*minimum_length(get_bound(next_net, ends_at(next_net) == START, true))}) == distance_to_traverse) {
+#ifdef debug_distance_paths
+                cerr << "\tThis can reach the end by looping in " << distance_to_traverse << " so iterate on it and continue from " << net_handle_as_string(flip(next_net)) << endl;
+#endif
+                //If the next node can reach the end in the correct distances by reversing in the node
+
+                //Recurse on the chain
+                net_handle_t chain_start_bound = get_bound(next_net, ends_at(next_net) == START, true);
+
+                //Iteratee on the bound of the chain going in
+                iteratee(get_handle(chain_start_bound, graph), distance_traversed);
+                distance_traversed += minimum_length(chain_start_bound);
+                distance_to_traverse -= minimum_length(chain_start_bound);
+                if (to_duplicate != nullptr) {
+                    to_duplicate->emplace_back(flip(chain_start_bound), minimum_length(chain_start_bound));
+                }
+
+                //Recurse on the chain finding a path from start to start
+                for_each_handle_in_shortest_path_in_chain(next_net, chain_start_bound, 
+                                                          flip(chain_start_bound),
+                                                          distance_in_parent(next_net, chain_start_bound, chain_start_bound), 
+                                                          distance_traversed, graph, iteratee, to_duplicate);
+                distance_to_traverse -= distance_in_parent(next_net, chain_start_bound, chain_start_bound);
+
+
+                //Iteratee on the bound of the chain going out
+                iteratee(get_handle(flip(chain_start_bound), graph), distance_traversed);
+                distance_traversed += minimum_length(chain_start_bound);
+                distance_to_traverse -= minimum_length(chain_start_bound);
+                if (to_duplicate != nullptr) {
+                    to_duplicate->emplace_back(flip(chain_start_bound), minimum_length(chain_start_bound));
+                }
+
+                //Flip the chain so it's pointing backwards
+                next = flip(next_net);
+#ifdef debug_distance_paths
+                cerr << "back to traversing snarl " << net_handle_as_string(snarl_handle) << " after looping through chain " << net_handle_as_string(next_net) << " now start from " << net_handle_as_string(next) << endl;
+#endif
+                started = false; //Just in case this is the thing we want to reach that we just looped on and now we need to reach it from the other side
+
+                return false;//Return false to stop iterating
+            } else {
+#ifdef debug_distance_paths
+                cerr << "\tThis is nothing interesting so continue looking" << endl;
+                cerr << "\t\tdistance across is " << distance_in_parent(snarl_handle, next_net, flip(end)) << " + " <<  minimum_length(next_net)<< endl;
+                cerr << "\t\tdistance to loop is " << distance_in_parent(snarl_handle, flip(next_net), flip(end)) << " + " <<  
+                             distance_in_parent(next_net, get_bound(next_net, ends_at(next_net) == START, true),
+                                                          get_bound(next_net, ends_at(next_net) == START, true)) << " + " << 
+                            minimum_length(get_bound(next_net, ends_at(next_net) == START, true)) << endl;
+#endif
+                return true;//Return true to continue iterating
+            }
+        });
+    }
+#ifdef debug_distance_paths
+    cerr << "Finished traversing " << net_handle_as_string(snarl_handle) << " we were looking for distance " << target_distance << " starting at " << starting_distance << " and now we've traversed " << distance_traversed << endl;
+    assert(target_distance == (distance_traversed - starting_distance));
+#endif
+}
+void SnarlDistanceIndex::for_each_handle_in_shortest_path_in_chain(const net_handle_t& chain_handle, net_handle_t start, net_handle_t end,
+                                      size_t distance_to_traverse, size_t& distance_traversed, const HandleGraph* graph,
+                                      const std::function<bool(const handlegraph::handle_t, size_t)>& iteratee,
+                                      vector<pair<net_handle_t, size_t>>* to_duplicate_recursed) const {
+#ifdef debug_distance_paths
+    size_t target_distance = distance_to_traverse;
+    size_t starting_distance = distance_traversed;
+    cerr << "Find shortest path in " << net_handle_as_string(chain_handle) << " from " << net_handle_as_string(start) << " to " << net_handle_as_string(end) << " with distance " << distance_to_traverse << endl;
+    cerr << "\tactual distance is " << distance_in_parent(chain_handle, start, flip(end))<< endl;
+    assert(distance_in_parent(chain_handle, start, flip(end)) == distance_to_traverse);
+    assert(canonical(chain_handle) == canonical(get_parent(start)));
+    assert(canonical(chain_handle) == canonical(get_parent(end)));
+
+#endif
+
+
+    /* Walk through the chain and run iteratee for every node, recurse on every snarl
+     * The shortest path may loop up to twice in the chain - (eg if it goes from node 2 fd to node 1 fd) 
+     * In this case, keep track of everything that will be duplicated, and run through this list backwards,
+     * reversing the orientations of nodes when going in the opposite direction 
+     * There are three cases of the path being reversed:
+     *   1) If the two children are oriented towards each other ( -1-> <-2- ) 
+     *      The traversal goes forward from 1, reaches 2 going forward, reaches a loop, then duplicates everything between 2 and the loop
+     *   2) If the two children are oriented away from each other ( <-2-  -1->  ) 
+     *      The traversal goes forward from 1, finds a loop and duplicates everything until 1, then continues backwards until it reaches 2 
+     *   3) If the first node comes after the second, both oriented in the same direction ( -2->   -1-> ) 
+     *      The traversal must loop twice: traverse forward from 1, loop, duplicate everything from 1 to loop, traverse back to 2, 
+     *      traverse until loop, duplicate everything between 2 and loop
+     *
+     * Since I made this recursive and there can be two to_duplicates, only fill in one of them at a time. Prioritize the to_duplicate
+     * just created, and when to_duplicate gets duplicated, add the forward and reverse to to_duplicate_recursed
+    */
+    ChainRecord chain_record (chain_handle, &snarl_tree_records);
+
+    //Are we going left in the chain?
+    bool go_left_start = (ends_at(start) != START) == is_reversed_in_parent(start);
+    bool go_left_end = (ends_at(end) != START) == is_reversed_in_parent(end);
+    bool go_left = go_left_start;
+
+    // We need to keep track of if we're looking for a loop immediately or after traversing a specific node, and the start and end
+    // of the portion of the path that needs to be duplicated
+    // If loop_asap is true, then keep adding everything found (flipped) to to_duplicate. At each snarl, only go forwards if it can't loop
+    //   When the loop is found, call iteratee on everything in to_duplicate, in reverse order and continue from
+    //   the first thing in the list
+    // If loop_asap is false and loop_eventually is true (loop_after_this must not be the root), then traverse normally but check each
+    //   child to see if it's loop_after_this. When loop_after_this is found, loop_after this becomes root, loop_asap becomes true, and
+    //   we start looking for a loop
+    //
+    // to_duplicate will start with the net_handle_t that we start duplicating on (loop_after_this if we didn't start immediately)
+    // Everything but the first will be a node and gets copied and re-traversed, the first one becomes start in the next iteration  
+    // If the first thing is a node, then it goes in to_duplicate twice
+    bool loop_asap = false; 
+    vector<pair<net_handle_t, size_t>> to_duplicate;
+    bool loop_eventually = false;
+    net_handle_t loop_after_this = get_root();
+    size_t last_loop = is_node(start) ? (go_left ? get_reverse_loop_value(start) : get_forward_loop_value(start))
+                                      : std::numeric_limits<size_t>::max();
+
+    bool ordered = is_ordered_in_chain(start, end);
+#ifdef debug_distance_paths
+    cerr << "Children are " << (ordered ? " ordered in chain " : " not ordered in chain") << " node 1 is going " 
+         << (go_left_start ? " reverse " : " forward ") << " and node 2 is going " << (go_left_end ? " reverse " : " forward")
+         << " in the chain" << endl;
+#endif
+    if ((ordered && !go_left_start && go_left_end) || 
+        (!ordered && go_left_start && !go_left_end)) {
+#ifdef debug_distance_paths
+        cerr << " Children are oriented towards each other so loop at " << net_handle_as_string(flip(end)) << endl;
+#endif
+        //Case 1 - oriented towards each other- go forwards from 1, pass 2, and then loop
+        if (flip(end) == start) {
+#ifdef debug_distance_paths
+            cerr << "\tbut this is really the start so just loop immediately" << endl;
+#endif
+            loop_asap = true;
+
+        } else {
+            loop_eventually = true;
+            loop_after_this = flip(end);
+        }
+    } else if ((ordered && go_left_start && !go_left_end) ||
+               (!ordered && !go_left_start && go_left_end)) {
+#ifdef debug_distance_paths
+        cerr << " Children are oriented away from each other so loop at asap" << endl;
+#endif
+        //Case 2 - oriented away from each other - go forwards from 1, try to loop immediately to find 2
+        loop_asap = true;
+
+    } else if ((ordered && go_left_start && go_left_end) ||
+               (!ordered && !go_left_start && !go_left_end) ||
+               start == end) {
+        //Case 3 - loop twice - go forwards from 1 and loop immediately, then pass 2 and loop
+#ifdef debug_distance_paths
+        cerr << " Children are oriented backwards so loop at asap and then at " << net_handle_as_string(flip(end)) << endl;
+#endif
+        loop_asap = true;
+        loop_eventually = true;
+        loop_after_this = flip(end);
+    }
+
+    //If the start and end are the same, need to make sure that we actually start traversing
+    bool started = start != end;
+    
+    while (start != end || !started) {
+#ifdef debug_distance_paths
+        cerr << "at chain child " << net_handle_as_string(start) << (go_left ? " going left" : " going right") << endl;
+        cerr << "\t traversed " << distance_traversed << ", reach end (" << net_handle_as_string(end) << " in " << distance_to_traverse << endl;
+        cerr << "\t distance to end " << net_handle_as_string(end) << distance_in_parent(chain_handle, start, flip(end)) << endl;
+        if (loop_asap) {
+            cerr << "\tTrying to loop" << endl;
+        }
+        assert(start != get_bound(chain_handle, false, false));
+        assert(start != get_bound(chain_handle, true, false));
+        assert(distance_to_traverse == distance_in_parent(chain_handle, start, flip(end)));
+#endif
+        net_handle_t next = chain_record.get_next_child(start, go_left); 
+#ifdef debug_distance_paths
+        cerr << "\treached next node " << net_handle_as_string(next) << endl;
+#endif
+        bool need_to_flip = go_left;
+        if (ends_at(next) == START) {
+            need_to_flip = !need_to_flip;
+        }
+        if (is_reversed_in_parent(next)) {
+            need_to_flip = !need_to_flip;
+        }
+
+        if (need_to_flip) {
+            next = flip(next);
+#ifdef debug_distance_paths
+            cerr << "Flipping next node "  << endl;
+#endif
+        }
+        if (next == end && started) {
+#ifdef debug_distance_paths
+            cerr << "\tthis is the end so we're done" << endl;
+#endif
+            start = next;
+            break;
+        } else if (is_node(next)) {
+            //If this is a node, then run iteratee on it 
+#ifdef debug_distance_paths
+            cerr << "\titerate on node " << net_handle_as_string(next) << " with length " << minimum_length(next) << endl;
+#endif
+            iteratee(get_handle(next, graph), distance_traversed);
+            size_t length = minimum_length(next);
+            distance_traversed += length;
+            distance_to_traverse -= length;
+
+            last_loop = go_left ? get_reverse_loop_value(next) : get_forward_loop_value(next);
+            if (loop_asap) {
+                //If we want to loop as soon as possible, remember the distance to loop from this node (in the next snarl)
+#ifdef debug_distance_paths
+                cerr << "We want to loop, the next loop distance after " << net_handle_as_string(next) << " will be " << last_loop << endl;
+#endif
+                if (last_loop == 0) {
+                    //If we want to loop on this node
+#ifdef debug_distance_paths
+                    cerr << "Loop on this node" << endl;
+#endif
+
+                    //Flip the node
+                    next = flip(next);
+
+                    //Before we loop, copy everything we've saved so far to the higher recursion to_duplicate
+                    if (to_duplicate_recursed != nullptr) {
+                        for (size_t i = 1 ; i < to_duplicate.size() ; i++) {
+                            to_duplicate_recursed->emplace_back(to_duplicate[i]);
+                        }
+                    }
+
+                    //Iteratee() on the flipped node
+                    iteratee(get_handle(next, graph), distance_traversed);
+                    distance_traversed += length;
+                    distance_to_traverse -= length;
+
+#ifdef debug_distance_paths
+                cerr << "Finished looping on the node, now go back and repeat the duplicated portion (" << to_duplicate.size() << " things to duplicate)" << endl;
+                for (auto x : to_duplicate) {
+                    cerr << "\t" << net_handle_as_string(x.first) << ": " << x.second << endl;
+                }
+#endif
+
+                    //Now backtrack to when we started tracking the duplicated part
+                    //Skip the first thing in to_duplicate, which might be in to_duplicate twice
+                    if (to_duplicate.size() > 1) {
+                        for (int i = to_duplicate.size() - 1 ; i >= 1 ; i--) {
+                            iteratee(get_handle(to_duplicate[i].first, graph), distance_traversed);
+                            distance_traversed += to_duplicate[i].second;
+                            distance_to_traverse -= to_duplicate[i].second;
+                            if (to_duplicate_recursed != nullptr) {
+                                to_duplicate_recursed->emplace_back(flip(to_duplicate[i].first), to_duplicate[i].second);
+                            }
+                        }
+                    }
+
+                    //And continue traversing from the first thing in to_duplicate (or the current node)
+                    next = to_duplicate.size() == 0 ? next : to_duplicate[0].first;
+                    to_duplicate.clear();
+                    loop_asap = false;
+                    go_left = !go_left;
+#ifdef debug_distance_paths
+                    cerr << "WE looped and now the new current node is " << net_handle_as_string(next) << 
+                            " and we're going " << (go_left ? "left " : "right ") << "in the chain" << endl;
+#endif
+                    
+                } else {
+                    if (to_duplicate.size() == 0) 
+                        to_duplicate.emplace_back(flip(next), 0);{
+                    }
+                    to_duplicate.emplace_back(flip(next), length);
+                }
+            } else if (to_duplicate_recursed != nullptr) {
+                to_duplicate_recursed->emplace_back(flip(next), length);
+            }
+        } else {
+            net_handle_t start_in = go_left ? get_bound(next, true, true) : get_bound(next, false, true);
+            //If this is a snarl and it must be traversed, then recurse on the snarl
+            //If the chain is being traversed backwards, traverse the snarl end->start, otherwise start->end
+            if (loop_asap && last_loop != std::numeric_limits<size_t>::max() &&
+                last_loop == distance_in_parent(next, start_in,start_in, graph, std::numeric_limits<size_t>::max())) {
+#ifdef debug_distance_paths
+                cerr << "This snarl is the best place to loop so loop and then duplicate the last " << to_duplicate.size() << " traversals" << endl;
+#endif
+                //If we're trying to loop and the shortest loop is in this snarl, then traverse the snarl in a loop 
+                // and go through to_duplicate in reverse
+                // If we're also tracking to_duplicate_recursed, then we haven't added anything since we started adding to 
+                // to_duplicate, so first add everything there, then add everything duplicated as well
+                if (to_duplicate_recursed != nullptr) {
+                    for (size_t i = 1 ; i < to_duplicate.size() ; i++) {
+                        to_duplicate_recursed->emplace_back(to_duplicate[i]);
+                    }
+                }
+                for_each_handle_in_shortest_path_in_snarl(next, start_in, flip(start_in),
+                                                      last_loop, distance_traversed, graph, iteratee, to_duplicate_recursed);
+                distance_to_traverse -= last_loop;
+
+#ifdef debug_distance_paths
+                cerr << "Finished looping in the snarl, now go back and repeat the duplicated portion (" << to_duplicate.size() << " things to duplicate)" << endl;
+                for (auto x : to_duplicate) {
+                    cerr << "\t" << net_handle_as_string(x.first) << ": " << x.second << endl;
+                }
+#endif
+                //Now backtrack to when we started tracking the duplicated part
+                if (to_duplicate.size() > 1) {
+                    for (int i = to_duplicate.size() - 1 ; i >= 1 ; i--) {
+                        iteratee(get_handle(to_duplicate[i].first, graph), distance_traversed);
+                        distance_traversed += to_duplicate[i].second;
+                        distance_to_traverse -= to_duplicate[i].second;
+                        if (to_duplicate_recursed != nullptr) {
+                            to_duplicate_recursed->emplace_back(flip(to_duplicate[i].first), to_duplicate[i].second);
+                        }
+                    }
+                }
+
+                //And continue traversing from the first thing in to_duplicate
+                next = to_duplicate.size() == 0 ? flip(next) : to_duplicate[0].first;
+                to_duplicate.clear();
+                loop_asap = false;
+                go_left = !go_left;
+#ifdef debug_distance_paths
+                cerr << "Finished looping and duplicating, now continue from " << net_handle_as_string(next) << endl;
+#endif
+            } else if (minimum_length(next) != 0) {
+                //Otherwise traverse across snarl (if there is path straight across)
+#ifdef debug_distance_paths
+                if (loop_asap) {
+                    cerr << "this snarl didn't have the loop distance " << last_loop << " so traverse it forward" << endl;
+                }
+#endif
+
+                if (loop_asap && to_duplicate.size() == 0) 
+                    //If we're keeping track of what to duplicate and this is the first thing, then remember that when we finish
+                    //duplicating, we go backwards from here
+                    to_duplicate.emplace_back(flip(next), 0);{
+                }
+                for_each_handle_in_shortest_path_in_snarl(next, start_in,
+                                                            go_left ? get_bound(next, false, false) : get_bound(next, true, false),
+                                                      minimum_length(next), distance_traversed, graph, iteratee,
+                                                      loop_asap ? &to_duplicate : to_duplicate_recursed);
+                distance_to_traverse -= minimum_length(next);
+            }
+            last_loop = std::numeric_limits<size_t>::max();
+        }
+        if (!loop_asap && loop_eventually && next == loop_after_this) {
+            //If we want to find a loop after the current node/snarl
+#ifdef debug_distance_paths
+            cerr << "Found the next thing we want to loop after, so now look for a loop asap" << endl;
+#endif
+            loop_eventually = false;
+            loop_asap = true;
+            loop_after_this = get_root();
+        }
+        start = next;
+        started = true;
+    }
+#ifdef debug_distance_paths
+    cerr << "Finished traversing " << net_handle_as_string( chain_handle) << " we were looking for distance " << target_distance << " starting at " << starting_distance << " and now we've traversed " << distance_traversed << endl;
+    assert(target_distance == (distance_traversed - starting_distance));
+#endif
+}
+
 
 size_t SnarlDistanceIndex::node_length(const net_handle_t& net) const {
     if (is_node(net)) {
@@ -1369,7 +2896,6 @@ size_t SnarlDistanceIndex::node_length(const net_handle_t& net) const {
 }
 
 
-//TODO: This is kind of redundant with node_length 
 size_t SnarlDistanceIndex::minimum_length(const net_handle_t& net) const {
     if (SnarlTreeRecord(net, &snarl_tree_records).get_record_type() == TRIVIAL_SNARL || 
         SnarlTreeRecord(net, &snarl_tree_records).get_record_type() == DISTANCED_TRIVIAL_SNARL) {
@@ -1415,7 +2941,7 @@ size_t SnarlDistanceIndex::maximum_length(const net_handle_t& net) const {
     }
 }
 nid_t SnarlDistanceIndex::node_id(const net_handle_t& net) const {
-    if (is_node(net)) {
+    if (is_node(net) || is_trivial_chain(net)) {
         if (get_record_type(snarl_tree_records->at(get_record_offset(net))) == NODE 
             || get_record_type(snarl_tree_records->at(get_record_offset(net))) == DISTANCED_NODE) {
             return NodeRecord(net, &snarl_tree_records).get_node_id();
@@ -1454,12 +2980,12 @@ bool SnarlDistanceIndex::is_reversed_in_parent(const net_handle_t& net) const {
         return record.get_is_reversed_in_parent();
     }
 }
-net_handle_t SnarlDistanceIndex::get_node_net_handle(const nid_t id) const {
+net_handle_t SnarlDistanceIndex::get_node_net_handle(const nid_t id, bool rev) const {
     RootRecord root_record (get_root(), &snarl_tree_records);
     size_t node_pointer_offset = get_node_pointer_offset(id, root_record.get_min_node_id(), root_record.get_connected_component_count());
     size_t record_offset = snarl_tree_records->at(node_pointer_offset);
     size_t node_record_offset = snarl_tree_records->at(node_pointer_offset+1);
-    return get_net_handle_from_values(record_offset, START_END, NODE_HANDLE, node_record_offset); 
+    return get_net_handle_from_values(record_offset, rev ? END_START : START_END, NODE_HANDLE, node_record_offset); 
 }
 
 size_t SnarlDistanceIndex::get_max_tree_depth() const {
@@ -1533,6 +3059,27 @@ bool SnarlDistanceIndex::has_connectivity(const net_handle_t& net, endpoint_t st
     SnarlTreeRecord record(net, &snarl_tree_records);
     return record.has_connectivity(start, end);
 }
+
+SnarlDistanceIndex::SnarlTreeRecord::SnarlTreeRecord (size_t pointer, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records){
+    record_offset = pointer;
+    records = tree_records;
+ 
+ #ifdef debug_distance_indexing
+    record_t type = get_record_type();
+    assert(type >= 1 && type <= 17 );
+ #endif
+}
+
+SnarlDistanceIndex::SnarlTreeRecord::SnarlTreeRecord (const net_handle_t& net, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records){
+    record_offset = get_record_offset(net);
+    records = tree_records;
+ #ifdef debug_distance_indexing
+    record_t type = get_record_type();
+    assert(type >= 1 && type <= 17 );
+ #endif
+}
+
+
 bool SnarlDistanceIndex::SnarlTreeRecord::has_connectivity(connectivity_t connectivity) const {
     if (connectivity == START_START) {
         return is_start_start_connected();
@@ -1604,7 +3151,6 @@ size_t SnarlDistanceIndex::get_chain_component(const net_handle_t net, bool get_
 }
 
 
-
 size_t SnarlDistanceIndex::SnarlTreeRecord::get_min_length() const {
     record_t type = get_record_type();
     size_t val;
@@ -1685,7 +3231,7 @@ bool SnarlDistanceIndex::SnarlTreeRecord::get_is_reversed_in_parent() const {
     } else if (type == SNARL || type == DISTANCED_SNARL || type == OVERSIZED_SNARL
             || type == ROOT_SNARL || type == DISTANCED_ROOT_SNARL 
             || type == SIMPLE_SNARL || type == DISTANCED_SIMPLE_SNARL)  {
-        return false;//TODO: I'm pretty sure a snarl is always pointing forwards in the chain
+        return false;
     } else if (type == CHAIN || type == DISTANCED_CHAIN || type == MULTICOMPONENT_CHAIN)  {
         return (*records)->at(record_offset + CHAIN_RANK_OFFSET) & 1;
     } else {
@@ -1696,10 +3242,8 @@ bool SnarlDistanceIndex::SnarlTreeRecord::get_is_reversed_in_parent() const {
 handlegraph::nid_t SnarlDistanceIndex::SnarlTreeRecord::get_start_id() const {
     record_t type = get_record_type();
     if (type == ROOT) {
-        //TODO: Also not totally sure what this should do
         throw runtime_error("error: trying to get the start node of the root");
     } else if (type == NODE || type == DISTANCED_NODE) {
-        //TODO: I'm not sure if I want to allow this
         //cerr << "warning: Looking for the start of a node" << endl;
         return (*records)->at(record_offset + NODE_ID_OFFSET);
     } else if (type == TRIVIAL_SNARL || type == DISTANCED_TRIVIAL_SNARL) {
@@ -1722,10 +3266,8 @@ handlegraph::nid_t SnarlDistanceIndex::SnarlTreeRecord::get_start_id() const {
 bool SnarlDistanceIndex::SnarlTreeRecord::get_start_orientation() const {
     record_t type = get_record_type();
     if (type == ROOT) {
-        //TODO: Also not totally sure what this should do
         throw runtime_error("error: trying to get the start node of the root");
     } else if (type == NODE || type == DISTANCED_NODE || type == TRIVIAL_SNARL || type == DISTANCED_TRIVIAL_SNARL) {
-        //TODO: I'm not sure if I want to allow this
         //cerr << "warning: Looking for the start of a node" << endl;
         return false;
     } else if (type == SNARL || type == DISTANCED_SNARL || type == OVERSIZED_SNARL
@@ -1747,12 +3289,9 @@ bool SnarlDistanceIndex::SnarlTreeRecord::get_start_orientation() const {
 handlegraph::nid_t SnarlDistanceIndex::SnarlTreeRecord::get_end_id() const {
     record_t type = get_record_type();
     if (type == ROOT) {
-        //TODO: Also not totally sure what this should do
         throw runtime_error("error: trying to get the end node of the root");
     } else if (type == NODE || type == DISTANCED_NODE ) {
-        //TODO: I'm not sure if I want to allow this
         //cerr << "warning: Looking for the end of a node" << endl;
-        //TODO: Put this in its own function? Also double check for off by ones
         //Offset of the start of the node vector
         return (*records)->at(record_offset + NODE_ID_OFFSET);
     } else if (type == TRIVIAL_SNARL || type == DISTANCED_TRIVIAL_SNARL) {
@@ -1777,12 +3316,9 @@ handlegraph::nid_t SnarlDistanceIndex::SnarlTreeRecord::get_end_id() const {
 handlegraph::nid_t SnarlDistanceIndex::SnarlTreeRecord::get_end_orientation() const {
     record_t type = get_record_type();
     if (type == ROOT) {
-        //TODO: Also not totally sure what this should do
         throw runtime_error("error: trying to get the end node of the root");
     } else if (type == NODE || type == DISTANCED_NODE || type == TRIVIAL_SNARL || type == DISTANCED_TRIVIAL_SNARL) {
-        //TODO: I'm not sure if I want to allow this
         //cerr << "warning: Looking for the end of a node" << endl;
-        //TODO: Put this in its own function? Also double check for off by ones
         //Offset of the start of the node vector
         return false;
     } else if (type == SNARL || type == DISTANCED_SNARL || type == OVERSIZED_SNARL
@@ -1802,16 +3338,6 @@ handlegraph::nid_t SnarlDistanceIndex::SnarlTreeRecord::get_end_orientation() co
     }
 }
 
-size_t SnarlDistanceIndex::SnarlTreeRecord::get_offset_from_id (const handlegraph::nid_t id) const {
-
-    //Get the pointer to the pointer to the node record
-    size_t offset = SnarlDistanceIndex::get_node_pointer_offset(id, 
-            (*records)->at(MIN_NODE_ID_OFFSET),
-            (*records)->at(COMPONENT_COUNT_OFFSET));
-    
-    return (*records)->at(offset);
-
-}
 
 
 bool SnarlDistanceIndex::SnarlTreeRecord::has_connectivity(endpoint_t start, endpoint_t end){
@@ -1851,77 +3377,110 @@ size_t SnarlDistanceIndex::SnarlTreeRecord::get_parent_record_offset() const {
     }
 };
 
-SnarlDistanceIndex::record_t SnarlDistanceIndex::SnarlTreeRecordConstructor::get_record_type() const {
+SnarlDistanceIndex::SnarlTreeRecordWriter::SnarlTreeRecordWriter (size_t pointer, bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records){
+    record_offset = pointer;
+    records = tree_records;
+ 
+#ifdef debug_distance_indexing
+    record_t type = get_record_type();
+    assert(type == ROOT || type == NODE || type == DISTANCED_NODE ||
+            type == SIMPLE_SNARL || type == DISTANCED_SIMPLE_SNARL ||
+            type == TRIVIAL_SNARL || type == DISTANCED_TRIVIAL_SNARL ||
+            type == SNARL || type == DISTANCED_SNARL || type == OVERSIZED_SNARL ||
+            type == ROOT_SNARL || type == DISTANCED_ROOT_SNARL || type == CHAIN ||
+            type == DISTANCED_CHAIN || type == MULTICOMPONENT_CHAIN);
+#endif
+}
+
+SnarlDistanceIndex::SnarlTreeRecordWriter::SnarlTreeRecordWriter (const net_handle_t& net, 
+                                                          bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records){
+    record_offset = get_record_offset(net);
+    records = tree_records;
+#ifdef debug_distance_indexing
+    record_t type = get_record_type();
+    assert(type == ROOT || type == NODE || type == DISTANCED_NODE ||  
+            type == SIMPLE_SNARL || type == DISTANCED_SIMPLE_SNARL || 
+            type == TRIVIAL_SNARL || type == DISTANCED_TRIVIAL_SNARL || 
+            type == SNARL || type == DISTANCED_SNARL || type == OVERSIZED_SNARL || 
+            type == ROOT_SNARL || type == DISTANCED_ROOT_SNARL || type == CHAIN ||
+            type == DISTANCED_CHAIN || type == MULTICOMPONENT_CHAIN);
+#endif
+}
+
+
+
+
+SnarlDistanceIndex::record_t SnarlDistanceIndex::SnarlTreeRecordWriter::get_record_type() const {
     return static_cast<record_t>((*records)->at(record_offset) >> 9);
 }
-void SnarlDistanceIndex::SnarlTreeRecordConstructor::set_start_start_connected() {
+void SnarlDistanceIndex::SnarlTreeRecordWriter::set_start_start_connected() {
 #ifdef debug_distance_indexing
     cerr << record_offset << " set start_start_connected" << endl;
 #endif    
 
     (*records)->at(record_offset) = (*records)->at(record_offset) | 32;
 }
-void SnarlDistanceIndex::SnarlTreeRecordConstructor::set_start_end_connected() {
+void SnarlDistanceIndex::SnarlTreeRecordWriter::set_start_end_connected() {
 #ifdef debug_distance_indexing
     cerr << record_offset << " set start_end_connected" << endl;
 #endif
 
     (*records)->at(record_offset) = (*records)->at(record_offset) | 16;
 }
-void SnarlDistanceIndex::SnarlTreeRecordConstructor::set_start_tip_connected() {
+void SnarlDistanceIndex::SnarlTreeRecordWriter::set_start_tip_connected() {
 #ifdef debug_distance_indexing
     cerr << record_offset << " set start_tip_connected" << endl;
 #endif
 
     (*records)->at(record_offset) = (*records)->at(record_offset) | 8;
 }
-void SnarlDistanceIndex::SnarlTreeRecordConstructor::set_end_end_connected() {
+void SnarlDistanceIndex::SnarlTreeRecordWriter::set_end_end_connected() {
 #ifdef debug_distance_indexing
     cerr << record_offset << " set end_end_connected" << endl;
 #endif
 
     (*records)->at(record_offset) = (*records)->at(record_offset) | 4;
 }
-void SnarlDistanceIndex::SnarlTreeRecordConstructor::set_end_tip_connected() {
+void SnarlDistanceIndex::SnarlTreeRecordWriter::set_end_tip_connected() {
 #ifdef debug_distance_indexing
     cerr << record_offset << " set end_tip_connected" << endl;
 #endif
 
     (*records)->at(record_offset) = (*records)->at(record_offset) | 2;
 }
-void SnarlDistanceIndex::SnarlTreeRecordConstructor::set_tip_tip_connected() {
+void SnarlDistanceIndex::SnarlTreeRecordWriter::set_tip_tip_connected() {
 #ifdef debug_distance_indexing
     cerr << record_offset << " set tpi_tip_connected" << endl;
 #endif
 
     (*records)->at(record_offset) = (*records)->at(record_offset) | 1;
 }
-void SnarlDistanceIndex::SnarlTreeRecordConstructor::set_externally_start_end_connected() {
+void SnarlDistanceIndex::SnarlTreeRecordWriter::set_externally_start_end_connected() {
 #ifdef debug_distance_indexing
     cerr << record_offset << " set externally start_end connected" << endl;
 #endif
 
     (*records)->at(record_offset) = (*records)->at(record_offset) | 64;
 }
-void SnarlDistanceIndex::SnarlTreeRecordConstructor::set_externally_start_start_connected() const {
+void SnarlDistanceIndex::SnarlTreeRecordWriter::set_externally_start_start_connected() const {
 #ifdef debug_distance_indexing
     cerr << record_offset << " set externally start_start connected" << endl;
 #endif
     (*records)->at(record_offset) = (*records)->at(record_offset) | 128;
 }
-void SnarlDistanceIndex::SnarlTreeRecordConstructor::set_externally_end_end_connected() const {
+void SnarlDistanceIndex::SnarlTreeRecordWriter::set_externally_end_end_connected() const {
 #ifdef debug_distance_indexing
     cerr << record_offset << " set externally end_end connected" << endl;
 #endif
     (*records)->at(record_offset) = (*records)->at(record_offset) | 256;
 }
-void SnarlDistanceIndex::SnarlTreeRecordConstructor::set_record_type(record_t type) {
+void SnarlDistanceIndex::SnarlTreeRecordWriter::set_record_type(record_t type) {
     assert((*records)->at(record_offset) == 0);
     (*records)->at(record_offset) = ((static_cast<size_t>(type) << 9) | ((*records)->at(record_offset) & 511));
 }
 
 
-void SnarlDistanceIndex::SnarlTreeRecordConstructor::set_min_length(size_t length) {
+void SnarlDistanceIndex::SnarlTreeRecordWriter::set_min_length(size_t length) {
     record_t type = get_record_type();
     size_t offset;
     if (type == DISTANCED_NODE) {
@@ -1952,7 +3511,7 @@ void SnarlDistanceIndex::SnarlTreeRecordConstructor::set_min_length(size_t lengt
 
     (*records)->at(offset) = (length == std::numeric_limits<size_t>::max() ? 0 : length + 1);
 };
-void SnarlDistanceIndex::SnarlTreeRecordConstructor::set_max_length(size_t length) {
+void SnarlDistanceIndex::SnarlTreeRecordWriter::set_max_length(size_t length) {
     record_t type = get_record_type();
     size_t offset;
     if (type == DISTANCED_NODE) {
@@ -1984,7 +3543,7 @@ void SnarlDistanceIndex::SnarlTreeRecordConstructor::set_max_length(size_t lengt
     (*records)->at(offset) = (length == std::numeric_limits<size_t>::max() ? 0 : length + 1);
 };
 
-void SnarlDistanceIndex::SnarlTreeRecordConstructor::set_rank_in_parent(size_t rank) {
+void SnarlDistanceIndex::SnarlTreeRecordWriter::set_rank_in_parent(size_t rank) {
     record_t type = get_record_type();
     size_t offset;
     if (type == NODE || type == DISTANCED_NODE) {
@@ -2010,7 +3569,7 @@ void SnarlDistanceIndex::SnarlTreeRecordConstructor::set_rank_in_parent(size_t r
     bool rev = (*records)->at(offset) & 1;
     (*records)->at(offset) = (rank << 1) | rev;
 };
-void SnarlDistanceIndex::SnarlTreeRecordConstructor::set_is_reversed_in_parent(bool rev) {
+void SnarlDistanceIndex::SnarlTreeRecordWriter::set_is_reversed_in_parent(bool rev) {
     record_t type = get_record_type();
     size_t offset;
     if (type == SNARL || type == DISTANCED_SNARL || type == OVERSIZED_SNARL
@@ -2028,7 +3587,7 @@ void SnarlDistanceIndex::SnarlTreeRecordConstructor::set_is_reversed_in_parent(b
 
     (*records)->at(offset) =  (((*records)->at(offset)>>1)<<1) | rev;
 };
-void SnarlDistanceIndex::SnarlTreeRecordConstructor::set_parent_record_offset(size_t pointer){
+void SnarlDistanceIndex::SnarlTreeRecordWriter::set_parent_record_offset(size_t pointer){
     record_t type = get_record_type();
     size_t offset;
     if (type == NODE || type == DISTANCED_NODE) {
@@ -2059,7 +3618,7 @@ void SnarlDistanceIndex::SnarlTreeRecordConstructor::set_parent_record_offset(si
     (*records)->at(offset) = pointer;
 };
 //Rev is true if the node is traversed backwards to enter the snarl
-void SnarlDistanceIndex::SnarlTreeRecordConstructor::set_start_node(handlegraph::nid_t id, bool rev) {
+void SnarlDistanceIndex::SnarlTreeRecordWriter::set_start_node(handlegraph::nid_t id, bool rev) {
     record_t type = get_record_type();
     size_t offset;
     if (type == ROOT || type == NODE || type == DISTANCED_NODE || type == TRIVIAL_SNARL || type == DISTANCED_TRIVIAL_SNARL) {
@@ -2080,7 +3639,7 @@ void SnarlDistanceIndex::SnarlTreeRecordConstructor::set_start_node(handlegraph:
 
     (*records)->at(offset) = (id << 1) | rev;
 }
-void SnarlDistanceIndex::SnarlTreeRecordConstructor::set_end_node(handlegraph::nid_t id, bool rev) const {
+void SnarlDistanceIndex::SnarlTreeRecordWriter::set_end_node(handlegraph::nid_t id, bool rev) const {
     record_t type = get_record_type();
     size_t offset;
     if (type == ROOT || type == NODE || type == DISTANCED_NODE || type == TRIVIAL_SNARL || type == DISTANCED_TRIVIAL_SNARL) {
@@ -2102,6 +3661,23 @@ void SnarlDistanceIndex::SnarlTreeRecordConstructor::set_end_node(handlegraph::n
     (*records)->at(offset) = (id << 1) | rev;
 }
 
+SnarlDistanceIndex::RootRecord::RootRecord (size_t pointer, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records){
+    record_offset = pointer;
+    records = tree_records;
+#ifdef debug_distance_indexing
+    assert(get_record_type() == ROOT);
+#endif
+}
+
+
+SnarlDistanceIndex::RootRecord::RootRecord (net_handle_t net, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records){
+    record_offset = get_record_offset(net);
+    records = tree_records;
+#ifdef debug_distance_indexing
+    assert(get_record_type() == ROOT);
+#endif
+}
+
 
 
 bool SnarlDistanceIndex::RootRecord::for_each_child(const std::function<bool(const handlegraph::net_handle_t&)>& iteratee) const {
@@ -2136,7 +3712,36 @@ bool SnarlDistanceIndex::RootRecord::for_each_child(const std::function<bool(con
     return true;
 }
 
-void SnarlDistanceIndex::RootRecordConstructor::set_connected_component_count(size_t connected_component_count) {
+SnarlDistanceIndex::RootRecordWriter::RootRecordWriter (size_t pointer, size_t connected_component_count, size_t node_count, 
+        size_t max_tree_depth, handlegraph::nid_t min_node_id, bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* records){
+
+    record_offset = pointer;
+    records = records;
+    SnarlTreeRecordWriter::record_offset = pointer;
+    SnarlTreeRecordWriter::records = records;
+    RootRecord::record_offset = pointer;
+    RootRecord::records = records;
+    //Allocate memory for the root vector and for all of the nodes
+#ifdef debug_distance_indexing
+
+    //The root record will always start at 0
+    assert(pointer == 0);
+    cerr << " Resizing array to add root: length " << (*records)->size() << " -> "
+         << (*records)->size() + ROOT_RECORD_SIZE + connected_component_count + (node_count*2) << endl;
+#endif
+    (*records)->resize((*records)->size() + ROOT_RECORD_SIZE + connected_component_count + (node_count*2));
+    set_record_type(ROOT);
+    set_min_node_id(min_node_id);
+    set_node_count(node_count);
+    set_max_tree_depth(max_tree_depth);
+    set_connected_component_count(connected_component_count);
+#ifdef count_allocations
+    cerr << "new_root\t" <<  (ROOT_RECORD_SIZE + connected_component_count + (node_count*2)) << "\t" << (*records)->siz     e() << endl;
+#endif
+}
+
+
+void SnarlDistanceIndex::RootRecordWriter::set_connected_component_count(size_t connected_component_count) {
 #ifdef debug_distance_indexing
     cerr << record_offset+COMPONENT_COUNT_OFFSET << " set connected component to be " << connected_component_count << endl;
     assert((*records)->at(record_offset+COMPONENT_COUNT_OFFSET) == 0);
@@ -2144,7 +3749,7 @@ void SnarlDistanceIndex::RootRecordConstructor::set_connected_component_count(si
 
     (*records)->at(record_offset+COMPONENT_COUNT_OFFSET)=connected_component_count;
 }
-void SnarlDistanceIndex::RootRecordConstructor::set_node_count(size_t node_count) {
+void SnarlDistanceIndex::RootRecordWriter::set_node_count(size_t node_count) {
 #ifdef debug_distance_indexing
     cerr << record_offset+NODE_COUNT_OFFSET << " set node count to be " << node_count << endl;
     assert((*records)->at(record_offset+NODE_COUNT_OFFSET) == 0);
@@ -2152,7 +3757,7 @@ void SnarlDistanceIndex::RootRecordConstructor::set_node_count(size_t node_count
 
     (*records)->at(record_offset+NODE_COUNT_OFFSET)=node_count;
 }
-void SnarlDistanceIndex::RootRecordConstructor::set_max_tree_depth(size_t tree_depth) {
+void SnarlDistanceIndex::RootRecordWriter::set_max_tree_depth(size_t tree_depth) {
 #ifdef debug_distance_indexing
     cerr << record_offset+MAX_TREE_DEPTH_OFFSET << " set max tree depth to be " << tree_depth << endl;
     assert((*records)->at(record_offset+MAX_TREE_DEPTH_OFFSET) == 0);
@@ -2160,7 +3765,7 @@ void SnarlDistanceIndex::RootRecordConstructor::set_max_tree_depth(size_t tree_d
 
     (*records)->at(record_offset+MAX_TREE_DEPTH_OFFSET)=tree_depth;
 }
-void SnarlDistanceIndex::RootRecordConstructor::set_min_node_id(handlegraph::nid_t node_id) {
+void SnarlDistanceIndex::RootRecordWriter::set_min_node_id(handlegraph::nid_t node_id) {
 #ifdef debug_distance_indexing
     cerr << record_offset+MIN_NODE_ID_OFFSET << " set min node id to be " << node_id << endl;
     assert((*records)->at(record_offset+MIN_NODE_ID_OFFSET) == 0);
@@ -2168,7 +3773,7 @@ void SnarlDistanceIndex::RootRecordConstructor::set_min_node_id(handlegraph::nid
 
     (*records)->at(record_offset+MIN_NODE_ID_OFFSET)=node_id;
 }
-void SnarlDistanceIndex::RootRecordConstructor::add_component(size_t index, size_t offset) {
+void SnarlDistanceIndex::RootRecordWriter::add_component(size_t index, size_t offset) {
 #ifdef debug_distance_indexing
     cerr << record_offset+ROOT_RECORD_SIZE+index << " set new component " << offset << endl;
     cerr << "Old value " << (*records)->at(record_offset+ROOT_RECORD_SIZE+index) << endl;
@@ -2180,25 +3785,38 @@ void SnarlDistanceIndex::RootRecordConstructor::add_component(size_t index, size
 
 }
 
+SnarlDistanceIndex::SnarlRecord::SnarlRecord (size_t pointer, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records){
+    record_offset = pointer;
+    records = tree_records;
+#ifdef debug_distance_indexing
+    record_t type = get_record_type();
+    assert(type == SNARL || type == DISTANCED_SNARL || type == OVERSIZED_SNARL || type == ROOT_SNARL
+        || type == ROOT_SNARL || type == DISTANCED_ROOT_SNARL);
+#endif
+}
+
+SnarlDistanceIndex::SnarlRecord::SnarlRecord (net_handle_t net, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records){
+    record_offset = get_record_offset(net);
+    records = tree_records;
+#ifdef debug_distance_indexing
+    net_handle_record_t type = get_handle_type(net);
+    assert(type == SNARL_HANDLE || type == SENTINEL_HANDLE || type == ROOT_HANDLE);
+#endif
+}
+
 
 size_t SnarlDistanceIndex::SnarlRecord::distance_vector_size(record_t type, size_t node_count) {
     if (type == SNARL || type == ROOT_SNARL){
         //For a normal snarl, its just the record size and the pointers to children
         return 0;
-    } else if (type == DISTANCED_SNARL) {
-        //For a normal min distance snarl, record size and the pointers to children, and
-        //matrix of distances
-        size_t node_side_count = node_count * 2 + 2;
+    } else if (type == DISTANCED_SNARL || type == DISTANCED_ROOT_SNARL) {
+        //For a normal min distance snarl just the distances between internal node sides
+        size_t node_side_count = node_count * 2;
         size_t vector_size =  (((node_side_count+1)*node_side_count) / 2);
         return vector_size;
     } else if (type ==  OVERSIZED_SNARL){
-        //For a large min_distance snarl, record the side, pointers to children, and just
-        //the min distances from each node side to the two boundary nodes
-        size_t node_side_count = node_count * 2 + 2;
-        return  (node_side_count * 2);
-    } else if (type == DISTANCED_ROOT_SNARL) {
-        size_t node_side_count = node_count * 2;
-        return  (((node_side_count+1)*node_side_count) / 2);
+        //For a large min_distance snarl, all distances get stored in the children
+        return 0;
     } else {
         throw runtime_error ("error: this is not a snarl");
     }
@@ -2212,39 +3830,86 @@ size_t SnarlDistanceIndex::SnarlRecord::record_size() {
    return record_size(type, get_node_count());
 }
 
+size_t SnarlDistanceIndex::SnarlRecord::get_distance_start_start() const {
+    size_t stored_value = (*records)->at(record_offset + SNARL_DISTANCE_START_START_OFFSET);
+    return stored_value == 0 ? std::numeric_limits<size_t>::max() : stored_value - 1;
+}
+size_t SnarlDistanceIndex::SnarlRecord::get_distance_end_end() const {
+    size_t stored_value = (*records)->at(record_offset + SNARL_DISTANCE_END_END_OFFSET);
+    return stored_value == 0 ? std::numeric_limits<size_t>::max() : stored_value - 1;
+}
+
+SnarlDistanceIndex::SnarlRecordWriter::SnarlRecordWriter (size_t node_count, bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* records, record_t type){
+    //Constructor for making a new record, including allocating memory.
+    //Assumes that this is the latest record being made, so pointer will be the end of
+    //the array and we need to allocate extra memory past it
+
+    records = records;
+    record_offset = (*records)->size();
+    SnarlTreeRecordWriter::record_offset = (*records)->size();
+    SnarlTreeRecordWriter::records = records;
+    SnarlRecord::record_offset = (*records)->size();
+    SnarlRecord::records = records;
+    
+    size_t extra_size = record_size(type, node_count);
+#ifdef debug_distance_indexing
+    if (type == OVERSIZED_SNARL) {
+            cerr << "oversized" << endl;
+    }
+    cerr << " Resizing array to add snarl: length " << (*records)->size() << " -> "  << (*records)->size() + extra_size      << endl;
+#endif
+    (*records)->resize((*records)->size() + extra_size);
+    set_node_count(node_count);
+    set_record_type(type);
+
+#ifdef count_allocations
+    cerr << "new_snarl\t" << extra_size << "\t" << (*records)->size() << endl;
+#endif
+}
+
+SnarlDistanceIndex::SnarlRecordWriter::SnarlRecordWriter(bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* records, size_t pointer) {
+    //Make a constructor for a snarl record that has already been allocated.
+    //For adding children to an existing snarl record
+    record_offset = pointer;
+    records = records;
+    SnarlTreeRecordWriter::records = records;
+    SnarlTreeRecordWriter::record_offset = pointer;
+    SnarlRecord::records = records;
+    SnarlRecord::record_offset = pointer;
+}
+
+
+void SnarlDistanceIndex::SnarlRecordWriter::set_distance_start_start(size_t value) {
+    (*records)->at(record_offset + SNARL_DISTANCE_START_START_OFFSET) = (value == std::numeric_limits<size_t>::max() ? 0 : value + 1);
+}
+void SnarlDistanceIndex::SnarlRecordWriter::set_distance_end_end(size_t value) {
+    (*records)->at(record_offset + SNARL_DISTANCE_END_END_OFFSET) = (value == std::numeric_limits<size_t>::max() ? 0 : value + 1);
+}
+
 
 size_t SnarlDistanceIndex::SnarlRecord::get_distance_vector_offset(size_t rank1, bool right_side1, size_t rank2,
         bool right_side2, size_t node_count, record_t type) {
-
     //how many node sides in this snarl
-    size_t node_side_count = type == DISTANCED_ROOT_SNARL ? node_count * 2 : node_count * 2 + 2;
+    size_t node_side_count = node_count * 2;
+
+    if (type == DISTANCED_SNARL) {
+        //For distances snarls, the ranks 0 and 1 are for the start and end nodes. The distance
+        //matrix in the snarl record is only for distances between internal nodes, so 0 and 1 are
+        //never stored and we decrement the ranks by 2
+        rank1 -= 2;
+        rank2 -= 2;
+    }
 
     //make sure we're looking at the correct node side
-    //If this is the start or end node, then we don't adjust based on orientation
-    //because we only care about the inner sides. If this is a root snarl, then
-    //there is no start or end node and the ranks 0 and 1 are not special
-     if (type == DISTANCED_ROOT_SNARL) {
-        rank1 = rank1 * 2;
-        if (right_side1) {
-            rank1 += 1;
-        }
-     } else if (rank1 != 0 && rank1 != 1) {
-        rank1 = (rank1-1) * 2;
-        if (right_side1) {
-            rank1 += 1;
-        }
+    rank1 = rank1 * 2;
+    if (right_side1) {
+        rank1 += 1;
     }
-    if (type == DISTANCED_ROOT_SNARL) {
-        rank2 = rank2 * 2;
-        if (right_side2) {
-            rank2 += 1;
-        }
-    } else if (rank2 != 0 && rank2 != 1) {
-        rank2 = (rank2-1) * 2;
-        if (right_side2) {
-            rank2 += 1;
-        }
+    rank2 = rank2 * 2;
+    if (right_side2) {
+        rank2 += 1;
     }
+    
 
     //reverse order of ranks if necessary
     if (rank1 > rank2) {
@@ -2253,22 +3918,12 @@ size_t SnarlDistanceIndex::SnarlRecord::get_distance_vector_offset(size_t rank1,
         rank2 = tmp;
     }
 
-    if (type == SNARL || type == ROOT_SNARL) {
+    if (type == SNARL || type == ROOT_SNARL || type == OVERSIZED_SNARL) {
         throw runtime_error("error: trying to access distance in a distanceless snarl tree");
     } else if (type == DISTANCED_SNARL || type == DISTANCED_ROOT_SNARL) {
         //normal distance index
         size_t k = node_side_count-rank1;
         return (((node_side_count+1) * node_side_count)/2) - (((k+1)*k) / 2) + rank2 - rank1;
-    } else if (type ==  OVERSIZED_SNARL) {
-        //abbreviated distance index storing only the distance from each node side to the
-        //start and end
-        if (rank1 == 0) {
-            return rank2;
-        } else if (rank1 == 1) {
-            return node_side_count + rank2;
-        } else {
-            throw runtime_error("error: trying to access distance in an oversized snarl");
-        }
     } else {
         throw runtime_error("error: trying to distance from something that isn't a snarl");
     }
@@ -2297,13 +3952,17 @@ bool SnarlDistanceIndex::SnarlRecord::for_each_child(const std::function<bool(co
     return true;
 }
 
-void SnarlDistanceIndex::SnarlRecordConstructor::set_distance(size_t rank1, bool right_side1, size_t rank2, bool right_side2, size_t distance) {
+void SnarlDistanceIndex::SnarlRecordWriter::set_distance(size_t rank1, bool right_side1, size_t rank2, bool right_side2, size_t distance) {
 
 #ifdef debug_distance_indexing 
     //This distance hasn't been set yet (or it's equal to what we're setting)
     assert((get_distance(rank1, right_side1, rank2, right_side2) == std::numeric_limits<size_t>::max() ||
            get_distance(rank1, right_side1, rank2, right_side2) == distance));
 #endif
+    //Don't save internal distances for oversized snarls
+    if (get_record_type() == OVERSIZED_SNARL && !(rank1 == 0 || rank1 == 1 || rank2 == 0 || rank2 == 1)){
+        return;
+    }
 
     //Offset of this particular distance in the distance vector
     size_t distance_vector_offset = get_distance_vector_offset(rank1, right_side1, rank2, right_side2);
@@ -2317,7 +3976,7 @@ void SnarlDistanceIndex::SnarlRecordConstructor::set_distance(size_t rank1, bool
 
 size_t SnarlDistanceIndex::SnarlRecord::get_distance(size_t rank1, bool right_side1, size_t rank2, bool right_side2) const {
     if (get_record_type() == OVERSIZED_SNARL) {
-        assert(rank1 == 0 || rank1 == 1 || rank2 == 0 || rank2 == 1);
+        throw runtime_error("error: trying to distance from an oversized snarl");
     }
 
     //Offset of this particular distance in the distance vector
@@ -2333,10 +3992,10 @@ size_t SnarlDistanceIndex::SnarlRecord::get_node_count() const {
 }
 
 //Node count is the number of nodes in the snarl, not including boundary nodes
-void SnarlDistanceIndex::SnarlRecordConstructor::set_node_count(size_t node_count) {
+void SnarlDistanceIndex::SnarlRecordWriter::set_node_count(size_t node_count) {
 #ifdef debug_distance_indexing
     cerr << record_offset + SNARL_NODE_COUNT_OFFSET << " set snarl node count " << node_count << endl;
-    assert(node_count > 0);//TODO: Don't bother making a record for trivial snarls
+    assert(node_count > 0);
     assert((*records)->at(record_offset + SNARL_NODE_COUNT_OFFSET) == 0);
 #endif
 
@@ -2347,7 +4006,7 @@ size_t SnarlDistanceIndex::SnarlRecord::get_child_record_pointer() const {
     return (*records)->at(record_offset+SNARL_CHILD_RECORD_OFFSET) ;
 }
 
-void SnarlDistanceIndex::SnarlRecordConstructor::set_child_record_pointer(size_t pointer) {
+void SnarlDistanceIndex::SnarlRecordWriter::set_child_record_pointer(size_t pointer) {
 #ifdef debug_distance_indexing
     cerr << (*records)->at(record_offset+SNARL_CHILD_RECORD_OFFSET) << endl;
     assert((*records)->at(record_offset+SNARL_CHILD_RECORD_OFFSET) == 0);
@@ -2358,7 +4017,7 @@ void SnarlDistanceIndex::SnarlRecordConstructor::set_child_record_pointer(size_t
 
 //Add a reference to a child of this snarl. Assumes that the index is completed up
 //to here
-void SnarlDistanceIndex::SnarlRecordConstructor::add_child(size_t pointer){
+void SnarlDistanceIndex::SnarlRecordWriter::add_child(size_t pointer){
 #ifdef debug_distance_indexing
     cerr << (*records)->size() << " Adding child pointer to the end of the array " << endl;
 #endif
@@ -2372,6 +4031,29 @@ void SnarlDistanceIndex::SnarlRecordConstructor::add_child(size_t pointer){
 #endif
 }
 
+SnarlDistanceIndex::SimpleSnarlRecord::SimpleSnarlRecord (size_t pointer, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records, size_t node){
+    record_offset = pointer;
+    records = tree_records;
+    node_rank = node;
+#ifdef debug_distance_indexing
+    assert (node_rank >=2);
+    assert(get_record_type() == SIMPLE_SNARL || get_record_type() == DISTANCED_SIMPLE_SNARL);
+#endif
+}
+
+SnarlDistanceIndex::SimpleSnarlRecord::SimpleSnarlRecord (net_handle_t net, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records){
+    record_offset = get_record_offset(net);
+    records = tree_records;
+    node_rank = get_node_record_offset(net) == 1 ? std::numeric_limits<size_t>::max() : get_node_record_offset(net);
+    
+#ifdef debug_distance_indexing
+    assert (node_rank >=2);
+    assert(get_record_type() == SIMPLE_SNARL || get_record_type() == DISTANCED_SIMPLE_SNARL);
+#endif
+}
+
+
+
 size_t SnarlDistanceIndex::SimpleSnarlRecord::record_size() {
     
     return SIMPLE_SNARL_RECORD_SIZE + get_node_count()*2;
@@ -2380,7 +4062,48 @@ size_t SnarlDistanceIndex::SimpleSnarlRecord::get_node_count() const {
 
     return (*records)->at(record_offset + SIMPLE_SNARL_NODE_COUNT_AND_LENGTHS_OFFSET) >> 22;
 }
-void SnarlDistanceIndex::SimpleSnarlRecordConstructor::set_node_count(size_t node_count) {
+
+SnarlDistanceIndex::SimpleSnarlRecordWriter::SimpleSnarlRecordWriter (size_t node_count, bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* records, record_t type){
+
+    //Constructor for making a new record, including allocating memory.
+    //Assumes that this is the latest record being made, so pointer will be the end of
+    //the array and we need to allocate extra memory past it
+    records = records;
+    record_offset = (*records)->size();
+    SnarlTreeRecordWriter::record_offset = (*records)->size();
+    SnarlTreeRecordWriter::records = records;
+    SimpleSnarlRecord::record_offset = (*records)->size();
+    SimpleSnarlRecord::records = records;
+    
+#ifdef debug_distance_indexing
+    cerr << " Resizing array to add simple snarl: length " << (*records)->size() << " -> "  << (*records)->size() + SIM     PLE_SNARL_RECORD_SIZE + 2*node_count << endl;
+    cerr << "\t simple snarl has " << node_count << " nodes " << endl;
+#endif
+    (*records)->resize((*records)->size() + SIMPLE_SNARL_RECORD_SIZE + 2*node_count);
+    set_node_count(node_count);
+    set_record_type(type);
+    set_node_count(node_count);
+    set_start_end_connected();
+#ifdef count_allocations
+    cerr << "new_simple_snarl\t" << SIMPLE_SNARL_RECORD_SIZE << "\t" << (*records)->size() << endl;
+    cerr << "simple_snarl_nodes\t" << (node_count*2) << "\t" << (*records)->size() << endl;
+#endif
+}
+
+SnarlDistanceIndex::SimpleSnarlRecordWriter::SimpleSnarlRecordWriter(bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* records, size_t pointer) {
+    //Make a constructor for a snarl record that has already been allocated.
+    //For adding children to an existing snarl record
+    record_offset = pointer;
+    records = records;
+    SnarlTreeRecordWriter::record_offset = pointer;
+    SnarlTreeRecordWriter::records = records;
+    SimpleSnarlRecord::record_offset = pointer;
+    SimpleSnarlRecord::records = records;
+
+}
+
+
+void SnarlDistanceIndex::SimpleSnarlRecordWriter::set_node_count(size_t node_count) {
     size_t old_value = (*records)->at(record_offset + SIMPLE_SNARL_NODE_COUNT_AND_LENGTHS_OFFSET);
     size_t new_value = old_value | (node_count << 22);
     (*records)->at(record_offset + SIMPLE_SNARL_NODE_COUNT_AND_LENGTHS_OFFSET) = new_value;
@@ -2446,7 +4169,7 @@ bool SnarlDistanceIndex::SimpleSnarlRecord::for_each_child(const std::function<b
     }
     return true;
 }
-void SnarlDistanceIndex::SimpleSnarlRecordConstructor::add_child(size_t rank, nid_t node_id, size_t node_length, bool is_reversed) {
+void SnarlDistanceIndex::SimpleSnarlRecordWriter::add_child(size_t rank, nid_t node_id, size_t node_length, bool is_reversed) {
     //Let the root know where to find the node
     (*records)->at(get_node_pointer_offset(node_id,
                                           (*records)->at(MIN_NODE_ID_OFFSET),
@@ -2472,6 +4195,29 @@ void SnarlDistanceIndex::SimpleSnarlRecordConstructor::add_child(size_t rank, ni
 #endif
 
 }
+
+SnarlDistanceIndex::NodeRecord::NodeRecord (size_t pointer, size_t node_offset, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records){
+    record_offset = pointer;
+    records = tree_records;
+
+#ifdef debug_distance_indexing
+    assert(get_record_type() == NODE || get_record_type() == DISTANCED_NODE);
+#endif  
+}
+
+SnarlDistanceIndex::NodeRecord::NodeRecord (net_handle_t net, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records){
+    records = tree_records;
+    record_offset = get_record_offset(net);
+    
+#ifdef debug_distance_indexing
+    assert(get_handle_type(net) == NODE_HANDLE || get_handle_type(net) == CHAIN_HANDLE);
+    assert(get_record_type() == NODE || get_record_type() == DISTANCED_NODE);
+    assert(get_connectivity(net) == START_END || get_connectivity(net) == END_START
+          || get_connectivity(net) == START_START || get_connectivity(net) == END_END);
+#endif      
+}
+
+
 nid_t SnarlDistanceIndex::NodeRecord::get_node_id() const {
     return (*records)->at(record_offset + NODE_ID_OFFSET);
 }
@@ -2488,11 +4234,39 @@ size_t SnarlDistanceIndex::NodeRecord::get_node_length() const {
     //    return (*records)->at(record_offset + NODE_LENGTH_OFFSET);
     //}
 }
+size_t SnarlDistanceIndex::NodeRecord::get_distance_left_start() {
+    size_t stored_value = (*records)->at(record_offset + NODE_DISTANCE_LEFT_START_OFFSET);
+    return stored_value == 0 ? std::numeric_limits<size_t>::max() : stored_value - 1;
+}
+size_t SnarlDistanceIndex::NodeRecord::get_distance_right_start() {
+    size_t stored_value = (*records)->at(record_offset + NODE_DISTANCE_RIGHT_START_OFFSET);
+    return stored_value == 0 ? std::numeric_limits<size_t>::max() : stored_value - 1;
+}
+size_t SnarlDistanceIndex::NodeRecord::get_distance_left_end() {
+    size_t stored_value = (*records)->at(record_offset + NODE_DISTANCE_LEFT_END_OFFSET);
+    return stored_value == 0 ? std::numeric_limits<size_t>::max() : stored_value - 1;
+}
+size_t SnarlDistanceIndex::NodeRecord::get_distance_right_end() {
+    size_t stored_value = (*records)->at(record_offset + NODE_DISTANCE_RIGHT_END_OFFSET);
+    return stored_value == 0 ? std::numeric_limits<size_t>::max() : stored_value - 1;
+}
+
+SnarlDistanceIndex::TrivialSnarlRecord::TrivialSnarlRecord (size_t offset, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records){
+    records = tree_records;
+    record_offset = offset;
+    
+#ifdef debug_distance_indexing
+    assert(get_record_type() == TRIVIAL_SNARL || get_record_type() == DISTANCED_TRIVIAL_SNARL);
+    //assert(get_connectivity(net) == START_END || get_connectivity(net) == END_START
+    //      || get_connectivity(net) == START_START || get_connectivity(net) == END_END);
+#endif
+}
 
 
 size_t SnarlDistanceIndex::TrivialSnarlRecord::get_node_count() const {
     return (*records)->at(record_offset+TRIVIAL_SNARL_NODE_COUNT_OFFSET);
 }
+
 tuple<size_t, size_t, size_t, size_t> SnarlDistanceIndex::TrivialSnarlRecord::get_chain_values(size_t node_rank) const {
 #ifdef debug_distances
     assert(get_record_type() == TRIVIAL_SNARL || get_record_type() == DISTANCED_TRIVIAL_SNARL);
@@ -2539,6 +4313,22 @@ tuple<size_t, size_t, size_t, size_t> SnarlDistanceIndex::TrivialSnarlRecord::ge
 
     return make_tuple(prefix_sum, forward_loop, reverse_loop, component);
 
+}
+size_t SnarlDistanceIndex::TrivialSnarlRecord::get_max_prefix_sum(size_t node_rank) const {
+#ifdef debug_distances
+    assert(get_record_type() == TRIVIAL_SNARL || get_record_type() == DISTANCED_TRIVIAL_SNARL);
+#endif
+    size_t prefix_sum = (*records)->at(record_offset+TRIVIAL_SNARL_MAX_PREFIX_SUM_OFFSET);
+
+    //Get the right prefix sum value
+    prefix_sum = prefix_sum == 0 ? std::numeric_limits<size_t>::max() : prefix_sum - 1;
+    if (node_rank != 0) {
+        prefix_sum =  sum(prefix_sum,  
+               (*records)->at(record_offset+TRIVIAL_SNARL_RECORD_SIZE+ (node_rank*2)-1));
+    } 
+
+    return prefix_sum;
+
 }
 size_t SnarlDistanceIndex::TrivialSnarlRecord::get_prefix_sum(size_t node_rank) const {
 #ifdef debug_distances
@@ -2547,8 +4337,8 @@ size_t SnarlDistanceIndex::TrivialSnarlRecord::get_prefix_sum(size_t node_rank)
     size_t prefix_sum = (*records)->at(record_offset+TRIVIAL_SNARL_PREFIX_SUM_OFFSET);  
     prefix_sum = prefix_sum == 0 ? std::numeric_limits<size_t>::max() : prefix_sum - 1;
     if (node_rank != 0) {
-        return sum({prefix_sum,  
-               (*records)->at(record_offset+TRIVIAL_SNARL_RECORD_SIZE+ (node_rank*2)-1)});
+        return sum(prefix_sum,  
+               (*records)->at(record_offset+TRIVIAL_SNARL_RECORD_SIZE+ (node_rank*2)-1));
     } else {
         return prefix_sum;
     }
@@ -2591,6 +4381,7 @@ size_t SnarlDistanceIndex::TrivialSnarlRecord::get_chain_component(size_t node_r
     }
     return (*records)->at(record_offset + TRIVIAL_SNARL_COMPONENT_OFFSET);
 }
+
 size_t SnarlDistanceIndex::TrivialSnarlRecord::get_node_length(size_t node_rank) const {
     if (node_rank == 0) {
         return (*records)->at(record_offset + TRIVIAL_SNARL_RECORD_SIZE + (2*node_rank)+1);
@@ -2609,7 +4400,43 @@ bool SnarlDistanceIndex::TrivialSnarlRecord::get_is_reversed_in_parent(size_t no
     return (*records)->at(record_offset + TRIVIAL_SNARL_RECORD_SIZE + (2*node_rank)) & 1;
 }
 
-void SnarlDistanceIndex::NodeRecordConstructor::set_node_id(nid_t value) {
+SnarlDistanceIndex::NodeRecordWriter::NodeRecordWriter (size_t pointer, size_t node_offset, record_t type,
+             bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* snarl_records, nid_t node_id){
+    records = snarl_records;
+    record_offset =  pointer;
+    SnarlTreeRecordWriter::record_offset = pointer;
+    SnarlTreeRecordWriter::records = records;
+    NodeRecord::record_offset = pointer;
+    NodeRecord::records = records;
+    
+    (*records)->resize((*records)->size() + NODE_RECORD_SIZE); 
+#ifdef count_allocations
+    cerr << "new_node\t" <<  NODE_RECORD_SIZE << "\t" << (*records)->size() << endl;
+#endif
+    set_record_type(type);
+    set_start_end_connected();
+    
+    //Set the pointer for the node to this record
+#ifdef debug_distance_indexinging
+    assert (type == NODE || type == DISTANCED_NODE);
+    
+    cerr << get_node_pointer_offset(node_id,
+                                           (*records)->at(MIN_NODE_ID_OFFSET),
+                                           (*records)->at(COMPONENT_COUNT_OFFSET))
+         << " Set pointer to node " << node_id << " record: " << pointer << endl;
+#endif
+    //Tell the root where to find this node, and a 0 for the offset in a trivial snarl
+    (*records)->at(get_node_pointer_offset(node_id,
+                                           (*records)->at(MIN_NODE_ID_OFFSET),
+                                           (*records)->at(COMPONENT_COUNT_OFFSET))) = pointer;
+    (*records)->at(get_node_pointer_offset(node_id,
+                                           (*records)->at(MIN_NODE_ID_OFFSET),
+                                           (*records)->at(COMPONENT_COUNT_OFFSET))+1) = 0;
+
+}
+
+
+void SnarlDistanceIndex::NodeRecordWriter::set_node_id(nid_t value) {
 #ifdef debug_distance_indexing
     cerr <<record_offset + NODE_ID_OFFSET << " set node id " << value << endl;
     assert((*records)->at(record_offset + NODE_ID_OFFSET) == 0);
@@ -2617,25 +4444,64 @@ void SnarlDistanceIndex::NodeRecordConstructor::set_node_id(nid_t value) {
 
     (*records)->at(record_offset + NODE_ID_OFFSET) = value;
 }
-void SnarlDistanceIndex::NodeRecordConstructor::set_node_length(size_t length) {
+void SnarlDistanceIndex::NodeRecordWriter::set_node_length(size_t length) {
 #ifdef debug_distance_indexing
     cerr <<record_offset + NODE_LENGTH_OFFSET << " set node length " << length << endl;
     assert((*records)->at(record_offset + NODE_LENGTH_OFFSET) == 0);
 #endif
     (*records)->at(record_offset + NODE_LENGTH_OFFSET) = length;
 }
-void SnarlDistanceIndex::NodeRecordConstructor::set_rank_in_parent(size_t value) {
+void SnarlDistanceIndex::NodeRecordWriter::set_rank_in_parent(size_t value) {
 #ifdef debug_distance_indexing
     cerr <<record_offset + NODE_RANK_OFFSET << " set node rank " << value << endl;
     assert((*records)->at(record_offset + NODE_RANK_OFFSET) == 0);
 #endif
     (*records)->at(record_offset + NODE_RANK_OFFSET) = value;
 }
+void SnarlDistanceIndex::NodeRecordWriter::set_distance_left_start(size_t distance) {
+    (*records)->at(record_offset + NODE_DISTANCE_LEFT_START_OFFSET) = (distance == std::numeric_limits<size_t>::max() ? 0 : distance + 1);
+}
+void SnarlDistanceIndex::NodeRecordWriter::set_distance_right_start(size_t distance) {
+    (*records)->at(record_offset + NODE_DISTANCE_RIGHT_START_OFFSET) = (distance == std::numeric_limits<size_t>::max() ? 0 : distance + 1);
+}
+void SnarlDistanceIndex::NodeRecordWriter::set_distance_left_end(size_t distance) {
+    (*records)->at(record_offset + NODE_DISTANCE_LEFT_END_OFFSET) = (distance == std::numeric_limits<size_t>::max() ? 0 : distance + 1);
+}
+void SnarlDistanceIndex::NodeRecordWriter::set_distance_right_end(size_t distance) {
+    (*records)->at(record_offset + NODE_DISTANCE_RIGHT_END_OFFSET) = (distance == std::numeric_limits<size_t>::max() ? 0 : distance + 1);
+}
+
+SnarlDistanceIndex::TrivialSnarlRecordWriter::TrivialSnarlRecordWriter (size_t pointer, record_t type,
+             bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* snarl_records, bool new_record){
+
+    records = snarl_records;
+    record_offset =  pointer;
+    SnarlTreeRecordWriter::record_offset = pointer;
+    SnarlTreeRecordWriter::records = records;
+    TrivialSnarlRecord::record_offset = pointer;
+    TrivialSnarlRecord::records = records;
+    
+    assert (type == TRIVIAL_SNARL || type == DISTANCED_TRIVIAL_SNARL);
+    
+#ifdef debug_distance_indexing
+    cerr << " Resizing array to add trivial snarl: length " << (*records)->size() << " -> "  << (*records)->size() + TR     IVIAL_SNARL_RECORD_SIZE << endl;
+#endif
+ 
+    if (new_record) {
+        (*records)->resize(record_offset + TRIVIAL_SNARL_RECORD_SIZE);
+        set_record_type(type);
+        set_start_end_connected();
+#ifdef count_allocations
+        cerr << "new_trivial_snarl\t" << TRIVIAL_SNARL_RECORD_SIZE << "\t" << (*records)->size() << endl;
+#endif
+    }
+}
 
-void SnarlDistanceIndex::TrivialSnarlRecordConstructor::set_node_count(size_t value) const {
+
+void SnarlDistanceIndex::TrivialSnarlRecordWriter::set_node_count(size_t value) const {
     (*records)->at(record_offset+TRIVIAL_SNARL_NODE_COUNT_OFFSET)=value;
 }
-void SnarlDistanceIndex::TrivialSnarlRecordConstructor::set_prefix_sum(size_t value) const {
+void SnarlDistanceIndex::TrivialSnarlRecordWriter::set_prefix_sum(size_t value) const {
 #ifdef debug_distance_indexing
     cerr <<record_offset + TRIVIAL_SNARL_PREFIX_SUM_OFFSET << " set node prefix sum " << value << endl;
     assert((*records)->at(record_offset + TRIVIAL_SNARL_PREFIX_SUM_OFFSET) == 0);
@@ -2643,7 +4509,15 @@ void SnarlDistanceIndex::TrivialSnarlRecordConstructor::set_prefix_sum(size_t va
     value = value == std::numeric_limits<size_t>::max() ? 0 : value +1;
     (*records)->at(record_offset + TRIVIAL_SNARL_PREFIX_SUM_OFFSET) = value;
 }
-void SnarlDistanceIndex::TrivialSnarlRecordConstructor::set_forward_loop(size_t value) const { 
+void SnarlDistanceIndex::TrivialSnarlRecordWriter::set_max_prefix_sum(size_t value) const {
+#ifdef debug_distance_indexing
+    cerr <<record_offset + TRIVIAL_SNARL_MAX_PREFIX_SUM_OFFSET << " set node prefix sum " << value << endl;
+    assert((*records)->at(record_offset + TRIVIAL_SNARL_MAX_PREFIX_SUM_OFFSET) == 0);
+#endif
+    value = value == std::numeric_limits<size_t>::max() ? 0 : value +1;
+    (*records)->at(record_offset + TRIVIAL_SNARL_MAX_PREFIX_SUM_OFFSET) = value;
+}
+void SnarlDistanceIndex::TrivialSnarlRecordWriter::set_forward_loop(size_t value) const { 
 #ifdef debug_distance_indexing
     cerr <<record_offset + TRIVIAL_SNARL_FORWARD_LOOP_OFFSET << " set node forward loop " << value << endl;
     assert(get_record_type() == DISTANCED_TRIVIAL_SNARL);
@@ -2651,7 +4525,7 @@ void SnarlDistanceIndex::TrivialSnarlRecordConstructor::set_forward_loop(size_t
     value = value == std::numeric_limits<size_t>::max() ? 0 : value +1;
     (*records)->at(record_offset + TRIVIAL_SNARL_FORWARD_LOOP_OFFSET) = value;
 }
-void SnarlDistanceIndex::TrivialSnarlRecordConstructor::set_reverse_loop(size_t value) const {
+void SnarlDistanceIndex::TrivialSnarlRecordWriter::set_reverse_loop(size_t value) const {
 #ifdef debug_distance_indexing
     cerr <<record_offset + TRIVIAL_SNARL_REVERSE_LOOP_OFFSET << " set node reverse loop " << value << endl;
     assert((*records)->at(record_offset + TRIVIAL_SNARL_REVERSE_LOOP_OFFSET) == 0);
@@ -2662,7 +4536,7 @@ void SnarlDistanceIndex::TrivialSnarlRecordConstructor::set_reverse_loop(size_t
     (*records)->at(record_offset + TRIVIAL_SNARL_REVERSE_LOOP_OFFSET) = value;
     
 }
-void SnarlDistanceIndex::TrivialSnarlRecordConstructor::set_chain_component(size_t value) const {
+void SnarlDistanceIndex::TrivialSnarlRecordWriter::set_chain_component(size_t value) const {
 #ifdef debug_distance_indexing
     cerr <<record_offset + TRIVIAL_SNARL_COMPONENT_OFFSET << " set node component " << value << endl;
     assert((*records)->at(record_offset + TRIVIAL_SNARL_COMPONENT_OFFSET) == 0);
@@ -2671,6 +4545,60 @@ void SnarlDistanceIndex::TrivialSnarlRecordConstructor::set_chain_component(size
     (*records)->at(record_offset + TRIVIAL_SNARL_COMPONENT_OFFSET) = value;
 }
 
+SnarlDistanceIndex::ChainRecord::ChainRecord (size_t pointer, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records){
+
+    record_offset = pointer;
+    records = tree_records;
+    net_handle_record_t record_type= get_record_handle_type();
+    if (record_type == NODE_HANDLE) {
+        net_handle_record_t parent_type = SnarlTreeRecord(
+            NodeRecord(pointer, 0, records).get_parent_record_offset(), records
+        ).get_record_handle_type();
+#ifdef debug_distance_indexing
+        assert(parent_type == ROOT_HANDLE || parent_type == SNARL_HANDLE);
+#endif  
+    } else {
+#ifdef debug_distance_indexing
+    assert(get_record_handle_type() == CHAIN_HANDLE);
+#endif
+    }   
+}       
+
+SnarlDistanceIndex::ChainRecord::ChainRecord (net_handle_t net, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records){
+    record_offset = get_record_offset(net);
+    records = tree_records;
+    
+    net_handle_record_t record_type = get_record_handle_type();
+#ifdef debug_distance_indexing
+    if (record_type == NODE_HANDLE) {
+        net_handle_record_t parent_type = SnarlTreeRecord(
+            NodeRecord(record_offset, 0, records).get_parent_record_offset(), records
+        ).get_record_handle_type();
+        assert(parent_type == ROOT_HANDLE || parent_type == SNARL_HANDLE);
+    } else {
+        assert(get_record_handle_type() == CHAIN_HANDLE);
+    }
+#endif
+}   
+
+SnarlDistanceIndex::ChainRecord::ChainRecord (net_handle_t net, const bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* tree_records, size_t tag){
+    record_offset = get_record_offset(net);
+    records = tree_records;
+    
+#ifdef debug_distance_indexing
+    net_handle_record_t record_type= SnarlDistanceIndex::get_record_handle_type(SnarlDistanceIndex::get_record_type(tag     ));
+    if (record_type == NODE_HANDLE) {
+        net_handle_record_t parent_type = SnarlTreeRecord(
+            NodeRecord(record_offset, 0, records).get_parent_record_offset(), records
+        ).get_record_handle_type();
+        assert(parent_type == ROOT_HANDLE || parent_type == SNARL_HANDLE);
+    } else {
+        assert(get_record_handle_type() == CHAIN_HANDLE);
+    }       
+#endif
+}   
+
+
 
 size_t SnarlDistanceIndex::ChainRecord::get_node_count() const {
     if (get_record_handle_type() == NODE_HANDLE) {
@@ -2798,7 +4726,7 @@ size_t SnarlDistanceIndex::ChainRecord::get_distance_taking_chain_loop(size_t ra
      * enter the end node from the right (from the right or from the left and then looping)
      */
      if (get_record_type() == MULTICOMPONENT_CHAIN) {
-         size_t last_component = TrivialSnarlRecord(get_first_node_offset() , records).get_chain_component(0, true);
+        size_t last_component = TrivialSnarlRecord(get_first_node_offset() , records).get_chain_component(0, true);
         bool first_in_first_component = component1 == 0 || component1 == last_component;
         bool second_in_first_component = component2 == 0 || component2 == last_component;
         bool can_loop = get_is_looping_chain_connected_backwards();
@@ -2820,7 +4748,7 @@ size_t SnarlDistanceIndex::ChainRecord::get_distance_taking_chain_loop(size_t ra
         //then the chain must be connected for the path to be valid
         bool end_at_right_of_first = component2 == 0 && !left_side2;
         bool start_at_left_of_last = component1 == last_component && left_side1; 
-        if (end_at_right_of_first || start_at_left_of_last) {
+        if ((end_at_right_of_first || start_at_left_of_last)) {
             return std::numeric_limits<size_t>::max();
         }
     }
@@ -2861,6 +4789,23 @@ size_t SnarlDistanceIndex::ChainRecord::get_distance_taking_chain_loop(size_t ra
     return distance;
 }
 
+size_t SnarlDistanceIndex::ChainRecord::get_distance_left_start() {
+    size_t stored_value = (*records)->at(record_offset + CHAIN_DISTANCE_LEFT_START_OFFSET);
+    return stored_value == 0 ? std::numeric_limits<size_t>::max() : stored_value - 1;
+}
+size_t SnarlDistanceIndex::ChainRecord::get_distance_right_start() {
+    size_t stored_value = (*records)->at(record_offset + CHAIN_DISTANCE_RIGHT_START_OFFSET);
+    return stored_value == 0 ? std::numeric_limits<size_t>::max() : stored_value - 1;
+}
+size_t SnarlDistanceIndex::ChainRecord::get_distance_left_end() {
+    size_t stored_value = (*records)->at(record_offset + CHAIN_DISTANCE_LEFT_END_OFFSET);
+    return stored_value == 0 ? std::numeric_limits<size_t>::max() : stored_value - 1;
+}
+size_t SnarlDistanceIndex::ChainRecord::get_distance_right_end() {
+    size_t stored_value = (*records)->at(record_offset + CHAIN_DISTANCE_RIGHT_END_OFFSET);
+    return stored_value == 0 ? std::numeric_limits<size_t>::max() : stored_value - 1;
+}
+
 size_t SnarlDistanceIndex::ChainRecord::get_first_node_offset() const {
     if (get_record_handle_type() == NODE_HANDLE) {
         throw runtime_error("error: Trying to get chain traversal from a node");
@@ -2883,6 +4828,9 @@ net_handle_t SnarlDistanceIndex::ChainRecord::get_next_child(const net_handle_t&
     //If we are inside a trivial snarl and we aren't at the ends, then we just walk through the trivial snarl
     if (get_handle_type(net_handle) == NODE_HANDLE) {
         //If this is a node in a trivial snarl
+#ifdef debug_snarl_traversal
+        cerr << "GEt next in chain after " << TrivialSnarlRecord(get_record_offset(net_handle), records).get_node_id(get_node_record_offset(net_handle)) << endl;
+#endif
         if (go_left && get_node_record_offset(net_handle) != 0) {
             //If we are going left and this is not the first node in the trivial snarl,
             //then keep everything the same but decrement the node record offset by one
@@ -2895,6 +4843,13 @@ net_handle_t SnarlDistanceIndex::ChainRecord::get_next_child(const net_handle_t&
                 connectivity = endpoints_to_connectivity(get_end_endpoint(connectivity), 
                                                                 get_start_endpoint(connectivity));
             }
+            if (TrivialSnarlRecord(get_record_offset(net_handle), records).get_is_reversed_in_parent(get_node_record_offset(net_handle)) !=
+                TrivialSnarlRecord(get_record_offset(net_handle), records).get_is_reversed_in_parent(get_node_record_offset(net_handle)-1)) {
+                //If this node is facing the opposite direction of the next nod in the chain
+                connectivity = endpoints_to_connectivity(get_end_endpoint(connectivity), 
+                                                                get_start_endpoint(connectivity));
+
+            }
             return get_net_handle_from_values(get_record_offset(net_handle), connectivity, 
                                   get_handle_type(net_handle), get_node_record_offset(net_handle)-1);
 
@@ -2904,7 +4859,15 @@ net_handle_t SnarlDistanceIndex::ChainRecord::get_next_child(const net_handle_t&
             //If we are going right and this is not the last node in the trivial snarl
             //then keep everything the same but increment the node record offset by one
             //to move one node right in the trivial snarl
-            return get_net_handle_from_values(get_record_offset(net_handle), get_connectivity(net_handle), 
+            connectivity_t connectivity = get_connectivity(net_handle);
+            if (TrivialSnarlRecord(get_record_offset(net_handle), records).get_is_reversed_in_parent(get_node_record_offset(net_handle)) !=
+                TrivialSnarlRecord(get_record_offset(net_handle), records).get_is_reversed_in_parent(get_node_record_offset(net_handle)+1)) {
+                //If this node is facing the opposite direction of the next nod in the chain
+                connectivity = endpoints_to_connectivity(get_end_endpoint(connectivity), 
+                                                                get_start_endpoint(connectivity));
+
+            }
+            return get_net_handle_from_values(get_record_offset(net_handle), connectivity, 
                                       get_handle_type(net_handle), get_node_record_offset(net_handle)+1);
         }
         //Otherwise, if we are going left from the first node or right from the last node, we pretend this is a 
@@ -2979,7 +4942,6 @@ net_handle_t SnarlDistanceIndex::ChainRecord::get_next_child(const net_handle_t&
 
         //Get the direction of the next handle
         //Handle will point in whichever direction we moved in
-        //TODO: Should it?
         connectivity_t connectivity = go_left == next_is_reversed_in_parent ? START_END : END_START;
 
         return get_net_handle_from_values(next_pointer, connectivity, NODE_HANDLE, node_offset);
@@ -2994,8 +4956,10 @@ bool SnarlDistanceIndex::ChainRecord::for_each_child(const std::function<bool(co
     }
 
 
-    net_handle_t first_child = get_net_handle_from_values(get_first_node_offset(), START_END, NODE_HANDLE, 0);
-    net_handle_t current_child = get_net_handle_from_values(get_first_node_offset(), START_END, NODE_HANDLE, 0);
+    size_t first_node_offset = get_first_node_offset();
+    bool rev_in_parent = TrivialSnarlRecord(first_node_offset, records).get_is_reversed_in_parent(0);
+    net_handle_t first_child = get_net_handle_from_values(first_node_offset, rev_in_parent ? END_START : START_END, NODE_HANDLE, 0);
+    net_handle_t current_child = get_net_handle_from_values(first_node_offset, rev_in_parent ? END_START : START_END, NODE_HANDLE, 0);
     bool is_first = true;
 
     while (true) {
@@ -3020,7 +4984,31 @@ bool SnarlDistanceIndex::ChainRecord::for_each_child(const std::function<bool(co
 }
 
 
-void SnarlDistanceIndex::ChainRecordConstructor::set_node_count(size_t node_count) {
+SnarlDistanceIndex::ChainRecordWriter::ChainRecordWriter (size_t pointer, record_t type, size_t node_count, bdsg::yomo::UniqueMappedPointer<bdsg::MappedIntVector>* records){
+#ifdef debug_distance_indexing
+    assert(type == CHAIN ||
+           type == DISTANCED_CHAIN ||
+           type == MULTICOMPONENT_CHAIN);
+#endif
+    record_offset = pointer;
+    records = records;
+    SnarlTreeRecordWriter::record_offset = pointer;
+    SnarlTreeRecordWriter::records = records;
+    ChainRecord::record_offset = pointer;
+    ChainRecord::records = records;
+#ifdef debug_distance_indexing
+    cerr << " Resizing array to add chain: length " << (*records)->size() << " -> "  << (*records)->size() + CHAIN_RECO     RD_SIZE << endl;
+#endif
+    (*records)->resize((*records)->size() + CHAIN_RECORD_SIZE);
+    set_node_count(node_count);
+    set_record_type(type);
+#ifdef count_allocations
+    cerr << "new_chain\t" << CHAIN_RECORD_SIZE << "\t" << (*records)->size() << endl;
+#endif
+}
+
+
+void SnarlDistanceIndex::ChainRecordWriter::set_node_count(size_t node_count) {
 #ifdef debug_distance_indexing
     cerr << record_offset + CHAIN_NODE_COUNT_OFFSET << " set chain node count " << node_count << endl;
     assert((*records)->at(record_offset + CHAIN_NODE_COUNT_OFFSET) == 0);
@@ -3031,7 +5019,7 @@ void SnarlDistanceIndex::ChainRecordConstructor::set_node_count(size_t node_coun
 size_t SnarlDistanceIndex::ChainRecord::get_depth() const {
     return (*records)->at(record_offset+CHAIN_DEPTH_OFFSET) ;
 }
-void SnarlDistanceIndex::ChainRecordConstructor::set_depth(size_t depth) {
+void SnarlDistanceIndex::ChainRecordWriter::set_depth(size_t depth) {
 #ifdef debug_distance_indexing
     cerr << record_offset + CHAIN_DEPTH_OFFSET << " set chain depth " << depth << endl;
     assert((*records)->at(record_offset + CHAIN_DEPTH_OFFSET) == 0);
@@ -3041,7 +5029,7 @@ void SnarlDistanceIndex::ChainRecordConstructor::set_depth(size_t depth) {
 }
 
 //The offset of the last child, if it is a snarl, and if it can loop
-void SnarlDistanceIndex::ChainRecordConstructor::set_last_child_offset(size_t offset, bool is_snarl, bool loopable) {
+void SnarlDistanceIndex::ChainRecordWriter::set_last_child_offset(size_t offset, bool is_snarl, bool loopable) {
 #ifdef debug_distance_indexing
     cerr << record_offset + CHAIN_LAST_CHILD_OFFSET << " set chain last child offset " << offset << endl;
     assert((*records)->at(record_offset + CHAIN_LAST_CHILD_OFFSET) == 0);
@@ -3050,8 +5038,21 @@ void SnarlDistanceIndex::ChainRecordConstructor::set_last_child_offset(size_t of
     (*records)->at(record_offset + CHAIN_LAST_CHILD_OFFSET) = ((offset << 2) | (is_snarl<<1)) | loopable;
 }
 
-//Add a snarl to the end of the chain and return a SnarlRecordConstructor pointing to it
-SnarlDistanceIndex::SnarlRecordConstructor SnarlDistanceIndex::ChainRecordConstructor::add_snarl(size_t snarl_size, record_t type, size_t previous_child_offset) {
+void SnarlDistanceIndex::ChainRecordWriter::set_distance_left_start(size_t distance) {
+    (*records)->at(record_offset + CHAIN_DISTANCE_LEFT_START_OFFSET) = (distance == std::numeric_limits<size_t>::max() ? 0 : distance + 1);
+}
+void SnarlDistanceIndex::ChainRecordWriter::set_distance_right_start(size_t distance) {
+    (*records)->at(record_offset + CHAIN_DISTANCE_RIGHT_START_OFFSET) = (distance == std::numeric_limits<size_t>::max() ? 0 : distance + 1);
+}
+void SnarlDistanceIndex::ChainRecordWriter::set_distance_left_end(size_t distance) {
+    (*records)->at(record_offset + CHAIN_DISTANCE_LEFT_END_OFFSET) = (distance == std::numeric_limits<size_t>::max() ? 0 : distance + 1);
+}
+void SnarlDistanceIndex::ChainRecordWriter::set_distance_right_end(size_t distance) {
+    (*records)->at(record_offset + CHAIN_DISTANCE_RIGHT_END_OFFSET) = (distance == std::numeric_limits<size_t>::max() ? 0 : distance + 1);
+}
+
+//Add a snarl to the end of the chain and return a SnarlRecordWriter pointing to it
+SnarlDistanceIndex::SnarlRecordWriter SnarlDistanceIndex::ChainRecordWriter::add_snarl(size_t snarl_size, record_t type, size_t previous_child_offset) {
 
     size_t snarl_record_size = SnarlRecord::record_size(type, snarl_size);
 #ifdef debug_distance_indexing
@@ -3070,7 +5071,7 @@ SnarlDistanceIndex::SnarlRecordConstructor SnarlDistanceIndex::ChainRecordConstr
     (*records)->resize(start_i+1);
     (*records)->at(start_i) = snarl_record_size;
     (*records)->reserve(start_i + snarl_record_size);
-    SnarlRecordConstructor snarl_record(snarl_size, records, type);
+    SnarlRecordWriter snarl_record(snarl_size, records, type);
     snarl_record.set_parent_record_offset(get_offset());
 #ifdef debug_distance_indexing
     cerr << (*records)->size() << " Adding child snarl length to the end of the array " << endl;
@@ -3083,8 +5084,8 @@ SnarlDistanceIndex::SnarlRecordConstructor SnarlDistanceIndex::ChainRecordConstr
 #endif
     return snarl_record;
 }
-//Add a simple snarl to the end of the chain and return a SnarlRecordConstructor pointing to it
-SnarlDistanceIndex::SimpleSnarlRecordConstructor SnarlDistanceIndex::ChainRecordConstructor::add_simple_snarl(size_t snarl_size, record_t type, size_t previous_child_offset) {
+//Add a simple snarl to the end of the chain and return a SnarlRecordWriter pointing to it
+SnarlDistanceIndex::SimpleSnarlRecordWriter SnarlDistanceIndex::ChainRecordWriter::add_simple_snarl(size_t snarl_size, record_t type, size_t previous_child_offset) {
 
     size_t snarl_record_size = SIMPLE_SNARL_RECORD_SIZE + 2*snarl_size;
 #ifdef debug_distance_indexing
@@ -3104,7 +5105,7 @@ SnarlDistanceIndex::SimpleSnarlRecordConstructor SnarlDistanceIndex::ChainRecord
     (*records)->resize(start_i+1);
     (*records)->at(start_i) = snarl_record_size;
     (*records)->reserve(start_i + snarl_record_size);
-    SimpleSnarlRecordConstructor snarl_record(snarl_size, records, type);
+    SimpleSnarlRecordWriter snarl_record(snarl_size, records, type);
     snarl_record.set_parent_record_offset(get_offset());
 #ifdef debug_distance_indexing
     cerr << (*records)->size() << " Adding child snarl length to the end of the array " << endl;
@@ -3119,13 +5120,14 @@ SnarlDistanceIndex::SimpleSnarlRecordConstructor SnarlDistanceIndex::ChainRecord
 }
 
 
-size_t SnarlDistanceIndex::ChainRecordConstructor::add_node(nid_t node_id, size_t node_length, bool is_reversed_in_parent,
-    size_t prefix_sum, size_t forward_loop, size_t reverse_loop, size_t component, size_t previous_child_offset) {
+size_t SnarlDistanceIndex::ChainRecordWriter::add_node(nid_t node_id, size_t node_length, bool is_reversed_in_parent,
+    size_t prefix_sum, size_t forward_loop, size_t reverse_loop, size_t component, size_t max_prefix_sum, size_t previous_child_offset, bool new_record) {
 #ifdef debug_distance_indexing
     cerr << "Adding new node to chain, with previous child at offset " << previous_child_offset << endl;
 #endif
     if (SnarlDistanceIndex::get_record_type((*records)->at(previous_child_offset)) == DISTANCED_TRIVIAL_SNARL
-            && TrivialSnarlRecord(previous_child_offset, records).get_node_count() == MAX_TRIVIAL_SNARL_NODE_COUNT) {
+            && (TrivialSnarlRecord(previous_child_offset, records).get_node_count() == MAX_TRIVIAL_SNARL_NODE_COUNT 
+                || new_record)) {
         //If the last thing was a trivial snarl and it is full, then finish it off
         (*records)->at(previous_child_offset-1) = TrivialSnarlRecord(previous_child_offset, records).get_record_size();
         size_t current_size = (*records)->size();
@@ -3137,7 +5139,8 @@ size_t SnarlDistanceIndex::ChainRecordConstructor::add_node(nid_t node_id, size_
             || SnarlDistanceIndex::get_record_type((*records)->at(previous_child_offset)) == DISTANCED_SNARL 
             || SnarlDistanceIndex::get_record_type((*records)->at(previous_child_offset)) == OVERSIZED_SNARL 
             || SnarlDistanceIndex::get_record_type((*records)->at(previous_child_offset)) == DISTANCED_SIMPLE_SNARL 
-            || TrivialSnarlRecord(previous_child_offset, records).get_node_count() == MAX_TRIVIAL_SNARL_NODE_COUNT) {
+            || TrivialSnarlRecord(previous_child_offset, records).get_node_count() == MAX_TRIVIAL_SNARL_NODE_COUNT
+            || reverse_loop == 0 || new_record) {
         //If the last thing was a snarl or nothing (previous_child_offset == 0, meaning that this is the 
         //first thing in the chain), then create a new trivial snarl
         size_t start_i = (*records)->size();
@@ -3145,7 +5148,6 @@ size_t SnarlDistanceIndex::ChainRecordConstructor::add_node(nid_t node_id, size_
         (*records)->at(start_i) = 0; //Add a place for the size of this trivial snarl, to be filled in later
 
         //Set the node to point to the correct node record
-        //TODO: Shouldn't this have been done in the node constructor?
         (*records)->at(get_node_pointer_offset(node_id,
                                               (*records)->at(MIN_NODE_ID_OFFSET),
                                               (*records)->at(COMPONENT_COUNT_OFFSET))) 
@@ -3157,10 +5159,11 @@ size_t SnarlDistanceIndex::ChainRecordConstructor::add_node(nid_t node_id, size_
     
 
         //Create a new trivial snarl record
-        TrivialSnarlRecordConstructor trivial_snarl_record((*records)->size(), DISTANCED_TRIVIAL_SNARL, records, true);
+        TrivialSnarlRecordWriter trivial_snarl_record((*records)->size(), DISTANCED_TRIVIAL_SNARL, records, true);
         trivial_snarl_record.set_parent_record_offset(record_offset);
         trivial_snarl_record.set_node_count(1);
         trivial_snarl_record.set_prefix_sum(prefix_sum);
+        trivial_snarl_record.set_max_prefix_sum(max_prefix_sum);;
         trivial_snarl_record.set_forward_loop(forward_loop);
         trivial_snarl_record.set_reverse_loop(reverse_loop);
         trivial_snarl_record.set_chain_component(component);
@@ -3195,7 +5198,7 @@ size_t SnarlDistanceIndex::ChainRecordConstructor::add_node(nid_t node_id, size_
     cerr << "trivial_snarl\t2\t" <<  (*records)->size() << endl;
 #endif
 
-        TrivialSnarlRecordConstructor trivial_snarl_record(previous_child_offset, DISTANCED_TRIVIAL_SNARL, records, false);
+        TrivialSnarlRecordWriter trivial_snarl_record(previous_child_offset, DISTANCED_TRIVIAL_SNARL, records, false);
 
         //Increment the node count
         size_t old_node_count = trivial_snarl_record.get_node_count();
@@ -3216,14 +5219,17 @@ size_t SnarlDistanceIndex::ChainRecordConstructor::add_node(nid_t node_id, size_
         return trivial_snarl_record.record_offset;
     }
 }
-
 string SnarlDistanceIndex::net_handle_as_string(const net_handle_t& net) const {
     net_handle_record_t type = get_handle_type(net);
     SnarlTreeRecord record (net, &snarl_tree_records);
     net_handle_record_t record_type = record.get_record_handle_type();
     string result;
     if (type == ROOT_HANDLE) {
-        return "root"; 
+        if (record.get_record_type() == ROOT_SNARL || record.get_record_type() == DISTANCED_ROOT_SNARL) {
+            return "root snarl";
+        } else {
+            return "root"; 
+        }
     } else if (type == NODE_HANDLE) {
         if (ends_at(net) == starts_at(net)) {
             return "node" + std::to_string( node_id(net)) + (ends_at(net) == START ? "rev" : "fd") + " that is the end node of a looping chain";
@@ -3266,6 +5272,45 @@ string SnarlDistanceIndex::net_handle_as_string(const net_handle_t& net) const {
     return result;
 }
 
+bool SnarlDistanceIndex::traverse_decomposition(const std::function<bool(const net_handle_t&)>& snarl_iteratee,
+                                                const std::function<bool(const net_handle_t&)>& chain_iteratee,
+                                                const std::function<bool(const net_handle_t&)>& node_iteratee) const {
+    net_handle_t root = get_root();
+    return for_each_child(root, [&] (const net_handle_t& child) {
+        return traverse_decomposition_helper(child, snarl_iteratee, chain_iteratee, node_iteratee);
+    });
+
+}
+bool SnarlDistanceIndex::traverse_decomposition_helper(const net_handle_t& net,
+                                                const std::function<bool(const net_handle_t&)>& snarl_iteratee,
+                                                const std::function<bool(const net_handle_t&)>& chain_iteratee,
+                                                const std::function<bool(const net_handle_t&)>& node_iteratee) const {
+    if (is_node(net)) {
+        //If this is a node, then run iteratee and we're done
+        return node_iteratee(net);
+    } else if (is_snarl(net)) {
+        //IF this is a snarl, run iteratee and if it returns false, return false to stop iterating
+        bool result = snarl_iteratee(net);
+        if (!result){
+            return false;
+        }
+    } else if (is_chain(net)) {
+        //IF this is a chain, run iteratee and if it returns false, return false to stop iterating
+        bool result = chain_iteratee(net);
+        if (!result){
+            return false;
+        }
+    } else {
+        throw runtime_error("error: traversing the wrong kind of net_handle_t in traverse_decomposition");
+    }
+    //If this was a snarl or chain, recurse
+    return for_each_child(net, [&] (const net_handle_t& child) {
+        return traverse_decomposition_helper(child, snarl_iteratee, chain_iteratee, node_iteratee);
+    });
+
+}
+
+
 
 //Print entire index to cout as csv:
 //self, parent, # children, depth
@@ -3318,6 +5363,214 @@ void SnarlDistanceIndex::print_descendants_of(const net_handle_t net) const {
     }
 }
 
+void SnarlDistanceIndex::print_snarl_stats() const {
+    cout << "#start_id\tend_id\tsnarl_size\tsnarl_depth" << endl;
+    traverse_decomposition(
+        [&](const net_handle_t& snarl_child) {
+            //Iteratee for a snarl child
+            SnarlTreeRecord record(snarl_child, &snarl_tree_records);
+
+            //Get the number of children depending on the type of record
+            size_t child_count;
+            if (record.get_record_type() == SNARL ||
+                        record.get_record_type() == DISTANCED_SNARL||
+                        record.get_record_type() == OVERSIZED_SNARL  
+                        ){
+ 
+                child_count = SnarlRecord(snarl_child, &snarl_tree_records).get_node_count();
+            } else if (record.get_record_type() == SIMPLE_SNARL ||
+                        record.get_record_type() == DISTANCED_SIMPLE_SNARL) {
+                child_count = SimpleSnarlRecord(snarl_child, &snarl_tree_records).get_node_count();
+            } else {
+                throw runtime_error("error: getting the snarl child count of the wrong type of record");
+            }
+            //Print the stats
+            cout << record.get_start_id() << "\t" 
+                 << record.get_end_id() << "\t" 
+                 << child_count << "\t" 
+                 << get_depth(snarl_child) << endl; 
+            return true;
+        }, 
+        [&](const net_handle_t& chain_child) {
+            //Iteratee of a chain child -do nothing
+            return true;
+        }, 
+        [&](const net_handle_t& node_child) {
+            //Iteratee of a node child - do nothing
+            return true;
+        });
+}
+
+void SnarlDistanceIndex::write_snarls_to_json() const {
+    traverse_decomposition(
+        [&](const net_handle_t& snarl_child) {
+            //Iteratee for a snarl child
+
+            //Make a new json object for this snarl
+            json_t* out_json = json_object();
+            json_object_set_new(out_json, "type", json_string("snarl")); 
+            SnarlTreeRecord record(snarl_child, &snarl_tree_records);
+
+            //Get the start node pointing in
+            net_handle_t start_bound = get_node_from_sentinel(get_bound(snarl_child, false, true));
+            json_t* start_json = json_object();
+            json_object_set_new(start_json, "node_id", json_integer(node_id(start_bound)));
+            json_object_set_new(start_json, "is_rev", json_boolean(ends_at(start_bound) == START));
+            //Set the start node
+            json_object_set_new(out_json, "start_node", start_json);
+
+            //Get the end node pointing in
+            net_handle_t end_bound = get_node_from_sentinel(get_bound(snarl_child, true, true));
+            json_t* end_json = json_object();
+            json_object_set_new(end_json, "node_id", json_integer(node_id(end_bound)));
+            json_object_set_new(end_json, "is_rev", json_boolean(ends_at(end_bound) == START));
+            //Set the end node
+            json_object_set_new(out_json, "end_node", end_json);
+
+            //Set the parent
+            net_handle_t parent = get_parent(snarl_child);
+                json_t* parent_json = json_object();
+            if (is_root(parent)) {
+                json_object_set_new(parent_json, "type", json_string("root"));
+            } else {
+                json_object_set_new(parent_json, "type", json_string("chain"));
+                net_handle_t parent_start = get_bound(parent, false, true);
+                json_object_set_new(parent_json, "start_id", json_integer(node_id(parent_start)));
+                net_handle_t parent_end = get_bound(parent, true, false);
+                json_object_set_new(parent_json, "end_id", json_integer(node_id(parent_end)));
+            }
+            json_object_set_new(out_json, "parent", parent_json);
+
+            //Get the number of children depending on the type of record
+            if (record.get_record_type() == SNARL ||
+                        record.get_record_type() == DISTANCED_SNARL||
+                        record.get_record_type() == OVERSIZED_SNARL  
+                        ){
+                size_t child_count = SnarlRecord(snarl_child, &snarl_tree_records).get_node_count();
+                json_object_set_new(out_json, "child_count", json_integer(child_count)); 
+            } else if (record.get_record_type() == SIMPLE_SNARL ||
+                        record.get_record_type() == DISTANCED_SIMPLE_SNARL) {
+                size_t child_count = SimpleSnarlRecord(snarl_child, &snarl_tree_records).get_node_count();
+                json_object_set_new(out_json, "child_count", json_integer(child_count)); 
+            } else {
+                throw runtime_error("error: getting the snarl child count of the wrong type of record");
+            }
+
+            //Set the min and max length, if applicable
+            if (record.get_record_type() == DISTANCED_SNARL ||
+                        record.get_record_type() == DISTANCED_SIMPLE_SNARL){
+                json_object_set_new(out_json, "minimum_length", json_integer(minimum_length(snarl_child))); 
+                json_object_set_new(out_json, "maximum_length", json_integer(maximum_length(snarl_child))); 
+            }
+
+            //Set the depth
+            json_object_set_new(out_json, "depth", json_integer(get_depth(snarl_child)));
+
+            cout << json_dumps(out_json, JSON_ENCODE_ANY) << endl;
+
+            return true;
+        }, 
+        [&](const net_handle_t& chain_child) {
+            //Iteratee of a chain child
+            if (is_trivial_chain(chain_child)) {
+                //If this is a trivial chain, do nothing, handle it as a node
+                return true;
+            }
+            json_t* out_json = json_object();
+            json_object_set_new(out_json, "type", json_string("chain"));
+
+            //Make a new json object for this chain
+            ChainRecord record(chain_child, &snarl_tree_records);
+
+            //Get the start node pointing in
+            net_handle_t start_bound = get_bound(chain_child, false, true);
+            json_t* start_json = json_object();
+            json_object_set_new(start_json, "node_id", json_integer(node_id(start_bound)));
+            json_object_set_new(start_json, "is_rev", json_boolean(ends_at(start_bound) == START));
+            //Set the start node
+            json_object_set_new(out_json, "start_node", start_json);
+
+            //Get the end node pointing in
+            net_handle_t end_bound = get_bound(chain_child, true, true);
+            json_t* end_json = json_object();
+            json_object_set_new(end_json, "node_id", json_integer(node_id(end_bound)));
+            json_object_set_new(end_json, "is_rev", json_boolean(ends_at(end_bound) == START));
+            //Set the end node
+            json_object_set_new(out_json, "end_node", end_json);
+
+            //Set the parent
+            net_handle_t parent = get_parent(chain_child);
+                json_t* parent_json = json_object();
+            if (is_root(parent)) {
+                json_object_set_new(parent_json, "type", json_string("root"));
+            } else {
+                json_object_set_new(parent_json, "type", json_string("snarl"));
+                net_handle_t parent_start = get_bound(parent, false, true);
+                json_object_set_new(parent_json, "start_id", json_integer(node_id(parent_start)));
+                net_handle_t parent_end = get_bound(parent, true, false);
+                json_object_set_new(parent_json, "end_id", json_integer(node_id(parent_end)));
+            }
+            json_object_set_new(out_json, "parent", parent_json);
+
+            //Get the number of children depending on the type of record
+            json_object_set_new(out_json, "child_count", json_integer(record.get_node_count())); 
+
+            //Set the min and max length, if applicable
+            if (record.get_record_type() == DISTANCED_CHAIN) {
+                json_object_set_new(out_json, "minimum_length", json_integer(minimum_length(chain_child))); 
+                json_object_set_new(out_json, "maximum_length", json_integer(maximum_length(chain_child))); 
+            }
+
+            //Set the depth
+            json_object_set_new(out_json, "depth", json_integer(get_depth(chain_child)));
+
+            cout << json_dumps(out_json, JSON_ENCODE_ANY) << endl;
+            return true;
+        }, 
+        [&](const net_handle_t& node_child) {
+            //Iteratee of a node child
+            json_t* out_json = json_object();
+
+            net_handle_t parent = get_parent(node_child);
+            if (is_trivial_chain(parent)) {
+                json_object_set_new(out_json, "type", json_string("trivial_chain"));
+                json_object_set_new(out_json, "node_id", json_integer(node_id(node_child)));
+                net_handle_t grandparent_snarl = get_parent(parent);
+
+                json_t* parent_json = json_object();
+                if (is_root(parent)) {
+                    json_object_set_new(parent_json, "type", json_string("root"));
+                } else {
+                    json_object_set_new(parent_json, "type", json_string("snarl"));
+                    net_handle_t parent_start = get_bound(grandparent_snarl, false, true);
+                    json_object_set_new(parent_json, "start_id", json_integer(node_id(parent_start)));
+                    net_handle_t parent_end = get_bound(grandparent_snarl, true, false);
+                    json_object_set_new(parent_json, "end_id", json_integer(node_id(parent_end)));
+                }
+                json_object_set_new(out_json, "parent", parent_json);
+            } else {
+                //Otherwise this is just a node
+                json_object_set_new(out_json, "type", json_string("node"));
+                json_object_set_new(out_json, "node_id", json_integer(node_id(node_child)));
+
+                json_t* parent_json = json_object();
+                if (is_root(parent)) {
+                    json_object_set_new(parent_json, "type", json_string("root"));
+                } else {
+                    json_object_set_new(parent_json, "type", json_string("chain"));
+                    net_handle_t parent_start = get_bound(parent, false, true);
+                    json_object_set_new(parent_json, "start_id", json_integer(node_id(parent_start)));
+                    net_handle_t parent_end = get_bound(parent, true, false);
+                    json_object_set_new(parent_json, "end_id", json_integer(node_id(parent_end)));
+                }
+                json_object_set_new(out_json, "parent", parent_json);
+            }
+            json_object_set_new(out_json, "length", json_integer(minimum_length(node_child)));
+            cout << json_dumps(out_json, JSON_ENCODE_ANY) << endl;
+            return true;
+        });
+}
+
 void SnarlDistanceIndex::validate_index() const {
     //Go down tree and validate
     net_handle_t root = get_root();
@@ -3376,7 +5629,6 @@ void SnarlDistanceIndex::get_snarl_tree_records(const vector<const TemporaryDist
     cerr << "Convert a temporary distance index into a permanent one" << endl;
 #endif
 
-    //TODO: Make sure not to include trivial chains
     //Convert temporary distance indexes into the final index stored as a single vector
     size_t total_component_count = 0;
     handlegraph::nid_t min_node_id = 0;
@@ -3411,13 +5663,15 @@ void SnarlDistanceIndex::get_snarl_tree_records(const vector<const TemporaryDist
     size_t max_dist_bit_width = bit_width(std::max(maximum_distance, (size_t) max_node_id));
     size_t max_address_bit_width = bit_width(maximum_index_size);
     size_t new_width = std::max(std::max(max_dist_bit_width, max_address_bit_width), (size_t)26); //26 is the size for the simple snarl node count + node lengths
-    snarl_tree_records->width(new_width);//TODO: Fix this
+    snarl_tree_records->width(new_width);
 
+#ifdef debug_distance_indexing
     cerr << "Max index size " << maximum_index_size << endl;
+#endif
     snarl_tree_records->reserve(maximum_index_size);
 
     /*Allocate memory for the root and the nodes */
-    RootRecordConstructor root_record(0, total_component_count, max_node_id-min_node_id+1, maximum_tree_depth, min_node_id, &snarl_tree_records);
+    RootRecordWriter root_record(0, total_component_count, max_node_id-min_node_id+1, maximum_tree_depth, min_node_id, &snarl_tree_records);
 #ifdef debug_distance_indexing
     cerr << "  Root record had length " << snarl_tree_records->size() << endl;
 #endif
@@ -3425,7 +5679,6 @@ void SnarlDistanceIndex::get_snarl_tree_records(const vector<const TemporaryDist
     /*Now go through each of the chain/snarl indexes and copy them into snarl_tree_records
      * Walk down the snarl tree and fill in children
      */
-    //TODO: For now I'm assuming that I'm including distances
     // maps <index into temporary_indexes, <record type, index into chain/snarl/node records>> to new offset
     unordered_map<std::pair<size_t, std::pair<temp_record_t, size_t>>, size_t> record_to_offset;
     //Set the root index
@@ -3439,7 +5692,6 @@ void SnarlDistanceIndex::get_snarl_tree_records(const vector<const TemporaryDist
         //Get a stack of temporary snarl tree records to be added to the index
         //Initially, it contains only the root components
         //This reverses the order of the connected components but I don't think that matters
-        //TODO: this is copying the components but it shouldn't be too big so I think it's fine
         vector<pair<temp_record_t, size_t>> temp_record_stack = temp_index->components;
 
         while (!temp_record_stack.empty()) {
@@ -3464,19 +5716,23 @@ void SnarlDistanceIndex::get_snarl_tree_records(const vector<const TemporaryDist
 #endif
                     record_to_offset.emplace(make_pair(temp_index_i,current_record_index), snarl_tree_records->size());
 
-                    ChainRecordConstructor chain_record_constructor;
+                    ChainRecordWriter chain_record_constructor;
 
                     if (temp_chain_record.chain_components.back() == 0 || snarl_size_limit == 0) {
                         record_t record_type = snarl_size_limit == 0 ? CHAIN : DISTANCED_CHAIN;
-                        chain_record_constructor = ChainRecordConstructor(snarl_tree_records->size(), record_type,
+                        chain_record_constructor = ChainRecordWriter(snarl_tree_records->size(), record_type,
                                                                temp_chain_record.prefix_sum.size(), &snarl_tree_records);
                         chain_record_constructor.set_start_end_connected();
                     } else {
-                        chain_record_constructor = ChainRecordConstructor(snarl_tree_records->size(), MULTICOMPONENT_CHAIN,
+                        chain_record_constructor = ChainRecordWriter(snarl_tree_records->size(), MULTICOMPONENT_CHAIN,
                                                                temp_chain_record.prefix_sum.size(), &snarl_tree_records);
                     }
                     chain_record_constructor.set_parent_record_offset(
-                            record_to_offset[make_pair(temp_index_i, temp_chain_record.parent)]);//TODO: Get the actual parent
+                            record_to_offset[make_pair(temp_index_i, temp_chain_record.parent)]);
+                    chain_record_constructor.set_distance_left_start(temp_chain_record.distance_left_start);
+                    chain_record_constructor.set_distance_right_start(temp_chain_record.distance_right_start);
+                    chain_record_constructor.set_distance_left_end(temp_chain_record.distance_left_end);
+                    chain_record_constructor.set_distance_right_end(temp_chain_record.distance_right_end);
 
                     //If this chain's parent is a root snarl, then the temporary parent is a snarl but we consider 
                     //the parent to be the root and the chain to have depth 1
@@ -3512,6 +5768,10 @@ void SnarlDistanceIndex::get_snarl_tree_records(const vector<const TemporaryDist
                     size_t chain_node_i = 0; //How far along the chain are we?
                     pair<size_t, bool> last_child_offset = make_pair(0, false);
 
+                    //A trivial snarl might not actually be a trivial snarl if it has loops in it. Keep track of whether the last 
+                    //child node actually had a 0 value forward loop, making the last child a non-trivial snarl
+                    bool last_child_was_nontrivial_snarl = false;
+
                     for (size_t child_record_index_i = 0 ; child_record_index_i < temp_chain_record.children.size() ; child_record_index_i++) {
                         const pair<temp_record_t, size_t>& child_record_index = temp_chain_record.children[child_record_index_i];
                         //Go through each node and snarl in the chain and add them to the index
@@ -3521,18 +5781,8 @@ void SnarlDistanceIndex::get_snarl_tree_records(const vector<const TemporaryDist
 
                         if (child_record_index.first == TEMP_NODE) {
                             //Add a node to the chain
-                            if (chain_node_i != 0 && child_record_index == temp_chain_record.children.front()) {
-                                //If this is the last node in the chain, and it is the same as the first node -
-                                // it is a looping chain and we set this and don't re-record the node
-                                // TODO: I'm using externally_start_start_connected here to indicate that 
-                                // it's sharing a start and end node, but chains might actually be allowed to
-                                // be start-end connected in which case I need a new flag
-                                //chain_record_constructor.set_externally_start_end_connected();
-#ifdef debug_distance_indexing
-                            cerr << "    This is a looping chain"  << endl;
-#endif
-
-                            } else {
+                            if (!(chain_node_i != 0 && child_record_index == temp_chain_record.children.front())) {
+                                //If this is not a looping chain, then we haven't seen this node yet
 
                                 //Get the temporary node record
                                 const TemporaryDistanceIndex::TemporaryNodeRecord& temp_node_record = 
@@ -3544,12 +5794,26 @@ void SnarlDistanceIndex::get_snarl_tree_records(const vector<const TemporaryDist
                                         temp_node_record.node_id, temp_node_record.node_length, temp_node_record.reversed_in_parent,
                                         temp_chain_record.prefix_sum[chain_node_i], temp_chain_record.forward_loops[chain_node_i],
                                         temp_chain_record.backward_loops[chain_node_i], temp_chain_record.chain_components[chain_node_i],
-                                        last_child_offset.first);
+                                        temp_chain_record.max_prefix_sum[chain_node_i],
+                                        last_child_offset.first, last_child_was_nontrivial_snarl);
 
                                 //Remember this node as the last thing in the chain
                                 last_child_offset = make_pair(new_offset, false);
+                                if (temp_chain_record.forward_loops[chain_node_i] == 0) {
+                                    last_child_was_nontrivial_snarl = true;
+                                } else {
+                                    last_child_was_nontrivial_snarl = false;
+                                }
+
+                            } 
+#ifdef debug_distance_indexing
+                            else {
 
+                                //If this is the last node in the chain, and it is the same as the first node -
+                                // it is a looping chain and we set this and don't re-record the node
+                            cerr << "    This is a looping chain"  << endl;
                             }
+#endif
 
                             chain_node_i++;
 
@@ -3567,8 +5831,8 @@ void SnarlDistanceIndex::get_snarl_tree_records(const vector<const TemporaryDist
                                 //Add the snarl to the chain, and get back the record to fill it in
 
                                 record_t record_type = snarl_size_limit == 0 ? SNARL :
-                                    (temp_snarl_record.node_count < snarl_size_limit ? DISTANCED_SNARL : OVERSIZED_SNARL);
-                                SnarlRecordConstructor snarl_record_constructor =
+                                    (temp_snarl_record.node_count < snarl_size_limit && !temp_snarl_record.skipped_distances ? DISTANCED_SNARL : OVERSIZED_SNARL);
+                                SnarlRecordWriter snarl_record_constructor =
                                     chain_record_constructor.add_snarl(temp_snarl_record.node_count, record_type, last_child_offset.first);
 
                                 //Record how to find the new snarl record
@@ -3577,47 +5841,43 @@ void SnarlDistanceIndex::get_snarl_tree_records(const vector<const TemporaryDist
                                 //Fill in snarl info
                                 snarl_record_constructor.set_min_length(temp_snarl_record.min_length);
                                 snarl_record_constructor.set_max_length(temp_snarl_record.max_length);
+                                snarl_record_constructor.set_distance_start_start(temp_snarl_record.distance_start_start);
+                                snarl_record_constructor.set_distance_end_end(temp_snarl_record.distance_end_end);
 
                                 //Add distances and record connectivity
                                 for (const auto& it : temp_snarl_record.distances) {
-                                    pair<size_t, size_t> node_rank1 = std::get<0>(it);
-                                    pair<size_t, size_t> node_rank2 = std::get<1>(it);
-                                    const size_t distance = std::get<2>(it);
-
-                                    if (snarl_size_limit != 0 &&
-                                        (temp_snarl_record.node_count < snarl_size_limit ||
-                                         (node_rank1.first == 0 || node_rank1.first == 1 ||
-                                          node_rank2.first == 0 || node_rank2.first == 1))) {
-                                        //If we are keeping track of distances and either this is a small enough snarl,
-                                        //or the snarl is too big but we are looking at the boundaries
-                                        assert(distance <= temp_snarl_record.max_distance);
+                                    pair<size_t, size_t> node_rank1 = it.first.first;
+                                    pair<size_t, size_t> node_rank2 = it.first.second;
+                                    const size_t distance = it.second;
+
+                                    if (snarl_size_limit != 0) {
+                                        //If we are keeping track of distances
+                                        //If the distance exceeded the limit, then it wasn't found in the first place
                                         snarl_record_constructor.set_distance(node_rank1.first, node_rank1.second,
                                             node_rank2.first, node_rank2.second, distance);
+
+                                        if (temp_snarl_record.tippy_child_ranks.count(node_rank1.first)
+                                            && temp_snarl_record.tippy_child_ranks.count(node_rank2.first)) {
+                                            snarl_record_constructor.set_tip_tip_connected();
+                                        }
+#ifdef debug_distance_indexing
+                                        assert(distance <= temp_snarl_record.max_distance);
                                         assert(snarl_record_constructor.get_distance(node_rank1.first, node_rank1.second,
                                                node_rank2.first, node_rank2.second) ==  distance);
+#endif
                                     }
-
-                                    //Now set the connectivity of this snarl
-                                    if (node_rank1.first == 0 && node_rank2.first == 0) {
-                                        snarl_record_constructor.set_start_start_connected();
-                                    } else if ((node_rank1.first == 0 && node_rank2.first == 1) ||
-                                               (node_rank1.first == 1 && node_rank2.first == 0)) {
-                                        snarl_record_constructor.set_start_end_connected();
-                                    } else if (node_rank1.first == 1 && node_rank2.first == 1) {
-                                        snarl_record_constructor.set_end_end_connected();
-                                    } else if ((node_rank1.first == 0 || node_rank2.first == 0) &&
-                                               (temp_snarl_record.tippy_child_ranks.count(node_rank1.first)
-                                                || temp_snarl_record.tippy_child_ranks.count(node_rank2.first))) {
-                                        snarl_record_constructor.set_start_tip_connected();
-                                    } else if ((node_rank1.first == 1 || node_rank2.first == 1) &&
-                                               (temp_snarl_record.tippy_child_ranks.count(node_rank1.first)
-                                                || temp_snarl_record.tippy_child_ranks.count(node_rank2.first))) {
-                                        snarl_record_constructor.set_end_tip_connected();
-                                    } else if (temp_snarl_record.tippy_child_ranks.count(node_rank1.first)
-                                                && temp_snarl_record.tippy_child_ranks.count(node_rank2.first)) {
-                                        snarl_record_constructor.set_tip_tip_connected();
-                                    }
                                 }
+                                //Now set the connectivity of this snarl
+                                if (temp_snarl_record.distance_start_start != std::numeric_limits<size_t>::max()) {
+                                    snarl_record_constructor.set_start_start_connected();
+                                }
+                                if (temp_snarl_record.min_length != std::numeric_limits<size_t>::max()) {
+                                    snarl_record_constructor.set_start_end_connected();
+                                }
+                                if (temp_snarl_record.distance_end_end != std::numeric_limits<size_t>::max()) {
+                                    snarl_record_constructor.set_end_end_connected();
+                                }
+
 #ifdef debug_distance_indexing
                             cerr << "    The snarl record is at offset " << snarl_record_constructor.record_offset << endl;
                             cerr << "    This child snarl has " << snarl_record_constructor.get_node_count() << " children: " << endl;
@@ -3669,7 +5929,7 @@ void SnarlDistanceIndex::get_snarl_tree_records(const vector<const TemporaryDist
                                 //Add the snarl to the chain, and get back the record to fill it in
 
                                 record_t record_type = snarl_size_limit == 0 ? SIMPLE_SNARL : DISTANCED_SIMPLE_SNARL;
-                                SimpleSnarlRecordConstructor snarl_record_constructor =
+                                SimpleSnarlRecordWriter snarl_record_constructor =
                                     chain_record_constructor.add_simple_snarl(temp_snarl_record.node_count, record_type, last_child_offset.first);
 
                                 //Record how to find the new snarl record
@@ -3709,6 +5969,7 @@ void SnarlDistanceIndex::get_snarl_tree_records(const vector<const TemporaryDist
 #endif
                                 last_child_offset = make_pair(snarl_record_constructor.record_offset, true);
                             }
+                            last_child_was_nontrivial_snarl = false;
                         }
                     }
                     //Does the chain loop and is the last node connected to the rest of the chain through the last snarl
@@ -3727,11 +5988,15 @@ void SnarlDistanceIndex::get_snarl_tree_records(const vector<const TemporaryDist
                             temp_index->temp_node_records[temp_chain_record.children[0].second-min_node_id];
 
                     record_t record_type = snarl_size_limit == 0 ? NODE : DISTANCED_NODE;
-                    NodeRecordConstructor node_record(snarl_tree_records->size(), 0, record_type, &snarl_tree_records, temp_node_record.node_id);
+                    NodeRecordWriter node_record(snarl_tree_records->size(), 0, record_type, &snarl_tree_records, temp_node_record.node_id);
                     node_record.set_node_id(temp_node_record.node_id);
                     node_record.set_node_length(temp_node_record.node_length);
                     node_record.set_rank_in_parent(temp_chain_record.rank_in_parent);
                     node_record.set_parent_record_offset(record_to_offset[make_pair(temp_index_i, temp_chain_record.parent)]);
+                    node_record.set_distance_left_start(temp_chain_record.distance_left_start);
+                    node_record.set_distance_right_start(temp_chain_record.distance_right_start);
+                    node_record.set_distance_left_end(temp_chain_record.distance_left_end);
+                    node_record.set_distance_right_end(temp_chain_record.distance_right_end);
 
                     record_to_offset.emplace(make_pair(temp_index_i, current_record_index), node_record.record_offset);
 
@@ -3747,7 +6012,7 @@ void SnarlDistanceIndex::get_snarl_tree_records(const vector<const TemporaryDist
                 const TemporaryDistanceIndex::TemporarySnarlRecord& temp_snarl_record = temp_index->temp_snarl_records[current_record_index.second];
                 record_to_offset.emplace(make_pair(temp_index_i,current_record_index), snarl_tree_records->size());
 
-                SnarlRecordConstructor snarl_record_constructor (temp_snarl_record.node_count, &snarl_tree_records, record_type);
+                SnarlRecordWriter snarl_record_constructor (temp_snarl_record.node_count, &snarl_tree_records, record_type);
 
                 //Fill in snarl info
                 snarl_record_constructor.set_parent_record_offset(0);
@@ -3758,18 +6023,15 @@ void SnarlDistanceIndex::get_snarl_tree_records(const vector<const TemporaryDist
 
 
                     for (const auto& it : temp_snarl_record.distances) {
-                        const pair<size_t, bool> node_rank1 = std::get<0>(it);
-                        const pair<size_t, bool> node_rank2 = std::get<1>(it);
-                        const size_t distance = std::get<2>(it);
-                        //TODO: I"m checking this but also automatically making a distanced snarl
+                        const pair<size_t, bool> node_rank1 = it.first.first;
+                        const pair<size_t, bool> node_rank2 = it.first.second;
+                        const size_t distance = it.second;
                         //If we are keeping track of distances and either this is a small enough snarl,
                         //or the snarl is too big but we are looking at the boundaries
 #ifdef debug_distance_indexing
                         assert(distance <= temp_snarl_record.max_distance);
 #endif
-                        if ((temp_snarl_record.node_count < snarl_size_limit ||
-                                     (node_rank1.first == 0 || node_rank1.first == 1 ||
-                                      node_rank2.first == 0 || node_rank2.first == 1))) {
+                        if ((temp_snarl_record.node_count < snarl_size_limit)) {
                             snarl_record_constructor.set_distance(node_rank1.first, node_rank1.second,
                              node_rank2.first, node_rank2.second, distance);
 #ifdef debug_distance_indexing
@@ -3789,7 +6051,6 @@ void SnarlDistanceIndex::get_snarl_tree_records(const vector<const TemporaryDist
                 }
 
             } else {
-                //TODO: This was a node that was a tip, so it wasn't put in a chain by the temporary index
                 assert(current_record_index.first == TEMP_NODE);
                 //and then add them all after adding the snarl
 #ifdef debug_distance_indexing
@@ -3799,12 +6060,17 @@ void SnarlDistanceIndex::get_snarl_tree_records(const vector<const TemporaryDist
                 const TemporaryDistanceIndex::TemporaryNodeRecord& temp_node_record =
                         temp_index->temp_node_records[current_record_index.second-min_node_id];
                 record_t record_type = snarl_size_limit == 0 ? NODE : DISTANCED_NODE;
-                NodeRecordConstructor node_record(snarl_tree_records->size(), 0, record_type, &snarl_tree_records, temp_node_record.node_id);
+                NodeRecordWriter node_record(snarl_tree_records->size(), 0, record_type, &snarl_tree_records, temp_node_record.node_id);
                 node_record.set_node_id(temp_node_record.node_id);
                 node_record.set_node_length(temp_node_record.node_length);
                 node_record.set_rank_in_parent(temp_node_record.rank_in_parent);
                 node_record.set_parent_record_offset(record_to_offset[make_pair(temp_index_i, temp_node_record.parent)]);
 
+                node_record.set_distance_left_start(temp_node_record.distance_left_start);
+                node_record.set_distance_right_start(temp_node_record.distance_right_start);
+                node_record.set_distance_left_end(temp_node_record.distance_left_end);
+                node_record.set_distance_right_end(temp_node_record.distance_right_end);
+
                 record_to_offset.emplace(make_pair(temp_index_i, current_record_index), node_record.record_offset);
             }
 #ifdef debug_distance_indexing
@@ -3822,7 +6088,7 @@ void SnarlDistanceIndex::get_snarl_tree_records(const vector<const TemporaryDist
 
             SnarlTreeRecord record (record_to_offset[make_pair(temp_index_i, component_index)],
                                     &snarl_tree_records);
-            SnarlTreeRecordConstructor record_constructor(record_to_offset[make_pair(temp_index_i, component_index)],
+            SnarlTreeRecordWriter record_constructor(record_to_offset[make_pair(temp_index_i, component_index)],
                                                               &snarl_tree_records);
 
             if (record.get_record_handle_type() == CHAIN_HANDLE || record.get_record_handle_type() == ROOT_HANDLE) {
@@ -3877,16 +6143,43 @@ void SnarlDistanceIndex::get_snarl_tree_records(const vector<const TemporaryDist
             const TemporaryDistanceIndex::TemporarySnarlRecord& temp_snarl_record = temp_index->temp_snarl_records[temp_snarl_i];
             if (!temp_snarl_record.is_trivial && !temp_snarl_record.is_simple) {
                 //And a constructor for the permanent record, which we've already created
-                SnarlRecordConstructor snarl_record_constructor (&snarl_tree_records,
+                SnarlRecordWriter snarl_record_constructor (&snarl_tree_records,
                         record_to_offset[make_pair(temp_index_i, make_pair(TEMP_SNARL, temp_snarl_i))]);
                 //Now add the children and tell the record where to find them
                 snarl_record_constructor.set_child_record_pointer(snarl_tree_records->size());
                 for (pair<temp_record_t, size_t> child : temp_snarl_record.children) {
                     snarl_record_constructor.add_child(record_to_offset[make_pair(temp_index_i, child)]);
+
+                    //Check if the child is a tip, and if so set start/end_tip connectivity of parent snarl
+                    if (child.first == TEMP_NODE) {
+                        auto temp_node_record = temp_index->temp_node_records[child.second-min_node_id];
+                        if (temp_node_record.is_tip) {
+                            if (temp_node_record.distance_left_start != std::numeric_limits<size_t>::max() ||
+                                 temp_node_record.distance_right_start != std::numeric_limits<size_t>::max()){
+                                snarl_record_constructor.set_start_tip_connected();
+                            }
+                            if (temp_node_record.distance_left_end != std::numeric_limits<size_t>::max() ||
+                                 temp_node_record.distance_right_end != std::numeric_limits<size_t>::max()){
+                                snarl_record_constructor.set_end_tip_connected();
+                            }
+                        }
+                    } else {
+                        auto temp_chain_record = temp_index->temp_chain_records[child.second];
+                        if (temp_chain_record.is_tip) {
+                            if (temp_chain_record.distance_left_start != std::numeric_limits<size_t>::max() ||
+                                 temp_chain_record.distance_right_start != std::numeric_limits<size_t>::max()){
+                                snarl_record_constructor.set_start_tip_connected();
+                            }
+                            if (temp_chain_record.distance_left_end != std::numeric_limits<size_t>::max() ||
+                                 temp_chain_record.distance_right_end != std::numeric_limits<size_t>::max()){
+                                snarl_record_constructor.set_end_tip_connected();
+                            }
+                        }
+                    }
 #ifdef debug_distance_indexing
                 cerr << "       child " << temp_index->structure_start_end_as_string(child) << endl;
                 cerr << "        " << child.first << " " << child.second << endl;
-                cerr << "        Add child " << net_handle_as_string(get_net_handle(record_to_offset[make_pair(temp_index_i, child)], START_END))
+                cerr << "        Add child " << net_handle_as_string(get_net_handle_from_values(record_to_offset[make_pair(temp_index_i, child)], START_END))
                      << "     at offset " << record_to_offset[make_pair(temp_index_i, child)]
                      << "     to child list at offset " << snarl_tree_records->size() << endl;
 #endif
@@ -3894,8 +6187,10 @@ void SnarlDistanceIndex::get_snarl_tree_records(const vector<const TemporaryDist
             }
         }
     }
+#ifdef debug_distance_indexing
     //Repack the vector to use fewer bits
-    //TODO: Wouldn't have to do this if I could predict the vector better
+    //This doesn't actually get used anymore but keep it around in case I change things and can't
+    //predict the size anymore
     size_t max_val = 0;
     for (size_t i = 0 ; i < snarl_tree_records->size() ; i++ ) {
         max_val = std::max(max_val, (size_t) snarl_tree_records->at(i));
@@ -3905,6 +6200,8 @@ void SnarlDistanceIndex::get_snarl_tree_records(const vector<const TemporaryDist
         cerr << "Resetting bit width from " << snarl_tree_records->width() << " to " << ideal_bit_width << endl;
         //snarl_tree_records->repack(ideal_bit_width, snarl_tree_records->size());
     }
+#endif
+#ifdef debug_distance_indexing
     tuple<size_t, size_t, size_t> usage =get_usage();
     cerr << "total\t" << snarl_tree_records->size() << endl;
     cerr << "Usage: " << std::get<0>(usage) << " total bytes, " << std::get<1>(usage) << " free bytes " << std::get<2>(usage) << " reclaimable free bytes " << endl;
@@ -3912,7 +6209,6 @@ void SnarlDistanceIndex::get_snarl_tree_records(const vector<const TemporaryDist
     cerr << "Max value " << max_val << endl;
     cerr << "Predicted size: " << maximum_index_size << " actual size: " <<  snarl_tree_records->size() << endl;
     //assert(maximum_index_size == snarl_tree_records->size());
-#ifdef debug_distance_indexing
     cerr << "Predicted size: " << maximum_index_size << " actual size: " <<  snarl_tree_records->size() << endl;
     //assert(snarl_tree_records->size() <= maximum_index_size); 
 #endif
@@ -3931,8 +6227,6 @@ void SnarlDistanceIndex::get_snarl_tree_records(const vector<const TemporaryDist
 
 //TODO: Also need to go the other way, from final index to temporary one for merging
 
-//TODO: Probably don't want to keep this
-
 void SnarlDistanceIndex::time_accesses() {
     cerr << "Distance index:" << endl;
     cerr << "Vector of length " << snarl_tree_records->size() << " with bit width " << snarl_tree_records->width() << endl;


Test patch:
diff --git a/.github/workflows/testmac.yml b/.github/workflows/testmac.yml
index 95fcaf5d..5b7e5e93 100644
--- a/.github/workflows/testmac.yml
+++ b/.github/workflows/testmac.yml
@@ -26,7 +26,7 @@ jobs:
       - name: Run build and test
         run: |
           set -e
-          brew install libomp doxygen
+          brew install libomp doxygen jansson
           mkdir -p build
           cd build
           cmake .. -DRUN_DOXYGEN=ON -DPYTHON_EXECUTABLE="$(which python3)"