From a12ec3c34d907a6bbf3c2a4d0e114826d24f46c8 Mon Sep 17 00:00:00 2001
From: Anton Akhmerov <anton.akhmerov@gmail.com>
Date: Sat, 2 Feb 2013 12:08:49 -0500
Subject: [PATCH] remove Builder.default_site_group

---
 kwant/builder.py                    | 159 +++++++-------------
 kwant/solvers/tests/_test_sparse.py |  52 +++----
 kwant/tests/test_builder.py         | 217 ++++++++++++++--------------
 kwant/tests/test_system.py          |  21 ++-
 4 files changed, 194 insertions(+), 255 deletions(-)

diff --git a/kwant/builder.py b/kwant/builder.py
index 52a0771a..99313b69 100644
--- a/kwant/builder.py
+++ b/kwant/builder.py
@@ -403,53 +403,35 @@ class SelfEnergy(Lead):
 
 ################ Builder class
 
-def is_sitelike(key):
-    """Determine whether key is similar to a site.
-
-    Returns True if `key` is potentially sitelike, False if `key` is
-    potentially hoppinglike, None if it is neither."""
-    if isinstance(key, Site):
-        return True
-    if not isinstance(key, tuple):
-        return None
-    if not key:
-        raise KeyError(key)
-    first = key[0]
-    return not (isinstance(first, Site) or isinstance(first, tuple))
-
 
 def for_each_in_key(key, f_site, f_hopp):
     """Perform an operation on each site or hopping in key.
 
     Key may be
-    * a single sitelike or hoppinglike object,
-    * a non-tuple iterable of sitelike objects,
-    * a non-tuple iterable of hoppinglike objects.
+    * a single site or hopping object,
+    * a non-tuple iterable of sites,
+    * a non-tuple iterable of hoppings.
     """
-    isl = is_sitelike(key)
-    if isl is not None:
-        if isl:
-            f_site(key)
-        else:
+    if isinstance(key, Site):
+        f_site(key)
+    elif isinstance(key, tuple):
             f_hopp(key)
-    elif isinstance(key, Iterable) and not isinstance(key, tuple):
+    elif isinstance(key, Iterable):
         ikey = iter(key)
         try:
             first = next(ikey)
         except StopIteration:
             return
-        isl = is_sitelike(first)
-        if isl is None:
-            raise KeyError(first)
+        if isinstance(first, Site):
+            f_site(first)
+            for site in ikey:
+                f_site(site)
+        elif isinstance(first, tuple):
+            f_hopp(first)
+            for hopping in ikey:
+                f_hopp(hopping)
         else:
-            if isl:
-                f_site(first)
-                for sitelike in ikey:
-                    f_site(sitelike)
-            else:
-                f_hopp(first)
-                for hoppinglike in ikey:
-                    f_hopp(hoppinglike)
+            raise KeyError(first)
     else:
         raise KeyError(key)
 
@@ -458,6 +440,7 @@ def for_each_in_key(key, f_site, f_hopp):
 # conjugate the value of the hopping (j, i).  Used by Builder and System.
 other = []
 
+
 def edges(seq):
     # izip, when given the same iterator twice, turns a sequence into a
     # sequence of pairs.
@@ -466,6 +449,7 @@ def edges(seq):
     next(result)                # Skip the special loop edge.
     return result
 
+
 class Builder(object):
     """A tight binding system defined on a graph.
 
@@ -494,19 +478,8 @@ class Builder(object):
     symmetry : `Symmetry` or `None`
         The symmetry of the system.
 
-    Instance Variables
-    ------------------
-    default_site_group : `SiteGroup` or `None`
-        Defaults falue is `None`
-
     Notes
     -----
-    The instance variable `default_site_group` can be set to a `SiteGroup`
-    instance.  Then, whenever a `Site` would have been acceptable as parameter
-    to the methods of the builder, a non-site ``tag`` object will be also
-    accepted.  The ``tag`` will be converted into a site in the following way:
-    ``Site(default_site_group, tag)``.
-
     Builder instances automatically ensure that every hopping is Hermitian, so
     that if ``builder[a, b]`` has been set, there is no need to set
     ``builder[b, a]``.
@@ -556,7 +529,6 @@ class Builder(object):
         if symmetry is None:
             symmetry = NoSymmetry()
         self.symmetry = symmetry
-        self.default_site_group = None
         self.leads = []
         self.H = {}
 
@@ -623,49 +595,33 @@ class Builder(object):
         """
         result = object.__new__(Builder)
         result.symmetry = self.symmetry.reversed()
-        result.default_site_group = self.default_site_group
         if self.leads:
             raise ValueError('System to be reversed may not have leads.')
         result.leads = []
         result.H = self.H
         return result
 
-    def _to_site(self, sitelike):
-        """Convert `sitelike` to a site.
-
-        Sitelike can be
-        * a site, (It is returned unmodified.)
-        * a tag. (Works only if self.default_site_group is not None.)
-        """
-        if isinstance(sitelike, Site):
-            return sitelike
-        dsg = self.default_site_group
-        if dsg is not None:
-            return Site(dsg, sitelike)
-        raise KeyError(sitelike)
-
     def __nonzero__(self):
         return bool(self.H)
 
