群运算的构建

1. 群运算的构建#

想用python实现较为通用的(离散)群运算操作,需要一些技巧。因为群的运算有其特殊之处:

  • 首先,需要定义一个群,一个群需要有它的乘法和它的群元素。这些是需要程序的使用者自己提供的。见群论基础知识

  • 其次,在一个给定的群里,群元的运算应该要得到另一个群元。

所以,如果我们使用如下的定义:

class GroupElement:

    elements = ...
    product_table = ...

    def __mul__(self, other: GroupElement
                ) -> GroupElement:
        pass
    def __imul__(self, other: GroupElement
                ) -> GroupElement:
        pass

就只能定义一个特定的群,而无法做到对一系列的不同的离散群通用。因为群的元素和乘法表已经确定了。

对于一系列的群,比如分子结构中的\(C_{2v}\), \(D_{\infty h}\), \(C_S\)群之类的,可以用如下的构造类的函数。

小心

这不同于所谓“类的构造函数”。“类的构造函数”是指__init__函数,它为一个专门的类生成对象。而我这里说的“构造类的函数”指的是在某一个基础类上进行修饰的做法。

首先,我们定义一个通用的群和运算规则,它们有元素表和元素乘法表的声明,但是,这里我们并不直接提供一个运算表,而是只规定了表的数据结构。

class PrimaryGroupElement:

    element_names = [ ... ]
    element_arrays = [ [...],
                        ... ]

    def __init__():
        pass

    def __primul__(self, other) -> str:
        pass

规定了数据结构后,我们就可以形式上定义运算的过程,比如如果元素是一个字符串数组,运算表是某个字典,总能定义这种查找操作。即使我们还没有真正把这数组和字典具体的定义出来。

也就是说,这个类现在还不能用,但是只需要给出运算表就行了。

但是,如果我们每次都使用类生成对象,再把运算表附上,显然过于麻烦。我们可以定义一个函数,产生派生类。

IRREP_ID_TABLE = {'C2v': [ ... ],
                    ...}
CHARACTER_TABLE = {'C2v': [ (...), ... ],
                    ...}

def build_group_element(symmetry_type: str = 'C2v'):

    class group_element(PrimaryGroupElement):

        element_names = IRREP_ID_TABLE[symmetry_type]
        element_arrays = CHARACTER_TABLE[symmetry_type]

        def __mul__(self, other: group_element):
            new_name = self.__premul__(other)
            return group_element(new_name)

        def __imul__(self, other: group_element):
            new_name = self.__premul__(other)
            self.__init__(new_name)
            return self

        def copy(self):
            pass

        @classmethod
        def from_idx(cls, idx: int) -> group_element:
            pass

    return group_element

可以看到,这是一个生成派生类的函数。这个函数在定义派生类的时候,通过查找总表,把\(C_{2v}\)的群元素和群运算表分配给了基类。并且额外定义了乘法运算。这样,当使用者要进行某一种群的操作时,就可以有如下方式:

>>> c2v_group_element = build_group_element('C2v')
>>> a1 = c2v_group_element('a1')
>>> a2 = c2v_group_element('a2')
>>> a2_new = a1 * a2
>>> type(a2_new)

     c2v_group_element

总的来说,基类首先定义了一种通用的群的运算理念,而构造类的函数则返回一个可以调用的类,这个类可以生成某个特定的群元,进行这个特定群元的运算。