diff --git a/kwant/physics/selfenergy.py b/kwant/physics/selfenergy.py
index 5c0814c9b89f0d4bba60516051e15cecc4834646..cd9af0c7bfa79cec4e0cebbb02090da3adf845a7 100644
--- a/kwant/physics/selfenergy.py
+++ b/kwant/physics/selfenergy.py
@@ -1,5 +1,6 @@
 from __future__ import division
 from math import sin, cos, sqrt, pi, copysign
+from collections import namedtuple
 import numpy as np
 import numpy.linalg as npl
 import scipy.linalg as la
@@ -7,7 +8,7 @@ import kwant.linalg as kla
 
 dot = np.dot
 
-__all__ = [ 'self_energy', 'modes' ]
+__all__ = ['self_energy', 'modes', 'Modes']
 
 def setup_linsys(h_onslice, h_hop, tol=1e6):
     """
@@ -569,12 +570,12 @@ def self_energy(h_onslice, h_hop, tol=1e6):
         #       eigenvectors will be real, too.
 
         if nprop > 0:
-            nrmodes = np.sum(rselect)
-            vecs[:, : nrmodes] = prop_vecs[:, rselect]
+            nmodes = np.sum(rselect)
+            vecs[:, : nmodes] = prop_vecs[:, rselect]
         else:
-            nrmodes = 0
+            nmodes = 0
 
-        vecs[:, nrmodes:] = vec_gen(select)
+        vecs[:, nmodes:] = vec_gen(select)
 
         if v is not None:
             return dot(v * w, dot(vecs[n :], dot(npl.inv(vecs[: n]),
@@ -596,6 +597,8 @@ def self_energy(h_onslice, h_hop, tol=1e6):
         else:
             return dot(h_hop.T.conj(), dot(z[n:, : n], npl.inv(z[: n, : n])))
 
+Modes = namedtuple('Modes', ['vecs', 'vecslmbdainv', 'nmodes', 'svd'])
+
 def modes(h_onslice, h_hop, tol=1e6):
     """
     Compute the eigendecomposition of a translation operator of a lead.
@@ -610,15 +613,13 @@ def modes(h_onslice, h_hop, tol=1e6):
 
     Returns
     -------
-    vecs : numpy matrix
-        the matrix of eigenvectors of translation operator.
-    vecslmbdainv : numpy matrix
-        the matrix of eigenvectors multiplied with their corresponding inverse
-        eigenvalue.
-    nrmodes : integer
-        number of propagating modes in either direction.
-    (u, s, v) : singular value decomposition of the hopping matrix.
-        If `h_hop` is invertible, a single None is returned instead.
+    (vecs, vecslmbdainv, nmodes, svd) : Modes
+        `vecs` is the matrix of eigenvectors of the translation operator.
+        `vecslmbdainv` is the matrix of eigenvectors multiplied with their
+        corresponding inverse eigenvalue.  `nmodes` is the number of
+        propagating modes in either direction.  `svd` is a tuple (u, s, v)
+        holding the singular value decomposition of the hopping matrix, or a
+        single None if `h_hop` is invertible.
 
     Notes
     -----
@@ -629,7 +630,7 @@ def modes(h_onslice, h_hop, tol=1e6):
     If it is singular, the projections (u^dagger psi, v^dagger psi lambda^-1)
     are returned.
 
-    First `nrmodes` are incoming, second `nrmodes` are reflected, the rest are
+    First `nmodes` are incoming, second `nmodes` are reflected, the rest are
     evanescent.
 
     Propagating modes with the same lambda are orthogonalized. All the
@@ -648,7 +649,7 @@ def modes(h_onslice, h_hop, tol=1e6):
     if not np.any(h_hop):
         n = h_hop.shape[0]
         svd = (np.empty((n, 0)), np.empty((0, 0)), np.empty((0, m)))
-        return np.empty((0, 0)), np.empty((0, 0)), 0, svd
+        return Modes(np.empty((0, 0)), np.empty((0, 0)), 0, svd)
 
     # Defer most of the calculation to a helper routine.
     ev, evanselect, propselect, vec_gen, ord_schur, \
@@ -686,7 +687,7 @@ def modes(h_onslice, h_hop, tol=1e6):
         prop_vecs /= maxnode
 
         lprop = np.logical_not(rprop)
-        nrmodes = np.sum(rprop)
+        nmodes = np.sum(rprop)
         vecs = np.c_[prop_vecs[n:, lprop], prop_vecs[n:, rprop],
                      evan_vecs[n:]]
         vecslmbdainv = np.c_[prop_vecs[: n, lprop], prop_vecs[: n, rprop],
@@ -695,12 +696,10 @@ def modes(h_onslice, h_hop, tol=1e6):
     else:
         vecs = evan_vecs[n:]
         vecslmbdainv = evan_vecs[: n]
-        nrmodes = 0
+        nmodes = 0
 
-    if s is not None:
-        return vecs, vecslmbdainv, nrmodes, (u, s, v)
-    else:
-        return vecs, vecslmbdainv, nrmodes, None
+    svd = None if s is None else (u, s, v)
+    return Modes(vecs, vecslmbdainv, nmodes, svd)
 
 
 def square_self_energy(width, hopping, potential, fermi_energy):
diff --git a/kwant/solvers/sparse.py b/kwant/solvers/sparse.py
index 86d2c0877eee2c1dca42162b41901232fba2dd1a..cdaa1b31a1ba28a512a0c7d93b7e75ad6f6d31b7 100644
--- a/kwant/solvers/sparse.py
+++ b/kwant/solvers/sparse.py
@@ -394,11 +394,12 @@ def ldos(fsys, e=0):
     ldos : a numpy array
         local density of states at each orbital of the system.
     """
+    Modes = physics.Modes
     linsys = make_linear_sys(fsys, [], [], e)
     num_extra_vars = 0
     for i in linsys[-1]:
-        if isinstance(i, tuple):
-            num_extra_vars += i[0].shape[1] - i[2]
+        if isinstance(i, Modes):
+            num_extra_vars += i.vecs.shape[1] - i.nmodes
     a = linsys[0]
     slv = factorized(a)
     num_orb = a.shape[0] - num_extra_vars