-    def _get_site(self, sitelike):
-        site = self.symmetry.to_fd(self._to_site(sitelike))
+    def _get_site(self, site):
+        site = self.symmetry.to_fd(site)
         try:
             return self.H[site][1]
         except KeyError:
-            raise KeyError(sitelike)
+            raise KeyError(site)
 
-    def _get_hopping(self, hoppinglike):
-        ts = self._to_site
+    def _get_hopping(self, hopping):
         sym = self.symmetry
         try:
-            a, b = hoppinglike
+            a, b = hopping
         except:
-            raise KeyError(hoppinglike)
+            raise KeyError(hopping)
         try:
-            a, b = sym.to_fd(ts(a), ts(b))
+            a, b = sym.to_fd(a, b)
             value = self._get_edge(a, b)
         except ValueError:
-            raise KeyError(hoppinglike)
+            raise KeyError(hopping)
         if value is other:
             if not sym.in_fd(b):
                 b, a = sym.to_fd(b, a)
@@ -680,54 +636,50 @@ class Builder(object):
 
     def __getitem__(self, key):
         """Get the value of a single site or hopping."""
-        isl = is_sitelike(key)
-        if isl is None:
-            raise KeyError(key)
-        if isl:
+        if isinstance(key, Site):
             return self._get_site(key)
-        else:
+        elif isinstance(key, tuple):
             return self._get_hopping(key)
+        else:
+            raise KeyError(key)
 
     def __contains__(self, key):
         """Tell whether the system contains a site or hopping."""
-        isl = is_sitelike(key)
-        if isl is None:
-            raise KeyError(key)
-        if isl:
-            site = self.symmetry.to_fd(self._to_site(key))
+        if isinstance(key, Site):
+            site = self.symmetry.to_fd(key)
             return site in self.H
-        else:
-            ts = self._to_site
+        elif isinstance(key, tuple):
             a, b = key
-            a, b = self.symmetry.to_fd(ts(a), ts(b))
+            a, b = self.symmetry.to_fd(a, b)
             hvhv = self.H.get(a, ())
             return b in islice(hvhv, 2, None, 2)
+        else:
+            raise KeyError(key)
 
-    def _set_site(self, sitelike, value):
+    def _set_site(self, site, value):
         """Set a single site."""
-        site = self.symmetry.to_fd(self._to_site(sitelike))
+        site = self.symmetry.to_fd(site)
         hvhv = self.H.setdefault(site, [])
         if hvhv:
             hvhv[1] = value
         else:
             hvhv[:] = [site, value]
 
-    def _set_hopping(self, hoppinglike, value):
+    def _set_hopping(self, hopping, value):
         """Set a single hopping."""
         # Avoid nested HermConjOfFunc instances.
         try:
-            a, b = hoppinglike
+            a, b = hopping
         except:
-            raise KeyError(hoppinglike)
+            raise KeyError(hopping)
         if isinstance(value, HermConjOfFunc):
             a, b = b, a
             value = value.function
 
-        ts = self._to_site
         sym = self.symmetry
 
         try:
-            a, b = sym.to_fd(ts(a), ts(b))
+            a, b = sym.to_fd(a, b)
             if sym.in_fd(b):
                 # These two following lines make sure we do not waste space by
                 # storing different instances of identical sites.  They also
@@ -744,7 +696,7 @@ class Builder(object):
                 self._set_edge(a, b, value)      # Might fail.
                 self._set_edge(b2, a2, other)    # Will work.
         except KeyError:
-            raise KeyError(hoppinglike)
+            raise KeyError(hopping)
 
     def __setitem__(self, key, value):
         """Set a single site/hopping or an iterable of them."""
@@ -752,10 +704,10 @@ class Builder(object):
                         lambda s: self._set_site(s, value),
                         lambda h: self._set_hopping(h, value))
 
-    def _del_site(self, sitelike):
+    def _del_site(self, site):
         """Delete a single site and all associated hoppings."""
         tfd = self.symmetry.to_fd
-        site = tfd(self._to_site(sitelike))
+        site = tfd(site)
         try:
             for neighbor in self._out_neighbors(site):
                 if neighbor in self.H:
@@ -765,20 +717,19 @@ class Builder(object):
                     a, b = tfd(neighbor, site)
                     self._del_edge(a, b)
         except ValueError:
-            raise KeyError(sitelike)
+            raise KeyError(site)
         del self.H[site]
 
-    def _del_hopping(self, hoppinglike):
+    def _del_hopping(self, hopping):
         """Delete a single hopping."""
-        ts = self._to_site
         sym = self.symmetry
 
         try:
-            a, b = hoppinglike
+            a, b = hopping
         except:
-            raise KeyError(hoppinglike)
+            raise KeyError(hopping)
         try:
-            a, b = sym.to_fd(ts(a), ts(b))
+            a, b = sym.to_fd(a, b)
             if sym.in_fd(b):
                 self._del_edge(a, b)
                 self._del_edge(b, a)
@@ -788,7 +739,7 @@ class Builder(object):
                 assert not sym.in_fd(a)
                 self._del_edge(b, a)
         except ValueError:
