# 群运算的构建

想用python实现较为通用的（离散）群运算操作，需要一些技巧。因为群的运算有其特殊之处：

- 首先，需要定义一个群，一个群需要有它的乘法和它的群元素。这些是需要程序的使用者自己提供的。见[群论基础知识](/docs/群论/1_基础.md)
- 其次，在一个给定的群里，群元的运算应该要得到另一个群元。

所以，如果我们使用如下的定义：

```{code-block} 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$群之类的，可以用如下的构造类的函数。

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

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

```{code-block} python
class PrimaryGroupElement:

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

    def __init__():
        pass

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

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

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

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

```{code-block} python
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}$的群元素和群运算表分配给了基类。并且额外定义了乘法运算。这样，当使用者要进行某一种群的操作时，就可以有如下方式：

```{code-block} python
>>> 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
```

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