diff --git a/kwant/builder.py b/kwant/builder.py index 2af9f2753ba7986b979dca966c5846c1c541c714..24428ae7b216873d8af7d88b1cd38057339c435c 100644 --- a/kwant/builder.py +++ b/kwant/builder.py @@ -333,22 +333,16 @@ class Symmetry(metaclass=abc.ABCMeta): pass @abc.abstractmethod - def isstrictsupergroup(self, other): - """Test whether `self` is a strict supergroup of `other`... + def has_subgroup(self, other): + """Test whether `self` has the subgroup `other`... or, in other words, whether `other` is a subgroup of `self`. The - reason why this is the abstract method (and not `issubgroup`) is that + reason why this is the abstract method (and not `is_subgroup`) is that in general it's not possible for a subgroup to know its supergroups. """ pass - def issubgroup(self, other): - """Test whether `self` is a subgroup of `other`.""" - return other.isstrictsupergroup(self) - - __le__ = issubgroup - class NoSymmetry(Symmetry): """A symmetry with a trivial symmetry group.""" @@ -389,8 +383,8 @@ class NoSymmetry(Symmetry): raise ValueError('Generators must be empty for NoSymmetry.') return NoSymmetry(generators) - def isstrictsupergroup(self, other): - return False + def has_subgroup(self, other): + return isinstance(other, NoSymmetry) @@ -1303,7 +1297,7 @@ class Builder: templ_sym = template.symmetry # Check that symmetries are commensurate. - if not self.symmetry <= templ_sym: + if not templ_sym.has_subgroup(self.symmetry): raise ValueError("Builder symmetry is not a subgroup of the " "template symmetry") diff --git a/kwant/lattice.py b/kwant/lattice.py index e57a6e27a06830e4face8d5ef48c79dd827abe45..8cf0d6a20065339ee389de2eb7cc2cc23cad074e 100644 --- a/kwant/lattice.py +++ b/kwant/lattice.py @@ -555,7 +555,7 @@ class TranslationalSymmetry(builder.Symmetry): raise ValueError('Generators must be sequences of integers.') return TranslationalSymmetry(*ta.dot(generators, self.periods)) - def isstrictsupergroup(self, other): + def has_subgroup(self, other): if isinstance(other, builder.NoSymmetry): return True elif not isinstance(other, TranslationalSymmetry): diff --git a/kwant/tests/test_builder.py b/kwant/tests/test_builder.py index 9f6dc7442b94856c5ba8702ceaeb79ba1fe7ad9d..b1e5c6792c833e4316e51a29112c31acf49677b3 100644 --- a/kwant/tests/test_builder.py +++ b/kwant/tests/test_builder.py @@ -129,7 +129,7 @@ class VerySimpleSymmetry(builder.Symmetry): def num_directions(self): return 1 - def isstrictsupergroup(self, other): + def has_subgroup(self, other): if isinstance(other, builder.NoSymmetry): return True elif isinstance(other, VerySimpleSymmetry): @@ -652,32 +652,36 @@ def test_fill(): return -100 <= site.pos[0] < 100 ## Test that copying a builder by "fill" preserves everything. - cubic = kwant.lattice.general(ta.identity(3)) - sym = kwant.TranslationalSymmetry((3, 0, 0), (0, 4, 0), (0, 0, 5)) - - # Make a weird system. - orig = kwant.Builder(sym) - sites = cubic.shape(lambda pos: True, (0, 0, 0)) - for i, site in enumerate(orig.expand(sites)): - if i % 7 == 0: - continue - orig[site] = i - for i, hopp in enumerate(orig.expand(cubic.neighbors(1))): - if i % 11 == 0: - continue - orig[hopp] = i * 1.2345 - for i, hopp in enumerate(orig.expand(cubic.neighbors(2))): - if i % 13 == 0: - continue - orig[hopp] = i * 1j - - # Clone the original using fill. - clone = kwant.Builder(sym) - clone.fill(orig, lambda s: True, (0, 0, 0)) - - # Verify that both are identical. - assert set(clone.site_value_pairs()) == set(orig.site_value_pairs()) - assert set(clone.hopping_value_pairs()) == set(orig.hopping_value_pairs()) + for sym, func in [(kwant.TranslationalSymmetry(*np.diag([3, 4, 5])), + lambda pos: True), + (builder.NoSymmetry(), + lambda pos: ta.dot(pos, pos) < 17)]: + cubic = kwant.lattice.general(ta.identity(3)) + + # Make a weird system. + orig = kwant.Builder(sym) + sites = cubic.shape(func, (0, 0, 0)) + for i, site in enumerate(orig.expand(sites)): + if i % 7 == 0: + continue + orig[site] = i + for i, hopp in enumerate(orig.expand(cubic.neighbors(1))): + if i % 11 == 0: + continue + orig[hopp] = i * 1.2345 + for i, hopp in enumerate(orig.expand(cubic.neighbors(2))): + if i % 13 == 0: + continue + orig[hopp] = i * 1j + + # Clone the original using fill. + clone = kwant.Builder(sym) + clone.fill(orig, lambda s: True, (0, 0, 0)) + + # Verify that both are identical. + assert set(clone.site_value_pairs()) == set(orig.site_value_pairs()) + assert (set(clone.hopping_value_pairs()) + == set(orig.hopping_value_pairs())) ## Test for warning when "start" is out. target = builder.Builder() diff --git a/kwant/tests/test_lattice.py b/kwant/tests/test_lattice.py index c3ea78e7b17162d25a1b5314de5a51f1c507aa85..ab4cea6096c5b96235dd28619aeceab9e2dea5d6 100644 --- a/kwant/tests/test_lattice.py +++ b/kwant/tests/test_lattice.py @@ -251,21 +251,23 @@ def test_symmetry_act(): sym.act(ta.array(el), site) -def test_symmetry_subgroup(): +def test_symmetry_has_subgroup(): rng = np.random.RandomState(0) ## test whether actual subgroups are detected as such vecs = rng.randn(3, 3) sym1 = lattice.TranslationalSymmetry(*vecs) - assert sym1 >= sym1 - assert sym1 >= builder.NoSymmetry() - assert sym1 >= lattice.TranslationalSymmetry(2 * vecs[0], - 3 * vecs[1] + 4 * vecs[2]) - assert not sym1 <= lattice.TranslationalSymmetry(*(0.8 * vecs)) + ns = builder.NoSymmetry() + assert ns.has_subgroup(ns) + assert sym1.has_subgroup(sym1) + assert sym1.has_subgroup(ns) + assert sym1.has_subgroup(lattice.TranslationalSymmetry( + 2 * vecs[0], 3 * vecs[1] + 4 * vecs[2])) + assert not lattice.TranslationalSymmetry(*(0.8 * vecs)).has_subgroup(sym1) ## test subgroup creation for dim in range(1, 4): generators = rng.randint(10, size=(dim, 3)) - assert sym1.subgroup(*generators) <= sym1 + assert sym1.has_subgroup(sym1.subgroup(*generators)) # generators are not linearly independent with raises(ValueError):