-            raise KeyError(hoppinglike)
+            raise KeyError(hopping)
 
     def __delitem__(self, key):
         """Delete a single site/hopping or an iterable of them."""
@@ -864,14 +815,14 @@ class Builder(object):
             if self._out_degree(site) < 2:
                 yield site
 
-    def degree(self, sitelike):
+    def degree(self, site):
         """Return the number of neighbors of a site."""
-        site = self.symmetry.to_fd(self._to_site(sitelike))
+        site = self.symmetry.to_fd(site)
         return self._out_degree(site)
 
-    def neighbors(self, sitelike):
+    def neighbors(self, site):
         """Return an iterator over all neighbors of a site."""
-        a = self.symmetry.to_fd(self._to_site(sitelike))
+        a = self.symmetry.to_fd(site)
         return self._out_neighbors(a)
 
     def __iadd__(self, other_sys):
diff --git a/kwant/solvers/tests/_test_sparse.py b/kwant/solvers/tests/_test_sparse.py
index 373f491b..79e86661 100644
--- a/kwant/solvers/tests/_test_sparse.py
+++ b/kwant/solvers/tests/_test_sparse.py
@@ -14,7 +14,7 @@ import kwant
 
 n = 5
 chain = kwant.lattice.chain()
-square = kwant.lattice.square()
+sq = square = kwant.lattice.square()
 
 
 # Test output sanity: that an error is raised if no output is requested,
@@ -169,19 +169,17 @@ def test_graph_system(solve):
     np.random.seed(11)
     system = kwant.Builder()
     lead = kwant.Builder(kwant.TranslationalSymmetry((-1, 0)))
-    lead.default_site_group = system.default_site_group = square
-
     h = np.random.rand(n, n) + 1j * np.random.rand(n, n)
     h += h.conjugate().transpose()
     h *= 0.8
     t = 4 * np.random.rand(n, n) + 4j * np.random.rand(n, n)
     t1 = 4 * np.random.rand(n, n) + 4j * np.random.rand(n, n)
-    lead[0, 0] = system[[(0, 0), (1, 0)]] = h
-    lead[0, 1] = system[[(0, 1), (1, 1)]] = 4 * h
+    lead[sq(0, 0)] = system[[sq(0, 0), sq(1, 0)]] = h
+    lead[sq(0, 1)] = system[[sq(0, 1), sq(1, 1)]] = 4 * h
     for builder in [system, lead]:
-        builder[(0, 0), (1, 0)] = t
-        builder[(0, 1), (1, 0)] = t1
-        builder[(0, 1), (1, 1)] = 1.1j * t1
+        builder[sq(0, 0), sq(1, 0)] = t
+        builder[sq(0, 1), sq(1, 0)] = t1
+        builder[sq(0, 1), sq(1, 1)] = 1.1j * t1
     system.attach_lead(lead)
     system.attach_lead(lead.reversed())
     fsys = system.finalized()
@@ -193,7 +191,7 @@ def test_graph_system(solve):
     n_modes = leads[0][2]
     assert_equal(leads[1][2], n_modes)
     assert_almost_equal(s[: n_modes, : n_modes], 0)
