diff --git a/doc/source/pre/whatsnew/1.1.rst b/doc/source/pre/whatsnew/1.1.rst
index c53199844f416d8491deae5d831aa99d6beb22a6..12f8c505a27c2ef369200893c05d55fac9311c1a 100644
--- a/doc/source/pre/whatsnew/1.1.rst
+++ b/doc/source/pre/whatsnew/1.1.rst
@@ -38,3 +38,25 @@ be thus done as follows::
 
 Note how we set the onsite Hamiltonians of the sites that have been added to
 the value used in the system.
+
+New method ``conductance_matrix``
+---------------------------------
+`~kwant.solvers.common.SMatrix` and `~kwant.solvers.common.GreensFunction`
+have each gained a method ``conductance_matrix`` that returns the matrix
+:math:`G` such that :math:`I = GV` where :math:`I` and :math:`V` are,
+respectively, the vectors of currents and voltages for all the leads.  This
+matrix is useful for calculating non-local resistances. See Section 2.4 of the
+book by S. Datta.
+
+Deduction of transmission probabilities
+---------------------------------------
+If `kwant.smatrix` or `kwant.greens_function` have been called with
+``check_hermicity=True`` (on by default) and a restricted number of leads in
+the ``out_leads`` and ``in_leads`` parameters, calls to ``transmission`` and
+``conductance_matrix`` will work whenever it is possible to deduce the result
+from current conservation.
+
+This allows leaving out one lead (preferably the widest) from ``out_leads``
+and ``in_leads``, and still to calculate all transmission probabilities.
+Doing so has been measured to speed up computations by 20% in some
+cases.
diff --git a/kwant/solvers/common.py b/kwant/solvers/common.py
index 545092d88aed504556f20bd6701d4dc87e8a770b..68479c8cfb631504de85e4f0ef9c9bd0145948b6 100644
--- a/kwant/solvers/common.py
+++ b/kwant/solvers/common.py
@@ -9,6 +9,7 @@
 __all__ = ['SparseSolver', 'SMatrix', 'GreensFunction']
 
 from collections import namedtuple
+from itertools import product
 import abc
 import numpy as np
 import scipy.sparse as sp
@@ -107,6 +108,7 @@ class SparseSolver(object):
             Positional arguments to pass to the ``hamiltonian`` method.
         check_hermiticity : bool
             Check if Hamiltonian matrices are in fact Hermitian.
+            Enables deduction of missing transmission coefficients.
         realspace : bool
             Calculate Green's function between the outermost lead
             sites, instead of lead modes. This is almost always
@@ -302,6 +304,7 @@ class SparseSolver(object):
             "all leads".
         check_hermiticity : ``bool``
             Check if the Hamiltonian matrices are Hermitian.
+            Enables deduction of missing transmission coefficients.
 
         Returns
         -------
@@ -349,8 +352,8 @@ class SparseSolver(object):
         len_rhs = sum(i.shape[1] for i in linsys.rhs)
         len_kv = len(kept_vars)
         if not(len_rhs and len_kv):
