class Monomial:
def __init__(self, vars, sgn=1):
self.vars = tuple(vars)
self.sgn = sgn
def __mul__(self, other):
return Monomial(self.vars + other.vars,self.sgn * other.sgn)
def __repr__(self):
return f"{'-+'[self.sgn > 0]} {'.'.join(sorted(map(repr,self.vars))) or '1'}"
def __eq__(self, other):
return repr(self) == repr(other)
у такого умножения мономов есть нейтральный элемент и оно (операционально) коммутативно
> print(Monomial(("y",))*Monomial(("x",))*Monomial() == Monomial(("x","y")))
True
тут занятно, что хотя изначальная идея была класть в vars набор строк (имен переменных) — в коде от этого осталось мало следов, можно пользоваться и любыми другими типами, print(Monomial((2,1))) работает без проблем
в качестве математической интермедии можно посмотреть, что за множество мы получим, если разрешим в качестве меток (‘имен переменных’) не строки, а произвольные числа
теорема Виета говорит, что Monomials<ComplexNumbers> (буду дальше писать тип vars в угловых скобках; и давайте считать, что разрешен только sgn=1) — это по сути то же, что упорядоченные наборы чисел (т.е. чтобы это увидеть, можно попросить repr печатать значения элементарных симметических многочленов от vars)
любителям геометрии приятнее смотреть не на ℂ, а на ℂ с добавленной точкой '∞' — и примерно то же рассуждение говорит, что Monomials от такого образования суть точки комплексных проективных пространств
если еще отождествить Monomial(0) с нейтральным элементом Monomial(), то все эти проективные пространства склеятся в одно большое красивое ℂP∞
в ту же игру можно играть не только с ℂP¹ aka S², но и с другими топологическими пространствами — если в качестве меток разрешить точки топологического пространства X (и одну из точек объявить нейтральным элементом), то получается определение групп гомологий без всяких комплексов и т.п.: просто H_n(X) = π_n ( Monomials<X> )
называется теорема Дольда–Тома
упражнение для любителей геометрии: разобраться, как выглядит пространство Monomials<RP²>