-    t_elements = np.sort(abs(np.asarray(s[n_modes :, : n_modes])),
+    t_elements = np.sort(abs(np.asarray(s[n_modes:, :n_modes])),
                          axis=None)
     t_el_should_be = n_modes * (n_modes - 1) * [0] + n_modes * [1]
     assert_almost_equal(t_elements, t_el_should_be)
@@ -205,17 +203,16 @@ def test_singular_graph_system(solve):
 
     system = kwant.Builder()
     lead = kwant.Builder(kwant.TranslationalSymmetry((-1, 0)))
-    lead.default_site_group = system.default_site_group = square
     h = np.random.rand(n, n) + 1j * np.random.rand(n, n)
     h += h.conjugate().transpose()
     h *= 0.8
     t = 4 * np.random.rand(n, n) + 4j * np.random.rand(n, n)
     t1 = 4 * np.random.rand(n, n) + 4j * np.random.rand(n, n)
-    lead[0, 0] = system[[(0, 0), (1, 0)]] = h
-    lead[0, 1] = system[[(0, 1), (1, 1)]] = 4 * h
+    lead[sq(0, 0)] = system[[sq(0, 0), sq(1, 0)]] = h
+    lead[sq(0, 1)] = system[[sq(0, 1), sq(1, 1)]] = 4 * h
     for builder in [system, lead]:
-        builder[(0, 0), (1, 0)] = t
-        builder[(0, 1), (1, 0)] = t1
+        builder[sq(0, 0), sq(1, 0)] = t
+        builder[sq(0, 1), sq(1, 0)] = t1
     system.attach_lead(lead)
     system.attach_lead(lead.reversed())
     fsys = system.finalized()
@@ -239,23 +236,22 @@ def test_singular_graph_system(solve):
 def test_tricky_singular_hopping(solve):
     system = kwant.Builder()
     lead = kwant.Builder(kwant.TranslationalSymmetry((4, 0)))
-    lead.default_site_group = system.default_site_group = square
 
     interface = []
     for i in xrange(n):
-        site = square(-1, i)
+        site = sq(-1, i)
         interface.append(site)
         system[site] = 0
         for j in xrange(4):
-            lead[j, i] = 0
+            lead[sq(j, i)] = 0
     for i in xrange(n-1):
-        system[(-1, i), (-1, i+1)] = -1
+        system[sq(-1, i), sq(-1, i+1)] = -1
         for j in xrange(4):
-            lead[(j, i), (j, i+1)] = -1
+            lead[sq(j, i), sq(j, i+1)] = -1
     for i in xrange(n):
         for j in xrange(4):
-            lead[(j, i), (j+1, i)] = -1
-    del lead[(1, 0), (2, 0)]
+            lead[sq(j, i), sq(j+1, i)] = -1
+    del lead[sq(1, 0), sq(2, 0)]
 
     system.leads.append(kwant.builder.BuilderLead(lead, interface))
     fsys = system.finalized()
@@ -302,7 +298,7 @@ def test_self_energy(solve):
     eig_are = np.linalg.eigvals(ttdagnew)
     t_should_be = np.sum(eig_are)
     assert_almost_equal(eig_are.imag, 0)
-    assert_almost_equal(np.sort(eig_are.real)[-n_eig :],
+    assert_almost_equal(np.sort(eig_are.real)[-n_eig:],
                         np.sort(eig_should_be.real))
     assert_almost_equal(t_should_be, sol.transmission(1, 0))
 
@@ -352,11 +348,9 @@ def test_very_singular_leads(solve):
     gr = kwant.lattice.chain()
     left_lead = kwant.Builder(kwant.TranslationalSymmetry((-1,)))
     right_lead = kwant.Builder(kwant.TranslationalSymmetry((1,)))
-    sys.default_site_group = gr
-    left_lead.default_site_group = right_lead.default_site_group = gr
-    sys[(0,)] = left_lead[(0,)] = right_lead[(0,)] = np.identity(2)
-    left_lead[(0,), (1,)] = np.zeros((2, 2))
-    right_lead[(0,), (1,)] = np.identity(2)
+    sys[gr(0)] = left_lead[gr(0)] = right_lead[gr(0)] = np.identity(2)
+    left_lead[gr(0), gr(1)] = np.zeros((2, 2))
+    right_lead[gr(0), gr(1)] = np.identity(2)
     sys.attach_lead(left_lead)
     sys.attach_lead(right_lead)
     fsys = sys.finalized()
@@ -369,8 +363,8 @@ def test_ldos(ldos):
     gr = kwant.lattice.chain()
     lead = kwant.Builder(kwant.TranslationalSymmetry(gr.vec((1,))))
     sys.default_site_group = lead.default_site_group = gr
-    sys[(0,)] = sys[(1,)] = lead[(0,)] = 0
-    sys[(0,), (1,)] = lead[(0,), (1,)] = 1
+    sys[gr(0)] = sys[gr(1)] = lead[gr(0)] = 0
+    sys[gr(0), gr(1)] = lead[gr(0), gr(1)] = 1
     sys.attach_lead(lead)
     sys.attach_lead(lead.reversed())
     fsys = sys.finalized()
diff --git a/kwant/tests/test_builder.py b/kwant/tests/test_builder.py
index 366a19c2..42884095 100644
--- a/kwant/tests/test_builder.py
+++ b/kwant/tests/test_builder.py
@@ -27,9 +27,7 @@ def test_site_groups():
     assert_raises(KeyError, sys.__getitem__, (0, ))
 
     assert len(set([sg, osg, sg('a'), osg('a'), yasg])) == 3
-    sys.default_site_group = sg
-    sys[1,] = 123
-    assert_equal(sys[1,], 123)
+    sys[sg(1)] = 123
     assert_equal(sys[sg(1)], 123)
     assert_equal(sys[osg(1)], 123)
     assert_raises(KeyError, sys.__getitem__, yasg(1))
@@ -59,8 +57,8 @@ class VerySimpleSymmetry(builder.Symmetry):
 # made.
 def check_construction_and_indexing(sites, sites_fd, hoppings, hoppings_fd,
                                     failing_hoppings, sym=None):
+    gr = builder.SimpleSiteGroup()
     sys = builder.Builder(sym)
-    sys.default_site_group = builder.SimpleSiteGroup()
     t, V = 1.0j, 0.0
     sys[sites] = V
     for site in sites:
@@ -72,9 +70,9 @@ def check_construction_and_indexing(sites, sites_fd, hoppings, hoppings_fd,
     for hopping in failing_hoppings:
         assert_raises(KeyError, sys.__setitem__, hopping, t)
 
-    assert (5, 123) not in sys
-    assert (sites[0], (5, 123)) not in sys
-    assert ((7, 8), sites[0]) not in sys
+    assert (gr(5), gr(123)) not in sys
+    assert (sites[0], gr(5, 123)) not in sys
+    assert (gr(7, 8), sites[0]) not in sys
     for site in sites:
         assert site in sys
         assert_equal(sys[site], V)
@@ -86,7 +84,7 @@ def check_construction_and_indexing(sites, sites_fd, hoppings, hoppings_fd,
         assert_equal(sys[rev_hop], t.conjugate())
 
     assert_equal(sys.degree(sites[0]), 2)
-    assert_equal(sorted(s.tag for s in sys.neighbors(sites[0])),
+    assert_equal(sorted(s for s in sys.neighbors(sites[0])),
                  sorted([sites[1], sites[-1]]))
 
     del sys[hoppings]
@@ -94,9 +92,9 @@ def check_construction_and_indexing(sites, sites_fd, hoppings, hoppings_fd,
     sys[hoppings] = t
 
     del sys[sites[0]]
-    assert_equal(sorted(tuple(s.tag)
+    assert_equal(sorted(tuple(s)
                         for s in sys.sites()), sorted(sites_fd[1:]))
-    assert_equal(sorted((tuple(a.tag), tuple(b.tag))
+    assert_equal(sorted((a, b)
                         for a, b in sys.hoppings()),
                  sorted(hoppings_fd[1:-1]))
 
@@ -111,28 +109,29 @@ def check_construction_and_indexing(sites, sites_fd, hoppings, hoppings_fd,
 
 def test_construction_and_indexing():
     # Without symmetry
-    sites = [(0, 0), (0, 1), (1, 0)]
-    hoppings = [((0, 0), (0, 1)),
-                ((0, 1), (1, 0)),
-                ((1, 0), (0, 0))]
-    failing_hoppings = [((0, 1), (7, 8)), ((12, 14), (0, 1))]
+    gr = builder.SimpleSiteGroup()
+    sites = [gr(0, 0), gr(0, 1), gr(1, 0)]
+    hoppings = [(gr(0, 0), gr(0, 1)),
+                (gr(0, 1), gr(1, 0)),
+                (gr(1, 0), gr(0, 0))]
+    failing_hoppings = [(gr(0, 1), gr(7, 8)), (gr(12, 14), gr(0, 1))]
     check_construction_and_indexing(sites, sites, hoppings, hoppings,
                                     failing_hoppings)
 
     # With symmetry
-    sites = [(0, 0), (1, 1), (2, 1), (4, 2)]
-    sites_fd = [(0, 0), (1, 1), (0, 1), (0, 2)]
-    hoppings = [((0, 0), (1, 1)),
-                ((1, 1), (2, 1)),
-                ((2, 1), (4, 2)),
-                ((4, 2), (0, 0))]
-    hoppings_fd = [((0, 0), (1, 1)),
-                   ((1, 1), (2, 1)),
-                   ((0, 1), (2, 2)),
-                   ((0, 2), (-4, 0))]
-    failing_hoppings = [((0, 0), (0, 3)), ((0, 4), (0, 0)),
-                        ((0, 0), (2, 3)), ((2, 4), (0, 0)),
-                        ((4, 2), (6, 3)), ((6, 4), (4, 2))]
+    sites = [gr(0, 0), gr(1, 1), gr(2, 1), gr(4, 2)]
+    sites_fd = [gr(0, 0), gr(1, 1), gr(0, 1), gr(0, 2)]
+    hoppings = [(gr(0, 0), gr(1, 1)),
+                (gr(1, 1), gr(2, 1)),
+                (gr(2, 1), gr(4, 2)),
+                (gr(4, 2), gr(0, 0))]
+    hoppings_fd = [(gr(0, 0), gr(1, 1)),
+                   (gr(1, 1), gr(2, 1)),
+                   (gr(0, 1), gr(2, 2)),
+                   (gr(0, 2), gr(-4, 0))]
+    failing_hoppings = [(gr(0, 0), gr(0, 3)), (gr(0, 4), gr(0, 0)),
+                        (gr(0, 0), gr(2, 3)), (gr(2, 4), gr(0, 0)),
+                        (gr(4, 2), gr(6, 3)), (gr(6, 4), gr(4, 2))]
     sym = VerySimpleSymmetry(2)
     check_construction_and_indexing(sites, sites_fd, hoppings, hoppings_fd,
                                     failing_hoppings, sym)
@@ -140,41 +139,42 @@ def test_construction_and_indexing():
 
 def test_hermitian_conjugation():
     def f(i, j):
+        i, j = i.tag, j.tag
         if j[0] == i[0] + 1:
             return ta.array([[1, 2j], [3 + 1j, 4j]])
         else:
             raise ValueError
 
     sys = builder.Builder()
-    sys.default_site_group = builder.SimpleSiteGroup()
-    sys[0,] = sys[1,] = ta.identity(2)
+    sg = builder.SimpleSiteGroup()
+    sys[sg(0)] = sys[sg(1)] = ta.identity(2)
 
-    sys[(0,), (1,)] = f
-    assert sys[(0,), (1,)] is f
-    assert isinstance(sys[(1,), (0,)], builder.HermConjOfFunc)
-    assert_equal(sys[(1,), (0,)]((1,), (0,)),
-                 sys[(0,), (1,)]((0,), (1,)).conjugate().transpose())
-    sys[(0,), (1,)] = sys[(1,), (0,)]
-    assert isinstance(sys[(0,), (1,)], builder.HermConjOfFunc)
-    assert sys[(1,), (0,)] is f
+    sys[sg(0), sg(1)] = f
+    assert sys[sg(0), sg(1)] is f
+    assert isinstance(sys[sg(1), sg(0)], builder.HermConjOfFunc)
+    assert_equal(sys[sg(1), sg(0)](sg(1), sg(0)),
+                 sys[sg(0), sg(1)](sg(0), sg(1)).conjugate().transpose())
+    sys[sg(0), sg(1)] = sys[sg(1), sg(0)]
+    assert isinstance(sys[sg(0), sg(1)], builder.HermConjOfFunc)
+    assert sys[sg(1), sg(0)] is f
 
 
 def test_value_equality_and_identity():
     m = ta.array([[1, 2], [3j, 4j]])
     sys = builder.Builder()
-    sys.default_site_group = builder.SimpleSiteGroup()
+    sg = builder.SimpleSiteGroup()
 
-    sys[0,] = m
-    sys[1,] = m
-    assert sys[1,] is m
+    sys[sg(0)] = m
+    sys[sg(1)] = m
+    assert sys[sg(1)] is m
 
-    sys[(0,), (1,)] = m
-    assert_equal(sys[(1,), (0,)], m.transpose().conjugate())
-    assert sys[(0,), (1,)] is m
+    sys[sg(0), sg(1)] = m
+    assert_equal(sys[sg(1), sg(0)], m.transpose().conjugate())
+    assert sys[sg(0), sg(1)] is m
 
-    sys[(1,), (0,)] = m
-    assert_equal(sys[(0,), (1,)], m.transpose().conjugate())
-    assert sys[(1,), (0,)] is m
+    sys[sg(1), sg(0)] = m
+    assert_equal(sys[sg(0), sg(1)], m.transpose().conjugate())
+    assert sys[sg(1), sg(0)] is m
 
 
 def random_onsite_hamiltonian(rng):
@@ -270,27 +270,26 @@ def test_finalization():
 
     # Build scattering region from blueprint and test it.
     sys = builder.Builder()
-    sys.default_site_group = sg = kwant.lattice.general(ta.identity(2))
+    sg = kwant.lattice.general(ta.identity(2))
     for site, value in sr_sites.iteritems():
-        sys[site] = value
+        sys[sg(*site)] = value
     for hop, value in sr_hops.iteritems():
-        sys[hop] = value
+        sys[sg(*hop[0]), sg(*hop[1])] = value
     fsys = sys.finalized()
     check_onsite(fsys, sr_sites)
     check_hoppings(fsys, sr_hops)
 
     # Build lead from blueprint and test it.
     lead = builder.Builder(kwant.TranslationalSymmetry((size, 0)))
-    lead.default_site_group = sg
     for site, value in lead_sites.iteritems():
         shift = rng.randrange(-5, 6) * size
         site = site[0] + shift, site[1]
-        lead[site] = value
+        lead[sg(*site)] = value
     for (a, b), value in lead_hops.iteritems():
         shift = rng.randrange(-5, 6) * size
         a = a[0] + shift, a[1]
         b = b[0] + shift, b[1]
-        lead[a, b] = value
+        lead[sg(*a), sg(*b)] = value
     flead = lead.finalized()
     all_sites = list(lead_sites)
     all_sites.extend((x - size, y) for (x, y) in neighbors)
@@ -311,7 +310,7 @@ def test_finalization():
     a = rng.choice(lead_sites_list)
     b = rng.choice(possible_neighbors)
     b = b[0] + 2 * size, b[1]
-    lead[a, b] = random_hopping_integral(rng)
+    lead[sg(*a), sg(*b)] = random_hopping_integral(rng)
     assert_raises(ValueError, lead.finalized)
 
 
@@ -327,10 +326,10 @@ def test_hamiltonian_evaluation():
     edges = [(0, 1), (0, 2), (0, 3), (1, 2)]
 
     sys = builder.Builder()
-    sys.default_site_group = sg = builder.SimpleSiteGroup()
+    sg = builder.SimpleSiteGroup()
     sites = [sg(*tag) for tag in tags]
-    sys[tags] = f_onsite
-    sys[((tags[i], tags[j]) for (i, j) in edges)] = f_hopping
+    sys[(sg(*tag) for tag in tags)] = f_onsite
+    sys[((sg(*tags[i]), sg(*tags[j])) for (i, j) in edges)] = f_hopping
     fsys = sys.finalized()
 
     assert_equal(fsys.graph.num_nodes, len(tags))
@@ -355,11 +354,11 @@ def test_dangling():
         #       / \
         #    3-0---2-4-5  6-7  8
         sys = builder.Builder()
-        sys.default_site_group = builder.SimpleSiteGroup()
-        sys[((i,) for i in range(9))] = None
-        sys[[((0,), (1,)), ((1,), (2,)), ((2,), (0,))]] = None
-        sys[[((0,), (3,)), ((2,), (4,)), ((4,), (5,))]] = None
-        sys[(6,), (7,)] = None
+        sg = builder.SimpleSiteGroup()
+        sys[(sg(i) for i in range(9))] = None
+        sys[[(sg(0), sg(1)), (sg(1), sg(2)), (sg(2), sg(0))]] = None
+        sys[[(sg(0), sg(3)), (sg(2), sg(4)), (sg(4), sg(5))]] = None
+        sys[sg(6), sg(7)] = None
         return sys
 
     sys0 = make_system()
@@ -383,48 +382,47 @@ def test_dangling():
 def test_builder_with_symmetry():
     g = kwant.lattice.general(ta.identity(3))
     sym = kwant.TranslationalSymmetry((0, 0, 3), (0, 2, 0))
-    bob = builder.Builder(sym)
-    bob.default_site_group = g
+    sys = builder.Builder(sym)
 
     t, V = 1.0j, 0.0
-    hoppings = [((5, 0, 0), (0, 5, 0)),
-                ((0, 5, 0), (0, 0, 5)),
-                ((0, 0, 5), (5, 0, 0)),
-                ((0, 3, 0), (0, 0, 5)),
-                ((0, 7, -6), (5, 6, -6))]
-    hoppings_fd = [((5, 0, 0), (0, 5, 0)),
-                   ((0, 1, 0), (0, -4, 5)),
-                   ((0, 0, 2), (5, 0, -3)),
-                   ((0, 1, 0), (0, -2, 5)),
-                   ((0, 1, 0), (5, 0, 0))]
-
-    bob[(a for a, b in hoppings)] = V
-    bob[hoppings] = t
+    hoppings = [(g(5, 0, 0), g(0, 5, 0)),
+                (g(0, 5, 0), g(0, 0, 5)),
+                (g(0, 0, 5), g(5, 0, 0)),
+                (g(0, 3, 0), g(0, 0, 5)),
+                (g(0, 7, -6), g(5, 6, -6))]
+    hoppings_fd = [(g(5, 0, 0), g(0, 5, 0)),
+                   (g(0, 1, 0), g(0, -4, 5)),
+                   (g(0, 0, 2), g(5, 0, -3)),
+                   (g(0, 1, 0), g(0, -2, 5)),
+                   (g(0, 1, 0), g(5, 0, 0))]
+
+    sys[(a for a, b in hoppings)] = V
+    sys[hoppings] = t
 
     # TODO: Once tinyarray supports "<" the conversion to tuple can be removed.
-    assert_equal(sorted(tuple(site.tag) for site in bob.sites()),
-                 sorted(set(a for a, b in hoppings_fd)))
+    assert_equal(sorted(tuple(site.tag) for site in sys.sites()),
+                 sorted(set(tuple(a.tag) for a, b in hoppings_fd)))
     for sites in hoppings_fd:
         for site in sites:
-            assert site in bob
-            assert_equal(bob[site], V)
+            assert site in sys
+            assert_equal(sys[site], V)
 
     # TODO: Once tinyarray supports "<" the conversion to tuple can be removed.
     assert_equal(sorted((tuple(a.tag), tuple(b.tag))
-                        for a, b in bob.hoppings()),
-                 sorted(hoppings_fd))
+                        for a, b in sys.hoppings()),
+                 sorted((tuple(a.tag), tuple(b.tag)) for a, b in hoppings_fd))
     for hop in hoppings_fd:
         rhop = hop[1], hop[0]
-        assert hop in bob
-        assert rhop in bob
-        assert_equal(bob[hop], t)
-        assert_equal(bob[rhop], t.conjugate())
+        assert hop in sys
+        assert rhop in sys
+        assert_equal(sys[hop], t)
+        assert_equal(sys[rhop], t.conjugate())
 
-    del bob[(0, 6, -4), (0, 11, -9)]
-    assert ((0, 1, 0), (0, -4, 5)) not in bob
+    del sys[g(0, 6, -4), g(0, 11, -9)]
+    assert (g(0, 1, 0), g(0, -4, 5)) not in sys
 
-    del bob[0, 3, -3]
-    assert_equal(list((a.tag, b.tag) for a, b in bob.hoppings()),
+    del sys[g(0, 3, -3)]
+    assert_equal(list((a.tag, b.tag) for a, b in sys.hoppings()),
                  [((0, 0, 2), (5, 0, -3))])
 
 
@@ -432,33 +430,31 @@ def test_attach_lead():
     gr = builder.SimpleSiteGroup()
 
     sys = builder.Builder()
-    sys.default_site_group = gr
-    sys[(1,)] = 0
+    sys[gr(1)] = 0
     lead0 = builder.Builder(VerySimpleSymmetry(-2))
     assert_raises(ValueError, sys.attach_lead, lead0)
 
     lead0.default_site_group = gr
-    lead0[(0,)] = lead0[(1,)] = 1
+    lead0[gr(0)] = lead0[gr(1)] = 1
 
     sys2 = builder.Builder()
     sys2.default_site_group = gr
-    sys2[(1,)] = 0
+    sys2[gr(1)] = 0
     assert_raises(ValueError, sys2.attach_lead, lead0)
 
-    lead0[(0,), (1,)] = lead0[(0,), (2,)] = 1
+    lead0[gr(0), gr(1)] = lead0[gr(0), gr(2)] = 1
     assert_raises(ValueError, sys.attach_lead, lead0)
 
-    sys[(0,)] = 1
+    sys[gr(0)] = 1
     assert_raises(ValueError, sys.attach_lead, lead0, gr(5))
 
     sys = builder.Builder()
-    sys.default_site_group = gr
-    sys[(1,)] = 0
-    sys[(0,)] = 1
+    sys[gr(1)] = 0
+    sys[gr(0)] = 1
     sys.attach_lead(lead0)
     assert_equal(len(list(sys.sites())), 3)
     assert_equal(set(sys.leads[0].interface), set([gr(-1), gr(0)]))
-    sys[(-10,)] = sys[(-11,)] = 0
+    sys[gr(-10)] = sys[gr(-11)] = 0
     sys.attach_lead(lead0)
     assert_equal(set(sys.leads[1].interface), set([gr(-10), gr(-11)]))
     assert_equal(len(list(sys.sites())), 5)
@@ -470,15 +466,14 @@ def test_attach_lead():
 def test_neighbors_not_in_single_domain():
     sr = builder.Builder()
     lead = builder.Builder(VerySimpleSymmetry(-1))
-    lat = builder.SimpleSiteGroup()
-    sr.default_site_group = lead.default_site_group = lat
-    sr[((x, y) for x in range(3) for y in range(3) if x >= y)] = 0
-    sr[sr.possible_hoppings((1, 0), lat, lat)] = 1
-    sr[sr.possible_hoppings((0, 1), lat, lat)] = 1
-    lead[((0, y) for y in range(3))] = 0
-    lead[(((0, y), (1, y)) for y in range(3))] = 1
-    lead[(((0, y), (0, y + 1)) for y in range(2))] = 1
-    sr.leads.append(builder.BuilderLead(lead, [lat(i, i) for i in range(3)]))
+    gr = builder.SimpleSiteGroup()
+    sr[(gr(x, y) for x in range(3) for y in range(3) if x >= y)] = 0
+    sr[sr.possible_hoppings((1, 0), gr, gr)] = 1
+    sr[sr.possible_hoppings((0, 1), gr, gr)] = 1
+    lead[(gr(0, y) for y in range(3))] = 0
+    lead[((gr(0, y), gr(1, y)) for y in range(3))] = 1
+    lead[((gr(0, y), gr(0, y + 1)) for y in range(2))] = 1
+    sr.leads.append(builder.BuilderLead(lead, [gr(i, i) for i in range(3)]))
     assert_raises(ValueError, sr.finalized)
 
 
diff --git a/kwant/tests/test_system.py b/kwant/tests/test_system.py
index 2db50f44..ce721a88 100644
--- a/kwant/tests/test_system.py
+++ b/kwant/tests/test_system.py
@@ -13,11 +13,11 @@ import kwant
 
 def test_hamiltonian_submatrix():
     sys = kwant.Builder()
-    sys.default_site_group = kwant.lattice.chain()
+    gr = kwant.lattice.chain()
     for i in xrange(3):
-        sys[(i,)] = 0.5 * i
+        sys[gr(i)] = 0.5 * i
     for i in xrange(2):
-        sys[(i,), (i + 1,)] = 1j * (i + 1)
+        sys[gr(i), gr(i + 1)] = 1j * (i + 1)
 
     sys2 = sys.finalized()
     mat = sys2.hamiltonian_submatrix()
@@ -46,23 +46,22 @@ def test_hamiltonian_submatrix():
 
     # Test for correct treatment of matrix input.
     sys = kwant.Builder()
-    sys.default_site_group = kwant.lattice.chain()
-    sys[(0,)] = np.array([[0, 1j], [-1j, 0]])
-    sys[(1,)] = np.array([[1]])
-    sys[(2,)] = np.array([[2]])
-    sys[(1,), (0,)] = np.array([[1, 2j]])
-    sys[(2,), (1,)] = np.array([[3j]])
+    sys[gr(0)] = np.array([[0, 1j], [-1j, 0]])
+    sys[gr(1)] = np.array([[1]])
+    sys[gr(2)] = np.array([[2]])
+    sys[gr(1), gr(0)] = np.array([[1, 2j]])
+    sys[gr(2), gr(1)] = np.array([[3j]])
     sys2 = sys.finalized()
     mat_dense = sys2.hamiltonian_submatrix()
     mat_sp = sys2.hamiltonian_submatrix(sparse=True).todense()
     np.testing.assert_array_equal(mat_sp, mat_dense)
 
     # Test for shape errors.
-    sys[(0,), (2,)] = np.array([[1, 2]])
+    sys[gr(0), gr(2)] = np.array([[1, 2]])
     sys2 = sys.finalized()
     assert_raises(ValueError, sys2.hamiltonian_submatrix)
     assert_raises(ValueError, sys2.hamiltonian_submatrix, None, None, True)
-    sys[(0,), (2,)] = 1
+    sys[gr(0), gr(2)] = 1
     sys2 = sys.finalized()
     assert_raises(ValueError, sys2.hamiltonian_submatrix)
     assert_raises(ValueError, sys2.hamiltonian_submatrix, None, None, True)
-- 
GitLab