-            return SMatrix(np.zeros((len_kv, len_rhs)),
-                               lead_info, out_leads, in_leads)
+            return SMatrix(np.zeros((len_kv, len_rhs)), lead_info,
+                           out_leads, in_leads, check_hermiticity)
 
         # See comment about zero-shaped sparse matrices at the top of common.py.
         rhs = sp.bmat([[i for i in linsys.rhs if i.shape[1]]],
@@ -358,7 +361,7 @@ class SparseSolver(object):
         flhs = self._factorized(linsys.lhs)
         data = self._solve_linear_sys(flhs, rhs, kept_vars)
 
-        return SMatrix(data, lead_info, out_leads, in_leads)
+        return SMatrix(data, lead_info, out_leads, in_leads, check_hermiticity)
 
     def greens_function(self, sys, energy=0, args=(),
                         out_leads=None, in_leads=None, check_hermiticity=True):
@@ -384,6 +387,7 @@ class SparseSolver(object):
             "all leads".
         check_hermiticity : ``bool``
             Check if the Hamiltonian matrices are Hermitian.
+            Enables deduction of missing transmission coefficients.
 
         Returns
         -------
@@ -434,8 +438,8 @@ class SparseSolver(object):
         len_rhs = sum(i.shape[1] for i in linsys.rhs)
         len_kv = len(kept_vars)
         if not(len_rhs and len_kv):
-            return GreensFunction(np.zeros((len_kv, len_rhs)),
-                               lead_info, out_leads, in_leads)
+            return GreensFunction(np.zeros((len_kv, len_rhs)), lead_info,
+                                  out_leads, in_leads, check_hermiticity)
 
         # See comment about zero-shaped sparse matrices at the top of common.py.
         rhs = sp.bmat([[i for i in linsys.rhs if i.shape[1]]],
@@ -443,7 +447,8 @@ class SparseSolver(object):
         flhs = self._factorized(linsys.lhs)
         data = self._solve_linear_sys(flhs, rhs, kept_vars)
 
-        return GreensFunction(data, lead_info, out_leads, in_leads)
+        return GreensFunction(data, lead_info, out_leads, in_leads,
+                              check_hermiticity)
 
     def ldos(self, sys, energy=0, args=(), check_hermiticity=True):
         """
@@ -554,16 +559,18 @@ class WaveFunction(object):
 
 class BlockResult(object):
     """
-    Container for a linear system solution with variable grouping.
-
-    This class is not intended to be used directly.
+    ABC for a linear system solution with variable grouping.
     """
-    def __init__(self, data, lead_info, out_leads, in_leads, sizes):
+    __metaclass__ = abc.ABCMeta
+
+    def __init__(self, data, lead_info, out_leads, in_leads, sizes,
+                 current_conserving=False):
         self.data = data
         self.lead_info = lead_info
         self.out_leads = out_leads = list(out_leads)
         self.in_leads = in_leads = list(in_leads)
         self.sizes = sizes = np.array(sizes)
+        self.current_conserving = current_conserving
         self.in_offsets = np.zeros(len(in_leads) + 1, int)
         self.in_offsets[1 :] = np.cumsum(self.sizes[in_leads])
         self.out_offsets = np.zeros(len(self.out_leads) + 1, int)
@@ -594,6 +601,77 @@ class BlockResult(object):
         """Return the matrix elements from lead_in to lead_out."""
         return self.data[self.block_coords(lead_out, lead_in)]
 
+    @abc.abstractmethod
+    def num_propagating(self, lead):
+        """Return the number of propagating modes in the lead."""
+        pass
+
+    @abc.abstractmethod
+    def _transmission(self, lead_out, lead_in):
+        """Return transmission from lead_in to lead_out.
+
+        The calculation is expected to be done directly from the corresponding
+        matrix elements.
+        """
+        pass
+
+    def transmission(self, lead_out, lead_in):
+        """Return transmission from lead_in to lead_out.
+
+        If the option ``current_conserving`` has been enabled for this object,
+        this method will deduce missing transmission values whenever possible.
+
+        Current conservation is enabled by default for objects returned by
+        `~kwant.solvers.default.smatrix` and
+        `~kwant.solvers.default.greens_function` whenever the Hamiltonian has
+        been verified to be Hermitian (option ``check_hermiticity``, enabled by
+        default).
+
+        """
+        chosen = [lead_out, lead_in]
+        present = self.out_leads, self.in_leads
+        # OK means: chosen (outgoing, incoming) lead is present.
+        ok = [int(c in p) for c, p in zip(chosen, present)]
+        if all(ok):
+            return self._transmission(lead_out, lead_in)
+
+        if self.current_conserving:
+            all_but_one = len(self.lead_info) - 1
+            s_t = self._transmission
+            if sum(ok) == 1:
+                # Calculate the transmission element by summing over a single
+                # row or column.
+                sum_dim, ok_dim = ok
+                if len(present[sum_dim]) == all_but_one:
+                    return (self.num_propagating(chosen[ok_dim]) - sum(
+                        s_t(*chosen) for chosen[sum_dim] in present[sum_dim]))
+            elif all(len(p) == all_but_one for p in present):
+                # Calculate the transmission element at the center of a single
+                # missing row and a single missing column.
+                return (sum(s_t(o, i) - self.num_propagating(o) if o == i else 0
+                            for o, i in product(*present)))
+
+        raise ValueError("Insufficient matrix elements to compute "
+                         "transmission({0}, {1}).".format(*chosen))
+
+    def conductance_matrix(self):
+        """Return the conductance matrix.
+
+        This is the matrix :math:`C` such that :math:`I = CV` where :math:`I`
+        and :math:`V` are, respectively, the vectors of currents and voltages
+        for each lead.
+
+        This matrix is useful for calculating non-local resistances.  See
+        Section 2.4 of the book by S. Datta.
+        """
+        n = len(self.lead_info)
+        rn = xrange(n)
+        result = np.array([[-self.transmission(i, j) if i != j else 0
+                            for j in rn] for i in rn])
+        # Set the diagonal elements such that the sums of columns are zero.
+        result.flat[::n+1] = -result.sum(axis=0)
+        return result
+
 
 class SMatrix(BlockResult):
     """A scattering matrix.
@@ -623,13 +701,17 @@ class SMatrix(BlockResult):
         calculated result.
     """
 
-    def __init__(self, data, lead_info, out_leads, in_leads):
+    def __init__(self, data, lead_info, out_leads, in_leads,
+                 current_conserving=False):
         sizes = [len(i.momenta) // 2 for i in lead_info]
         super(SMatrix, self).__init__(data, lead_info, out_leads, in_leads,
-                                      sizes)
+                                      sizes, current_conserving)
 
-    def transmission(self, lead_out, lead_in):
-        """Return transmission from lead_in to lead_out."""
+    def num_propagating(self, lead):
+        """Return the number of propagating modes in the lead."""
+        return self.sizes[lead]
+
+    def _transmission(self, lead_out, lead_in):
         return np.linalg.norm(self.submatrix(lead_out, lead_in)) ** 2
 
     def __repr__(self):
@@ -666,10 +748,24 @@ class GreensFunction(BlockResult):
         calculated result.
     """
 
-    def __init__(self, data, lead_info, out_leads, in_leads):
+    def __init__(self, data, lead_info, out_leads, in_leads,
+                 current_conserving=False):
         sizes = [i.shape[0] for i in lead_info]
-        super(GreensFunction, self).__init__(data, lead_info, out_leads,
-                                             in_leads, sizes)
+        super(GreensFunction, self).__init__(
+            data, lead_info, out_leads, in_leads, sizes, current_conserving)
+
+    def num_propagating(self, lead):
+        """Return the number of propagating modes in the lead."""
+        gamma = 1j * (self.lead_info[lead] -
+                      self.lead_info[lead].conj().T)
+
+        # The number of channels is given by the number of
+        # nonzero eigenvalues of Gamma
+        # rationale behind the threshold from
+        # Golub; van Loan, chapter 5.5.8
+        eps = np.finfo(gamma.dtype).eps * 1000
+        return np.sum(np.linalg.eigvalsh(gamma) >
+                      eps * np.linalg.norm(gamma, np.inf))
 
     def _a_ttdagger_a_inv(self, lead_out, lead_in):
         """Return t * t^dagger in a certain basis."""
@@ -681,8 +777,7 @@ class GreensFunction(BlockResult):
             factors.append(gf2)
         return reduce(np.dot, factors)
 
-    def transmission(self, lead_out, lead_in):
-        """Return transmission from lead_in to lead_out."""
+    def _transmission(self, lead_out, lead_in):
         gf = self.submatrix(lead_out, lead_in)
         factors = []
         for lead, gf2 in ((lead_out, gf), (lead_in, gf.conj().T)):
diff --git a/kwant/solvers/tests/_test_sparse.py b/kwant/solvers/tests/_test_sparse.py
index 737c720d58122792a5edd6808151d7d764b25981..4754e3ee96668222e8ec62db29251a5d4002feae 100644
--- a/kwant/solvers/tests/_test_sparse.py
+++ b/kwant/solvers/tests/_test_sparse.py
@@ -1,4 +1,4 @@
-# Copyright 2011-2013 Kwant authors.
+# Copyright 2011-2014 Kwant authors.
 #
 # This file is part of Kwant.  It is subject to the license terms in the
 # LICENSE file found in the top-level directory of this distribution and at
@@ -7,6 +7,7 @@
 # http://kwant-project.org/authors.
 
 from __future__ import division
+from math import cos, sin
 import numpy as np
 from nose.tools import assert_raises
 from numpy.testing import assert_equal, assert_almost_equal
@@ -285,6 +286,62 @@ def test_tricky_singular_hopping(smatrix):
                         np.identity(s.shape[0]))
 
 
+# Test the consistency of transmission and conductance_matrix for a four-lead
+# system without time-reversal symmetry.
+def test_many_leads(*factories):
+    E=2.1
+    B=0.01
+
+    def phase(a, b):
+        ap = a.pos
+        bp = b.pos
+        phase = -B * (0.5 * (ap[1] + bp[1]) * (bp[0] - ap[0]))
+        return -complex(cos(phase), sin(phase))
+
+    # Build a square system with four leads and a hole in the center.
+    sys = kwant.Builder()
+    sys[(sq(x, y) for x in xrange(-4, 4) for y in xrange(-4, 4)
+         if x**2 + y**2 >= 2)] = 3
+    sys[sq.neighbors()] = phase
+    for r in [xrange(-4, -1), xrange(4)]:
+        lead = kwant.Builder(kwant.TranslationalSymmetry([-1, 0]))
+        lead[(sq(0, y) for y in r)] = 4
+        lead[sq.neighbors()] = phase
+        sys.attach_lead(lead)
+        sys.attach_lead(lead.reversed())
+    sys = sys.finalized()
+
+    r4 = range(4)
+    br = factories[0](sys, E, out_leads=r4, in_leads=r4)
+    trans = np.array([[br._transmission(i, j) for j in r4] for i in r4])
+    cmat = br.conductance_matrix()
+    assert_almost_equal(cmat.sum(axis=0), [0] * 4)
+    assert_almost_equal(cmat.sum(axis=1), [0] * 4)
+    for i in r4:
+        for j in r4:
+            assert_almost_equal(
+                (br.num_propagating(i) if i == j else 0) - cmat[i, j],
+                trans[i, j])
+
+    for out_leads, in_leads in [(r4, r4), ((1, 2, 3), r4), (r4, (0, 2, 3)),
+                                ((1, 3), (1, 2, 3)), ((0, 2), (0, 1, 2)),
+                                ((0, 1,), (1, 2)), ((3,), (3,))]:
+        for f in factories:
+            br = f(sys, E, out_leads=out_leads, in_leads=in_leads)
+            if len(out_leads) == 3:
+                out_leads = r4
+            if len(in_leads) == 3:
+                in_leads = r4
+            for i in r4:
+                for j in r4:
+                    if i in out_leads and j in in_leads:
+                        assert_almost_equal(br.transmission(i, j), trans[i, j])
+                    else:
+                        assert_raises(ValueError, br.transmission, i, j)
+            if len(out_leads) == len(in_leads) == 4:
+                assert_almost_equal(br.conductance_matrix(), cmat)
+
+
 # Test equivalence between self-energy and scattering matrix representations.
 # Also check that transmission works.
 def test_selfenergy(greens_function, smatrix):
diff --git a/kwant/solvers/tests/test_mumps.py b/kwant/solvers/tests/test_mumps.py
index c28f263bb79776f7c9fb2368e6a624be37e68325..a2007c029103220fdbe4c89cfb17dc20ded53391 100644
--- a/kwant/solvers/tests/test_mumps.py
+++ b/kwant/solvers/tests/test_mumps.py
@@ -1,4 +1,4 @@
-# Copyright 2011-2013 Kwant authors.
+# Copyright 2011-2014 Kwant authors.
 #
 # This file is part of Kwant.  It is subject to the license terms in the
 # LICENSE file found in the top-level directory of this distribution and at
@@ -80,6 +80,14 @@ def test_tricky_singular_hopping():
         _test_sparse.test_tricky_singular_hopping(smatrix)
 
 
+@skipif(no_mumps)
+def test_many_leads():
+    for opts in opt_list:
+        reset_options()
+        options(**opts)
+        _test_sparse.test_many_leads(greens_function, smatrix)
+
+
 @skipif(no_mumps)
 def test_selfenergy():
     for opts in opt_list:
diff --git a/kwant/solvers/tests/test_sparse.py b/kwant/solvers/tests/test_sparse.py
index 33d059115e5b24265c356280f677c99886223bb7..0f9b6b2879fed47c77eb5c29a81dc6f3b7e7b3b1 100644
--- a/kwant/solvers/tests/test_sparse.py
+++ b/kwant/solvers/tests/test_sparse.py
@@ -1,4 +1,4 @@
-# Copyright 2011-2013 Kwant authors.
+# Copyright 2011-2014 Kwant authors.
 #
 # This file is part of Kwant.  It is subject to the license terms in the
 # LICENSE file found in the top-level directory of this distribution and at
@@ -39,6 +39,10 @@ def test_tricky_singular_hopping():
     _test_sparse.test_tricky_singular_hopping(smatrix)
 
 
+def test_many_leads():
+    _test_sparse.test_many_leads(greens_function, smatrix)
+
+
 def test_selfenergy():
     _test_sparse.test_selfenergy(greens_function, smatrix)