From b008821f286e271a4e3a2aa84d0c4703c7fca8d1 Mon Sep 17 00:00:00 2001 From: Joseph Weston <joseph@weston.cloud> Date: Tue, 26 Nov 2019 10:57:02 +0100 Subject: [PATCH] move Symmetry and NoSymmetry to the system module N-dimensional systems will need symmetry elements, so the symmetry definition needs to be in the system module. --- kwant/builder.py | 181 +---------------------------------------------- kwant/lattice.py | 2 +- kwant/system.py | 177 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 179 insertions(+), 181 deletions(-) diff --git a/kwant/builder.py b/kwant/builder.py index 0d4e3399..05ee58f7 100644 --- a/kwant/builder.py +++ b/kwant/builder.py @@ -21,7 +21,7 @@ import tinyarray as ta import numpy as np from scipy import sparse from . import system, graph, KwantDeprecationWarning, UserCodeError -from .system import Site, SiteArray, SiteFamily +from .system import Site, SiteArray, SiteFamily, Symmetry, NoSymmetry from .linalg import lll from .operator import Density from .physics import DiscreteSymmetry, magnetic_gauge @@ -29,7 +29,7 @@ from ._common import (ensure_isinstance, get_parameters, reraise_warnings, interleave, deprecate_args, memoize) -__all__ = ['Builder', 'Symmetry', 'HoppingKind', 'Lead', +__all__ = ['Builder', 'HoppingKind', 'Lead', 'BuilderLead', 'SelfEnergyLead', 'ModesLead', 'add_peierls_phase'] @@ -64,183 +64,6 @@ def validate_hopping(hopping): raise ValueError("A hopping connects the following site to itself:\n" "{0}".format(a)) - - -################ Symmetries - -class Symmetry(metaclass=abc.ABCMeta): - """Abstract base class for spatial symmetries. - - Many physical systems possess a discrete spatial symmetry, which results in - special properties of these systems. This class is the standard way to - describe discrete spatial symmetries in Kwant. An instance of this class - can be passed to a `Builder` instance at its creation. The most important - kind of symmetry is translational symmetry, used to define scattering - leads. - - Each symmetry has a fundamental domain -- a set of sites and hoppings, - generating all the possible sites and hoppings upon action of symmetry - group elements. A class derived from `Symmetry` has to implement mapping - of any site or hopping into the fundamental domain, applying a symmetry - group element to a site or a hopping, and a method `which` to determine the - group element bringing some site from the fundamental domain to the - requested one. Additionally, it has to have a property `num_directions` - returning the number of independent symmetry group generators (number of - elementary periods for translational symmetry). - - A ``ValueError`` must be raised by the symmetry class whenever a symmetry - is used together with sites whose site family is not compatible with it. A - typical example of this is when the vector defining a translational - symmetry is not a lattice vector. - - The type of the domain objects as handled by the methods of this class is - not specified. The only requirement is that it must support the unary - minus operation. The reference implementation of `to_fd()` is hence - `self.act(-self.which(a), a, b)`. - """ - - @abc.abstractproperty - def num_directions(self): - """Number of elementary periods of the symmetry.""" - pass - - @abc.abstractmethod - def which(self, site): - """Calculate the domain of the site. - - Parameters - ---------- - site : `~kwant.system.Site` or `~kwant.system.SiteArray` - - Returns - ------- - group_element : tuple or sequence of tuples - A single tuple if ``site`` is a Site, or a sequence of tuples if - ``site`` is a SiteArray. The group element(s) whose action - on a certain site(s) from the fundamental domain will result - in the given ``site``. - """ - pass - - @abc.abstractmethod - def act(self, element, a, b=None): - """Act with symmetry group element(s) on site(s) or hopping(s). - - Parameters - ---------- - element : tuple or sequence of tuples - Group element(s) with which to act on the provided site(s) - or hopping(s) - a, b : `~kwant.system.Site` or `~kwant.system.SiteArray` - If Site then ``element`` is a single tuple, if SiteArray then - ``element`` is a single tuple or a sequence of tuples. - If only ``a`` is provided then ``element`` acts on the site(s) - of ``a``. If ``b`` is also provided then ``element`` acts - on the hopping(s) ``(a, b)``. - """ - pass - - def to_fd(self, a, b=None): - """Map a site or hopping to the fundamental domain. - - Parameters - ---------- - a, b : `~kwant.system.Site` or `~kwant.system.SiteArray` - - If ``b`` is None, return a site equivalent to ``a`` within the - fundamental domain. Otherwise, return a hopping equivalent to ``(a, - b)`` but where the first element belongs to the fundamental domain. - - Equivalent to `self.act(-self.which(a), a, b)`. - """ - return self.act(-self.which(a), a, b) - - def in_fd(self, site): - """Tell whether ``site`` lies within the fundamental domain. - - Parameters - ---------- - site : `~kwant.system.Site` or `~kwant.system.SiteArray` - - Returns - ------- - in_fd : bool or sequence of bool - single bool if ``site`` is a Site, or a sequence of - bool if ``site`` is a SiteArray. In the latter case - we return whether each site in the SiteArray is in - the fundamental domain. - """ - if isinstance(site, Site): - for d in self.which(site): - if d != 0: - return False - return True - elif isinstance(site, SiteArray): - which = self.which(site) - return np.logical_and.reduce(which != 0, axis=1) - else: - raise TypeError("'site' must be a Site or SiteArray") - - @abc.abstractmethod - def subgroup(self, *generators): - """Return the subgroup generated by a sequence of group elements.""" - pass - - @abc.abstractmethod - 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 `is_subgroup`) is that - in general it's not possible for a subgroup to know its supergroups. - - """ - pass - - -class NoSymmetry(Symmetry): - """A symmetry with a trivial symmetry group.""" - - def __eq__(self, other): - return isinstance(other, NoSymmetry) - - def __ne__(self, other): - return not self.__eq__(other) - - def __repr__(self): - return 'NoSymmetry()' - - @property - def num_directions(self): - return 0 - - periods = () - - _empty_array = ta.array((), int) - - def which(self, site): - return self._empty_array - - def act(self, element, a, b=None): - if element: - raise ValueError('`element` must be empty for NoSymmetry.') - return a if b is None else (a, b) - - def to_fd(self, a, b=None): - return a if b is None else (a, b) - - def in_fd(self, site): - return True - - def subgroup(self, *generators): - if any(generators): - raise ValueError('Generators must be empty for NoSymmetry.') - return NoSymmetry(generators) - - def has_subgroup(self, other): - return isinstance(other, NoSymmetry) - - ################ Hopping kinds diff --git a/kwant/lattice.py b/kwant/lattice.py index b713c0ad..7e0d5590 100644 --- a/kwant/lattice.py +++ b/kwant/lattice.py @@ -514,7 +514,7 @@ class Monatomic(system.SiteFamily, Polyatomic): # The following class is designed such that it should avoid floating # point precision issues. -class TranslationalSymmetry(builder.Symmetry): +class TranslationalSymmetry(system.Symmetry): """A translational symmetry defined in real space. An alias exists for this common name: ``kwant.TranslationalSymmetry``. diff --git a/kwant/system.py b/kwant/system.py index 7bc33ae7..318fa90a 100644 --- a/kwant/system.py +++ b/kwant/system.py @@ -9,7 +9,7 @@ """Low-level interface of systems""" __all__ = [ - 'Site', 'SiteArray', 'SiteFamily', + 'Site', 'SiteArray', 'SiteFamily', 'Symmetry', 'NoSymmetry', 'System', 'VectorizedSystem', 'FiniteSystem', 'FiniteVectorizedSystem', 'InfiniteSystem', 'InfiniteVectorizedSystem', 'is_finite', 'is_infinite', 'is_vectorized', @@ -22,6 +22,7 @@ from copy import copy from collections import namedtuple from functools import total_ordering, lru_cache import numpy as np +import tinyarray as ta from . import _system from ._common import deprecate_args, KwantDeprecationWarning @@ -269,6 +270,180 @@ class SiteFamily: 'site_family((1, 2))!') return Site(self, tag) + +################ Symmetries + +class Symmetry(metaclass=abc.ABCMeta): + """Abstract base class for spatial symmetries. + + Many physical systems possess a discrete spatial symmetry, which results in + special properties of these systems. This class is the standard way to + describe discrete spatial symmetries in Kwant. An instance of this class + can be passed to a `Builder` instance at its creation. The most important + kind of symmetry is translational symmetry, used to define scattering + leads. + + Each symmetry has a fundamental domain -- a set of sites and hoppings, + generating all the possible sites and hoppings upon action of symmetry + group elements. A class derived from `Symmetry` has to implement mapping + of any site or hopping into the fundamental domain, applying a symmetry + group element to a site or a hopping, and a method `which` to determine the + group element bringing some site from the fundamental domain to the + requested one. Additionally, it has to have a property `num_directions` + returning the number of independent symmetry group generators (number of + elementary periods for translational symmetry). + + A ``ValueError`` must be raised by the symmetry class whenever a symmetry + is used together with sites whose site family is not compatible with it. A + typical example of this is when the vector defining a translational + symmetry is not a lattice vector. + + The type of the domain objects as handled by the methods of this class is + not specified. The only requirement is that it must support the unary + minus operation. The reference implementation of `to_fd()` is hence + `self.act(-self.which(a), a, b)`. + """ + + @abc.abstractproperty + def num_directions(self): + """Number of elementary periods of the symmetry.""" + pass + + @abc.abstractmethod + def which(self, site): + """Calculate the domain of the site. + + Parameters + ---------- + site : `~kwant.system.Site` or `~kwant.system.SiteArray` + + Returns + ------- + group_element : tuple or sequence of tuples + A single tuple if ``site`` is a Site, or a sequence of tuples if + ``site`` is a SiteArray. The group element(s) whose action + on a certain site(s) from the fundamental domain will result + in the given ``site``. + """ + pass + + @abc.abstractmethod + def act(self, element, a, b=None): + """Act with symmetry group element(s) on site(s) or hopping(s). + + Parameters + ---------- + element : tuple or sequence of tuples + Group element(s) with which to act on the provided site(s) + or hopping(s) + a, b : `~kwant.system.Site` or `~kwant.system.SiteArray` + If Site then ``element`` is a single tuple, if SiteArray then + ``element`` is a single tuple or a sequence of tuples. + If only ``a`` is provided then ``element`` acts on the site(s) + of ``a``. If ``b`` is also provided then ``element`` acts + on the hopping(s) ``(a, b)``. + """ + pass + + def to_fd(self, a, b=None): + """Map a site or hopping to the fundamental domain. + + Parameters + ---------- + a, b : `~kwant.system.Site` or `~kwant.system.SiteArray` + + If ``b`` is None, return a site equivalent to ``a`` within the + fundamental domain. Otherwise, return a hopping equivalent to ``(a, + b)`` but where the first element belongs to the fundamental domain. + + Equivalent to `self.act(-self.which(a), a, b)`. + """ + return self.act(-self.which(a), a, b) + + def in_fd(self, site): + """Tell whether ``site`` lies within the fundamental domain. + + Parameters + ---------- + site : `~kwant.system.Site` or `~kwant.system.SiteArray` + + Returns + ------- + in_fd : bool or sequence of bool + single bool if ``site`` is a Site, or a sequence of + bool if ``site`` is a SiteArray. In the latter case + we return whether each site in the SiteArray is in + the fundamental domain. + """ + if isinstance(site, Site): + for d in self.which(site): + if d != 0: + return False + return True + elif isinstance(site, SiteArray): + which = self.which(site) + return np.logical_and.reduce(which != 0, axis=1) + else: + raise TypeError("'site' must be a Site or SiteArray") + + @abc.abstractmethod + def subgroup(self, *generators): + """Return the subgroup generated by a sequence of group elements.""" + pass + + @abc.abstractmethod + 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 `is_subgroup`) is that + in general it's not possible for a subgroup to know its supergroups. + + """ + pass + + +class NoSymmetry(Symmetry): + """A symmetry with a trivial symmetry group.""" + + def __eq__(self, other): + return isinstance(other, NoSymmetry) + + def __ne__(self, other): + return not self.__eq__(other) + + def __repr__(self): + return 'NoSymmetry()' + + @property + def num_directions(self): + return 0 + + periods = () + + _empty_array = ta.array((), int) + + def which(self, site): + return self._empty_array + + def act(self, element, a, b=None): + if element: + raise ValueError('`element` must be empty for NoSymmetry.') + return a if b is None else (a, b) + + def to_fd(self, a, b=None): + return a if b is None else (a, b) + + def in_fd(self, site): + return True + + def subgroup(self, *generators): + if any(generators): + raise ValueError('Generators must be empty for NoSymmetry.') + return NoSymmetry(generators) + + def has_subgroup(self, other): + return isinstance(other, NoSymmetry) ################ Systems -- GitLab